123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- #include "../higan-ui.hpp"
- #include "platform.cpp"
- #include "video.cpp"
- #include "audio.cpp"
- #include "input.cpp"
- #include "states.cpp"
- #include "status.cpp"
- #include "utility.cpp"
- Emulator emulator;
- auto Emulator::create(shared_pointer<higan::Interface> instance, string location) -> void {
- interface = instance;
- system = {};
- system.name = Location::base(location).trimRight("/", 1L);
- system.data = location;
- system.templates = {Path::templates, interface->name(), "/"};
- string configuration = file::read({location, "settings.bml"});
- if(!configuration) {
- auto system = higan::Node::System::create();
- system->setName(interface->name());
- system->setAttribute("location", location);
- configuration = higan::Node::serialize(system);
- }
- //peripherals may have been renamed or deleted since last run; remove them from the configuration now
- auto document = BML::unserialize(configuration);
- for(auto node : document) validateConfiguration(node, document);
- configuration = BML::serialize(document);
- screens.reset();
- streams.reset();
- interface->load(root);
- root->copy(higan::Node::unserialize(configuration));
- systemMenu.setText(system.name);
- toolsMenu.pauseEmulation.setChecked(false);
- program.setEmulatorMode();
- program.setTitle(system.name);
- program.setFocused();
- videoUpdate();
- audioUpdate();
- inputManager.bind(root);
- inputManager.poll();
- power(false);
- }
- auto Emulator::unload() -> void {
- if(!interface) return;
- power(false);
- if(system.log) system.log.close();
- if(auto location = root->attribute("location")) {
- file::write({location, "settings.bml"}, higan::Node::serialize(root));
- }
- inputManager.unbind();
- root = {};
- interface->unload();
- interface.reset();
- program.setTitle({"higan v", higan::Version});
- systemMenu.setText("System");
- setCaption();
- }
- auto Emulator::main() -> void {
- updateMessage();
- if(Application::modal()) return; //modal loop calls usleep() internally
- inputManager.poll();
- hotkeys.poll();
- if(!interface) return (void)usleep(20 * 1000);
- if(!system.power
- || program.toolsMenu.pauseEmulation.checked()
- || (!program.viewport.focused() && settings.input.unfocused == "Pause")
- ) {
- usleep(20 * 1000);
- } else {
- interface->run();
- if(events.power) power(false); //system powered itself off
- }
- }
- auto Emulator::quit() -> void {
- //make quitting feel more responsive
- program.setVisible(false);
- Application::processEvents();
- //stop processing callbacks and timers
- Application::quit();
- unload();
- interfaces.reset();
- videoInstance.reset();
- audioInstance.reset();
- inputInstance.reset();
- }
- auto Emulator::power(bool on) -> void {
- if(system.power == on) return;
- if(system.power = on) {
- program.setTitle(interface->game());
- videoUpdateColors();
- audioUpdateEffects();
- events = {};
- interface->power();
- //powering on the system latches static settings
- nodeManager.refreshSettings();
- if(settingEditor.visible()) settingEditor.refresh();
- program.viewport.setFocused();
- } else {
- program.setTitle(system.name);
- setCaption();
- videoInstance.clear();
- audioInstance.clear();
- inputInstance.release();
- }
- systemMenu.power.setChecked(on);
- toolsMenu.saveStateMenu.setEnabled(on);
- toolsMenu.loadStateMenu.setEnabled(on);
- }
- //used to prevent connecting the same (emulated) physical device to multiple ports simultaneously
- auto Emulator::connected(string location) -> higan::Node::Port {
- for(auto& peripheral : root->find<higan::Node::Peripheral>()) {
- if(location == peripheral->attribute("location")) {
- if(auto parent = peripheral->parent()) return parent.acquire();
- }
- }
- return {};
- }
- auto Emulator::validateConfiguration(Markup::Node node, Markup::Node parent) -> void {
- for(auto attribute : node.find("attribute")) {
- if(attribute["name"].text() != "location") continue;
- auto location = attribute["value"].text();
- //if the peripheral is missing, remove it from the tree
- if(!directory::exists(location)) parent.remove(node);
- }
- for(auto branch : node) validateConfiguration(branch, node);
- }
|