Moved animation-related classes to their own subfolder

This commit is contained in:
parax0
2016-10-26 18:12:08 -06:00
parent 3942c09e89
commit 595e4b931e
28 changed files with 129 additions and 40 deletions

View File

@@ -0,0 +1,52 @@
#ifndef CANIMEVENTDATA
#define CANIMEVENTDATA
#include "Core/Resource/CResource.h"
class CAnimEventData : public CResource
{
struct SEvent
{
u32 mCharacterIndex;
CAssetID mAssetRef;
};
std::vector<SEvent> mEvents;
public:
CAnimEventData(CResourceEntry *pEntry = 0)
: CResource(pEntry)
{
}
CDependencyTree* BuildDependencyTree() const
{
CDependencyTree *pTree = new CDependencyTree(ID());
AddDependenciesToTree(pTree);
return pTree;
}
void AddDependenciesToTree(CDependencyTree *pTree) const
{
for (u32 iEvt = 0; iEvt < mEvents.size(); iEvt++)
{
const SEvent& rkEvent = mEvents[iEvt];
CAssetID ID = rkEvent.mAssetRef;
if (ID.IsValid() && !pTree->HasDependency(ID))
{
CAnimEventDependency *pDep = new CAnimEventDependency(ID, rkEvent.mCharacterIndex);
pTree->AddChild(pDep);
}
}
}
inline u32 NumEvents() const { return mEvents.size(); }
inline u32 EventCharacterIndex(u32 EventIdx) const { return mEvents[EventIdx].mCharacterIndex; }
inline CAssetID EventAssetRef(u32 EventIdx) const { return mEvents[EventIdx].mAssetRef; }
inline void AddEvent(u32 CharIdx, CAssetID AssetID) { mEvents.push_back( SEvent { CharIdx, AssetID } ); }
};
#endif // CANIMEVENTDATA

View File

@@ -0,0 +1,96 @@
#ifndef CANIMSET_H
#define CANIMSET_H
#include "CAnimation.h"
#include "CAnimEventData.h"
#include "CSkeleton.h"
#include "CSkin.h"
#include "Core/Resource/CDependencyGroup.h"
#include "Core/Resource/CResource.h"
#include "Core/Resource/TResPtr.h"
#include "Core/Resource/Model/CModel.h"
#include <Common/types.h>
#include <vector>
struct SSetCharacter
{
TString Name;
TResPtr<CModel> pModel;
TResPtr<CSkin> pSkin;
TResPtr<CSkeleton> pSkeleton;
std::vector<CAssetID> GenericParticles;
std::vector<CAssetID> ElectricParticles;
std::vector<CAssetID> SwooshParticles;
std::vector<CAssetID> SpawnParticles;
std::vector<CAssetID> EffectParticles;
CAssetID IceModel;
CAssetID IceSkin;
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;
std::vector<SSetCharacter> mCharacters;
std::vector<SSetAnimation> mAnimations;
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
if (Game() >= eEchoesDemo)
{
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{
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;
}
}
}
CDependencyTree* BuildDependencyTree() const
{
CDependencyTree *pTree = new CDependencyTree(ID());
// Character dependencies
for (u32 iChar = 0; iChar < mCharacters.size(); iChar++)
{
CSetCharacterDependency *pCharTree = CSetCharacterDependency::BuildTree(this, iChar);
ASSERT(pCharTree);
pTree->AddChild(pCharTree);
}
for (u32 iAnim = 0; iAnim < mAnimations.size(); iAnim++)
{
CSetAnimationDependency *pAnimTree = CSetAnimationDependency::BuildTree(this, iAnim);
ASSERT(pAnimTree);
pTree->AddChild(pAnimTree);
}
return pTree;
}
// 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]; }
};
#endif // CCHARACTERSET_H

View File

