diff --git a/Generals/Code/GameEngine/Include/GameClient/Display.h b/Generals/Code/GameEngine/Include/GameClient/Display.h index 1a873ce8e6..3cd74d355f 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Display.h +++ b/Generals/Code/GameEngine/Include/GameClient/Display.h @@ -180,6 +180,7 @@ class Display : public SubsystemInterface virtual void setCinematicTextFrames( Int frames ) { m_cinematicTextFrames = frames; } virtual Real getAverageFPS( void ) = 0; ///< returns the average FPS. + virtual Real getCurrentFPS( void ) = 0; ///< returns the current FPS. virtual Int getLastFrameDrawCalls( void ) = 0; ///< returns the number of draw calls issued in the previous frame protected: diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 075d588302..2e48fa29b3 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -396,6 +396,13 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage // scroll the view if (m_isScrolling) { + + // TheSuperHackers @bugfix Mauller 07/06/2025 Adjust the viewport scrolling so it is independent of GameClient FPS + // The scaling is based on the current logic rate, this provides a consistent scroll speed at all GameClient FPS + // This also fixes scrolling within replays when fast forwarding due to the uncapped FPS + // When the FPS is in excess of the expected frame rate, the ratio will reduce the offset of the cameras movement + Real logicToFpsRatio = TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS(); + switch (m_scrollType) { case SCROLL_RMB: @@ -416,34 +423,35 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage m_anchor.y = m_currentPos.y - maxY; } - offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * (m_currentPos.x - m_anchor.x); - offset.y = TheGlobalData->m_verticalScrollSpeedFactor * (m_currentPos.y - m_anchor.y); + // TheSuperHackers @fix Mauller 16/06/2025 Fix RMB scrolling to make it scale properly with scroll factor and to make it move consistently in all directions Coord2D vec; - vec.x = offset.x; - vec.y = offset.y; + vec.x = (m_currentPos.x - m_anchor.x); + vec.y = (m_currentPos.y - m_anchor.y); + // TheSuperHackers @info we need to get the length of the vector before the vector is normalised + // The length is then used to properly scale the speed using the mouse position from the anchor point + float vecLength = vec.length(); vec.normalize(); - // Add in the window scroll amount as the minimum. - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor); - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor); + offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * vecLength * vec.x * TheGlobalData->m_keyboardScrollFactor; + offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * vecLength * vec.y * TheGlobalData->m_keyboardScrollFactor; } break; case SCROLL_KEY: { if (scrollDir[DIR_UP]) { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_DOWN]) { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_LEFT]) { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_RIGHT]) { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } } break; @@ -453,19 +461,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage UnsignedInt width = TheDisplay->getWidth(); if (m_currentPos.y < edgeScrollSize) { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.y >= height-edgeScrollSize) { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.x < edgeScrollSize) { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.x >= width-edgeScrollSize) { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } } break; diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index b88aa035fd..e5d8661497 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -145,7 +145,8 @@ class W3DDisplay : public Display static W3DAssetManager *m_assetManager; ///< W3D asset manager void drawFPSStats( void ); ///< draw the fps on the screen - virtual Real getAverageFPS( void ); ///< return the average FPS. + virtual Real getAverageFPS( void ); ///< return the average FPS. + virtual Real getCurrentFPS( void ); ///< return the current FPS. virtual Int getLastFrameDrawCalls( void ); ///< returns the number of draw calls issued in the previous frame protected: @@ -166,6 +167,7 @@ class W3DDisplay : public Display IRegion2D m_clipRegion; ///< the clipping region for images Bool m_isClippedEnabled; ///= FPS_HISTORY_SIZE) historyOffset = 0; - double currentFPS = 1.0/elapsedSeconds; - fpsHistory[historyOffset++] = currentFPS; + m_currentFPS = 1.0/elapsedSeconds; + fpsHistory[historyOffset++] = m_currentFPS; numSamples++; if (numSamples > FPS_HISTORY_SIZE) numSamples = FPS_HISTORY_SIZE; @@ -1559,6 +1559,11 @@ Real W3DDisplay::getAverageFPS() return m_averageFPS; } +Real W3DDisplay::getCurrentFPS() +{ + return m_currentFPS; +} + Int W3DDisplay::getLastFrameDrawCalls() { return Debug_Statistics::Get_Draw_Calls(); diff --git a/Generals/Code/Tools/GUIEdit/Include/GUIEditDisplay.h b/Generals/Code/Tools/GUIEdit/Include/GUIEditDisplay.h index 9d2966ac5b..904d2851b6 100644 --- a/Generals/Code/Tools/GUIEdit/Include/GUIEditDisplay.h +++ b/Generals/Code/Tools/GUIEdit/Include/GUIEditDisplay.h @@ -126,6 +126,7 @@ class GUIEditDisplay : public Display #endif virtual Real getAverageFPS(void) { return 0; } + virtual Real getCurrentFPS(void) { return 0; } virtual Int getLastFrameDrawCalls( void ) { return 0; } protected: diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h index 92775c7e36..d9bc33688d 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Display.h @@ -181,6 +181,7 @@ class Display : public SubsystemInterface virtual void setCinematicTextFrames( Int frames ) { m_cinematicTextFrames = frames; } virtual Real getAverageFPS( void ) = 0; ///< returns the average FPS. + virtual Real getCurrentFPS( void ) = 0; ///< returns the current FPS. virtual Int getLastFrameDrawCalls( void ) = 0; ///< returns the number of draw calls issued in the previous frame protected: diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 0942418e53..32064d117d 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -395,6 +395,13 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage // scroll the view if (m_isScrolling) { + + // TheSuperHackers @bugfix Mauller 07/06/2025 Adjust the viewport scrolling so it is independent of GameClient FPS + // The scaling is based on the current logic rate, this provides a consistent scroll speed at all GameClient FPS + // This also fixes scrolling within replays when fast forwarding due to the uncapped FPS + // When the FPS is in excess of the expected frame rate, the ratio will reduce the offset of the cameras movement + Real logicToFpsRatio = TheGlobalData->m_framesPerSecondLimit / TheDisplay->getCurrentFPS(); + switch (m_scrollType) { case SCROLL_RMB: @@ -415,34 +422,35 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage m_anchor.y = m_currentPos.y - maxY; } - offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * (m_currentPos.x - m_anchor.x); - offset.y = TheGlobalData->m_verticalScrollSpeedFactor * (m_currentPos.y - m_anchor.y); + // TheSuperHackers @fix Mauller 16/06/2025 Fix RMB scrolling to make it scale properly with scroll factor and to make it move consistently in all directions Coord2D vec; - vec.x = offset.x; - vec.y = offset.y; + vec.x = (m_currentPos.x - m_anchor.x); + vec.y = (m_currentPos.y - m_anchor.y); + // TheSuperHackers @info we need to get the length of the vector before the vector is normalised + // The length is then used to properly scale the speed using the mouse position from the anchor point + float vecLength = vec.length(); vec.normalize(); - // Add in the window scroll amount as the minimum. - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * vec.x * sqr(TheGlobalData->m_keyboardScrollFactor); - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * vec.y * sqr(TheGlobalData->m_keyboardScrollFactor); + offset.x = TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * vecLength * vec.x * TheGlobalData->m_keyboardScrollFactor; + offset.y = TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * vecLength * vec.y * TheGlobalData->m_keyboardScrollFactor; } break; case SCROLL_KEY: { if (scrollDir[DIR_UP]) { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_DOWN]) { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_LEFT]) { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (scrollDir[DIR_RIGHT]) { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } } break; @@ -452,19 +460,19 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage UnsignedInt width = TheDisplay->getWidth(); if (m_currentPos.y < edgeScrollSize) { - offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y -= TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.y >= height-edgeScrollSize) { - offset.y += TheGlobalData->m_verticalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.y += TheGlobalData->m_verticalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.x < edgeScrollSize) { - offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x -= TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } if (m_currentPos.x >= width-edgeScrollSize) { - offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; + offset.x += TheGlobalData->m_horizontalScrollSpeedFactor * logicToFpsRatio * SCROLL_AMT * TheGlobalData->m_keyboardScrollFactor; } } break; diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h index 132596da91..43fb4ac473 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/W3DDisplay.h @@ -146,7 +146,8 @@ class W3DDisplay : public Display static W3DAssetManager *m_assetManager; ///< W3D asset manager void drawFPSStats( void ); ///< draw the fps on the screen - virtual Real getAverageFPS( void ); ///< return the average FPS. + virtual Real getAverageFPS( void ); ///< return the average FPS. + virtual Real getCurrentFPS( void ); ///< return the current FPS. virtual Int getLastFrameDrawCalls( void ); ///< returns the number of draw calls issued in the previous frame protected: @@ -167,6 +168,7 @@ class W3DDisplay : public Display IRegion2D m_clipRegion; ///< the clipping region for images Bool m_isClippedEnabled; ///= FPS_HISTORY_SIZE) historyOffset = 0; - double currentFPS = 1.0/elapsedSeconds; - fpsHistory[historyOffset++] = currentFPS; + m_currentFPS = 1.0/elapsedSeconds; + fpsHistory[historyOffset++] = m_currentFPS; numSamples++; if (numSamples > FPS_HISTORY_SIZE) numSamples = FPS_HISTORY_SIZE; @@ -1647,6 +1647,11 @@ Real W3DDisplay::getAverageFPS() return m_averageFPS; } +Real W3DDisplay::getCurrentFPS() +{ + return m_currentFPS; +} + Int W3DDisplay::getLastFrameDrawCalls() { return Debug_Statistics::Get_Draw_Calls(); diff --git a/GeneralsMD/Code/Tools/GUIEdit/Include/GUIEditDisplay.h b/GeneralsMD/Code/Tools/GUIEdit/Include/GUIEditDisplay.h index bcae0e79f2..e7ed0c86f2 100644 --- a/GeneralsMD/Code/Tools/GUIEdit/Include/GUIEditDisplay.h +++ b/GeneralsMD/Code/Tools/GUIEdit/Include/GUIEditDisplay.h @@ -126,6 +126,7 @@ class GUIEditDisplay : public Display #endif virtual Real getAverageFPS(void) { return 0; } + virtual Real getCurrentFPS(void) { return 0; } virtual Int getLastFrameDrawCalls( void ) { return 0; } protected: