Added support for model skinning

This commit is contained in:
parax0
2016-04-27 04:27:57 -06:00
parent c5ff634cd1
commit 98059cedaa
81 changed files with 802 additions and 245 deletions

View File

@@ -5,6 +5,7 @@
#include "CAnimation.h"
#include "CResource.h"
#include "CSkeleton.h"
#include "CSkin.h"
#include "Core/Resource/Model/CModel.h"
#include <Common/types.h>
@@ -20,7 +21,7 @@ class CAnimSet : public CResource
{
TString Name;
TResPtr<CModel> pModel;
u32 SkinID;
TResPtr<CSkin> pSkin;
TResPtr<CSkeleton> pSkeleton;
SNode() { pModel = nullptr; }
@@ -40,6 +41,7 @@ public:
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; }
CSkin* NodeSkin(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pSkin; }
CSkeleton* NodeSkeleton(u32 Index) { if (Index >= mNodes.size()) Index = 0; return mNodes[Index].pSkeleton; }
u32 NumAnims() const { return mAnims.size(); }

View File

@@ -37,7 +37,8 @@ public:
eLightmap = 0x800,
eShortTexCoord = 0x2000,
eAllMP1Settings = 0x2FF8,
eDrawWhiteAmbientDKCR = 0x80000
eDrawWhiteAmbientDKCR = 0x80000,
eSkinningEnabled = 0x80000000
};
DECLARE_FLAGS(EMaterialOption, FMaterialOptions)
@@ -100,12 +101,12 @@ public:
inline CMaterialPass* Pass(u32 PassIndex) const { return mPasses[PassIndex]; }
inline void SetName(const TString& rkName) { mName = rkName; }
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; mRecalcHash = true; }
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; mRecalcHash = true; }
inline void SetOptions(FMaterialOptions Options) { mOptions = Options; Update(); }
inline void SetVertexDescription(FVertexDescription Desc) { mVtxDesc = Desc; Update(); }
inline void SetBlendMode(GLenum SrcFac, GLenum DstFac) { mBlendSrcFac = SrcFac; mBlendDstFac = DstFac; mRecalcHash = true; }
inline void SetKonst(CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; mRecalcHash = true; }
inline void SetKonst(CColor& Konst, u32 KIndex) { mKonstColors[KIndex] = Konst; Update(); }
inline void SetIndTexture(CTexture *pTex) { mpIndirectTexture = pTex; }
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; mRecalcHash = true; }
inline void SetLightingEnabled(bool Enabled) { mLightingEnabled = Enabled; Update(); }
// Static
inline static void KillCachedMaterial() { sCurrentMaterial = 0; }

View File

@@ -8,6 +8,7 @@
#include "Core/Resource/Factory/CPoiToWorldLoader.h"
#include "Core/Resource/Factory/CScanLoader.h"
#include "Core/Resource/Factory/CSkeletonLoader.h"
#include "Core/Resource/Factory/CSkinLoader.h"
#include "Core/Resource/Factory/CStringLoader.h"
#include "Core/Resource/Factory/CTextureDecoder.h"
#include "Core/Resource/Factory/CWorldLoader.h"
@@ -153,6 +154,7 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC Type)
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 if (Type == "CSKR") pRes = CSkinLoader::LoadCSKR(Mem);
else SupportedFormat = false;
// Log errors
@@ -209,6 +211,7 @@ CResource* CResCache::GetResource(const TString& rkResPath)
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 if (Type == "CSKR") pRes = CSkinLoader::LoadCSKR(File);
else SupportedFormat = false;
if (!pRes) pRes = new CResource(); // Default for unsupported formats

View File

