diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 5aa23b573f..37e9eb6453 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -702,8 +702,8 @@ enum EViewPosFlags // [MC] Flags for SetViewPos. enum EAnimOverrideFlags { - ANIMOVERRIDE_NONE = 1 << 0, // no animation - ANIMOVERRIDE_LOOP = 1 << 1, // animation loops, otherwise it stays on the last frame once it ends + ANIMOVERRIDE_NONE = 1 << 0, // no animation + ANIMOVERRIDE_LOOP = 1 << 1, // animation loops, otherwise it stays on the last frame once it ends }; struct AnimOverride diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 4a647af4ef..1612c75163 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5128,7 +5128,7 @@ enum ESetAnimationFlags SAF_NOOVERRIDE = 1 << 2, }; -extern double getCurrentFrame(const AnimOverride &anim, double tic); +extern double getCurrentFrame(const AnimOverride &anim, double tic, bool *looped); void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int endFrame, int interpolateTics, int flags, double ticFrac) { @@ -5218,7 +5218,13 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s if(!(flags & SAF_INSTANT)) { - self->modelData->prevAnim.startFrame = getCurrentFrame(self->modelData->prevAnim, tic); + bool looped = false; + self->modelData->prevAnim.startFrame = getCurrentFrame(self->modelData->prevAnim, tic, &looped); + + if(!looped) + { + self->modelData->prevAnim.flags &= ~ANIMOVERRIDE_LOOP; + } int startTic = floor(tic) + interpolateTics; self->modelData->curAnim.startTic = startTic; @@ -5272,7 +5278,7 @@ void SetAnimationFrameRateInternal(AActor * self, double framerate, double ticFr return; } - double frame = getCurrentFrame(self->modelData->curAnim, tic); + double frame = getCurrentFrame(self->modelData->curAnim, tic, nullptr); self->modelData->curAnim.startFrame = frame; self->modelData->curAnim.startTic = tic; diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 866e538c3d..3c2ed56d7c 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -258,7 +258,7 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio renderer->EndDrawHUDModel(playermo->RenderStyle, smf_flags); } -double getCurrentFrame(const AnimOverride &anim, double tic) +double getCurrentFrame(const AnimOverride &anim, double tic, bool *looped) { if(anim.framerate <= 0) return anim.startFrame; @@ -268,6 +268,7 @@ double getCurrentFrame(const AnimOverride &anim, double tic) if((anim.flags & ANIMOVERRIDE_LOOP) && frame >= duration) { + if(looped) *looped = true; frame = frame - duration; return fmod(frame, anim.lastFrame - anim.loopFrame) + anim.loopFrame; } @@ -277,15 +278,26 @@ double getCurrentFrame(const AnimOverride &anim, double tic) } } -static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next) +static void fixFrame(const AnimOverride &anim, double frame, double &inter, int &prev, int &next, bool looped) { - double frame = getCurrentFrame(anim, tic); - prev = int(floor(frame)); + int startFrame = (looped ? anim.startFrame : anim.loopFrame); + + if(prev < startFrame) prev = anim.lastFrame; + inter = frame - prev; next = int(ceil(frame)); + + if(next > anim.lastFrame) next = startFrame; +} + +static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next) +{ + bool looped = false; + double frame = getCurrentFrame(anim, tic, &looped); + fixFrame(anim, frame, inter, prev, next, looped); } void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor) @@ -325,17 +337,8 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { inter = (tic - (actor->modelData->curAnim.startTic - actor->modelData->curAnim.switchOffset)) / actor->modelData->curAnim.switchOffset; - double nextFrame = actor->modelData->curAnim.startFrame; - - double prevFrame = actor->modelData->prevAnim.startFrame; - - decoupled_next_prev_frame = floor(nextFrame); - decoupled_next_frame = ceil(nextFrame); - inter_next = nextFrame - floor(nextFrame); - - decoupled_main_prev_frame = floor(prevFrame); - decoupled_main_frame = ceil(prevFrame); - inter_main = prevFrame - floor(prevFrame); + fixFrame(actor->modelData->curAnim, actor->modelData->curAnim.startFrame, inter_next, decoupled_next_prev_frame, decoupled_next_frame, false); + fixFrame(actor->modelData->prevAnim, actor->modelData->prevAnim.startFrame, inter_main, decoupled_main_prev_frame, decoupled_main_frame, actor->modelData->prevAnim.flags & ANIMOVERRIDE_LOOP); } else {