Skip to content

Commit 2d9093a

Browse files
committed
tweak(fps): Decouple WW3D::Sync from render update (#1451)
1 parent 4c14ada commit 2d9093a

File tree

12 files changed

+130
-58
lines changed

12 files changed

+130
-58
lines changed

Generals/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,

Generals/Code/GameEngine/Include/GameClient/GameClient.h

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

98+
void step(); ///< Do one fixed time step
99+
98100
void updateHeadless();
99101

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

Generals/Code/GameEngine/Source/Common/GameEngine.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@
8585
#include "GameLogic/SidesList.h"
8686

8787
#include "GameClient/ClientInstance.h"
88-
#include "GameClient/Display.h"
8988
#include "GameClient/FXList.h"
9089
#include "GameClient/GameClient.h"
9190
#include "GameClient/Keyboard.h"
@@ -732,6 +731,7 @@ void GameEngine::update( void )
732731
{
733732
if (TheNetwork->isFrameDataReady())
734733
{
734+
TheGameClient->step();
735735
TheGameLogic->UPDATE();
736736
}
737737
}
@@ -752,6 +752,7 @@ void GameEngine::update( void )
752752
if (useFastMode || !enabled || logicTimeScaleFps >= maxRenderFps)
753753
{
754754
// Logic time scale is uncapped or larger equal Render FPS. Update straight away.
755+
TheGameClient->step();
755756
TheGameLogic->UPDATE();
756757
}
757758
else
@@ -764,6 +765,7 @@ void GameEngine::update( void )
764765
if (m_logicTimeAccumulator >= targetFrameTime)
765766
{
766767
m_logicTimeAccumulator -= targetFrameTime;
768+
TheGameClient->step();
767769
TheGameLogic->UPDATE();
768770
}
769771
}

Generals/Code/GameEngine/Source/GameClient/GameClient.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -735,6 +735,11 @@ void GameClient::update( void )
735735
}
736736
} // end update
737737

738+
void GameClient::step()
739+
{
740+
TheDisplay->step();
741+
}
742+
738743
void GameClient::updateHeadless()
739744
{
740745
// TheSuperHackers @info helmutbuhler 03/05/2025

Generals/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
@@ -161,6 +162,7 @@ class W3DDisplay : public Display
161162
void calculateTerrainLOD(void); ///< Calculate terrain LOD.
162163
void renderLetterBox(UnsignedInt time); ///< draw letter box border
163164
void updateAverageFPS(void); ///< figure out the average fps over the last 30 frames.
165+
static Bool isTimeFrozen();
164166

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

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

Lines changed: 52 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1606,6 +1606,53 @@ Int W3DDisplay::getLastFrameDrawCalls()
16061606
return Debug_Statistics::Get_Draw_Calls();
16071607
}
16081608

1609+
Bool W3DDisplay::isTimeFrozen()
1610+
{
1611+
if (TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished())
1612+
return true;
1613+
1614+
if (TheScriptEngine->isTimeFrozenDebug())
1615+
return true;
1616+
1617+
if (TheScriptEngine->isTimeFrozenScript())
1618+
return true;
1619+
1620+
if (TheGameLogic->isGamePaused())
1621+
return true;
1622+
1623+
return false;
1624+
}
1625+
1626+
// TheSuperHackers @tweak xezon 12/08/2025 The WW3D Sync is no longer tied
1627+
// to the render update, but is advanced separately for every fixed time step.
1628+
void W3DDisplay::step()
1629+
{
1630+
// TheSuperHackers @info This will wrap in 1205 hours at 30 fps logic step.
1631+
static UnsignedInt syncTime = 0;
1632+
1633+
extern HWND ApplicationHWnd;
1634+
if (ApplicationHWnd && ::IsIconic(ApplicationHWnd)) {
1635+
return;
1636+
}
1637+
1638+
if (TheGlobalData->m_headless)
1639+
return;
1640+
1641+
Bool freezeTime = isTimeFrozen();
1642+
1643+
if (!freezeTime)
1644+
{
1645+
syncTime += (UnsignedInt)TheW3DFrameLengthInMsec;
1646+
1647+
if (TheScriptEngine->isTimeFast())
1648+
{
1649+
return;
1650+
}
1651+
}
1652+
1653+
WW3D::Sync( syncTime );
1654+
}
1655+
16091656
//DECLARE_PERF_TIMER(BigAssRenderLoop)
16101657

16111658
// W3DDisplay::draw ===========================================================
@@ -1615,7 +1662,6 @@ Int W3DDisplay::getLastFrameDrawCalls()
16151662
void W3DDisplay::draw( void )
16161663
{
16171664
//USE_PERF_TIMER(W3DDisplay_draw)
1618-
static UnsignedInt syncTime = 0;
16191665

16201666
extern HWND ApplicationHWnd;
16211667
if (ApplicationHWnd && ::IsIconic(ApplicationHWnd)) {
@@ -1690,21 +1736,19 @@ void W3DDisplay::draw( void )
16901736
//
16911737
//PredictiveLODOptimizerClass::Optimize_LODs( 5000 );
16921738

1693-
Bool freezeTime = TheTacticalView->isTimeFrozen() && !TheTacticalView->isCameraMovementFinished();
1694-
freezeTime = freezeTime || TheScriptEngine->isTimeFrozenDebug() || TheScriptEngine->isTimeFrozenScript();
1695-
freezeTime = freezeTime || TheGameLogic->isGamePaused();
1739+
Bool freezeTime = isTimeFrozen();
16961740

16971741
// hack to let client spin fast in network games but still do effects at the same pace. -MDC
16981742
static UnsignedInt lastFrame = ~0;
1699-
freezeTime = freezeTime || (lastFrame == TheGameClient->getFrame());
1743+
freezeTime = freezeTime || (TheNetwork != NULL && lastFrame == TheGameClient->getFrame());
17001744
lastFrame = TheGameClient->getFrame();
17011745

17021746
/// @todo: I'm assuming the first view is our main 3D view.
17031747
W3DView *primaryW3DView=(W3DView *)getFirstView();
1748+
17041749
if (!freezeTime && TheScriptEngine->isTimeFast())
17051750
{
17061751
primaryW3DView->updateCameraMovements(); // Update camera motion effects.
1707-
syncTime += TheW3DFrameLengthInMsec;
17081752
return;
17091753
}
17101754

@@ -1733,21 +1777,9 @@ void W3DDisplay::draw( void )
17331777
}
17341778
}
17351779

1736-
if (!freezeTime)
1737-
{
1738-
/// @todo Decouple framerate from timestep
1739-
// for now, use constant time steps to avoid animations running independent of framerate
1740-
syncTime += TheW3DFrameLengthInMsec;
1741-
// allow W3D to update its internals
1742-
// WW3D::Sync( GetTickCount() );
1743-
}
1744-
WW3D::Sync( syncTime );
1745-
1746-
// Fast & Frozen time limits the time to 33 fps.
1747-
Int minTime = 30;
1748-
static Int prevTime = timeGetTime(), now;
1749-
1780+
static Int now;
17501781
now=timeGetTime();
1782+
17511783
if (TheTacticalView->getTimeMultiplier()>1)
17521784
{
17531785
static Int timeMultiplierCounter = 1;
@@ -1757,12 +1789,6 @@ void W3DDisplay::draw( void )
17571789
timeMultiplierCounter = TheTacticalView->getTimeMultiplier();
17581790
// limit the framerate, because while fast time is on, the game logic is running as fast as it can.
17591791
}
1760-
else
1761-
{
1762-
now = timeGetTime();
1763-
prevTime = now - minTime; // do the first frame immediately.
1764-
}
1765-
17661792

17671793
do {
17681794

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: 3 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
}
@@ -927,6 +927,7 @@ void GameEngine::update( void )
927927
if (useFastMode || !enabled || logicTimeScaleFps >= maxRenderFps)
928928
{
929929
// Logic time scale is uncapped or larger equal Render FPS. Update straight away.
930+
TheGameClient->step();
930931
TheGameLogic->UPDATE();
931932
}
932933
else
@@ -939,6 +940,7 @@ void GameEngine::update( void )
939940
if (m_logicTimeAccumulator >= targetFrameTime)
940941
{
941942
m_logicTimeAccumulator -= targetFrameTime;
943+
TheGameClient->step();
942944
TheGameLogic->UPDATE();
943945
}
944946
}

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

0 commit comments

Comments
 (0)