diff --git a/rwgame/RWGame.cpp b/rwgame/RWGame.cpp index d1a9a5d8..94094082 100644 --- a/rwgame/RWGame.cpp +++ b/rwgame/RWGame.cpp @@ -35,6 +35,7 @@ StdOutReciever logPrinter; RWGame::RWGame(int argc, char* argv[]) : config("openrw.ini") , state(nullptr), world(nullptr), renderer(nullptr), script(nullptr), + window(nullptr), work(nullptr), debugScript(false), inFocus(true), showDebugStats(false), showDebugPaths(false), showDebugPhysics(false), accum(0.f), timescale(1.f) @@ -90,8 +91,11 @@ RWGame::RWGame(int argc, char* argv[]) if (SDL_Init(SDL_INIT_VIDEO) < 0) throw std::runtime_error("Failed to initialize SDL2!"); - window.create(w, h, fullscreen); - window.hideCursor(); + window = new GameWindow(); + window->create(w, h, fullscreen); + window->hideCursor(); + + work = new WorkContext(); log.addReciever(&logPrinter); log.info("Game", "Game directory: " + config.getGameDataPath()); @@ -101,7 +105,7 @@ RWGame::RWGame(int argc, char* argv[]) throw std::runtime_error("Invalid game directory path: " + config.getGameDataPath()); } - data = new GameData(&log, &work, config.getGameDataPath()); + data = new GameData(&log, work, config.getGameDataPath()); // Initalize all the archives. data->loadIMG("/models/gta3"); @@ -168,10 +172,30 @@ RWGame::RWGame(int argc, char* argv[]) RWGame::~RWGame() { + log.info("Game", "Beginning cleanup"); + + log.info("Game", "Stopping work queue"); + work->stop(); + + log.info("Game", "Cleaning up scripts"); delete script; + + log.info("Game", "Cleaning up renderer"); delete renderer; + + log.info("Game", "Cleaning up world"); delete world; + + log.info("Game", "Cleaning up state"); delete state; + + log.info("Game", "Cleaning up window"); + delete window; + + log.info("Game", "Cleaning up work queue"); + delete work; + + log.info("Game", "Done cleaning up"); } void RWGame::newGame() @@ -183,7 +207,7 @@ void RWGame::newGame() } state = new GameState(); - world = new GameWorld(&log, &work, data); + world = new GameWorld(&log, work, data); world->dynamicsWorld->setDebugDrawer(debug); // Associate the new world with the new state and vice versa @@ -294,8 +318,8 @@ int RWGame::run() { last_clock_time = clock.now(); - // Loop until the window is closed or we run out of state. - while (window.isOpen() && StateManager::get().states.size()) { + // Loop until we run out of states. + while (StateManager::get().states.size()) { State* state = StateManager::get().states.back(); RW_PROFILE_FRAME_BOUNDARY(); @@ -305,7 +329,7 @@ int RWGame::run() while (SDL_PollEvent(&event)) { switch (event.type) { case SDL_QUIT: - window.close(); + StateManager::get().clear(); break; case SDL_WINDOWEVENT: @@ -343,14 +367,14 @@ int RWGame::run() RW_PROFILE_BEGIN("Update"); if ( accum >= GAME_TIMESTEP ) { - RW_PROFILE_BEGIN("state"); - StateManager::get().tick(GAME_TIMESTEP); - RW_PROFILE_END(); - if (StateManager::get().states.size() == 0) { break; } + RW_PROFILE_BEGIN("state"); + StateManager::get().tick(GAME_TIMESTEP); + RW_PROFILE_END(); + RW_PROFILE_BEGIN("engine"); tick(GAME_TIMESTEP); RW_PROFILE_END(); @@ -385,7 +409,7 @@ int RWGame::run() renderProfile(); - window.swap(); + window->swap(); } if( httpserver_thread ) @@ -483,7 +507,7 @@ void RWGame::render(float alpha, float time) getRenderer()->getRenderer()->swap(); - glm::ivec2 windowSize = window.getSize(); + glm::ivec2 windowSize = window->getSize(); renderer->setViewport(windowSize.x, windowSize.y); ViewCamera viewCam; diff --git a/rwgame/RWGame.hpp b/rwgame/RWGame.hpp index 42c353b7..fc71ce77 100644 --- a/rwgame/RWGame.hpp +++ b/rwgame/RWGame.hpp @@ -28,11 +28,11 @@ class RWGame GameRenderer* renderer; ScriptMachine* script; // Background worker - WorkContext work; + WorkContext *work; bool debugScript; HttpServer* httpserver = nullptr; std::thread* httpserver_thread = nullptr; - GameWindow window; + GameWindow *window; std::chrono::steady_clock clock; std::chrono::steady_clock::time_point last_clock_time; @@ -79,7 +79,7 @@ public: GameWindow& getWindow() { - return window; + return *window; } ScriptMachine* getScript() const diff --git a/rwgame/State.hpp b/rwgame/State.hpp index 03618497..d0f089a0 100644 --- a/rwgame/State.hpp +++ b/rwgame/State.hpp @@ -80,6 +80,11 @@ struct StateManager } std::deque states; + + void clear() + { + states.clear(); + } void enter(State* state) { diff --git a/rwgame/menustate.cpp b/rwgame/menustate.cpp index 98254e7b..9ca737dd 100644 --- a/rwgame/menustate.cpp +++ b/rwgame/menustate.cpp @@ -20,7 +20,7 @@ void MenuState::enterMainMenu() m->addEntry(Menu::lambda("Load Game", [=] { enterLoadMenu(); })); m->addEntry(Menu::lambda("Test", [=] { StateManager::get().enter(new IngameState(game, true, "test")); })); m->addEntry(Menu::lambda("Options", [] { RW_UNIMPLEMENTED("Options Menu"); })); - m->addEntry(Menu::lambda("Exit", [=] { getWindow().close(); })); + m->addEntry(Menu::lambda("Exit", [] { StateManager::get().clear(); })); this->enterMenu(m); } diff --git a/rwgame/pausestate.cpp b/rwgame/pausestate.cpp index f44b111b..69bd7169 100644 --- a/rwgame/pausestate.cpp +++ b/rwgame/pausestate.cpp @@ -10,7 +10,7 @@ PauseState::PauseState(RWGame* game) m->offset = glm::vec2( 200.f, 200.f ); m->addEntry(Menu::lambda("Continue", [] { StateManager::get().exit(); })); m->addEntry(Menu::lambda("Options", [] { std::cout << "Options" << std::endl; })); - m->addEntry(Menu::lambda("Exit", [&] { getWindow().close(); })); + m->addEntry(Menu::lambda("Exit", [] { StateManager::get().clear(); })); this->enterMenu(m); } diff --git a/rwlib/source/job/WorkContext.cpp b/rwlib/source/job/WorkContext.cpp index 76b55c58..73784048 100644 --- a/rwlib/source/job/WorkContext.cpp +++ b/rwlib/source/job/WorkContext.cpp @@ -12,20 +12,21 @@ void WorkContext::workNext() { WorkJob* j = nullptr; - _inMutex.lock(); - if( ! _workQueue.empty() ) { - j = _workQueue.front(); - _workQueue.pop(); + { + std::lock_guard guard( _inMutex ); + + if( ! _workQueue.empty() ) { + j = _workQueue.front(); + _workQueue.pop(); + } } - _inMutex.unlock(); if( j == nullptr ) return; j->work(); - - _outMutex.lock(); + + std::lock_guard guard( _outMutex ); _completeQueue.push(j); - _outMutex.unlock(); } void WorkContext::update() diff --git a/rwlib/source/job/WorkContext.hpp b/rwlib/source/job/WorkContext.hpp index 0d074b0d..c5f0756a 100644 --- a/rwlib/source/job/WorkContext.hpp +++ b/rwlib/source/job/WorkContext.hpp @@ -5,8 +5,11 @@ #include #include #include +#include +#include #include #include +#include class WorkContext; @@ -16,7 +19,7 @@ class LoadWorker public: - bool _running; + std::atomic _running; std::thread _thread; void start(); @@ -66,26 +69,32 @@ class GameWorld; */ class WorkContext { + std::unique_ptr _worker; + std::queue _workQueue; std::queue _completeQueue; - LoadWorker _worker; - std::mutex _inMutex; std::mutex _outMutex; public: WorkContext() - : _worker(this) { } + : _worker(new LoadWorker(this)) { } void queueJob( WorkJob* job ) { - std::lock_guard guard(_inMutex); + std::lock_guard guard( _inMutex ); _workQueue.push( job ); } - // Called by the worker thread - don't touch; + void stop() + { + // Stop serving the queue. + _worker.reset(nullptr); + } + + // Called by the worker thread - don't touch void workNext(); const std::queue getWorkQueue() const { return _workQueue; }