Skip to content

Commit d83c8c9

Browse files
authored
bugfix(anim): Fix elapsed time of object animations (#1656)
1 parent 228ebdd commit d83c8c9

File tree

7 files changed

+69
-15
lines changed

7 files changed

+69
-15
lines changed

Core/Libraries/Source/WWVegas/WW3D2/seglinerenderer.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ SegLineRendererClass::SegLineRendererClass(void) :
7878
NoiseAmplitude(0.0f),
7979
MergeAbortFactor(1.5f),
8080
TextureTileFactor(1.0f),
81+
LastUsedSyncTime(WW3D::Get_Logic_Time_Milliseconds()),
8182
CurrentUVOffset(0.0f,0.0f),
8283
UVOffsetDeltaPerMS(0.0f, 0.0f),
8384
Bits(DEFAULT_BITS),
@@ -97,6 +98,7 @@ SegLineRendererClass::SegLineRendererClass(const SegLineRendererClass & that) :
9798
NoiseAmplitude(0.0f),
9899
MergeAbortFactor(1.5f),
99100
TextureTileFactor(1.0f),
101+
LastUsedSyncTime(that.LastUsedSyncTime),
100102
CurrentUVOffset(0.0f,0.0f),
101103
UVOffsetDeltaPerMS(0.0f, 0.0f),
102104
Bits(DEFAULT_BITS),
@@ -118,6 +120,7 @@ SegLineRendererClass & SegLineRendererClass::operator = (const SegLineRendererCl
118120
NoiseAmplitude = that.NoiseAmplitude;
119121
MergeAbortFactor = that.MergeAbortFactor;
120122
TextureTileFactor = that.TextureTileFactor;
123+
LastUsedSyncTime = that.LastUsedSyncTime;
121124
CurrentUVOffset = that.CurrentUVOffset;
122125
UVOffsetDeltaPerMS = that.UVOffsetDeltaPerMS;
123126
Bits = that.Bits;
@@ -198,6 +201,7 @@ void SegLineRendererClass::Set_Texture_Tile_Factor(float factor)
198201

199202
void SegLineRendererClass::Reset_Line(void)
200203
{
204+
LastUsedSyncTime = WW3D::Get_Logic_Time_Milliseconds();
201205
CurrentUVOffset.Set(0.0f,0.0f);
202206
}
203207

@@ -224,14 +228,16 @@ void SegLineRendererClass::Render
224228
** Handle texture UV offset animation (done once for entire line).
225229
*/
226230
// TheSuperHackers @tweak The render update is now decoupled from the logic step.
227-
Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * WW3D::Get_Logic_Frame_Time_Milliseconds();
231+
const unsigned int delta = WW3D::Get_Logic_Time_Milliseconds() - LastUsedSyncTime;
232+
Vector2 uv_offset = CurrentUVOffset + UVOffsetDeltaPerMS * (float)delta;
228233

229234
// ensure offsets are in [0, 1] range:
230235
uv_offset.X = uv_offset.X - floorf(uv_offset.X);
231236
uv_offset.Y = uv_offset.Y - floorf(uv_offset.Y);
232237

233238
// Update state
234239
CurrentUVOffset = uv_offset;
240+
LastUsedSyncTime = WW3D::Get_Logic_Time_Milliseconds();
235241

236242
// Used later
237243
TextureMapMode map_mode = Get_Texture_Mapping_Mode();

Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) :
8989
ModeAnim.Motion=NULL;
9090
ModeAnim.Frame=0.0f;
9191
ModeAnim.PrevFrame=0.0f;
92+
ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds();
9293
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
9394
ModeAnim.animDirection=1.0; // 020607 srj -- added
9495
ModeInterp.Motion0=NULL;
@@ -144,6 +145,7 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) :
144145
ModeAnim.Motion=NULL;
145146
ModeAnim.Frame=0.0f;
146147
ModeAnim.PrevFrame=0.0f;
148+
ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds();
147149
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
148150
ModeAnim.animDirection=1.0; // 020607 srj -- added
149151
ModeInterp.Motion0=NULL;
@@ -203,6 +205,7 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl
203205
ModeAnim.Motion = NULL;
204206
ModeAnim.Frame = 0.0f;
205207
ModeAnim.PrevFrame = 0.0f;
208+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
206209
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
207210
ModeAnim.animDirection=1.0; // 020607 srj -- added
208211
ModeInterp.Motion0 = NULL;
@@ -471,6 +474,7 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m
471474
ModeAnim.Motion = motion;
472475
ModeAnim.PrevFrame = ModeAnim.Frame;
473476
ModeAnim.Frame = frame;
477+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
474478
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
475479
ModeAnim.animDirection=1.0; // 020607 srj -- added
476480

@@ -939,14 +943,16 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const
939943
{
940944
frame = ModeAnim.Frame;
941945

942-
//
943-
// Compute the current frame based on elapsed time.
944-
//
945946
if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) {
947+
//
948+
// Compute the current frame based on elapsed time.
949+
// TheSuperHackers @info Is using elapsed time because frame computation is not guaranteed to be called every render frame!
950+
//
946951
// TheSuperHackers @tweak The animation render update is now decoupled from the logic step.
947-
const float frametime = WW3D::Get_Logic_Frame_Time_Seconds();
948-
const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime;
949-
frame += delta;
952+
const float syncMilliseconds = WW3D::Get_Logic_Time_Milliseconds() - ModeAnim.LastSyncTime;
953+
const float animMilliseconds = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * syncMilliseconds;
954+
const float animSeconds = animMilliseconds * 0.001f;
955+
frame += animSeconds;
950956

951957
//
952958
// Wrap the frame
@@ -1042,6 +1048,7 @@ void Animatable3DObjClass::Single_Anim_Progress (void)
10421048
//
10431049
ModeAnim.PrevFrame = ModeAnim.Frame;
10441050
ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection);
1051+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
10451052
}
10461053

10471054

Generals/Code/Libraries/Source/WWVegas/WW3D2/animobj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class Animatable3DObjClass : public CompositeRenderObjClass
188188
float Frame;
189189
float PrevFrame;
190190
int AnimMode;
191+
int LastSyncTime;
191192
float animDirection;
192193
float frameRateMultiplier; // 020607 srj -- added
193194
} ModeAnim;

Generals/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,28 @@ class WW3D
169169
** will control things like animated uv-offset mappers and render object animations.
170170
*/
171171
static void Sync(bool step);
172+
173+
// Total sync time in milliseconds. Advances in full logic time steps only.
172174
static unsigned int Get_Sync_Time(void) { return SyncTime; }
175+
176+
// Current sync frame time in milliseconds. Can be zero when the logic has not stepped forward in the current render update.
173177
static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; }
174-
static unsigned int Get_Fractional_Sync_Milliseconds() { return FractionalSyncMs; }
178+
179+
// Fractional sync frame time. Accumulates for as long as the sync frame is not stepped forward.
180+
static unsigned int Get_Fractional_Sync_Milliseconds() { return (unsigned int)FractionalSyncMs; }
181+
182+
// Total logic time in milliseconds. Can include fractions of a logic step. Is rounded to integer.
183+
static unsigned int Get_Logic_Time_Milliseconds() { return SyncTime + (unsigned int)FractionalSyncMs; }
184+
185+
// Logic time step in milliseconds. Can be a fraction of a logic step.
175186
static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; }
187+
188+
// Logic time step in seconds. Can be a fraction of a logic step.
176189
static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; }
190+
191+
// Returns the render frame count.
177192
static unsigned int Get_Frame_Count(void) { return FrameCount; }
193+
178194
static unsigned int Get_Last_Frame_Poly_Count(void);
179195
static unsigned int Get_Last_Frame_Vertex_Count(void);
180196

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.cpp

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ Animatable3DObjClass::Animatable3DObjClass(const char * htree_name) :
8989
ModeAnim.Motion=NULL;
9090
ModeAnim.Frame=0.0f;
9191
ModeAnim.PrevFrame=0.0f;
92+
ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds();
9293
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
9394
ModeAnim.animDirection=1.0; // 020607 srj -- added
9495
ModeInterp.Motion0=NULL;
@@ -144,6 +145,7 @@ Animatable3DObjClass::Animatable3DObjClass(const Animatable3DObjClass & src) :
144145
ModeAnim.Motion=NULL;
145146
ModeAnim.Frame=0.0f;
146147
ModeAnim.PrevFrame=0.0f;
148+
ModeAnim.LastSyncTime=WW3D::Get_Logic_Time_Milliseconds();
147149
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
148150
ModeAnim.animDirection=1.0; // 020607 srj -- added
149151
ModeInterp.Motion0=NULL;
@@ -203,6 +205,7 @@ Animatable3DObjClass & Animatable3DObjClass::operator = (const Animatable3DObjCl
203205
ModeAnim.Motion = NULL;
204206
ModeAnim.Frame = 0.0f;
205207
ModeAnim.PrevFrame = 0.0f;
208+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
206209
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
207210
ModeAnim.animDirection=1.0; // 020607 srj -- added
208211
ModeInterp.Motion0 = NULL;
@@ -471,6 +474,7 @@ void Animatable3DObjClass::Set_Animation(HAnimClass * motion, float frame, int m
471474
ModeAnim.Motion = motion;
472475
ModeAnim.PrevFrame = ModeAnim.Frame;
473476
ModeAnim.Frame = frame;
477+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
474478
ModeAnim.frameRateMultiplier=1.0; // 020607 srj -- added
475479
ModeAnim.animDirection=1.0; // 020607 srj -- added
476480

@@ -947,14 +951,16 @@ float Animatable3DObjClass::Compute_Current_Frame(float *newDirection) const
947951
{
948952
frame = ModeAnim.Frame;
949953

950-
//
951-
// Compute the current frame based on elapsed time.
952-
//
953954
if (ModeAnim.AnimMode != ANIM_MODE_MANUAL) {
955+
//
956+
// Compute the current frame based on elapsed time.
957+
// TheSuperHackers @info Is using elapsed time because frame computation is not guaranteed to be called every render frame!
958+
//
954959
// TheSuperHackers @tweak The animation render update is now decoupled from the logic step.
955-
const float frametime = WW3D::Get_Logic_Frame_Time_Seconds();
956-
const float delta = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * frametime;
957-
frame += delta;
960+
const float syncMilliseconds = WW3D::Get_Logic_Time_Milliseconds() - ModeAnim.LastSyncTime;
961+
const float animMilliseconds = ModeAnim.Motion->Get_Frame_Rate() * ModeAnim.frameRateMultiplier * ModeAnim.animDirection * syncMilliseconds;
962+
const float animSeconds = animMilliseconds * 0.001f;
963+
frame += animSeconds;
958964

959965
//
960966
// Wrap the frame
@@ -1050,6 +1056,7 @@ void Animatable3DObjClass::Single_Anim_Progress (void)
10501056
//
10511057
ModeAnim.PrevFrame = ModeAnim.Frame;
10521058
ModeAnim.Frame = Compute_Current_Frame(&ModeAnim.animDirection);
1059+
ModeAnim.LastSyncTime = WW3D::Get_Logic_Time_Milliseconds();
10531060
}
10541061

10551062

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/animobj.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,7 @@ class Animatable3DObjClass : public CompositeRenderObjClass
188188
float Frame;
189189
float PrevFrame;
190190
int AnimMode;
191+
int LastSyncTime;
191192
float animDirection;
192193
float frameRateMultiplier; // 020607 srj -- added
193194
} ModeAnim;

GeneralsMD/Code/Libraries/Source/WWVegas/WW3D2/ww3d.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,12 +169,28 @@ class WW3D
169169
** will control things like animated uv-offset mappers and render object animations.
170170
*/
171171
static void Sync(bool step);
172+
173+
// Total sync time in milliseconds. Advances in full logic time steps only.
172174
static unsigned int Get_Sync_Time(void) { return SyncTime; }
175+
176+
// Current sync frame time in milliseconds. Can be zero when the logic has not stepped forward in the current render update.
173177
static unsigned int Get_Sync_Frame_Time(void) { return SyncTime - PreviousSyncTime; }
174-
static unsigned int Get_Fractional_Sync_Milliseconds() { return FractionalSyncMs; }
178+
179+
// Fractional sync frame time. Accumulates for as long as the sync frame is not stepped forward.
180+
static unsigned int Get_Fractional_Sync_Milliseconds() { return (unsigned int)FractionalSyncMs; }
181+
182+
// Total logic time in milliseconds. Can include fractions of a logic step. Is rounded to integer.
183+
static unsigned int Get_Logic_Time_Milliseconds() { return SyncTime + (unsigned int)FractionalSyncMs; }
184+
185+
// Logic time step in milliseconds. Can be a fraction of a logic step.
175186
static float Get_Logic_Frame_Time_Milliseconds() { return LogicFrameTimeMs; }
187+
188+
// Logic time step in seconds. Can be a fraction of a logic step.
176189
static float Get_Logic_Frame_Time_Seconds() { return LogicFrameTimeMs * 0.001f; }
190+
191+
// Returns the render frame count.
177192
static unsigned int Get_Frame_Count(void) { return FrameCount; }
193+
178194
static unsigned int Get_Last_Frame_Poly_Count(void);
179195
static unsigned int Get_Last_Frame_Vertex_Count(void);
180196

0 commit comments

Comments
 (0)