Skip to content

Commit acb7301

Browse files
committed
[GEN][ZH] Fix viewport scroll speed so it is independent of FPS in LookAtTranslator::translateGameMessage()
1 parent 68d9f99 commit acb7301

File tree

10 files changed

+64
-30
lines changed

10 files changed

+64
-30
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: 20 additions & 12 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+
Real logicToFpsRatio = TheGlobalData->m_useFpsLimit ? TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS() : 1.0f;
405+
399406
switch (m_scrollType)
400407
{
401408
case SCROLL_RMB:
@@ -416,34 +423,35 @@ 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+
// TheSuperHackers @info the position factor here is divided by two to provide more fine grained control over the RMB scrolling
427+
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * ((m_currentPos.x - m_anchor.x) / 2.0f);
428+
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * ((m_currentPos.y - m_anchor.y) / 2.0f);
421429
Coord2D vec;
422430
vec.x = offset.x;
423431
vec.y = offset.y;
424432
vec.normalize();
425433
// Add in the window scroll amount as the minimum.
426-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor);
427-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor);
434+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor);
435+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor);
428436
}
429437
break;
430438
case SCROLL_KEY:
431439
{
432440
if (scrollDir[DIR_UP])
433441
{
434-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
442+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
435443
}
436444
if (scrollDir[DIR_DOWN])
437445
{
438-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
446+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
439447
}
440448
if (scrollDir[DIR_LEFT])
441449
{
442-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
450+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
443451
}
444452
if (scrollDir[DIR_RIGHT])
445453
{
446-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
454+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
447455
}
448456
}
449457
break;
@@ -453,19 +461,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
453461
UnsignedInt width = TheDisplay->getWidth();
454462
if (m_currentPos.y < edgeScrollSize)
455463
{
456-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
464+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
457465
}
458466
if (m_currentPos.y >= height-edgeScrollSize)
459467
{
460-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
468+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
461469
}
462470
if (m_currentPos.x < edgeScrollSize)
463471
{
464-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
472+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
465473
}
466474
if (m_currentPos.x >= width-edgeScrollSize)
467475
{
468-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
476+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
469477
}
470478
}
471479
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) || defined(RTS_INTERNAL)
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
@@ -832,8 +832,8 @@ void W3DDisplay::updateAverageFPS(void)
832832
if (historyOffset >= FPS_HISTORY_SIZE)
833833
historyOffset = 0;
834834

835-
double currentFPS = 1.0/elapsedSeconds;
836-
fpsHistory[historyOffset++] = currentFPS;
835+
m_currentFPS = 1.0/elapsedSeconds;
836+
fpsHistory[historyOffset++] = m_currentFPS;
837837
numSamples++;
838838
if (numSamples > FPS_HISTORY_SIZE)
839839
numSamples = FPS_HISTORY_SIZE;
@@ -1559,6 +1559,11 @@ Real W3DDisplay::getAverageFPS()
15591559
return m_averageFPS;
15601560
}
15611561

1562+
Real W3DDisplay::getCurrentFPS()
1563+
{
1564+
return m_currentFPS;
1565+
}
1566+
15621567
Int W3DDisplay::getLastFrameDrawCalls()
15631568
{
15641569
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: 20 additions & 12 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+
Real logicToFpsRatio = TheGlobalData->m_useFpsLimit ? TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS() : 1.0f;
404+
398405
switch (m_scrollType)
399406
{
400407
case SCROLL_RMB:
@@ -415,34 +422,35 @@ 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+
// TheSuperHackers @info the position factor here is divided by two to provide more fine grained control over the RMB scrolling
426+
offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * ((m_currentPos.x - m_anchor.x) / 2.0f);
427+
offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * ((m_currentPos.y - m_anchor.y) / 2.0f);
420428
Coord2D vec;
421429
vec.x = offset.x;
422430
vec.y = offset.y;
423431
vec.normalize();
424432
// Add in the window scroll amount as the minimum.
425-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor);
426-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor);
433+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor);
434+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor);
427435
}
428436
break;
429437
case SCROLL_KEY:
430438
{
431439
if (scrollDir[DIR_UP])
432440
{
433-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
441+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
434442
}
435443
if (scrollDir[DIR_DOWN])
436444
{
437-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
445+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
438446
}
439447
if (scrollDir[DIR_LEFT])
440448
{
441-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
449+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
442450
}
443451
if (scrollDir[DIR_RIGHT])
444452
{
445-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
453+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
446454
}
447455
}
448456
break;
@@ -452,19 +460,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage
452460
UnsignedInt width = TheDisplay->getWidth();
453461
if (m_currentPos.y < edgeScrollSize)
454462
{
455-
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
463+
offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
456464
}
457465
if (m_currentPos.y >= height-edgeScrollSize)
458466
{
459-
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
467+
offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
460468
}
461469
if (m_currentPos.x < edgeScrollSize)
462470
{
463-
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
471+
offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
464472
}
465473
if (m_currentPos.x >= width-edgeScrollSize)
466474
{
467-
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
475+
offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor;
468476
}
469477
}
470478
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) || defined(RTS_INTERNAL)
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
@@ -899,8 +899,8 @@ void W3DDisplay::updateAverageFPS(void)
899899
if (historyOffset >= FPS_HISTORY_SIZE)
900900
historyOffset = 0;
901901

902-
double currentFPS = 1.0/elapsedSeconds;
903-
fpsHistory[historyOffset++] = currentFPS;
902+
m_currentFPS = 1.0/elapsedSeconds;
903+
fpsHistory[historyOffset++] = m_currentFPS;
904904
numSamples++;
905905
if (numSamples > FPS_HISTORY_SIZE)
906906
numSamples = FPS_HISTORY_SIZE;
@@ -1647,6 +1647,11 @@ Real W3DDisplay::getAverageFPS()
16471647
return m_averageFPS;
16481648
}
16491649

1650+
Real W3DDisplay::getCurrentFPS()
1651+
{
1652+
return m_currentFPS;
1653+
}
1654+
16501655
Int W3DDisplay::getLastFrameDrawCalls()
16511656
{
16521657
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)