Skip to content

Commit

Permalink
Decoupled Animation fixes and improvements
Browse files Browse the repository at this point in the history
* fixes looping that uses `loopFrame`
* adds `endFrame`
* adds `SAF_NOOVERRIDE`
* fixes crash on SetAnimation if a BaseFrame isn't defined
  • Loading branch information
RicardoLuis0 committed Apr 16, 2024
1 parent f2072ce commit 7c93cfa
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 35 deletions.
2 changes: 1 addition & 1 deletion src/playsim/actor.h
Expand Up @@ -709,7 +709,7 @@ struct AnimOverride
double startFrame;
int flags = ANIMOVERRIDE_NONE;
float framerate;
double startTic; // when the animation starts if interpolating from previous animation
double startTic; // when the current animation started (changing framerates counts as restarting) (or when animation starts if interpolating from previous animation)
double switchTic; // when the animation was changed -- where to interpolate the switch from
};

Expand Down
43 changes: 31 additions & 12 deletions src/playsim/p_actionfunctions.cpp
Expand Up @@ -5125,11 +5125,10 @@ enum ESetAnimationFlags
{
SAF_INSTANT = 1 << 0,
SAF_LOOP = 1 << 1,
SAF_USEACTORROLL = 1 << 2,
SAF_USEACTORPITCH = 1 << 3,
SAF_NOOVERRIDE = 1 << 2,
};

void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags, double ticFrac)
void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags, double ticFrac)
{
if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self");

Expand All @@ -5138,6 +5137,11 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
ThrowAbortException(X_OTHER, "Cannot set animation for non-decoupled actors");
}

if(!BaseSpriteModelFrames.CheckKey(self->GetClass()))
{
ThrowAbortException(X_OTHER, "Actor class is missing a MODELDEF definition or a MODELDEF BaseFrame");
}

if(interpolateTics <= 0) interpolateTics = 1;

EnsureModelData(self);
Expand Down Expand Up @@ -5168,6 +5172,13 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
Printf("Could not find animation %s\n", animName.GetChars());
return;
}

if((flags & SAF_NOOVERRIDE) && self->modelData->curAnim.flags != ANIMOVERRIDE_NONE && self->modelData->curAnim.firstFrame == animStart)
{
//same animation as current, skip setting it
return;
}

int animEnd = mdl->FindLastFrame(animName);

if(framerate < 0)
Expand All @@ -5180,18 +5191,24 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
if(startFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars());
Printf("frame %d (startFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
return;
}
else if(loopFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d is past the end of animation %s\n", startFrame, animName.GetChars());
Printf("frame %d (loopFrame) is past the end of animation %s\n", startFrame, animName.GetChars());
return;
}
else if(endFrame >= len)
{
self->modelData->curAnim.flags = ANIMOVERRIDE_NONE;
Printf("frame %d (endFrame) is past the end of animation %s\n", endFrame, animName.GetChars());
return;
}

self->modelData->curAnim.firstFrame = animStart;
self->modelData->curAnim.lastFrame = animEnd - 1;
self->modelData->curAnim.lastFrame = endFrame < 0 ? animEnd - 1 : animStart + endFrame;
self->modelData->curAnim.startFrame = startFrame < 0 ? animStart : animStart + startFrame;
self->modelData->curAnim.loopFrame = loopFrame < 0 ? animStart : animStart + loopFrame;
self->modelData->curAnim.flags = (flags&SAF_LOOP) ? ANIMOVERRIDE_LOOP : 0;
Expand All @@ -5208,14 +5225,14 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
}
}

void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags)
void SetAnimationNative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags)
{
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, interpolateTics, flags, 1);
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1);
}

void SetAnimationUINative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags)
void SetAnimationUINative(AActor * self, int i_animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags)
{
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, interpolateTics, flags, I_GetTimeFrac());
SetAnimationInternal(self, FName(ENamedName(i_animName)), framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac());
}

extern double getCurrentFrame(const AnimOverride &anim, double tic);
Expand Down Expand Up @@ -5471,10 +5488,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimation, SetAnimationNative)
PARAM_FLOAT(framerate);
PARAM_INT(startFrame);
PARAM_INT(loopFrame);
PARAM_INT(endFrame);
PARAM_INT(interpolateTics);
PARAM_INT(flags);

SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, interpolateTics, flags, 1);
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, 1);

return 0;
}
Expand All @@ -5486,10 +5504,11 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationUI, SetAnimationUINative)
PARAM_FLOAT(framerate);
PARAM_INT(startFrame);
PARAM_INT(loopFrame);
PARAM_INT(endFrame);
PARAM_INT(interpolateTics);
PARAM_INT(flags);

SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, interpolateTics, flags, I_GetTimeFrac());
SetAnimationInternal(self, animName, framerate, startFrame, loopFrame, endFrame, interpolateTics, flags, I_GetTimeFrac());

return 0;
}
Expand Down
32 changes: 12 additions & 20 deletions src/r_data/models.cpp
Expand Up @@ -261,12 +261,19 @@ double getCurrentFrame(const AnimOverride &anim, double tic)
{
if(anim.framerate <= 0) return anim.startFrame;

double duration = double(anim.lastFrame - anim.firstFrame) / double(anim.framerate); // duration in seconds
double startPos = double(anim.startFrame - anim.firstFrame) / double(anim.framerate);
double frame = ((tic - anim.startTic) / GameTicRate) * anim.framerate; // position in frames

double pos = startPos + ((tic - anim.startTic) / GameTicRate); // position in seconds
double duration = double(anim.lastFrame) - anim.startFrame;

return (((anim.flags & ANIMOVERRIDE_LOOP) ? fmod(pos, duration) : min(pos, duration)) * anim.framerate) + anim.firstFrame;
if((anim.flags & ANIMOVERRIDE_LOOP) && frame >= duration)
{
frame = frame - duration;
return fmod(frame, anim.lastFrame - anim.loopFrame) + anim.loopFrame;
}
else
{
return min(frame, duration) + anim.startFrame;
}
}

static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next)
Expand All @@ -277,22 +284,7 @@ static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &

inter = frame - prev;

if(frame > anim.lastFrame)
{
if(anim.flags & ANIMOVERRIDE_LOOP)
{
next = anim.loopFrame + (prev - anim.lastFrame);
}
else
{
inter = 0;
prev = next = anim.lastFrame;
}
}
else
{
next = int(ceil(frame));
}
next = int(ceil(frame));
}

void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor)
Expand Down
4 changes: 2 additions & 2 deletions wadsrc/static/zscript/actors/actor.zs
Expand Up @@ -1305,8 +1305,8 @@ class Actor : Thinker native
native bool A_AttachLight(Name lightid, int type, Color lightcolor, int radius1, int radius2, int flags = 0, Vector3 ofs = (0,0,0), double param = 0, double spoti = 10, double spoto = 25, double spotp = 0);
native bool A_RemoveLight(Name lightid);

native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame= -1, int interpolateTics = -1, int flags = 0);
native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") void SetAnimation(Name animName, double framerate = -1, int startFrame = -1, int loopFrame= -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);
native version("4.12") ui void SetAnimationUI(Name animName, double framerate = -1, int startFrame = -1, int loopFrame = -1, int endFrame = -1, int interpolateTics = -1, int flags = 0);

native version("4.12") void SetAnimationFrameRate(double framerate);
native version("4.12") ui void SetAnimationFrameRateUI(double framerate);
Expand Down
1 change: 1 addition & 0 deletions wadsrc/static/zscript/constants.zs
Expand Up @@ -375,6 +375,7 @@ enum ESetAnimationFlags
{
SAF_INSTANT = 1 << 0,
SAF_LOOP = 1 << 1,
SAF_NOOVERRIDE = 1 << 2,
};

// Change model flags
Expand Down

0 comments on commit 7c93cfa

Please sign in to comment.