Skip to content

Commit 9527b54

Browse files
authored
[GEN][ZH] Make viewport scroll speed frame rate independent (#1026)
1 parent 1a8475d commit 9527b54

File tree

10 files changed

+58
-26
lines changed

10 files changed

+58
-26
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,7 @@ class Display : public SubsystemInterface
180180
virtual void setCinematicTextFrames( Int frames ) { m_cinematicTextFrames = frames; }
181181

182182
virtual Real getAverageFPS( void ) = 0; ///< returns the average FPS.
183+
virtual Real getCurrentFPS( void ) = 0; ///< returns the current FPS.
183184
virtual Int getLastFrameDrawCalls( void ) = 0; ///< returns the number of draw calls issued in the previous frame
184185

185186
protected:

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -396,6 +396,13 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
396396
// scroll the view
397397
if (m_isScrolling)
398398
{
399+
400+
// TheSuperHackers @bugfix Mauller 07/06/2025 Adjust the viewport scrolling so it is independent of GameClient FPS
401+
// The scaling is based on the current logic rate, this provides a consistent scroll speed at all GameClient FPS
402+
// This also fixes scrolling within replays when fast forwarding due to the uncapped FPS
403+
// When the FPS is in excess of the expected frame rate, the ratio will reduce the offset of the cameras movement
404+
const Real logicToFpsRatio = TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS();
405+
399406
switch (m_scrollType)
400407
{
401408
case SCROLL_RMB:
@@ -416,8 +423,8 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
416423
m_anchor.y = m_currentPos.y - maxY;
417424
}
418425

419-
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * (m_currentPos.x - m_anchor.x);
420-
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * (m_currentPos.y - m_anchor.y);
426+
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * (m_currentPos.x - m_anchor.x);
427+
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * (m_currentPos.y - m_anchor.y);
421428
Coord2D vec;
422429
vec.x = offset.x;
423430
vec.y = offset.y;
@@ -431,19 +438,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
431438
{
432439
if (scrollDir[DIR_UP])
433440
{
434-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
441+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
435442
}
436443
if (scrollDir[DIR_DOWN])
437444
{
438-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
445+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
439446
}
440447
if (scrollDir[DIR_LEFT])
441448
{
442-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
449+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
443450
}
444451
if (scrollDir[DIR_RIGHT])
445452
{
446-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
453+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
447454
}
448455
}
449456
break;
@@ -453,19 +460,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
453460
UnsignedInt width = TheDisplay->getWidth();
454461
if (m_currentPos.y < edgeScrollSize)
455462
{
456-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
463+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
457464
}
458465
if (m_currentPos.y >= height-edgeScrollSize)
459466
{
460-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
467+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
461468
}
462469
if (m_currentPos.x < edgeScrollSize)
463470
{
464-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
471+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
465472
}
466473
if (m_currentPos.x >= width-edgeScrollSize)
467474
{
468-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
475+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
469476
}
470477
}
471478
break;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,8 @@ class W3DDisplay : public Display
145145
static W3DAssetManager *m_assetManager; ///< W3D asset manager
146146

147147
void drawFPSStats( void ); ///< draw the fps on the screen
148-
virtual Real getAverageFPS( void ); ///< return the average FPS.
148+
virtual Real getAverageFPS( void ); ///< return the average FPS.
149+
virtual Real getCurrentFPS( void ); ///< return the current FPS.
149150
virtual Int getLastFrameDrawCalls( void ); ///< returns the number of draw calls issued in the previous frame
150151

151152
protected:
@@ -166,6 +167,7 @@ class W3DDisplay : public Display
166167
IRegion2D m_clipRegion; ///< the clipping region for images
167168
Bool m_isClippedEnabled; ///<used by 2D drawing operations to define clip re
168169
Real m_averageFPS; ///<average fps over the last 30 frames.
170+
Real m_currentFPS; ///<current fps value.
169171
#if defined(RTS_DEBUG)
170172
Int64 m_timerAtCumuFPSStart;
171173
#endif

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -873,8 +873,8 @@ void W3DDisplay::updateAverageFPS(void)
873873
if (historyOffset >= FPS_HISTORY_SIZE)
874874
historyOffset = 0;
875875

876-
double currentFPS = 1.0/elapsedSeconds;
877-
fpsHistory[historyOffset++] = currentFPS;
876+
m_currentFPS = 1.0/elapsedSeconds;
877+
fpsHistory[historyOffset++] = m_currentFPS;
878878
numSamples++;
879879
if (numSamples > FPS_HISTORY_SIZE)
880880
numSamples = FPS_HISTORY_SIZE;
@@ -1600,6 +1600,11 @@ Real W3DDisplay::getAverageFPS()
16001600
return m_averageFPS;
16011601
}
16021602

1603+
Real W3DDisplay::getCurrentFPS()
1604+
{
1605+
return m_currentFPS;
1606+
}
1607+
16031608
Int W3DDisplay::getLastFrameDrawCalls()
16041609
{
16051610
return Debug_Statistics::Get_Draw_Calls();

Generals/Code/Tools/GUIEdit/Include/GUIEditDisplay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class GUIEditDisplay : public Display
126126
#endif
127127

128128
virtual Real getAverageFPS(void) { return 0; }
129+
virtual Real getCurrentFPS(void) { return 0; }
129130
virtual Int getLastFrameDrawCalls( void ) { return 0; }
130131

131132
protected:

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ class Display : public SubsystemInterface
181181
virtual void setCinematicTextFrames( Int frames ) { m_cinematicTextFrames = frames; }
182182

183183
virtual Real getAverageFPS( void ) = 0; ///< returns the average FPS.
184+
virtual Real getCurrentFPS( void ) = 0; ///< returns the current FPS.
184185
virtual Int getLastFrameDrawCalls( void ) = 0; ///< returns the number of draw calls issued in the previous frame
185186

186187
protected:

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

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,13 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
395395
// scroll the view
396396
if (m_isScrolling)
397397
{
398+
399+
// TheSuperHackers @bugfix Mauller 07/06/2025 Adjust the viewport scrolling so it is independent of GameClient FPS
400+
// The scaling is based on the current logic rate, this provides a consistent scroll speed at all GameClient FPS
401+
// This also fixes scrolling within replays when fast forwarding due to the uncapped FPS
402+
// When the FPS is in excess of the expected frame rate, the ratio will reduce the offset of the cameras movement
403+
const Real logicToFpsRatio = TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS();
404+
398405
switch (m_scrollType)
399406
{
400407
case SCROLL_RMB:
@@ -415,8 +422,8 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
415422
m_anchor.y = m_currentPos.y - maxY;
416423
}
417424

418-
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * (m_currentPos.x - m_anchor.x);
419-
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * (m_currentPos.y - m_anchor.y);
425+
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * (m_currentPos.x - m_anchor.x);
426+
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * (m_currentPos.y - m_anchor.y);
420427
Coord2D vec;
421428
vec.x = offset.x;
422429
vec.y = offset.y;
@@ -430,19 +437,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
430437
{
431438
if (scrollDir[DIR_UP])
432439
{
433-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
440+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
434441
}
435442
if (scrollDir[DIR_DOWN])
436443
{
437-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
444+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
438445
}
439446
if (scrollDir[DIR_LEFT])
440447
{
441-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
448+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
442449
}
443450
if (scrollDir[DIR_RIGHT])
444451
{
445-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
452+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
446453
}
447454
}
448455
break;
@@ -452,19 +459,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
452459
UnsignedInt width = TheDisplay->getWidth();
453460
if (m_currentPos.y < edgeScrollSize)
454461
{
455-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
462+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
456463
}
457464
if (m_currentPos.y >= height-edgeScrollSize)
458465
{
459-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
466+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
460467
}
461468
if (m_currentPos.x < edgeScrollSize)
462469
{
463-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
470+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
464471
}
465472
if (m_currentPos.x >= width-edgeScrollSize)
466473
{
467-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
474+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
468475
}
469476
}
470477
break;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,8 @@ class W3DDisplay : public Display
146146
static W3DAssetManager *m_assetManager; ///< W3D asset manager
147147

148148
void drawFPSStats( void ); ///< draw the fps on the screen
149-
virtual Real getAverageFPS( void ); ///< return the average FPS.
149+
virtual Real getAverageFPS( void ); ///< return the average FPS.
150+
virtual Real getCurrentFPS( void ); ///< return the current FPS.
150151
virtual Int getLastFrameDrawCalls( void ); ///< returns the number of draw calls issued in the previous frame
151152

152153
protected:
@@ -167,6 +168,7 @@ class W3DDisplay : public Display
167168
IRegion2D m_clipRegion; ///< the clipping region for images
168169
Bool m_isClippedEnabled; ///<used by 2D drawing operations to define clip re
169170
Real m_averageFPS; ///<average fps over the last 30 frames.
171+
Real m_currentFPS; ///<current fps value.
170172
#if defined(RTS_DEBUG)
171173
Int64 m_timerAtCumuFPSStart;
172174
#endif

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

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -923,8 +923,8 @@ void W3DDisplay::updateAverageFPS(void)
923923
if (historyOffset >= FPS_HISTORY_SIZE)
924924
historyOffset = 0;
925925

926-
double currentFPS = 1.0/elapsedSeconds;
927-
fpsHistory[historyOffset++] = currentFPS;
926+
m_currentFPS = 1.0/elapsedSeconds;
927+
fpsHistory[historyOffset++] = m_currentFPS;
928928
numSamples++;
929929
if (numSamples > FPS_HISTORY_SIZE)
930930
numSamples = FPS_HISTORY_SIZE;
@@ -1671,6 +1671,11 @@ Real W3DDisplay::getAverageFPS()
16711671
return m_averageFPS;
16721672
}
16731673

1674+
Real W3DDisplay::getCurrentFPS()
1675+
{
1676+
return m_currentFPS;
1677+
}
1678+
16741679
Int W3DDisplay::getLastFrameDrawCalls()
16751680
{
16761681
return Debug_Statistics::Get_Draw_Calls();

GeneralsMD/Code/Tools/GUIEdit/Include/GUIEditDisplay.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ class GUIEditDisplay : public Display
126126
#endif
127127

128128
virtual Real getAverageFPS(void) { return 0; }
129+
virtual Real getCurrentFPS(void) { return 0; }
129130
virtual Int getLastFrameDrawCalls( void ) { return 0; }
130131

131132
protected:

0 commit comments

Comments
 (0)