Added support for model skinning
This commit is contained in:
parent
c5ff634cd1
commit
98059cedaa
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.
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.
|
@ -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,8 +154,10 @@ 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";
|
||||
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";
|
||||
|
@ -165,6 +168,9 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
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
|
||||
|
@ -173,8 +179,8 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
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"
|
||||
|
@ -208,12 +214,24 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
<< " vec4 DistAtten;\n"
|
||||
<< " vec4 AngleAtten;\n"
|
||||
<< "};\n"
|
||||
<< "layout(std140) uniform LightBlock {\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"
|
||||
|
@ -221,10 +239,55 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
<< " 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"
|
||||
|
@ -232,10 +295,10 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
|
||||
// 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"
|
||||
<< " vec3 PositionMV = vec3(vec4(ModelSpacePos, 1.0) * MV);\n"
|
||||
<< " \n"
|
||||
<< " for (int iLight = 0; iLight < NumLights; iLight++)\n"
|
||||
<< " {\n"
|
||||
|
@ -268,11 +331,11 @@ bool CShaderGenerator::CreateVertexShader(const CMaterial& Mat)
|
|||
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>
|
||||
|
@ -9,11 +11,14 @@
|
|||
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.
|
||||
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:
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -35,30 +62,9 @@ public:
|
|||
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; }
|
||||
};
|
||||
|
||||
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 const CTransform4f& InverseBindMtx() const { return mpSkeleton->BoneInverseBindMatrix(mID); }
|
||||
};
|
||||
|
||||
#endif // CSKELETON_H
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue