From de51b00331f58ce24eb8ac719b56109609e46e0c Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 8 Feb 2026 11:49:42 +0100 Subject: [PATCH 1/3] refactor(view): Simplify View angle normalization --- Core/GameEngine/Include/GameClient/View.h | 8 ++-- Core/GameEngine/Source/GameClient/View.cpp | 4 +- .../Source/W3DDevice/GameClient/W3DView.cpp | 48 ++++++++----------- 3 files changed, 26 insertions(+), 34 deletions(-) diff --git a/Core/GameEngine/Include/GameClient/View.h b/Core/GameEngine/Include/GameClient/View.h index 6f1b0f007c9..cb64129d7d3 100644 --- a/Core/GameEngine/Include/GameClient/View.h +++ b/Core/GameEngine/Include/GameClient/View.h @@ -261,16 +261,16 @@ class View : public Snapshot Int m_width, m_height; ///< Dimensions of the view Int m_originX, m_originY; ///< Location of top/left view corner - Real m_angle; ///< Angle at which view has been rotated about the Z axis - Real m_pitch; ///< Rotation of view direction around horizontal (X) axis + Real m_angle; ///< Angle at which view has been rotated about the Z axis. Expected normalized + Real m_pitch; ///< Rotation of view direction around horizontal (X) axis. Expected normalized Real m_maxHeightAboveGround; ///< Highest camera above ground value Real m_minHeightAboveGround; ///< Lowest camera above ground value Real m_zoom; ///< Current zoom value Real m_heightAboveGround; ///< User's desired camera height above ground Bool m_zoomLimited; ///< Camera restricted in zoom height - Real m_defaultAngle; - Real m_defaultPitch; + Real m_defaultAngle; ///< Expected normalized + Real m_defaultPitch; ///< Expected normalized Real m_currentHeightAboveGround; ///< Actual camera height above ground, or rather height above ground at default pitch Real m_terrainHeightAtPivot; ///< Actual terrain height at camera pivot diff --git a/Core/GameEngine/Source/GameClient/View.cpp b/Core/GameEngine/Source/GameClient/View.cpp index bf7005ee110..ba30809f3bb 100644 --- a/Core/GameEngine/Source/GameClient/View.cpp +++ b/Core/GameEngine/Source/GameClient/View.cpp @@ -159,7 +159,7 @@ void View::scrollBy( Coord2D *delta ) */ void View::setAngle( Real radians ) { - m_angle = radians; + m_angle = WWMath::Normalize_Angle(radians); } /** @@ -174,7 +174,7 @@ void View::setPitch( Real radians ) /** * Set the view angle back to default */ -void View::setAngleToDefault() +void View::setAngleToDefault( void ) { m_angle = m_defaultAngle; } diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 7c7b64d369c..0be8d0899c1 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -98,13 +98,13 @@ #include "W3DDevice/GameClient/CameraShakeSystem.h" -constexpr const Real NearZ = MAP_XY_FACTOR; ///< Set the near to MAP_XY_FACTOR. Improves z buffer resolution. - // 30 fps Real TheW3DFrameLengthInMsec = MSEC_PER_LOGICFRAME_REAL; // default is 33msec/frame == 30fps. but we may change it depending on sys config. static const Int MAX_REQUEST_CACHE_SIZE = 40; // Any size larger than 10, or examine code below for changes. jkmcd. static const Real DRAWABLE_OVERSCAN = 75.0f; ///< 3D world coords of how much to overscan in the 3D screen region +constexpr const Real NearZ = MAP_XY_FACTOR; ///< Set the near to MAP_XY_FACTOR. Improves z buffer resolution. + //================================================================================================= inline Real minf(Real a, Real b) { if (a < b) return a; else return b; } inline Real maxf(Real a, Real b) { if (a > b) return a; else return b; } @@ -1234,22 +1234,20 @@ void W3DView::update(void) if (cameraLockObj->isUsingAirborneLocomotor() && cameraLockObj->isAboveTerrainOrWater()) { Matrix3D camXForm; - Real oldZRot = m_angle; Real idealZRot = cameraLockObj->getOrientation() - M_PI_2; - normAngle(oldZRot); - normAngle(idealZRot); - Real diff = idealZRot - oldZRot; - normAngle(diff); if (m_snapImmediate) { - m_angle = idealZRot; + View::setAngle(idealZRot); } else { - m_angle += diff * 0.1f; + normAngle(idealZRot); + Real oldZRot = m_angle; + Real diffRot = idealZRot - oldZRot; + normAngle(diffRot); + View::setAngle(m_angle + diffRot * 0.1f); } - normAngle(m_angle); } } if (m_snapImmediate) @@ -1816,12 +1814,9 @@ void W3DView::forceRedraw() //------------------------------------------------------------------------------------------------- /** Rotate the view around the up axis to the given angle. */ //------------------------------------------------------------------------------------------------- -void W3DView::setAngle( Real angle ) +void W3DView::setAngle( Real radians ) { - // Normalize to +-PI. - normAngle(angle); - // call our base class, we are adding functionality - View::setAngle( angle ); + View::setAngle( radians ); m_doingMoveCameraOnWaypointPath = false; m_CameraArrivedAtWaypointOnPathFlag = false; @@ -1837,10 +1832,9 @@ void W3DView::setAngle( Real angle ) //------------------------------------------------------------------------------------------------- /** Rotate the view around the horizontal (X) axis to the given angle. */ //------------------------------------------------------------------------------------------------- -void W3DView::setPitch( Real angle ) +void W3DView::setPitch( Real radians ) { - // call our base class, we are extending functionality - View::setPitch( angle ); + View::setPitch( radians ); m_doingMoveCameraOnWaypointPath = false; m_doingRotateCamera = false; @@ -2730,7 +2724,7 @@ void W3DView::resetCamera(const Coord3D *location, Int milliseconds, Real easeIn moveCameraTo(location, milliseconds, 0, false, easeIn, easeOut); m_mcwpInfo.cameraAngle[2] = 0.0f; // default angle. // m_mcwpInfo.cameraAngle[2] = m_defaultAngle; - m_angle = m_mcwpInfo.cameraAngle[0]; + View::setAngle(m_mcwpInfo.cameraAngle[0]); // terrain height + desired height offset == cameraOffset * actual zoom // find best approximation of max terrain height we can see @@ -2944,13 +2938,12 @@ void W3DView::rotateCameraOneFrame(void) Real angleDiff = angle - m_angle; normAngle(angleDiff); angleDiff *= factor; - m_angle += angleDiff; - normAngle(m_angle); + View::setAngle(m_angle + angleDiff); m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor); } else { - m_angle = angle; + View::setAngle(angle); } } } @@ -2958,8 +2951,8 @@ void W3DView::rotateCameraOneFrame(void) else if (m_rcInfo.curFrame <= m_rcInfo.numFrames) { Real factor = m_rcInfo.ease(((Real)m_rcInfo.curFrame)/m_rcInfo.numFrames); - m_angle = WWMath::Lerp(m_rcInfo.angle.startAngle, m_rcInfo.angle.endAngle, factor); - normAngle(m_angle); + Real angle = WWMath::Lerp(m_rcInfo.angle.startAngle, m_rcInfo.angle.endAngle, factor); + View::setAngle(angle); m_timeMultiplier = m_rcInfo.startTimeMultiplier + REAL_TO_INT_FLOOR(0.5 + (m_rcInfo.endTimeMultiplier-m_rcInfo.startTimeMultiplier)*factor); } @@ -2969,7 +2962,7 @@ void W3DView::rotateCameraOneFrame(void) m_freezeTimeForCameraMovement = false; if (! m_rcInfo.trackObject) { - m_angle = m_rcInfo.angle.endAngle; + View::setAngle(m_rcInfo.angle.endAngle); } } } @@ -3041,7 +3034,7 @@ void W3DView::moveAlongWaypointPath(Real milliseconds) m_CameraArrivedAtWaypointOnPathFlag = false; m_freezeTimeForCameraMovement = false; - m_angle = m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints]; + View::setAngle(m_mcwpInfo.cameraAngle[m_mcwpInfo.numWaypoints]); m_groundLevel = m_mcwpInfo.groundHeight[m_mcwpInfo.numWaypoints]; /////////////////////m_cameraOffset.z = m_groundLevel+TheGlobalData->m_cameraHeight; @@ -3112,8 +3105,7 @@ void W3DView::moveAlongWaypointPath(Real milliseconds) if (fabs(deltaAngle) > PI/10) { DEBUG_LOG(("Huh.")); } - m_angle += avgFactor*(deltaAngle); - normAngle(m_angle); + View::setAngle(m_angle + avgFactor*(deltaAngle)); Real timeMultiplier = m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment]*factor1 + m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment+1]*factor2; From 6a397175e5dbb7e13eca6869c727b3cb040848a2 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 8 Feb 2026 12:39:05 +0100 Subject: [PATCH 2/3] Readd normAngle(oldZRot) for robustness sake --- Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index 0be8d0899c1..ba87678c333 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -1244,6 +1244,7 @@ void W3DView::update(void) { normAngle(idealZRot); Real oldZRot = m_angle; + normAngle(oldZRot); Real diffRot = idealZRot - oldZRot; normAngle(diffRot); View::setAngle(m_angle + diffRot * 0.1f); From 9c278d882570853ec0712e50a1b59d93e721fee4 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 9 Feb 2026 19:22:12 +0100 Subject: [PATCH 3/3] Fix jank format --- Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp index ba87678c333..2a1b6583a20 100644 --- a/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp +++ b/Core/GameEngineDevice/Source/W3DDevice/GameClient/W3DView.cpp @@ -3106,7 +3106,7 @@ void W3DView::moveAlongWaypointPath(Real milliseconds) if (fabs(deltaAngle) > PI/10) { DEBUG_LOG(("Huh.")); } - View::setAngle(m_angle + avgFactor*(deltaAngle)); + View::setAngle(m_angle + (avgFactor*deltaAngle)); Real timeMultiplier = m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment]*factor1 + m_mcwpInfo.timeMultiplier[m_mcwpInfo.curSegment+1]*factor2;