From 1802f659d3b05f36510ab576d86b9a1053d42191 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Wed, 17 Sep 2025 10:17:22 +0200 Subject: [PATCH 1/2] Decouple zoom update from logic update --- .../Source/GameClient/MessageStream/LookAtXlat.cpp | 8 ++------ .../Source/W3DDevice/GameClient/W3DView.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index 459b694a27e..e753b258694 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -398,19 +398,15 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage Int spin = msg->getArgument( 1 )->integer; - // TheSuperHackers @tweak The camera zoom is now decoupled from the render update. - const Real fpsRatio = (Real)BaseFps / TheGameEngine->getUpdateFps(); - const Real zoomHeight = (Real)View::ZoomHeightPerSecond * fpsRatio; - if (spin > 0) { for ( ; spin > 0; spin--) - TheTacticalView->zoom( -zoomHeight ); + TheTacticalView->zoom( -View::ZoomHeightPerSecond ); } else { for ( ;spin < 0; spin++ ) - TheTacticalView->zoom( +zoomHeight ); + TheTacticalView->zoom( +View::ZoomHeightPerSecond ); } break; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 3e3a6c042a5..89f627d677e 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1348,6 +1348,7 @@ void W3DView::update(void) { Real desiredHeight = (m_terrainHeightUnderCamera + m_heightAboveGround); Real desiredZoom = desiredHeight / m_cameraOffset.z; + if (didScriptedMovement || (TheGameLogic->isInReplayGame() && TheGlobalData->m_useCameraInReplay)) { // if we are in a scripted camera movement, take its height above ground as our desired height. @@ -1355,27 +1356,26 @@ void W3DView::update(void) //DEBUG_LOG(("Frame %d: height above ground: %g %g %g %g", TheGameLogic->getFrame(), m_heightAboveGround, // m_cameraOffset.z, m_zoom, m_terrainHeightUnderCamera)); } + if (TheInGameUI->isScrolling()) { // if scrolling, only adjust if we're too close or too far if (m_scrollAmount.length() < m_scrollAmountCutoff || (m_currentHeightAboveGround < m_minHeightAboveGround) || (TheGlobalData->m_enforceMaxCameraHeight && m_currentHeightAboveGround > m_maxHeightAboveGround)) { - Real zoomAdj = (desiredZoom - m_zoom)*TheGlobalData->m_cameraAdjustSpeed; - if (fabs(zoomAdj) >= 0.0001) // only do positive + Real zoomAdj = (desiredZoom - m_zoom) * TheGlobalData->m_cameraAdjustSpeed * TheGameEngine->getActualLogicTimeScaleOverFpsRatio(); + if (fabs(zoomAdj) >= 0.0001f) // only do positive { m_zoom += zoomAdj; recalcCamera = true; } } } - else + else if (!didScriptedMovement) { // we're not scrolling; settle toward desired height above ground - Real zoomAdj = (m_zoom - desiredZoom)*TheGlobalData->m_cameraAdjustSpeed; - Real zoomAdjAbs = fabs(zoomAdj); - if (zoomAdjAbs >= 0.0001 && !didScriptedMovement) + Real zoomAdj = (m_zoom - desiredZoom) * TheGlobalData->m_cameraAdjustSpeed * TheGameEngine->getActualLogicTimeScaleOverFpsRatio(); + if (fabs(zoomAdj) >= 0.0001f) { - //DEBUG_LOG(("W3DView::update() - m_zoom=%g, desiredHeight=%g", m_zoom, desiredZoom)); m_zoom -= zoomAdj; recalcCamera = true; } From 183a60882b11eb925772db29fd89fb7f691aee31 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 20 Sep 2025 12:02:54 +0200 Subject: [PATCH 2/2] Replicate in Generals --- .../Source/GameClient/MessageStream/LookAtXlat.cpp | 8 ++------ .../Source/W3DDevice/GameClient/W3DView.cpp | 14 +++++++------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp index ff6131b6a45..34907e5b62c 100644 --- a/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/MessageStream/LookAtXlat.cpp @@ -399,19 +399,15 @@ GameMessageDisposition LookAtTranslator::translateGameMessage(const GameMessage Int spin = msg->getArgument( 1 )->integer; - // TheSuperHackers @tweak The camera zoom is now decoupled from the render update. - const Real fpsRatio = (Real)BaseFps / TheGameEngine->getUpdateFps(); - const Real zoomHeight = (Real)View::ZoomHeightPerSecond * fpsRatio; - if (spin > 0) { for ( ; spin > 0; spin--) - TheTacticalView->zoom( -zoomHeight ); + TheTacticalView->zoom( -View::ZoomHeightPerSecond ); } else { for ( ;spin < 0; spin++ ) - TheTacticalView->zoom( +zoomHeight ); + TheTacticalView->zoom( +View::ZoomHeightPerSecond ); } break; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 43657ed7c2d..707d086fd4c 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1195,6 +1195,7 @@ void W3DView::update(void) { Real desiredHeight = (m_terrainHeightUnderCamera + m_heightAboveGround); Real desiredZoom = desiredHeight / m_cameraOffset.z; + if (didScriptedMovement || (TheGameLogic->isInReplayGame() && TheGlobalData->m_useCameraInReplay)) { // if we are in a scripted camera movement, take its height above ground as our desired height. @@ -1202,27 +1203,26 @@ void W3DView::update(void) //DEBUG_LOG(("Frame %d: height above ground: %g %g %g %g", TheGameLogic->getFrame(), m_heightAboveGround, // m_cameraOffset.z, m_zoom, m_terrainHeightUnderCamera)); } + if (TheInGameUI->isScrolling()) { // if scrolling, only adjust if we're too close or too far if (m_scrollAmount.length() < m_scrollAmountCutoff || (m_currentHeightAboveGround < m_minHeightAboveGround) || (TheGlobalData->m_enforceMaxCameraHeight && m_currentHeightAboveGround > m_maxHeightAboveGround)) { - Real zoomAdj = (desiredZoom - m_zoom)*TheGlobalData->m_cameraAdjustSpeed; - if (fabs(zoomAdj) >= 0.0001) // only do positive + Real zoomAdj = (desiredZoom - m_zoom) * TheGlobalData->m_cameraAdjustSpeed * TheGameEngine->getActualLogicTimeScaleOverFpsRatio(); + if (fabs(zoomAdj) >= 0.0001f) // only do positive { m_zoom += zoomAdj; recalcCamera = true; } } } - else + else if (!didScriptedMovement) { // we're not scrolling; settle toward desired height above ground - Real zoomAdj = (m_zoom - desiredZoom)*TheGlobalData->m_cameraAdjustSpeed; - Real zoomAdjAbs = fabs(zoomAdj); - if (zoomAdjAbs >= 0.0001 && !didScriptedMovement) + Real zoomAdj = (m_zoom - desiredZoom) * TheGlobalData->m_cameraAdjustSpeed * TheGameEngine->getActualLogicTimeScaleOverFpsRatio(); + if (fabs(zoomAdj) >= 0.0001f) { - //DEBUG_LOG(("W3DView::update() - m_zoom=%g, desiredHeight=%g", m_zoom, desiredZoom)); m_zoom -= zoomAdj; recalcCamera = true; }