Skip to content

Commit

Permalink
Merge pull request #63 from noodlecollie/fix-model-viewer-anims
Browse files Browse the repository at this point in the history
Fixed animations in model viewer not looping properly
  • Loading branch information
noodlecollie authored Mar 27, 2024
2 parents 566ccae + 1ac45c8 commit a35daa2
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 4 deletions.
2 changes: 1 addition & 1 deletion game/game_libs/ui/controls/DeveloperStudioSceneView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ void CMenuDeveloperStudioSceneView::DrawSequenceBoundingBox(cl_entity_t* ent)
vec3_t mins = { 0.0f, 0.0f, 0.0f };
vec3_t maxs = { 0.0f, 0.0f, 0.0f };

if ( EngFuncs::pfnGetModelSequenceBounds(ent, ent->curstate.sequence, mins, maxs) )
if ( EngFuncs::GetModelSequenceBounds(ent, ent->curstate.sequence, mins, maxs) )
{
DrawBoundingBox(mins, maxs, 0x00FF00FF);
}
Expand Down
7 changes: 6 additions & 1 deletion game/game_libs/ui/enginecallback_menu.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,11 +274,16 @@ class EngFuncs
}

static inline qboolean
pfnGetModelSequenceBounds(struct cl_entity_s* ent, int sequenceIndex, float* outVec3Mins, float* outVec3Maxs)
GetModelSequenceBounds(struct cl_entity_s* ent, int sequenceIndex, float* outVec3Mins, float* outVec3Maxs)
{
return engfuncs.pfnGetModelSequenceBounds(ent, sequenceIndex, outVec3Mins, outVec3Maxs);
}

static inline float GetModelSequenceDuration(struct cl_entity_s* ent, int sequenceIndex)
{
return engfuncs.pfnGetModelSequenceDuration(ent, sequenceIndex);
}

static inline void ClearScene(void)
{
engfuncs.pfnClearScene();
Expand Down
38 changes: 37 additions & 1 deletion game/game_libs/ui/menus/ModelViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class CMenuModelViewer : public CMenuFramework
}

private:
virtual void _Init() override
void _Init() override
{
banner.SetPicture("gfx/shell/head_blank");

Expand All @@ -44,6 +44,12 @@ class CMenuModelViewer : public CMenuFramework
AddBottomControls();
}

void Draw() override
{
UpdateAnimationTime(m_MainStudioModel);
CMenuFramework::Draw();
}

void AddMainViews()
{
const int viewHeight = GetViewAreaHeight();
Expand Down Expand Up @@ -136,6 +142,8 @@ class CMenuModelViewer : public CMenuFramework
{
m_SequenceModel.AddToTail(CUtlString(EngFuncs::GetModelSequenceName(m_MainStudioModel, index)));
}

m_MainStudioModel->curstate.animtime = gpGlobals->time;
}

void HandleSequenceChanged()
Expand All @@ -146,6 +154,7 @@ class CMenuModelViewer : public CMenuFramework
}

m_MainStudioModel->curstate.sequence = m_SequenceTable.GetCurrentIndex();
m_MainStudioModel->curstate.animtime = gpGlobals->time;
}

void LookUpModelSubdirsRecursively()
Expand Down Expand Up @@ -199,6 +208,33 @@ class CMenuModelViewer : public CMenuFramework
}
}

// Update animtime (the time at which the animation began playing)
// so that animations will loop properly.
void UpdateAnimationTime(cl_entity_t* ent)
{
if ( !ent || !ent->model )
{
return;
}

float duration = EngFuncs::GetModelSequenceDuration(ent, ent->curstate.sequence);

if ( duration <= 0.0f || ent->curstate.framerate == 0.0f )
{
return;
}

duration /= ent->curstate.framerate;

float timeDiff = gpGlobals->time - ent->curstate.animtime;

if ( timeDiff >= duration )
{
timeDiff = fmodf(timeDiff, duration);
ent->curstate.animtime = gpGlobals->time + timeDiff;
}
}

void HandleOriginMarkerCheckBoxChanged()
{
m_SceneView.SetDrawOriginMarker(m_CheckEnableOriginMarker.bChecked);
Expand Down
23 changes: 22 additions & 1 deletion xash3d_engine/engine/ref/gl/src/gl_studio.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,38 +663,59 @@ StudioEstimateFrame
*/
float R_StudioEstimateFrame(cl_entity_t* e, mstudioseqdesc_t* pseqdesc, double time)
{
double dfdt, f;
double dfdt = 0.0;
double f = 0.0;

if ( g_studio.interpolate )
{
if ( time < e->curstate.animtime )
{
dfdt = 0.0;
}
else
{
dfdt = (time - e->curstate.animtime) * e->curstate.framerate * pseqdesc->fps;
}
}
else
{
dfdt = 0;
}

if ( pseqdesc->numframes <= 1 )
{
f = 0.0;
}
else
{
f = (e->curstate.frame * (pseqdesc->numframes - 1)) / 256.0f;
}

f += dfdt;

if ( pseqdesc->flags & STUDIO_LOOPING )
{
if ( pseqdesc->numframes > 1 )
{
f -= (int)(f / (pseqdesc->numframes - 1)) * (pseqdesc->numframes - 1);
}

if ( f < 0 )
{
f += (pseqdesc->numframes - 1);
}
}
else
{
if ( f >= pseqdesc->numframes - 1.001 )
{
f = pseqdesc->numframes - 1.001;
}

if ( f < 0.0 )
{
f = 0.0;
}
}

return (float)f;
Expand Down
6 changes: 6 additions & 0 deletions xash3d_engine/engine/src/client/cl_gameui.c
Original file line number Diff line number Diff line change
Expand Up @@ -832,6 +832,11 @@ qboolean pfnGetModelSequenceBounds(struct cl_entity_s* ent, int sequenceIndex, f
return ent ? Mod_StudioGetSequenceBounds(ent->model, sequenceIndex, outVec3Mins, outVec3Maxs) : false;
}

float pfnGetModelSequenceDuration(struct cl_entity_s* ent, int sequenceIndex)
{
return ent ? Mod_StudioGetSequenceDuration(ent->model, sequenceIndex) : 0.0f;
}

/*
====================
pfnClearScene
Expand Down Expand Up @@ -1274,6 +1279,7 @@ static ui_enginefuncs_t gEngfuncs = {
pfnGetModelSequenceCount,
pfnGetModelSequenceName,
pfnGetModelSequenceBounds,
pfnGetModelSequenceDuration,
pfnClearScene,
pfnUpdateScene,
pfnRenderScene,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ typedef struct ui_enginefuncs_s
const char* (*pfnGetModelSequenceName)(struct cl_entity_s* ent, int sequenceIndex);
qboolean (
*pfnGetModelSequenceBounds)(struct cl_entity_s* ent, int sequenceIndex, float* outVec3Mins, float* outVec3Maxs);
float (*pfnGetModelSequenceDuration)(struct cl_entity_s* ent, int sequenceIndex);
void (*pfnClearScene)(void);
void (*pfnUpdateScene)(void);
void (*pfnRenderScene)(const struct ref_viewpass_s* rvp);
Expand Down

0 comments on commit a35daa2

Please sign in to comment.