mirror of
https://github.com/ZDoom/gzdoom.git
synced 2024-11-25 05:21:16 +00:00
Properly fix double interpolation for IQM models
This commit is contained in:
parent
1429e22441
commit
79dacdf1b7
6 changed files with 154 additions and 48 deletions
|
@ -50,3 +50,7 @@ struct ModelAnim
|
|||
static_assert(sizeof(ModelAnim) == sizeof(double) * 6);
|
||||
|
||||
using ModelAnimFrame = std::variant<std::nullptr_t, ModelAnimFrameInterp, ModelAnimFramePrecalculatedIQM>;
|
||||
|
||||
double getCurrentFrame(const ModelAnim &anim, double tic, bool *looped);
|
||||
void calcFrame(const ModelAnim &anim, double tic, ModelAnimFrameInterp &inter);
|
||||
void calcFrames(const ModelAnim &curAnim, double tic, ModelAnimFrameInterp &to, float &inter);
|
||||
|
|
|
@ -97,6 +97,8 @@ public:
|
|||
virtual float getAspectFactor(float vscale) { return 1.f; }
|
||||
virtual const TArray<TRS>* AttachAnimationData() { return nullptr; };
|
||||
|
||||
virtual ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return nullptr; };
|
||||
|
||||
virtual const TArray<VSMatrix> CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
|
||||
|
||||
void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; }
|
||||
|
|
|
@ -120,9 +120,13 @@ public:
|
|||
void BuildVertexBuffer(FModelRenderer* renderer) override;
|
||||
void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override;
|
||||
const TArray<TRS>* AttachAnimationData() override;
|
||||
const TArray<VSMatrix> CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* bones, int index);
|
||||
|
||||
ModelAnimFrame PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
|
||||
const TArray<VSMatrix> CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
|
||||
|
||||
ModelAnimFramePrecalculatedIQM CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* bones, int index);
|
||||
const TArray<VSMatrix> CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* bones, int index);
|
||||
|
||||
private:
|
||||
void LoadGeometry();
|
||||
void UnloadGeometry();
|
||||
|
|
|
@ -562,27 +562,106 @@ static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt)
|
|||
|
||||
#include "printf.h"
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index)
|
||||
|
||||
ModelAnimFrame IQMModel::PrecalculateFrame(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index)
|
||||
{
|
||||
if(inter <= 0 || !(std::holds_alternative<ModelAnimFrameInterp>(from) || std::holds_alternative<ModelAnimFramePrecalculatedIQM>(from)))
|
||||
if(inter <= 0)
|
||||
{
|
||||
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, animationData, bones, index);
|
||||
return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
|
||||
}
|
||||
else if(std::holds_alternative<ModelAnimFrameInterp>(from))
|
||||
{
|
||||
auto &from_interp = std::get<ModelAnimFrameInterp>(from);
|
||||
|
||||
Printf("CalculateBones({%d, %d, %f}, {%d, %d, %f}, %f)\n", from_interp.frame1, from_interp.frame2, from_interp.inter, to.frame1, to.frame2, to.inter, inter);
|
||||
|
||||
return CalculateBonesIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, animationData, bones, index);
|
||||
return CalculateFrameIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index);
|
||||
}
|
||||
else if(std::holds_alternative<ModelAnimFramePrecalculatedIQM>(from))
|
||||
{ //TODO
|
||||
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, animationData, bones, index);
|
||||
{
|
||||
return CalculateFrameIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get<ModelAnimFramePrecalculatedIQM>(from), animationData, bones, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CalculateFrameIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
|
||||
}
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(const ModelAnimFrame &from, const ModelAnimFrameInterp &to, float inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index)
|
||||
{
|
||||
if(inter <= 0)
|
||||
{
|
||||
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
|
||||
}
|
||||
else if(std::holds_alternative<ModelAnimFrameInterp>(from))
|
||||
{
|
||||
auto &from_interp = std::get<ModelAnimFrameInterp>(from);
|
||||
|
||||
return CalculateBonesIQM(from_interp.frame2, to.frame2, inter, from_interp.frame1, from_interp.inter, to.frame1, to.inter, nullptr, animationData, bones, index);
|
||||
}
|
||||
else if(std::holds_alternative<ModelAnimFramePrecalculatedIQM>(from))
|
||||
{
|
||||
return CalculateBonesIQM(0, to.frame2, inter, 0, -1.f, to.frame1, to.inter, &std::get<ModelAnimFramePrecalculatedIQM>(from), animationData, bones, index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CalculateBonesIQM(to.frame1, to.frame2, to.inter, 0, -1.f, 0, -1.f, nullptr, animationData, bones, index);
|
||||
}
|
||||
}
|
||||
|
||||
ModelAnimFramePrecalculatedIQM IQMModel::CalculateFrameIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
{
|
||||
ModelAnimFramePrecalculatedIQM out;
|
||||
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
|
||||
|
||||
out.precalcBones.Resize(Joints.Size());
|
||||
|
||||
if (Joints.Size() > 0)
|
||||
{
|
||||
int numbones = Joints.SSize();
|
||||
|
||||
int offset1 = frame1 * numbones;
|
||||
int offset2 = frame2 * numbones;
|
||||
|
||||
int offset1_1 = frame1_prev * numbones;
|
||||
int offset2_1 = frame2_prev * numbones;
|
||||
|
||||
float invt = 1.0f - inter;
|
||||
float invt1 = 1.0f - inter1_prev;
|
||||
float invt2 = 1.0f - inter2_prev;
|
||||
|
||||
for (int i = 0; i < numbones; i++)
|
||||
{
|
||||
TRS prev;
|
||||
|
||||
if(precalculated)
|
||||
{
|
||||
prev = precalculated->precalcBones[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
|
||||
{
|
||||
prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
|
||||
}
|
||||
}
|
||||
|
||||
TRS next;
|
||||
|
||||
if(frame2 >= 0 && (frame2_prev >= 0 || inter2_prev < 0))
|
||||
{
|
||||
next = inter2_prev <= 0 ? animationFrames[offset2 + i] : InterpolateBone(animationFrames[offset2_1 + i], animationFrames[offset2 + i], inter2_prev, invt2);
|
||||
}
|
||||
|
||||
if(frame1 >= 0 || inter < 0)
|
||||
{
|
||||
out.precalcBones[i] = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBonesIQM(int frame1, int frame2, float inter, int frame1_prev, float inter1_prev, int frame2_prev, float inter2_prev, const ModelAnimFramePrecalculatedIQM* precalculated, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
{
|
||||
const TArray<TRS>& animationFrames = animationData ? *animationData : TRSData;
|
||||
if (Joints.Size() > 0)
|
||||
|
@ -619,10 +698,17 @@ const TArray<VSMatrix> IQMModel::CalculateBonesIQM(int frame1, int frame2, float
|
|||
{
|
||||
TRS prev;
|
||||
|
||||
if(precalculated)
|
||||
{
|
||||
prev = precalculated->precalcBones[i];
|
||||
}
|
||||
else
|
||||
{
|
||||
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
|
||||
{
|
||||
prev = inter1_prev <= 0 ? animationFrames[offset1 + i] : InterpolateBone(animationFrames[offset1_1 + i], animationFrames[offset1 + i], inter1_prev, invt1);
|
||||
}
|
||||
}
|
||||
|
||||
TRS next;
|
||||
|
||||
|
|
|
@ -5128,9 +5128,6 @@ enum ESetAnimationFlags
|
|||
SAF_NOOVERRIDE = 1 << 2,
|
||||
};
|
||||
|
||||
double getCurrentFrame(const ModelAnim &anim, double tic, bool *looped);
|
||||
void calcFrame(const ModelAnim &anim, double tic, ModelAnimFrameInterp &inter);
|
||||
|
||||
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");
|
||||
|
@ -5177,17 +5174,39 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
|
|||
return;
|
||||
}
|
||||
|
||||
|
||||
if(self->modelData->curAnim.startTic > tic)
|
||||
{ // force instant switch if interpolating
|
||||
flags |= SAF_INSTANT;
|
||||
}
|
||||
|
||||
if(!(flags & SAF_INSTANT))
|
||||
{
|
||||
if(self->modelData->curAnim.startTic > tic)
|
||||
{
|
||||
//TODO
|
||||
ModelAnimFrameInterp to;
|
||||
float inter;
|
||||
|
||||
calcFrames(self->modelData->curAnim, tic, to, inter);
|
||||
|
||||
const TArray<TRS>* animationData = nullptr;
|
||||
|
||||
int animationid = -1;
|
||||
|
||||
const FSpriteModelFrame * smf = &BaseSpriteModelFrames[self->GetClass()];
|
||||
|
||||
if (self->modelData->animationIDs.Size() > 0 && self->modelData->animationIDs[0] >= 0)
|
||||
{
|
||||
animationid = self->modelData->animationIDs[0];
|
||||
}
|
||||
else if(smf->modelsAmount > 0)
|
||||
{
|
||||
animationid = smf->animationIDs[0];
|
||||
}
|
||||
|
||||
FModel* animation = mdl;
|
||||
|
||||
if (animationid >= 0)
|
||||
{
|
||||
animation = Models[animationid];
|
||||
animationData = animation->AttachAnimationData();
|
||||
}
|
||||
|
||||
self->modelData->prevAnim = animation->PrecalculateFrame(self->modelData->prevAnim, to, inter, animationData, self->boneComponentData, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -5196,6 +5215,10 @@ void SetAnimationInternal(AActor * self, FName animName, double framerate, int s
|
|||
calcFrame(self->modelData->curAnim, tic, std::get<ModelAnimFrameInterp>(self->modelData->prevAnim));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
self->modelData->prevAnim = nullptr;
|
||||
}
|
||||
|
||||
int animEnd = mdl->FindLastFrame(animName);
|
||||
|
||||
|
|
|
@ -530,12 +530,16 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
|
|||
}
|
||||
|
||||
// [RL0] while per-model animations aren't done, DECOUPLEDANIMATIONS does the same as MODELSAREATTACHMENTS
|
||||
if ((!(smf_flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle)
|
||||
if(!evaluatedSingle)
|
||||
{
|
||||
FModel* animation = mdl;
|
||||
const TArray<TRS>* animationData = nullptr;
|
||||
|
||||
if (animationid >= 0)
|
||||
{
|
||||
FModel* animation = Models[animationid];
|
||||
animation = Models[animationid];
|
||||
const TArray<TRS>* animationData = animation->AttachAnimationData();
|
||||
}
|
||||
|
||||
if(is_decoupled)
|
||||
{
|
||||
|
@ -549,24 +553,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr
|
|||
boneData = animation->CalculateBones(nullptr, {nextFrame ? inter : -1.0f, modelframe, modelframenext}, -1.0f, animationData, actor->boneComponentData, i);
|
||||
}
|
||||
boneStartingPosition = renderer->SetupFrame(animation, 0, 0, 0, boneData, -1);
|
||||
evaluatedSingle = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(is_decoupled)
|
||||
{
|
||||
if(decoupled_frame.frame1 != -1)
|
||||
{
|
||||
boneData = mdl->CalculateBones(actor->modelData->prevAnim, decoupled_frame, inter, nullptr, actor->boneComponentData, i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boneData = mdl->CalculateBones(nullptr, {nextFrame ? inter : -1.0f, modelframe, modelframenext}, -1.0f, nullptr, actor->boneComponentData, i);
|
||||
}
|
||||
boneStartingPosition = renderer->SetupFrame(mdl, 0, 0, 0, boneData, -1);
|
||||
evaluatedSingle = true;
|
||||
}
|
||||
evaluatedSingle = (smf_flags & MDL_MODELSAREATTACHMENTS) || is_decoupled;
|
||||
}
|
||||
|
||||
mdl->RenderFrame(renderer, tex, modelframe, nextFrame ? modelframenext : modelframe, nextFrame ? inter : -1.f, translation, ssidp, boneData, boneStartingPosition);
|
||||
|
|
Loading…
Reference in a new issue