From 20ef6837446d58da9406e10bc6536fb7b48e89a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Thu, 2 Dec 2021 17:28:59 +0200 Subject: [PATCH] Use Timer and cleanup some code in Context --- src/openrct2-ui/title/TitleSequencePlayer.cpp | 3 +- src/openrct2/Context.cpp | 83 +++++++++---------- src/openrct2/Context.h | 14 ++-- 3 files changed, 46 insertions(+), 54 deletions(-) diff --git a/src/openrct2-ui/title/TitleSequencePlayer.cpp b/src/openrct2-ui/title/TitleSequencePlayer.cpp index 6acaf96dc7..51d46c8e7d 100644 --- a/src/openrct2-ui/title/TitleSequencePlayer.cpp +++ b/src/openrct2-ui/title/TitleSequencePlayer.cpp @@ -249,7 +249,8 @@ private: case TitleScript::Wait: // The waitCounter is measured in 25-ms game ticks. Previously it was seconds * 40 ticks/second, now it is ms / // 25 ms/tick - _waitCounter = std::max(1, command.Milliseconds / static_cast(GAME_UPDATE_TIME_MS)); + _waitCounter = std::max( + 1, command.Milliseconds / static_cast(GAME_UPDATE_TIME_MS * 1000.0f)); break; case TitleScript::Location: { diff --git a/src/openrct2/Context.cpp b/src/openrct2/Context.cpp index a1417b9d53..d161ec2c81 100644 --- a/src/openrct2/Context.cpp +++ b/src/openrct2/Context.cpp @@ -37,6 +37,7 @@ #include "core/MemoryStream.h" #include "core/Path.hpp" #include "core/String.hpp" +#include "core/Timer.hpp" #include "drawing/IDrawingEngine.h" #include "drawing/Image.h" #include "drawing/LightFX.h" @@ -124,11 +125,10 @@ namespace OpenRCT2 std::unique_ptr _painter; bool _initialised = false; - bool _isWindowMinimised = false; - uint32_t _lastTick = 0; + + Timer _timer; float _accumulator = 0.0f; float _timeScale = 1.0f; - uint32_t _lastUpdateTime = 0; bool _variableFrame = false; // If set, will end the OpenRCT2 game loop. Intentionally private to this module so that the flag can not be set back to @@ -948,12 +948,8 @@ namespace OpenRCT2 RunGameLoop(); } - bool ShouldRunVariableFrame() + bool ShouldDraw() { - if (!gConfigGeneral.uncap_fps) - return false; - if (gGameSpeed > 4) - return false; if (gOpenRCT2Headless) return false; if (_uiContext->IsMinimised()) @@ -961,6 +957,17 @@ namespace OpenRCT2 return true; } + bool ShouldRunVariableFrame() + { + if (!ShouldDraw()) + return false; + if (!gConfigGeneral.uncap_fps) + return false; + if (gGameSpeed > 4) + return false; + return true; + } + /** * Run the main game loop until the finished flag is set. */ @@ -988,11 +995,13 @@ namespace OpenRCT2 void RunFrame() { + const auto deltaTime = _timer.GetElapsed(); + _timer.Restart(); + // Make sure we catch the state change and reset it. bool useVariableFrame = ShouldRunVariableFrame(); if (_variableFrame != useVariableFrame) { - _lastTick = 0; _variableFrame = useVariableFrame; // Switching from variable to fixed frame requires reseting @@ -1004,32 +1013,25 @@ namespace OpenRCT2 if (useVariableFrame) { - RunVariableFrame(); + RunVariableFrame(deltaTime); } else { - RunFixedFrame(); + RunFixedFrame(deltaTime); } } - void RunFixedFrame() + void RunFixedFrame(float deltaTime) { - uint32_t currentTick = platform_get_ticks(); - - if (_lastTick == 0) - { - _lastTick = currentTick; - } - - float elapsed = (currentTick - _lastTick) * _timeScale; - _lastTick = currentTick; - _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); + float scaledDeltaTime = deltaTime * _timeScale; + _accumulator = std::min(_accumulator + scaledDeltaTime, GAME_UPDATE_MAX_THRESHOLD); _uiContext->ProcessMessages(); if (_accumulator < GAME_UPDATE_TIME_MS) { - platform_sleep(GAME_UPDATE_TIME_MS - _accumulator - 1); + const auto sleepTimeSec = (GAME_UPDATE_TIME_MS - _accumulator); + platform_sleep(static_cast(sleepTimeSec * 1000.f)); return; } @@ -1043,7 +1045,7 @@ namespace OpenRCT2 _accumulator -= GAME_UPDATE_TIME_MS; } - if (!_isWindowMinimised && !gOpenRCT2Headless) + if (ShouldDraw()) { _drawingEngine->BeginDraw(); _painter->Paint(*_drawingEngine); @@ -1051,30 +1053,20 @@ namespace OpenRCT2 } } - void RunVariableFrame() + void RunVariableFrame(float deltaTime) { - uint32_t currentTick = platform_get_ticks(); - + const bool shouldDraw = ShouldDraw(); auto& tweener = EntityTweener::Get(); - bool draw = !_isWindowMinimised && !gOpenRCT2Headless; - if (_lastTick == 0) - { - tweener.Reset(); - _lastTick = currentTick; - } - - float elapsed = (currentTick - _lastTick) * _timeScale; - - _lastTick = currentTick; - _accumulator = std::min(_accumulator + elapsed, static_cast(GAME_UPDATE_MAX_THRESHOLD)); + float scaledDeltaTime = deltaTime * _timeScale; + _accumulator = std::min(_accumulator + scaledDeltaTime, GAME_UPDATE_MAX_THRESHOLD); _uiContext->ProcessMessages(); while (_accumulator >= GAME_UPDATE_TIME_MS) { // Get the original position of each sprite - if (draw) + if (shouldDraw) tweener.PreTick(); Update(); @@ -1085,13 +1077,13 @@ namespace OpenRCT2 _accumulator -= GAME_UPDATE_TIME_MS; // Get the next position of each sprite - if (draw) + if (shouldDraw) tweener.PostTick(); } - if (draw) + if (shouldDraw) { - const float alpha = std::min(_accumulator / static_cast(GAME_UPDATE_TIME_MS), 1.0f); + const float alpha = std::min(_accumulator / GAME_UPDATE_TIME_MS, 1.0f); tweener.Tween(alpha); _drawingEngine->BeginDraw(); @@ -1102,10 +1094,9 @@ namespace OpenRCT2 void Update() { - uint32_t currentUpdateTime = platform_get_ticks(); - - gCurrentDeltaTime = std::min(currentUpdateTime - _lastUpdateTime, 500); - _lastUpdateTime = currentUpdateTime; + // TODO: This variable has been never "variable" in time, some code expects + // this to be 40Hz (25 ms). Refactor this once the UI is decoupled. + gCurrentDeltaTime = static_cast(GAME_UPDATE_TIME_MS * 1000.0f); if (game_is_not_paused()) { diff --git a/src/openrct2/Context.h b/src/openrct2/Context.h index cbb4529068..bf2c055507 100644 --- a/src/openrct2/Context.h +++ b/src/openrct2/Context.h @@ -169,17 +169,17 @@ namespace OpenRCT2 [[nodiscard]] IContext* GetContext(); } // namespace OpenRCT2 -enum +namespace { - // The game update interval in milliseconds, (1000 / 40fps) = 25ms - GAME_UPDATE_TIME_MS = 25, // The number of logical update / ticks per second. - GAME_UPDATE_FPS = 40, + constexpr uint32_t GAME_UPDATE_FPS = 40; // The maximum amount of updates in case rendering is slower - GAME_MAX_UPDATES = 4, + constexpr uint32_t GAME_MAX_UPDATES = 4; + // The game update interval in milliseconds, (1000 / 40fps) = 25ms + constexpr float GAME_UPDATE_TIME_MS = 1.0f / GAME_UPDATE_FPS; // The maximum threshold to advance. - GAME_UPDATE_MAX_THRESHOLD = GAME_UPDATE_TIME_MS * GAME_MAX_UPDATES, -}; + constexpr float GAME_UPDATE_MAX_THRESHOLD = GAME_UPDATE_TIME_MS * GAME_MAX_UPDATES; +}; // namespace constexpr float GAME_MIN_TIME_SCALE = 0.1f; constexpr float GAME_MAX_TIME_SCALE = 5.0f;