Skip to content

fix(gui): Pace whole-screen fade loop through the frame pacer#2848

Open
bobtista wants to merge 2 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/fix/fade-loop-frame-pacer
Open

fix(gui): Pace whole-screen fade loop through the frame pacer#2848
bobtista wants to merge 2 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/fix/fade-loop-frame-pacer

Conversation

@bobtista

Copy link
Copy Markdown

Follow-up to #2840.

The whole-screen fade loop in GameLogic::tryStartNewGame paced itself with a hardcoded Sleep(33). This froze the frame pacer for the duration of the fade, so the frame-rate-decoupled transition step from #2056 (getBaseOverUpdateFpsRatio()) read a stale delta and advanced at a fixed, frame-rate-dependent rate.

This change replaces the delay with TheFramePacer->update(), which caps the framerate and measures real elapsed time. The fade now advances at a consistent rate, and the magic 33 ms delay is gone now that transition speed is variable.

Todo

  • testing
  • replicate to Generals

@greptile-apps

greptile-apps Bot commented Jun 30, 2026

Copy link
Copy Markdown

Greptile Summary

Replaces the hardcoded Sleep(33) in the whole-screen fade loop inside GameLogic::tryStartNewGame with TheFramePacer->update(), ensuring the fade animation advances based on real elapsed time and respects the FPS limit rather than running at a fixed, frame-rate-dependent speed. The change is symmetrically applied to both the vanilla Generals and the Zero Hour (GeneralsMD) codebases.

  • TheFramePacer->update() calls m_frameRateLimit.wait(maxFps) and captures the real delta time into m_updateTime, which downstream consumers like getBaseOverUpdateFpsRatio() rely on for frame-rate-independent transition stepping.
  • TheFramePacer is guaranteed non-null at this call site: it is allocated in GameMain() before TheGameEngine->init() runs and torn down only after execute() returns.

Confidence Score: 5/5

Safe to merge — both files receive the same targeted one-line swap that removes a fixed sleep in favour of the established frame-pacer path.

The change is minimal and correct: TheFramePacer is guaranteed to be non-null at this call site (allocated in GameMain before any engine init), update() is the standard way to tick the pacer throughout the codebase, and isActualFramesPerSecondLimitEnabled() has proper null guards for all subsystems that might be mid-init during the load screen. The fix is symmetrically replicated to both game targets and the comment accurately describes the intent.

No files require special attention.

Important Files Changed

Filename Overview
Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Replaces Sleep(33) with TheFramePacer->update() in the whole-screen fade loop; change is minimal, correct, and well-commented.
GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp Identical fix replicated to Zero Hour; symmetric with the Generals change.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant GL as GameLogic::tryStartNewGame
    participant TH as TheTransitionHandler
    participant WM as TheWindowManager
    participant D as TheDisplay
    participant FP as TheFramePacer

    GL->>TH: setGroup("FadeWholeScreen")
    loop until isFinished()
        GL->>WM: update()
        WM->>TH: advance transition (uses getBaseOverUpdateFpsRatio())
        GL->>TH: isFinished()?
        alt not finished
            GL->>D: draw()
            GL->>GL: setFPMode()
            Note over GL,FP: Before: Sleep(33) — hardcoded delay, stale m_updateTime
            GL->>FP: update()
            FP-->>GL: waits for FPS cap, records real elapsed time into m_updateTime
        end
    end
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant GL as GameLogic::tryStartNewGame
    participant TH as TheTransitionHandler
    participant WM as TheWindowManager
    participant D as TheDisplay
    participant FP as TheFramePacer

    GL->>TH: setGroup("FadeWholeScreen")
    loop until isFinished()
        GL->>WM: update()
        WM->>TH: advance transition (uses getBaseOverUpdateFpsRatio())
        GL->>TH: isFinished()?
        alt not finished
            GL->>D: draw()
            GL->>GL: setFPMode()
            Note over GL,FP: Before: Sleep(33) — hardcoded delay, stale m_updateTime
            GL->>FP: update()
            FP-->>GL: waits for FPS cap, records real elapsed time into m_updateTime
        end
    end
Loading

Reviews (1): Last reviewed commit: "fix(gui): Replicate fade-loop frame pace..." | Re-trigger Greptile

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant