diff --git a/src/FpsLimit.h b/src/FpsLimit.h index cd821e3b2..d49c23142 100644 --- a/src/FpsLimit.h +++ b/src/FpsLimit.h @@ -8,7 +8,11 @@ struct FpsLimitExplicit { float value; }; -using FpsLimit = std::variant; +using SimFpsLimit = std::variant; +struct FpsLimitFollowDraw +{ +}; +using FpsLimit = std::variant; struct DrawLimitDisplay { diff --git a/src/PowderToySDL.cpp b/src/PowderToySDL.cpp index c3d4dc750..e455a55dc 100644 --- a/src/PowderToySDL.cpp +++ b/src/PowderToySDL.cpp @@ -477,6 +477,7 @@ void EngineProcess() EventProcess(event); } + std::optional delay; { auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); auto effectiveDrawLimit = engine.GetEffectiveDrawCap(); @@ -485,10 +486,6 @@ void EngineProcess() engine.Tick(); engine.Draw(); drawSchedule.SetNow(nowNs); - if (effectiveDrawLimit) - { - drawSchedule.Arm(float(*effectiveDrawLimit)); - } SDLSetScreen(); blit(engine.g->Data()); } @@ -496,14 +493,24 @@ void EngineProcess() { engine.SimTick(); } + if (effectiveDrawLimit) + { + delay = drawSchedule.Arm(float(*effectiveDrawLimit)) / UINT64_C(1'000'000); + } } + auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + if (!std::holds_alternative(fpsLimit)) { - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + delay.reset(); auto nowNs = uint64_t(SDL_GetTicks()) * UINT64_C(1'000'000); tickSchedule.SetNow(nowNs); if (auto *fpsLimitExplicit = std::get_if(&fpsLimit)) { - SDL_Delay(tickSchedule.Arm(fpsLimitExplicit->value) / UINT64_C(1'000'000)); + delay = tickSchedule.Arm(fpsLimitExplicit->value) / UINT64_C(1'000'000); } } + if (delay.has_value()) + { + SDL_Delay(std::max(*delay, UINT64_C(1))); + } } diff --git a/src/gui/game/GameController.cpp b/src/gui/game/GameController.cpp index c8256a651..7ba8adfcc 100644 --- a/src/gui/game/GameController.cpp +++ b/src/gui/game/GameController.cpp @@ -970,6 +970,11 @@ void GameController::SetZoomPosition(ui::Point position) gameModel->SetZoomWindowPosition(zoomWindowPosition); } +bool GameController::GetPaused() const +{ + return gameModel->GetPaused(); +} + void GameController::SetPaused(bool pauseState) { gameModel->SetPaused(pauseState); @@ -1730,7 +1735,7 @@ void GameController::AfterSimDraw() bool GameController::ThreadedRenderingAllowed() { - return gameModel->GetThreadedRendering() && !commandInterface->HaveSimGraphicsEventHandlers(); + return gameModel->GetThreadedRendering() && !GetPaused() && !commandInterface->HaveSimGraphicsEventHandlers(); } void GameController::SetToolIndex(ByteString identifier, std::optional index) diff --git a/src/gui/game/GameController.h b/src/gui/game/GameController.h index fa3531ad8..90ad43a36 100644 --- a/src/gui/game/GameController.h +++ b/src/gui/game/GameController.h @@ -117,6 +117,7 @@ public: void CopyRegion(ui::Point point1, ui::Point point2); void CutRegion(ui::Point point1, ui::Point point2); void Update(); + bool GetPaused() const; void SetPaused(bool pauseState); void SetPaused(); void SetDecoration(bool decorationState); diff --git a/src/gui/game/GameModel.cpp b/src/gui/game/GameModel.cpp index 45f12a40a..840170baf 100644 --- a/src/gui/game/GameModel.cpp +++ b/src/gui/game/GameModel.cpp @@ -1018,7 +1018,7 @@ void GameModel::SetPaused(bool pauseState) notifyPausedChanged(); } -bool GameModel::GetPaused() +bool GameModel::GetPaused() const { return sim->sys_pause?true:false; } diff --git a/src/gui/game/GameModel.h b/src/gui/game/GameModel.h index 9d5edd47e..085e41a4d 100644 --- a/src/gui/game/GameModel.h +++ b/src/gui/game/GameModel.h @@ -237,7 +237,7 @@ public: void AddObserver(GameView * observer); void SetPaused(bool pauseState); - bool GetPaused(); + bool GetPaused() const; void SetDecoration(bool decorationState); bool GetDecoration(); void SetAHeatEnable(bool aHeat); diff --git a/src/gui/game/GameView.cpp b/src/gui/game/GameView.cpp index b2c1a9bbf..5e1f83710 100644 --- a/src/gui/game/GameView.cpp +++ b/src/gui/game/GameView.cpp @@ -768,6 +768,7 @@ void GameView::NotifyUserChanged(GameModel * sender) void GameView::NotifyPausedChanged(GameModel * sender) { pauseButton->SetToggleState(sender->GetPaused()); + ApplySimFpsLimit(); } void GameView::NotifyToolTipChanged(GameModel * sender) @@ -2542,7 +2543,12 @@ void GameView::OnDraw() { //FPS and some version info StringBuilder fpsInfo; - fpsInfo << Format::Precision(2) << "FPS: " << ui::Engine::Ref().GetFps(); + auto fps = 0.f; + if (!c->GetPaused()) + { + fps = ui::Engine::Ref().GetFps(); + } + fpsInfo << Format::Precision(2) << "FPS: " << fps; if (showDebug) { @@ -2563,14 +2569,13 @@ void GameView::OnDraw() { fpsInfo << "\nSimulation"; fpsInfo << "\n FPS cap: "; - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); - if (std::holds_alternative(fpsLimit)) + if (std::holds_alternative(simFpsLimit)) { fpsInfo << "none"; } else { - fpsInfo << std::get(fpsLimit).value; + fpsInfo << std::get(simFpsLimit).value; } } if (c->GetDebugFlags() & DEBUG_RENHUD) @@ -2811,3 +2816,25 @@ void GameView::WaitForRendererThread() return !rendererThreadOwnsRenderer; }); } + +void GameView::ApplySimFpsLimit() +{ + if (c->GetPaused()) + { + SetFpsLimit(FpsLimitFollowDraw{}); + } + else if (std::holds_alternative(simFpsLimit)) + { + SetFpsLimit(FpsLimitNone{}); + } + else + { + SetFpsLimit(std::get(simFpsLimit)); + } +} + +void GameView::SetSimFpsLimit(SimFpsLimit newSimFpsLimit) +{ + simFpsLimit = newSimFpsLimit; + ApplySimFpsLimit(); +} diff --git a/src/gui/game/GameView.h b/src/gui/game/GameView.h index be73ae504..539f455c8 100644 --- a/src/gui/game/GameView.h +++ b/src/gui/game/GameView.h @@ -175,6 +175,9 @@ private: int foundParticles = 0; const RendererFrame *rendererFrame = nullptr; + SimFpsLimit simFpsLimit = FpsLimitExplicit{ 60.f }; + void ApplySimFpsLimit(); + public: GameView(); ~GameView(); @@ -278,4 +281,10 @@ public: void RenderSimulation(const RenderableSimulation &sim, bool handleEvents); void AfterSimDraw(const RenderableSimulation &sim); + + void SetSimFpsLimit(SimFpsLimit newSimFpsLimit); + SimFpsLimit GetSimFpsLimit() const + { + return simFpsLimit; + } }; diff --git a/src/gui/interface/Engine.cpp b/src/gui/interface/Engine.cpp index 95e797eec..e8eb02222 100644 --- a/src/gui/interface/Engine.cpp +++ b/src/gui/interface/Engine.cpp @@ -24,7 +24,6 @@ Engine::Engine(): mousexp_(0), mouseyp_(0) { - SetFpsLimit(FpsLimitExplicit{ 60.0f }); } Engine::~Engine() @@ -38,19 +37,9 @@ Engine::~Engine() } } -void Engine::SetFpsLimit(FpsLimit newFpsLimit) +void Engine::ApplyFpsLimit() { - fpsLimit = newFpsLimit; - ::SetFpsLimit(fpsLimit); - // Populate dt with whatever that makes any sort of sense. - if (auto *explicitFpsLimit = std::get_if(&fpsLimit)) - { - SetFps(explicitFpsLimit->value); - } - else - { - SetFps(1); - } + ::SetFpsLimit(GetFpsLimit()); } void Engine::Begin() @@ -110,7 +99,7 @@ void Engine::ShowWindow(Window * window) state_->DoBlur(); state_ = window; - + ApplyFpsLimit(); } void Engine::CloseWindowAndEverythingAbove(Window *window) @@ -153,11 +142,13 @@ int Engine::CloseWindow() mouseyp_ = mousey_; } ignoreEvents = true; + ApplyFpsLimit(); return 0; } else { state_ = nullptr; + ApplyFpsLimit(); return 1; } } @@ -179,7 +170,7 @@ void Engine::Tick() { if(state_ != nullptr) { - state_->DoTick(dt); + state_->DoTick(); state_->DoSimTick(); } @@ -241,19 +232,6 @@ void Engine::Draw() FrameIndex %= 7200; } -void Engine::SetFps(float fps) -{ - this->fps = fps; - if (std::holds_alternative(fpsLimit)) - { - this->dt = 60/fps; - } - else - { - this->dt = 1.0f; - } -} - void Engine::onKeyPress(int key, int scan, bool repeat, bool shift, bool ctrl, bool alt) { if (state_ && !ignoreEvents) @@ -396,3 +374,29 @@ std::optional Engine::GetEffectiveDrawCap() const } return effectiveDrawCap; } + +void Engine::SetFps(float newFps) +{ + if (state_) + { + return state_->SetFps(newFps); + } +} + +float Engine::GetFps() const +{ + if (state_) + { + return state_->GetFps(); + } + return 1; +} + +FpsLimit Engine::GetFpsLimit() const +{ + if (state_) + { + return state_->GetFpsLimit(); + } + return FpsLimitNone{}; +} diff --git a/src/gui/interface/Engine.h b/src/gui/interface/Engine.h index 1de1709d5..84b1f77ac 100644 --- a/src/gui/interface/Engine.h +++ b/src/gui/interface/Engine.h @@ -60,8 +60,8 @@ namespace ui void SimTick(); void Draw(); - void SetFps(float fps); - inline float GetFps() { return fps; } + void SetFps(float newFps); + float GetFps() const; inline int GetMouseButton() { return mouseb_; } inline int GetMouseX() { return mousex_; } @@ -75,11 +75,7 @@ namespace ui //inline State* GetState() { return state_; } inline Window* GetWindow() { return state_; } - void SetFpsLimit(FpsLimit newFpsLimit); - FpsLimit GetFpsLimit() const - { - return fpsLimit; - } + FpsLimit GetFpsLimit() const; DrawLimit drawingFrequencyLimit; Graphics * g; @@ -89,13 +85,11 @@ namespace ui unsigned int FrameIndex; private: - FpsLimit fpsLimit; bool textInput = false; int lastTextEditingStart = INT_MAX; - float dt; - float fps; + void ApplyFpsLimit(); std::deque windows; std::stack mousePositions; //Window* statequeued_; diff --git a/src/gui/interface/Window.cpp b/src/gui/interface/Window.cpp index ed9374683..3d71ade8f 100644 --- a/src/gui/interface/Window.cpp +++ b/src/gui/interface/Window.cpp @@ -26,6 +26,7 @@ Window::Window(Point _position, Point _size): destruct(false), stop(false) { + SetFps(1); } Window::~Window() @@ -228,7 +229,7 @@ void Window::DoDraw() } } -void Window::DoTick(float dt) +void Window::DoTick() { if (debugMode) return; @@ -610,3 +611,29 @@ void Window::Halt() halt = true; } +void Window::SetFps(float newFps) +{ + fps = newFps; + if (std::holds_alternative(fpsLimit)) + { + dt = 60/fps; + } + else + { + dt = 1.0f; + } +} + +void Window::SetFpsLimit(FpsLimit newFpsLimit) +{ + fpsLimit = newFpsLimit; + // Populate dt with whatever that makes any sort of sense. + if (auto *explicitFpsLimit = std::get_if(&fpsLimit)) + { + SetFps(explicitFpsLimit->value); + } + else + { + SetFps(1); + } +} diff --git a/src/gui/interface/Window.h b/src/gui/interface/Window.h index fba72edb8..d5247b3e6 100644 --- a/src/gui/interface/Window.h +++ b/src/gui/interface/Window.h @@ -1,6 +1,7 @@ #pragma once #include "common/String.h" #include "gui/interface/Point.h" +#include "FpsLimit.h" #include class Graphics; @@ -54,7 +55,7 @@ namespace ui virtual void DoInitialized(); virtual void DoExit(); - virtual void DoTick(float dt); + virtual void DoTick(); virtual void DoSimTick(); virtual void DoDraw(); virtual void DoFocus(); @@ -85,6 +86,16 @@ namespace ui void MakeActiveWindow(); void CloseActiveWindow(); Graphics * GetGraphics(); + void SetFps(float newFps); + float GetFps() const + { + return fps; + } + void SetFpsLimit(FpsLimit newFpsLimit); + FpsLimit GetFpsLimit() const + { + return fpsLimit; + } protected: ui::Button * okayButton; @@ -122,5 +133,8 @@ namespace ui bool destruct; bool stop; + float dt; + float fps; + FpsLimit fpsLimit = FpsLimitFollowDraw{}; }; } diff --git a/src/lua/LuaMisc.cpp b/src/lua/LuaMisc.cpp index 1d5126edc..9f9b2b6f1 100644 --- a/src/lua/LuaMisc.cpp +++ b/src/lua/LuaMisc.cpp @@ -197,10 +197,11 @@ static int debug(lua_State *L) static int fpsCap(lua_State *L) { + auto *lsi = GetLSI(); int acount = lua_gettop(L); if (acount == 0) { - auto fpsLimit = ui::Engine::Ref().GetFpsLimit(); + auto fpsLimit = lsi->window->GetSimFpsLimit(); if (std::holds_alternative(fpsLimit)) { lua_pushnumber(L, 2); @@ -218,10 +219,10 @@ static int fpsCap(lua_State *L) } if (fpscap == 2) { - ui::Engine::Ref().SetFpsLimit(FpsLimitNone{}); + lsi->window->SetSimFpsLimit(FpsLimitNone{}); return 0; } - ui::Engine::Ref().SetFpsLimit(FpsLimitExplicit{ fpscap }); + lsi->window->SetSimFpsLimit(FpsLimitExplicit{ fpscap }); return 0; } diff --git a/src/lua/LuaScriptInterface.h b/src/lua/LuaScriptInterface.h index 72a019cac..0ea66c294 100644 --- a/src/lua/LuaScriptInterface.h +++ b/src/lua/LuaScriptInterface.h @@ -14,11 +14,7 @@ namespace http class Request; } -namespace ui -{ - class Window; -} - +class GameView; class Graphics; class Renderer; class Simulation; @@ -82,7 +78,7 @@ public: GameModel *gameModel; GameController *gameController; - ui::Window *window; + GameView *window; Simulation *sim; Graphics *g;