Index: source/main.cpp =================================================================== --- source/main.cpp +++ source/main.cpp @@ -176,8 +176,10 @@ g_Shutdown = ShutdownType::RestartAsAtlas; } +namespace +{ // main app message handler -static InReaction MainInputHandler(const SDL_Event_* ev) +InReaction MainInputHandler(const SDL_Event_* ev) { switch(ev->ev.type) { @@ -251,7 +253,7 @@ // dispatch all pending events to the various receivers. -static void PumpEvents() +void PumpEvents() { ScriptRequest rq(g_GUI->GetScriptInterface()); @@ -278,7 +280,7 @@ * Optionally throttle the render frequency in order to * prevent 100% workload of the currently used CPU core. */ -inline static void LimitFPS() +void LimitFPS() { if (g_VideoMode.IsVSyncEnabled()) return; @@ -300,7 +302,7 @@ lastFrameTime = std::chrono::high_resolution_clock::now(); } -static int ProgressiveLoad() +int ProgressiveLoad() { PROFILE3("progressive load"); @@ -346,7 +348,7 @@ } -static void RendererIncrementalLoad() +void RendererIncrementalLoad() { PROFILE3("renderer incremental load"); @@ -360,122 +362,122 @@ while (more && timer_Time() - startTime < maxTime); } -static void Frame(RL::Interface* rlInterface) +void Frame(const bool isVisual, RL::Interface* rlInterface) { - g_Profiler2.RecordFrameStart(); - PROFILE2("frame"); - g_Profiler2.IncrementFrameNumber(); - PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); - - // get elapsed time - const double time = timer_Time(); - g_frequencyFilter->Update(time); - // .. old method - "exact" but contains jumps -#if 0 - static double last_time; - const double time = timer_Time(); - const float TimeSinceLastFrame = (float)(time-last_time); - last_time = time; - ONCE(return); // first call: set last_time and return - - // .. new method - filtered and more smooth, but errors may accumulate -#else - const float realTimeSinceLastFrame = 1.0 / g_frequencyFilter->SmoothedFrequency(); -#endif - ENSURE(realTimeSinceLastFrame > 0.0f); + const bool runProfiler{isVisual || !rlInterface}; + if (runProfiler) + g_Profiler2.RecordFrameStart(); + const std::optional profileRegion{[runProfiler]() -> std::optional + { + if (runProfiler) + return std::make_optional("frame"); + return std::nullopt; + }()}; + if (runProfiler) + { + g_Profiler2.IncrementFrameNumber(); + PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); + } + + const float realTimeSinceLastFrame{isVisual ? [] + { + g_frequencyFilter->Update(timer_Time()); + const float time = static_cast(1.0 / g_frequencyFilter->SmoothedFrequency()); + ENSURE(time > 0.0f); + return time; + }() : 0.0f}; // Decide if update is necessary - const bool needUpdate{g_app_has_focus || g_NetClient || !g_PauseOnFocusLoss}; + const bool needUpdate{!isVisual || g_app_has_focus || g_NetClient || !g_PauseOnFocusLoss}; - // If we are not running a multiplayer game, disable updates when the game is - // minimized or out of focus and relinquish the CPU a bit, in order to make - // debugging easier. - if (!needUpdate) + if (isVisual) { - PROFILE3("non-focus delay"); - // don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored - SDL_Delay(10); - } + // If we are not running a multiplayer game, disable updates when the game is + // minimized or out of focus and relinquish the CPU a bit, in order to make + // debugging easier. + if (!needUpdate) + { + PROFILE3("non-focus delay"); + // don't use SDL_WaitEvent: don't want the main loop to freeze until app focus is restored + SDL_Delay(10); + } - // this scans for changed files/directories and reloads them, thus - // allowing hotloading (changes are immediately assimilated in-game). - ReloadChangedFiles(); + // this scans for changed files/directories and reloads them, thus + // allowing hotloading (changes are immediately assimilated in-game). + ReloadChangedFiles(); - ProgressiveLoad(); + ProgressiveLoad(); - RendererIncrementalLoad(); + RendererIncrementalLoad(); - PumpEvents(); + PumpEvents(); - // if the user quit by closing the window, the GL context will be broken and - // may crash when we call Render() on some drivers, so leave this loop - // before rendering - if (g_Shutdown != ShutdownType::None) - return; + // if the user quit by closing the window, the GL context will be broken and + // may crash when we call Render() on some drivers, so leave this loop + // before rendering + if (g_Shutdown != ShutdownType::None) + return; - // respond to pumped resize events - if (g_ResizedW || g_ResizedH) - { - g_VideoMode.ResizeWindow(g_ResizedW, g_ResizedH); - g_ResizedW = g_ResizedH = 0; + // respond to pumped resize events + if (g_ResizedW || g_ResizedH) + { + g_VideoMode.ResizeWindow(g_ResizedW, g_ResizedH); + g_ResizedW = g_ResizedH = 0; + } } if (g_NetClient) g_NetClient->Poll(); - g_GUI->TickObjects(); + if (isVisual) + g_GUI->TickObjects(); if (rlInterface) rlInterface->TryApplyMessage(); if (g_Game && g_Game->IsGameStarted() && needUpdate) { - if (!rlInterface) - g_Game->Update(realTimeSinceLastFrame); + if (g_Game->GetTurnManager() && !rlInterface) + { + if (isVisual) + g_Game->Update(realTimeSinceLastFrame); + else if(g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1)) + { + static u32 turn = 0; + debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); + } + } - g_Game->GetView()->Update(float(realTimeSinceLastFrame)); + if (isVisual) + g_Game->GetView()->Update(realTimeSinceLastFrame); } - // Keep us connected to any XMPP servers - if (g_XmppClient) - g_XmppClient->recv(); - - g_UserReporter.Update(); - - g_Console->Update(realTimeSinceLastFrame); - - if (g_SoundManager) - g_SoundManager->IdleTask(); - - g_Renderer.RenderFrame(true); - - g_Profiler.Frame(); + if (isVisual) + { + // Keep us connected to any XMPP servers + if (g_XmppClient) + g_XmppClient->recv(); - LimitFPS(); -} + g_UserReporter.Update(); -static void NonVisualFrame() -{ - g_Profiler2.RecordFrameStart(); - PROFILE2("frame"); - g_Profiler2.IncrementFrameNumber(); - PROFILE2_ATTR("%d", g_Profiler2.GetFrameNumber()); + g_Console->Update(realTimeSinceLastFrame); - if (g_NetClient) - g_NetClient->Poll(); + if (g_SoundManager) + g_SoundManager->IdleTask(); - static u32 turn = 0; - if (g_Game && g_Game->IsGameStarted() && g_Game->GetTurnManager()) - if (g_Game->GetTurnManager()->Update(DEFAULT_TURN_LENGTH, 1)) - debug_printf("Turn %u (%u)...\n", turn++, DEFAULT_TURN_LENGTH); + g_Renderer.RenderFrame(true); + } - g_Profiler.Frame(); + if (runProfiler) + g_Profiler.Frame(); - if (g_Game->IsGameFinished()) + if (isVisual) + LimitFPS(); + else if (!rlInterface && g_Game->IsGameFinished()) QuitEngine(); } -static void MainControllerInit() +void MainControllerInit() { // add additional input handlers only needed by this controller: @@ -483,12 +485,12 @@ in_add_handler(MainInputHandler); } -static void MainControllerShutdown() +void MainControllerShutdown() { in_reset_handlers(); } -static std::optional CreateRLInterface(const CmdLineArgs& args) +std::optional CreateRLInterface(const CmdLineArgs& args) { if (!args.Has("rl-interface")) return std::nullopt; @@ -505,7 +507,7 @@ // moved into a helper function to ensure args is destroyed before // exit(), which may result in a memory leak. -static void RunGameOrAtlas(const PS::span argv) +void RunGameOrAtlas(const PS::span argv) { const CmdLineArgs args(argv); @@ -696,14 +698,7 @@ }()}; while (g_Shutdown == ShutdownType::None) - { - if (isVisual) - Frame(rlInterface ? &*rlInterface : nullptr); - else if(rlInterface) - rlInterface->TryApplyMessage(); - else - NonVisualFrame(); - } + Frame(isVisual, rlInterface ? &*rlInterface : nullptr); // Do not install mods again in case of restart (typically from the mod selector) modsToInstall.clear(); @@ -725,6 +720,7 @@ Threading::TaskManager::Instance().ClearQueue(); CXeromyces::Terminate(); } +} // anonymous namespace #if OS_ANDROID // In Android we compile the engine as a shared library, not an executable,