diff --git a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp index dd97d4a0508..3918dd716ff 100644 --- a/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp +++ b/Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp @@ -78,6 +78,7 @@ SegLineRendererClass::SegLineRendererClass(void) : NoiseAmplitude(0.0f), MergeAbortFactor(1.5f), TextureTileFactor(1.0f), + LastUsedSyncTime(WW3D::Get_Logic_Time_Milliseconds()), CurrentUVOffset(0.0f,0.0f), UVOffsetDeltaPerMS(0.0f, 0.0f), Bits(DEFAULT_BITS), @@ -97,6 +98,7 @@ 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), @@ -118,6 +120,7 @@ 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; @@ -198,6 +201,7 @@ void SegLineRendererClass::Set_Texture_Tile_Factor(float factor) void SegLineRendererClass::Reset_Line(void) { + LastUsedSyncTime = WW3D::Get_Logic_Time_Milliseconds(); CurrentUVOffset.Set(0.0f,0.0f); } @@ -224,7 +228,8 @@ void SegLineRendererClass::Render ** Handle texture UV offset animation (done once for entire line). */ // TheSuperHackers @tweak The render update is now decoupled from the logic step. - Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * WW3D::Get_Logic_Frame_Time_Milliseconds(); + const unsigned int delta = WW3D::Get_Logic_Time_Milliseconds() - LastUsedSyncTime; + Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * (float)delta; // ensure offsets are in [0, 1] range: uv_offset.X = uv_offset.X - floorf(uv_offset.X); @@ -232,6 +237,7 @@ void SegLineRendererClass::Render // Update state CurrentUVOffset = uv_offset; + LastUsedSyncTime = WW3D::Get_Logic_Time_Milliseconds(); // Used later TextureMapMode map_mode = Get_Texture_Mapping_Mode(); diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index d2b16477fd5..32a40db2f52 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,6 +89,7 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; + ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -144,6 +145,7 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; + ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -203,6 +205,7 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -471,6 +474,7 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -939,14 +943,16 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { frame = ModeAnim.Frame; - // - // Compute the current frame based on elapsed time. - // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { + // + // Compute the current frame based on elapsed time. + // TheSuperHackers @info Is using elapsed time because frame computation is not guaranteed to be called every render frame! + // // 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; + const float syncMilliseconds = WW3D::Get_Logic_Time_Milliseconds() - ModeAnim.LastSyncTime; + const float animMilliseconds = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * syncMilliseconds; + const float animSeconds = animMilliseconds * 0.001f; + frame += animSeconds; // // Wrap the frame @@ -1042,6 +1048,7 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); } diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index 06fc905d963..4b3803a8352 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -188,6 +188,7 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; + int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; diff --git a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index c4fd44916de..d3b3de3829d 100644 --- a/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -169,12 +169,28 @@ class WW3D ** will control things like animated uv-offset mappers and render object animations. */ static void Sync(bool step); + + // Total sync time in milliseconds. Advances in full logic time steps only. static unsigned int Get_Sync_Time(void) { return SyncTime; } + + // Current sync frame time in milliseconds. Can be zero when the logic has not stepped forward in the current render update. static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Fractional_Sync_Milliseconds() { return FractionalSyncMs; } + + // Fractional sync frame time. Accumulates for as long as the sync frame is not stepped forward. + static unsigned int Get_Fractional_Sync_Milliseconds() { return (unsigned int)FractionalSyncMs; } + + // Total logic time in milliseconds. Can include fractions of a logic step. Is rounded to integer. + static unsigned int Get_Logic_Time_Milliseconds() { return SyncTime + (unsigned int)FractionalSyncMs; } + + // Logic time step in milliseconds. Can be a fraction of a logic step. static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + + // Logic time step in seconds. Can be a fraction of a logic step. static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } + + // Returns the render frame count. 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); diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp index 1c5d4483a40..910f1f7d2f9 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp @@ -89,6 +89,7 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; + ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -144,6 +145,7 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) : ModeAnim.Motion=NULL; ModeAnim.Frame=0.0f; ModeAnim.PrevFrame=0.0f; + ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0=NULL; @@ -203,6 +205,7 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl ModeAnim.Motion = NULL; ModeAnim.Frame = 0.0f; ModeAnim.PrevFrame = 0.0f; + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added ModeInterp.Motion0 = NULL; @@ -471,6 +474,7 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m ModeAnim.Motion = motion; ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = frame; + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added ModeAnim.animDirection=1.0; // 020607 srj -- added @@ -947,14 +951,16 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const { frame = ModeAnim.Frame; - // - // Compute the current frame based on elapsed time. - // if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) { + // + // Compute the current frame based on elapsed time. + // TheSuperHackers @info Is using elapsed time because frame computation is not guaranteed to be called every render frame! + // // 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; + const float syncMilliseconds = WW3D::Get_Logic_Time_Milliseconds() - ModeAnim.LastSyncTime; + const float animMilliseconds = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * syncMilliseconds; + const float animSeconds = animMilliseconds * 0.001f; + frame += animSeconds; // // Wrap the frame @@ -1050,6 +1056,7 @@ void Animatable3DObjClass::Single_Anim_Progress (void) // ModeAnim.PrevFrame = ModeAnim.Frame; ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection); + ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds(); } diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h index f04f76c2333..43ed2783338 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h @@ -188,6 +188,7 @@ class Animatable3DObjClass : public CompositeRenderObjClass float Frame; float PrevFrame; int AnimMode; + int LastSyncTime; float animDirection; float frameRateMultiplier; // 020607 srj -- added } ModeAnim; diff --git a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h index 8d82f64de2e..15fe73034af 100644 --- a/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h +++ b/GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h @@ -169,12 +169,28 @@ class WW3D ** will control things like animated uv-offset mappers and render object animations. */ static void Sync(bool step); + + // Total sync time in milliseconds. Advances in full logic time steps only. static unsigned int Get_Sync_Time(void) { return SyncTime; } + + // Current sync frame time in milliseconds. Can be zero when the logic has not stepped forward in the current render update. static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; } - static unsigned int Get_Fractional_Sync_Milliseconds() { return FractionalSyncMs; } + + // Fractional sync frame time. Accumulates for as long as the sync frame is not stepped forward. + static unsigned int Get_Fractional_Sync_Milliseconds() { return (unsigned int)FractionalSyncMs; } + + // Total logic time in milliseconds. Can include fractions of a logic step. Is rounded to integer. + static unsigned int Get_Logic_Time_Milliseconds() { return SyncTime + (unsigned int)FractionalSyncMs; } + + // Logic time step in milliseconds. Can be a fraction of a logic step. static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; } + + // Logic time step in seconds. Can be a fraction of a logic step. static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; } + + // Returns the render frame count. 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);