Added support for loading animations from ANCS, fixed some bugs
This commit is contained in:
parent
a931e2aec6
commit
876cb0e737
|
@ -7,6 +7,11 @@ CAnimation::CAnimation()
|
||||||
, mTickInterval(0.0333333f)
|
, mTickInterval(0.0333333f)
|
||||||
, mNumKeys(0)
|
, mNumKeys(0)
|
||||||
{
|
{
|
||||||
|
for (u32 iBone = 0; iBone < 100; iBone++)
|
||||||
|
{
|
||||||
|
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
|
||||||
|
mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const
|
void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const
|
||||||
|
@ -35,3 +40,8 @@ void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) c
|
||||||
rOut.Translate( Math::Lerp<CVector3f>(rkLow, rkHigh, t) );
|
rOut.Translate( Math::Lerp<CVector3f>(rkLow, rkHigh, t) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CAnimation::HasTranslation(u32 BoneID) const
|
||||||
|
{
|
||||||
|
return (mBoneInfo[BoneID].TranslationChannelIdx != 0xFF);
|
||||||
|
}
|
||||||
|
|
|
@ -31,6 +31,7 @@ class CAnimation : public CResource
|
||||||
public:
|
public:
|
||||||
CAnimation();
|
CAnimation();
|
||||||
void EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const;
|
void EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const;
|
||||||
|
bool HasTranslation(u32 BoneID) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // CANIMATION_H
|
#endif // CANIMATION_H
|
||||||
|
|
|
@ -15,6 +15,7 @@ void CBone::UpdateTransform(CAnimation *pAnim, float Time, bool AnchorRoot)
|
||||||
if (pAnim)
|
if (pAnim)
|
||||||
pAnim->EvaluateTransform(Time, mID, mAnimTransform);
|
pAnim->EvaluateTransform(Time, mID, mAnimTransform);
|
||||||
|
|
||||||
|
if (!pAnim || !pAnim->HasTranslation(mID))
|
||||||
mAnimTransform.Translate(mPosition);
|
mAnimTransform.Translate(mPosition);
|
||||||
|
|
||||||
if (mpParent)
|
if (mpParent)
|
||||||
|
|
|
@ -71,6 +71,128 @@ void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadAnimation(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
TString Name = rANCS.ReadString();
|
||||||
|
Name = Name;
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadMetaAnimation(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
u32 Type = rANCS.ReadLong();
|
||||||
|
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
LoadPrimitive(rANCS);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
LoadBlend(rANCS);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
LoadRandom(rANCS);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
LoadSequence(rANCS);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadPrimitive(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
u32 AnimID = rANCS.ReadLong();
|
||||||
|
u32 AnimIndex = rANCS.ReadLong();
|
||||||
|
TString AnimName = rANCS.ReadString();
|
||||||
|
rANCS.Seek(0x8, SEEK_CUR);
|
||||||
|
|
||||||
|
if (mAnimPrimitives.size() < (AnimIndex + 1))
|
||||||
|
mAnimPrimitives.resize(AnimIndex + 1);
|
||||||
|
|
||||||
|
if (!mAnimPrimitives[AnimIndex].Loaded)
|
||||||
|
{
|
||||||
|
mAnimPrimitives[AnimIndex].Index = AnimIndex;
|
||||||
|
mAnimPrimitives[AnimIndex].AnimID = AnimID;
|
||||||
|
mAnimPrimitives[AnimIndex].Name = AnimName;
|
||||||
|
mAnimPrimitives[AnimIndex].Loaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadBlend(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
rANCS.Seek(0x5, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadRandom(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
u32 NumAnims = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||||
|
LoadAnimProbabilityPair(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadAnimProbabilityPair(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
rANCS.Seek(0x4, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadSequence(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
u32 NumAnims = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadTransition(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
rANCS.Seek(0xC, SEEK_CUR);
|
||||||
|
LoadMetaTransition(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadMetaTransition(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
u32 Type = rANCS.ReadLong();
|
||||||
|
|
||||||
|
switch (Type)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
LoadTransAnimation(rANCS);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
case 2:
|
||||||
|
LoadTransTransition(rANCS);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadTransAnimation(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
LoadMetaAnimation(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadTransTransition(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
rANCS.Seek(0xE, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadAdditiveAnimation(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
rANCS.Seek(0xC, SEEK_CUR);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CAnimSetLoader::LoadHalfTransition(IInputStream& rANCS)
|
||||||
|
{
|
||||||
|
rANCS.Seek(0x4, SEEK_CUR);
|
||||||
|
LoadMetaTransition(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
// ************ STATIC ************
|
// ************ STATIC ************
|
||||||
CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
||||||
{
|
{
|
||||||
|
@ -99,20 +221,21 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
||||||
pNode->Name = rANCS.ReadString();
|
pNode->Name = rANCS.ReadString();
|
||||||
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL");
|
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL");
|
||||||
pNode->SkinID = rANCS.ReadLong();
|
pNode->SkinID = rANCS.ReadLong();
|
||||||
|
|
||||||
|
if (Loader.mVersion == ePrime)
|
||||||
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
|
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
|
||||||
|
else
|
||||||
|
rANCS.Seek(0x4, SEEK_CUR);
|
||||||
|
|
||||||
// Unfortunately that's all that's actually supported at the moment. Hope to expand later.
|
// Unfortunately that's all that's actually supported at the moment. Hope to expand later.
|
||||||
// Since there's no size value I have to actually read the rest of the node to reach the next one
|
// Since there's no size value I have to actually read the rest of the node to reach the next one
|
||||||
u32 AnimCount = rANCS.ReadLong();
|
u32 AnimCount = rANCS.ReadLong();
|
||||||
bool ReadAnimNames = Loader.pSet->mAnims.empty();
|
|
||||||
if (ReadAnimNames) Loader.pSet->mAnims.resize(AnimCount);
|
|
||||||
|
|
||||||
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
|
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
|
||||||
{
|
{
|
||||||
rANCS.Seek(0x4, SEEK_CUR);
|
rANCS.Seek(0x4, SEEK_CUR);
|
||||||
if (Loader.mVersion == ePrime) rANCS.Seek(0x1, SEEK_CUR);
|
if (Loader.mVersion == ePrime) rANCS.Seek(0x1, SEEK_CUR);
|
||||||
TString AnimName = rANCS.ReadString();
|
rANCS.ReadString();
|
||||||
if (ReadAnimNames) Loader.pSet->mAnims[iAnim].Name = AnimName;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// PAS Database
|
// PAS Database
|
||||||
|
@ -171,6 +294,54 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load Animation Set
|
||||||
|
u32 SetStart = rANCS.Tell();
|
||||||
|
SetStart = SetStart;
|
||||||
|
u16 InfoCount = rANCS.ReadShort();
|
||||||
|
u32 NumAnims = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||||
|
Loader.LoadAnimation(rANCS);
|
||||||
|
|
||||||
|
u32 NumTransitions = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iTrans = 0; iTrans < NumTransitions; iTrans++)
|
||||||
|
Loader.LoadTransition(rANCS);
|
||||||
|
Loader.LoadMetaTransition(rANCS);
|
||||||
|
|
||||||
|
u32 NumAdditiveAnims = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iAnim = 0; iAnim < NumAdditiveAnims; iAnim++)
|
||||||
|
Loader.LoadAdditiveAnimation(rANCS);
|
||||||
|
|
||||||
|
rANCS.Seek(0x8, SEEK_CUR);
|
||||||
|
|
||||||
|
if (InfoCount > 2)
|
||||||
|
{
|
||||||
|
u32 NumHalfTransitions = rANCS.ReadLong();
|
||||||
|
|
||||||
|
for (u32 iHalf = 0; iHalf < NumHalfTransitions; iHalf++)
|
||||||
|
Loader.LoadHalfTransition(rANCS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove empty anims
|
||||||
|
for (auto it = Loader.mAnimPrimitives.begin(); it != Loader.mAnimPrimitives.end(); it++)
|
||||||
|
{
|
||||||
|
if (!it->Loaded)
|
||||||
|
it = Loader.mAnimPrimitives.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add anims to set
|
||||||
|
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
||||||
|
{
|
||||||
|
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
||||||
|
|
||||||
|
CAnimSet::SAnimation Anim;
|
||||||
|
Anim.Name = rPrim.Name;
|
||||||
|
Anim.pAnim = gResCache.GetResource(rPrim.AnimID, "ANIM");
|
||||||
|
Loader.pSet->mAnims.push_back(Anim);
|
||||||
|
}
|
||||||
|
|
||||||
return Loader.pSet;
|
return Loader.pSet;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,32 @@ class CAnimSetLoader
|
||||||
CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR);
|
CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR);
|
||||||
void LoadPASDatabase(IInputStream& rPAS4);
|
void LoadPASDatabase(IInputStream& rPAS4);
|
||||||
|
|
||||||
|
// Animation Set load functions
|
||||||
|
struct SPrimitive
|
||||||
|
{
|
||||||
|
u32 Index;
|
||||||
|
u32 AnimID;
|
||||||
|
TString Name;
|
||||||
|
bool Loaded;
|
||||||
|
|
||||||
|
SPrimitive() : Loaded(false) {}
|
||||||
|
};
|
||||||
|
std::vector<SPrimitive> mAnimPrimitives;
|
||||||
|
|
||||||
|
void LoadAnimation(IInputStream& rANCS);
|
||||||
|
void LoadMetaAnimation(IInputStream& rANCS);
|
||||||
|
void LoadPrimitive(IInputStream& rANCS);
|
||||||
|
void LoadBlend(IInputStream& rANCS);
|
||||||
|
void LoadRandom(IInputStream& rANCS);
|
||||||
|
void LoadAnimProbabilityPair(IInputStream& rANCS);
|
||||||
|
void LoadSequence(IInputStream& rANCS);
|
||||||
|
void LoadTransition(IInputStream& rANCS);
|
||||||
|
void LoadMetaTransition(IInputStream& rANCS);
|
||||||
|
void LoadTransAnimation(IInputStream& rANCS);
|
||||||
|
void LoadTransTransition(IInputStream& rANCS);
|
||||||
|
void LoadAdditiveAnimation(IInputStream& rANCS);
|
||||||
|
void LoadHalfTransition(IInputStream& rANCS);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static CAnimSet* LoadANCS(IInputStream& rANCS);
|
static CAnimSet* LoadANCS(IInputStream& rANCS);
|
||||||
static CAnimSet* LoadCHAR(IInputStream& rCHAR);
|
static CAnimSet* LoadCHAR(IInputStream& rCHAR);
|
||||||
|
|
|
@ -159,8 +159,6 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
||||||
{
|
{
|
||||||
SCompressedChannel& rChan = mCompressedChannels[iChan];
|
SCompressedChannel& rChan = mCompressedChannels[iChan];
|
||||||
|
|
||||||
// Reserve memory for all keys
|
|
||||||
|
|
||||||
// Set initial rotation/translation
|
// Set initial rotation/translation
|
||||||
if (rChan.NumRotationKeys > 0)
|
if (rChan.NumRotationKeys > 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ long CBitStreamInWrapper::ReadBits(long NumBits, bool ExtendSignBit /*= true*/)
|
||||||
|
|
||||||
while (BitsRemaining > 0)
|
while (BitsRemaining > 0)
|
||||||
{
|
{
|
||||||
if (mBitsRemaining <= BitsRemaining)
|
if (mBitsRemaining < BitsRemaining)
|
||||||
{
|
{
|
||||||
BitsRemaining -= mBitsRemaining;
|
BitsRemaining -= mBitsRemaining;
|
||||||
Out |= (mBitPool << Shift);
|
Out |= (mBitPool << Shift);
|
||||||
|
|
Loading…
Reference in New Issue