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

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,6 +1,7 @@
#ifndef ASSERT_H #ifndef ASSERT_H
#define ASSERT_H #define ASSERT_H
#include "Log.h"
#include "TString.h" #include "TString.h"
#include <cstdlib> #include <cstdlib>
#include <string.h> #include <string.h>

View File

@ -47,7 +47,7 @@ void CColor::SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A /*= 255*/)
A = _A / 255.f; A = _A / 255.f;
} }
void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/) void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/) const
{ {
if (Integral) if (Integral)
{ {

View File

@ -16,7 +16,7 @@ public:
CColor(float _R, float _G, float _B, float A = 1.f); CColor(float _R, float _G, float _B, float A = 1.f);
void SetIntegral(u8 RGBA); void SetIntegral(u8 RGBA);
void SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A = 255); void SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A = 255);
void Write(IOutputStream& rOutput, bool Integral = false); void Write(IOutputStream& rOutput, bool Integral = false) const;
long ToLongRGBA() const; long ToLongRGBA() const;
long ToLongARGB() const; long ToLongARGB() const;

View File

@ -68,7 +68,8 @@ HEADERS += \
Flags.h \ Flags.h \
TString.h \ TString.h \
types.h \ types.h \
Log.h Log.h \
Assert.h
# Source Files # Source Files
SOURCES += \ SOURCES += \

View File

@ -29,7 +29,9 @@ public:
inline TFlags operator&(u32 Mask) const { return TFlags(FlagEnum(mValue & Mask)); } inline TFlags operator&(u32 Mask) const { return TFlags(FlagEnum(mValue & Mask)); }
inline TFlags operator&(FlagEnum Flag) const { return TFlags(FlagEnum(mValue & Flag)); } inline TFlags operator&(FlagEnum Flag) const { return TFlags(FlagEnum(mValue & Flag)); }
inline bool HasFlag(FlagEnum Flag) const { return ((mValue & Flag) != 0); }
inline bool HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); } inline bool HasAnyFlags(TFlags Flags) const { return ((mValue & Flags) != 0); }
inline bool HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); }
}; };
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName; #define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;

View File

@ -93,6 +93,13 @@ void Warning(const TString& rkMessage)
gErrorLog.push_back(FullMessage); gErrorLog.push_back(FullMessage);
} }
void Fatal(const TString& rkMessage)
{
TString FullMessage = "FATAL ERROR: " + rkMessage;
Write(FullMessage);
abort();
}
void FileWrite(const TString& rkFilename, const TString& rkMessage) void FileWrite(const TString& rkFilename, const TString& rkMessage)
{ {
Write(rkFilename + " : " + rkMessage); Write(rkFilename + " : " + rkMessage);

View File

@ -10,6 +10,7 @@ bool InitLog(const TString& rkFilename);
void Write(const TString& rkMessage); void Write(const TString& rkMessage);
void Error(const TString& rkMessage); void Error(const TString& rkMessage);
void Warning(const TString& rkMessage); void Warning(const TString& rkMessage);
void Fatal(const TString& rkMessage);
void FileWrite(const TString& rkFilename, const TString& rkMessage); void FileWrite(const TString& rkFilename, const TString& rkMessage);
void FileWrite(const TString& rkFilename, unsigned long Offset, const TString& rkMessage); void FileWrite(const TString& rkFilename, unsigned long Offset, const TString& rkMessage);
void FileError(const TString& rkFilename, const TString& rkMessage); void FileError(const TString& rkFilename, const TString& rkMessage);

View File

@ -191,7 +191,9 @@ HEADERS += \
Scene/CCharacterNode.h \ Scene/CCharacterNode.h \
Resource/CAnimation.h \ Resource/CAnimation.h \
Resource/Factory/CAnimationLoader.h \ Resource/Factory/CAnimationLoader.h \
Render/CBoneTransformData.h Render/CBoneTransformData.h \
Resource/CSkin.h \
Resource/Factory/CSkinLoader.h
# Source Files # Source Files
SOURCES += \ SOURCES += \
@ -274,4 +276,6 @@ SOURCES += \
Resource/Factory/CSkeletonLoader.cpp \ Resource/Factory/CSkeletonLoader.cpp \
Scene/CCharacterNode.cpp \ Scene/CCharacterNode.cpp \
Resource/CAnimation.cpp \ Resource/CAnimation.cpp \
Resource/Factory/CAnimationLoader.cpp Resource/Factory/CAnimationLoader.cpp \
Resource/Factory/CSkinLoader.cpp \
Resource/Model/EVertexAttribute.cpp

View File

@ -157,6 +157,7 @@ bool CShader::LinkShaders()
mVertexBlockIndex = GetUniformBlockIndex("VertexBlock"); mVertexBlockIndex = GetUniformBlockIndex("VertexBlock");
mPixelBlockIndex = GetUniformBlockIndex("PixelBlock"); mPixelBlockIndex = GetUniformBlockIndex("PixelBlock");
mLightBlockIndex = GetUniformBlockIndex("LightBlock"); mLightBlockIndex = GetUniformBlockIndex("LightBlock");
mBoneTransformBlockIndex = GetUniformBlockIndex("BoneTransformBlock");
mProgramExists = true; mProgramExists = true;
return true; return true;
@ -193,6 +194,7 @@ void CShader::SetCurrent()
glUniformBlockBinding(mProgram, mVertexBlockIndex, CGraphics::VertexBlockBindingPoint()); glUniformBlockBinding(mProgram, mVertexBlockIndex, CGraphics::VertexBlockBindingPoint());
glUniformBlockBinding(mProgram, mPixelBlockIndex, CGraphics::PixelBlockBindingPoint()); glUniformBlockBinding(mProgram, mPixelBlockIndex, CGraphics::PixelBlockBindingPoint());
glUniformBlockBinding(mProgram, mLightBlockIndex, CGraphics::LightBlockBindingPoint()); glUniformBlockBinding(mProgram, mLightBlockIndex, CGraphics::LightBlockBindingPoint());
glUniformBlockBinding(mProgram, mBoneTransformBlockIndex, CGraphics::BoneTransformBlockBindingPoint());
} }
} }

View File

@ -17,6 +17,7 @@ class CShader
GLuint mVertexBlockIndex; GLuint mVertexBlockIndex;
GLuint mPixelBlockIndex; GLuint mPixelBlockIndex;
GLuint mLightBlockIndex; GLuint mLightBlockIndex;
GLuint mBoneTransformBlockIndex;
static CShader* spCurrentShader; static CShader* spCurrentShader;

View File

@ -1,12 +1,13 @@
#include "CShaderGenerator.h" #include "CShaderGenerator.h"
#include <Common/Assert.h>
#include <iostream> #include <iostream>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
#include <GL/glew.h> #include <GL/glew.h>
const TString gkCoordSrc[] = { const TString gkCoordSrc[] = {
"RawPosition.xyz", "ModelSpacePos.xyz",
"RawNormal.xyz", "ModelSpaceNormal.xyz",
"0.0, 0.0, 0.0", "0.0, 0.0, 0.0",
"0.0, 0.0, 0.0", "0.0, 0.0, 0.0",
"RawTex0.xy, 1.0", "RawTex0.xy, 1.0",
@ -144,7 +145,7 @@ CShaderGenerator::~CShaderGenerator()
{ {
} }
bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat) bool CShaderGenerator::CreateVertexShader(const CMaterial& rkMat)
{ {
std::stringstream ShaderCode; std::stringstream ShaderCode;
@ -153,126 +154,188 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
// Input // Input
ShaderCode << "// Input\n"; ShaderCode << "// Input\n";
FVertexDescription VtxDesc = Mat.VtxDesc(); FVertexDescription VtxDesc = rkMat.VtxDesc();
if (VtxDesc & ePosition) ShaderCode << "layout(location = 0) in vec3 RawPosition;\n"; ASSERT(VtxDesc & ePosition);
if (VtxDesc & eNormal) ShaderCode << "layout(location = 1) in vec3 RawNormal;\n";
if (VtxDesc & eColor0) ShaderCode << "layout(location = 2) in vec4 RawColor0;\n"; ShaderCode << "layout(location = 0) in vec3 RawPosition;\n";
if (VtxDesc & eColor1) ShaderCode << "layout(location = 3) in vec4 RawColor1;\n"; if (VtxDesc & eNormal) ShaderCode << "layout(location = 1) in vec3 RawNormal;\n";
if (VtxDesc & eTex0) ShaderCode << "layout(location = 4) in vec2 RawTex0;\n"; if (VtxDesc & eColor0) ShaderCode << "layout(location = 2) in vec4 RawColor0;\n";
if (VtxDesc & eTex1) ShaderCode << "layout(location = 5) in vec2 RawTex1;\n"; if (VtxDesc & eColor1) ShaderCode << "layout(location = 3) in vec4 RawColor1;\n";
if (VtxDesc & eTex2) ShaderCode << "layout(location = 6) in vec2 RawTex2;\n"; if (VtxDesc & eTex0) ShaderCode << "layout(location = 4) in vec2 RawTex0;\n";
if (VtxDesc & eTex3) ShaderCode << "layout(location = 7) in vec2 RawTex3;\n"; if (VtxDesc & eTex1) ShaderCode << "layout(location = 5) in vec2 RawTex1;\n";
if (VtxDesc & eTex4) ShaderCode << "layout(location = 8) in vec2 RawTex4;\n"; if (VtxDesc & eTex2) ShaderCode << "layout(location = 6) in vec2 RawTex2;\n";
if (VtxDesc & eTex5) ShaderCode << "layout(location = 9) in vec2 RawTex5;\n"; if (VtxDesc & eTex3) ShaderCode << "layout(location = 7) in vec2 RawTex3;\n";
if (VtxDesc & eTex6) ShaderCode << "layout(location = 10) in vec2 RawTex6;\n"; if (VtxDesc & eTex4) ShaderCode << "layout(location = 8) in vec2 RawTex4;\n";
if (VtxDesc & eTex5) ShaderCode << "layout(location = 9) in vec2 RawTex5;\n";
if (VtxDesc & eTex6) ShaderCode << "layout(location = 10) in vec2 RawTex6;\n";
if (VtxDesc & eTex7) ShaderCode << "layout(location = 11) in vec2 RawTex7;\n";
if (VtxDesc & eBoneIndices) ShaderCode << "layout(location = 12) in ivec4 BoneIndices;\n";
if (VtxDesc & eBoneWeights) ShaderCode << "layout(location = 13) in vec4 BoneWeights;\n";
ShaderCode << "\n"; ShaderCode << "\n";
// Output // Output
ShaderCode << "// Output\n"; ShaderCode << "// Output\n";
if (VtxDesc & eNormal) ShaderCode << "out vec3 Normal;\n"; if (VtxDesc & eNormal) ShaderCode << "out vec3 Normal;\n";
if (VtxDesc & eColor0) ShaderCode << "out vec4 Color0;\n"; if (VtxDesc & eColor0) ShaderCode << "out vec4 Color0;\n";
if (VtxDesc & eColor1) ShaderCode << "out vec4 Color1;\n"; if (VtxDesc & eColor1) ShaderCode << "out vec4 Color1;\n";
for (u32 iPass = 0; iPass < Mat.PassCount(); iPass++) for (u32 iPass = 0; iPass < rkMat.PassCount(); iPass++)
if (Mat.Pass(iPass)->TexCoordSource() != 0xFF) if (rkMat.Pass(iPass)->TexCoordSource() != 0xFF)
ShaderCode << "out vec3 Tex" << iPass << ";\n"; ShaderCode << "out vec3 Tex" << iPass << ";\n";
ShaderCode << "out vec4 COLOR0A0;\n" ShaderCode << "out vec4 COLOR0A0;\n"
<< "out vec4 COLOR1A1;\n"; << "out vec4 COLOR1A1;\n";
ShaderCode << "\n"; ShaderCode << "\n";
// Uniforms // Uniforms
ShaderCode << "// Uniforms\n" ShaderCode << "// Uniforms\n"
<< "layout(std140) uniform MVPBlock\n" << "layout(std140) uniform MVPBlock\n"
<< "{\n" << "{\n"
<< " mat4 ModelMtx;\n" << " mat4 ModelMtx;\n"
<< " mat4 ViewMtx;\n" << " mat4 ViewMtx;\n"
<< " mat4 ProjMtx;\n" << " mat4 ProjMtx;\n"
<< "};\n" << "};\n"
<< "\n" << "\n"
<< "layout(std140) uniform VertexBlock\n" << "layout(std140) uniform VertexBlock\n"
<< "{\n" << "{\n"
<< " mat4 TexMtx[10];\n" << " mat4 TexMtx[10];\n"
<< " mat4 PostMtx[20];\n" << " mat4 PostMtx[20];\n"
<< " vec4 COLOR0_Amb;\n" << " vec4 COLOR0_Amb;\n"
<< " vec4 COLOR0_Mat;\n" << " vec4 COLOR0_Mat;\n"
<< " vec4 COLOR1_Amb;\n" << " vec4 COLOR1_Amb;\n"
<< " vec4 COLOR1_Mat;\n" << " vec4 COLOR1_Mat;\n"
<< "};\n" << "};\n"
<< "\n" << "\n"
<< "struct GXLight\n" << "struct GXLight\n"
<< "{\n" << "{\n"
<< " vec4 Position;\n" << " vec4 Position;\n"
<< " vec4 Direction;\n" << " vec4 Direction;\n"
<< " vec4 Color;\n" << " vec4 Color;\n"
<< " vec4 DistAtten;\n" << " vec4 DistAtten;\n"
<< " vec4 AngleAtten;\n" << " vec4 AngleAtten;\n"
<< "};\n" << "};\n"
<< "layout(std140) uniform LightBlock {\n" << "\n"
<< " GXLight Lights[8];\n" << "layout(std140) uniform LightBlock\n"
<< "};\n" << "{\n"
<< "uniform int NumLights;\n" << " GXLight Lights[8];\n"
<< "\n"; << "};\n"
<< "uniform int NumLights;\n"
<< "\n";
if (rkMat.Options() & CMaterial::eSkinningEnabled)
{
ShaderCode << "layout(std140) uniform BoneTransformBlock\n"
<< "{\n"
<< " mat4 BoneTransforms[100];\n"
<< " mat4 InverseBindTransforms[100];\n"
<< "};\n"
<< "\n";
}
// Main // Main
ShaderCode << "// Main\n" ShaderCode << "// Main\n"
<< "void main()\n" << "void main()\n"
<< "{\n" << "{\n"
<< " mat4 MV = ModelMtx * ViewMtx;\n" << " mat4 MV = ModelMtx * ViewMtx;\n"
<< " mat4 MVP = MV * ProjMtx;\n"; << " mat4 MVP = MV * ProjMtx;\n";
if (VtxDesc & ePosition) ShaderCode << " gl_Position = vec4(RawPosition, 1) * MVP;\n";
if (VtxDesc & eNormal) ShaderCode << " Normal = normalize(RawNormal.xyz * inverse(transpose(mat3(MV))));\n";
if (VtxDesc & eColor0) ShaderCode << " Color0 = RawColor0;\n"; if (VtxDesc & eColor0) ShaderCode << " Color0 = RawColor0;\n";
if (VtxDesc & eColor1) ShaderCode << " Color1 = RawColor1;\n"; if (VtxDesc & eColor1) ShaderCode << " Color1 = RawColor1;\n";
ShaderCode << "\n";
// Skinning
if (rkMat.Options() & CMaterial::eSkinningEnabled)
{
ShaderCode << " // Skinning\n"
<< " vec3 ModelSpacePos = vec3(0,0,0);\n";
if (VtxDesc & eNormal)
ShaderCode << " vec3 ModelSpaceNormal = vec3(0,0,0);\n";
ShaderCode << " \n"
<< " for (int iBone = 0; iBone < 4; iBone++)\n"
<< " {\n"
<< " int BoneIdx = BoneIndices[iBone];\n"
<< " float Weight = BoneWeights[iBone];\n"
<< " \n"
<< " if (BoneIdx > 0)\n"
<< " {\n"
<< " mat4 BoneSpaceTransform = InverseBindTransforms[BoneIdx] * BoneTransforms[BoneIdx];\n"
<< " ModelSpacePos += vec3(vec4(RawPosition, 1) * BoneSpaceTransform * Weight);\n";
if (VtxDesc & eNormal)
ShaderCode << " ModelSpaceNormal += RawNormal.xyz * inverse(transpose(mat3(BoneSpaceTransform))) * Weight;\n";
ShaderCode << " }\n"
<< " }\n"
<< " \n";
if (VtxDesc & eNormal)
ShaderCode << " ModelSpaceNormal = normalize(ModelSpaceNormal);\n"
<< " \n";
}
else
{
ShaderCode << " vec3 ModelSpacePos = RawPosition;\n";
if (VtxDesc & eNormal)
ShaderCode << " vec3 ModelSpaceNormal = RawNormal.xyz;\n";
ShaderCode << "\n";
}
ShaderCode << " gl_Position = vec4(ModelSpacePos, 1) * MVP;\n";
if (VtxDesc & eNormal)
ShaderCode << " Normal = normalize(ModelSpaceNormal * inverse(transpose(mat3(MV))));\n";
// Per-vertex lighting // Per-vertex lighting
ShaderCode << "\n" ShaderCode << "\n"
<< " // Dynamic Lighting\n"; << " // Dynamic Lighting\n";
// This bit could do with some cleaning up // This bit could do with some cleaning up
// It took a lot of experimentation to get dynamic lights working and I never went back and cleaned it up after // It took a lot of experimentation to get dynamic lights working and I never went back and cleaned it up after
if (Mat.IsLightingEnabled()) if (rkMat.IsLightingEnabled())
{ {
ShaderCode << " vec4 Illum = vec4(0.0);\n" ShaderCode << " vec4 Illum = vec4(0.0);\n"
<< " vec3 PositionMV = vec3(vec4(RawPosition, 1.0) * MV);\n" << " vec3 PositionMV = vec3(vec4(ModelSpacePos, 1.0) * MV);\n"
<< " \n" << " \n"
<< " for (int iLight = 0; iLight < NumLights; iLight++)\n" << " for (int iLight = 0; iLight < NumLights; iLight++)\n"
<< " {\n" << " {\n"
<< " vec3 LightPosMV = vec3(Lights[iLight].Position * ViewMtx);\n" << " vec3 LightPosMV = vec3(Lights[iLight].Position * ViewMtx);\n"
<< " vec3 LightDirMV = normalize(Lights[iLight].Direction.xyz * inverse(transpose(mat3(ViewMtx))));\n" << " vec3 LightDirMV = normalize(Lights[iLight].Direction.xyz * inverse(transpose(mat3(ViewMtx))));\n"
<< " vec3 LightDist = LightPosMV.xyz - PositionMV.xyz;\n" << " vec3 LightDist = LightPosMV.xyz - PositionMV.xyz;\n"
<< " float DistSquared = dot(LightDist, LightDist);\n" << " float DistSquared = dot(LightDist, LightDist);\n"
<< " float Dist = sqrt(DistSquared);\n" << " float Dist = sqrt(DistSquared);\n"
<< " LightDist /= Dist;\n" << " LightDist /= Dist;\n"
<< " vec3 AngleAtten = Lights[iLight].AngleAtten.xyz;\n" << " vec3 AngleAtten = Lights[iLight].AngleAtten.xyz;\n"
<< " AngleAtten = vec3(AngleAtten.x, AngleAtten.y, AngleAtten.z);\n" << " AngleAtten = vec3(AngleAtten.x, AngleAtten.y, AngleAtten.z);\n"
<< " float Atten = max(0, dot(LightDist, LightDirMV.xyz));\n" << " float Atten = max(0, dot(LightDist, LightDirMV.xyz));\n"
<< " Atten = max(0, dot(AngleAtten, vec3(1.0, Atten, Atten * Atten))) / dot(Lights[iLight].DistAtten.xyz, vec3(1.0, Dist, DistSquared));\n" << " Atten = max(0, dot(AngleAtten, vec3(1.0, Atten, Atten * Atten))) / dot(Lights[iLight].DistAtten.xyz, vec3(1.0, Dist, DistSquared));\n"
<< " float DiffuseAtten = max(0, dot(Normal, LightDist));\n" << " float DiffuseAtten = max(0, dot(Normal, LightDist));\n"
<< " Illum += (Atten * DiffuseAtten * Lights[iLight].Color);\n" << " Illum += (Atten * DiffuseAtten * Lights[iLight].Color);\n"
<< " }\n" << " }\n"
<< " COLOR0A0 = COLOR0_Mat * (Illum + COLOR0_Amb);\n" << " COLOR0A0 = COLOR0_Mat * (Illum + COLOR0_Amb);\n"
<< " COLOR1A1 = COLOR1_Mat * (Illum + COLOR1_Amb);\n" << " COLOR1A1 = COLOR1_Mat * (Illum + COLOR1_Amb);\n"
<< " \n"; << " \n";
} }
else else
{ {
ShaderCode << " COLOR0A0 = COLOR0_Mat;\n" ShaderCode << " COLOR0A0 = COLOR0_Mat;\n"
<< " COLOR1A1 = COLOR1_Mat;\n" << " COLOR1A1 = COLOR1_Mat;\n"
<< "\n"; << "\n";
} }
// Texture coordinate generation // Texture coordinate generation
ShaderCode << " \n" ShaderCode << " \n"
<< " // TexGen\n"; << " // TexGen\n";
u32 PassCount = Mat.PassCount(); u32 PassCount = rkMat.PassCount();
for (u32 iPass = 0; iPass < PassCount; iPass++) for (u32 iPass = 0; iPass < PassCount; iPass++)
{ {
CMaterialPass *pPass = Mat.Pass(iPass); CMaterialPass *pPass = rkMat.Pass(iPass);
if (pPass->TexCoordSource() == 0xFF) continue; if (pPass->TexCoordSource() == 0xFF) continue;
EUVAnimMode AnimMode = pPass->AnimMode(); EUVAnimMode AnimMode = pPass->AnimMode();
@ -288,8 +351,8 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
if ((AnimMode < 2) || (AnimMode > 5)) if ((AnimMode < 2) || (AnimMode > 5))
{ {
// Normalization + Post-Transform // Normalization + Post-Transform
ShaderCode << " Tex" << iPass << " = normalize(Tex" << iPass << ");\n"; ShaderCode << " Tex" << iPass << " = normalize(Tex" << iPass << ");\n"
ShaderCode << " Tex" << iPass << " = vec3(vec4(Tex" << iPass << ", 1.0) * PostMtx[" << iPass << "]).xyz;\n"; << " Tex" << iPass << " = vec3(vec4(Tex" << iPass << ", 1.0) * PostMtx[" << iPass << "]).xyz;\n";
} }
} }
@ -302,22 +365,22 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
return mpShader->CompileVertexSource(ShaderCode.str().c_str()); return mpShader->CompileVertexSource(ShaderCode.str().c_str());
} }
bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat) bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)
{ {
std::stringstream ShaderCode; std::stringstream ShaderCode;
ShaderCode << "#version 330 core\n" ShaderCode << "#version 330 core\n"
<< "\n"; << "\n";
FVertexDescription VtxDesc = Mat.VtxDesc(); FVertexDescription VtxDesc = rkMat.VtxDesc();
if (VtxDesc & ePosition) ShaderCode << "in vec3 Position;\n"; if (VtxDesc & ePosition) ShaderCode << "in vec3 Position;\n";
if (VtxDesc & eNormal) ShaderCode << "in vec3 Normal;\n"; if (VtxDesc & eNormal) ShaderCode << "in vec3 Normal;\n";
if (VtxDesc & eColor0) ShaderCode << "in vec4 Color0;\n"; if (VtxDesc & eColor0) ShaderCode << "in vec4 Color0;\n";
if (VtxDesc & eColor1) ShaderCode << "in vec4 Color1;\n"; if (VtxDesc & eColor1) ShaderCode << "in vec4 Color1;\n";
u32 PassCount = Mat.PassCount(); u32 PassCount = rkMat.PassCount();
for (u32 iPass = 0; iPass < PassCount; iPass++) for (u32 iPass = 0; iPass < PassCount; iPass++)
if (Mat.Pass(iPass)->TexCoordSource() != 0xFF) if (rkMat.Pass(iPass)->TexCoordSource() != 0xFF)
ShaderCode << "in vec3 Tex" << iPass << ";\n"; ShaderCode << "in vec3 Tex" << iPass << ";\n";
ShaderCode << "in vec4 COLOR0A0;\n" ShaderCode << "in vec4 COLOR0A0;\n"
@ -333,7 +396,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
<< "};\n\n"; << "};\n\n";
for (u32 iPass = 0; iPass < PassCount; iPass++) for (u32 iPass = 0; iPass < PassCount; iPass++)
if (Mat.Pass(iPass)->Texture() != nullptr) if (rkMat.Pass(iPass)->Texture() != nullptr)
ShaderCode << "uniform sampler2D Texture" << iPass << ";\n"; ShaderCode << "uniform sampler2D Texture" << iPass << ";\n";
ShaderCode <<"\n"; ShaderCode <<"\n";
@ -351,7 +414,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
bool Lightmap = false; bool Lightmap = false;
for (u32 iPass = 0; iPass < PassCount; iPass++) for (u32 iPass = 0; iPass < PassCount; iPass++)
{ {
const CMaterialPass *pPass = Mat.Pass(iPass); const CMaterialPass *pPass = rkMat.Pass(iPass);
CFourCC PassType = pPass->Type(); CFourCC PassType = pPass->Type();
ShaderCode << " // TEV Stage " << iPass << " - " << PassType.ToString() << "\n"; ShaderCode << " // TEV Stage " << iPass << " - " << PassType.ToString() << "\n";
@ -377,7 +440,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
// Apply lightmap multiplier // Apply lightmap multiplier
if ( (PassType == "DIFF") || if ( (PassType == "DIFF") ||
(PassType == "CUST" && (Mat.Options() & CMaterial::eLightmap) && iPass == 0) ) (PassType == "CUST" && (rkMat.Options() & CMaterial::eLightmap) && iPass == 0) )
ShaderCode << " * LightmapMultiplier"; ShaderCode << " * LightmapMultiplier";
ShaderCode << ";\n"; ShaderCode << ";\n";
@ -415,9 +478,9 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
ShaderCode << "clamp(TevInD.a + ((1.0 - TevInC.a) * TevInA.a + TevInC.a * TevInB.a), 0.0, 1.0);\n\n"; ShaderCode << "clamp(TevInD.a + ((1.0 - TevInC.a) * TevInA.a + TevInC.a * TevInB.a), 0.0, 1.0);\n\n";
} }
if (Mat.Options() & CMaterial::ePunchthrough) if (rkMat.Options() & CMaterial::ePunchthrough)
{ {
if (Mat.Version() < eCorruptionProto) if (rkMat.Version() < eCorruptionProto)
{ {
ShaderCode << " if (Prev.a <= 0.25) discard;\n" ShaderCode << " if (Prev.a <= 0.25) discard;\n"
<< " else Prev.a = 1.0;\n\n"; << " else Prev.a = 1.0;\n\n";

View File

@ -45,10 +45,17 @@ public:
Unbind(); Unbind();
} }
void Buffer(void *pData) void Buffer(const void *pkData)
{ {
Bind(); Bind();
glBufferSubData(GL_UNIFORM_BUFFER, 0, mBufferSize, pData); glBufferSubData(GL_UNIFORM_BUFFER, 0, mBufferSize, pkData);
Unbind();
}
void BufferRange(const void *pkData, u32 Offset, u32 Size)
{
Bind();
glBufferSubData(GL_UNIFORM_BUFFER, Offset, Size, pkData);
Unbind(); Unbind();
} }

View File

@ -18,7 +18,7 @@ CVertexBuffer::~CVertexBuffer()
CVertexArrayManager::DeleteAllArraysForVBO(this); CVertexArrayManager::DeleteAllArraysForVBO(this);
if (mBuffered) if (mBuffered)
glDeleteBuffers(12, mAttribBuffers); glDeleteBuffers(14, mAttribBuffers);
} }
u16 CVertexBuffer::AddVertex(const CVertex& rkVtx) u16 CVertexBuffer::AddVertex(const CVertex& rkVtx)
@ -31,11 +31,18 @@ u16 CVertexBuffer::AddVertex(const CVertex& rkVtx)
if (mVtxDesc & eColor1) mColors[1].push_back(rkVtx.Color[1]); if (mVtxDesc & eColor1) mColors[1].push_back(rkVtx.Color[1]);
for (u32 iTex = 0; iTex < 8; iTex++) for (u32 iTex = 0; iTex < 8; iTex++)
if (mVtxDesc & (eTex0 << (iTex * 2))) mTexCoords[iTex].push_back(rkVtx.Tex[iTex]); if (mVtxDesc & (eTex0 << iTex)) mTexCoords[iTex].push_back(rkVtx.Tex[iTex]);
for (u32 iMtx = 0; iMtx < 8; iMtx++) for (u32 iMtx = 0; iMtx < 8; iMtx++)
if (mVtxDesc & (ePosMtx << iMtx)) mTexCoords[iMtx].push_back(rkVtx.MatrixIndices[iMtx]); if (mVtxDesc & (ePosMtx << iMtx)) mTexCoords[iMtx].push_back(rkVtx.MatrixIndices[iMtx]);
if (mVtxDesc.HasAnyFlags(eBoneIndices | eBoneWeights) && mpSkin)
{
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
if (mVtxDesc & eBoneIndices) mBoneIndices.push_back(rkWeights.Indices);
if (mVtxDesc & eBoneWeights) mBoneWeights.push_back(rkWeights.Weights);
}
return (mPositions.size() - 1); return (mPositions.size() - 1);
} }
@ -51,24 +58,39 @@ u16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, u16 Start)
if (mVtxDesc & ePosition) if (mVtxDesc & ePosition)
if (rkVtx.Position != mPositions[iVert]) Unique = true; if (rkVtx.Position != mPositions[iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eNormal)) if (!Unique && (mVtxDesc & eNormal))
if (rkVtx.Normal != mNormals[iVert]) Unique = true; if (rkVtx.Normal != mNormals[iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eColor0)) if (!Unique && (mVtxDesc & eColor0))
if (rkVtx.Color[0] != mColors[0][iVert]) Unique = true; if (rkVtx.Color[0] != mColors[0][iVert]) Unique = true;
if ((!Unique) && (mVtxDesc & eColor1)) if (!Unique && (mVtxDesc & eColor1))
if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true; if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true;
if (!Unique) if (!Unique)
for (u32 iTex = 0; iTex < 8; iTex++) for (u32 iTex = 0; iTex < 8; iTex++)
if ((mVtxDesc & (eTex0 << (iTex * 2)))) if ((mVtxDesc & (eTex0 << iTex)))
if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert]) if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert])
{ {
Unique = true; Unique = true;
break; break;
} }
if (!Unique && mpSkin && (mVtxDesc.HasAnyFlags(eBoneIndices | eBoneWeights)))
{
const SVertexWeights& rkWeights = mpSkin->WeightsForVertex(rkVtx.ArrayPosition);
for (u32 iWgt = 0; iWgt < 4; iWgt++)
{
if ( ((mVtxDesc & eBoneIndices) && (rkWeights.Indices[iWgt] != mBoneIndices[iVert][iWgt])) ||
((mVtxDesc & eBoneWeights) && (rkWeights.Weights[iWgt] != mBoneWeights[iVert][iWgt])) )
{
Unique = true;
break;
}
}
}
if (!Unique) return iVert; if (!Unique) return iVert;
} }
} }
@ -93,14 +115,20 @@ void CVertexBuffer::Reserve(u16 Size)
mColors[1].reserve(ReserveSize); mColors[1].reserve(ReserveSize);
for (u32 iTex = 0; iTex < 8; iTex++) for (u32 iTex = 0; iTex < 8; iTex++)
if (mVtxDesc & (eTex0 << (iTex * 2))) if (mVtxDesc & (eTex0 << iTex))
mTexCoords[iTex].reserve(ReserveSize); mTexCoords[iTex].reserve(ReserveSize);
if (mVtxDesc & eBoneIndices)
mBoneIndices.reserve(ReserveSize);
if (mVtxDesc & eBoneWeights)
mBoneWeights.reserve(ReserveSize);
} }
void CVertexBuffer::Clear() void CVertexBuffer::Clear()
{ {
if (mBuffered) if (mBuffered)
glDeleteBuffers(12, mAttribBuffers); glDeleteBuffers(14, mAttribBuffers);
mBuffered = false; mBuffered = false;
mPositions.clear(); mPositions.clear();
@ -110,6 +138,9 @@ void CVertexBuffer::Clear()
for (u32 iTex = 0; iTex < 8; iTex++) for (u32 iTex = 0; iTex < 8; iTex++)
mTexCoords[iTex].clear(); mTexCoords[iTex].clear();
mBoneIndices.clear();
mBoneWeights.clear();
} }
void CVertexBuffer::Buffer() void CVertexBuffer::Buffer()
@ -117,16 +148,16 @@ void CVertexBuffer::Buffer()
// Make sure we don't end up with two buffers for the same data... // Make sure we don't end up with two buffers for the same data...
if (mBuffered) if (mBuffered)
{ {
glDeleteBuffers(12, mAttribBuffers); glDeleteBuffers(14, mAttribBuffers);
mBuffered = false; mBuffered = false;
} }
// Generate buffers // Generate buffers
glGenBuffers(12, mAttribBuffers); glGenBuffers(14, mAttribBuffers);
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++) for (u32 iAttrib = 0; iAttrib < 14; iAttrib++)
{ {
int Attrib = (ePosition << (iAttrib * 2)); int Attrib = (ePosition << iAttrib);
bool HasAttrib = ((mVtxDesc & Attrib) != 0); bool HasAttrib = ((mVtxDesc & Attrib) != 0);
if (!HasAttrib) continue; if (!HasAttrib) continue;
@ -146,13 +177,25 @@ void CVertexBuffer::Buffer()
glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mColors[Index].size() * sizeof(CColor), mColors[Index].data(), GL_STATIC_DRAW);
} }
else else if (iAttrib < 12)
{ {
u8 Index = (u8) (iAttrib - 4); u8 Index = (u8) (iAttrib - 4);
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, mTexCoords[Index].size() * sizeof(CVector2f), mTexCoords[Index].data(), GL_STATIC_DRAW);
} }
else if (iAttrib == 12)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mBoneIndices.size() * sizeof(TBoneIndices), mBoneIndices.data(), GL_STATIC_DRAW);
}
else if (iAttrib == 13)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glBufferData(GL_ARRAY_BUFFER, mBoneWeights.size() * sizeof(TBoneWeights), mBoneWeights.data(), GL_STATIC_DRAW);
}
} }
mBuffered = true; mBuffered = true;
@ -185,6 +228,12 @@ void CVertexBuffer::SetVertexDesc(FVertexDescription Desc)
mVtxDesc = Desc; mVtxDesc = Desc;
} }
void CVertexBuffer::SetSkin(CSkin *pSkin)
{
Clear();
mpSkin = pSkin;
}
u32 CVertexBuffer::Size() u32 CVertexBuffer::Size()
{ {
return mPositions.size(); return mPositions.size();
@ -196,9 +245,9 @@ GLuint CVertexBuffer::CreateVAO()
glGenVertexArrays(1, &VertexArray); glGenVertexArrays(1, &VertexArray);
glBindVertexArray(VertexArray); glBindVertexArray(VertexArray);
for (u32 iAttrib = 0; iAttrib < 12; iAttrib++) for (u32 iAttrib = 0; iAttrib < 14; iAttrib++)
{ {
int Attrib = (ePosition << (iAttrib * 2)); int Attrib = (ePosition << iAttrib);
bool HasAttrib = ((mVtxDesc & Attrib) != 0); bool HasAttrib = ((mVtxDesc & Attrib) != 0);
if (!HasAttrib) continue; if (!HasAttrib) continue;
@ -216,12 +265,26 @@ GLuint CVertexBuffer::CreateVAO()
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else else if (iAttrib < 12)
{ {
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]); glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0); glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0);
glEnableVertexAttribArray(iAttrib); glEnableVertexAttribArray(iAttrib);
} }
else if (iAttrib == 12)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribIPointer(iAttrib, 4, GL_UNSIGNED_INT, sizeof(TBoneIndices), (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
else if (iAttrib == 13)
{
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
glVertexAttribPointer(iAttrib, 4, GL_FLOAT, GL_FALSE, sizeof(TBoneWeights), (void*) 0);
glEnableVertexAttribArray(iAttrib);
}
} }
glBindVertexArray(0); glBindVertexArray(0);

