mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-21 10:49:23 +00:00
Added support for loading and rendering skeletons, added character editor
This commit is contained in:
@@ -185,7 +185,10 @@ HEADERS += \
|
||||
Resource/Factory/CSectionMgrIn.h \
|
||||
Resource/Cooker/CScriptCooker.h \
|
||||
ScriptExtra/CSplinePathExtra.h \
|
||||
Resource/Script/CLink.h
|
||||
Resource/Script/CLink.h \
|
||||
Resource/CSkeleton.h \
|
||||
Resource/Factory/CSkeletonLoader.h \
|
||||
Scene/CCharacterNode.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
@@ -263,4 +266,7 @@ SOURCES += \
|
||||
Resource/Factory/CPoiToWorldLoader.cpp \
|
||||
Resource/Cooker/CPoiToWorldCooker.cpp \
|
||||
Resource/Cooker/CScriptCooker.cpp \
|
||||
ScriptExtra/CSplinePathExtra.cpp
|
||||
ScriptExtra/CSplinePathExtra.cpp \
|
||||
Resource/CSkeleton.cpp \
|
||||
Resource/Factory/CSkeletonLoader.cpp \
|
||||
Scene/CCharacterNode.cpp
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
55
src/Core/Resource/CSkeleton.cpp
Normal file
55
src/Core/Resource/CSkeleton.cpp
Normal 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());
|
||||
}
|
||||
}
|
||||
49
src/Core/Resource/CSkeleton.h
Normal file
49
src/Core/Resource/CSkeleton.h
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
#include "Core/Resource/CAnimSet.h"
|
||||
#include "Core/Resource/EGame.h"
|
||||
#include "Core/Resource/CResCache.h"
|
||||
|
||||
class CAnimSetLoader
|
||||
{
|
||||
|
||||
90
src/Core/Resource/Factory/CSkeletonLoader.cpp
Normal file
90
src/Core/Resource/Factory/CSkeletonLoader.cpp
Normal 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;
|
||||
}
|
||||
19
src/Core/Resource/Factory/CSkeletonLoader.h
Normal file
19
src/Core/Resource/Factory/CSkeletonLoader.h
Normal 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
|
||||
64
src/Core/Scene/CCharacterNode.cpp
Normal file
64
src/Core/Scene/CCharacterNode.cpp
Normal file
@@ -0,0 +1,64 @@
|
||||
#include "CCharacterNode.h"
|
||||
#include <Core/Render/CRenderer.h>
|
||||
|
||||
CCharacterNode::CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar /*= 0*/, CSceneNode *pParent /*= 0*/)
|
||||
: CSceneNode(pScene, NodeID, pParent)
|
||||
{
|
||||
SetCharacter(pChar);
|
||||
}
|
||||
|
||||
ENodeType CCharacterNode::NodeType()
|
||||
{
|
||||
return eCharacterNode;
|
||||
}
|
||||
|
||||
void CCharacterNode::PostLoad()
|
||||
{
|
||||
if (mpCharacter)
|
||||
{
|
||||
for (u32 iChar = 0; iChar < mpCharacter->NumNodes(); iChar++)
|
||||
mpCharacter->NodeModel(iChar)->BufferGL();
|
||||
}
|
||||
}
|
||||
|
||||
void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& /*rkViewInfo*/)
|
||||
{
|
||||
if (!mpCharacter) return;
|
||||
|
||||
if (mpCharacter->NodeSkeleton(mActiveCharSet))
|
||||
{
|
||||
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh);
|
||||
}
|
||||
}
|
||||
|
||||
void CCharacterNode::Draw(FRenderOptions Options, int /*ComponentIndex*/, const SViewInfo& /*rkViewInfo*/)
|
||||
{
|
||||
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
|
||||
pSkel->Draw(Options);
|
||||
}
|
||||
|
||||
SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& /*rkRay*/, u32 /*AssetID*/, const SViewInfo& /*rkViewInfo*/)
|
||||
{
|
||||
// Not currently doing any ray checks on character nodes so don't care about this right now.
|
||||
return SRayIntersection();
|
||||
}
|
||||
|
||||
void CCharacterNode::SetCharacter(CAnimSet *pChar)
|
||||
{
|
||||
mpCharacter = pChar;
|
||||
SetActiveCharSet(0);
|
||||
|
||||
if (!mpCharacter)
|
||||
mLocalAABox = CAABox::skOne;
|
||||
}
|
||||
|
||||
void CCharacterNode::SetActiveCharSet(u32 CharIndex)
|
||||
{
|
||||
mActiveCharSet = CharIndex;
|
||||
|
||||
if (mpCharacter)
|
||||
{
|
||||
mLocalAABox = mpCharacter->NodeModel(CharIndex)->AABox();
|
||||
MarkTransformChanged();
|
||||
}
|
||||
}
|
||||
27
src/Core/Scene/CCharacterNode.h
Normal file
27
src/Core/Scene/CCharacterNode.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#ifndef CCHARACTERNODE_H
|
||||
#define CCHARACTERNODE_H
|
||||
|
||||
#include "CSceneNode.h"
|
||||
#include "Core/Resource/CAnimSet.h"
|
||||
|
||||
class CCharacterNode : public CSceneNode
|
||||
{
|
||||
TResPtr<CAnimSet> mpCharacter;
|
||||
u32 mActiveCharSet;
|
||||
|
||||
public:
|
||||
explicit CCharacterNode(CScene *pScene, u32 NodeID, CAnimSet *pChar = 0, CSceneNode *pParent = 0);
|
||||
|
||||
virtual ENodeType NodeType();
|
||||
virtual void PostLoad();
|
||||
virtual void AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo);
|
||||
virtual void Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo);
|
||||
virtual SRayIntersection RayNodeIntersectTest(const CRay& rkRay, u32 AssetID, const SViewInfo& rkViewInfo);
|
||||
inline CAnimSet* Character() const { return mpCharacter; }
|
||||
inline u32 ActiveCharSet() const { return mActiveCharSet; }
|
||||
|
||||
void SetCharacter(CAnimSet *pChar);
|
||||
void SetActiveCharSet(u32 CharIndex);
|
||||
};
|
||||
|
||||
#endif // CCHARACTERNODE_H
|
||||
@@ -7,12 +7,13 @@ enum ENodeType
|
||||
{
|
||||
eRootNode = 0x0,
|
||||
eModelNode = 0x1,
|
||||
eStaticNode = 0x2,
|
||||
eCollisionNode = 0x4,
|
||||
eScriptNode = 0x8,
|
||||
eScriptExtraNode = 0x10,
|
||||
eLightNode = 0x20,
|
||||
eAllNodeTypes = 0x3F
|
||||
eCharacterNode = 0x2,
|
||||
eStaticNode = 0x4,
|
||||
eCollisionNode = 0x8,
|
||||
eScriptNode = 0x10,
|
||||
eScriptExtraNode = 0x20,
|
||||
eLightNode = 0x40,
|
||||
eAllNodeTypes = 0x7F
|
||||
};
|
||||
|
||||
DECLARE_FLAGS(ENodeType, FNodeFlags)
|
||||
|
||||
Reference in New Issue
Block a user