tweak(gui): Decouple GUI transition and world animation timing from render update#2056
tweak(gui): Decouple GUI transition and world animation timing from render update#2056bobtista wants to merge 7 commits into
Conversation
|
| Filename | Overview |
|---|---|
| Core/GameEngine/Include/GameClient/GameWindowTransitions.h | Changes m_currentFrame from Int to Real to support fractional frame accumulation; comment updated to clarify unit semantics. |
| Core/GameEngine/Source/GameClient/GUI/GameWindowTransitions.cpp | Replaces single-frame increment with a getBaseOverUpdateFpsRatio()-scaled accumulator and a stepping loop that replays every integer frame boundary — correctly handles both low and high fps for discrete state-machine transitions. |
| Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp | Z-rise now scaled by getActualLogicTimeScaleOverFpsRatio, which is capped at 1.0; corrects high-fps drift (>30fps) but leaves sub-30fps rise speed still frame-rate-dependent. |
| GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp | Identical change to the Zero Hour variant — same cap-at-1.0 limitation applies for sub-30fps scenarios. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Render Frame] --> B[TransitionGroup::update]
B --> C["timeScale = getBaseOverUpdateFpsRatio()\n(30 / renderFPS, floored at 5fps)"]
C --> D["prevFrame = int(m_currentFrame)\nm_currentFrame += dirMul * timeScale\nnewFrame = int(m_currentFrame)"]
D --> E{newFrame == prevFrame?}
E -- Yes --> F[return early\nno state change]
E -- No --> G["Step loop:\nfor frame = prevFrame+step to newFrame"]
G --> H["tWin->update(frame)\nfor each TransitionWindow"]
H --> I{isFinished?}
I -- Yes --> J[break]
I -- No --> G
A --> K[InGameUI::updateAndDrawWorldAnimations]
K --> L["zRiseTimeScale = getActualLogicTimeScaleOverFpsRatio()\nmin(1.0f, logicFPS / renderFPS)"]
L --> M["wad->m_worldPos.z +=\nzRisePerSecond / LOGICFRAMES_PER_SECOND * zRiseTimeScale"]
Prompt To Fix All With AI
Fix the following 2 code review issues. Work through them one at a time, proposing concise fixes.
---
### Issue 1 of 2
GeneralsMD/Code/GameEngine/Source/GameClient/InGameUI.cpp:5680
**`getActualLogicTimeScaleOverFpsRatio` clamps at 1.0 — sub-30fps rise speed not fixed**
`getActualLogicTimeScaleOverFpsRatio` is implemented as `min(1.0f, logicFPS / renderFPS)`, so it never returns a value greater than 1.0. At render rates below `BaseFps` (30fps), the multiplier is locked to 1.0 and `updateAndDrawWorldAnimations` runs fewer than 30 times per second, so the net rise per second is still frame-rate-proportional (e.g., 15fps → 0.5× speed).
In contrast, `getBaseOverUpdateFpsRatio()` — used for GUI transitions — has no such cap (only a floor at 5fps) and would produce the correct compensating value (2.0 at 15fps) to keep the total rise consistent. The PR description says both systems use "the same time factor," but they use different methods with different bounds. If sub-30fps consistency is in scope, switching to `getBaseOverUpdateFpsRatio()` here would fully solve it.
### Issue 2 of 2
Generals/Code/GameEngine/Source/GameClient/InGameUI.cpp:5507
**Same `getActualLogicTimeScaleOverFpsRatio` cap applies here**
Same issue as in `GeneralsMD`: `getActualLogicTimeScaleOverFpsRatio` clamps at 1.0, so z-rise is still frame-rate-dependent below 30fps. Consistent with the Zero Hour copy; worth resolving in both places together if sub-30fps behavior is addressed.
Reviews (5): Last reviewed commit: "fix(gui): Step every integer transition ..." | Re-trigger Greptile
Additional Comments (1)
Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! Prompt To Fix With AIThis is a comment left during a code review.
Path: Generals/Code/GameEngine/Source/GameClient/GUI/GameWindowTransitions.cpp
Line: 62:62
Comment:
[P2] This file still uses `NULL` (`TheTransitionHandler = NULL;`). New code in this PR also adds `FramePacer` usage; consider switching to `nullptr` for null pointer literals to match the repo’s C++ style.
```suggestion
GameWindowTransitionsHandler *TheTransitionHandler = nullptr;
```
<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>
How can I resolve this? If you propose a fix, please make it concise. |
|
I frequently find myself increasing the render frame rate at the menu because I find the window transitions too slow at 30 fps, and would probably like it better if they played close to ~1.75x the original speed. Is there anything this PR can do in that regard? |
|
I agree with Caball. It would be nice to have a setting to adjust GUI speed (x1.0... x1.25... x1.5x... x1.75... x2.00... and so on). |
|
Feature for scaling animation speed is unrelated to decoupling step and better be follow up change. |
|
Looks good. |
276ed5c to
e6cd525
Compare
|
There are still a couple of to-dos in the PR description. |
Is this something you can reproduce? I don't think I've seen anything like this during my testing. |
|
I ran into this several times when testing. My SSD was slow, but still it was unusual behavior. I can retest if this is not reproducible for others. |
Please do. |
Can you take a look at this? I cannot reproduce it, and this PR probably shouldn't be blocked from merging if you can't reproduce it either |
|
I replicated Xezon's bug by running this on a networked drive. The logic seems to fail on long IO stalls. |
|
Added a single sleep to replicate this, the menu won't even launch on this. But it does on main. GameEngine.cpp 30 will randomly bug out the menu after a few switches. |
|
|
@bobtista Can you take a look at the stuck menu issue? |
| it++; | ||
| } | ||
|
|
||
| if( isFinished() ) |
There was a problem hiding this comment.
This goes through the list a second time. This can probably be optimized by returning finished result in update function above and then use that to determine finished status.
There was a problem hiding this comment.
Or just check isFinished for each transition group after each update.




Summary
Changes
TransitionGroup::m_currentFramechanged fromInttoRealto support fractional frame accumulationTransitionGroup::update()scales frame advancement byTheFramePacer->getActualLogicTimeScaleOverFpsRatio()InGameUIworld animation Z-rise calculation now scales by the same time factorTest plan