View File

@ -1,6 +1,8 @@
#ifndef CVERTEXBUFFER_H #ifndef CVERTEXBUFFER_H
#define CVERTEXBUFFER_H #define CVERTEXBUFFER_H
#include "Core/Resource/CSkin.h"
#include "Core/Resource/TResPtr.h"
#include "Core/Resource/Model/CVertex.h" #include "Core/Resource/Model/CVertex.h"
#include "Core/Resource/Model/EVertexAttribute.h" #include "Core/Resource/Model/EVertexAttribute.h"
#include <vector> #include <vector>
@ -8,13 +10,16 @@
class CVertexBuffer class CVertexBuffer
{ {
FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
GLuint mAttribBuffers[12]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently. GLuint mAttribBuffers[14]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
std::vector<CVector3f> mPositions; // Vector of vertex positions TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models;
std::vector<CVector3f> mNormals; // Vector of vertex normals std::vector<CVector3f> mPositions; // Vector of vertex positions
std::vector<CColor> mColors[2]; // Vectors of vertex colors std::vector<CVector3f> mNormals; // Vector of vertex normals
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates std::vector<CColor> mColors[2]; // Vectors of vertex colors
bool mBuffered; // Bool value that indicates whether the attributes have been buffered. std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates
std::vector<TBoneIndices> mBoneIndices; // Vectors of bone indices
std::vector<TBoneWeights> mBoneWeights; // Vectors of bone weights
bool mBuffered; // Bool value that indicates whether the attributes have been buffered.
public: public:
CVertexBuffer(); CVertexBuffer();
@ -30,6 +35,7 @@ public:
bool IsBuffered(); bool IsBuffered();
FVertexDescription VertexDesc(); FVertexDescription VertexDesc();
void SetVertexDesc(FVertexDescription Desc); void SetVertexDesc(FVertexDescription Desc);
void SetSkin(CSkin *pSkin);
u32 Size(); u32 Size();
GLuint CreateVAO(); GLuint CreateVAO();
}; };