@@ -0,0 +1,67 @@
#include "CAnimation.h"
#include <Math/CTransform4f.h>
#include <Math/MathUtil.h>
CAnimation::CAnimation(CResourceEntry *pEntry /*= 0*/)
: CResource(pEntry)
, mDuration(0.f)
, mTickInterval(0.0333333f)
, mNumKeys(0)
{
for (u32 iBone = 0; iBone < 100; iBone++)
{
mBoneInfo[iBone].TranslationChannelIdx = 0xFF;
mBoneInfo[iBone].RotationChannelIdx = 0xFF;
mBoneInfo[iBone].ScaleChannelIdx = 0xFF;
}
}
CDependencyTree* CAnimation::BuildDependencyTree() const
{
CDependencyTree *pTree = new CDependencyTree(ID());
pTree->AddDependency(mEventData);
return pTree;
}
void CAnimation::EvaluateTransform(float Time, u32 BoneID, CVector3f *pOutTranslation, CQuaternion *pOutRotation, CVector3f *pOutScale) const
{
const bool kInterpolate = true;
if (!pOutTranslation && !pOutRotation && !pOutScale) return;
if (mDuration == 0.f) return;
if (Time >= mDuration) Time = mDuration;
if (Time >= FLT_EPSILON) Time -= FLT_EPSILON;
float t = fmodf(Time, mTickInterval) / mTickInterval;
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 && pOutScale)
{
const CVector3f& rkLow = mScaleChannels[ScaleChannel][LowKey];
const CVector3f& rkHigh = mScaleChannels[ScaleChannel][LowKey + 1];
*pOutScale = (kInterpolate ? Math::Lerp<CVector3f>(rkLow, rkHigh, t) : rkLow);
}
if (RotChannel != 0xFF && pOutRotation)
{
const CQuaternion& rkLow = mRotationChannels[RotChannel][LowKey];
const CQuaternion& rkHigh = mRotationChannels[RotChannel][LowKey + 1];
*pOutRotation = (kInterpolate ? rkLow.Slerp(rkHigh, t) : rkLow);
}
if (TransChannel != 0xFF && pOutTranslation)
{
const CVector3f& rkLow = mTranslationChannels[TransChannel][LowKey];
const CVector3f& rkHigh = mTranslationChannels[TransChannel][LowKey + 1];
*pOutTranslation = (kInterpolate ? Math::Lerp<CVector3f>(rkLow, rkHigh, t) : rkLow);
}
}
bool CAnimation::HasTranslation(u32 BoneID) const
{
return (mBoneInfo[BoneID].TranslationChannelIdx != 0xFF);
}

View File

@@ -0,0 +1,47 @@
#ifndef CANIMATION_H
#define CANIMATION_H
#include "Core/Resource/CResource.h"
#include <Math/CQuaternion.h>
#include <Math/CVector3f.h>
#include <vector>
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;
float mDuration;
float mTickInterval;
u32 mNumKeys;
std::vector<TScaleChannel> mScaleChannels;
std::vector<TRotationChannel> mRotationChannels;
std::vector<TTranslationChannel> mTranslationChannels;
struct SBoneChannelInfo
{
u8 ScaleChannelIdx;
u8 RotationChannelIdx;
u8 TranslationChannelIdx;
};
SBoneChannelInfo mBoneInfo[100];
CAssetID mEventData;
public:
CAnimation(CResourceEntry *pEntry = 0);
CDependencyTree* BuildDependencyTree() const;
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; }
};
#endif // CANIMATION_H

View File

@@ -0,0 +1,205 @@
#include "CAnimationParameters.h"
#include "CAnimSet.h"
#include "Core/GameProject/CResourceStore.h"
#include <Common/Log.h>
#include <iostream>
CAnimationParameters::CAnimationParameters()
: mGame(ePrime)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
}
CAnimationParameters::CAnimationParameters(EGame Game)
: mGame(Game)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
}
CAnimationParameters::CAnimationParameters(IInputStream& rSCLY, EGame Game)
: mGame(Game)
, mCharIndex(0)
, mAnimIndex(0)
, mUnknown2(0)
, mUnknown3(0)
{
if (Game <= eEchoes)
{
mCharacterID = CAssetID(rSCLY, Game);
mCharIndex = rSCLY.ReadLong();
mAnimIndex = rSCLY.ReadLong();
}
else if (Game <= eCorruption)
{
mCharacterID = CAssetID(rSCLY, Game);
mAnimIndex = rSCLY.ReadLong();
}
else if (Game == eReturns)
{
u8 Flags = rSCLY.ReadByte();
// 0x80 - CharacterAnimationSet is empty.
if (Flags & 0x80)
{
mAnimIndex = -1;
mUnknown2 = 0;
mUnknown3 = 0;
return;
}
mCharacterID = CAssetID(rSCLY, Game);
// 0x20 - Default Anim is present
if (Flags & 0x20)
mAnimIndex = rSCLY.ReadLong();
else
mAnimIndex = -1;
// 0x40 - Two-value struct is present
if (Flags & 0x40)
{
mUnknown2 = rSCLY.ReadLong();
mUnknown3 = rSCLY.ReadLong();
}
else
{
mUnknown2 = 0;
mUnknown3 = 0;
}
}
}
void CAnimationParameters::Write(IOutputStream& rSCLY)
{
if (mGame <= eEchoes)
{
if (mCharacterID.IsValid())
{
mCharacterID.Write(rSCLY);
rSCLY.WriteLong(mCharIndex);
rSCLY.WriteLong(mAnimIndex);
}
else
{
rSCLY.WriteLong(0xFFFFFFFF);
rSCLY.WriteLong(0);
rSCLY.WriteLong(0xFFFFFFFF);
}
}
else if (mGame <= eCorruption)
{
if (mCharacterID.IsValid())
{
mCharacterID.Write(rSCLY);
rSCLY.WriteLong(mAnimIndex);
}
else
{
rSCLY.WriteLongLong(CAssetID::skInvalidID64.ToLongLong());
rSCLY.WriteLong(0xFFFFFFFF);
}
}
else
{
if (!mCharacterID.IsValid())
rSCLY.WriteByte((u8) 0x80);
else
{
u8 Flag = 0;
if (mAnimIndex != -1) Flag |= 0x20;
if (mUnknown2 != 0 || mUnknown3 != 0) Flag |= 0x40;
rSCLY.WriteByte(Flag);
mCharacterID.Write(rSCLY);
if (Flag & 0x20)
rSCLY.WriteLong(mAnimIndex);
if (Flag & 0x40)
{
rSCLY.WriteLong(mUnknown2);
rSCLY.WriteLong(mUnknown3);
}
}
}
}
CModel* CAnimationParameters::GetCurrentModel(s32 NodeIndex /*= -1*/)
{
if (!mCharacterID.IsValid()) return nullptr;
CAnimSet *pSet = AnimSet();
if (!pSet) return nullptr;
if (pSet->Type() != eAnimSet) return nullptr;
if (NodeIndex == -1) NodeIndex = mCharIndex;
if (pSet->NumCharacters() <= (u32) NodeIndex) return nullptr;
return pSet->Character(NodeIndex)->pModel;
}
TString CAnimationParameters::GetCurrentCharacterName(s32 NodeIndex /*= -1*/)
{
if (!mCharacterID.IsValid()) return "";
CAnimSet *pSet = AnimSet();
if (!pSet) return "";
if (pSet->Type() != eAnimSet) return "";
if (NodeIndex == -1) NodeIndex = mCharIndex;
if (pSet->NumCharacters() <= (u32) NodeIndex) return "";
return pSet->Character(NodeIndex)->Name;
}
// ************ ACCESSORS ************
u32 CAnimationParameters::Unknown(u32 Index)
{
// mAnimIndex isn't unknown, but I'm too lazy to move it because there's a lot
// of UI stuff that depends on these functions atm for accessing and editing parameters.
switch (Index)
{
case 0: return mAnimIndex;
case 1: return mUnknown2;
case 2: return mUnknown3;
default: return 0;
}
}
void CAnimationParameters::SetResource(const CAssetID& rkID)
{
mCharacterID = rkID;
mCharIndex = 0;
mAnimIndex = 0;
// Validate ID
if (mCharacterID.IsValid())
{
CResourceEntry *pEntry = gpResourceStore->FindEntry(rkID);
if (!pEntry)
Log::Error("Invalid resource ID passed to CAnimationParameters: " + rkID.ToString());
else if (pEntry->ResourceType() != eAnimSet)
Log::Error("Resource with invalid type passed to CAnimationParameters: " + pEntry->CookedAssetPath().GetFileName());
}
}
void CAnimationParameters::SetUnknown(u32 Index, u32 Value)
{
switch (Index)
{
case 0: mAnimIndex = Value;
case 1: mUnknown2 = Value;
case 2: mUnknown3 = Value;
}
}

View File

@@ -0,0 +1,53 @@
#ifndef CANIMATIONPARAMETERS_H
#define CANIMATIONPARAMETERS_H
#include "CAnimSet.h"
#include "Core/Resource/TResPtr.h"
#include "Core/Resource/Model/CModel.h"
#include <Common/EGame.h>
class CAnimationParameters
{
EGame mGame;
CAssetID mCharacterID;
u32 mCharIndex;
u32 mAnimIndex;
u32 mUnknown2;
u32 mUnknown3;
public:
CAnimationParameters();
CAnimationParameters(EGame Game);
CAnimationParameters(IInputStream& rSCLY, EGame Game);
void Write(IOutputStream& rSCLY);
CModel* GetCurrentModel(s32 NodeIndex = -1);
TString GetCurrentCharacterName(s32 NodeIndex = -1);
// Accessors
inline EGame Version() const { return mGame; }
inline CAssetID ID() const { return mCharacterID; }
inline CAnimSet* AnimSet() const { return (CAnimSet*) gpResourceStore->LoadResource(mCharacterID, (mGame < eCorruptionProto ? "ANCS" : "CHAR")); }
inline u32 CharacterIndex() const { return mCharIndex; }
inline u32 AnimIndex() const { return mAnimIndex; }
inline void SetCharIndex(u32 Index) { mCharIndex = Index; }
inline void SetAnimIndex(u32 Index) { mAnimIndex = Index; }
u32 Unknown(u32 Index);
void SetResource(const CAssetID& rkID);
void SetUnknown(u32 Index, u32 Value);
// Operators
inline bool operator==(const CAnimationParameters& rkOther) const
{
return ( (mGame == rkOther.mGame) &&
(mCharacterID == rkOther.mCharacterID) &&
(mCharIndex == rkOther.mCharIndex) &&
(mAnimIndex == rkOther.mAnimIndex) &&
(mUnknown2 == rkOther.mUnknown2) &&
(mUnknown3 == rkOther.mUnknown3) );
}
};
#endif // CANIMATIONPARAMETERS_H

View File

@@ -0,0 +1,182 @@
#include "CSkeleton.h"
#include "Core/Render/CBoneTransformData.h"
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CGraphics.h"
#include <Common/AssertMacro.h>
#include <Math/MathUtil.h>
// ************ CBone ************
CBone::CBone(CSkeleton *pSkel)
: mpSkeleton(pSkel)
, mSelected(false)
{
}
void CBone::UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot)
{
// Get transform data
SBoneTransformInfo TransformInfo;
TransformInfo.Position = mLocalPosition;
if (pAnim)
pAnim->EvaluateTransform(Time, mID, &TransformInfo.Position, &TransformInfo.Rotation, &TransformInfo.Scale);
if (AnchorRoot && IsRoot())
TransformInfo.Position = CVector3f::skZero;
// Apply parent transform
TransformInfo.Position = rkParentTransform.Position + (rkParentTransform.Rotation * (rkParentTransform.Scale * TransformInfo.Position));
TransformInfo.Rotation = rkParentTransform.Rotation * TransformInfo.Rotation;
// Calculate transform
CTransform4f& rTransform = rData[mID];
rTransform.SetIdentity();
rTransform.Scale(TransformInfo.Scale);
rTransform.Rotate(TransformInfo.Rotation);
rTransform.Translate(TransformInfo.Position);
rTransform *= mInvBind;
// Calculate children
for (u32 iChild = 0; iChild < mChildren.size(); iChild++)
mChildren[iChild]->UpdateTransform(rData, TransformInfo, pAnim, Time, AnchorRoot);
}
CVector3f CBone::TransformedPosition(const CBoneTransformData& rkData) const
{
return rkData[mID] * Position();
}
CQuaternion CBone::TransformedRotation(const CBoneTransformData &rkData) const
{
return rkData[mID] * Rotation();
}
bool CBone::IsRoot() const
{
// In Retro's engine most skeletons have another bone named Skeleton_Root parented directly under the
// actual root bone... that bone sometimes acts as the actual root (transforming the entire skeleton),
// so we need to account for both
return (mpParent == nullptr || mpParent->Parent() == nullptr);
}
// ************ CSkeleton ************
const float CSkeleton::skSphereRadius = 0.025f;
CSkeleton::CSkeleton(CResourceEntry *pEntry /*= 0*/)
: CResource(pEntry)
, mpRootBone(nullptr)
{
}
CSkeleton::~CSkeleton()
{
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
delete mBones[iBone];
}
CBone* CSkeleton::BoneByID(u32 BoneID) const
{
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
if (mBones[iBone]->ID() == BoneID)
return mBones[iBone];
}
return nullptr;
}
CBone* CSkeleton::BoneByName(const TString& rkBoneName) const
{
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
if (mBones[iBone]->Name() == rkBoneName)
return mBones[iBone];
}
return nullptr;
}
u32 CSkeleton::MaxBoneID() const
{
u32 ID = 0;
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
if (mBones[iBone]->ID() > ID)
ID = mBones[iBone]->ID();
}
return ID;
}
void CSkeleton::UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot)
{
ASSERT(rData.NumTrackedBones() >= MaxBoneID());
mpRootBone->UpdateTransform(rData, SBoneTransformInfo(), pAnim, Time, AnchorRoot);
}
void CSkeleton::Draw(FRenderOptions /*Options*/, const CBoneTransformData *pkData)
{
glBlendFunc(GL_ONE, GL_ZERO);
glLineWidth(1.f);
// Draw all child links first to minimize model matrix swaps.
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
// Draw the bone's local XYZ axes for selected bones
if (pBone->IsSelected())
{
CQuaternion BoneRot = pkData ? pBone->TransformedRotation(*pkData) : pBone->Rotation();
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.XAxis(), CColor::skRed);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.YAxis(), CColor::skGreen);
CDrawUtil::DrawLine(BonePos, BonePos + BoneRot.ZAxis(), CColor::skBlue);
}
// Draw child links
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
{
CBone *pChild = pBone->ChildByIndex(iChild);
CVector3f ChildPos = pkData ? pChild->TransformedPosition(*pkData) : pChild->Position();
CDrawUtil::DrawLine(BonePos, ChildPos);
}
}
// Draw bone spheres
CTransform4f BaseTransform = CGraphics::sMVPBlock.ModelMatrix;
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pkData ? pBone->TransformedPosition(*pkData) : pBone->Position();
CTransform4f Transform;
Transform.Scale(skSphereRadius);
Transform.Translate(BonePos);
CGraphics::sMVPBlock.ModelMatrix = Transform * BaseTransform;
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawSphere(pBone->IsSelected() ? CColor::skRed : CColor::skWhite);
}
}
std::pair<s32,float> CSkeleton::RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData)
{
std::pair<s32,float> Out(-1, FLT_MAX);
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
CVector3f BonePos = pBone->TransformedPosition(rkData);
std::pair<bool,float> Intersect = Math::RaySphereIntersection(rkRay, BonePos, skSphereRadius);
if (Intersect.first && Intersect.second < Out.second)
{
Out.first = pBone->ID();
Out.second = Intersect.second;
}
}
return Out;
}

View File

@@ -0,0 +1,89 @@
#ifndef CSKELETON_H
#define CSKELETON_H
#include "CAnimation.h"
#include "Core/Render/FRenderOptions.h"
#include "Core/Resource/CResource.h"
#include <Common/TString.h>
#include <Common/types.h>
#include <Math/CRay.h>
#include <Math/CVector3f.h>
class CBoneTransformData;
class CBone;
struct SBoneTransformInfo
{
CVector3f Position;
CQuaternion Rotation;
CVector3f Scale;
SBoneTransformInfo()
: Position(CVector3f::skZero), Rotation(CQuaternion::skIdentity), Scale(CVector3f::skOne) {}
};
class CSkeleton : public CResource
{
DECLARE_RESOURCE_TYPE(eSkeleton)
friend class CSkeletonLoader;
CBone *mpRootBone;
std::vector<CBone*> mBones;
static const float skSphereRadius;
public:
CSkeleton(CResourceEntry *pEntry = 0);
~CSkeleton();
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
CBone* BoneByID(u32 BoneID) const;
CBone* BoneByName(const TString& rkBoneName) const;
u32 MaxBoneID() const;
void Draw(FRenderOptions Options, const CBoneTransformData *pkData);
std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
inline u32 NumBones() const { return mBones.size(); }
inline CBone* RootBone() const { return mpRootBone; }
};
class CBone
{
friend class CSkeletonLoader;
CSkeleton *mpSkeleton;
CBone *mpParent;
std::vector<CBone*> mChildren;
u32 mID;
CVector3f mPosition;
CVector3f mLocalPosition;
CQuaternion mRotation;
CQuaternion mLocalRotation;
TString mName;
CTransform4f mInvBind;
bool mSelected;
public:
CBone(CSkeleton *pSkel);
void UpdateTransform(CBoneTransformData& rData, const SBoneTransformInfo& rkParentTransform, CAnimation *pAnim, float Time, bool AnchorRoot);
CVector3f TransformedPosition(const CBoneTransformData& rkData) const;
CQuaternion TransformedRotation(const CBoneTransformData& rkData) const;
bool IsRoot() const;
// Accessors
inline CSkeleton* Skeleton() const { return mpSkeleton; }
inline CBone* Parent() const { return mpParent; }
inline u32 NumChildren() const { return mChildren.size(); }
inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; }
inline u32 ID() const { return mID; }
inline CVector3f Position() const { return mPosition; }
inline CVector3f LocalPosition() const { return mLocalPosition; }
inline CQuaternion Rotation() const { return mRotation; }
inline CQuaternion LocalRotation() const { return mLocalRotation; }
inline TString Name() const { return mName; }
inline bool IsSelected() const { return mSelected; }
inline void SetSelected(bool Selected) { mSelected = Selected; }
};
#endif // CSKELETON_H

View File

@@ -0,0 +1,50 @@
#ifndef CSKIN_H
#define CSKIN_H
#include "Core/Resource/CResource.h"
#include "Core/Resource/Model/CVertex.h"
struct SVertexWeights
{
TBoneIndices Indices;
TBoneWeights Weights;
};
class CSkin : public CResource
{
DECLARE_RESOURCE_TYPE(eSkin)
friend class CSkinLoader;
struct SVertGroup
{
SVertexWeights Weights;
u32 NumVertices;
};
std::vector<SVertGroup> mVertGroups;
public:
CSkin(CResourceEntry *pEntry = 0) : CResource(pEntry) {}
const SVertexWeights& WeightsForVertex(u32 VertIdx)
{
// Null weights bind everything to the root bone in case there is no matching vertex group
static const SVertexWeights skNullWeights = {
{ 3, 0, 0, 0 },
{ 1.f, 0.f, 0.f, 0.f }
};
u32 Index = 0;
for (u32 iGrp = 0; iGrp < mVertGroups.size(); iGrp++)
{
if (VertIdx < Index + mVertGroups[iGrp].NumVertices)
return mVertGroups[iGrp].Weights;
Index += mVertGroups[iGrp].NumVertices;
}
return skNullWeights;
}
};
#endif // CSKIN_H

View File

@@ -0,0 +1,88 @@
#ifndef IMETAANIMATION
#define IMETAANIMATION
#include "CAnimation.h"
#include "Core/Resource/TResPtr.h"
#include <Common/TString.h>
enum EMetaAnimationType
{
eMAT_Play = 0,
eMAT_Blend = 1,
eMAT_PhaseBlend = 2, // note: structure shared with eMAT_Blend, differences are currently unknown
eMAT_Random = 3,
eMAT_Sequence = 4
};
// Base MetaAnimation interface
class IMetaAnimation
{
protected:
TString mName;
EMetaAnimationType mType;
public:
IMetaAnimation(EMetaAnimationType Type)
: mType(Type) {}
virtual ~IMetaAnimation() {}
// Accessors
inline void SetName(const TString& rkName) { mName = rkName; }
inline TString Name() const { return mName; }
inline EMetaAnimationType Type() const { return mType; }
};
// CMetaAnimationPlay - plays an animation
class CMetaAnimationPlay : public IMetaAnimation
{
protected:
TResPtr<CAnimation> mpAnim;
public:
CMetaAnimationPlay(CAnimation *pAnim)
: IMetaAnimation(eMAT_Play), mpAnim(pAnim) {}
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; }
};
// SAnimProbabilityPair - structure used by CMetaAnimationRandom to associate an animation with a probability value
struct SAnimProbabilityPair
{
IMetaAnimation *pAnim;
u32 Probability;
};
// CMetaAnimationRandom - play random animation
class CMetaAnimationRandom : public IMetaAnimation
{
protected:
std::vector<SAnimProbabilityPair> mProbabilityPairs;
public:
};
#endif // IMETAANIMATION