Decoupled IQM Model Animations

This commit is contained in:
Ricardo Luís Vaz Silva 2023-11-20 18:54:49 -03:00 committed by Rachael Alexanderson
commit 5d5e7ca042
14 changed files with 515 additions and 75 deletions

View file

@ -253,13 +253,88 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio
renderer->EndDrawHUDModel(playermo->RenderStyle, smf);
}
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 pos = startPos + ((tic - anim.startTic) / GameTicRate); // position in seconds
return (((anim.flags & ANIMOVERRIDE_LOOP) ? fmod(pos, duration) : min(pos, duration)) * anim.framerate) + anim.firstFrame;
}
static void calcFrame(const AnimOverride &anim, double tic, double &inter, int &prev, int &next)
{
double frame = getCurrentFrame(anim, tic);
prev = int(floor(frame));
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)
{
// [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation
// and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame.
FSpriteModelFrame * smfNext = nullptr;
const FSpriteModelFrame * smfNext = nullptr;
double inter = 0.;
if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION))
double inter_main = -1.f;
double inter_next = -1.f;
bool is_decoupled = (actor->flags9 & MF9_DECOUPLEDANIMATIONS);
int decoupled_main_prev_frame = -1;
int decoupled_next_prev_frame = -1;
int decoupled_main_frame = -1;
int decoupled_next_frame = -1;
// if prev_frame == -1: interpolate(main_frame, next_frame, inter), else: interpolate(interpolate(main_prev_frame, main_frame, inter_main), interpolate(next_prev_frame, next_frame, inter_next), inter)
// 4-way interpolation is needed to interpolate animation switches between animations that aren't 35hz
if(is_decoupled)
{
smfNext = smf = &BaseSpriteModelFrames[actor->GetClass()];
if(actor->modelData && !(actor->modelData->curAnim.flags & ANIMOVERRIDE_NONE))
{
double tic = actor->Level->totaltime;
if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !Level->isFrozen())
{
tic += I_GetTimeFrac();
}
if(actor->modelData->curAnim.startTic > tic)
{
inter = (tic - actor->modelData->curAnim.switchTic) / (actor->modelData->curAnim.startTic - actor->modelData->curAnim.switchTic);
calcFrame(actor->modelData->curAnim, actor->modelData->curAnim.startTic, inter_next, decoupled_next_prev_frame, decoupled_next_frame);
calcFrame(actor->modelData->prevAnim, actor->modelData->curAnim.switchTic, inter_main, decoupled_main_prev_frame, decoupled_main_frame);
}
else
{
calcFrame(actor->modelData->curAnim, tic, inter, decoupled_main_frame, decoupled_next_frame);
}
}
}
else if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION))
{
FState *nextState = curState->GetNextState();
if (curState != nextState && nextState)
@ -267,7 +342,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
// [BB] To interpolate at more than 35 fps we take tic fractions into account.
float ticFraction = 0.;
// [BB] In case the tic counter is frozen we have to leave ticFraction at zero.
if (ConsoleState == c_up && menuactive != MENU_On && !Level->isFrozen())
if ((ConsoleState == c_up || ConsoleState == c_rising) && (menuactive == MENU_Off || menuactive == MENU_OnNoPause) && !Level->isFrozen())
{
ticFraction = I_GetTimeFrac();
}
@ -311,7 +386,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
TArray<FTextureID> surfaceskinids;
TArray<VSMatrix> boneData = TArray<VSMatrix>();
TArray<VSMatrix> boneData;
int boneStartingPosition = 0;
bool evaluatedSingle = false;
@ -321,7 +396,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
int animationid = -1;
int modelframe = -1;
int modelframenext = -1;
FTextureID skinid; skinid.SetNull();
FTextureID skinid(nullptr);
surfaceskinids.Clear();
@ -350,30 +425,32 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
{
animationid = smf->animationIDs[i];
}
if(!is_decoupled)
{
//modelFrame
if (actor->modelData->modelFrameGenerators.Size() > i
&& (unsigned)actor->modelData->modelFrameGenerators[i] < modelsamount
&& smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0
) {
modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]];
//modelFrame
if (actor->modelData->modelFrameGenerators.Size() > i
&& (unsigned)actor->modelData->modelFrameGenerators[i] < modelsamount
&& smf->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0
) {
modelframe = smf->modelframes[actor->modelData->modelFrameGenerators[i]];
if (smfNext)
{
if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0)
if (smfNext)
{
modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]];
}
else
{
modelframenext = smfNext->modelframes[i];
if(smfNext->modelframes[actor->modelData->modelFrameGenerators[i]] >= 0)
{
modelframenext = smfNext->modelframes[actor->modelData->modelFrameGenerators[i]];
}
else
{
modelframenext = smfNext->modelframes[i];
}
}
}
}
else if(smf->modelsAmount > i)
{
modelframe = smf->modelframes[i];
if (smfNext) modelframenext = smfNext->modelframes[i];
else if(smf->modelsAmount > i)
{
modelframe = smf->modelframes[i];
if (smfNext) modelframenext = smfNext->modelframes[i];
}
}
//skinID
@ -444,29 +521,47 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
GC::WriteBarrier(actor, ptr);
}
if (animationid >= 0)
// [RL0] while per-model animations aren't done, DECOUPLEDANIMATIONS does the same as MODELSAREATTACHMENTS
if ((!(smf->flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle)
{
FModel* animation = Models[animationid];
const TArray<TRS>* animationData = animation->AttachAnimationData();
if (!(smf->flags & MDL_MODELSAREATTACHMENTS) || evaluatedSingle == false)
if (animationid >= 0)
{
boneData = animation->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, animationData, actor->boneComponentData, i);
FModel* animation = Models[animationid];
const TArray<TRS>* animationData = animation->AttachAnimationData();
if(is_decoupled)
{
if(decoupled_main_frame != -1)
{
boneData = animation->CalculateBones(decoupled_main_frame, decoupled_next_frame, inter, decoupled_main_prev_frame, inter_main, decoupled_next_prev_frame, inter_next, animationData, actor->boneComponentData, i);
}
}
else
{
boneData = animation->CalculateBones(modelframe, modelframenext, nextFrame ? inter : -1.f, 0, -1.f, 0, -1.f, animationData, actor->boneComponentData, i);
}
boneStartingPosition = renderer->SetupFrame(animation, 0, 0, 0, boneData, -1);
evaluatedSingle = true;
}
}
else
{
if (!(smf->flags & MDL_MODELSAREATTACHMENTS) || evaluatedSingle == false)
else
{
boneData = mdl->CalculateBones(modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, nullptr, actor->boneComponentData, i);
if(is_decoupled)
{
if(decoupled_main_frame != -1)
{
boneData = mdl->CalculateBones(decoupled_main_frame, decoupled_next_frame, inter, decoupled_main_prev_frame, inter_main, decoupled_next_prev_frame, inter_next, nullptr, actor->boneComponentData, i);
}
}
else
{
boneData = mdl->CalculateBones(modelframe, modelframenext, nextFrame ? inter : -1.f, 0, -1.f, 0, -1.f, nullptr, actor->boneComponentData, i);
}
boneStartingPosition = renderer->SetupFrame(mdl, 0, 0, 0, boneData, -1);
evaluatedSingle = true;
}
}
mdl->RenderFrame(renderer, tex, modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : 0.f, translation, ssidp, boneData, boneStartingPosition);
mdl->RenderFrame(renderer, tex, modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : -1.f, translation, ssidp, boneData, boneStartingPosition);
}
}
}
@ -849,6 +944,16 @@ static void ParseModelDefLump(int Lump)
}
}
}
else if (sc.Compare("baseframe"))
{
FSpriteModelFrame *smfp = &BaseSpriteModelFrames.Insert(type, smf);
for(int modelID : smf.modelIDs)
{
if(modelID >= 0)
Models[modelID]->baseFrame = smfp;
}
GetDefaultByType(type)->hasmodel = true;
}
else if (sc.Compare("frameindex") || sc.Compare("frame"))
{
bool isframe=!!sc.Compare("frame");
@ -1008,7 +1113,16 @@ FSpriteModelFrame * FindModelFrameRaw(const PClass * ti, int sprite, int frame,
FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, bool dropped)
{
return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != NAME_None) ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass(), sprite, frame, dropped);
if(!thing) return nullptr;
if(thing->flags9 & MF9_DECOUPLEDANIMATIONS)
{
return &BaseSpriteModelFrames[thing->GetClass()];
}
else
{
return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != NAME_None) ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass(), sprite, frame, dropped);
}
}
//===========================================================================
@ -1025,8 +1139,7 @@ bool IsHUDModelForPlayerAvailable (player_t * player)
// [MK] check that at least one psprite uses models
for (DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext())
{
FSpriteModelFrame *smf = psp->Caller != nullptr ? FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) : nullptr;
if ( smf != nullptr ) return true;
if ( FindModelFrame(psp->Caller, psp->GetSprite(), psp->GetFrame(), false) != nullptr ) return true;
}
return false;
}