View File

@ -16,7 +16,7 @@ public:
inline void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); } inline void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); }
inline CTransform4f& BoneMatrix(u32 BoneID) { return mBoneMatrices[BoneID]; } inline CTransform4f& BoneMatrix(u32 BoneID) { return mBoneMatrices[BoneID]; }
inline const CTransform4f& BoneMatrix(u32 BoneID) const { return mBoneMatrices[BoneID]; } inline const CTransform4f& BoneMatrix(u32 BoneID) const { return mBoneMatrices[BoneID]; }
inline void* Data() { return mBoneMatrices.data(); } inline const void* Data() const { return mBoneMatrices.data(); }
inline u32 DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); } inline u32 DataSize() const { return mBoneMatrices.size() * sizeof(CTransform4f); }
inline CTransform4f& operator[](u32 BoneIndex) { return BoneMatrix(BoneIndex); } inline CTransform4f& operator[](u32 BoneIndex) { return BoneMatrix(BoneIndex); }
inline const CTransform4f& operator[](u32 BoneIndex) const { return BoneMatrix(BoneIndex); } inline const CTransform4f& operator[](u32 BoneIndex) const { return BoneMatrix(BoneIndex); }

View File

@ -8,10 +8,13 @@ CUniformBuffer* CGraphics::mpMVPBlockBuffer;
CUniformBuffer* CGraphics::mpVertexBlockBuffer; CUniformBuffer* CGraphics::mpVertexBlockBuffer;
CUniformBuffer* CGraphics::mpPixelBlockBuffer; CUniformBuffer* CGraphics::mpPixelBlockBuffer;
CUniformBuffer* CGraphics::mpLightBlockBuffer; CUniformBuffer* CGraphics::mpLightBlockBuffer;
CUniformBuffer* CGraphics::mpBoneTransformBuffer;
u32 CGraphics::mContextIndices = 0; u32 CGraphics::mContextIndices = 0;
u32 CGraphics::mActiveContext = -1; u32 CGraphics::mActiveContext = -1;
bool CGraphics::mInitialized = false; bool CGraphics::mInitialized = false;
std::vector<CVertexArrayManager*> CGraphics::mVAMs; std::vector<CVertexArrayManager*> CGraphics::mVAMs;
bool CGraphics::mIdentityBoneTransforms = false;
const CSkeleton *CGraphics::mpkCurrentSkeleton = nullptr;
CGraphics::SMVPBlock CGraphics::sMVPBlock; CGraphics::SMVPBlock CGraphics::sMVPBlock;
CGraphics::SVertexBlock CGraphics::sVertexBlock; CGraphics::SVertexBlock CGraphics::sVertexBlock;
@ -44,6 +47,7 @@ void CGraphics::Initialize()
mpVertexBlockBuffer = new CUniformBuffer(sizeof(sVertexBlock)); mpVertexBlockBuffer = new CUniformBuffer(sizeof(sVertexBlock));
mpPixelBlockBuffer = new CUniformBuffer(sizeof(sPixelBlock)); mpPixelBlockBuffer = new CUniformBuffer(sizeof(sPixelBlock));
mpLightBlockBuffer = new CUniformBuffer(sizeof(sLightBlock)); mpLightBlockBuffer = new CUniformBuffer(sizeof(sLightBlock));
mpBoneTransformBuffer = new CUniformBuffer(sizeof(CTransform4f) * 200);
sLightMode = eWorldLighting; sLightMode = eWorldLighting;
sNumLights = 0; sNumLights = 0;
@ -55,6 +59,8 @@ void CGraphics::Initialize()
mpVertexBlockBuffer->BindBase(1); mpVertexBlockBuffer->BindBase(1);
mpPixelBlockBuffer->BindBase(2); mpPixelBlockBuffer->BindBase(2);
mpLightBlockBuffer->BindBase(3); mpLightBlockBuffer->BindBase(3);
mpBoneTransformBuffer->BindBase(4);
LoadIdentityBoneTransforms();
} }
void CGraphics::Shutdown() void CGraphics::Shutdown()
@ -66,6 +72,7 @@ void CGraphics::Shutdown()
delete mpVertexBlockBuffer; delete mpVertexBlockBuffer;
delete mpPixelBlockBuffer; delete mpPixelBlockBuffer;
delete mpLightBlockBuffer; delete mpLightBlockBuffer;
delete mpBoneTransformBuffer;
mInitialized = false; mInitialized = false;
} }
} }
@ -110,6 +117,11 @@ GLuint CGraphics::LightBlockBindingPoint()
return 3; return 3;
} }
GLuint CGraphics::BoneTransformBlockBindingPoint()
{
return 4;
}
u32 CGraphics::GetContextIndex() u32 CGraphics::GetContextIndex()
{ {
for (u32 iCon = 0; iCon < 32; iCon++) for (u32 iCon = 0; iCon < 32; iCon++)
@ -178,3 +190,31 @@ void CGraphics::SetIdentityMVP()
sMVPBlock.ViewMatrix = CMatrix4f::skIdentity; sMVPBlock.ViewMatrix = CMatrix4f::skIdentity;
sMVPBlock.ProjectionMatrix = CMatrix4f::skIdentity; sMVPBlock.ProjectionMatrix = CMatrix4f::skIdentity;
} }
void CGraphics::LoadBoneTransforms(const CBoneTransformData& rkData)
{
mpBoneTransformBuffer->BufferRange(rkData.Data(), 0, rkData.DataSize());
mIdentityBoneTransforms = false;
}
void CGraphics::LoadBoneInverseBindTransforms(CSkeleton *pSkel)
{
if (mpkCurrentSkeleton != pSkel)
{
mpBoneTransformBuffer->BufferRange(pSkel->InverseBindMatricesData(), sizeof(CTransform4f) * 100, pSkel->InverseBindMatricesSize());
mpkCurrentSkeleton = pSkel;
mIdentityBoneTransforms = false;
}
}
void CGraphics::LoadIdentityBoneTransforms()
{
static CTransform4f IdentityTransforms[200];
if (!mIdentityBoneTransforms)
{
mpBoneTransformBuffer->Buffer(&IdentityTransforms);
mpkCurrentSkeleton = nullptr;
mIdentityBoneTransforms = true;
}
}

