emulator.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. #include "../higan-ui.hpp"
  2. #include "platform.cpp"
  3. #include "video.cpp"
  4. #include "audio.cpp"
  5. #include "input.cpp"
  6. #include "states.cpp"
  7. #include "status.cpp"
  8. #include "utility.cpp"
  9. Emulator emulator;
  10. auto Emulator::create(shared_pointer<higan::Interface> instance, string location) -> void {
  11. interface = instance;
  12. system = {};
  13. system.name = Location::base(location).trimRight("/", 1L);
  14. system.data = location;
  15. system.templates = {Path::templates, interface->name(), "/"};
  16. string configuration = file::read({location, "settings.bml"});
  17. if(!configuration) {
  18. auto system = higan::Node::System::create();
  19. system->setName(interface->name());
  20. system->setAttribute("location", location);
  21. configuration = higan::Node::serialize(system);
  22. }
  23. //peripherals may have been renamed or deleted since last run; remove them from the configuration now
  24. auto document = BML::unserialize(configuration);
  25. for(auto node : document) validateConfiguration(node, document);
  26. configuration = BML::serialize(document);
  27. screens.reset();
  28. streams.reset();
  29. interface->load(root);
  30. root->copy(higan::Node::unserialize(configuration));
  31. systemMenu.setText(system.name);
  32. toolsMenu.pauseEmulation.setChecked(false);
  33. program.setEmulatorMode();
  34. program.setTitle(system.name);
  35. program.setFocused();
  36. videoUpdate();
  37. audioUpdate();
  38. inputManager.bind(root);
  39. inputManager.poll();
  40. power(false);
  41. }
  42. auto Emulator::unload() -> void {
  43. if(!interface) return;
  44. power(false);
  45. if(system.log) system.log.close();
  46. if(auto location = root->attribute("location")) {
  47. file::write({location, "settings.bml"}, higan::Node::serialize(root));
  48. }
  49. inputManager.unbind();
  50. root = {};
  51. interface->unload();
  52. interface.reset();
  53. program.setTitle({"higan v", higan::Version});
  54. systemMenu.setText("System");
  55. setCaption();
  56. }
  57. auto Emulator::main() -> void {
  58. updateMessage();
  59. if(Application::modal()) return; //modal loop calls usleep() internally
  60. inputManager.poll();
  61. hotkeys.poll();
  62. if(!interface) return (void)usleep(20 * 1000);
  63. if(!system.power
  64. || program.toolsMenu.pauseEmulation.checked()
  65. || (!program.viewport.focused() && settings.input.unfocused == "Pause")
  66. ) {
  67. usleep(20 * 1000);
  68. } else {
  69. interface->run();
  70. if(events.power) power(false); //system powered itself off
  71. }
  72. }
  73. auto Emulator::quit() -> void {
  74. //make quitting feel more responsive
  75. program.setVisible(false);
  76. Application::processEvents();
  77. //stop processing callbacks and timers
  78. Application::quit();
  79. unload();
  80. interfaces.reset();
  81. videoInstance.reset();
  82. audioInstance.reset();
  83. inputInstance.reset();
  84. }
  85. auto Emulator::power(bool on) -> void {
  86. if(system.power == on) return;
  87. if(system.power = on) {
  88. program.setTitle(interface->game());
  89. videoUpdateColors();
  90. audioUpdateEffects();
  91. events = {};
  92. interface->power();
  93. //powering on the system latches static settings
  94. nodeManager.refreshSettings();
  95. if(settingEditor.visible()) settingEditor.refresh();
  96. program.viewport.setFocused();
  97. } else {
  98. program.setTitle(system.name);
  99. setCaption();
  100. videoInstance.clear();
  101. audioInstance.clear();
  102. inputInstance.release();
  103. }
  104. systemMenu.power.setChecked(on);
  105. toolsMenu.saveStateMenu.setEnabled(on);
  106. toolsMenu.loadStateMenu.setEnabled(on);
  107. }
  108. //used to prevent connecting the same (emulated) physical device to multiple ports simultaneously
  109. auto Emulator::connected(string location) -> higan::Node::Port {
  110. for(auto& peripheral : root->find<higan::Node::Peripheral>()) {
  111. if(location == peripheral->attribute("location")) {
  112. if(auto parent = peripheral->parent()) return parent.acquire();
  113. }
  114. }
  115. return {};
  116. }
  117. auto Emulator::validateConfiguration(Markup::Node node, Markup::Node parent) -> void {
  118. for(auto attribute : node.find("attribute")) {
  119. if(attribute["name"].text() != "location") continue;
  120. auto location = attribute["value"].text();
  121. //if the peripheral is missing, remove it from the tree
  122. if(!directory::exists(location)) parent.remove(node);
  123. }
  124. for(auto branch : node) validateConfiguration(branch, node);
  125. }