Added support for Echoes animation formats
This commit is contained in:
parent
769662b51d
commit
82f037c69e
|
@ -9,8 +9,9 @@ CAnimation::CAnimation()
|
|||
{
|
||||
for (u32 iBone = 0; iBone < 100; iBone++)
|
||||
{
|
||||
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
|
||||
mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
|
||||
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
|
||||
mBoneInfo[iBone].ScaleChannelIdx = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,9 +25,17 @@ void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) c
|
|||
u32 LowKey = (u32) (Time / mTickInterval);
|
||||
if (LowKey == (mNumKeys - 1)) LowKey = mNumKeys - 2;
|
||||
|
||||
u8 ScaleChannel = mBoneInfo[BoneID].ScaleChannelIdx;
|
||||
u8 RotChannel = mBoneInfo[BoneID].RotationChannelIdx;
|
||||
u8 TransChannel = mBoneInfo[BoneID].TranslationChannelIdx;
|
||||
|
||||
if (ScaleChannel != 0xFF)
|
||||
{
|
||||
const CVector3f& rkLow = mScaleChannels[ScaleChannel][LowKey];
|
||||
const CVector3f& rkHigh = mScaleChannels[ScaleChannel][LowKey + 1];
|
||||
rOut.Scale( Math::Lerp<CVector3f>(rkLow, rkHigh, t) );
|
||||
}
|
||||
|
||||
if (RotChannel != 0xFF)
|
||||
{
|
||||
const CQuaternion& rkLow = mRotationChannels[RotChannel][LowKey];
|
||||
|
|
|
@ -11,6 +11,7 @@ class CAnimation : public CResource
|
|||
DECLARE_RESOURCE_TYPE(eAnimation)
|
||||
friend class CAnimationLoader;
|
||||
|
||||
typedef std::vector<CVector3f> TScaleChannel;
|
||||
typedef std::vector<CQuaternion> TRotationChannel;
|
||||
typedef std::vector<CVector3f> TTranslationChannel;
|
||||
|
||||
|
@ -18,11 +19,13 @@ class CAnimation : public CResource
|
|||
float mTickInterval;
|
||||
u32 mNumKeys;
|
||||
|
||||
std::vector<TScaleChannel> mScaleChannels;
|
||||
std::vector<TRotationChannel> mRotationChannels;
|
||||
std::vector<TTranslationChannel> mTranslationChannels;
|
||||
|
||||
struct SBoneChannelInfo
|
||||
{
|
||||
u8 ScaleChannelIdx;
|
||||
u8 RotationChannelIdx;
|
||||
u8 TranslationChannelIdx;
|
||||
};
|
||||
|
|
|
@ -220,16 +220,9 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
|||
if (iNode == 0) Loader.mVersion = (Unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately
|
||||
pNode->Name = rANCS.ReadString();
|
||||
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL");
|
||||
|
||||
if (Loader.mVersion <= ePrime)
|
||||
{
|
||||
pNode->pSkin = gResCache.GetResource(rANCS.ReadLong(), "CSKR");
|
||||
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
|
||||
|
||||
pNode->pModel->SetSkin(pNode->pSkin);
|
||||
}
|
||||
else
|
||||
rANCS.Seek(0x8, SEEK_CUR);
|
||||
pNode->pSkin = gResCache.GetResource(rANCS.ReadLong(), "CSKR");
|
||||
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
|
||||
if (pNode->pModel) pNode->pModel->SetSkin(pNode->pSkin);
|
||||
|
||||
// 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
|
||||
|
@ -298,50 +291,47 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
|||
}
|
||||
}
|
||||
|
||||
if (Loader.mVersion <= ePrime)
|
||||
// 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)
|
||||
{
|
||||
// Load Animation Set
|
||||
u32 SetStart = rANCS.Tell();
|
||||
SetStart = SetStart;
|
||||
u16 InfoCount = rANCS.ReadShort();
|
||||
u32 NumAnims = rANCS.ReadLong();
|
||||
u32 NumHalfTransitions = rANCS.ReadLong();
|
||||
|
||||
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||
Loader.LoadAnimation(rANCS);
|
||||
for (u32 iHalf = 0; iHalf < NumHalfTransitions; iHalf++)
|
||||
Loader.LoadHalfTransition(rANCS);
|
||||
}
|
||||
|
||||
u32 NumTransitions = rANCS.ReadLong();
|
||||
// Add anims to set
|
||||
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
||||
{
|
||||
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
||||
|
||||
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)
|
||||
if (rPrim.Loaded)
|
||||
{
|
||||
u32 NumHalfTransitions = rANCS.ReadLong();
|
||||
|
||||
for (u32 iHalf = 0; iHalf < NumHalfTransitions; iHalf++)
|
||||
Loader.LoadHalfTransition(rANCS);
|
||||
}
|
||||
|
||||
// Add anims to set
|
||||
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
||||
{
|
||||
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
||||
|
||||
if (rPrim.Loaded)
|
||||
{
|
||||
CAnimSet::SAnimation Anim;
|
||||
Anim.Name = rPrim.Name;
|
||||
Anim.pAnim = gResCache.GetResource(rPrim.AnimID, "ANIM");
|
||||
Loader.pSet->mAnims.push_back(Anim);
|
||||
}
|
||||
CAnimSet::SAnimation Anim;
|
||||
Anim.Name = rPrim.Name;
|
||||
Anim.pAnim = gResCache.GetResource(rPrim.AnimID, "ANIM");
|
||||
Loader.pSet->mAnims.push_back(Anim);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -2,31 +2,103 @@
|
|||
#include <Common/Log.h>
|
||||
#include <Math/MathUtil.h>
|
||||
|
||||
bool CAnimationLoader::UncompressedCheckEchoes()
|
||||
{
|
||||
// The best way we have to tell this is an Echoes ANIM is to try to parse it as an
|
||||
// Echoes ANIM and see whether we read the file correctly. The formatting has to be
|
||||
// a little weird because we have to make sure we don't try to seek or read anything
|
||||
// past the end of the file. The +4 being added to each size we test is to account
|
||||
// for the next size value of the next array.
|
||||
u32 End = mpInput->Size();
|
||||
|
||||
u32 NumRotIndices = mpInput->ReadLong();
|
||||
if (mpInput->Tell() + NumRotIndices + 4 >= End) return false;
|
||||
mpInput->Seek(NumRotIndices, SEEK_CUR);
|
||||
|
||||
u32 NumTransIndices = mpInput->ReadLong();
|
||||
if (mpInput->Tell() + NumTransIndices + 4 >= End) return false;
|
||||
mpInput->Seek(NumTransIndices, SEEK_CUR);
|
||||
|
||||
u32 NumScaleIndices = mpInput->ReadLong();
|
||||
if (mpInput->Tell() + NumScaleIndices + 4 >= End) return false;
|
||||
mpInput->Seek(NumScaleIndices, SEEK_CUR);
|
||||
|
||||
u32 ScaleKeysSize = mpInput->ReadLong() * 0xC;
|
||||
if (mpInput->Tell() + ScaleKeysSize + 4 >= End) return false;
|
||||
mpInput->Seek(ScaleKeysSize, SEEK_CUR);
|
||||
|
||||
u32 RotKeysSize = mpInput->ReadLong() * 0x10;
|
||||
if (mpInput->Tell() + RotKeysSize + 4 >= End) return false;
|
||||
mpInput->Seek(RotKeysSize, SEEK_CUR);
|
||||
|
||||
u32 TransKeysSize = mpInput->ReadLong() * 0xC;
|
||||
return (mpInput->Tell() + TransKeysSize == End);
|
||||
}
|
||||
|
||||
EGame CAnimationLoader::UncompressedCheckVersion()
|
||||
{
|
||||
// Call this function after the bone channel index array
|
||||
// No version number, so this is how we have to determine the version...
|
||||
u32 Start = mpInput->Tell();
|
||||
bool Echoes = UncompressedCheckEchoes();
|
||||
mpInput->Seek(Start, SEEK_SET);
|
||||
return (Echoes ? eEchoes : ePrime);
|
||||
}
|
||||
|
||||
void CAnimationLoader::ReadUncompressedANIM()
|
||||
{
|
||||
mpAnim->mDuration = mpInput->ReadFloat();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip differential state
|
||||
mpAnim->mTickInterval = mpInput->ReadFloat();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip differential state
|
||||
|
||||
mpAnim->mNumKeys = mpInput->ReadLong();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip root bone ID
|
||||
|
||||
// Read bone channel info
|
||||
u32 NumBoneChannels = 0;
|
||||
u32 NumScaleChannels = 0;
|
||||
u32 NumRotationChannels = 0;
|
||||
u32 NumTranslationChannels = 0;
|
||||
|
||||
u32 NumRotIndices = mpInput->ReadLong();
|
||||
std::vector<u8> RotIndices(NumRotIndices);
|
||||
// Bone channel list
|
||||
u32 NumBoneIndices = mpInput->ReadLong();
|
||||
std::vector<u8> BoneIndices(NumBoneIndices);
|
||||
|
||||
for (u32 iRot = 0; iRot < NumRotIndices; iRot++)
|
||||
for (u32 iChan = 0; iChan < NumBoneIndices; iChan++)
|
||||
{
|
||||
RotIndices[iRot] = mpInput->ReadByte();
|
||||
BoneIndices[iChan] = mpInput->ReadByte();
|
||||
|
||||
if (RotIndices[iRot] != 0xFF)
|
||||
NumRotationChannels++;
|
||||
if (BoneIndices[iChan] != 0xFF)
|
||||
NumBoneChannels++;
|
||||
}
|
||||
|
||||
mGame = UncompressedCheckVersion();
|
||||
|
||||
// Echoes only - rotation channel indices
|
||||
std::vector<u8> RotationIndices;
|
||||
|
||||
if (mGame == eEchoes)
|
||||
{
|
||||
u32 NumRotationIndices = mpInput->ReadLong();
|
||||
RotationIndices.resize(NumRotationIndices);
|
||||
|
||||
for (u32 iRot = 0; iRot < NumRotationIndices; iRot++)
|
||||
{
|
||||
RotationIndices[iRot] = mpInput->ReadByte();
|
||||
|
||||
if (RotationIndices[iRot] != 0xFF)
|
||||
NumRotationChannels++;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
NumRotationChannels = NumBoneChannels;
|
||||
RotationIndices = BoneIndices;
|
||||
}
|
||||
|
||||
// Translation channel indices
|
||||
u32 NumTransIndices = mpInput->ReadLong();
|
||||
std::vector<u8> TransIndices(NumTransIndices);
|
||||
|
||||
|
@ -38,23 +110,60 @@ void CAnimationLoader::ReadUncompressedANIM()
|
|||
NumTranslationChannels++;
|
||||
}
|
||||
|
||||
// Set up bone channel info
|
||||
for (u32 iRot = 0, iTrans = 0; iRot < NumRotIndices; iRot++)
|
||||
{
|
||||
u8 RotIdx = RotIndices[iRot];
|
||||
mpAnim->mBoneInfo[iRot].RotationChannelIdx = RotIdx;
|
||||
// Echoes only - scale channel indices
|
||||
std::vector<u8> ScaleIndices;
|
||||
|
||||
if (RotIdx != 0xFF)
|
||||
if (mGame == eEchoes)
|
||||
{
|
||||
u32 NumScaleIndices = mpInput->ReadLong();
|
||||
ScaleIndices.resize(NumScaleIndices);
|
||||
|
||||
for (u32 iScale = 0; iScale < NumScaleIndices; iScale++)
|
||||
{
|
||||
mpAnim->mBoneInfo[iRot].TranslationChannelIdx = TransIndices[iTrans];
|
||||
iTrans++;
|
||||
ScaleIndices[iScale] = mpInput->ReadByte();
|
||||
|
||||
if (ScaleIndices[iScale] != 0xFF)
|
||||
NumScaleIndices++;
|
||||
}
|
||||
}
|
||||
|
||||
// Set up bone channel info
|
||||
for (u32 iBone = 0, iChan = 0; iBone < NumBoneIndices; iBone++)
|
||||
{
|
||||
u8 BoneIdx = BoneIndices[iBone];
|
||||
|
||||
if (BoneIdx != 0xFF)
|
||||
{
|
||||
mpAnim->mBoneInfo[iBone].TranslationChannelIdx = (TransIndices.empty() ? 0xFF : TransIndices[iChan]);
|
||||
mpAnim->mBoneInfo[iBone].RotationChannelIdx = (RotationIndices.empty() ? 0xFF : RotationIndices[iChan]);
|
||||
mpAnim->mBoneInfo[iBone].ScaleChannelIdx = (ScaleIndices.empty() ? 0xFF : ScaleIndices[iChan]);
|
||||
iChan++;
|
||||
}
|
||||
|
||||
else
|
||||
mpAnim->mBoneInfo[iRot].TranslationChannelIdx = 0xFF;
|
||||
{
|
||||
mpAnim->mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
|
||||
mpAnim->mBoneInfo[iBone].RotationChannelIdx = 0xFF;
|
||||
mpAnim->mBoneInfo[iBone].ScaleChannelIdx = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
// Read bone transforms
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping quaternion count
|
||||
if (mGame == eEchoes)
|
||||
{
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping scale key count
|
||||
mpAnim->mScaleChannels.resize(NumScaleChannels);
|
||||
|
||||
for (u32 iScale = 0; iScale < NumScaleChannels; iScale++)
|
||||
{
|
||||
mpAnim->mScaleChannels[iScale].resize(mpAnim->mNumKeys);
|
||||
|
||||
for (u32 iKey = 0; iKey < mpAnim->mNumKeys; iKey++)
|
||||
mpAnim->mScaleChannels[iScale][iKey] = CVector3f(*mpInput);
|
||||
}
|
||||
}
|
||||
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping rotation key count
|
||||
mpAnim->mRotationChannels.resize(NumRotationChannels);
|
||||
|
||||
for (u32 iRot = 0; iRot < NumRotationChannels; iRot++)
|
||||
|
@ -65,7 +174,7 @@ void CAnimationLoader::ReadUncompressedANIM()
|
|||
mpAnim->mRotationChannels[iRot][iKey] = CQuaternion(*mpInput);
|
||||
}
|
||||
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping vector3f count
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping translation key count
|
||||
mpAnim->mTranslationChannels.resize(NumTranslationChannels);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < NumTranslationChannels; iTrans++)
|
||||
|
@ -76,19 +185,25 @@ void CAnimationLoader::ReadUncompressedANIM()
|
|||
mpAnim->mTranslationChannels[iTrans][iKey] = CVector3f(*mpInput);
|
||||
}
|
||||
|
||||
// Skip EVNT file
|
||||
if (mGame == ePrime)
|
||||
{
|
||||
// Skip EVNT file
|
||||
}
|
||||
}
|
||||
|
||||
void CAnimationLoader::ReadCompressedANIM()
|
||||
{
|
||||
// Header
|
||||
mpInput->Seek(0xC, SEEK_CUR); // Skip alloc size, EVNT ID, unknown value
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip alloc size
|
||||
mGame = (mpInput->PeekShort() == 0x0101 ? eEchoes : ePrime); // Version check
|
||||
mpInput->Seek(mGame == ePrime ? 0x8 : 0x2, SEEK_CUR); // Skip EVNT (MP1) and unknowns
|
||||
mpAnim->mDuration = mpInput->ReadFloat();
|
||||
mpAnim->mTickInterval = mpInput->ReadFloat();
|
||||
mpInput->Seek(0x8, SEEK_CUR); // Skip two unknown values
|
||||
|
||||
mRotationDivisor = mpInput->ReadLong();
|
||||
mTranslationMultiplier = mpInput->ReadFloat();
|
||||
if (mGame == eEchoes) mpInput->Seek(0x4, SEEK_CUR);
|
||||
u32 NumBoneChannels = mpInput->ReadLong();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown value
|
||||
|
||||
|
@ -102,17 +217,18 @@ void CAnimationLoader::ReadCompressedANIM()
|
|||
for (u32 iBit = 0; iBit < NumKeys; iBit++)
|
||||
mKeyFlags[iBit] = BitStream.ReadBit();
|
||||
}
|
||||
mpInput->Seek(0x8, SEEK_CUR);
|
||||
mpInput->Seek(mGame == ePrime ? 0x8 : 0x4, SEEK_CUR);
|
||||
|
||||
// Read bone channel descriptors
|
||||
mCompressedChannels.resize(NumBoneChannels);
|
||||
mpAnim->mScaleChannels.resize(NumBoneChannels);
|
||||
mpAnim->mRotationChannels.resize(NumBoneChannels);
|
||||
mpAnim->mTranslationChannels.resize(NumBoneChannels);
|
||||
|
||||
for (u32 iChan = 0; iChan < NumBoneChannels; iChan++)
|
||||
{
|
||||
SCompressedChannel& rChan = mCompressedChannels[iChan];
|
||||
rChan.BoneID = mpInput->ReadLong();
|
||||
rChan.BoneID = (mGame == ePrime ? mpInput->ReadLong() : mpInput->ReadByte());
|
||||
|
||||
// Read rotation parameters
|
||||
rChan.NumRotationKeys = mpInput->ReadShort();
|
||||
|
@ -142,8 +258,27 @@ void CAnimationLoader::ReadCompressedANIM()
|
|||
|
||||
mpAnim->mBoneInfo[rChan.BoneID].TranslationChannelIdx = (u8) iChan;
|
||||
}
|
||||
else
|
||||
mpAnim->mBoneInfo[rChan.BoneID].TranslationChannelIdx = 0xFF;
|
||||
else mpAnim->mBoneInfo[rChan.BoneID].TranslationChannelIdx = 0xFF;
|
||||
|
||||
// Read scale parameters
|
||||
u8 ScaleIdx = 0xFF;
|
||||
|
||||
if (mGame == eEchoes)
|
||||
{
|
||||
rChan.NumScaleKeys = mpInput->ReadShort();
|
||||
|
||||
if (rChan.NumScaleKeys > 0)
|
||||
{
|
||||
for (u32 iComp = 0; iComp < 3; iComp++)
|
||||
{
|
||||
rChan.Scale[iComp] = mpInput->ReadShort();
|
||||
rChan.ScaleBits[iComp] = mpInput->ReadByte();
|
||||
}
|
||||
|
||||
ScaleIdx = (u8) iChan;
|
||||
}
|
||||
}
|
||||
mpAnim->mBoneInfo[rChan.BoneID].ScaleChannelIdx = ScaleIdx;
|
||||
}
|
||||
|
||||
// Read animation data
|
||||
|
@ -159,7 +294,7 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
|||
{
|
||||
SCompressedChannel& rChan = mCompressedChannels[iChan];
|
||||
|
||||
// Set initial rotation/translation
|
||||
// Set initial rotation/translation/scale
|
||||
if (rChan.NumRotationKeys > 0)
|
||||
{
|
||||
mpAnim->mRotationChannels[iChan].reserve(rChan.NumRotationKeys + 1);
|
||||
|
@ -173,6 +308,13 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
|||
CVector3f Translate = CVector3f(rChan.Translation[0], rChan.Translation[1], rChan.Translation[2]) * mTranslationMultiplier;
|
||||
mpAnim->mTranslationChannels[iChan].push_back(Translate);
|
||||
}
|
||||
|
||||
if (rChan.NumScaleKeys > 0)
|
||||
{
|
||||
mpAnim->mScaleChannels[iChan].reserve(rChan.NumScaleKeys + 1);
|
||||
CVector3f Scale = CVector3f(rChan.Scale[0], rChan.Scale[1], rChan.Scale[2]) / (float) mRotationDivisor;
|
||||
mpAnim->mScaleChannels[iChan].push_back(Scale);
|
||||
}
|
||||
}
|
||||
|
||||
// Read keys
|
||||
|
@ -215,6 +357,20 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
|||
CVector3f Translate = CVector3f(rChan.Translation[0], rChan.Translation[1], rChan.Translation[2]) * mTranslationMultiplier;
|
||||
mpAnim->mTranslationChannels[iChan].push_back(Translate);
|
||||
}
|
||||
|
||||
// Read scale
|
||||
if (rChan.NumScaleKeys > 0)
|
||||
{
|
||||
if (KeyPresent)
|
||||
{
|
||||
rChan.Scale[0] += (s16) BitStream.ReadBits(rChan.ScaleBits[0]);
|
||||
rChan.Scale[1] += (s16) BitStream.ReadBits(rChan.ScaleBits[1]);
|
||||
rChan.Scale[2] += (s16) BitStream.ReadBits(rChan.ScaleBits[2]);
|
||||
}
|
||||
|
||||
CVector3f Scale = CVector3f(rChan.Scale[0], rChan.Scale[1], rChan.Scale[2]) / (float) mRotationDivisor;
|
||||
mpAnim->mScaleChannels[iChan].push_back(Scale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -242,6 +398,7 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
|||
{
|
||||
bool HasTranslationKeys = mCompressedChannels[iChan].NumTranslationKeys > 0;
|
||||
bool HasRotationKeys = mCompressedChannels[iChan].NumRotationKeys > 0;
|
||||
bool HasScaleKeys = mCompressedChannels[iChan].NumScaleKeys > 0;
|
||||
|
||||
if (HasRotationKeys)
|
||||
{
|
||||
|
@ -256,6 +413,13 @@ void CAnimationLoader::ReadCompressedAnimationData()
|
|||
CVector3f Right = mpAnim->mTranslationChannels[iChan][LastIndex];
|
||||
mpAnim->mTranslationChannels[iChan][KeyIndex] = Math::Lerp<CVector3f>(Left, Right, Interp);
|
||||
}
|
||||
|
||||
if (HasScaleKeys)
|
||||
{
|
||||
CVector3f Left = mpAnim->mScaleChannels[iChan][FirstIndex];
|
||||
CVector3f Right = mpAnim->mScaleChannels[iChan][LastIndex];
|
||||
mpAnim->mScaleChannels[iChan][KeyIndex] = Math::Lerp<CVector3f>(Left, Right, Interp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,13 @@
|
|||
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
#include "Core/Resource/CAnimation.h"
|
||||
#include "Core/Resource/EGame.h"
|
||||
|
||||
class CAnimationLoader
|
||||
{
|
||||
TResPtr<CAnimation> mpAnim;
|
||||
IInputStream *mpInput;
|
||||
EGame mGame;
|
||||
|
||||
// Compression data
|
||||
std::vector<bool> mKeyFlags;
|
||||
|
@ -23,10 +25,15 @@ class CAnimationLoader
|
|||
u16 NumTranslationKeys;
|
||||
s16 Translation[3];
|
||||
u8 TranslationBits[3];
|
||||
u16 NumScaleKeys;
|
||||
s16 Scale[3];
|
||||
u8 ScaleBits[3];
|
||||
};
|
||||
std::vector<SCompressedChannel> mCompressedChannels;
|
||||
|
||||
CAnimationLoader() {}
|
||||
bool UncompressedCheckEchoes();
|
||||
EGame UncompressedCheckVersion();
|
||||
void ReadUncompressedANIM();
|
||||
void ReadCompressedANIM();
|
||||
void ReadCompressedAnimationData();
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#include "CSkeletonLoader.h"
|
||||
#include <Common/Assert.h>
|
||||
#include <Common/Log.h>
|
||||
|
||||
#include <vector>
|
||||
|
@ -27,6 +28,7 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
|
|||
CSkeletonLoader Loader;
|
||||
CSkeleton *pSkel = new CSkeleton();
|
||||
Loader.mpSkeleton = pSkel;
|
||||
EGame Game = eUnknownVersion;
|
||||
|
||||
u32 NumBones = rCINF.ReadLong();
|
||||
pSkel->mBones.reserve(NumBones);
|
||||
|
@ -48,7 +50,19 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
|
|||
BoneInfo[iBone].ParentID = rCINF.ReadLong();
|
||||
pBone->mPosition = CVector3f(rCINF);
|
||||
|
||||
// Version test. No version number. The next value is the linked bone count in MP1 and the first
|
||||
// skin metric value in MP2. The max bone count is 100 so the linked bone count will not be higher
|
||||
// than that. Additionally, every bone links to its parent at least and every skeleton (as far as I
|
||||
// know) has at least two bones so the linked bone count will never be 0.
|
||||
if (Game == eUnknownVersion)
|
||||
{
|
||||
u32 Check = rCINF.PeekLong();
|
||||
Game = ((Check > 100 || Check == 0) ? eEchoes : ePrime);
|
||||
}
|
||||
if (Game == eEchoes) rCINF.Seek(0x20, SEEK_CUR); // Skip skin metrics
|
||||
|
||||
u32 NumLinkedBones = rCINF.ReadLong();
|
||||
ASSERT(NumLinkedBones != 0);
|
||||
|
||||
for (u32 iLink = 0; iLink < NumLinkedBones; iLink++)
|
||||
{
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include "Core/Render/CDrawUtil.h"
|
||||
#include "Core/Render/CRenderer.h"
|
||||
#include "Core/OpenGL/GLCommon.h"
|
||||
#include <Common/Assert.h>
|
||||
|
||||
CModel::CModel()
|
||||
: CBasicModel()
|
||||
|
@ -162,6 +163,8 @@ void CModel::DrawWireframe(FRenderOptions Options, CColor WireColor /*= CColor::
|
|||
|
||||
void CModel::SetSkin(CSkin *pSkin)
|
||||
{
|
||||
ASSERT(!mpSkin || !pSkin || mpSkin == pSkin); // This is to verify no model has more than one unique skin applied
|
||||
|
||||
if (mpSkin != pSkin)
|
||||
{
|
||||
const FVertexDescription kBoneFlags = (eBoneIndices | eBoneWeights);
|
||||
|
|
|
@ -124,8 +124,9 @@ void CCharacterNode::SetActiveChar(u32 CharIndex)
|
|||
|
||||
if (mpCharacter)
|
||||
{
|
||||
CModel *pModel = mpCharacter->NodeModel(CharIndex);
|
||||
mTransformData.ResizeToSkeleton(mpCharacter->NodeSkeleton(CharIndex));
|
||||
mLocalAABox = mpCharacter->NodeModel(CharIndex)->AABox();
|
||||
mLocalAABox = pModel ? pModel->AABox() : CAABox::skZero;
|
||||
MarkTransformChanged();
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue