Decoupled IQM Model Animations
This commit is contained in:
parent
1a8dfd2dfa
commit
5d5e7ca042
14 changed files with 515 additions and 75 deletions
|
|
@ -47,6 +47,7 @@
|
|||
TArray<FString> savedModelFiles;
|
||||
TDeletingArray<FModel*> Models;
|
||||
TArray<FSpriteModelFrame> SpriteModelFrames;
|
||||
TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -6,6 +6,8 @@
|
|||
#include "matrix.h"
|
||||
#include "palettecontainer.h"
|
||||
#include "TRS.h"
|
||||
#include "tarray.h"
|
||||
#include "name.h"
|
||||
|
||||
class DBoneComponents;
|
||||
class FModelRenderer;
|
||||
|
|
@ -19,6 +21,7 @@ void FlushModels();
|
|||
extern TArray<FString> savedModelFiles;
|
||||
extern TDeletingArray<FModel*> Models;
|
||||
extern TArray<FSpriteModelFrame> SpriteModelFrames;
|
||||
extern TMap<void*, FSpriteModelFrame> BaseSpriteModelFrames;
|
||||
|
||||
#define MD3_MAX_SURFACES 32
|
||||
#define MIN_MODELS 4
|
||||
|
|
@ -72,13 +75,20 @@ public:
|
|||
virtual ~FModel();
|
||||
|
||||
virtual bool Load(const char * fn, int lumpnum, const char * buffer, int length) = 0;
|
||||
|
||||
virtual int FindFrame(const char * name, bool nodefault = false) = 0;
|
||||
|
||||
// [RL0] these are used for decoupled iqm animations
|
||||
virtual int FindFirstFrame(FName name) { return FErr_NotFound; }
|
||||
virtual int FindLastFrame(FName name) { return FErr_NotFound; }
|
||||
virtual double FindFramerate(FName name) { return FErr_NotFound; }
|
||||
|
||||
virtual void RenderFrame(FModelRenderer *renderer, FGameTexture * skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition) = 0;
|
||||
virtual void BuildVertexBuffer(FModelRenderer *renderer) = 0;
|
||||
virtual void AddSkins(uint8_t *hitlist, const FTextureID* surfaceskinids) = 0;
|
||||
virtual float getAspectFactor(float vscale) { return 1.f; }
|
||||
virtual const TArray<TRS>* AttachAnimationData() { return nullptr; };
|
||||
virtual const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) { return {}; };
|
||||
virtual const TArray<VSMatrix> CalculateBones(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) { return {}; };
|
||||
|
||||
void SetVertexBuffer(int type, IModelVertexBuffer *buffer) { mVBuf[type] = buffer; }
|
||||
IModelVertexBuffer *GetVertexBuffer(int type) const { return mVBuf[type]; }
|
||||
|
|
@ -86,7 +96,8 @@ public:
|
|||
|
||||
bool hasSurfaces = false;
|
||||
FString mFileName;
|
||||
|
||||
|
||||
FSpriteModelFrame *baseFrame;
|
||||
private:
|
||||
IModelVertexBuffer *mVBuf[NumModelRendererTypes];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
#include "matrix.h"
|
||||
#include "common/rendering/i_modelvertexbuffer.h"
|
||||
#include "m_swap.h"
|
||||
#include "name.h"
|
||||
|
||||
class DBoneComponents;
|
||||
|
||||
|
|
@ -112,11 +113,14 @@ public:
|
|||
|
||||
bool Load(const char* fn, int lumpnum, const char* buffer, int length) override;
|
||||
int FindFrame(const char* name, bool nodefault) override;
|
||||
int FindFirstFrame(FName name) override;
|
||||
int FindLastFrame(FName name) override;
|
||||
double FindFramerate(FName name) override;
|
||||
void RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition) override;
|
||||
void BuildVertexBuffer(FModelRenderer* renderer) override;
|
||||
void AddSkins(uint8_t* hitlist, const FTextureID* surfaceskinids) override;
|
||||
const TArray<TRS>* AttachAnimationData() override;
|
||||
const TArray<VSMatrix> CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* bones, int index) override;
|
||||
const TArray<VSMatrix> CalculateBones(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) override;
|
||||
|
||||
private:
|
||||
void LoadGeometry();
|
||||
|
|
@ -129,6 +133,9 @@ private:
|
|||
void LoadBlendWeights(IQMFileReader& reader, const IQMVertexArray& vertexArray);
|
||||
|
||||
int mLumpNum = -1;
|
||||
|
||||
TMap<FName, int> NamedAnimations;
|
||||
|
||||
TArray<IQMMesh> Meshes;
|
||||
TArray<IQMTriangle> Triangles;
|
||||
TArray<IQMAdjacency> Adjacency;
|
||||
|
|
|
|||
|
|
@ -137,9 +137,12 @@ bool IQMModel::Load(const char* path, int lumpnum, const char* buffer, int lengt
|
|||
}
|
||||
|
||||
reader.SeekTo(ofs_anims);
|
||||
for (IQMAnim& anim : Anims)
|
||||
for(int i = 0; i < Anims.Size(); i++)
|
||||
{
|
||||
IQMAnim& anim = Anims[i];
|
||||
anim.Name = reader.ReadName(text);
|
||||
NamedAnimations.Insert(anim.Name, i);
|
||||
|
||||
anim.FirstFrame = reader.ReadUInt32();
|
||||
anim.NumFrames = reader.ReadUInt32();
|
||||
anim.Framerate = reader.ReadFloat();
|
||||
|
|
@ -445,6 +448,27 @@ int IQMModel::FindFrame(const char* name, bool nodefault)
|
|||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
int IQMModel::FindFirstFrame(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].FirstFrame;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
int IQMModel::FindLastFrame(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].FirstFrame + Anims[*nam].NumFrames;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
double IQMModel::FindFramerate(FName name)
|
||||
{
|
||||
int * nam = NamedAnimations.CheckKey(name);
|
||||
if(nam) return Anims[*nam].Framerate;
|
||||
return FErr_NotFound;
|
||||
}
|
||||
|
||||
void IQMModel::RenderFrame(FModelRenderer* renderer, FGameTexture* skin, int frame1, int frame2, double inter, FTranslationID translation, const FTextureID* surfaceskinids, const TArray<VSMatrix>& boneData, int boneStartPosition)
|
||||
{
|
||||
renderer->SetupFrame(this, 0, 0, NumVertices, boneData, boneStartPosition);
|
||||
|
|
@ -517,7 +541,26 @@ const TArray<TRS>* IQMModel::AttachAnimationData()
|
|||
return &TRSData;
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double inter, const TArray<TRS>* animationData, DBoneComponents* boneComponentData, int index)
|
||||
static TRS InterpolateBone(const TRS &from, const TRS &to, float t, float invt)
|
||||
{
|
||||
TRS bone;
|
||||
|
||||
bone.translation = from.translation * invt + to.translation * t;
|
||||
bone.rotation = from.rotation * invt;
|
||||
|
||||
if ((bone.rotation | to.rotation * t) < 0)
|
||||
{
|
||||
bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1;
|
||||
}
|
||||
|
||||
bone.rotation += to.rotation * t;
|
||||
bone.rotation.MakeUnit();
|
||||
bone.scaling = from.scaling * invt + to.scaling * t;
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
const TArray<VSMatrix> IQMModel::CalculateBones(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<TRS>& animationFrames = animationData ? *animationData : TRSData;
|
||||
if (Joints.Size() > 0)
|
||||
|
|
@ -534,8 +577,13 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
|
|||
|
||||
int offset1 = frame1 * numbones;
|
||||
int offset2 = frame2 * numbones;
|
||||
float t = (float)inter;
|
||||
float invt = 1.0f - t;
|
||||
|
||||
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;
|
||||
|
||||
float swapYZ[16] = { 0.0f };
|
||||
swapYZ[0 + 0 * 4] = 1.0f;
|
||||
|
|
@ -547,19 +595,26 @@ const TArray<VSMatrix> IQMModel::CalculateBones(int frame1, int frame2, double i
|
|||
TArray<bool> modifiedBone(numbones, true);
|
||||
for (int i = 0; i < numbones; i++)
|
||||
{
|
||||
TRS bone;
|
||||
TRS from = animationFrames[offset1 + i];
|
||||
TRS to = animationFrames[offset2 + i];
|
||||
TRS prev;
|
||||
|
||||
bone.translation = from.translation * invt + to.translation * t;
|
||||
bone.rotation = from.rotation * invt;
|
||||
if ((bone.rotation | to.rotation * t) < 0)
|
||||
if(frame1 >= 0 && (frame1_prev >= 0 || inter1_prev < 0))
|
||||
{
|
||||
bone.rotation.X *= -1; bone.rotation.Y *= -1; bone.rotation.Z *= -1; bone.rotation.W *= -1;
|
||||
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);
|
||||
}
|
||||
|
||||
TRS bone;
|
||||
|
||||
if(frame1 >= 0 || inter < 0)
|
||||
{
|
||||
bone = inter < 0 ? animationFrames[offset1 + i] : InterpolateBone(prev, next , inter, invt);
|
||||
}
|
||||
bone.rotation += to.rotation * t;
|
||||
bone.rotation.MakeUnit();
|
||||
bone.scaling = from.scaling * invt + to.scaling * t;
|
||||
|
||||
if (Joints[i].Parent >= 0 && modifiedBone[Joints[i].Parent])
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue