Added support for loading and rendering skeletons, added character editor

This commit is contained in:
parax0
2016-04-05 17:26:16 -06:00
parent f9a2d019e1
commit 2376a36f0b
21 changed files with 626 additions and 18 deletions

View File

@@ -3,6 +3,7 @@
#include "TResPtr.h"
#include "CResource.h"
#include "CSkeleton.h"
#include "Core/Resource/Model/CModel.h"
#include <Common/types.h>
@@ -19,7 +20,7 @@ class CAnimSet : public CResource
TString Name;
TResPtr<CModel> pModel;
u32 SkinID;
u32 SkelID;
TResPtr<CSkeleton> pSkeleton;
SNode() { pModel = nullptr; }
};
@@ -28,9 +29,10 @@ class CAnimSet : public CResource
public:
CAnimSet() : CResource() {}
u32 NumNodes() const { return mNodes.size(); }
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; }
u32 NumNodes() const { return mNodes.size(); }
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; }
};
#endif // CCHARACTERSET_H

View File

@@ -6,6 +6,7 @@
#include "Core/Resource/Factory/CModelLoader.h"
#include "Core/Resource/Factory/CPoiToWorldLoader.h"
#include "Core/Resource/Factory/CScanLoader.h"
#include "Core/Resource/Factory/CSkeletonLoader.h"
#include "Core/Resource/Factory/CStringLoader.h"
#include "Core/Resource/Factory/CTextureDecoder.h"
#include "Core/Resource/Factory/CWorldLoader.h"
@@ -149,6 +150,7 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC Type)
else if (Type == "SCAN") pRes = CScanLoader::LoadSCAN(Mem);
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 SupportedFormat = false;
// Log errors
@@ -203,6 +205,7 @@ CResource* CResCache::GetResource(const TString& rkResPath)
else if (Type == "SCAN") pRes = CScanLoader::LoadSCAN(File);
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 SupportedFormat = false;
if (!pRes) pRes = new CResource(); // Default for unsupported formats

View File

@@ -0,0 +1,55 @@
#include "CSkeleton.h"
#include "Core/Render/CDrawUtil.h"
#include "Core/Render/CGraphics.h"
// ************ CBone ************
CBone::CBone(CSkeleton *pSkel)
: mpSkeleton(pSkel)
{
}
// ************ CSkeleton ************
CSkeleton::CSkeleton()
: 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;
}
void CSkeleton::Draw(FRenderOptions /*Options*/)
{
for (u32 iBone = 0; iBone < mBones.size(); iBone++)
{
CBone *pBone = mBones[iBone];
// Draw bone
CTransform4f Transform;
Transform.Scale(0.01f);
Transform.Translate(pBone->Position());
CGraphics::sMVPBlock.ModelMatrix = Transform.ToMatrix4f();
CGraphics::UpdateMVPBlock();
CDrawUtil::DrawSphere(CColor::skWhite);
// Draw child links
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
CGraphics::UpdateMVPBlock();
for (u32 iChild = 0; iChild < pBone->NumChildren(); iChild++)
CDrawUtil::DrawLine(pBone->Position(), pBone->ChildByIndex(iChild)->Position());
}
}

View File

@@ -0,0 +1,49 @@
#ifndef CSKELETON_H
#define CSKELETON_H
#include "CResource.h"
#include "Core/Render/FRenderOptions.h"
#include <Common/TString.h>
#include <Common/types.h>
#include <Math/CVector3f.h>
class CSkeleton;
class CBone
{
friend class CSkeletonLoader;
CSkeleton *mpSkeleton;
CBone *mpParent;
std::vector<CBone*> mChildren;
u32 mID;
CVector3f mPosition;
TString mName;
public:
CBone(CSkeleton *pSkel);
// Accessors
inline u32 ID() const { return mID; }
inline CVector3f Position() const { return mPosition; }
inline u32 NumChildren() const { return mChildren.size(); }
inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; }
};
class CSkeleton : public CResource
{
DECLARE_RESOURCE_TYPE(eSkeleton)
friend class CSkeletonLoader;
CBone *mpRootBone;
std::vector<CBone*> mBones;
public:
CSkeleton();
~CSkeleton();
CBone* BoneByID(u32 BoneID) const;
void Draw(FRenderOptions Options);
};
#endif // CSKELETON_H

