mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 05:21:16 +00:00
Decoupled Animation fixes and improvements
* fixes looping that uses `loopFrame` * adds `endFrame` * adds `SAF_NOOVERRIDE` * fixes crash on SetAnimation if a BaseFrame isn't defined
This commit is contained in:
parent
f2072cec95
commit
7c93cfa97b
5 changed files with 47 additions and 35 deletions
|
@ -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
|
||||
};
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
@ -277,23 +284,8 @@ 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));
|
||||
}
|
||||
}
|
||||
|
||||
void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpriteModelFrame *smf, const FState *curState, const int curTics, FTranslationID translation, AActor* actor)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -375,6 +375,7 @@ enum ESetAnimationFlags
|
|||
{
|
||||
SAF_INSTANT = 1 << 0,
|
||||
SAF_LOOP = 1 << 1,
|
||||
SAF_NOOVERRIDE = 1 << 2,
|
||||
};
|
||||
|
||||
// Change model flags
|
||||
|
|
Loading…
Reference in a new issue