Added support for loading uncompressed animations and playing them back
This commit is contained in:
parent
2376a36f0b
commit
ef523c2339
|
@ -188,7 +188,9 @@ HEADERS += \
|
|||
Resource/Script/CLink.h \
|
||||
Resource/CSkeleton.h \
|
||||
Resource/Factory/CSkeletonLoader.h \
|
||||
Scene/CCharacterNode.h
|
||||
Scene/CCharacterNode.h \
|
||||
Resource/CAnimation.h \
|
||||
Resource/Factory/CAnimationLoader.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -269,4 +271,6 @@ SOURCES += \
|
|||
ScriptExtra/CSplinePathExtra.cpp \
|
||||
Resource/CSkeleton.cpp \
|
||||
Resource/Factory/CSkeletonLoader.cpp \
|
||||
Scene/CCharacterNode.cpp
|
||||
Scene/CCharacterNode.cpp \
|
||||
Resource/CAnimation.cpp \
|
||||
Resource/Factory/CAnimationLoader.cpp
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define CANIMSET_H
|
||||
|
||||
#include "TResPtr.h"
|
||||
#include "CAnimation.h"
|
||||
#include "CResource.h"
|
||||
#include "CSkeleton.h"
|
||||
#include "Core/Resource/Model/CModel.h"
|
||||
|
@ -26,6 +27,13 @@ class CAnimSet : public CResource
|
|||
};
|
||||
std::vector<SNode> mNodes;
|
||||
|
||||
struct SAnimation
|
||||
{
|
||||
TString Name;
|
||||
TResPtr<CAnimation> pAnim;
|
||||
};
|
||||
std::vector<SAnimation> mAnims;
|
||||
|
||||
public:
|
||||
CAnimSet() : CResource() {}
|
||||
|
||||
|
@ -33,6 +41,10 @@ public:
|
|||
TString NodeName(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].Name; }
|
||||
CModel* NodeModel(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pModel; }
|
||||
CSkeleton* NodeSkeleton(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pSkeleton; }
|
||||
|
||||
u32 NumAnims() const { return mAnims.size(); }
|
||||
CAnimation* Animation(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].pAnim; }
|
||||
TString AnimName(u32 Index) { if (Index >= mAnims.size()) Index = 0; return mAnims[Index].Name; }
|
||||
};
|
||||
|
||||
#endif // CCHARACTERSET_H
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
#include "CAnimation.h"
|
||||
#include <Math/CTransform4f.h>
|
||||
#include <Math/MathUtil.h>
|
||||
|
||||
CAnimation::CAnimation()
|
||||
: mDuration(0.f)
|
||||
, mTickInterval(0.0333333f)
|
||||
, mNumKeys(0)
|
||||
{
|
||||
}
|
||||
|
||||
void CAnimation::EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const
|
||||
{
|
||||
if (mDuration == 0.f) return;
|
||||
|
||||
Time = fmodf(Time, mDuration);
|
||||
if (Time >= FLT_EPSILON) Time -= FLT_EPSILON;
|
||||
float t = fmodf(Time, mTickInterval) / mTickInterval;
|
||||
u32 LowKey = (u32) (Time / mTickInterval);
|
||||
|
||||
u8 RotChannel = mBoneInfo[BoneID].RotationChannelIdx;
|
||||
u8 TransChannel = mBoneInfo[BoneID].TranslationChannelIdx;
|
||||
|
||||
if (RotChannel != 0xFF)
|
||||
{
|
||||
const CQuaternion& rkLow = mRotationChannels[RotChannel][LowKey];
|
||||
const CQuaternion& rkHigh = mRotationChannels[RotChannel][LowKey + 1];
|
||||
rOut.Rotate( rkLow.Slerp(rkHigh, t) );
|
||||
}
|
||||
|
||||
if (TransChannel != 0xFF)
|
||||
{
|
||||
const CVector3f& rkLow = mTranslationChannels[TransChannel][LowKey];
|
||||
const CVector3f& rkHigh = mTranslationChannels[TransChannel][LowKey + 1];
|
||||
rOut.Translate( Math::Lerp<CVector3f>(rkLow, rkHigh, t) );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#ifndef CANIMATION_H
|
||||
#define CANIMATION_H
|
||||
|
||||
#include "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<CQuaternion> TRotationChannel;
|
||||
typedef std::vector<CVector3f> TTranslationChannel;
|
||||
|
||||
float mDuration;
|
||||
float mTickInterval;
|
||||
u32 mNumKeys;
|
||||
|
||||
std::vector<TRotationChannel> mRotationChannels;
|
||||
std::vector<TTranslationChannel> mTranslationChannels;
|
||||
|
||||
struct SBoneChannelInfo
|
||||
{
|
||||
u8 RotationChannelIdx;
|
||||
u8 TranslationChannelIdx;
|
||||
};
|
||||
std::vector<SBoneChannelInfo> mBoneInfo;
|
||||
|
||||
public:
|
||||
CAnimation();
|
||||
void EvaluateTransform(float Time, u32 BoneID, CTransform4f& rOut) const;
|
||||
};
|
||||
|
||||
#endif // CANIMATION_H
|
|
@ -1,5 +1,6 @@
|
|||
#include "CResCache.h"
|
||||
#include "Core/Resource/Factory/CAreaLoader.h"
|
||||
#include "Core/Resource/Factory/CAnimationLoader.h"
|
||||
#include "Core/Resource/Factory/CAnimSetLoader.h"
|
||||
#include "Core/Resource/Factory/CCollisionLoader.h"
|
||||
#include "Core/Resource/Factory/CFontLoader.h"
|
||||
|
@ -151,6 +152,7 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC Type)
|
|||
else if (Type == "DCLN") pRes = CCollisionLoader::LoadDCLN(Mem);
|
||||
else if (Type == "EGMC") pRes = CPoiToWorldLoader::LoadEGMC(Mem);
|
||||
else if (Type == "CINF") pRes = CSkeletonLoader::LoadCINF(Mem);
|
||||
else if (Type == "ANIM") pRes = CAnimationLoader::LoadANIM(Mem);
|
||||
else SupportedFormat = false;
|
||||
|
||||
// Log errors
|
||||
|
@ -206,6 +208,7 @@ CResource* CResCache::GetResource(const TString& rkResPath)
|
|||
else if (Type == "DCLN") pRes = CCollisionLoader::LoadDCLN(File);
|
||||
else if (Type == "EGMC") pRes = CPoiToWorldLoader::LoadEGMC(File);
|
||||
else if (Type == "CINF") pRes = CSkeletonLoader::LoadCINF(File);
|
||||
else if (Type == "ANIM") pRes = CAnimationLoader::LoadANIM(File);
|
||||
else SupportedFormat = false;
|
||||
|
||||
if (!pRes) pRes = new CResource(); // Default for unsupported formats
|
||||
|
|
|
@ -8,6 +8,43 @@ CBone::CBone(CSkeleton *pSkel)
|
|||
{
|
||||
}
|
||||
|
||||
void CBone::UpdateTransform(CAnimation *pAnim, float Time, bool AnchorRoot)
|
||||
{
|
||||
mAnimTransform = CTransform4f::skIdentity;
|
||||
|
||||
if (pAnim)
|
||||
pAnim->EvaluateTransform(Time, mID, mAnimTransform);
|
||||
|
||||
mAnimTransform.Translate(mPosition);
|
||||
|
||||
if (mpParent)
|
||||
mAnimTransform = mpParent->AnimTransform() * mAnimTransform;
|
||||
|
||||
if (AnchorRoot && IsRoot())
|
||||
mAnimTransform.ZeroTranslation();
|
||||
|
||||
mAbsPosDirty = true;
|
||||
|
||||
for (u32 iChild = 0; iChild < mChildren.size(); iChild++)
|
||||
mChildren[iChild]->UpdateTransform(pAnim, Time, AnchorRoot);
|
||||
}
|
||||
|
||||
bool CBone::IsRoot() const
|
||||
{
|
||||
return (mpParent == nullptr);
|
||||
}
|
||||
|
||||
CVector3f CBone::AbsolutePosition() const
|
||||
{
|
||||
if (mAbsPosDirty)
|
||||
{
|
||||
mAbsolutePosition = (mAnimTransform * CVector3f::skZero);
|
||||
mAbsPosDirty = false;
|
||||
}
|
||||
|
||||
return mAbsolutePosition;
|
||||
}
|
||||
|
||||
// ************ CSkeleton ************
|
||||
CSkeleton::CSkeleton()
|
||||
: mpRootBone(nullptr)
|
||||
|
@ -31,6 +68,11 @@ CBone* CSkeleton::BoneByID(u32 BoneID) const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void CSkeleton::UpdateTransform(CAnimation *pAnim, float Time, bool AnchorRoot)
|
||||
{
|
||||
mpRootBone->UpdateTransform(pAnim, Time, AnchorRoot);
|
||||
}
|
||||
|
||||
void CSkeleton::Draw(FRenderOptions /*Options*/)
|
||||
{
|
||||
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
|
||||
|
@ -39,8 +81,8 @@ void CSkeleton::Draw(FRenderOptions /*Options*/)
|
|||
|
||||
// Draw bone
|
||||
CTransform4f Transform;
|
||||
Transform.Scale(0.01f);
|
||||
Transform.Translate(pBone->Position());
|
||||
Transform.Scale(0.025f);
|
||||
Transform.Translate(pBone->AbsolutePosition());
|
||||
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
|
||||
CGraphics::UpdateMVPBlock();
|
||||
CDrawUtil::DrawSphere(CColor::skWhite);
|
||||
|
@ -50,6 +92,6 @@ void CSkeleton::Draw(FRenderOptions /*Options*/)
|
|||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
|
||||
CDrawUtil::DrawLine(pBone->Position(), pBone->ChildByIndex(iChild)->Position());
|
||||
CDrawUtil::DrawLine(pBone->AbsolutePosition(), pBone->ChildByIndex(iChild)->AbsolutePosition());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,10 +1,12 @@
|
|||
#ifndef CSKELETON_H
|
||||
#define CSKELETON_H
|
||||
|
||||
#include "CAnimation.h"
|
||||
#include "CResource.h"
|
||||
#include "Core/Render/FRenderOptions.h"
|
||||
#include <Common/TString.h>
|
||||
#include <Common/types.h>
|
||||
#include <Math/CTransform4f.h>
|
||||
#include <Math/CVector3f.h>
|
||||
|
||||
class CSkeleton;
|
||||
|
@ -20,14 +22,24 @@ class CBone
|
|||
CVector3f mPosition;
|
||||
TString mName;
|
||||
|
||||
CTransform4f mAnimTransform;
|
||||
mutable bool mAbsPosDirty;
|
||||
mutable CVector3f mAbsolutePosition;
|
||||
|
||||
public:
|
||||
CBone(CSkeleton *pSkel);
|
||||
void UpdateTransform(CAnimation *pAnim, float Time, bool AnchorRoot);
|
||||
bool IsRoot() const;
|
||||
|
||||
// Accessors
|
||||
inline u32 ID() const { return mID; }
|
||||
inline CVector3f Position() const { return mPosition; }
|
||||
inline CBone* Parent() const { return mpParent; }
|
||||
inline u32 NumChildren() const { return mChildren.size(); }
|
||||
inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; }
|
||||
inline const CTransform4f& AnimTransform() const { return mAnimTransform; }
|
||||
|
||||
CVector3f AbsolutePosition() const;
|
||||
};
|
||||
|
||||
class CSkeleton : public CResource
|
||||
|
@ -41,7 +53,7 @@ class CSkeleton : public CResource
|
|||
public:
|
||||
CSkeleton();
|
||||
~CSkeleton();
|
||||
|
||||
void UpdateTransform(CAnimation *pAnim, float Time, bool AnchorRoot);
|
||||
CBone* BoneByID(u32 BoneID) const;
|
||||
void Draw(FRenderOptions Options);
|
||||
};
|
||||
|
|
|
@ -104,11 +104,15 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
|||
// 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
|
||||
u32 AnimCount = rANCS.ReadLong();
|
||||
bool ReadAnimNames = Loader.pSet->mAnims.empty();
|
||||
if (ReadAnimNames) Loader.pSet->mAnims.resize(AnimCount);
|
||||
|
||||
for (u32 iAnim = 0; iAnim < AnimCount; iAnim++)
|
||||
{
|
||||
rANCS.Seek(0x4, SEEK_CUR);
|
||||
if (Loader.mVersion == ePrime) rANCS.Seek(0x1, SEEK_CUR);
|
||||
rANCS.ReadString();
|
||||
TString AnimName = rANCS.ReadString();
|
||||
if (ReadAnimNames) Loader.pSet->mAnims[iAnim].Name = AnimName;
|
||||
}
|
||||
|
||||
// PAS Database
|
||||
|
@ -165,7 +169,6 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
|
|||
u32 UnknownCount2 = rANCS.ReadLong();
|
||||
rANCS.Seek(UnknownCount2 * 0x1C, SEEK_CUR);
|
||||
}
|
||||
// Lots of work for data I'm not even using x.x
|
||||
}
|
||||
|
||||
return Loader.pSet;
|
||||
|
|
|
@ -0,0 +1,105 @@
|
|||
#include "CAnimationLoader.h"
|
||||
#include <Common/Log.h>
|
||||
|
||||
void CAnimationLoader::ReadUncompressedANIM()
|
||||
{
|
||||
mpAnim->mDuration = mpInput->ReadFloat();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
mpAnim->mTickInterval = mpInput->ReadFloat();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
|
||||
mpAnim->mNumKeys = mpInput->ReadLong();
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skip unknown
|
||||
|
||||
// Read bone channel info
|
||||
u32 NumRotationChannels = 0;
|
||||
u32 NumTranslationChannels = 0;
|
||||
|
||||
u32 NumRotIndices = mpInput->ReadLong();
|
||||
std::vector<u8> RotIndices(NumRotIndices);
|
||||
|
||||
for (u32 iRot = 0; iRot < NumRotIndices; iRot++)
|
||||
{
|
||||
RotIndices[iRot] = mpInput->ReadByte();
|
||||
|
||||
if (RotIndices[iRot] != 0xFF)
|
||||
NumRotationChannels++;
|
||||
}
|
||||
|
||||
u32 NumTransIndices = mpInput->ReadLong();
|
||||
std::vector<u8> TransIndices(NumTransIndices);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < NumTransIndices; iTrans++)
|
||||
{
|
||||
TransIndices[iTrans] = mpInput->ReadByte();
|
||||
|
||||
if (TransIndices[iTrans] != 0xFF)
|
||||
NumTranslationChannels++;
|
||||
}
|
||||
|
||||
// Set up bone channel info
|
||||
mpAnim->mBoneInfo.resize(NumRotIndices);
|
||||
|
||||
for (u32 iRot = 0, iTrans = 0; iRot < NumRotIndices; iRot++)
|
||||
{
|
||||
u8 RotIdx = RotIndices[iRot];
|
||||
mpAnim->mBoneInfo[iRot].RotationChannelIdx = RotIdx;
|
||||
|
||||
if (RotIdx != 0xFF)
|
||||
{
|
||||
mpAnim->mBoneInfo[iRot].TranslationChannelIdx = TransIndices[iTrans];
|
||||
iTrans++;
|
||||
}
|
||||
else
|
||||
mpAnim->mBoneInfo[iRot].TranslationChannelIdx = 0xFF;
|
||||
}
|
||||
|
||||
// Read bone transforms
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping quaternion count
|
||||
mpAnim->mRotationChannels.resize(NumRotationChannels);
|
||||
|
||||
for (u32 iRot = 0; iRot < NumRotationChannels; iRot++)
|
||||
{
|
||||
mpAnim->mRotationChannels[iRot].resize(mpAnim->mNumKeys);
|
||||
|
||||
for (u32 iKey = 0; iKey < mpAnim->mNumKeys; iKey++)
|
||||
mpAnim->mRotationChannels[iRot][iKey] = CQuaternion(*mpInput);
|
||||
}
|
||||
|
||||
mpInput->Seek(0x4, SEEK_CUR); // Skipping vector3f count
|
||||
mpAnim->mTranslationChannels.resize(NumTranslationChannels);
|
||||
|
||||
for (u32 iTrans = 0; iTrans < NumTranslationChannels; iTrans++)
|
||||
{
|
||||
mpAnim->mTranslationChannels[iTrans].resize(mpAnim->mNumKeys);
|
||||
|
||||
for (u32 iKey = 0; iKey < mpAnim->mNumKeys; iKey++)
|
||||
mpAnim->mTranslationChannels[iTrans][iKey] = CVector3f(*mpInput);
|
||||
}
|
||||
|
||||
// Skip EVNT file
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
CAnimation* CAnimationLoader::LoadANIM(IInputStream& rANIM)
|
||||
{
|
||||
u32 CompressionType = rANIM.ReadLong();
|
||||
|
||||
if (CompressionType != 0 && CompressionType != 2)
|
||||
{
|
||||
Log::FileError(rANIM.GetSourceString(), "Unknown ANIM compression type: " + TString::HexString(CompressionType, 2));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (CompressionType == 2)
|
||||
{
|
||||
Log::FileError(rANIM.GetSourceString(), "Compressed ANIMs not supported yet");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CAnimationLoader Loader;
|
||||
Loader.mpAnim = new CAnimation();
|
||||
Loader.mpInput = &rANIM;
|
||||
Loader.ReadUncompressedANIM();
|
||||
return Loader.mpAnim;
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CANIMATIONLOADER_H
|
||||
#define CANIMATIONLOADER_H
|
||||
|
||||
#include "Core/Resource/TResPtr.h"
|
||||
#include "Core/Resource/CAnimation.h"
|
||||
|
||||
class CAnimationLoader
|
||||
{
|
||||
TResPtr<CAnimation> mpAnim;
|
||||
IInputStream *mpInput;
|
||||
|
||||
CAnimationLoader() {}
|
||||
void ReadUncompressedANIM();
|
||||
|
||||
public:
|
||||
static CAnimation* LoadANIM(IInputStream& rANIM);
|
||||
};
|
||||
|
||||
#endif // CANIMATIONLOADER_H
|
|
@ -3,13 +3,19 @@
|
|||
|
||||
#include <vector>
|
||||
|
||||
CSkeletonLoader::CSkeletonLoader()
|
||||
void CSkeletonLoader::SetLocalBoneCoords(CBone *pBone)
|
||||
{
|
||||
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
|
||||
SetLocalBoneCoords(pBone->ChildByIndex(iChild));
|
||||
|
||||
if (pBone->mpParent)
|
||||
pBone->mPosition -= pBone->mpParent->mPosition;
|
||||
}
|
||||
|
||||
// ************ STATIC ************
|
||||
CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
|
||||
{
|
||||
CSkeletonLoader Loader;
|
||||
CSkeleton *pSkel = new CSkeleton();
|
||||
|
||||
u32 NumBones = rCINF.ReadLong();
|
||||
|
@ -71,6 +77,8 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
|
|||
}
|
||||
}
|
||||
|
||||
Loader.SetLocalBoneCoords(pSkel->mpRootBone);
|
||||
|
||||
// Skip bone ID array
|
||||
u32 NumBoneIDs = rCINF.ReadLong();
|
||||
rCINF.Seek(NumBoneIDs * 4, SEEK_CUR);
|
||||
|
|
|
@ -10,7 +10,8 @@ class CSkeletonLoader
|
|||
TResPtr<CSkeleton> mpSkeleton;
|
||||
EGame mVersion;
|
||||
|
||||
CSkeletonLoader();
|
||||
CSkeletonLoader() {}
|
||||
void SetLocalBoneCoords(CBone *pBone);
|
||||
|
||||
public:
|
||||
static CSkeleton* LoadCINF(IInputStream& rCINF);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include "CCharacterNode.h"
|
||||
#include <Core/Render/CRenderer.h>
|
||||
#include "Core/Render/CRenderer.h"
|
||||
#include <Common/CTimer.h>
|
||||
|
||||
CCharacterNode::CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar /*= 0*/, CSceneNode *pParent /*= 0*/)
|
||||
: CSceneNode(pScene, NodeID, pParent)
|
||||
|
@ -34,6 +35,8 @@ void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& /*rkVi
|
|||
void CCharacterNode::Draw(FRenderOptions Options, int /*ComponentIndex*/, const SViewInfo& /*rkViewInfo*/)
|
||||
{
|
||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
||||
CAnimation *pAnim = mpCharacter->Animation(mActiveAnim);
|
||||
pSkel->UpdateTransform(pAnim, (float) CTimer::GlobalTime(), false);
|
||||
pSkel->Draw(Options);
|
||||
}
|
||||
|
||||
|
@ -62,3 +65,8 @@ void CCharacterNode::SetActiveCharSet(u32 CharIndex)
|
|||
MarkTransformChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void CCharacterNode::SetActiveAnim(u32 AnimIndex)
|
||||
{
|
||||
mActiveAnim = AnimIndex;
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ class CCharacterNode : public CSceneNode
|
|||
{
|
||||
TResPtr<CAnimSet> mpCharacter;
|
||||
u32 mActiveCharSet;
|
||||
u32 mActiveAnim;
|
||||
|
||||
public:
|
||||
explicit CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar = 0, CSceneNode *pParent = 0);
|
||||
|
@ -19,9 +20,11 @@ public:
|
|||
virtual SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo);
|
||||
inline CAnimSet* Character() const { return mpCharacter; }
|
||||
inline u32 ActiveCharSet() const { return mActiveCharSet; }
|
||||
inline u32 ActiveAnim() const { return mActiveAnim; }
|
||||
|
||||
void SetCharacter(CAnimSet *pChar);
|
||||
void SetActiveCharSet(u32 CharIndex);
|
||||
void SetActiveAnim(u32 AnimIndex);
|
||||
};
|
||||
|
||||
#endif // CCHARACTERNODE_H
|
||||
|
|
|
@ -19,15 +19,21 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
|
|||
rCamera.SetMoveSpeed(0.5f);
|
||||
|
||||
// Init UI
|
||||
ui->ToolBar->addSeparator();
|
||||
|
||||
mpCharComboBox = new QComboBox(this);
|
||||
mpCharComboBox->setMinimumWidth(175);
|
||||
ui->ToolBar->addSeparator();
|
||||
ui->ToolBar->addWidget(mpCharComboBox);
|
||||
|
||||
mpAnimComboBox = new QComboBox(this);
|
||||
mpAnimComboBox->setMinimumWidth(175);
|
||||
ui->ToolBar->addWidget(mpAnimComboBox);
|
||||
|
||||
connect(&mRefreshTimer, SIGNAL(timeout()), this, SLOT(RefreshViewport()));
|
||||
mRefreshTimer.start(0);
|
||||
|
||||
connect(mpCharComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveCharacterIndex(int)));
|
||||
connect(mpAnimComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveAnimation(int)));
|
||||
connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open()));
|
||||
}
|
||||
|
||||
|
@ -58,6 +64,16 @@ void CCharacterEditor::Open()
|
|||
|
||||
SetActiveCharacterIndex(0);
|
||||
mpCharComboBox->blockSignals(false);
|
||||
|
||||
// Set up anim combo box
|
||||
mpAnimComboBox->blockSignals(true);
|
||||
mpAnimComboBox->clear();
|
||||
|
||||
for (u32 iAnim = 0; iAnim < pSet->NumAnims(); iAnim++)
|
||||
mpAnimComboBox->addItem( TO_QSTRING(pSet->AnimName(iAnim)) );
|
||||
|
||||
SetActiveAnimation(0);
|
||||
mpAnimComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
gResCache.Clean();
|
||||
|
@ -73,3 +89,8 @@ void CCharacterEditor::SetActiveCharacterIndex(int CharIndex)
|
|||
{
|
||||
mpCharNode->SetActiveCharSet((u32) CharIndex);
|
||||
}
|
||||
|
||||
void CCharacterEditor::SetActiveAnimation(int AnimIndex)
|
||||
{
|
||||
mpCharNode->SetActiveAnim((u32) AnimIndex);
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class CCharacterEditor : public QMainWindow
|
|||
CCharacterNode *mpCharNode;
|
||||
|
||||
QComboBox *mpCharComboBox;
|
||||
QComboBox *mpAnimComboBox;
|
||||
QTimer mRefreshTimer;
|
||||
|
||||
public:
|
||||
|
@ -32,6 +33,7 @@ public slots:
|
|||
void Open();
|
||||
void RefreshViewport();
|
||||
void SetActiveCharacterIndex(int CharIndex);
|
||||
void SetActiveAnimation(int AnimIndex);
|
||||
};
|
||||
|
||||
#endif // CCHARACTEREDITORWINDOW_H
|
||||
|
|
|
@ -41,7 +41,8 @@ HEADERS += \
|
|||
FileIO.h \
|
||||
IOUtil.h \
|
||||
IInputStream.h \
|
||||
IOutputStream.h
|
||||
IOutputStream.h \
|
||||
CBitStreamInWrapper.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
@ -54,4 +55,5 @@ SOURCES += \
|
|||
CVectorOutStream.cpp \
|
||||
IOUtil.cpp \
|
||||
IInputStream.cpp \
|
||||
IOutputStream.cpp
|
||||
IOutputStream.cpp \
|
||||
CBitStreamInWrapper.cpp
|
||||
|
|
|
@ -20,6 +20,14 @@ CQuaternion::CQuaternion(float _W, float _X, float _Y, float _Z)
|
|||
{
|
||||
}
|
||||
|
||||
CQuaternion::CQuaternion(IInputStream& rInput)
|
||||
: W(rInput.ReadFloat())
|
||||
, X(rInput.ReadFloat())
|
||||
, Y(rInput.ReadFloat())
|
||||
, Z(rInput.ReadFloat())
|
||||
{
|
||||
}
|
||||
|
||||
CVector3f CQuaternion::XAxis() const
|
||||
{
|
||||
return (*this * CVector3f::skUnitX);
|
||||
|
@ -48,6 +56,36 @@ CQuaternion CQuaternion::Inverse() const
|
|||
return CQuaternion::skZero;
|
||||
}
|
||||
|
||||
CQuaternion CQuaternion::Slerp(const CQuaternion& rkRight, float t) const
|
||||
{
|
||||
// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/
|
||||
float CosHalfTheta = (W * rkRight.W) + (X * rkRight.X) + (Y * rkRight.Y) + (Z * rkRight.Z);
|
||||
|
||||
if (Math::Abs(CosHalfTheta) >= 1.f)
|
||||
return *this;
|
||||
|
||||
float ScalarA, ScalarB;
|
||||
float SinHalfTheta = Math::Sqrt(1.f - (CosHalfTheta * CosHalfTheta));
|
||||
|
||||
if (Math::Abs(SinHalfTheta) < 0.001f)
|
||||
{
|
||||
ScalarA = 0.5f;
|
||||
ScalarB = 0.5f;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
float HalfTheta = acosf(CosHalfTheta);
|
||||
ScalarA = sinf((1.f - t) * HalfTheta) / SinHalfTheta;
|
||||
ScalarB = sinf(t * HalfTheta) / SinHalfTheta;
|
||||
}
|
||||
|
||||
return CQuaternion( (W * ScalarA) + (rkRight.W * ScalarB),
|
||||
(X * ScalarA) + (rkRight.X * ScalarB),
|
||||
(Y * ScalarA) + (rkRight.Y * ScalarB),
|
||||
(Z * ScalarA) + (rkRight.Z * ScalarB) );
|
||||
}
|
||||
|
||||
CVector3f CQuaternion::ToEuler() const
|
||||
{
|
||||
// There is more than one way to do this conversion, based on rotation order.
|
||||
|
|
|
@ -10,11 +10,13 @@ public:
|
|||
|
||||
CQuaternion();
|
||||
CQuaternion(float _W, float _X, float _Y, float _Z);
|
||||
CQuaternion(IInputStream& rInput);
|
||||
|
||||
CVector3f XAxis() const;
|
||||
CVector3f YAxis() const;
|
||||
CVector3f ZAxis() const;
|
||||
CQuaternion Inverse() const;
|
||||
CQuaternion Slerp(const CQuaternion& rkRight, float t) const;
|
||||
CVector3f ToEuler() const;
|
||||
|
||||
// Operators
|
||||
|
|
|
@ -100,6 +100,13 @@ void CTransform4f::Scale(float XScale, float YScale, float ZScale)
|
|||
Scale(CVector3f(XScale, YScale, ZScale));
|
||||
}
|
||||
|
||||
void CTransform4f::ZeroTranslation()
|
||||
{
|
||||
m[0][3] = 0.f;
|
||||
m[1][3] = 0.f;
|
||||
m[2][3] = 0.f;
|
||||
}
|
||||
|
||||
CTransform4f CTransform4f::MultiplyIgnoreTranslation(const CTransform4f& rkMtx) const
|
||||
{
|
||||
CTransform4f Out;
|
||||
|
@ -153,6 +160,13 @@ CTransform4f CTransform4f::NoTranslation() const
|
|||
m[2][0], m[2][1], m[2][2], 0.f);
|
||||
}
|
||||
|
||||
CTransform4f CTransform4f::TranslationOnly() const
|
||||
{
|
||||
return CTransform4f(1.f, 0.f, 0.f, m[0][3],
|
||||
0.f, 1.f, 0.f, m[1][3],
|
||||
0.f, 0.f, 1.f, m[2][3]);
|
||||
}
|
||||
|
||||
CTransform4f CTransform4f::RotationOnly() const
|
||||
{
|
||||
return CTransform4f::FromMatrix4f(Inverse().ToMatrix4f().Transpose());
|
||||
|
|
|
@ -37,10 +37,12 @@ public:
|
|||
void Rotate(float XRot, float YRot, float ZRot);
|
||||
void Scale(CVector3f Scale);
|
||||
void Scale(float XScale, float YScale, float ZScale);
|
||||
void ZeroTranslation();
|
||||
CTransform4f MultiplyIgnoreTranslation(const CTransform4f& rkMtx) const;
|
||||
CTransform4f Inverse() const;
|
||||
CTransform4f QuickInverse() const;
|
||||
CTransform4f NoTranslation() const;
|
||||
CTransform4f TranslationOnly() const;
|
||||
CTransform4f RotationOnly() const;
|
||||
|
||||
// Conversion
|
||||
|
|
|
@ -22,6 +22,13 @@ float DegreesToRadians(float Deg);
|
|||
|
||||
float RadiansToDegrees(float Rad);
|
||||
|
||||
template<typename Type>
|
||||
Type Lerp(const Type& rkA, const Type& rkB, float t)
|
||||
{
|
||||
Type Diff = rkB - rkA;
|
||||
return rkA + (Diff * t);
|
||||
}
|
||||
|
||||
std::pair<bool,float> RayPlaneIntersecton(const CRay& rkRay, const CPlane& rkPlane);
|
||||
|
||||
std::pair<bool,float> RayBoxIntersection(const CRay& rkRay, const CAABox& rkBox);
|
||||
|
|
Loading…
Reference in New Issue