From 98059cedaaec56c93e478e4c78801df7834622bd Mon Sep 17 00:00:00 2001 From: parax0 Date: Wed, 27 Apr 2016 04:27:57 -0600 Subject: [PATCH] Added support for model skinning --- resources/editor/RotateClipOutline.cmdl | Bin 4384 -> 4384 bytes resources/editor/RotateX.cmdl | Bin 1344 -> 1344 bytes resources/editor/RotateXYZ.cmdl | Bin 29184 -> 29184 bytes resources/editor/RotateY.cmdl | Bin 1344 -> 1344 bytes resources/editor/RotateZ.cmdl | Bin 1344 -> 1344 bytes resources/editor/ScaleLinesXY.cmdl | Bin 1120 -> 1120 bytes resources/editor/ScaleLinesXZ.cmdl | Bin 1120 -> 1120 bytes resources/editor/ScaleLinesYZ.cmdl | Bin 1120 -> 1120 bytes resources/editor/ScalePolyXY.cmdl | Bin 768 -> 768 bytes resources/editor/ScalePolyXZ.cmdl | Bin 768 -> 768 bytes resources/editor/ScalePolyYZ.cmdl | Bin 768 -> 768 bytes resources/editor/ScaleX.cmdl | Bin 1888 -> 1888 bytes resources/editor/ScaleXYZ.cmdl | Bin 1216 -> 1216 bytes resources/editor/ScaleY.cmdl | Bin 1888 -> 1888 bytes resources/editor/ScaleZ.cmdl | Bin 1888 -> 1888 bytes resources/editor/TranslateLinesXY.cmdl | Bin 864 -> 864 bytes resources/editor/TranslateLinesXZ.cmdl | Bin 864 -> 864 bytes resources/editor/TranslateLinesYZ.cmdl | Bin 864 -> 864 bytes resources/editor/TranslatePolyXY.cmdl | Bin 768 -> 768 bytes resources/editor/TranslatePolyXZ.cmdl | Bin 768 -> 768 bytes resources/editor/TranslatePolyYZ.cmdl | Bin 768 -> 768 bytes resources/editor/TranslateX.cmdl | Bin 1984 -> 1984 bytes resources/editor/TranslateY.cmdl | Bin 1984 -> 1984 bytes resources/editor/TranslateZ.cmdl | Bin 1984 -> 1984 bytes src/Common/Assert.h | 1 + src/Common/CColor.cpp | 2 +- src/Common/CColor.h | 2 +- src/Common/Common.pro | 3 +- src/Common/Flags.h | 2 + src/Common/Log.cpp | 7 + src/Common/Log.h | 1 + src/Core/Core.pro | 8 +- src/Core/OpenGL/CShader.cpp | 2 + src/Core/OpenGL/CShader.h | 1 + src/Core/OpenGL/CShaderGenerator.cpp | 269 +++++++++++------- src/Core/OpenGL/CUniformBuffer.h | 11 +- src/Core/OpenGL/CVertexBuffer.cpp | 95 +++++-- src/Core/OpenGL/CVertexBuffer.h | 20 +- src/Core/Render/CBoneTransformData.h | 2 +- src/Core/Render/CGraphics.cpp | 40 +++ src/Core/Render/CGraphics.h | 9 + src/Core/Resource/CAnimSet.h | 4 +- src/Core/Resource/CMaterial.h | 11 +- src/Core/Resource/CResCache.cpp | 3 + src/Core/Resource/CSkeleton.h | 68 +++-- src/Core/Resource/CSkin.h | 51 ++++ src/Core/Resource/Cooker/CMaterialCooker.cpp | 32 ++- src/Core/Resource/Cooker/CMaterialCooker.h | 1 + src/Core/Resource/Cooker/CModelCooker.cpp | 18 +- src/Core/Resource/Factory/CAnimSetLoader.cpp | 10 +- src/Core/Resource/Factory/CMaterialLoader.cpp | 30 +- src/Core/Resource/Factory/CMaterialLoader.h | 1 + src/Core/Resource/Factory/CModelLoader.cpp | 25 +- src/Core/Resource/Factory/CModelLoader.h | 3 +- src/Core/Resource/Factory/CSkeletonLoader.cpp | 13 + src/Core/Resource/Factory/CSkeletonLoader.h | 1 + src/Core/Resource/Factory/CSkinLoader.cpp | 29 ++ src/Core/Resource/Factory/CSkinLoader.h | 14 + src/Core/Resource/Model/CModel.cpp | 40 +++ src/Core/Resource/Model/CModel.h | 5 + src/Core/Resource/Model/CVertex.h | 10 +- src/Core/Resource/Model/EVertexAttribute.cpp | 32 +++ src/Core/Resource/Model/EVertexAttribute.h | 45 +-- src/Core/Scene/CCharacterNode.cpp | 56 +++- src/Core/Scene/CModelNode.cpp | 3 + src/Core/Scene/CSceneNode.cpp | 4 +- src/Core/Scene/CSceneNode.h | 2 +- src/Core/Scene/FShowFlags.h | 3 +- src/Editor/CBasicViewport.cpp | 8 + src/Editor/CBasicViewport.h | 1 + src/Editor/CSceneViewport.cpp | 8 - src/Editor/CSceneViewport.h | 1 - .../CharacterEditor/CCharacterEditor.cpp | 8 +- src/Editor/CharacterEditor/CCharacterEditor.h | 2 + .../CharacterEditor/CCharacterEditor.ui | 13 + .../CCharacterEditorViewport.cpp | 1 + src/Math/CVector2f.cpp | 2 +- src/Math/CVector2f.h | 2 +- src/Math/CVector3f.cpp | 2 +- src/Math/CVector3f.h | 2 +- src/Math/MathUtil.cpp | 8 +- 81 files changed, 802 insertions(+), 245 deletions(-) create mode 100644 src/Core/Resource/CSkin.h create mode 100644 src/Core/Resource/Factory/CSkinLoader.cpp create mode 100644 src/Core/Resource/Factory/CSkinLoader.h create mode 100644 src/Core/Resource/Model/EVertexAttribute.cpp diff --git a/resources/editor/RotateClipOutline.cmdl b/resources/editor/RotateClipOutline.cmdl index a64256a8f158d994bb1f1bc7748cff4716ab451e..9cde2cb3cc350f642d182a58feaab002c5548260 100644 GIT binary patch delta 21 bcmZ3Wv_OgH-r8OJ7#J9sfS6??kBA@uP6-8k delta 21 bcmZ3Wv_OgH-r8OJ7#J9sfS7e7kBA@uP7Vcq diff --git a/resources/editor/RotateX.cmdl b/resources/editor/RotateX.cmdl index 396f307ad1fc124f54be9f4aa9cb0360f9f8e81e..b707d606e081988b7044739fac559a923c1069ea 100644 GIT binary patch delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS6??j|nRPPpt)@ delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS7e7j|nRPPqGD} diff --git a/resources/editor/RotateXYZ.cmdl b/resources/editor/RotateXYZ.cmdl index 98005bc4f487aa9a3347c64822adc09833ee2b8b..3e1d4a57d9ed8741a5ebaf191fd913124d38a7ff 100644 GIT binary patch delta 23 dcmZp8!r1VHk>}ppUHcdq7?^;VWh2j*LI7+^2m$~A delta 23 dcmZp8!r1VHk>}ppUHcdq7?^;VbtBK0LI7+}2m=5B diff --git a/resources/editor/RotateY.cmdl b/resources/editor/RotateY.cmdl index 1e87c175242cf379cfd3892085b6c5c08fc46b7f..ab6e64714dd2bed0637bc7a7f8dccc6b403b3dde 100644 GIT binary patch delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS6??j|nRPPpt)@ delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS7e7j|nRPPqGD} diff --git a/resources/editor/RotateZ.cmdl b/resources/editor/RotateZ.cmdl index 88f6b8a7248a0461d823172fe1e796b6a7a94650..8a79f888eea4112a67a640df412e196db4d1f3fe 100644 GIT binary patch delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS6??j|nRPPpt)@ delta 21 bcmX@Wb%2ZK-r8OJ7#J9sfS7e7j|nRPPqGD} diff --git a/resources/editor/ScaleLinesXY.cmdl b/resources/editor/ScaleLinesXY.cmdl index dfa177a71d5365041cd409c0eca691aa7cec7e34..870e4a6b4ddb18a8027dcd7dc76f9f7869cbe929 100644 GIT binary patch delta 21 bcmaFB@qmNp-r8OJ7#J9sfS6??PY4SDRG delta 21 bcmaFB@qmNp-r8OJ7#J9sfS7e7PY4SDRHX&{ diff --git a/resources/editor/ScaleLinesXZ.cmdl b/resources/editor/ScaleLinesXZ.cmdl index 53033fa6fbf0a31fcbdde203dc755cd013c6409b..64f316750a6e6b5317d748e1c9c9270ff1d540c3 100644 GIT binary patch delta 21 bcmaFB@qmNp-r8OJ7#J9sfS6??PY4SDRG delta 21 bcmaFB@qmNp-r8OJ7#J9sfS7e7PY4SDRHX&{ diff --git a/resources/editor/ScaleLinesYZ.cmdl b/resources/editor/ScaleLinesYZ.cmdl index 893333303b51666e98f2799bcde61fcf6b3256a7..6521939c7f65ff6b420c1f03adbba2eb79e602ce 100644 GIT binary patch delta 20 ccmaFB@qmNl-r8OJ7#J9sCNYX^lyPAJ08`=yng9R* delta 21 bcmaFB@qmNp-r8OJ7#J9sfS7e7PY4SDRHX&{ diff --git a/resources/editor/ScalePolyXY.cmdl b/resources/editor/ScalePolyXY.cmdl index 12531da1f24ec5ef6b133218467b415d9203f3db..ef94d900db88a9f620b7f46f37c53a9e9439a054 100644 GIT binary patch delta 21 bcmZo*YhdHKw|3V)1_lNuAZFRf^MwfjMv?{9 delta 21 bcmZo*YhdHKw|3V)1_lNuAZFdj^MwfjMwbQF diff --git a/resources/editor/ScalePolyXZ.cmdl b/resources/editor/ScalePolyXZ.cmdl index 3b8c1bc9dc363dfd4064a2edc441d1fa291fb3ee..3ff888f5f29324a82c5fa4295129c735bfa08737 100644 GIT binary patch delta 21 bcmZo*YhdHKw|3V)1_lNuAZFRf^MwfjMv?{9 delta 21 bcmZo*YhdHKw|3V)1_lNuAZFdj^MwfjMwbQF diff --git a/resources/editor/ScalePolyYZ.cmdl b/resources/editor/ScalePolyYZ.cmdl index 2682097cbe0e21bfdc11e2206f7f2ec5cbfe6d26..26585ea6dff7e083116104d4993fe4aee505057f 100644 GIT binary patch delta 21 bcmZo*YhdHKw|3V)1_lNuAZFRf^MwfjMv?{9 delta 21 bcmZo*YhdHKw|3V)1_lNuAZFdj^MwfjMwbQF diff --git a/resources/editor/ScaleX.cmdl b/resources/editor/ScaleX.cmdl index 41f43174ba06d63a6143811f00ff2ae082d41585..13787663b08214359f59316279e00e8ed655d543 100644 GIT binary patch delta 21 bcmaFB_kfS*-r8OJ7#J9sfS6??PY62zRfh%& delta 21 bcmaFB_kfS*-r8OJ7#J9sfS7e7PY62zRg4A; diff --git a/resources/editor/ScaleXYZ.cmdl b/resources/editor/ScaleXYZ.cmdl index 06547b35b73eda77a2b20669e2b2dc9c5f3626c5..a7e5c056f7903240604846a7b86adbfd87118fdc 100644 GIT binary patch delta 25 fcmX@Wd4QAW-r8OJ7#J9sfS6^n1Ea`Bg#|1CY5WHT delta 25 fcmX@Wd4QAW-r8OJ7#J9sfS7f%1Ea`Bg#|1CY6S-d diff --git a/resources/editor/ScaleY.cmdl b/resources/editor/ScaleY.cmdl index 1a7326ed5bc53f4ac8fe97a0a125131eb89a6093..5937e4446f209791bb8317ffdb8302bec6f7e116 100644 GIT binary patch delta 21 bcmaFB_kfS*-r8OJ7#J9sfS6??PY62zRfh%& delta 21 bcmaFB_kfS*-r8OJ7#J9sfS7e7PY62zRg4A; diff --git a/resources/editor/ScaleZ.cmdl b/resources/editor/ScaleZ.cmdl index 404232719423dfeaf192badf67331124efd2c2f4..53404aa171188e4644187ee5fcbf9ce016db2433 100644 GIT binary patch delta 21 bcmaFB_kfS*-r8OJ7#J9sfS6??PY62zRfh%& delta 21 bcmaFB_kfS*-r8OJ7#J9sfS7e7PY62zRg4A; diff --git a/resources/editor/TranslateLinesXY.cmdl b/resources/editor/TranslateLinesXY.cmdl index f78cdf21ef188f131c44a5f0567b6dbb01a4cc05..3b0a68314268351e1d7d957c504da56f167177d6 100644 GIT binary patch delta 21 bcmaFB_JED&-r8OJ7#J9sfS6??PY5#rR8s}^ delta 21 bcmaFB_JED&-r8OJ7#J9sfS7e7PY5#rR9FS~ diff --git a/resources/editor/TranslateLinesXZ.cmdl b/resources/editor/TranslateLinesXZ.cmdl index 463613e7e10830f03c3650b28453a5c1277338c2..2a41e22cb5bde0c1259d24f9cd0d46862b4e08c6 100644 GIT binary patch delta 21 bcmaFB_JED&-r8OJ7#J9sfS6??PY5#rR8s}^ delta 21 bcmaFB_JED&-r8OJ7#J9sfS7e7PY5#rR9FS~ diff --git a/resources/editor/TranslateLinesYZ.cmdl b/resources/editor/TranslateLinesYZ.cmdl index 7ddb1d039ce4e7bc9bf29169a9d44edf51a3733a..dd8b2f690e28afa84182ff3c7d28cf8e1941e9a3 100644 GIT binary patch delta 21 bcmaFB_JED&-r8OJ7#J9sfS6??PY5#rR8s}^ delta 21 bcmaFB_JED&-r8OJ7#J9sfS7e7PY5#rR9FS~ diff --git a/resources/editor/TranslatePolyXY.cmdl b/resources/editor/TranslatePolyXY.cmdl index 3c23e308013443db36ccc0a300192736a1757aeb..e6138972eb8a7dd71a5659d1fdd3ab37bc2da85a 100644 GIT binary patch delta 21 bcmZo*YhdHKw|3V)1_lNuAZFRf^MwfjMv?{9 delta 21 bcmZo*YhdHKw|3V)1_lNuAZFdj^MwfjMwbQF diff --git a/resources/editor/TranslatePolyXZ.cmdl b/resources/editor/TranslatePolyXZ.cmdl index 64cb1fdf782427e986e33beac5fd4d5abb2dee15..ee46fdccfaa0612ead6d4e2b3235bd5037da6b8b 100644 GIT binary patch delta 21 bcmZo*YhdHKw|3V)1_lNuAZFRf^MwfjMv?{9 delta 21 bcmZo*YhdHKw|3V)1_lNuAZFdj^MwfjMwbQF diff --git a/resources/editor/TranslatePolyYZ.cmdl b/resources/editor/TranslatePolyYZ.cmdl index ab8ace848f97599e48d4b99a6b1bf71539bc4da9..2e98e3eddff8c5ea76ae8ebbfd02f2e7c732579c 100644 GIT binary patch delta 25 fcmZo*YhdHKw|3V)1_lNuAZD4Yz$mg&;QT@VJH delta 25 fcmZo*YhdHKw|3V)1_lNuAZDGcz$mg&;QT^R #include diff --git a/src/Common/CColor.cpp b/src/Common/CColor.cpp index 32fd9e09..6391d726 100644 --- a/src/Common/CColor.cpp +++ b/src/Common/CColor.cpp @@ -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) { diff --git a/src/Common/CColor.h b/src/Common/CColor.h index d3ebf6d2..ab2074c9 100644 --- a/src/Common/CColor.h +++ b/src/Common/CColor.h @@ -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; diff --git a/src/Common/Common.pro b/src/Common/Common.pro index 433fd825..83ff470a 100644 --- a/src/Common/Common.pro +++ b/src/Common/Common.pro @@ -68,7 +68,8 @@ HEADERS += \ Flags.h \ TString.h \ types.h \ - Log.h + Log.h \ + Assert.h # Source Files SOURCES += \ diff --git a/src/Common/Flags.h b/src/Common/Flags.h index 5a117a19..bf8554e6 100644 --- a/src/Common/Flags.h +++ b/src/Common/Flags.h @@ -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 FlagTypeName; diff --git a/src/Common/Log.cpp b/src/Common/Log.cpp index bc8005ad..7d7de083 100644 --- a/src/Common/Log.cpp +++ b/src/Common/Log.cpp @@ -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); diff --git a/src/Common/Log.h b/src/Common/Log.h index fdf5e8de..8bba8bff 100644 --- a/src/Common/Log.h +++ b/src/Common/Log.h @@ -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); diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 16889514..0dc779fb 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -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 diff --git a/src/Core/OpenGL/CShader.cpp b/src/Core/OpenGL/CShader.cpp index 1ad6e1dc..1bca46e0 100644 --- a/src/Core/OpenGL/CShader.cpp +++ b/src/Core/OpenGL/CShader.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()); } } diff --git a/src/Core/OpenGL/CShader.h b/src/Core/OpenGL/CShader.h index e91d301b..6491255a 100644 --- a/src/Core/OpenGL/CShader.h +++ b/src/Core/OpenGL/CShader.h @@ -17,6 +17,7 @@ class CShader GLuint mVertexBlockIndex; GLuint mPixelBlockIndex; GLuint mLightBlockIndex; + GLuint mBoneTransformBlockIndex; static CShader* spCurrentShader; diff --git a/src/Core/OpenGL/CShaderGenerator.cpp b/src/Core/OpenGL/CShaderGenerator.cpp index 4e4dd56a..f3ecb2c1 100644 --- a/src/Core/OpenGL/CShaderGenerator.cpp +++ b/src/Core/OpenGL/CShaderGenerator.cpp @@ -1,12 +1,13 @@ #include "CShaderGenerator.h" +#include #include #include #include #include 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"; diff --git a/src/Core/OpenGL/CUniformBuffer.h b/src/Core/OpenGL/CUniformBuffer.h index 4a88997a..7e1889a3 100644 --- a/src/Core/OpenGL/CUniformBuffer.h +++ b/src/Core/OpenGL/CUniformBuffer.h @@ -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(); } diff --git a/src/Core/OpenGL/CVertexBuffer.cpp b/src/Core/OpenGL/CVertexBuffer.cpp index f3fef626..9469b698 100644 --- a/src/Core/OpenGL/CVertexBuffer.cpp +++ b/src/Core/OpenGL/CVertexBuffer.cpp @@ -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); diff --git a/src/Core/OpenGL/CVertexBuffer.h b/src/Core/OpenGL/CVertexBuffer.h index 2d03ee26..ec1951a0 100644 --- a/src/Core/OpenGL/CVertexBuffer.h +++ b/src/Core/OpenGL/CVertexBuffer.h @@ -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 @@ -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 mPositions; // Vector of vertex positions - std::vector mNormals; // Vector of vertex normals - std::vector mColors[2]; // Vectors of vertex colors - std::vector 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 mpSkin; // Skin for skinned models. Null on unskinned models; + std::vector mPositions; // Vector of vertex positions + std::vector mNormals; // Vector of vertex normals + std::vector mColors[2]; // Vectors of vertex colors + std::vector mTexCoords[8]; // Vectors of texture coordinates + std::vector mBoneIndices; // Vectors of bone indices + std::vector 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(); }; diff --git a/src/Core/Render/CBoneTransformData.h b/src/Core/Render/CBoneTransformData.h index f873832d..3a0133b8 100644 --- a/src/Core/Render/CBoneTransformData.h +++ b/src/Core/Render/CBoneTransformData.h @@ -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); } diff --git a/src/Core/Render/CGraphics.cpp b/src/Core/Render/CGraphics.cpp index 10a7b664..997585f3 100644 --- a/src/Core/Render/CGraphics.cpp +++ b/src/Core/Render/CGraphics.cpp @@ -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 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; + } +} diff --git a/src/Core/Render/CGraphics.h b/src/Core/Render/CGraphics.h index 67014e9a..fde3e607 100644 --- a/src/Core/Render/CGraphics.h +++ b/src/Core/Render/CGraphics.h @@ -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 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 diff --git a/src/Core/Resource/CAnimSet.h b/src/Core/Resource/CAnimSet.h index 25caf205..446f0a70 100644 --- a/src/Core/Resource/CAnimSet.h +++ b/src/Core/Resource/CAnimSet.h @@ -5,6 +5,7 @@ #include "CAnimation.h" #include "CResource.h" #include "CSkeleton.h" +#include "CSkin.h" #include "Core/Resource/Model/CModel.h" #include @@ -20,7 +21,7 @@ class CAnimSet : public CResource { TString Name; TResPtr pModel; - u32 SkinID; + TResPtr pSkin; TResPtr 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(); } diff --git a/src/Core/Resource/CMaterial.h b/src/Core/Resource/CMaterial.h index 6e58a0f0..627cfbdb 100644 --- a/src/Core/Resource/CMaterial.h +++ b/src/Core/Resource/CMaterial.h @@ -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; } diff --git a/src/Core/Resource/CResCache.cpp b/src/Core/Resource/CResCache.cpp index eb873b24..9cd6d00e 100644 --- a/src/Core/Resource/CResCache.cpp +++ b/src/Core/Resource/CResCache.cpp @@ -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 diff --git a/src/Core/Resource/CSkeleton.h b/src/Core/Resource/CSkeleton.h index b0ca4057..f54e3421 100644 --- a/src/Core/Resource/CSkeleton.h +++ b/src/Core/Resource/CSkeleton.h @@ -10,7 +10,34 @@ #include class CBoneTransformData; -class CSkeleton; +class CBone; + +class CSkeleton : public CResource +{ + DECLARE_RESOURCE_TYPE(eSkeleton) + friend class CSkeletonLoader; + + CBone *mpRootBone; + std::vector mBones; + std::vector 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 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 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 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 diff --git a/src/Core/Resource/CSkin.h b/src/Core/Resource/CSkin.h new file mode 100644 index 00000000..f61531de --- /dev/null +++ b/src/Core/Resource/CSkin.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 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 diff --git a/src/Core/Resource/Cooker/CMaterialCooker.cpp b/src/Core/Resource/Cooker/CMaterialCooker.cpp index 22be2372..d1d5b38e 100644 --- a/src/Core/Resource/Cooker/CMaterialCooker.cpp +++ b/src/Core/Resource/Cooker/CMaterialCooker.cpp @@ -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) diff --git a/src/Core/Resource/Cooker/CMaterialCooker.h b/src/Core/Resource/Cooker/CMaterialCooker.h index e9bd05a0..b496471b 100644 --- a/src/Core/Resource/Cooker/CMaterialCooker.h +++ b/src/Core/Resource/Cooker/CMaterialCooker.h @@ -14,6 +14,7 @@ class CMaterialCooker std::vector mMaterialHashes; CMaterialCooker(); + u32 ConvertFromVertexDescription(FVertexDescription VtxDesc); void WriteMatSetPrime(IOutputStream& rOut); void WriteMatSetCorruption(IOutputStream& rOut); void WriteMaterialPrime(IOutputStream& rOut); diff --git a/src/Core/Resource/Cooker/CModelCooker.cpp b/src/Core/Resource/Cooker/CModelCooker.cpp index 0ca23662..13727858 100644 --- a/src/Core/Resource/Cooker/CModelCooker.cpp +++ b/src/Core/Resource/Cooker/CModelCooker.cpp @@ -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; diff --git a/src/Core/Resource/Factory/CAnimSetLoader.cpp b/src/Core/Resource/Factory/CAnimSetLoader.cpp index b5c12fe1..c779e667 100644 --- a/src/Core/Resource/Factory/CAnimSetLoader.cpp +++ b/src/Core/Resource/Factory/CAnimSetLoader.cpp @@ -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 diff --git a/src/Core/Resource/Factory/CMaterialLoader.cpp b/src/Core/Resource/Factory/CMaterialLoader.cpp index 57d1540a..32900845 100644 --- a/src/Core/Resource/Factory/CMaterialLoader.cpp +++ b/src/Core/Resource/Factory/CMaterialLoader.cpp @@ -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 diff --git a/src/Core/Resource/Factory/CMaterialLoader.h b/src/Core/Resource/Factory/CMaterialLoader.h index dde3cd61..a10da6bd 100644 --- a/src/Core/Resource/Factory/CMaterialLoader.h +++ b/src/Core/Resource/Factory/CMaterialLoader.h @@ -25,6 +25,7 @@ class CMaterialLoader CMaterialLoader(); ~CMaterialLoader(); + FVertexDescription ConvertToVertexDescription(u32 VertexFlags); // Load Functions void ReadPrimeMatSet(); diff --git a/src/Core/Resource/Factory/CModelLoader.cpp b/src/Core/Resource/Factory/CModelLoader.cpp index 6784ad8a..1e7dfe52 100644 --- a/src/Core/Resource/Factory/CModelLoader.cpp +++ b/src/Core/Resource/Factory/CModelLoader.cpp @@ -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(); diff --git a/src/Core/Resource/Factory/CModelLoader.h b/src/Core/Resource/Factory/CModelLoader.h index 2bf75319..2db4ca88 100644 --- a/src/Core/Resource/Factory/CModelLoader.h +++ b/src/Core/Resource/Factory/CModelLoader.h @@ -20,7 +20,8 @@ public: eShortPositions = 0x1, eShortNormals = 0x2, eHasTex1 = 0x4, - eHasVisGroups = 0x8 + eHasVisGroups = 0x8, + eSkinnedModel = 0x10 }; DECLARE_FLAGS(EModelFlag, FModelFlags) diff --git a/src/Core/Resource/Factory/CSkeletonLoader.cpp b/src/Core/Resource/Factory/CSkeletonLoader.cpp index 0f6584b3..fb383564 100644 --- a/src/Core/Resource/Factory/CSkeletonLoader.cpp +++ b/src/Core/Resource/Factory/CSkeletonLoader.cpp @@ -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(); diff --git a/src/Core/Resource/Factory/CSkeletonLoader.h b/src/Core/Resource/Factory/CSkeletonLoader.h index b74f3e6f..88c7d7b3 100644 --- a/src/Core/Resource/Factory/CSkeletonLoader.h +++ b/src/Core/Resource/Factory/CSkeletonLoader.h @@ -12,6 +12,7 @@ class CSkeletonLoader CSkeletonLoader() {} void SetLocalBoneCoords(CBone *pBone); + void CalculateBoneInverseBindMatrices(); public: static CSkeleton* LoadCINF(IInputStream& rCINF); diff --git a/src/Core/Resource/Factory/CSkinLoader.cpp b/src/Core/Resource/Factory/CSkinLoader.cpp new file mode 100644 index 00000000..e24ebe40 --- /dev/null +++ b/src/Core/Resource/Factory/CSkinLoader.cpp @@ -0,0 +1,29 @@ +#include "CSkinLoader.h" +#include + +// ************ 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; +} diff --git a/src/Core/Resource/Factory/CSkinLoader.h b/src/Core/Resource/Factory/CSkinLoader.h new file mode 100644 index 00000000..ff988894 --- /dev/null +++ b/src/Core/Resource/Factory/CSkinLoader.h @@ -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 diff --git a/src/Core/Resource/Model/CModel.cpp b/src/Core/Resource/Model/CModel.cpp index 8e98b0d1..eb2d1b4b 100644 --- a/src/Core/Resource/Model/CModel.cpp +++ b/src/Core/Resource/Model/CModel.cpp @@ -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(); diff --git a/src/Core/Resource/Model/CModel.h b/src/Core/Resource/Model/CModel.h index 70a95fa4..30c2a411 100644 --- a/src/Core/Resource/Model/CModel.h +++ b/src/Core/Resource/Model/CModel.h @@ -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 mpSkin; std::vector mMaterialSets; std::vector> 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); }; diff --git a/src/Core/Resource/Model/CVertex.h b/src/Core/Resource/Model/CVertex.h index af48fb89..75199f1b 100644 --- a/src/Core/Resource/Model/CVertex.h +++ b/src/Core/Resource/Model/CVertex.h @@ -4,6 +4,10 @@ #include #include #include +#include + +typedef std::array TBoneIndices; +typedef std::array 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)); } }; diff --git a/src/Core/Resource/Model/EVertexAttribute.cpp b/src/Core/Resource/Model/EVertexAttribute.cpp new file mode 100644 index 00000000..20cd6d81 --- /dev/null +++ b/src/Core/Resource/Model/EVertexAttribute.cpp @@ -0,0 +1,32 @@ +#include "EVertexAttribute.h" +#include + +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; + } +} diff --git a/src/Core/Resource/Model/EVertexAttribute.h b/src/Core/Resource/Model/EVertexAttribute.h index 9d5a4216..6943b06f 100644 --- a/src/Core/Resource/Model/EVertexAttribute.h +++ b/src/Core/Resource/Model/EVertexAttribute.h @@ -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 diff --git a/src/Core/Scene/CCharacterNode.cpp b/src/Core/Scene/CCharacterNode.cpp index 5c09a08b..64d4e056 100644 --- a/src/Core/Scene/CCharacterNode.cpp +++ b/src/Core/Scene/CCharacterNode.cpp @@ -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*/) diff --git a/src/Core/Scene/CModelNode.cpp b/src/Core/Scene/CModelNode.cpp index 556488eb..6eafe6bb 100644 --- a/src/Core/Scene/CModelNode.cpp +++ b/src/Core/Scene/CModelNode.cpp @@ -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 diff --git a/src/Core/Scene/CSceneNode.cpp b/src/Core/Scene/CSceneNode.cpp index 3ec0f0ee..0b299098 100644 --- a/src/Core/Scene/CSceneNode.cpp +++ b/src/Core/Scene/CSceneNode.cpp @@ -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); diff --git a/src/Core/Scene/CSceneNode.h b/src/Core/Scene/CSceneNode.h index c5583ed1..232e4c49 100644 --- a/src/Core/Scene/CSceneNode.h +++ b/src/Core/Scene/CSceneNode.h @@ -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); diff --git a/src/Core/Scene/FShowFlags.h b/src/Core/Scene/FShowFlags.h index 0dbe3da1..8940f833 100644 --- a/src/Core/Scene/FShowFlags.h +++ b/src/Core/Scene/FShowFlags.h @@ -14,7 +14,8 @@ enum EShowFlag eShowObjects = 0x18, eShowLights = 0x20, eShowSky = 0x40, - eShowAll = 0x7F + eShowSkeletons = 0x80, + eShowAll = 0xFFFFFFFF }; DECLARE_FLAGS(EShowFlag, FShowFlags) diff --git a/src/Editor/CBasicViewport.cpp b/src/Editor/CBasicViewport.cpp index ea47d828..17895319 100644 --- a/src/Editor/CBasicViewport.cpp +++ b/src/Editor/CBasicViewport.cpp @@ -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; diff --git a/src/Editor/CBasicViewport.h b/src/Editor/CBasicViewport.h index 3b96761e..99a9ecad 100644 --- a/src/Editor/CBasicViewport.h +++ b/src/Editor/CBasicViewport.h @@ -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); diff --git a/src/Editor/CSceneViewport.cpp b/src/Editor/CSceneViewport.cpp index 5a1105b5..63aec7cc 100644 --- a/src/Editor/CSceneViewport.cpp +++ b/src/Editor/CSceneViewport.cpp @@ -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) diff --git a/src/Editor/CSceneViewport.h b/src/Editor/CSceneViewport.h index dc541372..2afe7b41 100644 --- a/src/Editor/CSceneViewport.h +++ b/src/Editor/CSceneViewport.h @@ -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; diff --git a/src/Editor/CharacterEditor/CCharacterEditor.cpp b/src/Editor/CharacterEditor/CCharacterEditor.cpp index 1df32897..b163bf85 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.cpp +++ b/src/Editor/CharacterEditor/CCharacterEditor.cpp @@ -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); diff --git a/src/Editor/CharacterEditor/CCharacterEditor.h b/src/Editor/CharacterEditor/CCharacterEditor.h index 6e1fe883..761eddc0 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.h +++ b/src/Editor/CharacterEditor/CCharacterEditor.h @@ -28,6 +28,7 @@ class CCharacterEditor : public QMainWindow TResPtr 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); diff --git a/src/Editor/CharacterEditor/CCharacterEditor.ui b/src/Editor/CharacterEditor/CCharacterEditor.ui index 750b7712..657db216 100644 --- a/src/Editor/CharacterEditor/CCharacterEditor.ui +++ b/src/Editor/CharacterEditor/CCharacterEditor.ui @@ -154,6 +154,8 @@ false + + @@ -170,6 +172,17 @@ Ctrl+O + + + true + + + Show Skeleton + + + Show Skeleton + + diff --git a/src/Editor/CharacterEditor/CCharacterEditorViewport.cpp b/src/Editor/CharacterEditor/CCharacterEditorViewport.cpp index 16627197..cd88cf83 100644 --- a/src/Editor/CharacterEditor/CCharacterEditorViewport.cpp +++ b/src/Editor/CharacterEditor/CCharacterEditorViewport.cpp @@ -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; diff --git a/src/Math/CVector2f.cpp b/src/Math/CVector2f.cpp index f2bbed78..eaf74f1f 100644 --- a/src/Math/CVector2f.cpp +++ b/src/Math/CVector2f.cpp @@ -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); diff --git a/src/Math/CVector2f.h b/src/Math/CVector2f.h index e5a604b5..6b7e39db 100644 --- a/src/Math/CVector2f.h +++ b/src/Math/CVector2f.h @@ -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; diff --git a/src/Math/CVector3f.cpp b/src/Math/CVector3f.cpp index 2f06f034..5b7245f6 100644 --- a/src/Math/CVector3f.cpp +++ b/src/Math/CVector3f.cpp @@ -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); diff --git a/src/Math/CVector3f.h b/src/Math/CVector3f.h index b89638a3..f00024fc 100644 --- a/src/Math/CVector3f.h +++ b/src/Math/CVector3f.h @@ -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(); diff --git a/src/Math/MathUtil.cpp b/src/Math/MathUtil.cpp index 8b3bad32..3fedb876 100644 --- a/src/Math/MathUtil.cpp +++ b/src/Math/MathUtil.cpp @@ -37,20 +37,20 @@ float RadiansToDegrees(float Rad) return Rad * 180.f / skPi; } -std::pair RayPlaneIntersection(const CRay& rkRay, const CPlane& plane) +std::pair 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(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(t >= 0.f, t); }