Skip to content

feat(gui): Implement user option to scale the game window transition speed#2840

Merged
xezon merged 9 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/feat/configurable-menu-transition-speed
Jul 4, 2026
Merged

feat(gui): Implement user option to scale the game window transition speed#2840
xezon merged 9 commits into
TheSuperHackers:mainfrom
bobtista:bobtista/feat/configurable-menu-transition-speed

Conversation

@bobtista

@bobtista bobtista commented Jun 28, 2026

Copy link
Copy Markdown

Closes #2839

This change adds a GameWindowTransitionSpeedMultiplier option (in Options.ini) that scales the speed of menu/window transition animations, as requested following #2056. Defaults to 1.0 (unchanged behavior); values range from 1.0 (1×) to 1000.0 (1000× faster).

The multiplier is applied to the existing frame-rate-decoupled time step from #2056, so transitions still step through every state and never skip.

Todo

  • testing
  • replicate to Generals

@greptile-apps

greptile-apps Bot commented Jun 28, 2026

Copy link
Copy Markdown

Greptile Summary

This PR introduces a per-user GameWindowTransitionSpeedMultiplier preference (stored in Options.ini) that scales the speed of menu/window transition animations. The multiplier is applied to the existing frame-rate-decoupled time step in TransitionGroup::update(), and values are clamped to [1.0, 1000.0]; the change is replicated consistently across both the Generals and Zero Hour code trees.

  • OptionPreferences: New getGameWindowTransitionSpeedMultiplier() reads the INI key via atof, falls back to 1.0f if absent, and clamps to [1.0, 1000.0].
  • GameWindowTransitions.cpp: Single-line change multiplies timeScale by the global data field; the existing isFinished guard in the frame-stepping loop keeps worst-case iteration count bounded by animation length regardless of multiplier magnitude.
  • Both OptionsMenu.cpp copies: saveOptions reads the current pref value and persists it back to the INI — an intentional INI-only pattern consistent with ResolutionFontAdjustment, meaning the setting is changed by editing Options.ini directly rather than through an in-game UI control.

Confidence Score: 5/5

Safe to merge — the change is a small, well-scoped multiplier applied to an existing frame-decoupled time step, with the animation loop already guarded against unbounded iteration.

All nine changed files follow established patterns in the codebase (INI read/clamp/persist, GlobalData field init, frame-step loop). The core update logic is bounded by the isFinished check and defaults to 1.0f when the key is absent, leaving unmodified behavior for all existing users.

No files require special attention.

Important Files Changed

Filename Overview
Core/GameEngine/Include/Common/OptionPreferences.h Adds getGameWindowTransitionSpeedMultiplier() declaration; clean addition consistent with surrounding interface.
Core/GameEngine/Source/Common/OptionPreferences.cpp Implements getGameWindowTransitionSpeedMultiplier(): reads from INI via atof, clamps to [1.0, 1000.0], returns default 1.0f if key absent — follows the same pattern as neighboring prefs.
Core/GameEngine/Source/GameClient/GUI/GameWindowTransitions.cpp Scales timeScale by m_gameWindowTransitionSpeedMultiplier; the existing isFinished guard in the frame-stepping loop bounds iteration count to animation length even at max multiplier.
Generals/Code/GameEngine/Include/Common/GlobalData.h Adds m_gameWindowTransitionSpeedMultiplier field to GlobalData; correctly placed alongside other per-user display preferences.
Generals/Code/GameEngine/Source/Common/GlobalData.cpp Initializes field to 1.0f in constructor and loads it from optionPref in parseGameDataDefinition, consistent with neighboring settings.
Generals/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp Adds a saveOptions block that reads the existing INI value and writes it back unchanged (INI-only configuration, no UI control), matching the established pattern for ResolutionFontAdjustment.
GeneralsMD/Code/GameEngine/Include/Common/GlobalData.h Same field addition as in Generals/; correctly replicated to the Zero Hour expansion.
GeneralsMD/Code/GameEngine/Source/Common/GlobalData.cpp Same init and load pattern as in Generals/; correctly replicated.
GeneralsMD/Code/GameEngine/Source/GameClient/GUI/GUICallbacks/Menus/OptionsMenu.cpp Same saveOptions block as in Generals/; correctly replicated.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant INI as Options.ini
    participant OptPref as OptionPreferences
    participant GD as GlobalData
    participant TG as TransitionGroup::update()

    Note over INI,GD: At startup (parseGameDataDefinition)
    INI->>OptPref: "GameWindowTransitionSpeedMultiplier=N"
    OptPref->>OptPref: clamp(1.0, N, 1000.0)
    OptPref->>GD: "m_gameWindowTransitionSpeedMultiplier = N"

    Note over TG: Each render update
    TG->>TG: "timeScale = FramePacer.getBaseOverUpdateFpsRatio()"
    TG->>GD: read m_gameWindowTransitionSpeedMultiplier
    TG->>TG: "timeScale *= multiplier"
    TG->>TG: step frames (bounded by isFinished)

    Note over INI,GD: On saveOptions()
    GD->>OptPref: getGameWindowTransitionSpeedMultiplier()
    OptPref->>INI: write clamped value back
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 INI as Options.ini
    participant OptPref as OptionPreferences
    participant GD as GlobalData
    participant TG as TransitionGroup::update()

    Note over INI,GD: At startup (parseGameDataDefinition)
    INI->>OptPref: "GameWindowTransitionSpeedMultiplier=N"
    OptPref->>OptPref: clamp(1.0, N, 1000.0)
    OptPref->>GD: "m_gameWindowTransitionSpeedMultiplier = N"

    Note over TG: Each render update
    TG->>TG: "timeScale = FramePacer.getBaseOverUpdateFpsRatio()"
    TG->>GD: read m_gameWindowTransitionSpeedMultiplier
    TG->>TG: "timeScale *= multiplier"
    TG->>TG: step frames (bounded by isFinished)

    Note over INI,GD: On saveOptions()
    GD->>OptPref: getGameWindowTransitionSpeedMultiplier()
    OptPref->>INI: write clamped value back
