diff --git a/src/E2wxApp.cpp b/src/E2wxApp.cpp index d4e8a54..0f0403d 100644 --- a/src/E2wxApp.cpp +++ b/src/E2wxApp.cpp @@ -54,6 +54,11 @@ wxIMPLEMENT_APP_NO_MAIN(E2wxApp); #define PROJECT_VERSION 0.0.1 #endif + +std::promise E2wxApp::barrier_to_init; + + + E2wxApp::E2wxApp() : id("nu.mine.mosher.epple2"), version(wxSTRINGIZE_T(PROJECT_VERSION)) { } @@ -151,6 +156,7 @@ bool E2wxApp::OnInit() { frame->Show(); + barrier_to_init.set_value(); return true; } diff --git a/src/E2wxApp.h b/src/E2wxApp.h index 5410c8c..10d8312 100644 --- a/src/E2wxApp.h +++ b/src/E2wxApp.h @@ -27,6 +27,7 @@ #include #include #include +#include class E2wxApp : public wxApp { const std::string id; @@ -41,6 +42,8 @@ class E2wxApp : public wxApp { void InitBoostLog(); public: + static std::promise barrier_to_init; + E2wxApp(); virtual ~E2wxApp(); diff --git a/src/PreferencesDialog.cpp b/src/PreferencesDialog.cpp index 3b1a64b..2d61008 100644 --- a/src/PreferencesDialog.cpp +++ b/src/PreferencesDialog.cpp @@ -137,7 +137,7 @@ void PreferencesDialog::OnInit() { wxConfigBase *appconf = wxConfigBase::Get(); if (!appconf->Read(wxT("/ActivePreferences/name"), &this->active)) { // TODO what to do when no config? - this->active = ".template"; + this->active = "epple2"; appconf->Write(wxT("/ActivePreferences/name"), this->active); appconf->Flush(); } diff --git a/src/configep2.cpp b/src/configep2.cpp index 06c4aa1..5563305 100644 --- a/src/configep2.cpp +++ b/src/configep2.cpp @@ -17,6 +17,8 @@ */ #include "configep2.h" +#include "E2wxApp.h" + #include "apple2.h" #include "memory.h" #include "memoryrandomaccess.h" @@ -31,6 +33,9 @@ #include "cassetteout.h" #include "tinyfiledialogs.h" +#include +#include + #include #include #include @@ -105,11 +110,46 @@ void Config::parse(MemoryRandomAccess& ram, Memory& rom, Slots& slts, int& revis pConfig = new std::ifstream(path.c_str()); if (!pConfig->is_open()) { + // TODO use filename only and look in standard resources std::stringstream ss; ss << "Cannot open config file " << this->file_path.c_str(); throw std::runtime_error(ss.str()); } } + + + + if (path.empty()) + { + // TODO config file location, how to be backwardly compatible? + wxString user_config; + if (!wxConfigBase::Get()->Read(wxT("/ActivePreferences/name"), &user_config)) { + // TODO what to do when no config? + user_config = wxT("epple2"); + } + + std::filesystem::path f = wxGetApp().GetConfigDir(); + f /= user_config.t_str(); + f += ".conf"; + path = f.string(); + std::cout << "looking for config file: " << path << std::endl; + pConfig = new std::ifstream(path.c_str()); + if (!pConfig->is_open()) { + f = wxGetApp().GetResDir(); + f /= user_config.t_str(); + f += ".conf"; + path = f.string(); + std::cout << "looking for config file: " << path << std::endl; + pConfig = new std::ifstream(path.c_str()); + if (!pConfig->is_open()) { + path.clear(); + } + } + } + + + + if (path.empty()) { std::cout << "standard config file location: " ETCDIR "/epple2/epple2.conf" << std::endl; @@ -304,17 +344,23 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo std::string file; std::getline(tok,file); trim(file); - std::ifstream memfile(file.c_str(),std::ios::binary); - if (!memfile.is_open()) + std::ifstream *memfile = new std::ifstream(file.c_str(),std::ios::binary); + if (!memfile->is_open()) { - throw ConfigException("cannot open file "+file); + std::filesystem::path f = wxGetApp().GetResDir(); + f /= file; + memfile = new std::ifstream(f,std::ios::binary); + if (!memfile->is_open()) + { + throw ConfigException("cannot open file "+file); + } } if (slot < 0) // motherboard { if (romtype == "rom") { - rom.load(base,memfile); + rom.load(base,*memfile); } else { @@ -329,15 +375,15 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo } Card* card = slts.get(slot); if (romtype == "rom") - card->loadRom(base,memfile); + card->loadRom(base,*memfile); else if (romtype == "rom7") - card->loadSeventhRom(base,memfile); + card->loadSeventhRom(base,*memfile); else if (romtype == "rombank") - card->loadBankRom(base,memfile); + card->loadBankRom(base,*memfile); else throw ConfigException("error at \""+romtype+"\"; expected rom, rom7, or rombank"); } - memfile.close(); + memfile->close(); } else if (cmd == "load" || cmd == "save" || cmd == "unload") { @@ -375,6 +421,7 @@ void Config::tryParseLine(const std::string& line, MemoryRandomAccess& ram, Memo } } if (fn_optional.length() > 0) { + // TODO check if file exists, if not then check resources loadDisk(slts,slot,drive,fn_optional); } } diff --git a/src/emulator.cpp b/src/emulator.cpp index 2d51d6c..3be9b71 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -95,81 +95,101 @@ void Emulator::init() { static const int CYCLES_PER_REPT(E2Const::AVG_CPU_HZ / 10); -// The core of this Apple + + + + + +// If the Apple ][ keyboard repeat is on (the REPT key is +// down)... +void Emulator::handleRepeatKey() { + if (this->repeat) { + // Count our way down to when the timer for the REPT key + // fires off: 10Hz in terms of how many CPU cycles have gone + // by + --this->rept; + // If it's time for the REPT key timer to fire (at long + // last)... + if (this->rept <= 0) { + // ...reload the timer for the next firing 1/10 second from + // now ( *reset* the timer ) + this->rept = CYCLES_PER_REPT; + // If any other keys are actually being held down... + if (this->keysDown > 0) { + // ...REPEAT the most recent one that was pressed + this->keypresses.push(this->lastKeyDown); + } + } + } +} + +void Emulator::handleAnyPendingEvents() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + switch (event.type) { + case SDL_QUIT: + // If SDL is going away... + quitIfSafe(); + break; + case SDL_KEYDOWN: + // If we're collecting a command line for changing any + // of the configurables of the emulator... + if (this->command) + cmdKey(event.key); + else + // ...else we're collecting keypresses for the keyboard + // emulation (and thus the Apple ][ emulation itself) + dispatchKeypress(event.key); + break; + case SDL_KEYUP: + // If we're collecting a command line for changing any + // of the configurables of the emulator... + if (this->command) { + if (this->pendingCommandExit) { + this->command = false; + this->pendingCommandExit = false; + } + } else { + // ...else we're collecting keypresses for the keyboard + // emulation (and thus the Apple ][ emulation itself) + dispatchKeyUp(event.key); + } + break; + } + } +} + + + + + + + +// The core of this Apple int Emulator::run() { - int skip = CHECK_EVERY_CYCLE; + int skip = 0; Uint32 prev_ms = SDL_GetTicks(); + // While the user still wants to run this emulation... while (!this->quit) { // (Obligatory protection against NULL object pointer) if (this->timable) { this->timable->tick(); - // If the Apple ][ keyboard repeat is on (the REPT key is - // down)... - if (this->repeat) { - // Count our way down to when the timer for the REPT key - // fires off: 10Hz in terms of how many CPU cycles have gone - // by - --this->rept; - // If it's time for the REPT key timer to fire (at long - // last)... - if (this->rept <= 0) { - // ...reload the timer for the next firing 1/10 second from - // now ( *reset* the timer ) - this->rept = CYCLES_PER_REPT; - // If any other keys are actually being held down... - if (this->keysDown > 0) { - // ...REPEAT the most recent one that was pressed - this->keypresses.push(this->lastKeyDown); - } - } - } + handleRepeatKey(); } // People who have too many press releases should be referred to as // keyboards - --skip; - // If skip has been decremented to zero... - if (!skip) { + if (CHECK_EVERY_CYCLE <= ++skip) { // ...then it's time to drain away any piled-up user interaction // events that SDL has stored up for us // Reload the skip quantity - skip = CHECK_EVERY_CYCLE; - SDL_Event event; - while (SDL_PollEvent(&event)) { - switch (event.type) { - // If SDL is going away... - case SDL_QUIT: - quitIfSafe(); - break; - case SDL_KEYDOWN: - // If we're collecting a command line for changing any - // of the configurables of the emulator... - if (this->command) - cmdKey(event.key); - else - // ...else we're collecting keypresses for the keyboard - // emulation (and thus the Apple ][ emulation itself) - dispatchKeypress(event.key); - break; - case SDL_KEYUP: - // If we're collecting a command line for changing any - // of the configurables of the emulator... - if (this->command) { - if (this->pendingCommandExit) { - this->command = false; - this->pendingCommandExit = false; - } - } else { - // ...else we're collecting keypresses for the keyboard - // emulation (and thus the Apple ][ emulation itself) - dispatchKeyUp(event.key); - } - break; - } - } + skip = 0; + + handleAnyPendingEvents(); + // If we're trying to run as slow as a real Apple ][... if (!this->fhyper.isHyper()) { const int delta_ms = EXPECTED_MS - (SDL_GetTicks() - prev_ms); @@ -178,15 +198,23 @@ int Emulator::run() { } } + // Display the current estimate of the emulator's actual speed // performance this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - prev_ms)); + prev_ms = SDL_GetTicks(); } } return 0; } + + + + + + void Emulator::dispatchKeyUp(const SDL_KeyboardEvent& keyEvent) { SDL_Keycode sym = keyEvent.keysym.sym; SDL_Keymod mod = (SDL_Keymod) keyEvent.keysym.mod; @@ -429,7 +457,6 @@ void Emulator::cmdKey(const SDL_KeyboardEvent& keyEvent) { } // Process a command line typed at the bottom of the emulator window - void Emulator::processCommand() { this->screenImage.exitCommandMode(); this->screenImage.drawPower(this->timable == &this->apple2); diff --git a/src/emulator.h b/src/emulator.h index 06663e8..e0270e8 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -62,6 +62,9 @@ class Emulator void processCommand(); bool isSafeToQuit(); + void handleRepeatKey(); + void handleAnyPendingEvents(); + public: Emulator(); virtual ~Emulator(); diff --git a/src/main.cpp b/src/main.cpp index 3fb578a..67e84f9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -48,19 +49,26 @@ static std::string parse_args(int argc, char* argv[]) { } -static int fake_argc(0); +static int fake_argc(1); static char fake_prog[] = "epple2"; static char *fake_argv[] { fake_prog }; static int runWx() { + std::cout << "starting wx..." << std::endl; return wxEntry(fake_argc, fake_argv); } static int runSdl(const std::string config_file) { GUI gui; + std::future barrier_to_app_init = E2wxApp::barrier_to_init.get_future(); + std::thread thread_wx(runWx); + std::cout << "wait for wx init" << std::endl; + barrier_to_app_init.wait(); + std::cout << "wx init finished" << std::endl; + std::unique_ptr emu(new Emulator()); Config cfg(config_file);