View File

@ -1,6 +1,7 @@
#ifndef CGRAPHICS_H #ifndef CGRAPHICS_H
#define CGRAPHICS_H #define CGRAPHICS_H
#include "CBoneTransformData.h"
#include "Core/OpenGL/CUniformBuffer.h" #include "Core/OpenGL/CUniformBuffer.h"
#include "Core/OpenGL/CVertexArrayManager.h" #include "Core/OpenGL/CVertexArrayManager.h"
#include "Core/Resource/CLight.h" #include "Core/Resource/CLight.h"
@ -23,11 +24,15 @@ class CGraphics
static CUniformBuffer *mpVertexBlockBuffer; static CUniformBuffer *mpVertexBlockBuffer;
static CUniformBuffer *mpPixelBlockBuffer; static CUniformBuffer *mpPixelBlockBuffer;
static CUniformBuffer *mpLightBlockBuffer; static CUniformBuffer *mpLightBlockBuffer;
static CUniformBuffer *mpBoneTransformBuffer;
static u32 mContextIndices; static u32 mContextIndices;
static u32 mActiveContext; static u32 mActiveContext;
static bool mInitialized; static bool mInitialized;
static std::vector<CVertexArrayManager*> mVAMs; static std::vector<CVertexArrayManager*> mVAMs;
static bool mIdentityBoneTransforms;
static const CSkeleton *mpkCurrentSkeleton;
public: public:
// SMVPBlock // SMVPBlock
struct SMVPBlock struct SMVPBlock
@ -95,6 +100,7 @@ public:
static GLuint VertexBlockBindingPoint(); static GLuint VertexBlockBindingPoint();
static GLuint PixelBlockBindingPoint(); static GLuint PixelBlockBindingPoint();
static GLuint LightBlockBindingPoint(); static GLuint LightBlockBindingPoint();
static GLuint BoneTransformBlockBindingPoint();
static u32 GetContextIndex(); static u32 GetContextIndex();
static u32 GetActiveContext(); static u32 GetActiveContext();
static void ReleaseContext(u32 Index); static void ReleaseContext(u32 Index);
@ -102,6 +108,9 @@ public:
static void SetDefaultLighting(); static void SetDefaultLighting();
static void SetupAmbientColor(); static void SetupAmbientColor();
static void SetIdentityMVP(); static void SetIdentityMVP();
static void LoadBoneTransforms(const CBoneTransformData& rkData);
static void LoadBoneInverseBindTransforms(CSkeleton *pSkel);
static void LoadIdentityBoneTransforms();
}; };
#endif // CGRAPHICS_H #endif // CGRAPHICS_H