@@ -10,7 +10,34 @@
#include <Math/CVector3f.h>
class CBoneTransformData;
class CSkeleton;
class CBone;
class CSkeleton : public CResource
{
DECLARE_RESOURCE_TYPE(eSkeleton)
friend class CSkeletonLoader;
CBone *mpRootBone;
std::vector<CBone*> mBones;
std::vector<CTransform4f> mInvBindMatrices;
static const float skSphereRadius;
public:
CSkeleton();
~CSkeleton();
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
CBone* BoneByID(u32 BoneID) const;
u32 MaxBoneID() const;
void Draw(FRenderOptions Options, const CBoneTransformData& rkData);
std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
inline u32 NumBones() const { return mBones.size(); }
inline const CTransform4f& BoneInverseBindMatrix(u32 BoneID) const { return mInvBindMatrices[BoneID]; }
inline const void* InverseBindMatricesData() const { return mInvBindMatrices.data(); }
inline u32 InverseBindMatricesSize() const { return mInvBindMatrices.size() * sizeof(CTransform4f); }
};
class CBone
{
@@ -29,36 +56,15 @@ public:
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 TString Name() const { return mName; }
};
class CSkeleton : public CResource
{
DECLARE_RESOURCE_TYPE(eSkeleton)
friend class CSkeletonLoader;
CBone *mpRootBone;
std::vector<CBone*> mBones;
static const float skSphereRadius;
public:
CSkeleton();
~CSkeleton();
void UpdateTransform(CBoneTransformData& rData, CAnimation *pAnim, float Time, bool AnchorRoot);
CBone* BoneByID(u32 BoneID) const;
u32 MaxBoneID() const;
void Draw(FRenderOptions Options, const CBoneTransformData& rkData);
std::pair<s32,float> RayIntersect(const CRay& rkRay, const CBoneTransformData& rkData);
inline u32 NumBones() const { return mBones.size(); }
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 AbsolutePosition() const { return mPosition + (mpParent ? mpParent->AbsolutePosition() : CVector3f::skZero); }
inline TString Name() const { return mName; }
inline const CTransform4f& InverseBindMtx() const { return mpSkeleton->BoneInverseBindMatrix(mID); }
};
#endif // CSKELETON_H

51
src/Core/Resource/CSkin.h Normal file
View File