View File

@@ -99,7 +99,7 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
pNode->Name = rANCS.ReadString();
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL");
pNode->SkinID = rANCS.ReadLong();
pNode->SkelID = rANCS.ReadLong();
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
// 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

View File

@@ -3,7 +3,6 @@
#include "Core/Resource/CAnimSet.h"
#include "Core/Resource/EGame.h"
#include "Core/Resource/CResCache.h"
class CAnimSetLoader
{

View File

@@ -0,0 +1,90 @@
#include "CSkeletonLoader.h"
#include <Common/Log.h>
#include <vector>
CSkeletonLoader::CSkeletonLoader()
{
}
// ************ STATIC ************
CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
{
CSkeleton *pSkel = new CSkeleton();
u32 NumBones = rCINF.ReadLong();
pSkel->mBones.reserve(NumBones);
// Read bones
struct SBoneInfo
{
u32 ParentID;
std::vector<u32> ChildIDs;
};
std::vector<SBoneInfo> BoneInfo(NumBones);
for (u32 iBone = 0; iBone < NumBones; iBone++)
{
CBone *pBone = new CBone(pSkel);
pSkel->mBones.push_back(pBone);
pBone->mID = rCINF.ReadLong();
BoneInfo[iBone].ParentID = rCINF.ReadLong();
pBone->mPosition = CVector3f(rCINF);
u32 NumLinkedBones = rCINF.ReadLong();
for (u32 iLink = 0; iLink < NumLinkedBones; iLink++)
{
u32 LinkedID = rCINF.ReadLong();
if (LinkedID != BoneInfo[iBone].ParentID)
BoneInfo[iBone].ChildIDs.push_back(LinkedID);
}
}
// Fill in bone info
for (u32 iBone = 0; iBone < NumBones; iBone++)
{
CBone *pBone = pSkel->mBones[iBone];
SBoneInfo& rInfo = BoneInfo[iBone];
pBone->mpParent = pSkel->BoneByID(rInfo.ParentID);
for (u32 iChild = 0; iChild < rInfo.ChildIDs.size(); iChild++)
{
u32 ChildID = rInfo.ChildIDs[iChild];
CBone *pChild = pSkel->BoneByID(ChildID);
if (pChild)
pBone->mChildren.push_back(pChild);
else
Log::FileError(rCINF.GetSourceString(), "Bone " + TString::FromInt32(pBone->mID, 0, 10) + " has invalid child ID: " + TString::FromInt32(ChildID, 0, 10));
}
if (!pBone->mpParent)
{
if (!pSkel->mpRootBone)
pSkel->mpRootBone = pBone;
else
Log::FileError(rCINF.GetSourceString(), "Multiple root bones?");
}
}
// Skip bone ID array
u32 NumBoneIDs = rCINF.ReadLong();
rCINF.Seek(NumBoneIDs * 4, SEEK_CUR);
// Read bone names
u32 NumBoneNames = rCINF.ReadLong();
for (u32 iName = 0; iName < NumBoneNames; iName++)
{
TString Name = rCINF.ReadString();
u32 BoneID = rCINF.ReadLong();
pSkel->BoneByID(BoneID)->mName = Name;
}
return pSkel;
}

View File

@@ -0,0 +1,19 @@
#ifndef CSKELETONLOADER_H
#define CSKELETONLOADER_H
#include "Core/Resource/CSkeleton.h"
#include "Core/Resource/EGame.h"
#include "Core/Resource/TResPtr.h"
class CSkeletonLoader
{
TResPtr<CSkeleton> mpSkeleton;
EGame mVersion;
CSkeletonLoader();
public:
static CSkeleton* LoadCINF(IInputStream& rCINF);
};
#endif // CSKELETONLOADER_H