From cc901117d883f6c47a4ff84cd0f2e681fac5bbd5 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:20:30 +0200 Subject: [PATCH 01/14] refactor(ww3d): Rename WW3D::Get_Frame_Time to WW3D::Get_Sync_Frame_Time (#1579) --- .../Source/WWVegas/WW3D2/ringobj.cpp | 2 +- .../Source/WWVegas/WW3D2/sphereobj.cpp | 2 +- Core/Tools/W3DView/GraphicView.cpp | 2 +- .../GameEngine/Source/GameClient/Drawable.cpp | 2 +- .../GameClient/Drawable/Draw/W3DTankDraw.cpp | 2 +- .../Drawable/Draw/W3DTankTruckDraw.cpp | 2 +- .../GameClient/Drawable/Draw/W3DTruckDraw.cpp | 2 +- .../Libraries/Source/WWVegas/WW3D2/dazzle.cpp | 7 ++--- .../Source/WWVegas/WW3D2/part_emt.cpp | 2 +- .../Source/WWVegas/WW3D2/texproject.cpp | 2 +- .../Libraries/Source/WWVegas/WW3D2/ww3d.h | 26 +++++++++---------- .../GameEngine/Source/GameClient/Drawable.cpp | 2 +- .../GameClient/Drawable/Draw/W3DTankDraw.cpp | 2 +- .../Drawable/Draw/W3DTankTruckDraw.cpp | 2 +- .../GameClient/Drawable/Draw/W3DTruckDraw.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DSnow.cpp | 2 +- .../Libraries/Source/WWVegas/WW3D2/dazzle.cpp | 7 ++--- .../Source/WWVegas/WW3D2/part_emt.cpp | 2 +- .../Source/WWVegas/WW3D2/texproject.cpp | 2 +- .../Libraries/Source/WWVegas/WW3D2/ww3d.h | 26 +++++++++---------- 20 files changed, 46 insertions(+), 52 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp index 9795b38909..5db7898b32 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp @@ -1150,7 +1150,7 @@ void RingRenderObjClass::animate() // Convert from milliseconds to seconds and normalize the time // if (AnimDuration > 0) { - float frametime = WW3D::Get_Frame_Time(); + float frametime = WW3D::Get_Sync_Frame_Time(); frametime = (frametime * 0.001F) / AnimDuration; anim_time += frametime; } else { diff --git a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp index fa3e5c4ed3..b14d7f323c 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp @@ -1108,7 +1108,7 @@ void SphereRenderObjClass::animate (void) // Convert from milliseconds to seconds and normalize the time // if (AnimDuration > 0) { - float frametime = WW3D::Get_Frame_Time(); + float frametime = WW3D::Get_Sync_Frame_Time(); frametime = (frametime * 0.001F) / AnimDuration; anim_time += frametime; } else { diff --git a/Core/Tools/W3DView/GraphicView.cpp b/Core/Tools/W3DView/GraphicView.cpp index ccf5bbfca5..c6e785198c 100644 --- a/Core/Tools/W3DView/GraphicView.cpp +++ b/Core/Tools/W3DView/GraphicView.cpp @@ -546,7 +546,7 @@ CGraphicView::RepaintView // // Let the audio class think // - WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Frame_Time()); + WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Sync_Frame_Time()); // // Update the count of particles and polys in the status bar diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index 9891fb0f89..4dd5fcee67 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1264,7 +1264,7 @@ void Drawable::applyPhysicsXform(Matrix3D* mtx) { // TheSuperHackers @tweak Update the physics transform on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() != 0) + if (WW3D::Get_Sync_Frame_Time() != 0) { calcPhysicsXform(*m_physicsXform); } diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index 1138e394b8..6b91b28be2 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -312,7 +312,7 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) { // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real DEBRIS_THRESHOLD = 0.00001f; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp index 899a4da37e..433b3af4c4 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp @@ -517,7 +517,7 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp index c34a8c4303..0baa25aa28 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp @@ -395,7 +395,7 @@ void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 5b27bdaf4a..5ff6f9ef2c 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -940,7 +940,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,current_distance); - unsigned time_ms=WW3D::Get_Frame_Time(); + unsigned time_ms=WW3D::Get_Sync_Frame_Time(); if (time_ms==0) time_ms=1; float weight=pow(params->ic.history_weight,time_ms); @@ -1012,9 +1012,6 @@ void DazzleRenderObjClass::Render_Dazzle(CameraClass* camera) screen_x_scale=h/w; } -// unsigned time_ms=WW3D::Get_Frame_Time(); -// if (time_ms==0) time_ms=1; - float halo_scale_x=types[type]->ic.halo_scale_x; float halo_scale_y=types[type]->ic.halo_scale_y; float dazzle_scale_x=types[type]->ic.dazzle_scale_x; @@ -1481,7 +1478,7 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Frame_Time(); + unsigned time_ms=WW3D::Get_Sync_Frame_Time(); if (time_ms==0) time_ms=1; DX8Wrapper::Set_Material(NULL); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp index f258545402..4f21627fa6 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp @@ -549,7 +549,7 @@ void ParticleEmitterClass::Create_New_Particles(const Quaternion & curr_quat, co // the previous interval when the last particle was emitted) is added to // the size of the current frame to yield the time currently available // for emitting particles. - unsigned int frametime = WW3D::Get_Frame_Time(); + unsigned int frametime = WW3D::Get_Sync_Frame_Time(); // Since the particles are written into a wraparound buffer, we can take the time modulo a time // constant which represents the time it takes to fill up the entire buffer with new particles. // We will do this so we don't run into performance problems with very large frame times. diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp index 12ab1a9056..46bc591351 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp @@ -1283,7 +1283,7 @@ void TexProjectClass::Pre_Render_Update(const Matrix3D & camera) /* ** update the current intensity by iterating it towards the desired intensity */ - float frame_time = (float)WW3D::Get_Frame_Time() / 1000.0f; + float frame_time = (float)WW3D::Get_Sync_Frame_Time() / 1000.0f; float intensity_delta = DesiredIntensity - Intensity; float max_intensity_delta = INTENSITY_RATE_OF_CHANGE * frame_time; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index 9c544db816..a8ef60241c 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -170,10 +170,10 @@ class WW3D ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync( unsigned int sync_time ); static unsigned int Get_Sync_Time(void) { return SyncTime; } - static unsigned int Get_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Frame_Count(void) { return FrameCount; } + static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -326,16 +326,16 @@ class WW3D static float FractionalSyncMs; // Timing info: - // The absolute synchronized frame time (in milliseconds) supplied by the - // application at the start of every frame. Note that wraparound cases - // etc. need to be considered. - static unsigned int SyncTime; - - // The previously set absolute sync time - this is used to get the interval between - // the most recently set sync time and the previous one. Assuming the - // application sets sync time at the start of every frame, this represents - // the frame interval. - static unsigned int PreviousSyncTime; + // The absolute synchronized frame time (in milliseconds) supplied by the + // application at the start of every frame. Note that wraparound cases + // etc. need to be considered. + static unsigned int SyncTime; + + // The previously set absolute sync time - this is used to get the interval between + // the most recently set sync time and the previous one. Assuming the + // application sets sync time at the start of every frame, this represents + // the frame interval. + static unsigned int PreviousSyncTime; static float PixelCenterX; static float PixelCenterY; diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 328440a0ea..1358b1b054 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -1392,7 +1392,7 @@ void Drawable::applyPhysicsXform(Matrix3D* mtx) { // TheSuperHackers @tweak Update the physics transform on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() != 0) + if (WW3D::Get_Sync_Frame_Time() != 0) { calcPhysicsXform(*m_physicsXform); } diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index eb59745dd9..0e366bb3df 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -312,7 +312,7 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) { // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real DEBRIS_THRESHOLD = 0.00001f; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp index 94b43a54b7..83945bf5f3 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankTruckDraw.cpp @@ -517,7 +517,7 @@ void W3DTankTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp index 12a52f8da1..49625d6628 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTruckDraw.cpp @@ -395,7 +395,7 @@ void W3DTruckDraw::doDrawModule(const Matrix3D* transformMtx) // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. - if (WW3D::Get_Frame_Time() == 0) + if (WW3D::Get_Sync_Frame_Time() == 0) return; const Real ACCEL_THRESHOLD = 0.01f; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp index cf40de7c79..348fc1f003 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp @@ -157,7 +157,7 @@ void W3DSnowManager::reset( void ) void W3DSnowManager::update(void) { - m_time += WW3D::Get_Frame_Time() / 1000.0f; + m_time += WW3D::Get_Sync_Frame_Time() / 1000.0f; //find current time offset, adjusting for overflow m_time=fmod(m_time,m_fullTimePeriod); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 1b19381d44..786e3db009 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -975,7 +975,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,dir,current_distance); - unsigned time_ms=WW3D::Get_Frame_Time(); + unsigned time_ms=WW3D::Get_Sync_Frame_Time(); if (time_ms==0) time_ms=1; float weight=pow(params->ic.history_weight,time_ms); @@ -1048,9 +1048,6 @@ void DazzleRenderObjClass::Render_Dazzle(CameraClass* camera) screen_x_scale=h/w; } -// unsigned time_ms=WW3D::Get_Frame_Time(); -// if (time_ms==0) time_ms=1; - // Do NOT scale halo by current scale // because it uses screen parallel primitives // and if it's too big it will be visible until @@ -1587,7 +1584,7 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Frame_Time(); + unsigned time_ms=WW3D::Get_Sync_Frame_Time(); if (time_ms==0) time_ms=1; DX8Wrapper::Set_Material(NULL); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp index 2e09baa753..9cf680b840 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/part_emt.cpp @@ -558,7 +558,7 @@ void ParticleEmitterClass::Create_New_Particles(const Quaternion & curr_quat, co // the previous interval when the last particle was emitted) is added to // the size of the current frame to yield the time currently available // for emitting particles. - unsigned int frametime = WW3D::Get_Frame_Time(); + unsigned int frametime = WW3D::Get_Sync_Frame_Time(); // Since the particles are written into a wraparound buffer, we can take the time modulo a time // constant which represents the time it takes to fill up the entire buffer with new particles. // We will do this so we don't run into performance problems with very large frame times. diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp index 5cb239e276..a729abc55e 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp @@ -1317,7 +1317,7 @@ void TexProjectClass::Pre_Render_Update(const Matrix3D & camera) /* ** update the current intensity by iterating it towards the desired intensity */ - float frame_time = (float)WW3D::Get_Frame_Time() / 1000.0f; + float frame_time = (float)WW3D::Get_Sync_Frame_Time() / 1000.0f; float intensity_delta = DesiredIntensity - Intensity; float max_intensity_delta = INTENSITY_RATE_OF_CHANGE * frame_time; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index af2261961e..9f23f2c1ec 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -170,10 +170,10 @@ class WW3D ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync( unsigned int sync_time ); static unsigned int Get_Sync_Time(void) { return SyncTime; } - static unsigned int Get_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Frame_Count(void) { return FrameCount; } + static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -326,16 +326,16 @@ class WW3D static float FractionalSyncMs; // Timing info: - // The absolute synchronized frame time (in milliseconds) supplied by the - // application at the start of every frame. Note that wraparound cases - // etc. need to be considered. - static unsigned int SyncTime; - - // The previously set absolute sync time - this is used to get the interval between - // the most recently set sync time and the previous one. Assuming the - // application sets sync time at the start of every frame, this represents - // the frame interval. - static unsigned int PreviousSyncTime; + // The absolute synchronized frame time (in milliseconds) supplied by the + // application at the start of every frame. Note that wraparound cases + // etc. need to be considered. + static unsigned int SyncTime; + + // The previously set absolute sync time - this is used to get the interval between + // the most recently set sync time and the previous one. Assuming the + // application sets sync time at the start of every frame, this represents + // the frame interval. + static unsigned int PreviousSyncTime; static float PixelCenterX; static float PixelCenterY; From a6862f1fe95adba4af8b2b7f7b43ac306a4176f7 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:22:16 +0200 Subject: [PATCH 02/14] bugfix(draw): Fix tank draw update logic step time is smaller than render frame time (#1579) --- .../Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp | 4 ++-- .../Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index 6b91b28be2..efdc37d46a 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -310,6 +310,8 @@ void W3DTankDraw::onRenderObjRecreated(void) //------------------------------------------------------------------------------------------------- void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) { + W3DModelDraw::doDrawModule(transformMtx); + // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. if (WW3D::Get_Sync_Frame_Time() == 0) @@ -405,8 +407,6 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) } } } - - W3DModelDraw::doDrawModule(transformMtx); } // ------------------------------------------------------------------------------------------------ diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp index 0e366bb3df..56af0e77ca 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/Drawable/Draw/W3DTankDraw.cpp @@ -310,6 +310,8 @@ void W3DTankDraw::onRenderObjRecreated(void) //------------------------------------------------------------------------------------------------- void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) { + W3DModelDraw::doDrawModule(transformMtx); + // TheSuperHackers @tweak Update the draw on every WW Sync only. // All calculations are originally catered to a 30 fps logic step. if (WW3D::Get_Sync_Frame_Time() == 0) @@ -405,8 +407,6 @@ void W3DTankDraw::doDrawModule(const Matrix3D* transformMtx) } } } - - W3DModelDraw::doDrawModule(transformMtx); } // ------------------------------------------------------------------------------------------------ From e4dd2989fb203f694e6271d278bb7330ec3ecae1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:30:43 +0200 Subject: [PATCH 03/14] tweak(snow): Decouple snow render update from logic step (#1579) --- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 2 +- .../Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 4 +++- Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h | 12 +++++++++--- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DSnow.cpp | 4 ++-- .../Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 4 +++- .../Code/Libraries/Source/WWVegas/WW3D2/ww3d.h | 12 +++++++++--- 7 files changed, 28 insertions(+), 12 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 0f1306bcb8..a1813f3d7e 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1731,7 +1731,7 @@ void W3DDisplay::draw( void ) } } - WW3D::Add_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); static Int now; now=timeGetTime(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index cadd4fb4bf..f44fa6820f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -165,6 +165,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ +float WW3D::LogicFrameTimeMs = 33.33f; float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; @@ -1168,8 +1169,9 @@ unsigned int WW3D::Get_Last_Frame_Vertex_Count(void) return Debug_Statistics::Get_DX8_Vertices(); } -void WW3D::Add_Frame_Time(float milliseconds) +void WW3D::Update_Logic_Frame_Time(float milliseconds) { + LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index a8ef60241c..d32aa3861f 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -162,9 +162,9 @@ class WW3D static void Flip_To_Primary(void); - // TheSuperHackers @info Call this function to accumulate fractional render time. - // It will then call Sync with a new time on its own once an appropriate amount of time has passed. - static void Add_Frame_Time(float milliseconds); + // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. + // This can be a fraction of a logic step. It will call Sync on its own once an appropriate amount of time has passed. + static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This @@ -173,6 +173,8 @@ class WW3D static void Sync( unsigned int sync_time ); static unsigned int Get_Sync_Time(void) { return SyncTime; } static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -323,6 +325,10 @@ class WW3D static void Allocate_Debug_Resources(void); static void Release_Debug_Resources(void); + // Logic frame time, in milliseconds + static float LogicFrameTimeMs; + + // Accumulated synchronized frame time in milliseconds static float FractionalSyncMs; // Timing info: diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index cadeda7209..bef1b0e489 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1812,7 +1812,7 @@ void W3DDisplay::draw( void ) } } - WW3D::Add_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); static Int now; now=timeGetTime(); diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp index 348fc1f003..bed66d1c65 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DSnow.cpp @@ -156,8 +156,8 @@ void W3DSnowManager::reset( void ) void W3DSnowManager::update(void) { - - m_time += WW3D::Get_Sync_Frame_Time() / 1000.0f; + // TheSuperHackers @tweak The snow render update is now decoupled from the logic step. + m_time += WW3D::Get_Logic_Frame_Time_Seconds(); //find current time offset, adjusting for overflow m_time=fmod(m_time,m_fullTimePeriod); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 14aa8203cd..072d816efd 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -166,6 +166,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ +float WW3D::LogicFrameTimeMs = 33.33f; float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; @@ -1163,8 +1164,9 @@ unsigned int WW3D::Get_Last_Frame_Vertex_Count(void) return Debug_Statistics::Get_DX8_Vertices(); } -void WW3D::Add_Frame_Time(float milliseconds) +void WW3D::Update_Logic_Frame_Time(float milliseconds) { + LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index 9f23f2c1ec..b46b135dce 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -162,9 +162,9 @@ class WW3D static void Flip_To_Primary(void); - // TheSuperHackers @info Call this function to accumulate fractional render time. - // It will then call Sync with a new time on its own once an appropriate amount of time has passed. - static void Add_Frame_Time(float milliseconds); + // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. + // This can be a fraction of a logic step. It will call Sync on its own once an appropriate amount of time has passed. + static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This @@ -173,6 +173,8 @@ class WW3D static void Sync( unsigned int sync_time ); static unsigned int Get_Sync_Time(void) { return SyncTime; } static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } + static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } static unsigned int Get_Frame_Count(void) { return FrameCount; } static unsigned int Get_Last_Frame_Poly_Count(void); static unsigned int Get_Last_Frame_Vertex_Count(void); @@ -323,6 +325,10 @@ class WW3D static void Allocate_Debug_Resources(void); static void Release_Debug_Resources(void); + // Logic frame time, in milliseconds + static float LogicFrameTimeMs; + + // Accumulated synchronized frame time in milliseconds static float FractionalSyncMs; // Timing info: From d4e74d824e2117be6c115553244cb299bfa025f1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 12:40:36 +0200 Subject: [PATCH 04/14] tweak(segline): Decouple segline render update from logic step (#1579) --- .../Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp index 16ccba9f86..dd97d4a050 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp @@ -78,7 +78,6 @@ SegLineRendererClass::SegLineRendererClass(void) : NoiseAmplitude(0.0f), MergeAbortFactor(1.5f), TextureTileFactor(1.0f), - LastUsedSyncTime(WW3D::Get_Sync_Time()), CurrentUVOffset(0.0f,0.0f), UVOffsetDeltaPerMS(0.0f, 0.0f), Bits(DEFAULT_BITS), @@ -98,7 +97,6 @@ SegLineRendererClass::SegLineRendererClass(const SegLineRendererClass & that) : NoiseAmplitude(0.0f), MergeAbortFactor(1.5f), TextureTileFactor(1.0f), - LastUsedSyncTime(that.LastUsedSyncTime), CurrentUVOffset(0.0f,0.0f), UVOffsetDeltaPerMS(0.0f, 0.0f), Bits(DEFAULT_BITS), @@ -120,7 +118,6 @@ SegLineRendererClass & SegLineRendererClass::operator = (const SegLineRendererCl NoiseAmplitude = that.NoiseAmplitude; MergeAbortFactor = that.MergeAbortFactor; TextureTileFactor = that.TextureTileFactor; - LastUsedSyncTime = that.LastUsedSyncTime; CurrentUVOffset = that.CurrentUVOffset; UVOffsetDeltaPerMS = that.UVOffsetDeltaPerMS; Bits = that.Bits; @@ -201,7 +198,6 @@ void SegLineRendererClass::Set_Texture_Tile_Factor(float factor) void SegLineRendererClass::Reset_Line(void) { - LastUsedSyncTime = WW3D::Get_Sync_Time(); CurrentUVOffset.Set(0.0f,0.0f); } @@ -227,9 +223,8 @@ void SegLineRendererClass::Render /* ** Handle texture UV offset animation (done once for entire line). */ - unsigned int delta = WW3D::Get_Sync_Time() - LastUsedSyncTime; - float del = (float)delta; - Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * del; + // TheSuperHackers @tweak The render update is now decoupled from the logic step. + Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * WW3D::Get_Logic_Frame_Time_Milliseconds(); // ensure offsets are in [0, 1] range: uv_offset.X = uv_offset.X - floorf(uv_offset.X); @@ -237,7 +232,6 @@ void SegLineRendererClass::Render // Update state CurrentUVOffset = uv_offset; - LastUsedSyncTime = WW3D::Get_Sync_Time(); // Used later TextureMapMode map_mode = Get_Texture_Mapping_Mode(); From 513ea776d3f88fe999cf70ceb2e3855317555507 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 16:51:52 +0200 Subject: [PATCH 05/14] bugfix(anim): Fix calling Animatable3DObjClass::Single_Anim_Progress more than once a frame (#1579) --- .../Source/WWVegas/WW3D2/animobj.cpp | 21 +------------------ .../Source/WWVegas/WW3D2/animobj.cpp | 21 +------------------ 2 files changed, 2 insertions(+), 40 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index f2d8d959ce..b5278deecb 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -289,12 +289,6 @@ void Animatable3DObjClass::Render(RenderInfoClass & rinfo) return; } - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid() || Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } @@ -316,12 +310,6 @@ void Animatable3DObjClass::Special_Render(SpecialRenderInfoClass & rinfo) { if (HTree == NULL) return; - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid()) { Update_Sub_Object_Transforms(); } @@ -1043,19 +1031,12 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // // Update the frame number and sync time // - float oldprev = ModeAnim.PrevFrame; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); - if (ModeAnim.Frame == ModeAnim.PrevFrame) { - // This function was somehow called twice per frame. - // Since ModeAnim.Frame hasn't changed, reset the ModeAnim.PrevFrame. - // If you don't do this sounds won't be triggered properly because Frame and PrevFrame will be the same. - ModeAnim.PrevFrame = oldprev; - } // - // Force the heirarchy to be recalculated + // Force the hierarchy to be recalculated // Set_Hierarchy_Valid (false); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 551cb69957..32ce456d48 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -289,12 +289,6 @@ void Animatable3DObjClass::Render(RenderInfoClass & rinfo) return; } - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid() || Are_Sub_Object_Transforms_Dirty()) { Update_Sub_Object_Transforms(); } @@ -316,12 +310,6 @@ void Animatable3DObjClass::Special_Render(SpecialRenderInfoClass & rinfo) { if (HTree == NULL) return; - if ( CurMotionMode == SINGLE_ANIM ) { - if ( ModeAnim.AnimMode != ANIM_MODE_MANUAL ) { - Single_Anim_Progress(); - } - } - if (!Is_Hierarchy_Valid()) { Update_Sub_Object_Transforms(); } @@ -1051,19 +1039,12 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // // Update the frame number and sync time // - float oldprev = ModeAnim.PrevFrame; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); - if (ModeAnim.Frame == ModeAnim.PrevFrame) { - // This function was somehow called twice per frame. - // Since ModeAnim.Frame hasn't changed, reset the ModeAnim.PrevFrame. - // If you don't do this sounds won't be triggered properly because Frame and PrevFrame will be the same. - ModeAnim.PrevFrame = oldprev; - } // - // Force the heirarchy to be recalculated + // Force the hierarchy to be recalculated // Set_Hierarchy_Valid (false); } From 0908bf9a38d4948bc6d0c065359ff4dd02d8e6f9 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 16:53:04 +0200 Subject: [PATCH 06/14] tweak(anim): Decouple anim object render update from logic step (#1579) --- .../Source/WWVegas/WW3D2/animobj.cpp | 28 ++++++++----------- .../Libraries/Source/WWVegas/WW3D2/animobj.h | 1 - .../Source/WWVegas/WW3D2/animobj.cpp | 28 ++++++++----------- .../Libraries/Source/WWVegas/WW3D2/animobj.h | 1 - 4 files changed, 24 insertions(+), 34 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index b5278deecb..2b81b7b36c 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,7 +89,6 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -145,7 +144,6 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -205,7 +203,6 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -464,7 +461,6 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -765,7 +761,7 @@ void Animatable3DObjClass::Control_Bone(int bindex,const Matrix3D & objtm,bool w void Animatable3DObjClass::Update_Sub_Object_Transforms(void) { /* - ** The RenderObj impementation will cause our 'container' + ** The RenderObj implementation will cause our 'container' ** to update if we are not valid yet */ CompositeRenderObjClass::Update_Sub_Object_Transforms(); @@ -937,8 +933,9 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // Compute the current frame based on elapsed time. // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { - float sync_time_diff = WW3D::Get_Sync_Time() - ModeAnim.LastSyncTime; - float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * sync_time_diff * 0.001f; + // TheSuperHackers @tweak The animation render update is now decoupled from the logic step. + const float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime; frame += delta; // @@ -954,10 +951,10 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const case ANIM_MODE_LOOP: if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { frame -= ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame = 0; + // If it is still too far out, reset + if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { + frame = 0; + } } break; case ANIM_MODE_ONCE_BACKWARDS: //play animation one time but backwards @@ -968,10 +965,10 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { frame += ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + // If it is still too far out, reset + if ( frame < 0 ) { + frame = ModeAnim.Motion->Get_Num_Frames() - 1; + } } break; case ANIM_MODE_LOOP_PINGPONG: @@ -1033,7 +1030,6 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); // // Force the hierarchy to be recalculated diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index cd5a745d84..174c1eeafe 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -190,7 +190,6 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; - mutable int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 32ce456d48..86ba38c191 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,7 +89,6 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -145,7 +144,6 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; - ModeAnim.LastSyncTime=WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -205,7 +203,6 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -464,7 +461,6 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -764,7 +760,7 @@ void Animatable3DObjClass::Control_Bone(int bindex,const Matrix3D & objtm,bool w void Animatable3DObjClass::Update_Sub_Object_Transforms(void) { /* - ** The RenderObj impementation will cause our 'container' + ** The RenderObj implementation will cause our 'container' ** to update if we are not valid yet */ CompositeRenderObjClass::Update_Sub_Object_Transforms(); @@ -945,8 +941,9 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // Compute the current frame based on elapsed time. // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { - float sync_time_diff = WW3D::Get_Sync_Time() - ModeAnim.LastSyncTime; - float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * sync_time_diff * 0.001f; + // TheSuperHackers @tweak The animation render update is now decoupled from the logic step. + const float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime; frame += delta; // @@ -962,10 +959,10 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const case ANIM_MODE_LOOP: if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { frame -= ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame = 0; + // If it is still too far out, reset + if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { + frame = 0; + } } break; case ANIM_MODE_ONCE_BACKWARDS: //play animation one time but backwards @@ -976,10 +973,10 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { frame += ModeAnim.Motion->Get_Num_Frames() - 1; - } - // If it is still too far out, reset - if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + // If it is still too far out, reset + if ( frame < 0 ) { + frame = ModeAnim.Motion->Get_Num_Frames() - 1; + } } break; case ANIM_MODE_LOOP_PINGPONG: @@ -1041,7 +1038,6 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); - ModeAnim.LastSyncTime = WW3D::Get_Sync_Time(); // // Force the hierarchy to be recalculated diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index a671b5b1af..6985ade3eb 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -190,7 +190,6 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; - mutable int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; From eae907a4a1f82809d5162ffaeca306e182c6e501 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 19:39:18 +0200 Subject: [PATCH 07/14] bugfix(ww3d): Bind the ww3d sync step to the game logic step (#1579) --- .../Source/WWVegas/WWLib/WWDefines.h | 6 ----- .../GameEngine/Include/GameLogic/GameLogic.h | 2 ++ .../Source/GameLogic/System/GameLogic.cpp | 6 +++++ .../W3DDevice/GameClient/W3DDisplay.cpp | 4 ++++ .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 23 +++++++------------ .../Libraries/Source/WWVegas/WW3D2/ww3d.h | 4 ++-- .../Source/WWVegas/WWLib/WWDefines.h | 6 ----- .../GameEngine/Include/GameLogic/GameLogic.h | 2 ++ .../Source/GameLogic/System/GameLogic.cpp | 6 +++++ .../W3DDevice/GameClient/W3DDisplay.cpp | 4 ++++ .../Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 23 +++++++------------ .../Libraries/Source/WWVegas/WW3D2/ww3d.h | 4 ++-- 12 files changed, 44 insertions(+), 46 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h index d7acdd7b4e..cb93ccd88d 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -17,9 +17,3 @@ */ #pragma once - -// The WW3D Sync time. This was originally 33 ms, ~30 fps, integer. -// Changing or removing this will require tweaking all Drawable code that concerns logic time step, including locomotion physics. -#ifndef MSEC_PER_WWSYNC_FRAME -#define MSEC_PER_WWSYNC_FRAME (33) -#endif diff --git a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h index 6b9815a411..512e0ee5a1 100644 --- a/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/Generals/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -133,6 +133,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Real getHeight( void ); ///< Returns the height of the world Bool isInGameLogicUpdate( void ) const { return m_isInUpdate; } + Bool hasUpdated() const { return m_hasUpdated; } ///< Returns true if the logic frame has advanced in the current client/render update UnsignedInt getFrame( void ); ///< Returns the current simulation frame number UnsignedInt getCRC( Int mode = CRC_CACHED, AsciiString deepCRCFileName = AsciiString::TheEmptyString ); ///< Returns the CRC @@ -301,6 +302,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Bool m_loadingScene; Bool m_isInUpdate; + Bool m_hasUpdated; Int m_rankPointsToAddAtGameStart; diff --git a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 1f01c04aa4..92bf469c28 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -226,6 +226,7 @@ GameLogic::GameLogic( void ) // m_frame = 0; + m_hasUpdated = FALSE; m_frameObjectsChangedTriggerAreas = 0; m_width = 0; m_height = 0; @@ -256,6 +257,7 @@ GameLogic::GameLogic( void ) void GameLogic::setDefaults( Bool saveGame ) { m_frame = 0; + m_hasUpdated = FALSE; m_width = DEFAULT_WORLD_WIDTH; m_height = DEFAULT_WORLD_HEIGHT; m_objList = NULL; @@ -1020,6 +1022,7 @@ void GameLogic::startNewGame( Bool saveGame ) // reset the frame counter m_frame = 0; + m_hasUpdated = FALSE; #ifdef DEBUG_CRC // TheSuperHackers @info helmutbuhler 04/09/2025 @@ -3327,6 +3330,7 @@ void GameLogic::update( void ) if (!m_startNewGame) { m_frame++; + m_hasUpdated = TRUE; } } @@ -3334,6 +3338,8 @@ void GameLogic::update( void ) // ------------------------------------------------------------------------------------------------ void GameLogic::preUpdate() { + m_hasUpdated = FALSE; + if (m_pauseFrame == m_frame && m_pauseFrame != 0) { m_pauseFrame = 0; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index a1813f3d7e..a5e39e7403 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1733,6 +1733,10 @@ void W3DDisplay::draw( void ) WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + // TheSuperHackers @info This binds the WW3D update to the logic update. This was originally 33 ms, ~30 fps, integer. + // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + WW3D::Sync(TheGameLogic->hasUpdated()); + static Int now; now=timeGetTime(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index f44fa6820f..973b0ff2fb 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -1173,18 +1173,6 @@ void WW3D::Update_Logic_Frame_Time(float milliseconds) { LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; - unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; - -#if MSEC_PER_WWSYNC_FRAME - if (integralSyncMs < MSEC_PER_WWSYNC_FRAME) - { - Sync(SyncTime); - return; - } -#endif - - FractionalSyncMs -= integralSyncMs; - Sync(SyncTime + integralSyncMs); } @@ -1200,12 +1188,17 @@ void WW3D::Update_Logic_Frame_Time(float milliseconds) * HISTORY: * * 3/24/98 GTH : Created. * *=============================================================================================*/ -void WW3D::Sync(unsigned int sync_time) +void WW3D::Sync(bool step) { PreviousSyncTime = SyncTime; - SyncTime = sync_time; -} + if (step) + { + unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; + FractionalSyncMs -= integralSyncMs; + SyncTime += integralSyncMs; + } +} /*********************************************************************************************** * WW3D::Set_Ext_Swap_Interval -- Sets the swap interval the device should aim sync for. * diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index d32aa3861f..4cb8c5bf9b 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -163,14 +163,14 @@ class WW3D static void Flip_To_Primary(void); // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. - // This can be a fraction of a logic step. It will call Sync on its own once an appropriate amount of time has passed. + // This can be a fraction of a logic step. static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync(bool step); static unsigned int Get_Sync_Time(void) { return SyncTime; } static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } diff --git a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h index d7acdd7b4e..cb93ccd88d 100644 --- a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -17,9 +17,3 @@ */ #pragma once - -// The WW3D Sync time. This was originally 33 ms, ~30 fps, integer. -// Changing or removing this will require tweaking all Drawable code that concerns logic time step, including locomotion physics. -#ifndef MSEC_PER_WWSYNC_FRAME -#define MSEC_PER_WWSYNC_FRAME (33) -#endif diff --git a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h index 285847aad9..5931e710fd 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h +++ b/GeneralsMD/Code/GameEngine/Include/GameLogic/GameLogic.h @@ -138,6 +138,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Real getHeight( void ); ///< Returns the height of the world Bool isInGameLogicUpdate( void ) const { return m_isInUpdate; } + Bool hasUpdated() const { return m_hasUpdated; } ///< Returns true if the logic frame has advanced in the current client/render update UnsignedInt getFrame( void ); ///< Returns the current simulation frame number UnsignedInt getCRC( Int mode = CRC_CACHED, AsciiString deepCRCFileName = AsciiString::TheEmptyString ); ///< Returns the CRC @@ -324,6 +325,7 @@ class GameLogic : public SubsystemInterface, public Snapshot Bool m_clearingGameData; Bool m_isInUpdate; + Bool m_hasUpdated; Int m_rankPointsToAddAtGameStart; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp index 540731886d..7cdcc3eabb 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/System/GameLogic.cpp @@ -237,6 +237,7 @@ GameLogic::GameLogic( void ) // m_frame = 0; + m_hasUpdated = FALSE; m_frameObjectsChangedTriggerAreas = 0; m_width = 0; m_height = 0; @@ -271,6 +272,7 @@ GameLogic::GameLogic( void ) void GameLogic::setDefaults( Bool loadingSaveGame ) { m_frame = 0; + m_hasUpdated = FALSE; m_width = DEFAULT_WORLD_WIDTH; m_height = DEFAULT_WORLD_HEIGHT; m_objList = NULL; @@ -1157,6 +1159,7 @@ void GameLogic::startNewGame( Bool loadingSaveGame ) // reset the frame counter m_frame = 0; + m_hasUpdated = FALSE; #ifdef DEBUG_CRC // TheSuperHackers @info helmutbuhler 04/09/2025 @@ -3863,6 +3866,7 @@ void GameLogic::update( void ) if (!m_startNewGame) { m_frame++; + m_hasUpdated = TRUE; } } @@ -3870,6 +3874,8 @@ void GameLogic::update( void ) // ------------------------------------------------------------------------------------------------ void GameLogic::preUpdate() { + m_hasUpdated = FALSE; + if (m_pauseFrame == m_frame && m_pauseFrame != 0) { m_pauseFrame = 0; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index bef1b0e489..2ae78b18ec 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1814,6 +1814,10 @@ void W3DDisplay::draw( void ) WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); + // TheSuperHackers @info This binds the WW3D update to the logic update. This was originally 33 ms, ~30 fps, integer. + // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + WW3D::Sync(TheGameLogic->hasUpdated()); + static Int now; now=timeGetTime(); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 072d816efd..fdc9b93dc7 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -1168,18 +1168,6 @@ void WW3D::Update_Logic_Frame_Time(float milliseconds) { LogicFrameTimeMs = milliseconds; FractionalSyncMs += milliseconds; - unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; - -#if MSEC_PER_WWSYNC_FRAME - if (integralSyncMs < MSEC_PER_WWSYNC_FRAME) - { - Sync(SyncTime); - return; - } -#endif - - FractionalSyncMs -= integralSyncMs; - Sync(SyncTime + integralSyncMs); } @@ -1195,12 +1183,17 @@ void WW3D::Update_Logic_Frame_Time(float milliseconds) * HISTORY: * * 3/24/98 GTH : Created. * *=============================================================================================*/ -void WW3D::Sync(unsigned int sync_time) +void WW3D::Sync(bool step) { PreviousSyncTime = SyncTime; - SyncTime = sync_time; -} + if (step) + { + unsigned int integralSyncMs = (unsigned int)FractionalSyncMs; + FractionalSyncMs -= integralSyncMs; + SyncTime += integralSyncMs; + } +} /*********************************************************************************************** * WW3D::Set_Ext_Swap_Interval -- Sets the swap interval the device should aim sync for. * diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index b46b135dce..0057dbf989 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -163,14 +163,14 @@ class WW3D static void Flip_To_Primary(void); // TheSuperHackers @info Add amount of milliseconds that the simulation has advanced in this render frame. - // This can be a fraction of a logic step. It will call Sync on its own once an appropriate amount of time has passed. + // This can be a fraction of a logic step. static void Update_Logic_Frame_Time(float milliseconds); /* ** Timing ** By calling the Sync function, the application can move the ww3d library time forward. This ** will control things like animated uv-offset mappers and render object animations. */ - static void Sync( unsigned int sync_time ); + static void Sync(bool step); static unsigned int Get_Sync_Time(void) { return SyncTime; } static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } From 05ec70b42a94cba5a978e28f0fd769c0a13ff2ed Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sat, 13 Sep 2025 20:58:18 +0200 Subject: [PATCH 08/14] refactor(anim): Cleanup and simplify animation code a bit (#1579) --- Core/Libraries/Source/WWVegas/WW3D2/hanim.h | 4 --- Core/Libraries/Source/WWVegas/WW3D2/hcanim.h | 2 -- .../Source/WWVegas/WW3D2/animobj.cpp | 26 ++++++++++--------- .../Libraries/Source/WWVegas/WW3D2/animobj.h | 4 +-- .../Source/WWVegas/WW3D2/hmorphanim.h | 2 -- .../Libraries/Source/WWVegas/WW3D2/hrawanim.h | 2 -- .../Source/WWVegas/WW3D2/animobj.cpp | 26 ++++++++++--------- .../Libraries/Source/WWVegas/WW3D2/animobj.h | 4 +-- .../Source/WWVegas/WW3D2/hmorphanim.h | 2 -- .../Libraries/Source/WWVegas/WW3D2/hrawanim.h | 2 -- 10 files changed, 32 insertions(+), 42 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hanim.h b/Core/Libraries/Source/WWVegas/WW3D2/hanim.h index 6565263988..34df969829 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hanim.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/hanim.h @@ -95,11 +95,7 @@ class HAnimClass : public RefCountClass, public HashableClass virtual float Get_Frame_Rate() = 0; virtual float Get_Total_Time() = 0; -// virtual Vector3 Get_Translation(int pividx,float frame) = 0; -// virtual Quaternion Get_Orientation(int pividx,float frame) = 0; // Jani: Changed to pass in reference of destination to avoid copying - virtual void Get_Translation(int pividx,float frame) {} // todo: remove - virtual void Get_Orientation(int pividx,float frame) {} // todo: remove virtual void Get_Translation(Vector3& translation, int pividx,float frame) const = 0; virtual void Get_Orientation(Quaternion& orientation, int pividx,float frame) const = 0; virtual void Get_Transform(Matrix3D&, int pividx, float frame) const = 0; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h index fe21ef1787..5924046fff 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/hcanim.h @@ -93,8 +93,6 @@ class HCompressedAnimClass : public HAnimClass float Get_Total_Time() { return (float)NumFrames / FrameRate; } int Get_Flavor() { return Flavor; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 2b81b7b36c..4cf15ff829 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -941,18 +941,20 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // // Wrap the frame // + const int numFrames = ModeAnim.Motion->Get_Num_Frames() - 1; + switch (ModeAnim.AnimMode) { case ANIM_MODE_ONCE: - if (frame >= ModeAnim.Motion->Get_Num_Frames() - 1) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + if (frame >= numFrames) { + frame = numFrames; } break; case ANIM_MODE_LOOP: - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame -= ModeAnim.Motion->Get_Num_Frames() - 1; + if ( frame >= numFrames ) { + frame -= numFrames; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { + if ( frame >= numFrames ) { frame = 0; } } @@ -964,22 +966,22 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const break; case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { - frame += ModeAnim.Motion->Get_Num_Frames() - 1; + frame += numFrames; // If it is still too far out, reset if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + frame = numFrames; } } break; case ANIM_MODE_LOOP_PINGPONG: if (ModeAnim.animDirection >= 1.0f) { //playing forwards, reverse direction - if (frame >= (ModeAnim.Motion->Get_Num_Frames() - 1)) + if (frame >= numFrames) { //step backwards in animation by excess time - frame = (ModeAnim.Motion->Get_Num_Frames() - 1)*2 - frame; + frame = numFrames * 2 - frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) - frame = (ModeAnim.Motion->Get_Num_Frames() - 1); + if ( frame >= numFrames - 1 ) + frame = numFrames; direction = ModeAnim.animDirection * -1.0f; } } @@ -989,7 +991,7 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { //step forwards in animation by excess time frame = -frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) + if ( frame >= numFrames ) frame = 0; direction = ModeAnim.animDirection * -1.0f; } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index 174c1eeafe..02a3f53425 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -261,8 +261,8 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { - if (ModeAnim.Motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(Transform,(HRawAnimClass*)ModeAnim.Motion,ModeAnim.Frame); + if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) + HTree->Anim_Update(root,(HRawAnimClass*)motion,frame); else HTree->Anim_Update(root,motion,frame); } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h index 425aec33d2..c74753c7b2 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h @@ -94,8 +94,6 @@ class HMorphAnimClass : public HAnimClass float Get_Frame_Rate() { return FrameRate; } float Get_Total_Time() { return (float)FrameCount / FrameRate; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h index 3cb08cce44..9056626704 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h @@ -97,8 +97,6 @@ class HRawAnimClass : public HAnimClass float Get_Frame_Rate() { return FrameRate; } float Get_Total_Time() { return (float)NumFrames / FrameRate; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 86ba38c191..15e089a0ba 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -949,18 +949,20 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const // // Wrap the frame // + const int numFrames = ModeAnim.Motion->Get_Num_Frames() - 1; + switch (ModeAnim.AnimMode) { case ANIM_MODE_ONCE: - if (frame >= ModeAnim.Motion->Get_Num_Frames() - 1) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + if (frame >= numFrames) { + frame = numFrames; } break; case ANIM_MODE_LOOP: - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { - frame -= ModeAnim.Motion->Get_Num_Frames() - 1; + if ( frame >= numFrames ) { + frame -= numFrames; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) { + if ( frame >= numFrames ) { frame = 0; } } @@ -972,22 +974,22 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const break; case ANIM_MODE_LOOP_BACKWARDS: //play animation backwards in a loop if ( frame < 0 ) { - frame += ModeAnim.Motion->Get_Num_Frames() - 1; + frame += numFrames; // If it is still too far out, reset if ( frame < 0 ) { - frame = ModeAnim.Motion->Get_Num_Frames() - 1; + frame = numFrames; } } break; case ANIM_MODE_LOOP_PINGPONG: if (ModeAnim.animDirection >= 1.0f) { //playing forwards, reverse direction - if (frame >= (ModeAnim.Motion->Get_Num_Frames() - 1)) + if (frame >= numFrames) { //step backwards in animation by excess time - frame = (ModeAnim.Motion->Get_Num_Frames() - 1)*2 - frame; + frame = numFrames * 2 - frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) - frame = (ModeAnim.Motion->Get_Num_Frames() - 1); + if ( frame >= numFrames - 1 ) + frame = numFrames; direction = ModeAnim.animDirection * -1.0f; } } @@ -997,7 +999,7 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { //step forwards in animation by excess time frame = -frame; // If it is still too far out, reset - if ( frame >= ModeAnim.Motion->Get_Num_Frames() - 1 ) + if ( frame >= numFrames ) frame = 0; direction = ModeAnim.animDirection * -1.0f; } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index 6985ade3eb..9a34e9c8eb 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -261,8 +261,8 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { - if (ModeAnim.Motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(Transform,(HRawAnimClass*)ModeAnim.Motion,ModeAnim.Frame); + if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) + HTree->Anim_Update(root,(HRawAnimClass*)motion,frame); else HTree->Anim_Update(root,motion,frame); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h index 537fb9639d..e6c8a27350 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hmorphanim.h @@ -94,8 +94,6 @@ class HMorphAnimClass : public HAnimClass float Get_Frame_Rate() { return FrameRate; } float Get_Total_Time() { return (float)FrameCount / FrameRate; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h index 38733f89b2..0ea90bfbf2 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/hrawanim.h @@ -97,8 +97,6 @@ class HRawAnimClass : public HAnimClass float Get_Frame_Rate() { return FrameRate; } float Get_Total_Time() { return (float)NumFrames / FrameRate; } -// Vector3 Get_Translation(int pividx,float frame); -// Quaternion Get_Orientation(int pividx,float frame); void Get_Translation(Vector3& translation, int pividx,float frame) const; void Get_Orientation(Quaternion& orientation, int pividx,float frame) const; void Get_Transform(Matrix3D& transform, int pividx,float frame) const; From 0bc8079e62fae5801a18fee3eb035002d56ec5d1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Sep 2025 09:57:25 +0200 Subject: [PATCH 09/14] tweak(anim): Enable interpolation for raw animation updates and couple the legacy non interpolated updates to the ww3d sync (#1579) --- Core/Libraries/Source/WWVegas/WW3D2/htree.cpp | 11 ++++++++++- Core/Libraries/Source/WWVegas/WW3D2/htree.h | 2 +- Core/Libraries/Source/WWVegas/WWLib/WWCommon.h | 6 ++++++ Core/Libraries/Source/WWVegas/WWLib/WWDefines.h | 9 +++++++++ Generals/Code/GameEngine/Include/Common/GameCommon.h | 2 +- Generals/Code/GameEngine/Source/Common/GameEngine.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 3 +-- .../Code/Libraries/Source/WWVegas/WW3D2/animobj.h | 4 +++- Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 2 +- Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h | 9 +++++++++ .../Code/GameEngine/Include/Common/GameCommon.h | 2 +- .../Code/GameEngine/Source/Common/GameEngine.cpp | 2 +- .../Source/W3DDevice/GameClient/W3DDisplay.cpp | 3 +-- .../Code/Libraries/Source/WWVegas/WW3D2/animobj.h | 4 +++- .../Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp | 2 +- 15 files changed, 49 insertions(+), 14 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp b/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp index 0a8d11c999..db808dc948 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/htree.cpp @@ -62,6 +62,7 @@ #include "wwmemlog.h" #include "hrawanim.h" #include "motchan.h" +#include "ww3d.h" /*********************************************************************************************** * HTreeClass::HTreeClass -- constructor * @@ -606,8 +607,16 @@ void HTreeClass::Anim_Update(const Matrix3D & root,HAnimClass * motion,float fra /*Customized version of the above which excludes interpolation and assumes HRawAnimClass For use by 'Generals' -MW*/ -void HTreeClass::Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame) +void HTreeClass::Anim_Update_Without_Interpolation(const Matrix3D & root,HRawAnimClass * motion,float frame) { + if (WW3D::Get_Sync_Frame_Time() == 0 && (int)motion->Get_Frame_Rate() == WWSyncPerSecond) + { + // TheSuperHackers @tweak Keep the animation frame step in sync with the ww3d frame step if they can align. + // @todo This needs improving if the WWSyncPerSecond is changed or the animation frame rates can be larger. + static_assert(WWSyncPerSecond == 30, "This is currently catered to a 30 fps sync"); + return; + } + PivotClass *pivot,*endpivot,*lastAnimPivot; Pivot[0].Transform = root; diff --git a/Core/Libraries/Source/WWVegas/WW3D2/htree.h b/Core/Libraries/Source/WWVegas/WW3D2/htree.h index f0fe2c563c..01e993061f 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/htree.h +++ b/Core/Libraries/Source/WWVegas/WW3D2/htree.h @@ -100,7 +100,7 @@ class HTreeClass : public W3DMPO void Anim_Update( const Matrix3D & root, HAnimClass * motion, float frame); - void Anim_Update(const Matrix3D & root,HRawAnimClass * motion,float frame); + void Anim_Update_Without_Interpolation(const Matrix3D & root,HRawAnimClass * motion,float frame); void Blend_Update( const Matrix3D & root, HAnimClass * motion0, diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h index a2a2248ecc..329324ca51 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWCommon.h @@ -26,6 +26,12 @@ #define ARRAY_SIZE(x) int(sizeof(x)/sizeof(x[0])) #endif +enum +{ + // TheSuperHackers @info The original WWSync was 33 ms, ~30 fps, integer. + // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + WWSyncPerSecond = 30 +}; #if defined(_MSC_VER) && _MSC_VER < 1300 typedef unsigned MemValueType; diff --git a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h index cb93ccd88d..eb25d597db 100644 --- a/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Core/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -17,3 +17,12 @@ */ #pragma once + +// Enable translation and rotation interpolation for raw animation (HRawAnimClass) updates. +// This was intentionally disabled in the retail version, but likely not fully thought through. +// Interpolation is certainly desired for animations that move and rotate meshes, but may not be +// desired for animations that teleport meshes from one location to another, such as blinking lights. +// @todo Implement a new flag per animation file to opt-out of interpolation. +#ifndef WW3D_ENABLE_RAW_ANIM_INTERPOLATION +#define WW3D_ENABLE_RAW_ANIM_INTERPOLATION (1) +#endif diff --git a/Generals/Code/GameEngine/Include/Common/GameCommon.h b/Generals/Code/GameEngine/Include/Common/GameCommon.h index 87813783e1..e83eea3bb3 100644 --- a/Generals/Code/GameEngine/Include/Common/GameCommon.h +++ b/Generals/Code/GameEngine/Include/Common/GameCommon.h @@ -66,7 +66,7 @@ enum { BaseFps = 30, // The historic base frame rate for this game. This value must never change. - LOGICFRAMES_PER_SECOND = 30, + LOGICFRAMES_PER_SECOND = WWSyncPerSecond, MSEC_PER_SECOND = 1000 }; const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND)); diff --git a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp index c2b324641c..58a1419c12 100644 --- a/Generals/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/Generals/Code/GameEngine/Source/Common/GameEngine.cpp @@ -255,7 +255,7 @@ GameEngine::GameEngine( void ) // initialize to non garbage values m_maxFPS = BaseFps; m_logicTimeScaleFPS = LOGICFRAMES_PER_SECOND; - m_updateTime = 0.0f; + m_updateTime = 1.0f / BaseFps; // initialized to something to avoid division by zero on first use m_logicTimeAccumulator = 0.0f; m_quitting = FALSE; m_isActive = FALSE; diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index a5e39e7403..c839a8e988 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1733,8 +1733,7 @@ void W3DDisplay::draw( void ) WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); - // TheSuperHackers @info This binds the WW3D update to the logic update. This was originally 33 ms, ~30 fps, integer. - // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + // TheSuperHackers @info This binds the WW3D update to the logic update. WW3D::Sync(TheGameLogic->hasUpdated()); static Int now; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index 02a3f53425..b93b1bc775 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -261,9 +261,11 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { +#if !WW3D_ENABLE_RAW_ANIM_INTERPOLATION if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(root,(HRawAnimClass*)motion,frame); + HTree->Anim_Update_Without_Interpolation(root,(HRawAnimClass*)motion,frame); else +#endif HTree->Anim_Update(root,motion,frame); } Set_Hierarchy_Valid(true); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index 973b0ff2fb..0acd23d847 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -165,7 +165,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ -float WW3D::LogicFrameTimeMs = 33.33f; +float WW3D::LogicFrameTimeMs = 1000.0f / WWSyncPerSecond; // initialized to something to avoid division by zero on first use float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; diff --git a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h index cb93ccd88d..eb25d597db 100644 --- a/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h +++ b/Generals/Libraries/Source/WWVegas/WWLib/WWDefines.h @@ -17,3 +17,12 @@ */ #pragma once + +// Enable translation and rotation interpolation for raw animation (HRawAnimClass) updates. +// This was intentionally disabled in the retail version, but likely not fully thought through. +// Interpolation is certainly desired for animations that move and rotate meshes, but may not be +// desired for animations that teleport meshes from one location to another, such as blinking lights. +// @todo Implement a new flag per animation file to opt-out of interpolation. +#ifndef WW3D_ENABLE_RAW_ANIM_INTERPOLATION +#define WW3D_ENABLE_RAW_ANIM_INTERPOLATION (1) +#endif diff --git a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h index 723ab57d2b..2ce08a130f 100644 --- a/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h +++ b/GeneralsMD/Code/GameEngine/Include/Common/GameCommon.h @@ -72,7 +72,7 @@ enum { BaseFps = 30, // The historic base frame rate for this game. This value must never change. - LOGICFRAMES_PER_SECOND = 30, + LOGICFRAMES_PER_SECOND = WWSyncPerSecond, MSEC_PER_SECOND = 1000 }; const Real LOGICFRAMES_PER_MSEC_REAL = (((Real)LOGICFRAMES_PER_SECOND) / ((Real)MSEC_PER_SECOND)); diff --git a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp index c7f30f53eb..02d786b4e5 100644 --- a/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp +++ b/GeneralsMD/Code/GameEngine/Source/Common/GameEngine.cpp @@ -253,7 +253,7 @@ GameEngine::GameEngine( void ) // initialize to non garbage values m_maxFPS = BaseFps; m_logicTimeScaleFPS = LOGICFRAMES_PER_SECOND; - m_updateTime = 0.0f; + m_updateTime = 1.0f / BaseFps; // initialized to something to avoid division by zero on first use m_logicTimeAccumulator = 0.0f; m_quitting = FALSE; m_isActive = FALSE; diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp index 2ae78b18ec..3b7fd684fd 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DDisplay.cpp @@ -1814,8 +1814,7 @@ void W3DDisplay::draw( void ) WW3D::Update_Logic_Frame_Time(TheGameEngine->getLogicTimeStepMilliseconds()); - // TheSuperHackers @info This binds the WW3D update to the logic update. This was originally 33 ms, ~30 fps, integer. - // Changing this will require tweaking all Drawable code that concerns the ww3d time step, including locomotion physics. + // TheSuperHackers @info This binds the WW3D update to the logic update. WW3D::Sync(TheGameLogic->hasUpdated()); static Int now; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index 9a34e9c8eb..437480caf1 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -261,9 +261,11 @@ inline void Animatable3DObjClass::Anim_Update(const Matrix3D & root,HAnimClass * ** Apply motion to the base pose */ if ((motion) && (HTree)) { +#if !WW3D_ENABLE_RAW_ANIM_INTERPOLATION if (motion->Class_ID() == HAnimClass::CLASSID_HRAWANIM) - HTree->Anim_Update(root,(HRawAnimClass*)motion,frame); + HTree->Anim_Update_Without_Interpolation(root,(HRawAnimClass*)motion,frame); else +#endif HTree->Anim_Update(root,motion,frame); } Set_Hierarchy_Valid(true); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp index fdc9b93dc7..c27bd87134 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.cpp @@ -166,7 +166,7 @@ const char* DAZZLE_INI_FILENAME="DAZZLE.INI"; ** ***********************************************************************************/ -float WW3D::LogicFrameTimeMs = 33.33f; +float WW3D::LogicFrameTimeMs = 1000.0f / WWSyncPerSecond; // initialized to something to avoid division by zero on first use float WW3D::FractionalSyncMs = 0.0f; unsigned int WW3D::SyncTime = 0; unsigned int WW3D::PreviousSyncTime = 0; From 9289ee183addf2ba9269345c350a8bba5ef73ef1 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Sep 2025 12:13:41 +0200 Subject: [PATCH 10/14] tweak(heightmap): Decouple cloud render update from logic step (#1579) --- .../Include/W3DDevice/GameClient/HeightMap.h | 4 +- .../W3DDevice/GameClient/W3DShaderManager.h | 2 + .../Source/W3DDevice/GameClient/HeightMap.cpp | 24 ++++++---- .../W3DDevice/GameClient/W3DShaderManager.cpp | 44 +++++++++---------- .../W3DDevice/GameClient/BaseHeightMap.h | 2 + .../Include/W3DDevice/GameClient/HeightMap.h | 7 +-- .../W3DDevice/GameClient/W3DShaderManager.h | 2 + .../W3DDevice/GameClient/BaseHeightMap.cpp | 5 +++ .../W3DDevice/GameClient/FlatHeightMap.cpp | 13 +++--- .../Source/W3DDevice/GameClient/HeightMap.cpp | 18 ++++---- .../W3DDevice/GameClient/W3DShaderManager.cpp | 44 +++++++++---------- 11 files changed, 89 insertions(+), 76 deletions(-) diff --git a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h index 5be5f6fc74..52cc395bc6 100644 --- a/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h +++ b/Generals/Code/GameEngineDevice/Include/W3DDevice/GameClient/HeightMap.h @@ -180,7 +180,6 @@ class HeightMapRenderObjClass : public RenderObjClass, public DX8_CleanupHook void renderTerrainPass(CameraClass *pCamera); ///< renders additional terrain pass. W3DShroud *getShroud() {return m_shroud;} - void renderExtraBlendTiles(void); ///< render 3-way blend tiles that have blend of 3 textures. void updateShorelineTiles(Int minX, Int minY, Int maxX, Int maxY, WorldHeightMap *pMap); ///
m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); #if 0 // There is some weirdness sometimes with the dx8 static buffers. @@ -3906,10 +3913,6 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_TERRAIN_BASE; //set default shader //set correct shader based on current settings @@ -4454,10 +4457,7 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) W3DShaderManager::ShaderTypes st = W3DShaderManager::ST_ROAD_BASE; - Bool doCloud = TheGlobalData->m_useCloudMap; - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } + const Bool doCloud = useCloud(); if (TheGlobalData->m_useLightMap && doCloud) { @@ -4486,3 +4486,9 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) } } } + +//============================================================================= +Bool HeightMapRenderObjClass::useCloud() +{ + return TheGlobalData->m_useCloudMap && TheGlobalData->m_timeOfDay != TIME_OF_DAY_NIGHT; +} diff --git a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index 2c9d8a26d5..a219e4912d 100644 --- a/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/Generals/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1248,12 +1248,14 @@ class TerrainShader2Stage : public W3DShaderInterface public: float m_xSlidePerSecond ; ///< How far the clouds move per second. float m_ySlidePerSecond ; ///< How far the clouds move per second. - int m_curTick; float m_xOffset; float m_yOffset; + virtual Int set(Int pass); /// 1) m_xOffset -= 1; + while (m_yOffset > 1) m_yOffset -= 1; + while (m_xOffset < -1) m_xOffset += 1; + while (m_yOffset < -1) m_yOffset += 1; +} + void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curViewInverse, Bool doUpdate) { #define STRETCH_FACTOR ((float)(1/(63.0*MAP_XY_FACTOR/2))) /* covers 63/2 tiles */ @@ -1340,26 +1352,6 @@ void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curVie *destMatrix = *curViewInverse * scale; D3DXMATRIX offset; - - Int delta = m_curTick; - m_curTick = WW3D::Get_Sync_Time();//::GetTickCount(); - delta = m_curTick-delta; - m_xOffset += m_xSlidePerSecond*delta/1000; - m_yOffset += m_ySlidePerSecond*delta/1000; - - - //m_xOffset += m_xSlidePerSecond*delta/500; - //m_yOffset += m_ySlidePerSecond*delta/500; - - - //m_yOffset = sinf( (float)m_curTick * 0.0001f ); - //m_xOffset = cosf( (float)m_curTick * 0.0001f ); - - if (m_xOffset > 1) m_xOffset -= 1; - if (m_yOffset > 1) m_yOffset -= 1; - if (m_xOffset < -1) m_xOffset += 1; - if (m_yOffset < -1) m_yOffset += 1; - D3DXMatrixTranslation(&offset, m_xOffset, m_yOffset,0); *destMatrix *= offset; } @@ -2447,6 +2439,12 @@ void W3DShaderManager::shutdown(void) } } +//============================================================================= +void W3DShaderManager::updateCloud() +{ + terrainShader2Stage.updateCloud(); +} + // W3DShaderManager::getShaderPasses ======================================================= /** Return number of renderig passes required in perform the desired shader on current hardware. App will need to re-render the polygons this many times to complete the diff --git a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h index 7e439de2da..60165711af 100644 --- a/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h +++ b/GeneralsMD/Code/GameEngineDevice/Include/W3DDevice/GameClient/BaseHeightMap.h @@ -328,6 +328,8 @@ class BaseHeightMapRenderObjClass : public RenderObjClass, public DX8_CleanupHoo void initDestAlphaLUT(void); ///m_useCloudMap && TheGlobalData->m_timeOfDay != TIME_OF_DAY_NIGHT; +} diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp index 07a36aad45..553e62db20 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/FlatHeightMap.cpp @@ -459,7 +459,14 @@ void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo) Int devicePasses; W3DShaderManager::ShaderTypes st; - Bool doCloud = TheGlobalData->m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); // If there are trees, tell them to draw at the transparent time to draw. @@ -494,10 +501,6 @@ void FlatHeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_FLAT_TERRAIN_BASE; //set default shader //set correct shader based on current settings diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp index 7891e46bdc..6b7dbd25a8 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/HeightMap.cpp @@ -1912,7 +1912,14 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) Int i,j,devicePasses; W3DShaderManager::ShaderTypes st; - Bool doCloud = TheGlobalData->m_useCloudMap; + const Bool doCloud = useCloud(); + + if (doCloud) + { + // TheSuperHackers @tweak Updates the cloud movement before applying it to the world. + // Is now decoupled from logic step. + W3DShaderManager::updateCloud(); + } Matrix3D tm(Transform); #if 0 // There is some weirdness sometimes with the dx8 static buffers. @@ -2003,10 +2010,6 @@ void HeightMapRenderObjClass::Render(RenderInfoClass & rinfo) DX8Wrapper::Set_Material(m_vertexMaterialClass); DX8Wrapper::Set_Shader(m_shaderClass); - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } - st=W3DShaderManager::ST_TERRAIN_BASE; //set default shader //set correct shader based on current settings @@ -2415,10 +2418,7 @@ void HeightMapRenderObjClass::renderExtraBlendTiles(void) W3DShaderManager::ShaderTypes st = W3DShaderManager::ST_ROAD_BASE; - Bool doCloud = TheGlobalData->m_useCloudMap; - if (TheGlobalData->m_timeOfDay == TIME_OF_DAY_NIGHT) { - doCloud = false; - } + const Bool doCloud = useCloud(); if (TheGlobalData->m_useLightMap && doCloud) { diff --git a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp index b487858291..a3df459813 100644 --- a/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp +++ b/GeneralsMD/Code/GameEngineDevice/Source/W3DDevice/GameClient/W3DShaderManager.cpp @@ -1482,12 +1482,14 @@ class TerrainShader2Stage : public W3DShaderInterface public: float m_xSlidePerSecond ; ///< How far the clouds move per second. float m_ySlidePerSecond ; ///< How far the clouds move per second. - int m_curTick; float m_xOffset; float m_yOffset; + virtual Int set(Int pass); /// 1) m_xOffset -= 1; + while (m_yOffset > 1) m_yOffset -= 1; + while (m_xOffset < -1) m_xOffset += 1; + while (m_yOffset < -1) m_yOffset += 1; +} + void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curViewInverse, Bool doUpdate) { #define STRETCH_FACTOR ((float)(1/(63.0*MAP_XY_FACTOR/2))) /* covers 63/2 tiles */ @@ -1605,26 +1617,6 @@ void TerrainShader2Stage::updateNoise1(D3DXMATRIX *destMatrix,D3DXMATRIX *curVie *destMatrix = *curViewInverse * scale; D3DXMATRIX offset; - - Int delta = m_curTick; - m_curTick = WW3D::Get_Sync_Time();//::GetTickCount(); - delta = m_curTick-delta; - m_xOffset += m_xSlidePerSecond*delta/1000; - m_yOffset += m_ySlidePerSecond*delta/1000; - - - //m_xOffset += m_xSlidePerSecond*delta/500; - //m_yOffset += m_ySlidePerSecond*delta/500; - - - //m_yOffset = sinf( (float)m_curTick * 0.0001f ); - //m_xOffset = cosf( (float)m_curTick * 0.0001f ); - - while (m_xOffset > 1) m_xOffset -= 1; - while (m_yOffset > 1) m_yOffset -= 1; - while (m_xOffset < -1) m_xOffset += 1; - while (m_yOffset < -1) m_yOffset += 1; - D3DXMatrixTranslation(&offset, m_xOffset, m_yOffset,0); *destMatrix *= offset; } @@ -2704,6 +2696,12 @@ void W3DShaderManager::shutdown(void) } +//============================================================================= +void W3DShaderManager::updateCloud() +{ + terrainShader2Stage.updateCloud(); +} + // W3DShaderManager::getShaderPasses ======================================================= /** Return number of renderig passes required in perform the desired shader on current hardware. App will need to re-render the polygons this many times to complete the From 6f6e458e700007ee2a9aa61e1b4dd83c2f781c54 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Sep 2025 18:09:44 +0200 Subject: [PATCH 11/14] bugfix(drawable): Fix locked color in Drawable::colorTint, EMPUpdate::update (#1579) --- .../GameEngine/Include/GameClient/Drawable.h | 5 ++--- .../GameEngine/Source/GameClient/Drawable.cpp | 17 +++-------------- .../GameLogic/Object/Update/EMPUpdate.cpp | 2 +- .../GameEngine/Include/GameClient/Drawable.h | 5 ++--- .../GameEngine/Source/GameClient/Drawable.cpp | 17 +++-------------- .../GameLogic/Object/Update/EMPUpdate.cpp | 2 +- 6 files changed, 12 insertions(+), 36 deletions(-) diff --git a/Generals/Code/GameEngine/Include/GameClient/Drawable.h b/Generals/Code/GameEngine/Include/GameClient/Drawable.h index 8807b3930e..750f76fcf8 100644 --- a/Generals/Code/GameEngine/Include/GameClient/Drawable.h +++ b/Generals/Code/GameEngine/Include/GameClient/Drawable.h @@ -168,7 +168,7 @@ class TintEnvelope : public MemoryPoolObject, public Snapshot TintEnvelope(void); void update(void); ///< does all the work void play(const RGBColor *peak, - UnsignedInt atackFrames = DEF_ATTACK_FRAMES, + UnsignedInt attackFrames = DEF_ATTACK_FRAMES, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt sustainAtPeak = DEF_SUSTAIN_FRAMES ); // ask MLorenzen void sustain(void) { m_envState = ENVELOPE_STATE_SUSTAIN; } @@ -231,7 +231,6 @@ enum DrawableStatus CPP_11(: DrawableStatusBits) DRAWABLE_STATUS_NONE = 0x00000000, ///< no status DRAWABLE_STATUS_DRAWS_IN_MIRROR = 0x00000001, ///< drawable can reflect DRAWABLE_STATUS_SHADOWS = 0x00000002, ///< use setShadowsEnabled() access method - DRAWABLE_STATUS_TINT_COLOR_LOCKED = 0x00000004, ///< drawable tint color is "locked" and won't fade to normal DRAWABLE_STATUS_NO_STATE_PARTICLES = 0x00000008, ///< do *not* auto-create particle systems based on model condition DRAWABLE_STATUS_NO_SAVE = 0x00000010, ///< do *not* save this drawable (UI fluff only). ignored (error, actually) if attached to an object @@ -372,7 +371,7 @@ class Drawable : public Thing, Bool getDrawsInMirror() const { return BitIsSet(m_status, DRAWABLE_STATUS_DRAWS_IN_MIRROR) || isKindOf(KINDOF_CAN_CAST_REFLECTIONS); } - void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = FALSE ); ///< flash a drawable in the color specified for a short time + void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = 0 ); ///< flash a drawable in the color specified for a short time void colorTint( const RGBColor *color ); ///< tint this drawable the color specified void setTintEnvelope( const RGBColor *color, Real attack, Real decay ); ///< how to transition color void flashAsSelected( const RGBColor *color = NULL ); ///< drawable takes care of the details if you spec no color diff --git a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp index 4dd5fcee67..891bd99470 100644 --- a/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/Generals/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -922,9 +922,6 @@ void Drawable::colorFlash( const RGBColor* color, UnsignedInt decayFrames, Unsig white.setFromInt(0xffffffff); m_colorTintEnvelope->play( &white ); } - - // make sure the tint color is unlocked so we "fade back down" to normal - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); } // ------------------------------------------------------------------------------------------------ @@ -935,11 +932,7 @@ void Drawable::colorTint( const RGBColor* color ) if( color ) { // set the color via color flash - colorFlash( color, 0, 0, TRUE ); - - // lock the tint color so the flash never "fades back down" - setDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - + colorFlash( color, 0, 0, ~0u ); } else { @@ -948,10 +941,6 @@ void Drawable::colorTint( const RGBColor* color ) // remove the tint applied to the object m_colorTintEnvelope->rest(); - - // set the tint as unlocked so we can flash and stuff again - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - } } @@ -4756,11 +4745,11 @@ TintEnvelope::TintEnvelope(void) const Real FADE_RATE_EPSILON = (0.001f); //------------------------------------------------------------------------------------------------- -void TintEnvelope::play(const RGBColor *peak, UnsignedInt atackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) +void TintEnvelope::play(const RGBColor *peak, UnsignedInt attackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) { setPeakColor( peak ); - setAttackFrames( atackFrames ); + setAttackFrames( attackFrames ); setDecayFrames( decayFrames ); m_envState = ENVELOPE_STATE_ATTACK; diff --git a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp index 3bfdc41b17..328d1dfdbe 100644 --- a/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp +++ b/Generals/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp @@ -147,7 +147,7 @@ UpdateSleepTime EMPUpdate::update( void ) { RGBColor end = data->m_endColor; saturateRGB( end, 5 ); - dr->colorFlash( &end, 9999, m_tintEnvFadeFrames, TRUE ); + dr->colorFlash( &end, 0, m_tintEnvFadeFrames, ~0u ); doDisableAttack(); } diff --git a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h index 868a189584..7f320bd409 100644 --- a/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h +++ b/GeneralsMD/Code/GameEngine/Include/GameClient/Drawable.h @@ -171,7 +171,7 @@ class TintEnvelope : public MemoryPoolObject, public Snapshot TintEnvelope(void); void update(void); ///< does all the work void play(const RGBColor *peak, - UnsignedInt atackFrames = DEF_ATTACK_FRAMES, + UnsignedInt attackFrames = DEF_ATTACK_FRAMES, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt sustainAtPeak = DEF_SUSTAIN_FRAMES ); // ask MLorenzen void sustain(void) { m_envState = ENVELOPE_STATE_SUSTAIN; } @@ -234,7 +234,6 @@ enum DrawableStatus CPP_11(: DrawableStatusBits) DRAWABLE_STATUS_NONE = 0x00000000, ///< no status DRAWABLE_STATUS_DRAWS_IN_MIRROR = 0x00000001, ///< drawable can reflect DRAWABLE_STATUS_SHADOWS = 0x00000002, ///< use setShadowsEnabled() access method - DRAWABLE_STATUS_TINT_COLOR_LOCKED = 0x00000004, ///< drawable tint color is "locked" and won't fade to normal DRAWABLE_STATUS_NO_STATE_PARTICLES = 0x00000008, ///< do *not* auto-create particle systems based on model condition DRAWABLE_STATUS_NO_SAVE = 0x00000010, ///< do *not* save this drawable (UI fluff only). ignored (error, actually) if attached to an object @@ -388,7 +387,7 @@ class Drawable : public Thing, Bool getDrawsInMirror() const { return BitIsSet(m_status, DRAWABLE_STATUS_DRAWS_IN_MIRROR) || isKindOf(KINDOF_CAN_CAST_REFLECTIONS); } - void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = FALSE ); ///< flash a drawable in the color specified for a short time + void colorFlash( const RGBColor *color, UnsignedInt decayFrames = DEF_DECAY_FRAMES, UnsignedInt attackFrames = 0, UnsignedInt sustainAtPeak = 0 ); ///< flash a drawable in the color specified for a short time void colorTint( const RGBColor *color ); ///< tint this drawable the color specified void setTintEnvelope( const RGBColor *color, Real attack, Real decay ); ///< how to transition color void flashAsSelected( const RGBColor *color = NULL ); ///< drawable takes care of the details if you spec no color diff --git a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp index 1358b1b054..dce9e2c412 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameClient/Drawable.cpp @@ -971,9 +971,6 @@ void Drawable::colorFlash( const RGBColor* color, UnsignedInt decayFrames, Unsig white.setFromInt(0xffffffff); m_colorTintEnvelope->play( &white ); } - - // make sure the tint color is unlocked so we "fade back down" to normal - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); } // ------------------------------------------------------------------------------------------------ @@ -984,11 +981,7 @@ void Drawable::colorTint( const RGBColor* color ) if( color ) { // set the color via color flash - colorFlash( color, 0, 0, TRUE ); - - // lock the tint color so the flash never "fades back down" - setDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - + colorFlash( color, 0, 0, ~0u ); } else { @@ -997,10 +990,6 @@ void Drawable::colorTint( const RGBColor* color ) // remove the tint applied to the object m_colorTintEnvelope->rest(); - - // set the tint as unlocked so we can flash and stuff again - clearDrawableStatus( DRAWABLE_STATUS_TINT_COLOR_LOCKED ); - } } @@ -5513,11 +5502,11 @@ TintEnvelope::TintEnvelope(void) const Real FADE_RATE_EPSILON = (0.001f); //------------------------------------------------------------------------------------------------- -void TintEnvelope::play(const RGBColor *peak, UnsignedInt atackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) +void TintEnvelope::play(const RGBColor *peak, UnsignedInt attackFrames, UnsignedInt decayFrames, UnsignedInt sustainAtPeak ) { setPeakColor( peak ); - setAttackFrames( atackFrames ); + setAttackFrames( attackFrames ); setDecayFrames( decayFrames ); m_envState = ENVELOPE_STATE_ATTACK; diff --git a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp index 8d754fa1b0..63e7fdb9e4 100644 --- a/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp +++ b/GeneralsMD/Code/GameEngine/Source/GameLogic/Object/Update/EMPUpdate.cpp @@ -149,7 +149,7 @@ UpdateSleepTime EMPUpdate::update( void ) { RGBColor end = data->m_endColor; saturateRGB( end, 5 ); - dr->colorFlash( &end, 9999, m_tintEnvFadeFrames, TRUE ); + dr->colorFlash( &end, 0, m_tintEnvFadeFrames, ~0u ); doDisableAttack(); } From 10e50c5c17605906668849af84d8259cf5b9898c Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Sep 2025 18:30:42 +0200 Subject: [PATCH 12/14] tweak(ww3d): Decouple render update from logic step in RingRenderObjClass::animate, SphereRenderObjClass::animate (#1579) --- Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp | 8 ++------ Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp | 8 ++------ 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp index 5db7898b32..f5fc0417a2 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/ringobj.cpp @@ -1146,13 +1146,9 @@ void RingRenderObjClass::animate() InnerScaleChannel.Get_Key_Count () > 0 || OuterScaleChannel.Get_Key_Count () > 0) { - // - // Convert from milliseconds to seconds and normalize the time - // if (AnimDuration > 0) { - float frametime = WW3D::Get_Sync_Frame_Time(); - frametime = (frametime * 0.001F) / AnimDuration; - anim_time += frametime; + float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + anim_time += frametime / AnimDuration; } else { anim_time = 1.0F; } diff --git a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp index b14d7f323c..bd3514e747 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/sphereobj.cpp @@ -1104,13 +1104,9 @@ void SphereRenderObjClass::animate (void) ScaleChannel.Get_Key_Count () > 0 || VectorChannel.Get_Key_Count () > 0) { - // - // Convert from milliseconds to seconds and normalize the time - // if (AnimDuration > 0) { - float frametime = WW3D::Get_Sync_Frame_Time(); - frametime = (frametime * 0.001F) / AnimDuration; - anim_time += frametime; + float frametime = WW3D::Get_Logic_Frame_Time_Seconds(); + anim_time += frametime / AnimDuration; } else { anim_time = 1.0F; } From 5ba34a3a5c81de5ad44a66665ecddea489209352 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Sun, 14 Sep 2025 18:31:23 +0200 Subject: [PATCH 13/14] tweak(ww3d): Decouple render update from logic step in DazzleRenderObjClass::Render, TexProjectClass::Pre_Render_Update (#1579) --- Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp | 6 +----- Generals/Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp | 3 +-- GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp | 6 +----- .../Code/Libraries/Source/WWVegas/WW3D2/texproject.cpp | 3 +-- 4 files changed, 4 insertions(+), 14 deletions(-) diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 5ff6f9ef2c..9e4a933d95 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -940,8 +940,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,current_distance); - unsigned time_ms=WW3D::Get_Sync_Frame_Time(); - if (time_ms==0) time_ms=1; + float time_ms=WW3D::Get_Logic_Frame_Time_Milliseconds(); float weight=pow(params->ic.history_weight,time_ms); if (dazzle_intensity>0.0f) { @@ -1478,9 +1477,6 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Sync_Frame_Time(); - if (time_ms==0) time_ms=1; - DX8Wrapper::Set_Material(NULL); for (unsigned type=0;type max_intensity_delta) { Intensity += max_intensity_delta; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp index 786e3db009..d609985123 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/dazzle.cpp @@ -975,8 +975,7 @@ void DazzleRenderObjClass::Render(RenderInfoClass & rinfo) const DazzleTypeClass* params=types[type]; params->Calculate_Intensities(dazzle_intensity,dazzle_size,current_halo_intensity,camera_dir,current_dir,dir,current_distance); - unsigned time_ms=WW3D::Get_Sync_Frame_Time(); - if (time_ms==0) time_ms=1; + float time_ms=WW3D::Get_Logic_Frame_Time_Milliseconds(); float weight=pow(params->ic.history_weight,time_ms); if (dazzle_intensity>0.0f) { @@ -1584,9 +1583,6 @@ void DazzleLayerClass::Render(CameraClass* camera) camera->Apply(); - unsigned time_ms=WW3D::Get_Sync_Frame_Time(); - if (time_ms==0) time_ms=1; - DX8Wrapper::Set_Material(NULL); for (unsigned type=0;type max_intensity_delta) { Intensity += max_intensity_delta; From dc35bc211221a726ff99393601b1506b1b096382 Mon Sep 17 00:00:00 2001 From: xezon <4720891+xezon@users.noreply.github.com> Date: Mon, 15 Sep 2025 11:46:45 +0200 Subject: [PATCH 14/14] tweak(w3dview): Decouple WWAudioClass update from logic step (#1579) --- Core/Tools/W3DView/GraphicView.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Core/Tools/W3DView/GraphicView.cpp b/Core/Tools/W3DView/GraphicView.cpp index c6e785198c..185c4465c6 100644 --- a/Core/Tools/W3DView/GraphicView.cpp +++ b/Core/Tools/W3DView/GraphicView.cpp @@ -546,7 +546,7 @@ CGraphicView::RepaintView // // Let the audio class think // - WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Sync_Frame_Time()); + WWAudioClass::Get_Instance ()->On_Frame_Update (WW3D::Get_Logic_Frame_Time_Milliseconds()); // // Update the count of particles and polys in the status bar