@@ -0,0 +1,51 @@
#ifndef CSKIN_H
#define CSKIN_H
#include "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;
u32 mSkinnedVertexCount;
public:
CSkin() {}
const SVertexWeights& WeightsForVertex(u32 VertIdx)
{
static const SVertexWeights skNullWeights = {
{ 0, 0, 0, 0 },
{ 0.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

@@ -6,6 +6,32 @@ CMaterialCooker::CMaterialCooker()
{
}
u32 CMaterialCooker::ConvertFromVertexDescription(FVertexDescription VtxDesc)
{
u32 Flags = 0;
if (VtxDesc & ePosition) Flags |= 0x00000003;
if (VtxDesc & eNormal) Flags |= 0x0000000C;
if (VtxDesc & eColor0) Flags |= 0x00000030;
if (VtxDesc & eColor1) Flags |= 0x000000C0;
if (VtxDesc & eTex0) Flags |= 0x00000300;
if (VtxDesc & eTex1) Flags |= 0x00000C00;
if (VtxDesc & eTex2) Flags |= 0x00003000;
if (VtxDesc & eTex3) Flags |= 0x0000C000;
if (VtxDesc & eTex4) Flags |= 0x00030000;
if (VtxDesc & eTex5) Flags |= 0x000C0000;
if (VtxDesc & eTex6) Flags |= 0x00300000;
if (VtxDesc & eTex7) Flags |= 0x00C00000;
if (VtxDesc & ePosMtx) Flags |= 0x01000000;
if (VtxDesc & eTex0Mtx) Flags |= 0x02000000;
if (VtxDesc & eTex1Mtx) Flags |= 0x04000000;
if (VtxDesc & eTex2Mtx) Flags |= 0x08000000;
if (VtxDesc & eTex3Mtx) Flags |= 0x10000000;
if (VtxDesc & eTex4Mtx) Flags |= 0x20000000;
if (VtxDesc & eTex5Mtx) Flags |= 0x40000000;
if (VtxDesc & eTex6Mtx) Flags |= 0x80000000;
return Flags;
}
void CMaterialCooker::WriteMatSetPrime(IOutputStream& rOut)
{
// Gather texture list from the materials before starting
@@ -150,12 +176,12 @@ void CMaterialCooker::WriteMaterialPrime(IOutputStream& rOut)
rOut.WriteLong(TexIndices[iTex]);
// Vertex description
FVertexDescription Desc = mpMat->VtxDesc();
u32 VtxFlags = ConvertFromVertexDescription( mpMat->VtxDesc() );
if (mVersion < eEchoes)
Desc &= 0x00FFFFFF;
VtxFlags &= 0x00FFFFFF;
rOut.WriteLong(Desc);
rOut.WriteLong(VtxFlags);
// Echoes unknowns
if (mVersion == eEchoes)

View File

@@ -14,6 +14,7 @@ class CMaterialCooker
std::vector<u64> mMaterialHashes;
CMaterialCooker();
u32 ConvertFromVertexDescription(FVertexDescription VtxDesc);
void WriteMatSetPrime(IOutputStream& rOut);
void WriteMatSetCorruption(IOutputStream& rOut);
void WriteMaterialPrime(IOutputStream& rOut);

View File

@@ -63,7 +63,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
// Header
rOut.WriteLong(0xDEADBABE);
rOut.WriteLong(GetCMDLVersion(mVersion));
rOut.WriteLong(5);
rOut.WriteLong(mpModel->IsSkinned() ? 6 : 5);
mpModel->mAABox.Write(rOut);
u32 NumSections = mNumMatSets + mNumSurfaces + 6;
@@ -115,7 +115,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
// Float UV coordinates
for (u32 iTexSlot = 0; iTexSlot < 8; iTexSlot++)
{
bool HasTexSlot = (mVtxAttribs & (eTex0 << (iTexSlot * 2))) != 0;
bool HasTexSlot = (mVtxAttribs & (eTex0 << iTexSlot)) != 0;
if (HasTexSlot)
{
for (u32 iTex = 0; iTex < mNumVertices; iTex++)
@@ -156,7 +156,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
rOut.WriteToBoundary(32, 0);
u32 PrimTableStart = rOut.Tell();
FVertexDescription MatAttribs = mpModel->GetMaterialBySurface(0, iSurf)->VtxDesc();
FVertexDescription VtxAttribs = mpModel->GetMaterialBySurface(0, iSurf)->VtxDesc();
for (u32 iPrim = 0; iPrim < pSurface->Primitives.size(); iPrim++)
{
@@ -171,28 +171,28 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
if (mVersion == eEchoes)
{
for (u32 iMtxAttribs = 0; iMtxAttribs < 8; iMtxAttribs++)
if (MatAttribs & (ePosMtx << iMtxAttribs))
if (VtxAttribs & (ePosMtx << iMtxAttribs))
rOut.WriteByte(pVert->MatrixIndices[iMtxAttribs]);
}
u16 VertexIndex = (u16) pVert->ArrayPosition;
if (MatAttribs & ePosition)
if (VtxAttribs & ePosition)
rOut.WriteShort(VertexIndex);
if (MatAttribs & eNormal)
if (VtxAttribs & eNormal)
rOut.WriteShort(VertexIndex);
if (MatAttribs & eColor0)
if (VtxAttribs & eColor0)
rOut.WriteShort(VertexIndex);
if (MatAttribs & eColor1)
if (VtxAttribs & eColor1)
rOut.WriteShort(VertexIndex);
u16 TexOffset = 0;
for (u32 iTex = 0; iTex < 8; iTex++)
{
if (MatAttribs & (eTex0 << (iTex * 2)))
if (VtxAttribs & (eTex0 << iTex))
{
rOut.WriteShort(VertexIndex + TexOffset);
TexOffset += (u16) mNumVertices;

View File

@@ -220,12 +220,16 @@ CAnimSet* CAnimSetLoader::LoadANCS(IInputStream& rANCS)
if (iNode == 0) Loader.mVersion = (Unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately
pNode->Name = rANCS.ReadString();
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL");
pNode->SkinID = rANCS.ReadLong();
if (Loader.mVersion == ePrime)
if (Loader.mVersion <= ePrime)
{
pNode->pSkin = gResCache.GetResource(rANCS.ReadLong(), "CSKR");
pNode->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
pNode->pModel->SetSkin(pNode->pSkin);
}
else
rANCS.Seek(0x4, SEEK_CUR);
rANCS.Seek(0x8, SEEK_CUR);
// 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

@@ -15,6 +15,32 @@ CMaterialLoader::~CMaterialLoader()
{
}
FVertexDescription CMaterialLoader::ConvertToVertexDescription(u32 VertexFlags)
{
FVertexDescription Desc;
if (VertexFlags & 0x00000003) Desc |= ePosition;
if (VertexFlags & 0x0000000C) Desc |= eNormal;
if (VertexFlags & 0x00000030) Desc |= eColor0;
if (VertexFlags & 0x000000C0) Desc |= eColor1;
if (VertexFlags & 0x00000300) Desc |= eTex0;
if (VertexFlags & 0x00000C00) Desc |= eTex1;
if (VertexFlags & 0x00003000) Desc |= eTex2;
if (VertexFlags & 0x0000C000) Desc |= eTex3;
if (VertexFlags & 0x00030000) Desc |= eTex4;
if (VertexFlags & 0x000C0000) Desc |= eTex5;
if (VertexFlags & 0x00300000) Desc |= eTex6;
if (VertexFlags & 0x00C00000) Desc |= eTex7;
if (VertexFlags & 0x01000000) Desc |= ePosMtx;
if (VertexFlags & 0x02000000) Desc |= eTex0Mtx;
if (VertexFlags & 0x04000000) Desc |= eTex1Mtx;
if (VertexFlags & 0x08000000) Desc |= eTex2Mtx;
if (VertexFlags & 0x10000000) Desc |= eTex3Mtx;
if (VertexFlags & 0x20000000) Desc |= eTex4Mtx;
if (VertexFlags & 0x40000000) Desc |= eTex5Mtx;
if (VertexFlags & 0x80000000) Desc |= eTex6Mtx;
return Desc;
}
void CMaterialLoader::ReadPrimeMatSet()
{
// Textures
@@ -63,7 +89,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
}
// Vertex description
pMat->mVtxDesc = (FVertexDescription) mpFile->ReadLong();
pMat->mVtxDesc = ConvertToVertexDescription( mpFile->ReadLong() );
// Unknowns
if (mVersion >= eEchoesDemo)
@@ -267,7 +293,7 @@ CMaterial* CMaterialLoader::ReadCorruptionMaterial()
mHas0x400 = ((Flags & 0x400) != 0);
mpFile->Seek(0x8, SEEK_CUR); // Don't know what any of this is
pMat->mVtxDesc = (FVertexDescription) mpFile->ReadLong();
pMat->mVtxDesc = ConvertToVertexDescription( mpFile->ReadLong() );
mpFile->Seek(0xC, SEEK_CUR);
// Initialize all KColors to white

View File

@@ -25,6 +25,7 @@ class CMaterialLoader
CMaterialLoader();
~CMaterialLoader();
FVertexDescription ConvertToVertexDescription(u32 VertexFlags);
// Load Functions
void ReadPrimeMatSet();

View File

@@ -168,7 +168,7 @@ SSurface* CModelLoader::LoadSurface(IInputStream& rModel)
// Color
for (u32 iClr = 0; iClr < 2; iClr++)
if (VtxDesc & (eColor0 << (iClr * 2)))
if (VtxDesc & (eColor0 << iClr))
Vtx.Color[iClr] = mColors[rModel.ReadShort() & 0xFFFF];
// Tex Coords - these are done a bit differently in DKCR than in the Prime series
@@ -185,7 +185,7 @@ SSurface* CModelLoader::LoadSurface(IInputStream& rModel)
// Tex1-7
for (u32 iTex = 1; iTex < 7; iTex++)
if (VtxDesc & (eTex0 << (iTex * 2)))
if (VtxDesc & (eTex0 << iTex))
Vtx.Tex[iTex] = mTex0[rModel.ReadShort() & 0xFFFF];
}
@@ -194,7 +194,7 @@ SSurface* CModelLoader::LoadSurface(IInputStream& rModel)
// Tex0-7
for (u32 iTex = 0; iTex < 7; iTex++)
{
if (VtxDesc & (eTex0 << iTex * 2))
if (VtxDesc & (eTex0 << iTex))
{
if (!mSurfaceUsingTex1)
Vtx.Tex[iTex] = mTex0[rModel.ReadShort() & 0xFFFF];
@@ -289,7 +289,7 @@ SSurface* CModelLoader::LoadAssimpMesh(const aiMesh *pkMesh, CMaterialSet *pSet)
if (pkMesh->HasNormals()) Desc |= eNormal;
for (u32 iUV = 0; iUV < pkMesh->GetNumUVChannels(); iUV++)
Desc |= (eTex0 << (iUV * 2));
Desc |= (eTex0 << iUV);
pMat->SetVertexDescription(Desc);
@@ -401,6 +401,7 @@ CModel* CModelLoader::LoadCMDL(IInputStream& rCMDL)
BlockCount = rCMDL.ReadLong();
MatSetCount = rCMDL.ReadLong();
if (Flags & 0x1) Loader.mFlags |= eSkinnedModel;
if (Flags & 0x2) Loader.mFlags |= eShortNormals;
if (Flags & 0x4) Loader.mFlags |= eHasTex1;
}
@@ -459,9 +460,21 @@ CModel* CModelLoader::LoadCMDL(IInputStream& rCMDL)
// Materials
Loader.mMaterials.resize(MatSetCount);
for (u32 iMat = 0; iMat < MatSetCount; iMat++)
for (u32 iSet = 0; iSet < MatSetCount; iSet++)
{
Loader.mMaterials[iMat] = CMaterialLoader::LoadMaterialSet(rCMDL, Loader.mVersion);
Loader.mMaterials[iSet] = CMaterialLoader::LoadMaterialSet(rCMDL, Loader.mVersion);
// Toggle skinning on materials
if (Loader.mFlags.HasAnyFlags(eSkinnedModel))
{
for (u32 iMat = 0; iMat < Loader.mMaterials[iSet]->NumMaterials(); iMat++)
{
CMaterial *pMat = Loader.mMaterials[iSet]->MaterialByIndex(iMat);
CMaterial::FMaterialOptions Options = pMat->Options();
pMat->SetOptions(Options | CMaterial::eSkinningEnabled);
pMat->SetVertexDescription(pMat->VtxDesc() | FVertexDescription(eBoneIndices | eBoneWeights));
}
}
if (Loader.mVersion < eCorruptionProto)
Loader.mpSectionMgr->ToNextSection();

View File

@@ -20,7 +20,8 @@ public:
eShortPositions = 0x1,
eShortNormals = 0x2,
eHasTex1 = 0x4,
eHasVisGroups = 0x8
eHasVisGroups = 0x8,
eSkinnedModel = 0x10
};
DECLARE_FLAGS(EModelFlag, FModelFlags)

View File

@@ -12,11 +12,23 @@ void CSkeletonLoader::SetLocalBoneCoords(CBone *pBone)
pBone->mPosition -= pBone->mpParent->mPosition;
}
void CSkeletonLoader::CalculateBoneInverseBindMatrices()
{
mpSkeleton->mInvBindMatrices.resize(mpSkeleton->MaxBoneID() + 1);
for (u32 iBone = 0; iBone < mpSkeleton->mBones.size(); iBone++)
{
CBone *pBone = mpSkeleton->mBones[iBone];
mpSkeleton->mInvBindMatrices[pBone->ID()] = CTransform4f::TranslationMatrix(-pBone->AbsolutePosition());
}
}
// ************ STATIC ************
CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
{
CSkeletonLoader Loader;
CSkeleton *pSkel = new CSkeleton();
Loader.mpSkeleton = pSkel;
u32 NumBones = rCINF.ReadLong();
pSkel->mBones.reserve(NumBones);
@@ -78,6 +90,7 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
}
Loader.SetLocalBoneCoords(pSkel->mpRootBone);
Loader.CalculateBoneInverseBindMatrices();
// Skip bone ID array
u32 NumBoneIDs = rCINF.ReadLong();

View File

@@ -12,6 +12,7 @@ class CSkeletonLoader
CSkeletonLoader() {}
void SetLocalBoneCoords(CBone *pBone);
void CalculateBoneInverseBindMatrices();
public:
static CSkeleton* LoadCINF(IInputStream& rCINF);

View File

@@ -0,0 +1,29 @@
#include "CSkinLoader.h"
#include <Common/Assert.h>
// ************ STATIC ************
CSkin* CSkinLoader::LoadCSKR(IInputStream& rCSKR)
{
if (!rCSKR.IsValid()) return nullptr;
u32 NumVertexGroups = rCSKR.ReadLong();
CSkin *pSkin = new CSkin();
pSkin->mVertGroups.resize(NumVertexGroups);
for (u32 iGrp = 0; iGrp < NumVertexGroups; iGrp++)
{
CSkin::SVertGroup& rGroup = pSkin->mVertGroups[iGrp];
u32 NumWeights = rCSKR.ReadLong();
ASSERT(NumWeights <= 4);
for (u32 iWgt = 0; iWgt < NumWeights; iWgt++)
{
rGroup.Weights.Indices[iWgt] = (u8) rCSKR.ReadLong();
rGroup.Weights.Weights[iWgt] = rCSKR.ReadFloat();
}
rGroup.NumVertices = rCSKR.ReadLong();
}
return pSkin;
}

View File

@@ -0,0 +1,14 @@
#ifndef CSKINLOADER_H
#define CSKINLOADER_H
#include "Core/Resource/CSkin.h"
#include "Core/Resource/TResPtr.h"
class CSkinLoader
{
CSkinLoader() {}
public:
static CSkin* LoadCSKR(IInputStream& rCSKR);
};
#endif // CSKINLOADER_H

View File

@@ -160,6 +160,46 @@ void CModel::DrawWireframe(FRenderOptions Options, CColor WireColor /*= CColor::
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
void CModel::SetSkin(CSkin *pSkin)
{
if (mpSkin != pSkin)
{
const FVertexDescription kBoneFlags = (eBoneIndices | eBoneWeights);
mpSkin = pSkin;
mVBO.SetSkin(pSkin);
ClearGLBuffer();
if (pSkin && !mVBO.VertexDesc().HasAllFlags(kBoneFlags))
mVBO.SetVertexDesc(mVBO.VertexDesc() | kBoneFlags);
else if (!pSkin && mVBO.VertexDesc().HasAnyFlags(kBoneFlags))
mVBO.SetVertexDesc(mVBO.VertexDesc() & ~kBoneFlags);
for (u32 iSet = 0; iSet < mMaterialSets.size(); iSet++)
{
CMaterialSet *pSet = mMaterialSets[iSet];
for (u32 iMat = 0; iMat < pSet->NumMaterials(); iMat++)
{
CMaterial *pMat = pSet->MaterialByIndex(iMat);
FVertexDescription VtxDesc = pMat->VtxDesc();
if (pSkin && !VtxDesc.HasAllFlags(kBoneFlags))
{
VtxDesc |= kBoneFlags;
pMat->SetVertexDescription(VtxDesc);
}
else if (!pSkin && VtxDesc.HasAnyFlags(kBoneFlags))
{
VtxDesc &= ~kBoneFlags;
pMat->SetVertexDescription(VtxDesc);
}
}
}
}
}
u32 CModel::GetMatSetCount()
{
return mMaterialSets.size();

View File

@@ -4,6 +4,7 @@
#include "CBasicModel.h"
#include "SSurface.h"
#include "Core/Resource/CMaterialSet.h"
#include "Core/Resource/CSkin.h"
#include "Core/OpenGL/CIndexBuffer.h"
#include "Core/OpenGL/GLCommon.h"
#include "Core/Render/FRenderOptions.h"
@@ -13,6 +14,7 @@ class CModel : public CBasicModel
friend class CModelLoader;
friend class CModelCooker;
TResPtr<CSkin> mpSkin;
std::vector<CMaterialSet*> mMaterialSets;
std::vector<std::vector<CIndexBuffer>> mSurfaceIndexBuffers;
bool mHasOwnMaterials;
@@ -28,6 +30,7 @@ public:
void Draw(FRenderOptions Options, u32 MatSet);
void DrawSurface(FRenderOptions Options, u32 Surface, u32 MatSet);
void DrawWireframe(FRenderOptions Options, CColor WireColor = CColor::skWhite);
void SetSkin(CSkin *pSkin);
u32 GetMatSetCount();
u32 GetMatCount();
@@ -37,6 +40,8 @@ public:
bool HasTransparency(u32 MatSet);
bool IsSurfaceTransparent(u32 Surface, u32 MatSet);
bool IsSkinned() const { return (mpSkin != nullptr); }
private:
CIndexBuffer* InternalGetIBO(u32 Surface, EGXPrimitiveType Primitive);
};

View File

@@ -4,6 +4,10 @@
#include <Common/CColor.h>
#include <Math/CVector2f.h>
#include <Math/CVector3f.h>
#include <array>
typedef std::array<u32, 4> TBoneIndices;
typedef std::array<float, 4> TBoneWeights;
class CVertex
{
@@ -14,6 +18,8 @@ public:
CVector3f Normal;
CColor Color[2];
CVector2f Tex[8];
TBoneIndices BoneIndices;
TBoneWeights BoneWeights;
u8 MatrixIndices[8];
CVertex() {}
@@ -35,7 +41,9 @@ public:
(Tex[4] == rkOther.Tex[4]) &&
(Tex[5] == rkOther.Tex[5]) &&
(Tex[6] == rkOther.Tex[6]) &&
(Tex[7] == rkOther.Tex[7]));
(Tex[7] == rkOther.Tex[7]) &&
(BoneIndices == rkOther.BoneIndices) &&
(BoneWeights == rkOther.BoneWeights));
}
};

View File

@@ -0,0 +1,32 @@
#include "EVertexAttribute.h"
#include <Common/Log.h>
const u32 gkNumVertexAttribs = 22;
u32 VertexAttributeSize(EVertexAttribute Attrib)
{
switch (Attrib)
{
case ePosition:
case eNormal:
return 0x0C;
case eColor0:
case eColor1:
case eBoneWeights:
return 0x10;
case eTex0:
case eTex1:
case eTex2:
case eTex3:
case eTex4:
case eTex5:
case eTex6:
case eTex7:
return 0x08;
case eBoneIndices:
return 0x04;
default:
Log::Error("AttributeSize(): Unknown vertex attribute: " + TString::FromInt32(Attrib, 0, 10));
return 0x00;
}
}

View File

@@ -6,28 +6,33 @@
enum EVertexAttribute
{
eNoAttributes = 0x0,
ePosition = 0x3,
eNormal = 0xC,
eColor0 = 0x30,
eColor1 = 0xC0,
eTex0 = 0x300,
eTex1 = 0xC00,
eTex2 = 0x3000,
eTex3 = 0xC000,
eTex4 = 0x30000,
eTex5 = 0xC0000,
eTex6 = 0x300000,
eTex7 = 0xC00000,
ePosMtx = 0x1000000,
eTex0Mtx = 0x2000000,
eTex1Mtx = 0x4000000,
eTex2Mtx = 0x8000000,
eTex3Mtx = 0x10000000,
eTex4Mtx = 0x20000000,
eTex5Mtx = 0x40000000,
eTex6Mtx = 0x80000000
ePosition = 0x1,
eNormal = 0x2,
eColor0 = 0x4,
eColor1 = 0x8,
eTex0 = 0x10,
eTex1 = 0x20,
eTex2 = 0x40,
eTex3 = 0x80,
eTex4 = 0x100,
eTex5 = 0x200,
eTex6 = 0x400,
eTex7 = 0x800,
eBoneIndices = 0x1000,
eBoneWeights = 0x2000,
ePosMtx = 0x4000,
eTex0Mtx = 0x8000,
eTex1Mtx = 0x10000,
eTex2Mtx = 0x20000,
eTex3Mtx = 0x40000,
eTex4Mtx = 0x80000,
eTex5Mtx = 0x100000,
eTex6Mtx = 0x200000
};
DECLARE_FLAGS(EVertexAttribute, FVertexDescription)
extern const u32 gkNumVertexAttribs;
u32 VertexAttributeSize(EVertexAttribute Attrib);
#endif // EVERTEXATTRIBUTE