Added support for loading meta-animations and meta-transitions (yay! animation exclusion doesn't crash anymore!)

This commit is contained in:
parax0
2016-10-27 07:18:59 -06:00
parent 595e4b931e
commit 040caca896
17 changed files with 692 additions and 284 deletions

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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);
}

View File

@@ -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

View File

@@ -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
{
}

View File

@@ -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