diff --git a/src/E2wxApp.cpp b/src/E2wxApp.cpp index 0f0403d..06a30d6 100644 --- a/src/E2wxApp.cpp +++ b/src/E2wxApp.cpp @@ -39,7 +39,6 @@ #include #include #include -#include #include #include #include @@ -53,13 +52,37 @@ wxIMPLEMENT_APP_NO_MAIN(E2wxApp); #ifndef PROJECT_VERSION #define PROJECT_VERSION 0.0.1 #endif - - -std::promise E2wxApp::barrier_to_init; +#ifndef PROJECT_VENDOR +#define PROJECT_VENDOR nu.mine.mosher +#endif +#ifndef PROJECT_NAME +#define PROJECT_NAME Epple-II +#endif -E2wxApp::E2wxApp() : id("nu.mine.mosher.epple2"), version(wxSTRINGIZE_T(PROJECT_VERSION)) { + + +EmuTimer::EmuTimer(Emulator *e) : wxTimer(), emu(e) { +} + +EmuTimer::~EmuTimer() { +} + +void EmuTimer::begin() { + this->Start(50); // TODO: EXPECTED_MS from Emulator +} + +void EmuTimer::Notify() { + this->emu->tick50ms(); +} + + + + +E2wxApp::E2wxApp() : + id(wxSTRINGIZE_T(PROJECT_VENDOR) wxT(".") wxSTRINGIZE_T(PROJECT_NAME)), + version(wxSTRINGIZE_T(PROJECT_VERSION)) { } E2wxApp::~E2wxApp() { @@ -69,11 +92,6 @@ E2wxApp::~E2wxApp() { - - - - - static std::filesystem::path dirCache() { return std::filesystem::path(wxStandardPaths::Get().GetUserDir(wxStandardPaths::Dir_Cache).t_str()); } @@ -107,6 +125,8 @@ bool E2wxApp::OnInit() { #endif #endif + + wxStandardPaths& stdpaths = wxStandardPaths::Get(); //stdpaths.SetInstallPrefix("."); stdpaths.SetFileLayout(wxStandardPaths::FileLayout_XDG); @@ -117,16 +137,15 @@ bool E2wxApp::OnInit() { - - this->confdir = dirConfig() / std::filesystem::path(GetID()+".d"); + this->confdir = dirConfig() / std::filesystem::path((GetID()+wxT(".d")).t_str()); std::filesystem::create_directories(this->confdir); BOOST_LOG_TRIVIAL(info) << "Configuration directory path: " << this->confdir; - this->conffile = dirConfig() / std::filesystem::path(GetID()); + this->conffile = dirConfig() / std::filesystem::path(GetID().t_str()); BOOST_LOG_TRIVIAL(info) << "Configuration file path: " << this->conffile; wxConfigBase::Set(new wxFileConfig("", "", GetID())); - this->docsdir = dirDocuments() / std::filesystem::path(GetID()); + this->docsdir = dirDocuments() / std::filesystem::path(GetID().t_str()); BOOST_LOG_TRIVIAL(info) << "User document directory path: " << this->docsdir; const std::filesystem::path exe = std::filesystem::path(stdpaths.GetExecutablePath().t_str()); @@ -156,38 +175,33 @@ bool E2wxApp::OnInit() { frame->Show(); - barrier_to_init.set_value(); + + this->emu = new Emulator(); + Config cfg((const std::string)this->arg_configfile.c_str()); + this->emu->config(cfg); + this->emu->init(); + this->emu_timer = new EmuTimer(this->emu); + this->emu_timer->begin(); + + return true; } -static int run(const std::string config_file) { - GUI gui; - std::unique_ptr emu(new Emulator()); - - Config cfg(config_file); - emu->config(cfg); - - emu->init(); - - return emu->run(); -} - -//void E2wxApp::StartSdlEpple2() { -// std::cout << "starting sdl thread..." << std::endl; -// this->thread_sdl = new std::thread(run, this->arg_configfile); -// std::cout << "started sdl thread." << std::endl; -//} int E2wxApp::OnExit() { -// std::cout << "stopping sdl thread..." << std::endl; - GUI::queueQuit(); -// this->thread_sdl->join(); -// std::cout << "exiting wx application..." << std::endl; + if (this->emu_timer) { + delete this->emu_timer; + } + if (this->emu) { + delete this->emu; + } return 0; } + + void E2wxApp::OnFatalException() { wxDebugReport report; report.AddAll(); @@ -198,33 +212,36 @@ void E2wxApp::OnFatalException() { } } -//static const wxCmdLineEntryDesc cmdLineDesc[] = -//{ -// { wxCMD_LINE_PARAM, NULL, NULL, "config file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, -// wxCMD_LINE_DESC_END -//}; -// -//void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) { -// wxApp::OnInitCmdLine(parser); -// parser.SetDesc(cmdLineDesc); -//} -// -//bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) { -// if (!wxApp::OnCmdLineParsed(parser)) { -// return false; -// } -// -// const int n = parser.GetParamCount(); -// -// if (n <= 0) { -// std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl; -// } else { -// this->arg_configfile = parser.GetParam(0); -// std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl; -// } -// -// return true; -//} + + +static const wxCmdLineEntryDesc cmdLineDesc[] = +{ + { wxCMD_LINE_PARAM, NULL, NULL, "config-file", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL }, + wxCMD_LINE_DESC_END +}; + +void E2wxApp::OnInitCmdLine(wxCmdLineParser& parser) { + wxApp::OnInitCmdLine(parser); + parser.SetDesc(cmdLineDesc); +} + +bool E2wxApp::OnCmdLineParsed(wxCmdLineParser& parser) { + if (!wxApp::OnCmdLineParsed(parser)) { + return false; + } + + const int n = parser.GetParamCount(); + + if (n <= 0) { + std::cout << "no config file specified on the command line; will use config file specified in user-preferences" << std::endl; + } else { + this->arg_configfile = parser.GetParam(0); + std::cout << "using config file specified on the command line: " << this->arg_configfile << std::endl; + } + + return true; +} + const std::filesystem::path E2wxApp::GetLogFile() const { @@ -235,7 +252,7 @@ const std::filesystem::path E2wxApp::GetResDir() const { return this->resdir; } -const std::string E2wxApp::GetID() const { +const wxString E2wxApp::GetID() const { return this->id; } @@ -260,8 +277,8 @@ const std::filesystem::path E2wxApp::GetDocumentsDir() const { const std::filesystem::path E2wxApp::BuildLogFilePath() const { std::filesystem::path logfile = dirCache() / - std::filesystem::path(GetID()) / - std::filesystem::path("log"); + std::filesystem::path(GetID().t_str()) / + std::filesystem::path(wxT("log")); std::filesystem::create_directories(logfile); logfile = std::filesystem::canonical(logfile); diff --git a/src/E2wxApp.h b/src/E2wxApp.h index 10d8312..9d7bc23 100644 --- a/src/E2wxApp.h +++ b/src/E2wxApp.h @@ -21,33 +21,55 @@ #ifndef E2WXAPP_H #define E2WXAPP_H + + #include #include +#include #include -#include #include #include -#include + + + +class Emulator; + + + +class EmuTimer : public wxTimer { + Emulator *emu; + +public: + EmuTimer(Emulator *e); + virtual ~EmuTimer(); + + void Notify() override; + + void begin(); +}; + + class E2wxApp : public wxApp { - const std::string id; + const wxString id; const wxString version; std::filesystem::path logfile; std::filesystem::path resdir; std::filesystem::path conffile; std::filesystem::path confdir; std::filesystem::path docsdir; + wxString arg_configfile; + EmuTimer *emu_timer; + Emulator *emu; const std::filesystem::path BuildLogFilePath() const; void InitBoostLog(); public: - static std::promise barrier_to_init; - E2wxApp(); virtual ~E2wxApp(); - const std::string GetID() const; + const wxString GetID() const; const wxString GetVersion() const; const std::filesystem::path GetLogFile() const; const std::filesystem::path GetResDir() const; @@ -58,10 +80,12 @@ public: virtual bool OnInit() override; virtual int OnExit() override; virtual void OnFatalException() override; -// virtual void OnInitCmdLine(wxCmdLineParser& parser) override; -// virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override; + virtual void OnInitCmdLine(wxCmdLineParser& parser) override; + virtual bool OnCmdLineParsed(wxCmdLineParser& parser) override; }; wxDECLARE_APP(E2wxApp); + + #endif /* E2WXAPP_H */ diff --git a/src/emulator.cpp b/src/emulator.cpp index 3be9b71..43733fc 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -32,6 +32,8 @@ timable(0), // No ticked object (NULL pointer) quit(false), repeat(false), keysDown(0), +skip(0), +prev_ms(SDL_GetTicks()), command(false), pendingCommandExit(false) { } @@ -162,49 +164,11 @@ void Emulator::handleAnyPendingEvents() { - - - - // The core of this Apple int Emulator::run() { - 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(); - handleRepeatKey(); - } - - // People who have too many press releases should be referred to as - // keyboards - - 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 = 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); - if (0 < delta_ms && delta_ms <= EXPECTED_MS) { - SDL_Delay(delta_ms); - } - - } - - // 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(); - } + tick(); } return 0; } @@ -212,6 +176,54 @@ int Emulator::run() { +void Emulator::tick() { + if (this->timable) { + this->timable->tick(); // this runs the emulator! + handleRepeatKey(); + } + + // People who have too many press releases should be referred to as + // keyboards + + if (CHECK_EVERY_CYCLE <= ++this->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 + this->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() - this->prev_ms); + if (0 < delta_ms && delta_ms <= EXPECTED_MS) { + SDL_Delay(delta_ms); + } + + } + + // Display the current estimate of the emulator's actual speed + // performance + this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms)); + + this->prev_ms = SDL_GetTicks(); + } +} + + + +void Emulator::tick50ms() { + if (this->timable) { + for (int i = 0; i < CHECK_EVERY_CYCLE; ++i) { + this->timable->tick(); // this runs the emulator! + handleRepeatKey(); + } + } + handleAnyPendingEvents(); + this->screenImage.displayHz(CHECK_CYCLES_K / (SDL_GetTicks() - this->prev_ms)); + this->prev_ms = SDL_GetTicks(); + // TODO: how to check this->quit ? +} diff --git a/src/emulator.h b/src/emulator.h index e0270e8..322e782 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -52,10 +52,14 @@ class Emulator int keysDown; int rept; unsigned char lastKeyDown; + int skip; + Uint32 prev_ms; bool command; bool pendingCommandExit; std::string cmdline; + void tick(); + void dispatchKeypress(const SDL_KeyboardEvent& keyEvent); void dispatchKeyUp(const SDL_KeyboardEvent& keyEvent); void cmdKey(const SDL_KeyboardEvent& keyEvent); @@ -80,6 +84,7 @@ public: void quitIfSafe(); virtual int run(); + void tick50ms(); }; #endif diff --git a/src/main.cpp b/src/main.cpp index c7bb6c8..5adc52e 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,7 @@ /* epple2 - Copyright (C) 2008, 2022 by Christopher A. Mosher + + Copyright (C) 2008, 2022 by Christopher A. Mosher, https://mosher.mine.nu https://github.com/cmosher01 This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -16,81 +17,16 @@ along with this program. If not, see . */ -#include "e2const.h" -#include "emulator.h" -#include "configep2.h" #include "gui.h" #include "e2const.h" -#include "E2wxApp.h" #include -#include -#include -#include #include #include #include -#include + #include -#include - -using namespace std::chrono_literals; - -static std::string parse_args(int argc, char* argv[]) { - if (argc > 2) { - throw std::runtime_error("usage: epple2 [config-file]" ); - } - - if (argc <= 1) { - return std::string(); - } - - return std::string(argv[1]); -} - - -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; - const std::future_status fut = barrier_to_app_init.wait_for(10s); - if (fut == std::future_status::timeout) { - std::cerr << "timed-out waiting for wx to finish initializing" << std::endl; - return 1; - } - std::cout << "wx init finished" << std::endl; - - std::unique_ptr emu(new Emulator()); - - Config cfg(config_file); - emu->config(cfg); - - emu->init(); - - const int ret = emu->run(); - - if (wxApp::GetInstance() != nullptr) { - wxApp::GetInstance()->ExitMainLoop(); - } - thread_wx.join(); - - return ret; -} - #ifdef __cplusplus @@ -106,9 +42,7 @@ int main(int argc, char *argv[]) { throw std::runtime_error("bad constant in e2const.h" ); } - const std::string config_file = parse_args(argc, argv); + GUI gui; - const int ret = runSdl(config_file); - - return ret; + return wxEntry(argc, argv); }