Added support for loading meta-animations and meta-transitions (yay! animation exclusion doesn't crash anymore!)
This commit is contained in:
parent
595e4b931e
commit
040caca896
|
@ -211,7 +211,9 @@ HEADERS += \
|
|||
Resource/Animation/CAnimEventData.h \
|
||||
Resource/Animation/CAnimSet.h \
|
||||
Resource/Animation/CSkeleton.h \
|
||||
Resource/Animation/CSkin.h
|
||||
Resource/Animation/CSkin.h \
|
||||
Resource/Animation/IMetaTransition.h \
|
||||
Resource/Animation/IMetaAnimation.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -310,4 +312,6 @@ SOURCES += \
|
|||
Resource/Factory/CAnimEventLoader.cpp \
|
||||
Resource/Animation/CAnimation.cpp \
|
||||
Resource/Animation/CAnimationParameters.cpp \
|
||||
Resource/Animation/CSkeleton.cpp
|
||||
Resource/Animation/CSkeleton.cpp \
|
||||
Resource/Animation/IMetaAnimation.cpp \
|
||||
Resource/Animation/IMetaTransition.cpp
|
||||
|
|
|
@ -186,7 +186,7 @@ EDependencyNodeType CSetCharacterDependency::Type() const
|
|||
|
||||
void CSetCharacterDependency::Serialize(IArchive& rArc)
|
||||
{
|
||||
rArc << SERIAL("SetIndex", mSetIndex)
|
||||
rArc << SERIAL("CharSetIndex", mCharSetIndex)
|
||||
<< SERIAL_ABSTRACT_CONTAINER("Children", mChildren, "Child", &gDependencyNodeFactory);
|
||||
}
|
||||
|
||||
|
@ -234,8 +234,8 @@ void CSetAnimationDependency::Serialize(IArchive& rArc)
|
|||
|
||||
CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOwnerSet, u32 AnimIndex)
|
||||
{
|
||||
const SSetAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
|
||||
CSetAnimationDependency *pTree = new CSetAnimationDependency;
|
||||
const SAnimation *pkAnim = pkOwnerSet->Animation(AnimIndex);
|
||||
|
||||
// Find relevant character indices
|
||||
for (u32 iChar = 0; iChar < pkOwnerSet->NumCharacters(); iChar++)
|
||||
|
@ -246,15 +246,21 @@ CSetAnimationDependency* CSetAnimationDependency::BuildTree(const CAnimSet *pkOw
|
|||
pTree->mCharacterIndices.insert(iChar);
|
||||
}
|
||||
|
||||
// Add dependencies. In MP2 animation event data is not a standalone resource.
|
||||
pTree->AddDependency(pkAnim->pAnim);
|
||||
// Add primitive dependencies. In MP2 animation event data is not a standalone resource.
|
||||
std::set<CAnimPrimitive> UsedPrimitives;
|
||||
pkAnim->pMetaAnim->GetUniquePrimitives(UsedPrimitives);
|
||||
|
||||
if (pkAnim->pEventData)
|
||||
for (auto Iter = UsedPrimitives.begin(); Iter != UsedPrimitives.end(); Iter++)
|
||||
{
|
||||
if (pkAnim->pEventData->Entry())
|
||||
pTree->AddDependency(pkAnim->pEventData);
|
||||
else
|
||||
pkAnim->pEventData->AddDependenciesToTree(pTree);
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
pTree->AddDependency(rkPrim.Animation());
|
||||
|
||||
if (pkOwnerSet->Game() >= eEchoesDemo)
|
||||
{
|
||||
CAnimEventData *pEvents = pkOwnerSet->AnimationEventData(rkPrim.ID());
|
||||
ASSERT(pEvents && !pEvents->Entry());
|
||||
pEvents->AddDependenciesToTree(pTree);
|
||||
}
|
||||
}
|
||||
|
||||
return pTree;
|
||||
|
|
|
@ -11,7 +11,6 @@ class CScriptObject;
|
|||
class CPropertyStruct;
|
||||
class CAnimSet;
|
||||
struct SSetCharacter;
|
||||
struct SSetAnimation;
|
||||
|
||||
// Group of node classes forming a tree of cached resource dependencies.
|
||||
enum EDependencyNodeType
|
||||
|
@ -154,17 +153,17 @@ protected:
|
|||
class CSetCharacterDependency : public CDependencyTree
|
||||
{
|
||||
protected:
|
||||
u32 mSetIndex;
|
||||
u32 mCharSetIndex;
|
||||
|
||||
public:
|
||||
CSetCharacterDependency() : CDependencyTree() {}
|
||||
CSetCharacterDependency(u32 SetIndex) : CDependencyTree(), mSetIndex(SetIndex) {}
|
||||
CSetCharacterDependency(u32 SetIndex) : CDependencyTree(), mCharSetIndex(SetIndex) {}
|
||||
|
||||
virtual EDependencyNodeType Type() const;
|
||||
virtual void Serialize(IArchive& rArc);
|
||||
|
||||
// Accessors
|
||||
inline u32 SetIndex() const { return mSetIndex; }
|
||||
inline u32 CharSetIndex() const { return mCharSetIndex; }
|
||||
|
||||
// Static
|
||||
static CSetCharacterDependency* BuildTree(const CAnimSet *pkOwnerSet, u32 CharIndex);
|
||||
|
|
|
@ -268,7 +268,7 @@ void CPackageDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurE
|
|||
else if (Type == eDNT_SetCharacter)
|
||||
{
|
||||
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->SetIndex()) || mIsPlayerActor;
|
||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || mIsPlayerActor;
|
||||
}
|
||||
|
||||
// Set animations should only be added if they're being used by at least one used character
|
||||
|
@ -438,8 +438,8 @@ void CAreaDependencyListBuilder::EvaluateDependencyNode(CResourceEntry *pCurEntr
|
|||
const u32 kEmptySuitIndex = (mGame >= eEchoesDemo ? 3 : 5);
|
||||
|
||||
CSetCharacterDependency *pChar = static_cast<CSetCharacterDependency*>(pNode);
|
||||
u32 SetIndex = pChar->SetIndex();
|
||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->SetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
|
||||
u32 SetIndex = pChar->CharSetIndex();
|
||||
ParseChildren = mCharacterUsageMap.IsCharacterUsed(mCurrentAnimSetID, pChar->CharSetIndex()) || (mIsPlayerActor && SetIndex == kEmptySuitIndex);
|
||||
}
|
||||
|
||||
else if (Type == eDNT_SetAnimation)
|
||||
|
|
|
@ -5,6 +5,8 @@
|
|||
#include "CAnimEventData.h"
|
||||
#include "CSkeleton.h"
|
||||
#include "CSkin.h"
|
||||
#include "IMetaAnimation.h"
|
||||
#include "IMetaTransition.h"
|
||||
#include "Core/Resource/CDependencyGroup.h"
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
|
@ -13,6 +15,34 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
// Animation structures
|
||||
struct SAdditiveAnim
|
||||
{
|
||||
u32 AnimID;
|
||||
float FadeInTime;
|
||||
float FadeOutTime;
|
||||
};
|
||||
|
||||
struct SAnimation
|
||||
{
|
||||
TString Name;
|
||||
IMetaAnimation *pMetaAnim;
|
||||
};
|
||||
|
||||
struct STransition
|
||||
{
|
||||
u32 Unknown;
|
||||
u32 AnimIdA;
|
||||
u32 AnimIdB;
|
||||
IMetaTransition *pMetaTrans;
|
||||
};
|
||||
|
||||
struct SHalfTransition
|
||||
{
|
||||
u32 AnimID;
|
||||
IMetaTransition *pMetaTrans;
|
||||
};
|
||||
|
||||
struct SSetCharacter
|
||||
{
|
||||
TString Name;
|
||||
|
@ -30,36 +60,37 @@ struct SSetCharacter
|
|||
std::set<u32> UsedAnimationIndices;
|
||||
};
|
||||
|
||||
struct SSetAnimation
|
||||
{
|
||||
TString Name;
|
||||
TResPtr<CAnimation> pAnim;
|
||||
TResPtr<CAnimEventData> pEventData;
|
||||
};
|
||||
|
||||
class CAnimSet : public CResource
|
||||
{
|
||||
DECLARE_RESOURCE_TYPE(eAnimSet)
|
||||
friend class CAnimSetLoader;
|
||||
|
||||
// Character Set
|
||||
std::vector<SSetCharacter> mCharacters;
|
||||
std::vector<SSetAnimation> mAnimations;
|
||||
|
||||
// Animation Set
|
||||
std::vector<CAnimPrimitive> mAnimPrimitives;
|
||||
std::vector<SAnimation> mAnimations;
|
||||
std::vector<STransition> mTransitions;
|
||||
IMetaTransition *mpDefaultTransition;
|
||||
std::vector<SAdditiveAnim> mAdditiveAnims;
|
||||
float mDefaultAdditiveFadeIn;
|
||||
float mDefaultAdditiveFadeOut;
|
||||
std::vector<SHalfTransition> mHalfTransitions;
|
||||
std::vector<CAnimEventData*> mAnimEvents; // note: these are for MP2, where event data isn't a standalone resource; these are owned by the animset
|
||||
|
||||
public:
|
||||
CAnimSet(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
|
||||
|
||||
~CAnimSet()
|
||||
{
|
||||
// note: in MP2, event data isn't a standalone resource, so it's owned by the animset; therefore we need to delete it manually
|
||||
// For MP2, anim events need to be cleaned up manually
|
||||
if (Game() >= eEchoesDemo)
|
||||
{
|
||||
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
for (u32 iEvent = 0; iEvent < mAnimEvents.size(); iEvent++)
|
||||
{
|
||||
SSetAnimation& rAnim = mAnimations[iAnim];
|
||||
CAnimEventData *pEvents = rAnim.pEventData;
|
||||
ASSERT(pEvents && !pEvents->Entry());
|
||||
rAnim.pEventData = nullptr; // make sure TResPtr destructor doesn't attempt to access
|
||||
delete pEvents;
|
||||
ASSERT(mAnimEvents[iEvent] && !mAnimEvents[iEvent]->Entry());
|
||||
delete mAnimEvents[iEvent];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -86,11 +117,48 @@ public:
|
|||
return pTree;
|
||||
}
|
||||
|
||||
CAnimation* FindAnimationAsset(u32 AnimID) const
|
||||
{
|
||||
if (AnimID >= 0 && AnimID < mAnimPrimitives.size())
|
||||
{
|
||||
CAnimPrimitive Prim = mAnimPrimitives[AnimID];
|
||||
return Prim.Animation();
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Accessors
|
||||
inline u32 NumCharacters() const { return mCharacters.size(); }
|
||||
inline u32 NumAnimations() const { return mAnimations.size(); }
|
||||
inline const SSetCharacter* Character(u32 Index) const { ASSERT(Index >= 0 && Index < NumCharacters()); return &mCharacters[Index]; }
|
||||
inline const SSetAnimation* Animation(u32 Index) const { ASSERT(Index >= 0 && Index < NumAnimations()); return &mAnimations[Index]; }
|
||||
inline u32 NumCharacters() const { return mCharacters.size(); }
|
||||
inline u32 NumAnimations() const { return mAnimations.size(); }
|
||||
|
||||
inline const SSetCharacter* Character(u32 Index) const
|
||||
{
|
||||
ASSERT(Index >= 0 && Index < NumCharacters());
|
||||
return &mCharacters[Index];
|
||||
}
|
||||
|
||||
inline const SAnimation* Animation(u32 Index) const
|
||||
{
|
||||
ASSERT(Index >= 0 && Index < NumAnimations());
|
||||
return &mAnimations[Index];
|
||||
}
|
||||
|
||||
CAnimEventData* AnimationEventData(u32 Index) const
|
||||
{
|
||||
ASSERT(Index >= 0 && Index < NumAnimations());
|
||||
|
||||
if (Game() <= ePrime)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = mAnimPrimitives[Index];
|
||||
return rkPrim.Animation() ? rkPrim.Animation()->EventData() : nullptr;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
return (Index < mAnimEvents.size() ? mAnimEvents[Index] : nullptr);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // CCHARACTERSET_H
|
||||
|
|
|
@ -19,7 +19,7 @@ CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/)
|
|||
CDependencyTree* CAnimation::BuildDependencyTree() const
|
||||
{
|
||||
CDependencyTree *pTree = new CDependencyTree(ID());
|
||||
pTree->AddDependency(mEventData);
|
||||
pTree->AddDependency(mpEventData);
|
||||
return pTree;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
#define CANIMATION_H
|
||||
|
||||
#include "Core/Resource/CResource.h"
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
#include "Core/Resource/Animation/CAnimEventData.h"
|
||||
#include <Math/CQuaternion.h>
|
||||
#include <Math/CVector3f.h>
|
||||
#include <vector>
|
||||
|
@ -31,7 +33,7 @@ class CAnimation : public CResource
|
|||
};
|
||||
SBoneChannelInfo mBoneInfo[100];
|
||||
|
||||
CAssetID mEventData;
|
||||
TResPtr<CAnimEventData> mpEventData;
|
||||
|
||||
public:
|
||||
CAnimation(CResourceEntry *pEntry = 0);
|
||||
|
@ -39,9 +41,10 @@ public:
|
|||
void EvaluateTransform(float Time, u32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const;
|
||||
bool HasTranslation(u32 BoneID) const;
|
||||
|
||||
inline float Duration() const { return mDuration; }
|
||||
inline u32 NumKeys() const { return mNumKeys; }
|
||||
inline float TickInterval() const { return mTickInterval; }
|
||||
inline float Duration() const { return mDuration; }
|
||||
inline u32 NumKeys() const { return mNumKeys; }
|
||||
inline float TickInterval() const { return mTickInterval; }
|
||||
inline CAnimEventData* EventData() const { return mpEventData; }
|
||||
};
|
||||
|
||||
#endif // CANIMATION_H
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
#include "IMetaAnimation.h"
|
||||
|
||||
// ************ CMetaAnimFactory ************
|
||||
CMetaAnimFactory gMetaAnimFactory;
|
||||
|
||||
IMetaAnimation* CMetaAnimFactory::LoadFromStream(IInputStream& rInput)
|
||||
{
|
||||
EMetaAnimationType Type = (EMetaAnimationType) rInput.ReadLong();
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case eMAT_Play:
|
||||
return new CMetaAnimPlay(rInput);
|
||||
|
||||
case eMAT_Blend:
|
||||
case eMAT_PhaseBlend:
|
||||
return new CMetaAnimBlend(Type, rInput);
|
||||
|
||||
case eMAT_Random:
|
||||
return new CMetaAnimRandom(rInput);
|
||||
|
||||
case eMAT_Sequence:
|
||||
return new CMetaAnimSequence(rInput);
|
||||
|
||||
default:
|
||||
Log::Error("Unrecognized meta-animation type: " + TString::FromInt32(Type, 0, 10));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CMetaAnimationPlay ************
|
||||
CMetaAnimPlay::CMetaAnimPlay(IInputStream& rInput)
|
||||
{
|
||||
mPrimitive = CAnimPrimitive(rInput);
|
||||
mUnknownA = rInput.ReadFloat();
|
||||
mUnknownB = rInput.ReadLong();
|
||||
}
|
||||
|
||||
EMetaAnimationType CMetaAnimPlay::Type() const
|
||||
{
|
||||
return eMAT_Play;
|
||||
}
|
||||
|
||||
void CMetaAnimPlay::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
rPrimSet.insert(mPrimitive);
|
||||
}
|
||||
|
||||
// ************ CMetaAnimBlend ************
|
||||
CMetaAnimBlend::CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput)
|
||||
{
|
||||
ASSERT(Type == eMAT_Blend || Type == eMAT_PhaseBlend);
|
||||
mType = Type;
|
||||
mpMetaAnimA = gMetaAnimFactory.LoadFromStream(rInput);
|
||||
mpMetaAnimB = gMetaAnimFactory.LoadFromStream(rInput);
|
||||
mUnknownA = rInput.ReadFloat();
|
||||
mUnknownB = rInput.ReadBool();
|
||||
}
|
||||
|
||||
CMetaAnimBlend::~CMetaAnimBlend()
|
||||
{
|
||||
delete mpMetaAnimA;
|
||||
delete mpMetaAnimB;
|
||||
}
|
||||
|
||||
EMetaAnimationType CMetaAnimBlend::Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void CMetaAnimBlend::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
mpMetaAnimA->GetUniquePrimitives(rPrimSet);
|
||||
mpMetaAnimB->GetUniquePrimitives(rPrimSet);
|
||||
}
|
||||
|
||||
// ************ CMetaAnimRandom ************
|
||||
CMetaAnimRandom::CMetaAnimRandom(IInputStream& rInput)
|
||||
{
|
||||
u32 NumPairs = rInput.ReadLong();
|
||||
mProbabilityPairs.reserve(NumPairs);
|
||||
|
||||
for (u32 iAnim = 0; iAnim < NumPairs; iAnim++)
|
||||
{
|
||||
SAnimProbabilityPair Pair;
|
||||
Pair.pAnim = gMetaAnimFactory.LoadFromStream(rInput);
|
||||
Pair.Probability = rInput.ReadLong();
|
||||
mProbabilityPairs.push_back(Pair);
|
||||
}
|
||||
}
|
||||
|
||||
CMetaAnimRandom::~CMetaAnimRandom()
|
||||
{
|
||||
for (u32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
||||
delete mProbabilityPairs[iPair].pAnim;
|
||||
}
|
||||
|
||||
EMetaAnimationType CMetaAnimRandom::Type() const
|
||||
{
|
||||
return eMAT_Random;
|
||||
}
|
||||
|
||||
void CMetaAnimRandom::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
for (u32 iPair = 0; iPair < mProbabilityPairs.size(); iPair++)
|
||||
mProbabilityPairs[iPair].pAnim->GetUniquePrimitives(rPrimSet);
|
||||
}
|
||||
|
||||
// ************ CMetaAnimSequence ************
|
||||
CMetaAnimSequence::CMetaAnimSequence(IInputStream& rInput)
|
||||
{
|
||||
u32 NumAnims = rInput.ReadLong();
|
||||
mAnimations.reserve(NumAnims);
|
||||
|
||||
for (u32 iAnim = 0; iAnim < NumAnims; iAnim++)
|
||||
{
|
||||
IMetaAnimation *pAnim = gMetaAnimFactory.LoadFromStream(rInput);
|
||||
mAnimations.push_back(pAnim);
|
||||
}
|
||||
}
|
||||
|
||||
CMetaAnimSequence::~CMetaAnimSequence()
|
||||
{
|
||||
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
delete mAnimations[iAnim];
|
||||
}
|
||||
|
||||
EMetaAnimationType CMetaAnimSequence::Type() const
|
||||
{
|
||||
return eMAT_Sequence;
|
||||
}
|
||||
|
||||
void CMetaAnimSequence::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
|
||||
mAnimations[iAnim]->GetUniquePrimitives(rPrimSet);
|
||||
}
|
|
@ -9,62 +9,98 @@ enum EMetaAnimationType
|
|||
{
|
||||
eMAT_Play = 0,
|
||||
eMAT_Blend = 1,
|
||||
eMAT_PhaseBlend = 2, // note: structure shared with eMAT_Blend, differences are currently unknown
|
||||
eMAT_PhaseBlend = 2, // note: structure shared with eMAT_Blend
|
||||
eMAT_Random = 3,
|
||||
eMAT_Sequence = 4
|
||||
};
|
||||
|
||||
// Factory class
|
||||
class CMetaAnimFactory
|
||||
{
|
||||
public:
|
||||
class IMetaAnimation* LoadFromStream(IInputStream& rInput);
|
||||
};
|
||||
extern CMetaAnimFactory gMetaAnimFactory;
|
||||
|
||||
// Animation primitive class
|
||||
class CAnimPrimitive
|
||||
{
|
||||
TResPtr<CAnimation> mpAnim;
|
||||
u32 mID;
|
||||
TString mName;
|
||||
|
||||
public:
|
||||
CAnimPrimitive() : mID(0) {}
|
||||
|
||||
CAnimPrimitive(IInputStream& rInput)
|
||||
{
|
||||
mpAnim = gpResourceStore->LoadResource(rInput.ReadLong(), "ANIM");
|
||||
mID = rInput.ReadLong();
|
||||
mName = rInput.ReadString();
|
||||
}
|
||||
|
||||
inline bool operator==(const CAnimPrimitive& rkRight) const { return mID == rkRight.mID; }
|
||||
inline bool operator< (const CAnimPrimitive& rkRight) const { return mID < rkRight.mID; }
|
||||
|
||||
// Accessors
|
||||
CAnimation* Animation() const { return mpAnim; }
|
||||
u32 ID() const { return mID; }
|
||||
TString Name() const { return mName; }
|
||||
};
|
||||
|
||||
// Base MetaAnimation interface
|
||||
class IMetaAnimation
|
||||
{
|
||||
public:
|
||||
IMetaAnimation() {}
|
||||
virtual ~IMetaAnimation() {}
|
||||
virtual EMetaAnimationType Type() const = 0;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
||||
|
||||
// Static
|
||||
static IMetaAnimation* LoadFromStream(IInputStream& rInput);
|
||||
};
|
||||
|
||||
// CMetaAnimPlay - plays an animation
|
||||
class CMetaAnimPlay : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
TString mName;
|
||||
EMetaAnimationType mType;
|
||||
CAnimPrimitive mPrimitive;
|
||||
float mUnknownA;
|
||||
u32 mUnknownB;
|
||||
|
||||
public:
|
||||
IMetaAnimation(EMetaAnimationType Type)
|
||||
: mType(Type) {}
|
||||
|
||||
virtual ~IMetaAnimation() {}
|
||||
CMetaAnimPlay(IInputStream& rInput);
|
||||
virtual EMetaAnimationType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
|
||||
// Accessors
|
||||
inline void SetName(const TString& rkName) { mName = rkName; }
|
||||
inline TString Name() const { return mName; }
|
||||
inline EMetaAnimationType Type() const { return mType; }
|
||||
inline CAnimPrimitive Primitive() const { return mPrimitive; }
|
||||
inline float UnknownA() const { return mUnknownA; }
|
||||
inline u32 UnknownB() const { return mUnknownB; }
|
||||
};
|
||||
|
||||
// CMetaAnimationPlay - plays an animation
|
||||
class CMetaAnimationPlay : public IMetaAnimation
|
||||
// CMetaAnimBlend - blend between two animations
|
||||
class CMetaAnimBlend : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
TResPtr<CAnimation> mpAnim;
|
||||
EMetaAnimationType mType;
|
||||
IMetaAnimation *mpMetaAnimA;
|
||||
IMetaAnimation *mpMetaAnimB;
|
||||
float mUnknownA;
|
||||
bool mUnknownB;
|
||||
|
||||
public:
|
||||
CMetaAnimationPlay(CAnimation *pAnim)
|
||||
: IMetaAnimation(eMAT_Play), mpAnim(pAnim) {}
|
||||
CMetaAnimBlend(EMetaAnimationType Type, IInputStream& rInput);
|
||||
~CMetaAnimBlend();
|
||||
virtual EMetaAnimationType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
|
||||
inline CAnimation* GetPlayAnimation() const { return mpAnim; }
|
||||
};
|
||||
|
||||
// CMetaAnimationBlend - blend between two animations
|
||||
class CMetaAnimationBlend : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
IMetaAnimation *mpAnimA;
|
||||
IMetaAnimation *mpAnimB;
|
||||
|
||||
public:
|
||||
CMetaAnimationBlend(IMetaAnimation *pAnimA, IMetaAnimation *pAnimB)
|
||||
: IMetaAnimation(eMAT_Blend), mpAnimA(pAnimA), mpAnimB(pAnimB) {}
|
||||
|
||||
~CMetaAnimationBlend()
|
||||
{
|
||||
delete mpAnimA;
|
||||
delete mpAnimB;
|
||||
}
|
||||
|
||||
inline IMetaAnimation* BlendAnimationA() const { return mpAnimA; }
|
||||
inline IMetaAnimation* BlendAnimationB() const { return mpAnimB; }
|
||||
// Accessors
|
||||
inline IMetaAnimation* BlendAnimationA() const { return mpMetaAnimA; }
|
||||
inline IMetaAnimation* BlendAnimationB() const { return mpMetaAnimB; }
|
||||
inline float UnknownA() const { return mUnknownA; }
|
||||
inline bool UnknownB() const { return mUnknownB; }
|
||||
};
|
||||
|
||||
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
|
||||
|
@ -74,14 +110,30 @@ struct SAnimProbabilityPair
|
|||
u32 Probability;
|
||||
};
|
||||
|
||||
// CMetaAnimationRandom - play random animation
|
||||
class CMetaAnimationRandom : public IMetaAnimation
|
||||
// CMetaAnimRandom - play random animation
|
||||
class CMetaAnimRandom : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
std::vector<SAnimProbabilityPair> mProbabilityPairs;
|
||||
|
||||
public:
|
||||
CMetaAnimRandom(IInputStream& rInput);
|
||||
~CMetaAnimRandom();
|
||||
virtual EMetaAnimationType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
};
|
||||
|
||||
// CMetaAnim - play a series of animations in sequence
|
||||
class CMetaAnimSequence : public IMetaAnimation
|
||||
{
|
||||
protected:
|
||||
std::vector<IMetaAnimation*> mAnimations;
|
||||
|
||||
public:
|
||||
CMetaAnimSequence(IInputStream& rInput);
|
||||
~CMetaAnimSequence();
|
||||
virtual EMetaAnimationType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
};
|
||||
|
||||
#endif // IMETAANIMATION
|
||||
|
|
|
@ -0,0 +1,83 @@
|
|||
#include "IMetaTransition.h"
|
||||
#include "IMetaAnimation.h"
|
||||
|
||||
// ************ CMetaTransFactory ************
|
||||
CMetaTransFactory gMetaTransFactory;
|
||||
|
||||
IMetaTransition* CMetaTransFactory::LoadFromStream(IInputStream& rInput)
|
||||
{
|
||||
EMetaTransitionType Type = (EMetaTransitionType) rInput.ReadLong();
|
||||
|
||||
switch (Type)
|
||||
{
|
||||
case eMTT_MetaAnim:
|
||||
return new CMetaTransMetaAnim(rInput);
|
||||
|
||||
case eMTT_Trans:
|
||||
case eMTT_PhaseTrans:
|
||||
return new CMetaTransTrans(Type, rInput);
|
||||
|
||||
case eMTT_Snap:
|
||||
return new CMetaTransSnap(rInput);
|
||||
|
||||
default:
|
||||
Log::Error("Unrecognized meta-transition type: " + TString::FromInt32(Type, 0, 10));
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// ************ CMetaTransMetaAnim ************
|
||||
CMetaTransMetaAnim::CMetaTransMetaAnim(IInputStream& rInput)
|
||||
{
|
||||
mpAnim = gMetaAnimFactory.LoadFromStream(rInput);
|
||||
}
|
||||
|
||||
CMetaTransMetaAnim::~CMetaTransMetaAnim()
|
||||
{
|
||||
delete mpAnim;
|
||||
}
|
||||
|
||||
EMetaTransitionType CMetaTransMetaAnim::Type() const
|
||||
{
|
||||
return eMTT_MetaAnim;
|
||||
}
|
||||
|
||||
void CMetaTransMetaAnim::GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const
|
||||
{
|
||||
mpAnim->GetUniquePrimitives(rPrimSet);
|
||||
}
|
||||
|
||||
// ************ CMetaTransTrans ************
|
||||
CMetaTransTrans::CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput)
|
||||
{
|
||||
ASSERT(Type == eMTT_Trans || Type == eMTT_PhaseTrans);
|
||||
mType = Type;
|
||||
mUnknownA = rInput.ReadFloat();
|
||||
mUnknownB = rInput.ReadLong();
|
||||
mUnknownC = rInput.ReadBool();
|
||||
mUnknownD = rInput.ReadBool();
|
||||
mUnknownE = rInput.ReadLong();
|
||||
}
|
||||
|
||||
EMetaTransitionType CMetaTransTrans::Type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
void CMetaTransTrans::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
|
||||
{
|
||||
}
|
||||
|
||||
// ************ CMetaTransSnap ************
|
||||
CMetaTransSnap::CMetaTransSnap(IInputStream&)
|
||||
{
|
||||
}
|
||||
|
||||
EMetaTransitionType CMetaTransSnap::Type() const
|
||||
{
|
||||
return eMTT_Snap;
|
||||
}
|
||||
|
||||
void CMetaTransSnap::GetUniquePrimitives(std::set<CAnimPrimitive>&) const
|
||||
{
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
#ifndef IMETATRANSITION_H
|
||||
#define IMETATRANSITION_H
|
||||
|
||||
#include "IMetaAnimation.h"
|
||||
|
||||
class IMetaAnimation;
|
||||
class IMetaTransition;
|
||||
|
||||
enum EMetaTransitionType
|
||||
{
|
||||
eMTT_MetaAnim = 0,
|
||||
eMTT_Trans = 1,
|
||||
eMTT_PhaseTrans = 2, // note: structure shared with eMTT_Trans
|
||||
eMTT_Snap = 3
|
||||
};
|
||||
|
||||
// Factory class
|
||||
class CMetaTransFactory
|
||||
{
|
||||
public:
|
||||
class IMetaTransition* LoadFromStream(IInputStream& rInput);
|
||||
};
|
||||
extern CMetaTransFactory gMetaTransFactory;
|
||||
|
||||
// Base MetaTransition interface
|
||||
class IMetaTransition
|
||||
{
|
||||
public:
|
||||
IMetaTransition() {}
|
||||
virtual ~IMetaTransition() {}
|
||||
virtual EMetaTransitionType Type() const = 0;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const = 0;
|
||||
};
|
||||
|
||||
// CMetaTransMetaAnim
|
||||
class CMetaTransMetaAnim : public IMetaTransition
|
||||
{
|
||||
IMetaAnimation *mpAnim;
|
||||
|
||||
public:
|
||||
CMetaTransMetaAnim(IInputStream& rInput);
|
||||
~CMetaTransMetaAnim();
|
||||
virtual EMetaTransitionType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
};
|
||||
|
||||
// CMetaTransTrans
|
||||
class CMetaTransTrans : public IMetaTransition
|
||||
{
|
||||
EMetaTransitionType mType;
|
||||
float mUnknownA;
|
||||
u32 mUnknownB;
|
||||
bool mUnknownC;
|
||||
bool mUnknownD;
|
||||
u32 mUnknownE;
|
||||
|
||||
public:
|
||||
CMetaTransTrans(EMetaTransitionType Type, IInputStream& rInput);
|
||||
virtual EMetaTransitionType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
};
|
||||
|
||||
// CMetaTransSnap
|
||||
class CMetaTransSnap : public IMetaTransition
|
||||
{
|
||||
public:
|
||||
CMetaTransSnap(IInputStream& rInput);
|
||||
virtual EMetaTransitionType Type() const;
|
||||
virtual void GetUniquePrimitives(std::set<CAnimPrimitive>& rPrimSet) const;
|
||||
};
|
||||
|
||||
#endif // IMETATRANSITION_H
|
|
@ -33,7 +33,7 @@ CAnimSet* CAnimSetLoader::LoadReturnsCHAR(IInputStream& rCHAR)
|
|||
return pSet;
|
||||
}
|
||||
|
||||
void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
|
||||
void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4, SSetCharacter *pChar)
|
||||
{
|
||||
// For now, just parse the data; don't store it
|
||||
rPAS4.Seek(0x4, SEEK_CUR); // Skipping PAS4 FourCC
|
||||
|
@ -68,128 +68,195 @@ void CAnimSetLoader::LoadPASDatabase(IInputStream& rPAS4)
|
|||
}
|
||||
|
||||
for (u32 iInfo = 0; iInfo < AnimInfoCount; iInfo++)
|
||||
rPAS4.Seek(0x4 + Skip, SEEK_CUR);
|
||||
{
|
||||
u32 MetaAnimID = rPAS4.ReadLong();
|
||||
rPAS4.Seek(Skip, SEEK_CUR);
|
||||
pChar->UsedAnimationIndices.insert(MetaAnimID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAnimSetLoader::LoadAnimation(IInputStream& rANCS)
|
||||
void CAnimSetLoader::LoadAnimationSet(IInputStream& rANCS)
|
||||
{
|
||||
TString Name = rANCS.ReadString();
|
||||
Name = Name;
|
||||
LoadMetaAnimation(rANCS);
|
||||
}
|
||||
u16 Version = rANCS.ReadShort();
|
||||
|
||||
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);
|
||||
ASSERT(AnimIndex < mAnimPrimitives.size());
|
||||
|
||||
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)
|
||||
{
|
||||
// Animations
|
||||
u32 NumAnims = rANCS.ReadLong();
|
||||
pSet->mAnimations.reserve(NumAnims);
|
||||
|
||||
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;
|
||||
SAnimation Anim;
|
||||
Anim.Name = rANCS.ReadString();
|
||||
Anim.pMetaAnim = gMetaAnimFactory.LoadFromStream(rANCS);
|
||||
pSet->mAnimations.push_back(Anim);
|
||||
}
|
||||
|
||||
// Transitions
|
||||
u32 NumTransitions = rANCS.ReadLong();
|
||||
pSet->mTransitions.reserve(NumTransitions);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < NumTransitions; iTrans++)
|
||||
{
|
||||
STransition Trans;
|
||||
Trans.Unknown = rANCS.ReadLong();
|
||||
Trans.AnimIdA = rANCS.ReadLong();
|
||||
Trans.AnimIdB = rANCS.ReadLong();
|
||||
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS);
|
||||
pSet->mTransitions.push_back(Trans);
|
||||
}
|
||||
|
||||
pSet->mpDefaultTransition = gMetaTransFactory.LoadFromStream(rANCS);
|
||||
|
||||
// Additive Animations
|
||||
u32 NumAdditive = rANCS.ReadLong();
|
||||
pSet->mAdditiveAnims.reserve(NumAdditive);
|
||||
|
||||
for (u32 iAdd = 0; iAdd < NumAdditive; iAdd++)
|
||||
{
|
||||
SAdditiveAnim Anim;
|
||||
Anim.AnimID = rANCS.ReadLong();
|
||||
Anim.FadeInTime = rANCS.ReadFloat();
|
||||
Anim.FadeOutTime = rANCS.ReadFloat();
|
||||
pSet->mAdditiveAnims.push_back(Anim);
|
||||
}
|
||||
|
||||
pSet->mDefaultAdditiveFadeIn = rANCS.ReadFloat();
|
||||
pSet->mDefaultAdditiveFadeOut = rANCS.ReadFloat();
|
||||
|
||||
// Half Transitions
|
||||
if (Version > 2)
|
||||
{
|
||||
u32 NumHalfTransitions = rANCS.ReadLong();
|
||||
pSet->mHalfTransitions.reserve(NumHalfTransitions);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < NumHalfTransitions; iTrans++)
|
||||
{
|
||||
SHalfTransition Trans;
|
||||
Trans.AnimID = rANCS.ReadLong();
|
||||
Trans.pMetaTrans = gMetaTransFactory.LoadFromStream(rANCS);
|
||||
pSet->mHalfTransitions.push_back(Trans);
|
||||
}
|
||||
}
|
||||
|
||||
// Skipping MP1 ANIM asset list
|
||||
// Events
|
||||
if (mVersion >= eEchoesDemo)
|
||||
{
|
||||
u32 EventDataCount = rANCS.ReadLong();
|
||||
pSet->mAnimEvents.reserve(EventDataCount);
|
||||
ASSERT(EventDataCount == NumAnims);
|
||||
|
||||
for (u32 iEvent = 0; iEvent < EventDataCount; iEvent++)
|
||||
{
|
||||
CAnimEventData *pData = CAnimEventLoader::LoadAnimSetEvents(rANCS);
|
||||
pSet->mAnimEvents.push_back(pData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAnimSetLoader::LoadTransAnimation(IInputStream& rANCS)
|
||||
void CAnimSetLoader::ProcessPrimitives()
|
||||
{
|
||||
LoadMetaAnimation(rANCS);
|
||||
}
|
||||
// Find all unique anim primitives
|
||||
std::set<CAnimPrimitive> UniquePrimitives;
|
||||
|
||||
void CAnimSetLoader::LoadTransTransition(IInputStream& rANCS)
|
||||
{
|
||||
rANCS.Seek(0xE, SEEK_CUR);
|
||||
}
|
||||
for (u32 iAnim = 0; iAnim < pSet->mAnimations.size(); iAnim++)
|
||||
pSet->mAnimations[iAnim].pMetaAnim->GetUniquePrimitives(UniquePrimitives);
|
||||
|
||||
void CAnimSetLoader::LoadAdditiveAnimation(IInputStream& rANCS)
|
||||
{
|
||||
rANCS.Seek(0xC, SEEK_CUR);
|
||||
}
|
||||
for (u32 iTrans = 0; iTrans < pSet->mTransitions.size(); iTrans++)
|
||||
pSet->mTransitions[iTrans].pMetaTrans->GetUniquePrimitives(UniquePrimitives);
|
||||
|
||||
void CAnimSetLoader::LoadHalfTransition(IInputStream& rANCS)
|
||||
{
|
||||
rANCS.Seek(0x4, SEEK_CUR);
|
||||
LoadMetaTransition(rANCS);
|
||||
pSet->mpDefaultTransition->GetUniquePrimitives(UniquePrimitives);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < pSet->mHalfTransitions.size(); iTrans++)
|
||||
pSet->mHalfTransitions[iTrans].pMetaTrans->GetUniquePrimitives(UniquePrimitives);
|
||||
|
||||
// Copy anim primitives into the animset
|
||||
for (auto Iter = UniquePrimitives.begin(); Iter != UniquePrimitives.end(); Iter++)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
u32 ID = rkPrim.ID();
|
||||
|
||||
if (ID >= pSet->mAnimPrimitives.size())
|
||||
pSet->mAnimPrimitives.resize(ID + 1);
|
||||
|
||||
pSet->mAnimPrimitives[ID] = rkPrim;
|
||||
ASSERT(pSet->Animation(ID)->pMetaAnim->Type() == eMAT_Play);
|
||||
}
|
||||
|
||||
// Add animations referenced by default transition
|
||||
std::set<CAnimPrimitive> DefaultTransPrimitives;
|
||||
pSet->mpDefaultTransition->GetUniquePrimitives(DefaultTransPrimitives);
|
||||
|
||||
for (u32 iChar = 0; iChar < pSet->mCharacters.size(); iChar++)
|
||||
{
|
||||
SSetCharacter& rChar = pSet->mCharacters[iChar];
|
||||
|
||||
for (auto Iter = DefaultTransPrimitives.begin(); Iter != DefaultTransPrimitives.end(); Iter++)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
rChar.UsedAnimationIndices.insert(rkPrim.ID());
|
||||
}
|
||||
}
|
||||
|
||||
// Add animations referenced by used transitions
|
||||
for (u32 iChar = 0; iChar < pSet->mCharacters.size(); iChar++)
|
||||
{
|
||||
SSetCharacter& rChar = pSet->mCharacters[iChar];
|
||||
bool AddedNewAnims = true;
|
||||
|
||||
// Loop this until we run out of new animations. This is in case any animations
|
||||
// referenced by any transitions are also referenced by earlier transitions.
|
||||
while (AddedNewAnims)
|
||||
{
|
||||
AddedNewAnims = false;
|
||||
|
||||
for (u32 iTrans = 0; iTrans < pSet->mTransitions.size(); iTrans++)
|
||||
{
|
||||
STransition& rTrans = pSet->mTransitions[iTrans];
|
||||
|
||||
if ( rChar.UsedAnimationIndices.find(rTrans.AnimIdA) != rChar.UsedAnimationIndices.end() &&
|
||||
rChar.UsedAnimationIndices.find(rTrans.AnimIdB) != rChar.UsedAnimationIndices.end() )
|
||||
{
|
||||
std::set<CAnimPrimitive> Primitives;
|
||||
rTrans.pMetaTrans->GetUniquePrimitives(Primitives);
|
||||
|
||||
for (auto Iter = Primitives.begin(); Iter != Primitives.end(); Iter++)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
|
||||
if (rChar.UsedAnimationIndices.find(rkPrim.ID()) == rChar.UsedAnimationIndices.end())
|
||||
{
|
||||
rChar.UsedAnimationIndices.insert(rkPrim.ID());
|
||||
AddedNewAnims = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (u32 iHalf = 0; iHalf < pSet->mHalfTransitions.size(); iHalf++)
|
||||
{
|
||||
SHalfTransition& rTrans = pSet->mHalfTransitions[iHalf];
|
||||
|
||||
if (rChar.UsedAnimationIndices.find(rTrans.AnimID) != rChar.UsedAnimationIndices.end())
|
||||
{
|
||||
std::set<CAnimPrimitive> Primitives;
|
||||
rTrans.pMetaTrans->GetUniquePrimitives(Primitives);
|
||||
|
||||
for (auto Iter = Primitives.begin(); Iter != Primitives.end(); Iter++)
|
||||
{
|
||||
const CAnimPrimitive& rkPrim = *Iter;
|
||||
|
||||
if (rChar.UsedAnimationIndices.find(rkPrim.ID()) == rChar.UsedAnimationIndices.end())
|
||||
{
|
||||
rChar.UsedAnimationIndices.insert(rkPrim.ID());
|
||||
AddedNewAnims = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
|
@ -254,7 +321,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||
}
|
||||
|
||||
// PAS Database
|
||||
Loader.LoadPASDatabase(rANCS);
|
||||
Loader.LoadPASDatabase(rANCS, pChar);
|
||||
|
||||
// Particles
|
||||
u32 ParticleCount = rANCS.ReadLong();
|
||||
|
@ -334,61 +401,8 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS, CResourceEntry *pEntry)
|
|||
}
|
||||
|
||||
// Load Animation Set
|
||||
u32 SetStart = rANCS.Tell();
|
||||
SetStart = SetStart;
|
||||
u16 InfoCount = rANCS.ReadShort();
|
||||
u32 NumAnims = rANCS.ReadLong();
|
||||
Loader.mAnimPrimitives.resize(NumAnims);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
// Add anims to set
|
||||
Loader.pSet->mAnimations.resize(Loader.mAnimPrimitives.size());
|
||||
|
||||
for (u32 iPrim = 0; iPrim < Loader.mAnimPrimitives.size(); iPrim++)
|
||||
{
|
||||
SPrimitive& rPrim = Loader.mAnimPrimitives[iPrim];
|
||||
|
||||
if (rPrim.Loaded)
|
||||
{
|
||||
SSetAnimation Anim;
|
||||
Anim.Name = rPrim.Name;
|
||||
Anim.pAnim = gpResourceStore->LoadResource(rPrim.AnimID, "ANIM");
|
||||
Loader.pSet->mAnimations[iPrim] = Anim;
|
||||
}
|
||||
}
|
||||
|
||||
// Parse anim event data
|
||||
if (Loader.pSet->Game() >= eEchoesDemo)
|
||||
{
|
||||
u32 EventDataCount = rANCS.ReadLong();
|
||||
ASSERT(EventDataCount == NumAnims);
|
||||
|
||||
for (u32 iEvnt = 0; iEvnt < EventDataCount; iEvnt++)
|
||||
Loader.pSet->mAnimations[iEvnt].pEventData = CAnimEventLoader::LoadAnimSetEvents(rANCS);
|
||||
}
|
||||
Loader.LoadAnimationSet(rANCS);
|
||||
Loader.ProcessPrimitives();
|
||||
|
||||
return Loader.pSet;
|
||||
}
|
||||
|
|
|
@ -12,33 +12,10 @@ class CAnimSetLoader
|
|||
CAnimSetLoader();
|
||||
CAnimSet* LoadCorruptionCHAR(IInputStream& rCHAR);
|
||||
CAnimSet* LoadReturnsCHAR(IInputStream& rCHAR);
|
||||
void LoadPASDatabase(IInputStream& rPAS4);
|
||||
void LoadPASDatabase(IInputStream& rPAS4, SSetCharacter *pChar);
|
||||
|
||||
// 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);
|
||||
void LoadAnimationSet(IInputStream& rANCS);
|
||||
void ProcessPrimitives();
|
||||
|
||||
public:
|
||||
static CAnimSet* LoadANCSOrCHAR(IInputStream& rFile, CResourceEntry *pEntry);
|
||||
|
|
|
@ -202,7 +202,7 @@ void CAnimationLoader::ReadUncompressedANIM()
|
|||
|
||||
if (mGame == ePrime)
|
||||
{
|
||||
mpAnim->mEventData = mpInput->ReadLong();
|
||||
mpAnim->mpEventData = gpResourceStore->LoadResource(mpInput->ReadLong(), "EVNT");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,7 +219,7 @@ void CAnimationLoader::ReadCompressedANIM()
|
|||
|
||||
if (mGame == ePrime)
|
||||
{
|
||||
mpAnim->mEventData = mpInput->ReadLong();
|
||||
mpAnim->mpEventData = gpResourceStore->LoadResource(mpInput->ReadLong(), "EVNT");
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
}
|
||||
else mpInput->Seek(0x2, SEEK_CUR); // Skip unknowns
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
inline CAnimSet* Character() const { return mpCharacter; }
|
||||
inline u32 ActiveCharIndex() const { return mActiveCharSet; }
|
||||
inline u32 ActiveAnimIndex() const { return mActiveAnim; }
|
||||
inline CAnimation* CurrentAnim() const { return (mAnimated && mpCharacter ? mpCharacter->Animation(mActiveAnim)->pAnim : nullptr); }
|
||||
inline CAnimation* CurrentAnim() const { return (mAnimated && mpCharacter ? mpCharacter->FindAnimationAsset(mActiveAnim) : nullptr); }
|
||||
inline bool IsAnimated() const { return (mAnimated && CurrentAnim() != nullptr); }
|
||||
|
||||
void SetAnimated(bool Animated) { mAnimated = Animated; SetDirty(); }
|
||||
|
|
|
@ -679,8 +679,7 @@ CSkeleton* CScriptNode::ActiveSkeleton() const
|
|||
CAnimation* CScriptNode::ActiveAnimation() const
|
||||
{
|
||||
CAnimSet *pSet = ActiveAnimSet();
|
||||
if (pSet) return pSet->Animation(mAnimIndex)->pAnim;
|
||||
else return nullptr;
|
||||
return pSet ? pSet->FindAnimationAsset(mAnimIndex) : nullptr;
|
||||
}
|
||||
|
||||
CTexture* CScriptNode::ActiveBillboard() const
|
||||
|
|
|
@ -160,18 +160,12 @@ void CCharacterEditor::UpdateCameraOrbit()
|
|||
|
||||
CSkeleton* CCharacterEditor::CurrentSkeleton() const
|
||||
{
|
||||
if (mpSet)
|
||||
return mpSet->Character(mCurrentChar)->pSkeleton;
|
||||
else
|
||||
return nullptr;
|
||||
return mpSet ? mpSet->Character(mCurrentChar)->pSkeleton : nullptr;
|
||||
}
|
||||
|
||||
CAnimation* CCharacterEditor::CurrentAnimation() const
|
||||
{
|
||||
if (mpSet)
|
||||
return mpSet->Animation(mCurrentAnim)->pAnim;
|
||||
else
|
||||
return nullptr;
|
||||
return mpSet ? mpSet->FindAnimationAsset(mCurrentAnim) : nullptr;
|
||||
}
|
||||
|
||||
void CCharacterEditor::SetActiveAnimSet(CAnimSet *pSet)
|
||||
|
@ -385,7 +379,7 @@ void CCharacterEditor::SetAnimTime(float Time)
|
|||
|
||||
mpCharNode->SetAnimTime(Time);
|
||||
|
||||
CAnimation *pAnim = (mpSet ? mpSet->Animation(mCurrentAnim)->pAnim : nullptr);
|
||||
CAnimation *pAnim = CurrentAnimation();
|
||||
u32 NumKeys = 1, CurKey = 0;
|
||||
|
||||
if (pAnim)
|
||||
|
|
Loading…
Reference in New Issue