Skip to content

Commit a091a51

Browse files
committed
tweak(fps): Decouple WW3D::Sync from render update (#1451)
1 parent 29dff58 commit a091a51

File tree

6 files changed

+66
-31
lines changed

6 files changed

+66
-31
lines changed

GeneralsMD/Code/GameEngine/Include/GameClient/Display.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ class Display : public SubsystemInterface
118118
virtual Bool isClippingEnabled( void ) = 0;
119119
virtual void enableClipping( Bool onoff ) = 0;
120120

121+
virtual void step() {}; ///< Do one fixed time step
121122
virtual void draw( void ); ///< Redraw the entire display
122123
virtual void setTimeOfDay( TimeOfDay tod ) = 0; ///< Set the time of day for this display
123124
virtual void createLightPulse( const Coord3D *pos, const RGBColor *color, Real innerRadius,Real attenuationWidth,

GeneralsMD/Code/GameEngine/Include/GameClient/GameClient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,8 @@ class GameClient : public SubsystemInterface,
9999
virtual void setFrame( UnsignedInt frame ) { m_frame = frame; } ///< Set the GameClient's internal frame number
100100
virtual void registerDrawable( Drawable *draw ); ///< Given a drawable, register it with the GameClient and give it a unique ID
101101

102+
void step(); ///< Do one fixed time step
103+
102104
void updateHeadless();
103105

104106
void addDrawableToLookupTable( Drawable *draw ); ///< add drawable ID to hash lookup table

GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,6 @@
8787
#include "GameLogic/SidesList.h"
8888

8989
#include "GameClient/ClientInstance.h"
90-
#include "GameClient/Display.h"
9190
#include "GameClient/FXList.h"
9291
#include "GameClient/GameClient.h"
9392
#include "GameClient/Keyboard.h"
@@ -907,6 +906,7 @@ void GameEngine::update( void )
907906
{
908907
if (TheNetwork->isFrameDataReady())
909908
{
909+
TheGameClient->step();
910910
TheGameLogic->UPDATE();
911911
}
912912
}
@@ -921,6 +921,7 @@ void GameEngine::update( void )
921921
if (!enabled || logicTimeScaleFps >= maxRenderFps)
922922
{
923923
// Logic time scale is uncapped or larger equal Render FPS. Update straight away.
924+
TheGameClient->step();
924925
TheGameLogic->UPDATE();
925926
}
926927
else
@@ -934,6 +935,7 @@ void GameEngine::update( void )
934935
#endif
935936
if (fastForward)
936937
{
938+
TheGameClient->step();
937939
TheGameLogic->UPDATE();
938940
}
939941
else
@@ -947,6 +949,7 @@ void GameEngine::update( void )
947949
if (m_logicTimeAccumulator >= targetFrameTime)
948950
{
949951
m_logicTimeAccumulator -= targetFrameTime;
952+
TheGameClient->step();
950953
TheGameLogic->UPDATE();
951954
}
952955

GeneralsMD/Code/GameEngine/Source/GameClient/GameClient.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -773,6 +773,11 @@ void GameClient::update( void )
773773
}
774774
} // end update
775775

776+
void GameClient::step()
777+
{
778+
TheDisplay->step();
779+
}
780+
776781
void GameClient::updateHeadless()
777782
{
778783
// TheSuperHackers @info helmutbuhler 03/05/2025

GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class W3DDisplay : public Display
8181
virtual Bool isClippingEnabled( void ) { return m_isClippedEnabled; }
8282
virtual void enableClipping( Bool onoff ) { m_isClippedEnabled = onoff; }
8383

84+
virtual void step(); ///< Do one fixed time step
8485
virtual void draw( void ); ///< redraw the entire display
8586

8687
/// @todo Replace these light management routines with a LightManager singleton
@@ -162,6 +163,7 @@ class W3DDisplay : public Display
162163
void calculateTerrainLOD(void); ///< Calculate terrain LOD.
163164
void renderLetterBox(UnsignedInt time); ///< draw letter box border
164165
void updateAverageFPS(void); ///< figure out the average fps over the last 30 frames.
166+
static Bool isTimeFrozen();
165167

166168
Byte m_initialized; ///< TRUE when system is initialized
167169
LightClass *m_myLight[LightEnvironmentClass::MAX_LIGHTS]; ///< light hack for now

GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp

Lines changed: 52 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1681,6 +1681,53 @@ Int W3DDisplay::getLastFrameDrawCalls()
16811681
return Debug_Statistics::Get_Draw_Calls();
16821682
}
16831683

1684+
Bool W3DDisplay::isTimeFrozen()
1685+
{
1686+
if (TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished())
1687+
return true;
1688+
1689+
if (TheScriptEngine->isTimeFrozenDebug())
1690+
return true;
1691+
1692+
if (TheScriptEngine->isTimeFrozenScript())
1693+
return true;
1694+
1695+
if (TheGameLogic->isGamePaused())
1696+
return true;
1697+
1698+
return false;
1699+
}
1700+
1701+
// TheSuperHackers @tweak xezon 12/08/2025 The WW3D Sync is no longer tied
1702+
// to the render update, but is advanced separately for every fixed time step.
1703+
void W3DDisplay::step()
1704+
{
1705+
// TheSuperHackers @info This will wrap in 1205 hours at 30 fps logic step.
1706+
static UnsignedInt syncTime = 0;
1707+
1708+
extern HWND ApplicationHWnd;
1709+
if (ApplicationHWnd && ::IsIconic(ApplicationHWnd)) {
1710+
return;
1711+
}
1712+
1713+
if (TheGlobalData->m_headless)
1714+
return;
1715+
1716+
Bool freezeTime = isTimeFrozen();
1717+
1718+
if (!freezeTime)
1719+
{
1720+
syncTime += (UnsignedInt)TheW3DFrameLengthInMsec;
1721+
1722+
if (TheScriptEngine->isTimeFast())
1723+
{
1724+
return;
1725+
}
1726+
}
1727+
1728+
WW3D::Sync( syncTime );
1729+
}
1730+
16841731
//DECLARE_PERF_TIMER(BigAssRenderLoop)
16851732

16861733
// W3DDisplay::draw ===========================================================
@@ -1690,7 +1737,6 @@ Int W3DDisplay::getLastFrameDrawCalls()
16901737
void W3DDisplay::draw( void )
16911738
{
16921739
//USE_PERF_TIMER(W3DDisplay_draw)
1693-
static UnsignedInt syncTime = 0;
16941740

16951741
extern HWND ApplicationHWnd;
16961742
if (ApplicationHWnd && ::IsIconic(ApplicationHWnd)) {
@@ -1735,10 +1781,6 @@ void W3DDisplay::draw( void )
17351781
TheInGameUI->message( UnicodeString( L"-stats is running, at interval: %d." ), TheGlobalData->m_statsInterval );
17361782
}
17371783
}
1738-
1739-
1740-
1741-
17421784
#endif
17431785

17441786
// compute debug statistics for display later
@@ -1779,21 +1821,19 @@ void W3DDisplay::draw( void )
17791821
//
17801822
//PredictiveLODOptimizerClass::Optimize_LODs( 5000 );
17811823

1782-
Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
1783-
freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
1784-
freezeTime = freezeTime || TheGameLogic->isGamePaused();
1824+
Bool freezeTime = isTimeFrozen();
17851825

17861826
// hack to let client spin fast in network games but still do effects at the same pace. -MDC
17871827
static UnsignedInt lastFrame = ~0;
1788-
freezeTime = freezeTime || (lastFrame == TheGameClient->getFrame());
1828+
freezeTime = freezeTime || (TheNetwork != NULL && lastFrame == TheGameClient->getFrame());
17891829
lastFrame = TheGameClient->getFrame();
17901830

17911831
/// @todo: I'm assuming the first view is our main 3D view.
17921832
W3DView *primaryW3DView=(W3DView *)getFirstView();
1833+
17931834
if (!freezeTime && TheScriptEngine->isTimeFast())
17941835
{
17951836
primaryW3DView->updateCameraMovements(); // Update camera motion effects.
1796-
syncTime += TheW3DFrameLengthInMsec;
17971837
return;
17981838
}
17991839

@@ -1822,21 +1862,9 @@ void W3DDisplay::draw( void )
18221862
}
18231863
}
18241864

1825-
if (!freezeTime)
1826-
{
1827-
/// @todo Decouple framerate from timestep
1828-
// for now, use constant time steps to avoid animations running independent of framerate
1829-
syncTime += TheW3DFrameLengthInMsec;
1830-
// allow W3D to update its internals
1831-
// WW3D::Sync( GetTickCount() );
1832-
}
1833-
WW3D::Sync( syncTime );
1834-
1835-
// Fast & Frozen time limits the time to 33 fps.
1836-
Int minTime = 30;
1837-
static Int prevTime = timeGetTime(), now;
1838-
1865+
static Int now;
18391866
now=timeGetTime();
1867+
18401868
if (TheTacticalView->getTimeMultiplier()>1)
18411869
{
18421870
static Int timeMultiplierCounter = 1;
@@ -1846,12 +1874,6 @@ void W3DDisplay::draw( void )
18461874
timeMultiplierCounter = TheTacticalView->getTimeMultiplier();
18471875
// limit the framerate, because while fast time is on, the game logic is running as fast as it can.
18481876
}
1849-
else
1850-
{
1851-
now = timeGetTime();
1852-
prevTime = now - minTime; // do the first frame immediately.
1853-
}
1854-
18551877

18561878
do {
18571879

0 commit comments

Comments
 (0)