mirror of
https://github.com/AxioDL/PrimeWorldEditor.git
synced 2025-12-18 01:15:26 +00:00
Added support for model skinning
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#ifndef ASSERT_H
|
||||
#define ASSERT_H
|
||||
|
||||
#include "Log.h"
|
||||
#include "TString.h"
|
||||
#include <cstdlib>
|
||||
#include <string.h>
|
||||
|
||||
@@ -47,7 +47,7 @@ void CColor::SetIntegral(u8 _R, u8 _G, u8 _B, u8 _A /*= 255*/)
|
||||
A = _A / 255.f;
|
||||
}
|
||||
|
||||
void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/)
|
||||
void CColor::Write(IOutputStream &rOutput, bool Integral /*= false*/) const
|
||||
{
|
||||
if (Integral)
|
||||
{
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
CColor(float _R, float _G, float _B, float A = 1.f);
|
||||
void SetIntegral(u8 RGBA);
|
||||
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 ToLongARGB() const;
|
||||
|
||||
@@ -68,7 +68,8 @@ HEADERS += \
|
||||
Flags.h \
|
||||
TString.h \
|
||||
types.h \
|
||||
Log.h
|
||||
Log.h \
|
||||
Assert.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
|
||||
@@ -29,7 +29,9 @@ public:
|
||||
inline TFlags operator&(u32 Mask) const { return TFlags(FlagEnum(mValue & Mask)); }
|
||||
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 HasAllFlags(TFlags Flags) const { return ((mValue & Flags) == Flags); }
|
||||
};
|
||||
#define DECLARE_FLAGS(Enum, FlagTypeName) typedef TFlags<Enum> FlagTypeName;
|
||||
|
||||
|
||||
@@ -93,6 +93,13 @@ void Warning(const TString& rkMessage)
|
||||
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)
|
||||
{
|
||||
Write(rkFilename + " : " + rkMessage);
|
||||
|
||||
@@ -10,6 +10,7 @@ bool InitLog(const TString& rkFilename);
|
||||
void Write(const TString& rkMessage);
|
||||
void Error(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, unsigned long Offset, const TString& rkMessage);
|
||||
void FileError(const TString& rkFilename, const TString& rkMessage);
|
||||
|
||||
@@ -191,7 +191,9 @@ HEADERS += \
|
||||
Scene/CCharacterNode.h \
|
||||
Resource/CAnimation.h \
|
||||
Resource/Factory/CAnimationLoader.h \
|
||||
Render/CBoneTransformData.h
|
||||
Render/CBoneTransformData.h \
|
||||
Resource/CSkin.h \
|
||||
Resource/Factory/CSkinLoader.h
|
||||
|
||||
# Source Files
|
||||
SOURCES += \
|
||||
@@ -274,4 +276,6 @@ SOURCES += \
|
||||
Resource/Factory/CSkeletonLoader.cpp \
|
||||
Scene/CCharacterNode.cpp \
|
||||
Resource/CAnimation.cpp \
|
||||
Resource/Factory/CAnimationLoader.cpp
|
||||
Resource/Factory/CAnimationLoader.cpp \
|
||||
Resource/Factory/CSkinLoader.cpp \
|
||||
Resource/Model/EVertexAttribute.cpp
|
||||
|
||||
@@ -157,6 +157,7 @@ bool CShader::LinkShaders()
|
||||
mVertexBlockIndex = GetUniformBlockIndex("VertexBlock");
|
||||
mPixelBlockIndex = GetUniformBlockIndex("PixelBlock");
|
||||
mLightBlockIndex = GetUniformBlockIndex("LightBlock");
|
||||
mBoneTransformBlockIndex = GetUniformBlockIndex("BoneTransformBlock");
|
||||
|
||||
mProgramExists = true;
|
||||
return true;
|
||||
@@ -193,6 +194,7 @@ void CShader::SetCurrent()
|
||||
glUniformBlockBinding(mProgram, mVertexBlockIndex, CGraphics::VertexBlockBindingPoint());
|
||||
glUniformBlockBinding(mProgram, mPixelBlockIndex, CGraphics::PixelBlockBindingPoint());
|
||||
glUniformBlockBinding(mProgram, mLightBlockIndex, CGraphics::LightBlockBindingPoint());
|
||||
glUniformBlockBinding(mProgram, mBoneTransformBlockIndex, CGraphics::BoneTransformBlockBindingPoint());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@ class CShader
|
||||
GLuint mVertexBlockIndex;
|
||||
GLuint mPixelBlockIndex;
|
||||
GLuint mLightBlockIndex;
|
||||
GLuint mBoneTransformBlockIndex;
|
||||
|
||||
static CShader* spCurrentShader;
|
||||
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
#include "CShaderGenerator.h"
|
||||
#include <Common/Assert.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <GL/glew.h>
|
||||
|
||||
const TString gkCoordSrc[] = {
|
||||
"RawPosition.xyz",
|
||||
"RawNormal.xyz",
|
||||
"ModelSpacePos.xyz",
|
||||
"ModelSpaceNormal.xyz",
|
||||
"0.0, 0.0, 0.0",
|
||||
"0.0, 0.0, 0.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;
|
||||
|
||||
@@ -153,126 +154,188 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
||||
|
||||
// Input
|
||||
ShaderCode << "// Input\n";
|
||||
FVertexDescription VtxDesc = Mat.VtxDesc();
|
||||
if (VtxDesc & ePosition) ShaderCode << "layout(location = 0) in vec3 RawPosition;\n";
|
||||
if (VtxDesc & eNormal) ShaderCode << "layout(location = 1) in vec3 RawNormal;\n";
|
||||
if (VtxDesc & eColor0) ShaderCode << "layout(location = 2) in vec4 RawColor0;\n";
|
||||
if (VtxDesc & eColor1) ShaderCode << "layout(location = 3) in vec4 RawColor1;\n";
|
||||
if (VtxDesc & eTex0) ShaderCode << "layout(location = 4) in vec2 RawTex0;\n";
|
||||
if (VtxDesc & eTex1) ShaderCode << "layout(location = 5) in vec2 RawTex1;\n";
|
||||
if (VtxDesc & eTex2) ShaderCode << "layout(location = 6) in vec2 RawTex2;\n";
|
||||
if (VtxDesc & eTex3) ShaderCode << "layout(location = 7) in vec2 RawTex3;\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";
|
||||
FVertexDescription VtxDesc = rkMat.VtxDesc();
|
||||
ASSERT(VtxDesc & ePosition);
|
||||
|
||||
ShaderCode << "layout(location = 0) in vec3 RawPosition;\n";
|
||||
if (VtxDesc & eNormal) ShaderCode << "layout(location = 1) in vec3 RawNormal;\n";
|
||||
if (VtxDesc & eColor0) ShaderCode << "layout(location = 2) in vec4 RawColor0;\n";
|
||||
if (VtxDesc & eColor1) ShaderCode << "layout(location = 3) in vec4 RawColor1;\n";
|
||||
if (VtxDesc & eTex0) ShaderCode << "layout(location = 4) in vec2 RawTex0;\n";
|
||||
if (VtxDesc & eTex1) ShaderCode << "layout(location = 5) in vec2 RawTex1;\n";
|
||||
if (VtxDesc & eTex2) ShaderCode << "layout(location = 6) in vec2 RawTex2;\n";
|
||||
if (VtxDesc & eTex3) ShaderCode << "layout(location = 7) in vec2 RawTex3;\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";
|
||||
|
||||
// Output
|
||||
ShaderCode << "// Output\n";
|
||||
if (VtxDesc & eNormal) ShaderCode << "out vec3 Normal;\n";
|
||||
if (VtxDesc & eColor0) ShaderCode << "out vec4 Color0;\n";
|
||||
if (VtxDesc & eColor1) ShaderCode << "out vec4 Color1;\n";
|
||||
if (VtxDesc & eNormal) ShaderCode << "out vec3 Normal;\n";
|
||||
if (VtxDesc & eColor0) ShaderCode << "out vec4 Color0;\n";
|
||||
if (VtxDesc & eColor1) ShaderCode << "out vec4 Color1;\n";
|
||||
|
||||
for (u32 iPass = 0; iPass < Mat.PassCount(); iPass++)
|
||||
if (Mat.Pass(iPass)->TexCoordSource() != 0xFF)
|
||||
for (u32 iPass = 0; iPass < rkMat.PassCount(); iPass++)
|
||||
if (rkMat.Pass(iPass)->TexCoordSource() != 0xFF)
|
||||
ShaderCode << "out vec3 Tex" << iPass << ";\n";
|
||||
|
||||
ShaderCode << "out vec4 COLOR0A0;\n"
|
||||
<< "out vec4 COLOR1A1;\n";
|
||||
ShaderCode << "\n";
|
||||
ShaderCode << "out vec4 COLOR0A0;\n"
|
||||
<< "out vec4 COLOR1A1;\n";
|
||||
ShaderCode << "\n";
|
||||
|
||||
// Uniforms
|
||||
ShaderCode << "// Uniforms\n"
|
||||
<< "layout(std140) uniform MVPBlock\n"
|
||||
<< "{\n"
|
||||
<< " mat4 ModelMtx;\n"
|
||||
<< " mat4 ViewMtx;\n"
|
||||
<< " mat4 ProjMtx;\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "layout(std140) uniform VertexBlock\n"
|
||||
<< "{\n"
|
||||
<< " mat4 TexMtx[10];\n"
|
||||
<< " mat4 PostMtx[20];\n"
|
||||
<< " vec4 COLOR0_Amb;\n"
|
||||
<< " vec4 COLOR0_Mat;\n"
|
||||
<< " vec4 COLOR1_Amb;\n"
|
||||
<< " vec4 COLOR1_Mat;\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "struct GXLight\n"
|
||||
<< "{\n"
|
||||
<< " vec4 Position;\n"
|
||||
<< " vec4 Direction;\n"
|
||||
<< " vec4 Color;\n"
|
||||
<< " vec4 DistAtten;\n"
|
||||
<< " vec4 AngleAtten;\n"
|
||||
<< "};\n"
|
||||
<< "layout(std140) uniform LightBlock {\n"
|
||||
<< " GXLight Lights[8];\n"
|
||||
<< "};\n"
|
||||
<< "uniform int NumLights;\n"
|
||||
<< "\n";
|
||||
ShaderCode << "// Uniforms\n"
|
||||
<< "layout(std140) uniform MVPBlock\n"
|
||||
<< "{\n"
|
||||
<< " mat4 ModelMtx;\n"
|
||||
<< " mat4 ViewMtx;\n"
|
||||
<< " mat4 ProjMtx;\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "layout(std140) uniform VertexBlock\n"
|
||||
<< "{\n"
|
||||
<< " mat4 TexMtx[10];\n"
|
||||
<< " mat4 PostMtx[20];\n"
|
||||
<< " vec4 COLOR0_Amb;\n"
|
||||
<< " vec4 COLOR0_Mat;\n"
|
||||
<< " vec4 COLOR1_Amb;\n"
|
||||
<< " vec4 COLOR1_Mat;\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "struct GXLight\n"
|
||||
<< "{\n"
|
||||
<< " vec4 Position;\n"
|
||||
<< " vec4 Direction;\n"
|
||||
<< " vec4 Color;\n"
|
||||
<< " vec4 DistAtten;\n"
|
||||
<< " vec4 AngleAtten;\n"
|
||||
<< "};\n"
|
||||
<< "\n"
|
||||
<< "layout(std140) uniform LightBlock\n"
|
||||
<< "{\n"
|
||||
<< " GXLight Lights[8];\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
|
||||
ShaderCode << "// Main\n"
|
||||
<< "void main()\n"
|
||||
<< "{\n"
|
||||
<< " mat4 MV = ModelMtx * ViewMtx;\n"
|
||||
<< " mat4 MVP = MV * ProjMtx;\n";
|
||||
ShaderCode << "// Main\n"
|
||||
<< "void main()\n"
|
||||
<< "{\n"
|
||||
<< " mat4 MV = ModelMtx * ViewMtx;\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 & 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
|
||||
ShaderCode << "\n"
|
||||
<< " // Dynamic Lighting\n";
|
||||
ShaderCode << "\n"
|
||||
<< " // Dynamic Lighting\n";
|
||||
|
||||
// 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
|
||||
if (Mat.IsLightingEnabled())
|
||||
if (rkMat.IsLightingEnabled())
|
||||
{
|
||||
ShaderCode << " vec4 Illum = vec4(0.0);\n"
|
||||
<< " vec3 PositionMV = vec3(vec4(RawPosition, 1.0) * MV);\n"
|
||||
<< " \n"
|
||||
<< " for (int iLight = 0; iLight < NumLights; iLight++)\n"
|
||||
<< " {\n"
|
||||
<< " vec3 LightPosMV = vec3(Lights[iLight].Position * ViewMtx);\n"
|
||||
<< " vec3 LightDirMV = normalize(Lights[iLight].Direction.xyz * inverse(transpose(mat3(ViewMtx))));\n"
|
||||
<< " vec3 LightDist = LightPosMV.xyz - PositionMV.xyz;\n"
|
||||
<< " float DistSquared = dot(LightDist, LightDist);\n"
|
||||
<< " float Dist = sqrt(DistSquared);\n"
|
||||
<< " LightDist /= Dist;\n"
|
||||
<< " vec3 AngleAtten = Lights[iLight].AngleAtten.xyz;\n"
|
||||
<< " AngleAtten = vec3(AngleAtten.x, AngleAtten.y, AngleAtten.z);\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"
|
||||
<< " float DiffuseAtten = max(0, dot(Normal, LightDist));\n"
|
||||
<< " Illum += (Atten * DiffuseAtten * Lights[iLight].Color);\n"
|
||||
<< " }\n"
|
||||
<< " COLOR0A0 = COLOR0_Mat * (Illum + COLOR0_Amb);\n"
|
||||
<< " COLOR1A1 = COLOR1_Mat * (Illum + COLOR1_Amb);\n"
|
||||
<< " \n";
|
||||
ShaderCode << " vec4 Illum = vec4(0.0);\n"
|
||||
<< " vec3 PositionMV = vec3(vec4(ModelSpacePos, 1.0) * MV);\n"
|
||||
<< " \n"
|
||||
<< " for (int iLight = 0; iLight < NumLights; iLight++)\n"
|
||||
<< " {\n"
|
||||
<< " vec3 LightPosMV = vec3(Lights[iLight].Position * ViewMtx);\n"
|
||||
<< " vec3 LightDirMV = normalize(Lights[iLight].Direction.xyz * inverse(transpose(mat3(ViewMtx))));\n"
|
||||
<< " vec3 LightDist = LightPosMV.xyz - PositionMV.xyz;\n"
|
||||
<< " float DistSquared = dot(LightDist, LightDist);\n"
|
||||
<< " float Dist = sqrt(DistSquared);\n"
|
||||
<< " LightDist /= Dist;\n"
|
||||
<< " vec3 AngleAtten = Lights[iLight].AngleAtten.xyz;\n"
|
||||
<< " AngleAtten = vec3(AngleAtten.x, AngleAtten.y, AngleAtten.z);\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"
|
||||
<< " float DiffuseAtten = max(0, dot(Normal, LightDist));\n"
|
||||
<< " Illum += (Atten * DiffuseAtten * Lights[iLight].Color);\n"
|
||||
<< " }\n"
|
||||
<< " COLOR0A0 = COLOR0_Mat * (Illum + COLOR0_Amb);\n"
|
||||
<< " COLOR1A1 = COLOR1_Mat * (Illum + COLOR1_Amb);\n"
|
||||
<< " \n";
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
ShaderCode << " COLOR0A0 = COLOR0_Mat;\n"
|
||||
<< " COLOR1A1 = COLOR1_Mat;\n"
|
||||
<< "\n";
|
||||
ShaderCode << " COLOR0A0 = COLOR0_Mat;\n"
|
||||
<< " COLOR1A1 = COLOR1_Mat;\n"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
// Texture coordinate generation
|
||||
ShaderCode << " \n"
|
||||
<< " // TexGen\n";
|
||||
ShaderCode << " \n"
|
||||
<< " // TexGen\n";
|
||||
|
||||
u32 PassCount = Mat.PassCount();
|
||||
u32 PassCount = rkMat.PassCount();
|
||||
|
||||
for (u32 iPass = 0; iPass < PassCount; iPass++)
|
||||
{
|
||||
CMaterialPass *pPass = Mat.Pass(iPass);
|
||||
CMaterialPass *pPass = rkMat.Pass(iPass);
|
||||
if (pPass->TexCoordSource() == 0xFF) continue;
|
||||
|
||||
EUVAnimMode AnimMode = pPass->AnimMode();
|
||||
@@ -288,8 +351,8 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
||||
if ((AnimMode < 2) || (AnimMode > 5))
|
||||
{
|
||||
// Normalization + Post-Transform
|
||||
ShaderCode << " Tex" << iPass << " = normalize(Tex" << iPass << ");\n";
|
||||
ShaderCode << " Tex" << iPass << " = vec3(vec4(Tex" << iPass << ", 1.0) * PostMtx[" << iPass << "]).xyz;\n";
|
||||
ShaderCode << " Tex" << iPass << " = normalize(Tex" << iPass << ");\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());
|
||||
}
|
||||
|
||||
bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
|
||||
bool CShaderGenerator::CreatePixelShader(const CMaterial& rkMat)
|
||||
{
|
||||
std::stringstream ShaderCode;
|
||||
ShaderCode << "#version 330 core\n"
|
||||
<< "\n";
|
||||
|
||||
FVertexDescription VtxDesc = Mat.VtxDesc();
|
||||
FVertexDescription VtxDesc = rkMat.VtxDesc();
|
||||
if (VtxDesc & ePosition) ShaderCode << "in vec3 Position;\n";
|
||||
if (VtxDesc & eNormal) ShaderCode << "in vec3 Normal;\n";
|
||||
if (VtxDesc & eColor0) ShaderCode << "in vec4 Color0;\n";
|
||||
if (VtxDesc & eColor1) ShaderCode << "in vec4 Color1;\n";
|
||||
|
||||
u32 PassCount = Mat.PassCount();
|
||||
u32 PassCount = rkMat.PassCount();
|
||||
|
||||
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 vec4 COLOR0A0;\n"
|
||||
@@ -333,7 +396,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
|
||||
<< "};\n\n";
|
||||
|
||||
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 <<"\n";
|
||||
@@ -351,7 +414,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
|
||||
bool Lightmap = false;
|
||||
for (u32 iPass = 0; iPass < PassCount; iPass++)
|
||||
{
|
||||
const CMaterialPass *pPass = Mat.Pass(iPass);
|
||||
const CMaterialPass *pPass = rkMat.Pass(iPass);
|
||||
CFourCC PassType = pPass->Type();
|
||||
|
||||
ShaderCode << " // TEV Stage " << iPass << " - " << PassType.ToString() << "\n";
|
||||
@@ -377,7 +440,7 @@ bool CShaderGenerator::CreatePixelShader(const CMaterial& Mat)
|
||||
|
||||
// Apply lightmap multiplier
|
||||
if ( (PassType == "DIFF") ||
|
||||
(PassType == "CUST" && (Mat.Options() & CMaterial::eLightmap) && iPass == 0) )
|
||||
(PassType == "CUST" && (rkMat.Options() & CMaterial::eLightmap) && iPass == 0) )
|
||||
ShaderCode << " * LightmapMultiplier";
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
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"
|
||||
<< " else Prev.a = 1.0;\n\n";
|
||||
|
||||
@@ -45,10 +45,17 @@ public:
|
||||
Unbind();
|
||||
}
|
||||
|
||||
void Buffer(void *pData)
|
||||
void Buffer(const void *pkData)
|
||||
{
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@ CVertexBuffer::~CVertexBuffer()
|
||||
CVertexArrayManager::DeleteAllArraysForVBO(this);
|
||||
|
||||
if (mBuffered)
|
||||
glDeleteBuffers(12, mAttribBuffers);
|
||||
glDeleteBuffers(14, mAttribBuffers);
|
||||
}
|
||||
|
||||
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]);
|
||||
|
||||
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++)
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -51,24 +58,39 @@ u16 CVertexBuffer::AddIfUnique(const CVertex& rkVtx, u16 Start)
|
||||
if (mVtxDesc & ePosition)
|
||||
if (rkVtx.Position != mPositions[iVert]) Unique = true;
|
||||
|
||||
if ((!Unique) && (mVtxDesc & eNormal))
|
||||
if (!Unique && (mVtxDesc & eNormal))
|
||||
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 ((!Unique) && (mVtxDesc & eColor1))
|
||||
if (!Unique && (mVtxDesc & eColor1))
|
||||
if (rkVtx.Color[1] != mColors[1][iVert]) Unique = true;
|
||||
|
||||
if (!Unique)
|
||||
for (u32 iTex = 0; iTex < 8; iTex++)
|
||||
if ((mVtxDesc & (eTex0 << (iTex * 2))))
|
||||
if ((mVtxDesc & (eTex0 << iTex)))
|
||||
if (rkVtx.Tex[iTex] != mTexCoords[iTex][iVert])
|
||||
{
|
||||
Unique = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -93,14 +115,20 @@ void CVertexBuffer::Reserve(u16 Size)
|
||||
mColors[1].reserve(ReserveSize);
|
||||
|
||||
for (u32 iTex = 0; iTex < 8; iTex++)
|
||||
if (mVtxDesc & (eTex0 << (iTex * 2)))
|
||||
if (mVtxDesc & (eTex0 << iTex))
|
||||
mTexCoords[iTex].reserve(ReserveSize);
|
||||
|
||||
if (mVtxDesc & eBoneIndices)
|
||||
mBoneIndices.reserve(ReserveSize);
|
||||
|
||||
if (mVtxDesc & eBoneWeights)
|
||||
mBoneWeights.reserve(ReserveSize);
|
||||
}
|
||||
|
||||
void CVertexBuffer::Clear()
|
||||
{
|
||||
if (mBuffered)
|
||||
glDeleteBuffers(12, mAttribBuffers);
|
||||
glDeleteBuffers(14, mAttribBuffers);
|
||||
|
||||
mBuffered = false;
|
||||
mPositions.clear();
|
||||
@@ -110,6 +138,9 @@ void CVertexBuffer::Clear()
|
||||
|
||||
for (u32 iTex = 0; iTex < 8; iTex++)
|
||||
mTexCoords[iTex].clear();
|
||||
|
||||
mBoneIndices.clear();
|
||||
mBoneWeights.clear();
|
||||
}
|
||||
|
||||
void CVertexBuffer::Buffer()
|
||||
@@ -117,16 +148,16 @@ void CVertexBuffer::Buffer()
|
||||
// Make sure we don't end up with two buffers for the same data...
|
||||
if (mBuffered)
|
||||
{
|
||||
glDeleteBuffers(12, mAttribBuffers);
|
||||
glDeleteBuffers(14, mAttribBuffers);
|
||||
mBuffered = false;
|
||||
}
|
||||
|
||||
// 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);
|
||||
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);
|
||||
}
|
||||
|
||||
else
|
||||
else if (iAttrib < 12)
|
||||
{
|
||||
u8 Index = (u8) (iAttrib - 4);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||
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;
|
||||
@@ -185,6 +228,12 @@ void CVertexBuffer::SetVertexDesc(FVertexDescription Desc)
|
||||
mVtxDesc = Desc;
|
||||
}
|
||||
|
||||
void CVertexBuffer::SetSkin(CSkin *pSkin)
|
||||
{
|
||||
Clear();
|
||||
mpSkin = pSkin;
|
||||
}
|
||||
|
||||
u32 CVertexBuffer::Size()
|
||||
{
|
||||
return mPositions.size();
|
||||
@@ -196,9 +245,9 @@ GLuint CVertexBuffer::CreateVAO()
|
||||
glGenVertexArrays(1, &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);
|
||||
if (!HasAttrib) continue;
|
||||
|
||||
@@ -216,12 +265,26 @@ GLuint CVertexBuffer::CreateVAO()
|
||||
glEnableVertexAttribArray(iAttrib);
|
||||
}
|
||||
|
||||
else
|
||||
else if (iAttrib < 12)
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, mAttribBuffers[iAttrib]);
|
||||
glVertexAttribPointer(iAttrib, 2, GL_FLOAT, GL_FALSE, sizeof(CVector2f), (void*) 0);
|
||||
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);
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#ifndef 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/EVertexAttribute.h"
|
||||
#include <vector>
|
||||
@@ -8,13 +10,16 @@
|
||||
|
||||
class CVertexBuffer
|
||||
{
|
||||
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.
|
||||
std::vector<CVector3f> mPositions; // Vector of vertex positions
|
||||
std::vector<CVector3f> mNormals; // Vector of vertex normals
|
||||
std::vector<CColor> mColors[2]; // Vectors of vertex colors
|
||||
std::vector<CVector2f> mTexCoords[8]; // Vectors of texture coordinates
|
||||
bool mBuffered; // Bool value that indicates whether the attributes have been buffered.
|
||||
FVertexDescription mVtxDesc; // Flags that indicate what vertex attributes are enabled on this vertex buffer
|
||||
GLuint mAttribBuffers[14]; // Separate GL buffer for each attribute to allow not tracking unused attribs. No support for matrix indices currently.
|
||||
TResPtr<CSkin> mpSkin; // Skin for skinned models. Null on unskinned models;
|
||||
std::vector<CVector3f> mPositions; // Vector of vertex positions
|
||||
std::vector<CVector3f> mNormals; // Vector of vertex normals
|
||||
std::vector<CColor> mColors[2]; // Vectors of vertex colors
|
||||
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:
|
||||
CVertexBuffer();
|
||||
@@ -30,6 +35,7 @@ public:
|
||||
bool IsBuffered();
|
||||
FVertexDescription VertexDesc();
|
||||
void SetVertexDesc(FVertexDescription Desc);
|
||||
void SetSkin(CSkin *pSkin);
|
||||
u32 Size();
|
||||
GLuint CreateVAO();
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
inline void ResizeToSkeleton(CSkeleton *pSkel) { mBoneMatrices.resize(pSkel ? pSkel->MaxBoneID() + 1 : 0); }
|
||||
inline CTransform4f& BoneMatrix(u32 BoneID) { 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 CTransform4f& operator[](u32 BoneIndex) { return BoneMatrix(BoneIndex); }
|
||||
inline const CTransform4f& operator[](u32 BoneIndex) const { return BoneMatrix(BoneIndex); }
|
||||
|
||||
@@ -8,10 +8,13 @@ CUniformBuffer* CGraphics::mpMVPBlockBuffer;
|
||||
CUniformBuffer* CGraphics::mpVertexBlockBuffer;
|
||||
CUniformBuffer* CGraphics::mpPixelBlockBuffer;
|
||||
CUniformBuffer* CGraphics::mpLightBlockBuffer;
|
||||
CUniformBuffer* CGraphics::mpBoneTransformBuffer;
|
||||
u32 CGraphics::mContextIndices = 0;
|
||||
u32 CGraphics::mActiveContext = -1;
|
||||
bool CGraphics::mInitialized = false;
|
||||
std::vector<CVertexArrayManager*> CGraphics::mVAMs;
|
||||
bool CGraphics::mIdentityBoneTransforms = false;
|
||||
const CSkeleton *CGraphics::mpkCurrentSkeleton = nullptr;
|
||||
|
||||
CGraphics::SMVPBlock CGraphics::sMVPBlock;
|
||||
CGraphics::SVertexBlock CGraphics::sVertexBlock;
|
||||
@@ -44,6 +47,7 @@ void CGraphics::Initialize()
|
||||
mpVertexBlockBuffer = new CUniformBuffer(sizeof(sVertexBlock));
|
||||
mpPixelBlockBuffer = new CUniformBuffer(sizeof(sPixelBlock));
|
||||
mpLightBlockBuffer = new CUniformBuffer(sizeof(sLightBlock));
|
||||
mpBoneTransformBuffer = new CUniformBuffer(sizeof(CTransform4f) * 200);
|
||||
|
||||
sLightMode = eWorldLighting;
|
||||
sNumLights = 0;
|
||||
@@ -55,6 +59,8 @@ void CGraphics::Initialize()
|
||||
mpVertexBlockBuffer->BindBase(1);
|
||||
mpPixelBlockBuffer->BindBase(2);
|
||||
mpLightBlockBuffer->BindBase(3);
|
||||
mpBoneTransformBuffer->BindBase(4);
|
||||
LoadIdentityBoneTransforms();
|
||||
}
|
||||
|
||||
void CGraphics::Shutdown()
|
||||
@@ -66,6 +72,7 @@ void CGraphics::Shutdown()
|
||||
delete mpVertexBlockBuffer;
|
||||
delete mpPixelBlockBuffer;
|
||||
delete mpLightBlockBuffer;
|
||||
delete mpBoneTransformBuffer;
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
@@ -110,6 +117,11 @@ GLuint CGraphics::LightBlockBindingPoint()
|
||||
return 3;
|
||||
}
|
||||
|
||||
GLuint CGraphics::BoneTransformBlockBindingPoint()
|
||||
{
|
||||
return 4;
|
||||
}
|
||||
|
||||
u32 CGraphics::GetContextIndex()
|
||||
{
|
||||
for (u32 iCon = 0; iCon < 32; iCon++)
|
||||
@@ -178,3 +190,31 @@ void CGraphics::SetIdentityMVP()
|
||||
sMVPBlock.ViewMatrix = 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#ifndef CGRAPHICS_H
|
||||
#define CGRAPHICS_H
|
||||
|
||||
#include "CBoneTransformData.h"
|
||||
#include "Core/OpenGL/CUniformBuffer.h"
|
||||
#include "Core/OpenGL/CVertexArrayManager.h"
|
||||
#include "Core/Resource/CLight.h"
|
||||
@@ -23,11 +24,15 @@ class CGraphics
|
||||
static CUniformBuffer *mpVertexBlockBuffer;
|
||||
static CUniformBuffer *mpPixelBlockBuffer;
|
||||
static CUniformBuffer *mpLightBlockBuffer;
|
||||
static CUniformBuffer *mpBoneTransformBuffer;
|
||||
static u32 mContextIndices;
|
||||
static u32 mActiveContext;
|
||||
static bool mInitialized;
|
||||
static std::vector<CVertexArrayManager*> mVAMs;
|
||||
|
||||
static bool mIdentityBoneTransforms;
|
||||
static const CSkeleton *mpkCurrentSkeleton;
|
||||
|
||||
public:
|
||||
// SMVPBlock
|
||||
struct SMVPBlock
|
||||
@@ -95,6 +100,7 @@ public:
|
||||
static GLuint VertexBlockBindingPoint();
|
||||
static GLuint PixelBlockBindingPoint();
|
||||
static GLuint LightBlockBindingPoint();
|
||||
static GLuint BoneTransformBlockBindingPoint();
|
||||
static u32 GetContextIndex();
|
||||
static u32 GetActiveContext();
|
||||
static void ReleaseContext(u32 Index);
|
||||
@@ -102,6 +108,9 @@ public:
|
||||
static void SetDefaultLighting();
|
||||
static void SetupAmbientColor();
|
||||
static void SetIdentityMVP();
|
||||
static void LoadBoneTransforms(const CBoneTransformData& rkData);
|
||||
static void LoadBoneInverseBindTransforms(CSkeleton *pSkel);
|
||||
static void LoadIdentityBoneTransforms();
|
||||
};
|
||||
|
||||
#endif // CGRAPHICS_H
|
||||
|
||||
@@ -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(); }
|
||||
|
||||
@@ -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; }
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
51
src/Core/Resource/CSkin.h
Normal 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
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -25,6 +25,7 @@ class CMaterialLoader
|
||||
|
||||
CMaterialLoader();
|
||||
~CMaterialLoader();
|
||||
FVertexDescription ConvertToVertexDescription(u32 VertexFlags);
|
||||
|
||||
// Load Functions
|
||||
void ReadPrimeMatSet();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -20,7 +20,8 @@ public:
|
||||
eShortPositions = 0x1,
|
||||
eShortNormals = 0x2,
|
||||
eHasTex1 = 0x4,
|
||||
eHasVisGroups = 0x8
|
||||
eHasVisGroups = 0x8,
|
||||
eSkinnedModel = 0x10
|
||||
};
|
||||
DECLARE_FLAGS(EModelFlag, FModelFlags)
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -12,6 +12,7 @@ class CSkeletonLoader
|
||||
|
||||
CSkeletonLoader() {}
|
||||
void SetLocalBoneCoords(CBone *pBone);
|
||||
void CalculateBoneInverseBindMatrices();
|
||||
|
||||
public:
|
||||
static CSkeleton* LoadCINF(IInputStream& rCINF);
|
||||
|
||||
29
src/Core/Resource/Factory/CSkinLoader.cpp
Normal file
29
src/Core/Resource/Factory/CSkinLoader.cpp
Normal 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;
|
||||
}
|
||||
14
src/Core/Resource/Factory/CSkinLoader.h
Normal file
14
src/Core/Resource/Factory/CSkinLoader.h
Normal 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
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
32
src/Core/Resource/Model/EVertexAttribute.cpp
Normal file
32
src/Core/Resource/Model/EVertexAttribute.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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;
|
||||
// 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);
|
||||
CAnimation *pAnim = mpCharacter->Animation(mActiveAnim);
|
||||
pSkel->UpdateTransform(mTransformData, pAnim, mAnimTime, false);
|
||||
pSkel->Draw(Options, mTransformData);
|
||||
|
||||
// Draw skeleton
|
||||
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*/)
|
||||
|
||||
@@ -83,6 +83,9 @@ void CModelNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInf
|
||||
CGraphics::sPixelBlock.TintColor = TintColor(rkViewInfo);
|
||||
LoadModelMatrix();
|
||||
|
||||
if (mpModel->IsSkinned())
|
||||
CGraphics::LoadIdentityBoneTransforms();
|
||||
|
||||
if (ComponentIndex < 0)
|
||||
mpModel->Draw(Options, mActiveMatSet);
|
||||
else
|
||||
|
||||
@@ -224,7 +224,7 @@ void CSceneNode::DrawRotationArrow() const
|
||||
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();
|
||||
|
||||
@@ -232,7 +232,7 @@ void CSceneNode::AddSurfacesToRenderer(CRenderer *pRenderer, CModel *pModel, u32
|
||||
{
|
||||
CAABox TransformedBox = pModel->GetSurfaceAABox(iSurf).Transformed(Transform());
|
||||
|
||||
if (rkViewInfo.ViewFrustum.BoxInFrustum(TransformedBox))
|
||||
if (!DoFrustumTest || rkViewInfo.ViewFrustum.BoxInFrustum(TransformedBox))
|
||||
{
|
||||
if (!pModel->IsSurfaceTransparent(iSurf, MatSet))
|
||||
pRenderer->AddOpaqueMesh(this, (int) iSurf, TransformedBox, eDrawMesh);
|
||||
|
||||
@@ -79,7 +79,7 @@ public:
|
||||
void LoadLights(const SViewInfo& rkViewInfo);
|
||||
void DrawBoundingBox() 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
|
||||
void Translate(const CVector3f& rkTranslation, ETransformSpace TransformSpace);
|
||||
|
||||
@@ -14,7 +14,8 @@ enum EShowFlag
|
||||
eShowObjects = 0x18,
|
||||
eShowLights = 0x20,
|
||||
eShowSky = 0x40,
|
||||
eShowAll = 0x7F
|
||||
eShowSkeletons = 0x80,
|
||||
eShowAll = 0xFFFFFFFF
|
||||
};
|
||||
DECLARE_FLAGS(EShowFlag, FShowFlags)
|
||||
|
||||
|
||||
@@ -178,6 +178,14 @@ void CBasicViewport::contextMenuEvent(QContextMenuEvent *pEvent)
|
||||
pEvent->ignore();
|
||||
}
|
||||
|
||||
void CBasicViewport::SetShowFlag(EShowFlag Flag, bool Visible)
|
||||
{
|
||||
if (Visible)
|
||||
mViewInfo.ShowFlags |= Flag;
|
||||
else
|
||||
mViewInfo.ShowFlags &= ~Flag;
|
||||
}
|
||||
|
||||
void CBasicViewport::SetGameMode(bool Enabled)
|
||||
{
|
||||
mViewInfo.GameMode = Enabled;
|
||||
|
||||
@@ -52,6 +52,7 @@ public:
|
||||
void focusOutEvent(QFocusEvent *pEvent);
|
||||
void contextMenuEvent(QContextMenuEvent *pEvent);
|
||||
|
||||
void SetShowFlag(EShowFlag Flag, bool Visible);
|
||||
void SetGameMode(bool Enabled);
|
||||
void SetCursorState(const QCursor& rkCursor);
|
||||
void SetCursorVisible(bool Visible);
|
||||
|
||||
@@ -42,14 +42,6 @@ void CSceneViewport::SetScene(INodeEditor *pEditor, CScene *pScene)
|
||||
mpScene = pScene;
|
||||
}
|
||||
|
||||
void CSceneViewport::SetShowFlag(EShowFlag Flag, bool Visible)
|
||||
{
|
||||
if (Visible)
|
||||
mViewInfo.ShowFlags |= Flag;
|
||||
else
|
||||
mViewInfo.ShowFlags &= ~Flag;
|
||||
}
|
||||
|
||||
void CSceneViewport::SetShowWorld(bool Visible)
|
||||
{
|
||||
if (mRenderingMergedWorld)
|
||||
|
||||
@@ -47,7 +47,6 @@ public:
|
||||
CSceneViewport(QWidget *pParent = 0);
|
||||
~CSceneViewport();
|
||||
void SetScene(INodeEditor *pEditor, CScene *pScene);
|
||||
void SetShowFlag(EShowFlag Flag, bool Visible);
|
||||
void SetShowWorld(bool Visible);
|
||||
void SetRenderMergedWorld(bool RenderMerged);
|
||||
FShowFlags ShowFlags() const;
|
||||
|
||||
@@ -39,6 +39,7 @@ CCharacterEditor::CCharacterEditor(QWidget *parent)
|
||||
|
||||
connect(ui->Viewport, SIGNAL(HoverBoneChanged(u32)), this, SLOT(HoverBoneChanged(u32)));
|
||||
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(mpAnimComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetActiveAnimation(int)));
|
||||
|
||||
@@ -143,6 +144,11 @@ void CCharacterEditor::Open()
|
||||
gResCache.Clean();
|
||||
}
|
||||
|
||||
void CCharacterEditor::ToggleSkeletonVisible(bool Visible)
|
||||
{
|
||||
ui->Viewport->SetShowFlag(eShowSkeletons, Visible);
|
||||
}
|
||||
|
||||
void CCharacterEditor::RefreshViewport()
|
||||
{
|
||||
UpdateAnimTime();
|
||||
@@ -171,7 +177,7 @@ void CCharacterEditor::SetActiveAnimation(int AnimIndex)
|
||||
mLastAnimUpdate = CTimer::GlobalTime();
|
||||
|
||||
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);
|
||||
|
||||
SetAnimTime(0.f);
|
||||
|
||||
@@ -28,6 +28,7 @@ class CCharacterEditor : public QMainWindow
|
||||
TResPtr<CAnimSet> mpSet;
|
||||
u32 mCurrentChar;
|
||||
u32 mCurrentAnim;
|
||||
bool mShowSkeleton;
|
||||
|
||||
// Playback Controls
|
||||
double mLastAnimUpdate;
|
||||
@@ -44,6 +45,7 @@ public:
|
||||
|
||||
public slots:
|
||||
void Open();
|
||||
void ToggleSkeletonVisible(bool Visible);
|
||||
void RefreshViewport();
|
||||
void HoverBoneChanged(u32 BoneID);
|
||||
void SetActiveCharacterIndex(int CharIndex);
|
||||
|
||||
@@ -154,6 +154,8 @@
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
<addaction name="ActionOpen"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="ActionShowSkeleton"/>
|
||||
</widget>
|
||||
<action name="ActionOpen">
|
||||
<property name="icon">
|
||||
@@ -170,6 +172,17 @@
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</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>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
|
||||
@@ -9,6 +9,7 @@ CCharacterEditorViewport::CCharacterEditorViewport(QWidget *pParent /*= 0*/)
|
||||
mpRenderer->SetClearColor(CColor(0.3f, 0.3f, 0.3f));
|
||||
mpRenderer->ToggleGrid(true);
|
||||
|
||||
mViewInfo.ShowFlags = eShowNone; // The mesh doesn't check any show flags so this just disables the skeleton.
|
||||
mViewInfo.pRenderer = mpRenderer;
|
||||
mViewInfo.pScene = nullptr;
|
||||
mViewInfo.GameMode = false;
|
||||
|
||||
@@ -22,7 +22,7 @@ CVector2f::CVector2f(IInputStream& rInput)
|
||||
Y = rInput.ReadFloat();
|
||||
}
|
||||
|
||||
void CVector2f::Write(IOutputStream& rOutput)
|
||||
void CVector2f::Write(IOutputStream& rOutput) const
|
||||
{
|
||||
rOutput.WriteFloat(X);
|
||||
rOutput.WriteFloat(Y);
|
||||
|
||||
@@ -12,7 +12,7 @@ public:
|
||||
CVector2f(float XY);
|
||||
CVector2f(float _X, float _Y);
|
||||
CVector2f(IInputStream& rInput);
|
||||
void Write(IOutputStream& rOutput);
|
||||
void Write(IOutputStream& rOutput) const;
|
||||
|
||||
float Magnitude() const;
|
||||
float SquaredMagnitude() const;
|
||||
|
||||
@@ -29,7 +29,7 @@ CVector3f::CVector3f(IInputStream& rInput)
|
||||
Z = rInput.ReadFloat();
|
||||
}
|
||||
|
||||
void CVector3f::Write(IOutputStream& rOutput)
|
||||
void CVector3f::Write(IOutputStream& rOutput) const
|
||||
{
|
||||
rOutput.WriteFloat(X);
|
||||
rOutput.WriteFloat(Y);
|
||||
|
||||
@@ -19,7 +19,7 @@ public:
|
||||
CVector3f(float XYZ);
|
||||
CVector3f(float _X, float _Y, float _Z);
|
||||
CVector3f(IInputStream& rInput);
|
||||
void Write(IOutputStream& rOutput);
|
||||
void Write(IOutputStream& rOutput) const;
|
||||
|
||||
// Swizzle
|
||||
CVector2f XY();
|
||||
|
||||
@@ -37,20 +37,20 @@ float RadiansToDegrees(float Rad)
|
||||
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
|
||||
// https://bitbucket.org/sinbad/ogre/src/197116fd2ac62c57cdeed1666f9866c3dddd4289/OgreMain/src/OgreMath.cpp?at=default#OgreMath.cpp-350
|
||||
|
||||
// Are ray and plane parallel?
|
||||
float Denom = plane.Normal().Dot(rkRay.Direction());
|
||||
float Denom = rkPlane.Normal().Dot(rkRay.Direction());
|
||||
|
||||
if (Abs(Denom) < FLT_EPSILON)
|
||||
return std::pair<bool,float>(false, 0.f);
|
||||
|
||||
// Not parallel
|
||||
float nom = plane.Normal().Dot(rkRay.Origin()) + plane.Dist();
|
||||
float t = -(nom / Denom);
|
||||
float Nom = rkPlane.Normal().Dot(rkRay.Origin()) + rkPlane.Dist();
|
||||
float t = -(Nom / Denom);
|
||||
return std::pair<bool,float>(t >= 0.f, t);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user