Loading

Reviews (5): Last reviewed commit: "feat(gui): Replicate GameWindowTransitio..." | Re-trigger Greptile

@bobtista bobtista self-assigned this Jun 28, 2026

@Caball009 Caball009 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you lower this Sleep? As far as I'm concerned it can be set to 1 msec.

Comment thread Core/GameEngine/Source/Common/OptionPreferences.cpp Outdated
// transitions cannot skip a state when the render frame rate dips below the base rate.
const Real timeScale = TheFramePacer->getBaseOverUpdateFpsRatio();
// TheSuperHackers @feature bobtista 28/06/2026 Scale by the user menu transition speed preference.
const Real timeScale = TheFramePacer->getBaseOverUpdateFpsRatio() * TheGlobalData->m_menuTransitionSpeed;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe also apply this to the movement speed of Control Bar, Diplomacy Screen? Or does that need to be a separate setting?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those don't go through TransitionGroup they use the sliding/animate-window path. Could make another PR for those - would you want it to be a separate setting or controlled by this one?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe make it a separate setting GameWindowMovementSpeedMultiplier

Comment thread Core/GameEngine/Include/Common/OptionPreferences.h Outdated
@bobtista

Copy link
Copy Markdown
Author

Can you lower this Sleep? As far as I'm concerned it can be set to 1ms.

It's iteration-bound (frame-pacer frozen in that loop), so lowering Sleep speeds the fade up rather than smoothing it, is that what you want? It would be like 30x faster right? Maybe the proper change is to route the loop through the frame pacer, which would presumably be in its own PR.

@Caball009

Caball009 commented Jun 28, 2026

Copy link
Copy Markdown

It's iteration-bound (frame-pacer frozen in that loop), so lowering Sleep speeds the fade up rather than smoothing it, is that what you want? It would be like 30x faster right?

Right, perhaps 1000.0f / (30 * TheWritableGlobalData->m_menuTransitionSpeed) as duration is better. Having a hardcoded 33 msec delay makes no sense anymore now that the transition speed is variable.

Maybe the proper change is to route the loop through the frame pacer, which would presumably be in its own PR.

I don't think that's necessary.

Comment thread Core/GameEngine/Source/Common/OptionPreferences.cpp Outdated
Comment thread Core/GameEngine/Source/Common/OptionPreferences.cpp Outdated
@bobtista

Copy link
Copy Markdown
Author

It's iteration-bound (frame-pacer frozen in that loop), so lowering Sleep speeds the fade up rather than smoothing it, is that what you want? It would be like 30x faster right?

Right, perhaps 1000.0f / (30 * TheWritableGlobalData->m_menuTransitionSpeed) as duration is better. Having a hardcoded 33 msec delay makes no sense anymore now that the transition speed is variable.

Maybe the proper change is to route the loop through the frame pacer, which would presumably be in its own PR.

I don't think that's necessary.

Let's handle this in another PR. If we use that formula it will double count the denominator, duration becomes 1/speed². That 33 msec delay just makes the whole fade loop have 30fps pacing. We could do something like

TheTransitionHandler->setGroup("FadeWholeScreen");
while (!TheTransitionHandler->isFinished())
{
    TheWindowManager->update();
    if (!TheTransitionHandler->isFinished())
    {
        TheDisplay->draw();
        setFPMode();
        TheFramePacer->update();   // caps the framerate and measures real elapsed time
    }
}

Comment thread Core/GameEngine/Source/Common/OptionPreferences.cpp
@Caball009

Copy link
Copy Markdown

Let's handle this in another PR.

Would you mind doing a follow-up PR for this, then?

@Evulant

Evulant commented Jul 2, 2026

Copy link
Copy Markdown

Any major issues keeping this from being merged?

@xezon xezon left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think there needs to be an addition to Options Menu so that this gets saved in the Options.INI

@xezon

xezon commented Jul 2, 2026

Copy link
Copy Markdown

Pull description says 1.0 means 1x slower. But it is not slower.

@xezon xezon added GUI For graphical user interface Minor Severity: Minor < Major < Critical < Blocker Gen Relates to Generals ZH Relates to Zero Hour Enhancement Is new feature or request labels Jul 2, 2026
@bobtista

bobtista commented Jul 2, 2026

Copy link
Copy Markdown
Author

I think there needs to be an addition to Options Menu so that this gets saved in the Options.INI

should that be its own PR? Or here?

@Caball009

Copy link
Copy Markdown

I tested it and it works great. (I added the setting to the options.ini file myself).

@xezon

xezon commented Jul 4, 2026

Copy link
Copy Markdown

should that be its own PR? Or here?

It requires 5 or so lines in Options Menu. We typically add this in one commit, because it belongs together and is thereofre not necessary to split to more than one commit.

We perhaps also have several other Options that have been forgotten to be added there and are therefore never default written to Options.ini.

@xezon xezon changed the title feat(gui): Add configurable menu transition speed feat(gui): Implement user option to scale the game window transition speed Jul 4, 2026
@xezon xezon merged commit 7a06dfd into TheSuperHackers:main Jul 4, 2026
17 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Enhancement Is new feature or request Gen Relates to Generals GUI For graphical user interface Minor Severity: Minor < Major < Critical < Blocker ZH Relates to Zero Hour

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make menu transition animation speed configurable

5 participants