View File

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

View File

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

View File

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

View File

@ -10,7 +10,34 @@
#include <Math/CVector3f.h> #include <Math/CVector3f.h>
class CBoneTransformData; 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 class CBone
{ {
@ -29,36 +56,15 @@ public:
bool IsRoot() const; bool IsRoot() const;
// Accessors // Accessors
inline CSkeleton* Skeleton() const { return mpSkeleton; } inline CSkeleton* Skeleton() const { return mpSkeleton; }
inline CBone* Parent() const { return mpParent; } inline CBone* Parent() const { return mpParent; }
inline u32 NumChildren() const { return mChildren.size(); } inline u32 NumChildren() const { return mChildren.size(); }
inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; } inline CBone* ChildByIndex(u32 Index) const { return mChildren[Index]; }
inline u32 ID() const { return mID; } inline u32 ID() const { return mID; }
inline CVector3f Position() const { return mPosition; } inline CVector3f Position() const { return mPosition; }
inline TString Name() const { return mName; } 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); }
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(); }
}; };
#endif // CSKELETON_H #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) void CMaterialCooker::WriteMatSetPrime(IOutputStream& rOut)
{ {
// Gather texture list from the materials before starting // Gather texture list from the materials before starting
@ -150,12 +176,12 @@ void CMaterialCooker::WriteMaterialPrime(IOutputStream& rOut)
rOut.WriteLong(TexIndices[iTex]); rOut.WriteLong(TexIndices[iTex]);
// Vertex description // Vertex description
FVertexDescription Desc = mpMat->VtxDesc(); u32 VtxFlags = ConvertFromVertexDescription( mpMat->VtxDesc() );
if (mVersion < eEchoes) if (mVersion < eEchoes)
Desc &= 0x00FFFFFF; VtxFlags &= 0x00FFFFFF;
rOut.WriteLong(Desc); rOut.WriteLong(VtxFlags);
// Echoes unknowns // Echoes unknowns
if (mVersion == eEchoes) if (mVersion == eEchoes)

View File

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

View File

@ -63,7 +63,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
// Header // Header
rOut.WriteLong(0xDEADBABE); rOut.WriteLong(0xDEADBABE);
rOut.WriteLong(GetCMDLVersion(mVersion)); rOut.WriteLong(GetCMDLVersion(mVersion));
rOut.WriteLong(5); rOut.WriteLong(mpModel->IsSkinned() ? 6 : 5);
mpModel->mAABox.Write(rOut); mpModel->mAABox.Write(rOut);
u32 NumSections = mNumMatSets + mNumSurfaces + 6; u32 NumSections = mNumMatSets + mNumSurfaces + 6;
@ -115,7 +115,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
// Float UV coordinates // Float UV coordinates
for (u32 iTexSlot = 0; iTexSlot < 8; iTexSlot++) for (u32 iTexSlot = 0; iTexSlot < 8; iTexSlot++)
{ {
bool HasTexSlot = (mVtxAttribs & (eTex0 << (iTexSlot * 2))) != 0; bool HasTexSlot = (mVtxAttribs & (eTex0 << iTexSlot)) != 0;
if (HasTexSlot) if (HasTexSlot)
{ {
for (u32 iTex = 0; iTex < mNumVertices; iTex++) for (u32 iTex = 0; iTex < mNumVertices; iTex++)
@ -156,7 +156,7 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
rOut.WriteToBoundary(32, 0); rOut.WriteToBoundary(32, 0);
u32 PrimTableStart = rOut.Tell(); 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++) for (u32 iPrim = 0; iPrim < pSurface->Primitives.size(); iPrim++)
{ {
@ -171,28 +171,28 @@ void CModelCooker::WriteModelPrime(IOutputStream& rOut)
if (mVersion == eEchoes) if (mVersion == eEchoes)
{ {
for (u32 iMtxAttribs = 0; iMtxAttribs < 8; iMtxAttribs++) for (u32 iMtxAttribs = 0; iMtxAttribs < 8; iMtxAttribs++)
if (MatAttribs & (ePosMtx << iMtxAttribs)) if (VtxAttribs & (ePosMtx << iMtxAttribs))
rOut.WriteByte(pVert->MatrixIndices[iMtxAttribs]); rOut.WriteByte(pVert->MatrixIndices[iMtxAttribs]);
} }
u16 VertexIndex = (u16) pVert->ArrayPosition; u16 VertexIndex = (u16) pVert->ArrayPosition;
if (MatAttribs & ePosition) if (VtxAttribs & ePosition)
rOut.WriteShort(VertexIndex); rOut.WriteShort(VertexIndex);
if (MatAttribs & eNormal) if (VtxAttribs & eNormal)
rOut.WriteShort(VertexIndex); rOut.WriteShort(VertexIndex);
if (MatAttribs & eColor0) if (VtxAttribs & eColor0)
rOut.WriteShort(VertexIndex); rOut.WriteShort(VertexIndex);
if (MatAttribs & eColor1) if (VtxAttribs & eColor1)
rOut.WriteShort(VertexIndex); rOut.WriteShort(VertexIndex);
u16 TexOffset = 0; u16 TexOffset = 0;
for (u32 iTex = 0; iTex < 8; iTex++) for (u32 iTex = 0; iTex < 8; iTex++)
{ {
if (MatAttribs & (eTex0 << (iTex * 2))) if (VtxAttribs & (eTex0 << iTex))
{ {
rOut.WriteShort(VertexIndex + TexOffset); rOut.WriteShort(VertexIndex + TexOffset);
TexOffset += (u16) mNumVertices; 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 if (iNode == 0) Loader.mVersion = (Unknown1 == 0xA) ? eEchoes : ePrime; // Best version indicator we know of unfortunately
pNode->Name = rANCS.ReadString(); pNode->Name = rANCS.ReadString();
pNode->pModel = gResCache.GetResource(rANCS.ReadLong(), "CMDL"); 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->pSkeleton = gResCache.GetResource(rANCS.ReadLong(), "CINF");
pNode->pModel->SetSkin(pNode->pSkin);
}
else 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. // 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 // 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() void CMaterialLoader::ReadPrimeMatSet()
{ {
// Textures // Textures
@ -63,7 +89,7 @@ CMaterial* CMaterialLoader::ReadPrimeMaterial()
} }
// Vertex description // Vertex description
pMat->mVtxDesc = (FVertexDescription) mpFile->ReadLong(); pMat->mVtxDesc = ConvertToVertexDescription( mpFile->ReadLong() );
// Unknowns // Unknowns
if (mVersion >= eEchoesDemo) if (mVersion >= eEchoesDemo)
@ -267,7 +293,7 @@ CMaterial* CMaterialLoader::ReadCorruptionMaterial()
mHas0x400 = ((Flags & 0x400) != 0); mHas0x400 = ((Flags & 0x400) != 0);
mpFile->Seek(0x8, SEEK_CUR); // Don't know what any of this is 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); mpFile->Seek(0xC, SEEK_CUR);
// Initialize all KColors to white // Initialize all KColors to white

View File

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

View File

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

View File

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

View File

@ -12,11 +12,23 @@ void CSkeletonLoader::SetLocalBoneCoords(CBone *pBone)
pBone->mPosition -= pBone->mpParent->mPosition; 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 ************ // ************ STATIC ************
CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF) CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
{ {
CSkeletonLoader Loader; CSkeletonLoader Loader;
CSkeleton *pSkel = new CSkeleton(); CSkeleton *pSkel = new CSkeleton();
Loader.mpSkeleton = pSkel;
u32 NumBones = rCINF.ReadLong(); u32 NumBones = rCINF.ReadLong();
pSkel->mBones.reserve(NumBones); pSkel->mBones.reserve(NumBones);
@ -78,6 +90,7 @@ CSkeleton* CSkeletonLoader::LoadCINF(IInputStream& rCINF)
} }
Loader.SetLocalBoneCoords(pSkel->mpRootBone); Loader.SetLocalBoneCoords(pSkel->mpRootBone);
Loader.CalculateBoneInverseBindMatrices();
// Skip bone ID array // Skip bone ID array
u32 NumBoneIDs = rCINF.ReadLong(); u32 NumBoneIDs = rCINF.ReadLong();

View File

@ -12,6 +12,7 @@ class CSkeletonLoader
CSkeletonLoader() {} CSkeletonLoader() {}
void SetLocalBoneCoords(CBone *pBone); void SetLocalBoneCoords(CBone *pBone);
void CalculateBoneInverseBindMatrices();
public: public:
static CSkeleton* LoadCINF(IInputStream& rCINF); 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); 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() u32 CModel::GetMatSetCount()
{ {
return mMaterialSets.size(); return mMaterialSets.size();

View File

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

View File

@ -4,6 +4,10 @@
#include <Common/CColor.h> #include <Common/CColor.h>
#include <Math/CVector2f.h> #include <Math/CVector2f.h>
#include <Math/CVector3f.h> #include <Math/CVector3f.h>
#include <array>
typedef std::array<u32, 4> TBoneIndices;
typedef std::array<float, 4> TBoneWeights;
class CVertex class CVertex
{ {
@ -14,6 +18,8 @@ public:
CVector3f Normal; CVector3f Normal;
CColor Color[2]; CColor Color[2];
CVector2f Tex[8]; CVector2f Tex[8];
TBoneIndices BoneIndices;
TBoneWeights BoneWeights;
u8 MatrixIndices[8]; u8 MatrixIndices[8];
CVertex() {} CVertex() {}
@ -35,7 +41,9 @@ public:
(Tex[4] == rkOther.Tex[4]) && (Tex[4] == rkOther.Tex[4]) &&
(Tex[5] == rkOther.Tex[5]) && (Tex[5] == rkOther.Tex[5]) &&
(Tex[6] == rkOther.Tex[6]) && (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 enum EVertexAttribute
{ {
eNoAttributes = 0x0, eNoAttributes = 0x0,
ePosition = 0x3, ePosition = 0x1,
eNormal = 0xC, eNormal = 0x2,
eColor0 = 0x30, eColor0 = 0x4,
eColor1 = 0xC0, eColor1 = 0x8,
eTex0 = 0x300, eTex0 = 0x10,
eTex1 = 0xC00, eTex1 = 0x20,
eTex2 = 0x3000, eTex2 = 0x40,
eTex3 = 0xC000, eTex3 = 0x80,
eTex4 = 0x30000, eTex4 = 0x100,
eTex5 = 0xC0000, eTex5 = 0x200,
eTex6 = 0x300000, eTex6 = 0x400,
eTex7 = 0xC00000, eTex7 = 0x800,
ePosMtx = 0x1000000, eBoneIndices = 0x1000,
eTex0Mtx = 0x2000000, eBoneWeights = 0x2000,
eTex1Mtx = 0x4000000, ePosMtx = 0x4000,
eTex2Mtx = 0x8000000, eTex0Mtx = 0x8000,
eTex3Mtx = 0x10000000, eTex1Mtx = 0x10000,
eTex4Mtx = 0x20000000, eTex2Mtx = 0x20000,
eTex5Mtx = 0x40000000, eTex3Mtx = 0x40000,
eTex6Mtx = 0x80000000 eTex4Mtx = 0x80000,
eTex5Mtx = 0x100000,
eTex6Mtx = 0x200000
}; };
DECLARE_FLAGS(EVertexAttribute, FVertexDescription) DECLARE_FLAGS(EVertexAttribute, FVertexDescription)
extern const u32 gkNumVertexAttribs;
u32 VertexAttributeSize(EVertexAttribute Attrib);
#endif // EVERTEXATTRIBUTE #endif // EVERTEXATTRIBUTE

View File

@ -23,22 +23,64 @@ void CCharacterNode::PostLoad()
} }
} }
void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& /*rkViewInfo*/) void CCharacterNode::AddToRenderer(CRenderer *pRenderer, const SViewInfo& rkViewInfo)
{ {
if (!mpCharacter) return; if (!mpCharacter) return;
// todo: frustum check. Currently don't have a means of pulling the AABox for the
// current animation so this isn't in yet.
if (mpCharacter->NodeSkeleton(mActiveCharSet)) CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
if (pModel)
{ {
pRenderer->AddOpaqueMesh(this, 0, AABox(), eDrawMesh); if (!pModel->HasTransparency(0))
pRenderer->AddOpaqueMesh(this, -1, AABox(), eDrawMesh);
else
AddSurfacesToRenderer(pRenderer, pModel, 0, rkViewInfo, false);
}
if (pSkel)
{
CAnimation *pAnim = mpCharacter->Animation(mActiveAnim);
pSkel->UpdateTransform(mTransformData, pAnim, mAnimTime, false);
if (rkViewInfo.ShowFlags.HasFlag(eShowSkeletons))
pRenderer->AddOpaqueMesh(this, -2, AABox(), eDrawMesh);
} }
} }
void CCharacterNode::Draw(FRenderOptions Options, int /*ComponentIndex*/, const SViewInfo& /*rkViewInfo*/) void CCharacterNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInfo& rkViewInfo)
{ {
CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet); CSkeleton *pSkel = mpCharacter->NodeSkeleton(mActiveCharSet);
CAnimation *pAnim = mpCharacter->Animation(mActiveAnim);
pSkel->UpdateTransform(mTransformData, pAnim, mAnimTime, false); // Draw skeleton
pSkel->Draw(Options, mTransformData); if (ComponentIndex == -2)
{
pSkel->Draw(Options, mTransformData);
}
// Draw mesh
else
{
// Set lighting
CGraphics::SetDefaultLighting();
CGraphics::UpdateLightBlock();
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor;
CGraphics::sPixelBlock.LightmapMultiplier = 1.f;
CGraphics::sPixelBlock.TevColor = CColor::skWhite;
CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo);
// Draw surface OR draw entire model
CGraphics::LoadBoneTransforms(mTransformData);
CGraphics::LoadBoneInverseBindTransforms(pSkel);
CModel *pModel = mpCharacter->NodeModel(mActiveCharSet);
if (ComponentIndex < 0)
pModel->Draw(Options, 0);
else
pModel->DrawSurface(Options, ComponentIndex, 0);
}
} }
SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*AssetID*/, const SViewInfo& /*rkViewInfo*/) SRayIntersection CCharacterNode::RayNodeIntersectTest(const CRay& rkRay, u32 /*AssetID*/, const SViewInfo& /*rkViewInfo*/)

View File

@ -83,6 +83,9 @@ void CModelNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInf
CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo); CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo);
LoadModelMatrix(); LoadModelMatrix();
if (mpModel->IsSkinned())
CGraphics::LoadIdentityBoneTransforms();
if (ComponentIndex < 0) if (ComponentIndex < 0)
mpModel->Draw(Options, mActiveMatSet); mpModel->Draw(Options, mActiveMatSet);
else else

View File

@ -224,7 +224,7 @@ void CSceneNode::DrawRotationArrow() const
spArrowModel->Draw(eNoRenderOptions, 0); spArrowModel->Draw(eNoRenderOptions, 0);
} }
void CSceneNode::AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& rkViewInfo) void CSceneNode::AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& rkViewInfo, bool DoFrustumTest /*= true*/)
{ {
u32 SurfaceCount = pModel->GetSurfaceCount(); u32 SurfaceCount = pModel->GetSurfaceCount();
@ -232,7 +232,7 @@ void CSceneNode::AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32
{ {
CAABox TransformedBox = pModel->GetSurfaceAABox(iSurf).Transformed(Transform()); CAABox TransformedBox = pModel->GetSurfaceAABox(iSurf).Transformed(Transform());
if (rkViewInfo.ViewFrustum.BoxInFrustum(TransformedBox)) if (!DoFrustumTest || rkViewInfo.ViewFrustum.BoxInFrustum(TransformedBox))
{ {
if (!pModel->IsSurfaceTransparent(iSurf, MatSet)) if (!pModel->IsSurfaceTransparent(iSurf, MatSet))
pRenderer->AddOpaqueMesh(this, (int) iSurf, TransformedBox, eDrawMesh); pRenderer->AddOpaqueMesh(this, (int) iSurf, TransformedBox, eDrawMesh);

View File

@ -79,7 +79,7 @@ public:
void LoadLights(const SViewInfo& rkViewInfo); void LoadLights(const SViewInfo& rkViewInfo);
void DrawBoundingBox() const; void DrawBoundingBox() const;
void DrawRotationArrow() const; void DrawRotationArrow() const;
void AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& rkViewInfo); void AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32 MatSet, const SViewInfo& rkViewInfo, bool DoFrustumTest = true);
// Transform // Transform
void Translate(const CVector3f& rkTranslation, ETransformSpace TransformSpace); void Translate(const CVector3f& rkTranslation, ETransformSpace TransformSpace);

View File

@ -14,7 +14,8 @@ enum EShowFlag
eShowObjects = 0x18, eShowObjects = 0x18,
eShowLights = 0x20, eShowLights = 0x20,
eShowSky = 0x40, eShowSky = 0x40,
eShowAll = 0x7F eShowSkeletons = 0x80,
eShowAll = 0xFFFFFFFF
}; };
DECLARE_FLAGS(EShowFlag, FShowFlags) DECLARE_FLAGS(EShowFlag, FShowFlags)

View File

@ -178,6 +178,14 @@ void CBasicViewport::contextMenuEvent(QContextMenuEvent *pEvent)
pEvent->ignore(); pEvent->ignore();
} }
void CBasicViewport::SetShowFlag(EShowFlag Flag, bool Visible)
{
if (Visible)
mViewInfo.ShowFlags |= Flag;
else
mViewInfo.ShowFlags &= ~Flag;
}
void CBasicViewport::SetGameMode(bool Enabled) void CBasicViewport::SetGameMode(bool Enabled)
{ {
mViewInfo.GameMode = Enabled; mViewInfo.GameMode = Enabled;

View File

@ -52,6 +52,7 @@ public:
void focusOutEvent(QFocusEvent *pEvent); void focusOutEvent(QFocusEvent *pEvent);
void contextMenuEvent(QContextMenuEvent *pEvent); void contextMenuEvent(QContextMenuEvent *pEvent);
void SetShowFlag(EShowFlag Flag, bool Visible);
void SetGameMode(bool Enabled); void SetGameMode(bool Enabled);
void SetCursorState(const QCursor& rkCursor); void SetCursorState(const QCursor& rkCursor);
void SetCursorVisible(bool Visible); void SetCursorVisible(bool Visible);

View File

@ -42,14 +42,6 @@ void CSceneViewport::SetScene(INodeEditor *pEditor, CScene *pScene)
mpScene = pScene; mpScene = pScene;
} }
void CSceneViewport::SetShowFlag(EShowFlag Flag, bool Visible)
{
if (Visible)
mViewInfo.ShowFlags |= Flag;
else
mViewInfo.ShowFlags &= ~Flag;
}
void CSceneViewport::SetShowWorld(bool Visible) void CSceneViewport::SetShowWorld(bool Visible)
{ {
if (mRenderingMergedWorld) if (mRenderingMergedWorld)

View File

@ -47,7 +47,6 @@ public:
CSceneViewport(QWidget *pParent = 0); CSceneViewport(QWidget *pParent = 0);
~CSceneViewport(); ~CSceneViewport();
void SetScene(INodeEditor *pEditor, CScene *pScene); void SetScene(INodeEditor *pEditor, CScene *pScene);
void SetShowFlag(EShowFlag Flag, bool Visible);
void SetShowWorld(bool Visible); void SetShowWorld(bool Visible);
void SetRenderMergedWorld(bool RenderMerged); void SetRenderMergedWorld(bool RenderMerged);
FShowFlags ShowFlags() const; FShowFlags ShowFlags() const;

View File

@ -39,6 +39,7 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(HoverBoneChanged(u32))); connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(HoverBoneChanged(u32)));
connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open())); connect(ui->ActionOpen, SIGNAL(triggered()), this, SLOT(Open()));
connect(ui->ActionShowSkeleton, SIGNAL(toggled(bool)), this, SLOT(ToggleSkeletonVisible(bool)));
connect(mpCharComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveCharacterIndex(int))); connect(mpCharComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveCharacterIndex(int)));
connect(mpAnimComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveAnimation(int))); connect(mpAnimComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveAnimation(int)));
@ -143,6 +144,11 @@ void CCharacterEditor::Open()
gResCache.Clean(); gResCache.Clean();
} }
void CCharacterEditor::ToggleSkeletonVisible(bool Visible)
{
ui->Viewport->SetShowFlag(eShowSkeletons, Visible);
}
void CCharacterEditor::RefreshViewport() void CCharacterEditor::RefreshViewport()
{ {
UpdateAnimTime(); UpdateAnimTime();
@ -171,7 +177,7 @@ void CCharacterEditor::SetActiveAnimation(int AnimIndex)
mLastAnimUpdate = CTimer::GlobalTime(); mLastAnimUpdate = CTimer::GlobalTime();
ui->AnimSlider->blockSignals(true); ui->AnimSlider->blockSignals(true);
ui->AnimSlider->setMaximum((int) (mpSet->Animation(AnimIndex)->Duration() * 1000)); ui->AnimSlider->setMaximum((int) (CurrentAnimation() ? CurrentAnimation()->Duration() * 1000 : 0));
ui->AnimSlider->blockSignals(false); ui->AnimSlider->blockSignals(false);
SetAnimTime(0.f); SetAnimTime(0.f);

View File

@ -28,6 +28,7 @@ class CCharacterEditor : public QMainWindow
TResPtr<CAnimSet> mpSet; TResPtr<CAnimSet> mpSet;
u32 mCurrentChar; u32 mCurrentChar;
u32 mCurrentAnim; u32 mCurrentAnim;
bool mShowSkeleton;
// Playback Controls // Playback Controls
double mLastAnimUpdate; double mLastAnimUpdate;
@ -44,6 +45,7 @@ public:
public slots: public slots:
void Open(); void Open();
void ToggleSkeletonVisible(bool Visible);
void RefreshViewport(); void RefreshViewport();
void HoverBoneChanged(u32 BoneID); void HoverBoneChanged(u32 BoneID);
void SetActiveCharacterIndex(int CharIndex); void SetActiveCharacterIndex(int CharIndex);

View File

@ -154,6 +154,8 @@
<bool>false</bool> <bool>false</bool>
</attribute> </attribute>
<addaction name="ActionOpen"/> <addaction name="ActionOpen"/>
<addaction name="separator"/>
<addaction name="ActionShowSkeleton"/>
</widget> </widget>
<action name="ActionOpen"> <action name="ActionOpen">
<property name="icon"> <property name="icon">
@ -170,6 +172,17 @@
<string>Ctrl+O</string> <string>Ctrl+O</string>
</property> </property>
</action> </action>
<action name="ActionShowSkeleton">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Show Skeleton</string>
</property>
<property name="toolTip">
<string>Show Skeleton</string>
</property>
</action>
</widget> </widget>
<customwidgets> <customwidgets>
<customwidget> <customwidget>

View File

@ -9,6 +9,7 @@ CCharacterEditorViewport::CCharacterEditorViewport(QWidget *pParent /*= 0*/)
mpRenderer->SetClearColor(CColor(0.3f, 0.3f, 0.3f)); mpRenderer->SetClearColor(CColor(0.3f, 0.3f, 0.3f));
mpRenderer->ToggleGrid(true); mpRenderer->ToggleGrid(true);
mViewInfo.ShowFlags = eShowNone; // The mesh doesn't check any show flags so this just disables the skeleton.
mViewInfo.pRenderer = mpRenderer; mViewInfo.pRenderer = mpRenderer;
mViewInfo.pScene = nullptr; mViewInfo.pScene = nullptr;
mViewInfo.GameMode = false; mViewInfo.GameMode = false;

View File

@ -22,7 +22,7 @@ CVector2f::CVector2f(IInputStream& rInput)
Y = rInput.ReadFloat(); Y = rInput.ReadFloat();
} }
void CVector2f::Write(IOutputStream& rOutput) void CVector2f::Write(IOutputStream& rOutput) const
{ {
rOutput.WriteFloat(X); rOutput.WriteFloat(X);
rOutput.WriteFloat(Y); rOutput.WriteFloat(Y);

View File

@ -12,7 +12,7 @@ public:
CVector2f(float XY); CVector2f(float XY);
CVector2f(float _X, float _Y); CVector2f(float _X, float _Y);
CVector2f(IInputStream& rInput); CVector2f(IInputStream& rInput);
void Write(IOutputStream& rOutput); void Write(IOutputStream& rOutput) const;
float Magnitude() const; float Magnitude() const;
float SquaredMagnitude() const; float SquaredMagnitude() const;

View File

@ -29,7 +29,7 @@ CVector3f::CVector3f(IInputStream& rInput)
Z = rInput.ReadFloat(); Z = rInput.ReadFloat();
} }
void CVector3f::Write(IOutputStream& rOutput) void CVector3f::Write(IOutputStream& rOutput) const
{ {
rOutput.WriteFloat(X); rOutput.WriteFloat(X);
rOutput.WriteFloat(Y); rOutput.WriteFloat(Y);

View File

@ -19,7 +19,7 @@ public:
CVector3f(float XYZ); CVector3f(float XYZ);
CVector3f(float _X, float _Y, float _Z); CVector3f(float _X, float _Y, float _Z);
CVector3f(IInputStream& rInput); CVector3f(IInputStream& rInput);
void Write(IOutputStream& rOutput); void Write(IOutputStream& rOutput) const;
// Swizzle // Swizzle
CVector2f XY(); CVector2f XY();

View File

@ -37,20 +37,20 @@ float RadiansToDegrees(float Rad)
return Rad * 180.f / skPi; return Rad * 180.f / skPi;
} }
std::pair<bool,float> RayPlaneIntersection(const CRay& rkRay, const CPlane& plane) std::pair<bool,float> RayPlaneIntersection(const CRay& rkRay, const CPlane& rkPlane)
{ {
// Code based on ray/plane intersect code from Ogre // Code based on ray/plane intersect code from Ogre
// https://bitbucket.org/sinbad/ogre/src/197116fd2ac62c57cdeed1666f9866c3dddd4289/OgreMain/src/OgreMath.cpp?at=default#OgreMath.cpp-350 // https://bitbucket.org/sinbad/ogre/src/197116fd2ac62c57cdeed1666f9866c3dddd4289/OgreMain/src/OgreMath.cpp?at=default#OgreMath.cpp-350
// Are ray and plane parallel? // Are ray and plane parallel?
float Denom = plane.Normal().Dot(rkRay.Direction()); float Denom = rkPlane.Normal().Dot(rkRay.Direction());
if (Abs(Denom) < FLT_EPSILON) if (Abs(Denom) < FLT_EPSILON)
return std::pair<bool,float>(false, 0.f); return std::pair<bool,float>(false, 0.f);
// Not parallel // Not parallel
float nom = plane.Normal().Dot(rkRay.Origin()) + plane.Dist(); float Nom = rkPlane.Normal().Dot(rkRay.Origin()) + rkPlane.Dist();
float t = -(nom / Denom); float t = -(Nom / Denom);
return std::pair<bool,float>(t >= 0.f, t); return std::pair<bool,float>(t >= 0.f, t);
} }