diff --git a/CMakeLists.txt b/CMakeLists.txt
index 1da832dd..8f6e2e65 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -120,6 +120,7 @@ set(LIBRARY_SOURCES
Src/DebugEffect.cpp
Src/DGSLEffect.cpp
Src/NPREffect.cpp
+ Src/NPREffectFactory.cpp
Src/DGSLEffectFactory.cpp
Src/DirectXHelpers.cpp
Src/DualPostProcess.cpp
@@ -296,7 +297,9 @@ if(WIN32 AND BUILD_SHARED_LIBS)
target_compile_definitions(${PROJECT_NAME} INTERFACE DIRECTX_TOOLKIT_IMPORT)
if(XBOX_CONSOLE_TARGET MATCHES "durango")
- target_link_libraries(${PROJECT_NAME} PRIVATE kernelx.lib combase.lib d3d12_x.lib xi.lib)
+ target_link_libraries(${PROJECT_NAME} PRIVATE kernelx.lib combase.lib d3d11_x.lib xi.lib)
+ else()
+ target_link_libraries(${PROJECT_NAME} PRIVATE d3d11.lib dxguid.lib)
endif()
if(MINGW AND BUILD_XINPUT)
diff --git a/DirectXTK_Desktop_2022.vcxproj b/DirectXTK_Desktop_2022.vcxproj
index d66aefc4..d6b66316 100644
--- a/DirectXTK_Desktop_2022.vcxproj
+++ b/DirectXTK_Desktop_2022.vcxproj
@@ -96,6 +96,7 @@
+
diff --git a/DirectXTK_Desktop_2022.vcxproj.filters b/DirectXTK_Desktop_2022.vcxproj.filters
index 05534581..6c97be34 100644
--- a/DirectXTK_Desktop_2022.vcxproj.filters
+++ b/DirectXTK_Desktop_2022.vcxproj.filters
@@ -287,6 +287,9 @@
Audio
+
+ Src
+
diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj b/DirectXTK_Desktop_2022_Win10.vcxproj
index 0f6540d6..280e4d7f 100644
--- a/DirectXTK_Desktop_2022_Win10.vcxproj
+++ b/DirectXTK_Desktop_2022_Win10.vcxproj
@@ -104,6 +104,7 @@
+
diff --git a/DirectXTK_Desktop_2022_Win10.vcxproj.filters b/DirectXTK_Desktop_2022_Win10.vcxproj.filters
index cfea2c70..84b887f8 100644
--- a/DirectXTK_Desktop_2022_Win10.vcxproj.filters
+++ b/DirectXTK_Desktop_2022_Win10.vcxproj.filters
@@ -287,6 +287,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_Desktop_2026.slnx b/DirectXTK_Desktop_2026.slnx
index 18982815..4c6ec620 100644
--- a/DirectXTK_Desktop_2026.slnx
+++ b/DirectXTK_Desktop_2026.slnx
@@ -8,11 +8,11 @@
-
+
-
-
+
+
diff --git a/DirectXTK_Desktop_2026.vcxproj b/DirectXTK_Desktop_2026.vcxproj
index 5418c4d3..afb6b9e8 100644
--- a/DirectXTK_Desktop_2026.vcxproj
+++ b/DirectXTK_Desktop_2026.vcxproj
@@ -104,6 +104,7 @@
+
diff --git a/DirectXTK_Desktop_2026.vcxproj.filters b/DirectXTK_Desktop_2026.vcxproj.filters
index cfea2c70..84b887f8 100644
--- a/DirectXTK_Desktop_2026.vcxproj.filters
+++ b/DirectXTK_Desktop_2026.vcxproj.filters
@@ -287,6 +287,9 @@
Src
+
+ Src
+
diff --git a/DirectXTK_GDKW_2022.vcxproj b/DirectXTK_GDKW_2022.vcxproj
index f309eeb1..8417d997 100644
--- a/DirectXTK_GDKW_2022.vcxproj
+++ b/DirectXTK_GDKW_2022.vcxproj
@@ -424,6 +424,7 @@
+
diff --git a/DirectXTK_GDKW_2022.vcxproj.filters b/DirectXTK_GDKW_2022.vcxproj.filters
index 511fb417..29fc5ea8 100644
--- a/DirectXTK_GDKW_2022.vcxproj.filters
+++ b/DirectXTK_GDKW_2022.vcxproj.filters
@@ -289,6 +289,9 @@
Audio
+
+ Src
+
diff --git a/DirectXTK_GDK_2022.vcxproj b/DirectXTK_GDK_2022.vcxproj
index d4f512a9..a6bfcd16 100644
--- a/DirectXTK_GDK_2022.vcxproj
+++ b/DirectXTK_GDK_2022.vcxproj
@@ -249,6 +249,7 @@
+
diff --git a/DirectXTK_GDK_2022.vcxproj.filters b/DirectXTK_GDK_2022.vcxproj.filters
index 511fb417..29fc5ea8 100644
--- a/DirectXTK_GDK_2022.vcxproj.filters
+++ b/DirectXTK_GDK_2022.vcxproj.filters
@@ -289,6 +289,9 @@
Audio
+
+ Src
+
diff --git a/DirectXTK_Windows10_2022.vcxproj b/DirectXTK_Windows10_2022.vcxproj
index 25ee0c87..d6e1e3fa 100644
--- a/DirectXTK_Windows10_2022.vcxproj
+++ b/DirectXTK_Windows10_2022.vcxproj
@@ -116,6 +116,7 @@
+
diff --git a/DirectXTK_Windows10_2022.vcxproj.filters b/DirectXTK_Windows10_2022.vcxproj.filters
index 354afcf7..bb1ed59a 100644
--- a/DirectXTK_Windows10_2022.vcxproj.filters
+++ b/DirectXTK_Windows10_2022.vcxproj.filters
@@ -365,5 +365,8 @@
Src
+
+ Src
+
\ No newline at end of file
diff --git a/Inc/Effects.h b/Inc/Effects.h
index be5eb548..8ec87c29 100644
--- a/Inc/Effects.h
+++ b/Inc/Effects.h
@@ -578,13 +578,14 @@ namespace DirectX
static constexpr int MaxTextures = 8;
protected:
- // Private implementation.
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
DIRECTX_TOOLKIT_API DGSLEffect(_In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader, bool skinningEnabled);
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void __cdecl SetPerPixelLighting(bool value) override;
};
@@ -604,7 +605,7 @@ namespace DirectX
~SkinnedDGSLEffect() override;
- // Animation setting.
+ // Animation settings.
void __cdecl SetWeightsPerVertex(int value) override;
void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override;
void __cdecl ResetBoneTransforms() override;
@@ -680,13 +681,14 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl SetInstancingEnabled(bool value);
protected:
- // Private implementation.
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
DIRECTX_TOOLKIT_API NormalMapEffect(_In_ ID3D11Device* device, bool skinningEnabled);
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void __cdecl SetLightingEnabled(bool value) override;
DIRECTX_TOOLKIT_API void __cdecl SetPerPixelLighting(bool value) override;
@@ -786,13 +788,14 @@ namespace DirectX
DIRECTX_TOOLKIT_API void __cdecl SetRenderTargetSizeInPixels(int width, int height);
protected:
- // Private implementation.
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
DIRECTX_TOOLKIT_API PBREffect(_In_ ID3D11Device* device, bool skinningEnabled);
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void __cdecl SetLightingEnabled(bool value) override;
DIRECTX_TOOLKIT_API void __cdecl SetPerPixelLighting(bool value) override;
@@ -890,7 +893,9 @@ namespace DirectX
Mode_MatCap, // Material Capture shading
};
- DIRECTX_TOOLKIT_API explicit NPREffect(_In_ ID3D11Device* device);
+ DIRECTX_TOOLKIT_API inline explicit NPREffect(_In_ ID3D11Device* device) :
+ NPREffect(device, false)
+ {}
DIRECTX_TOOLKIT_API NPREffect(NPREffect&&) noexcept;
DIRECTX_TOOLKIT_API NPREffect& operator= (NPREffect&&) noexcept;
@@ -960,12 +965,15 @@ namespace DirectX
// Instancing settings.
DIRECTX_TOOLKIT_API void __cdecl SetInstancingEnabled(bool value);
- private:
- // Private implementation.
+ protected:
+ // Internal implementation.
class Impl;
std::unique_ptr pImpl;
+ DIRECTX_TOOLKIT_API NPREffect(_In_ ID3D11Device* device, bool skinningEnabled);
+
+ private:
// Unsupported interface methods.
DIRECTX_TOOLKIT_API void __cdecl SetLightingEnabled(bool value) override;
DIRECTX_TOOLKIT_API void __cdecl SetPerPixelLighting(bool value) override;
@@ -975,6 +983,27 @@ namespace DirectX
DIRECTX_TOOLKIT_API void XM_CALLCONV SetLightSpecularColor(int whichLight, FXMVECTOR value) override;
};
+ class DIRECTX_TOOLKIT_API SkinnedNPREffect : public NPREffect, public IEffectSkinning
+ {
+ public:
+ explicit SkinnedNPREffect(_In_ ID3D11Device* device) :
+ NPREffect(device, true)
+ {}
+
+ SkinnedNPREffect(SkinnedNPREffect&&) = default;
+ SkinnedNPREffect& operator= (SkinnedNPREffect&&) = default;
+
+ SkinnedNPREffect(SkinnedNPREffect const&) = delete;
+ SkinnedNPREffect& operator= (SkinnedNPREffect const&) = delete;
+
+ ~SkinnedNPREffect() override;
+
+ // Animation settings.
+ void __cdecl SetWeightsPerVertex(int value) override;
+ void __cdecl SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) override;
+ void __cdecl ResetBoneTransforms() override;
+ };
+
//------------------------------------------------------------------------------
// Abstract interface to factory for sharing effects and texture resources
class DIRECTX_TOOLKIT_API IEffectFactory
@@ -1127,6 +1156,55 @@ namespace DirectX
};
+ // Factory for Non-Photorealistic Rendering (NPR)
+ class NPREffectFactory : public IEffectFactory
+ {
+ public:
+ DIRECTX_TOOLKIT_API explicit NPREffectFactory(_In_ ID3D11Device* device);
+
+ DIRECTX_TOOLKIT_API NPREffectFactory(NPREffectFactory&&) noexcept;
+ DIRECTX_TOOLKIT_API NPREffectFactory& operator= (NPREffectFactory&&) noexcept;
+
+ NPREffectFactory(NPREffectFactory const&) = delete;
+ NPREffectFactory& operator= (NPREffectFactory const&) = delete;
+
+ DIRECTX_TOOLKIT_API ~NPREffectFactory() override;
+
+ // IEffectFactory methods.
+ DIRECTX_TOOLKIT_API std::shared_ptr __cdecl CreateEffect(
+ _In_ const EffectInfo& info,
+ _In_opt_ ID3D11DeviceContext* deviceContext) override;
+ DIRECTX_TOOLKIT_API void __cdecl CreateTexture(
+ _In_z_ const wchar_t* name,
+ _In_opt_ ID3D11DeviceContext* deviceContext,
+ _Outptr_ ID3D11ShaderResourceView** textureView) override;
+
+ // Settings.
+ DIRECTX_TOOLKIT_API void __cdecl ReleaseCache();
+
+ DIRECTX_TOOLKIT_API void __cdecl SetSharing(bool enabled) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl EnableForceSRGB(bool forceSRGB) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetDirectory(_In_opt_z_ const wchar_t* path) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetMode(NPREffect::Mode mode) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetDefaultMatCap(_In_opt_ ID3D11ShaderResourceView* textureView) noexcept;
+
+ DIRECTX_TOOLKIT_API void __cdecl SetEmissiveAsMatCap(bool value) noexcept;
+
+ // Properties.
+ DIRECTX_TOOLKIT_API ID3D11Device* GetDevice() const noexcept;
+
+ private:
+ // Private implementation.
+ class Impl;
+
+ std::shared_ptr pImpl;
+ };
+
+
// Factory for sharing Visual Studio Shader Designer (DGSL) shaders and texture resources
class DGSLEffectFactory : public IEffectFactory
{
diff --git a/Src/DGSLEffectFactory.cpp b/Src/DGSLEffectFactory.cpp
index 49fa9c8c..ce242a9d 100644
--- a/Src/DGSLEffectFactory.cpp
+++ b/Src/DGSLEffectFactory.cpp
@@ -51,8 +51,6 @@ class DGSLEffectFactory::Impl
void CreatePixelShader(_In_z_ const wchar_t* shader, _Outptr_ ID3D11PixelShader** pixelShader);
void ReleaseCache();
- void SetSharing(bool enabled) noexcept { mSharing = enabled; }
- void EnableForceSRGB(bool forceSRGB) noexcept { mForceSRGB = forceSRGB; }
static SharedResourcePool instancePool;
@@ -60,6 +58,9 @@ class DGSLEffectFactory::Impl
ComPtr mDevice;
+ bool mSharing;
+ bool mForceSRGB;
+
private:
using EffectCache = std::map< std::wstring, std::shared_ptr >;
using TextureCache = std::map< std::wstring, ComPtr >;
@@ -70,9 +71,6 @@ class DGSLEffectFactory::Impl
TextureCache mTextureCache;
ShaderCache mShaderCache;
- bool mSharing;
- bool mForceSRGB;
-
std::mutex mutex;
};
@@ -590,12 +588,12 @@ void DGSLEffectFactory::ReleaseCache()
void DGSLEffectFactory::SetSharing(bool enabled) noexcept
{
- pImpl->SetSharing(enabled);
+ pImpl->mSharing = enabled;
}
void DGSLEffectFactory::EnableForceSRGB(bool forceSRGB) noexcept
{
- pImpl->EnableForceSRGB(forceSRGB);
+ pImpl->mForceSRGB = forceSRGB;
}
void DGSLEffectFactory::SetDirectory(_In_opt_z_ const wchar_t* path) noexcept
diff --git a/Src/EffectFactory.cpp b/Src/EffectFactory.cpp
index 3abef803..1099c53c 100644
--- a/Src/EffectFactory.cpp
+++ b/Src/EffectFactory.cpp
@@ -87,9 +87,6 @@ class EffectFactory::Impl
void CreateTexture(_In_z_ const wchar_t* texture, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView);
void ReleaseCache();
- void SetSharing(bool enabled) noexcept { mSharing = enabled; }
- void EnableNormalMapEffect(bool enabled) noexcept { mUseNormalMapEffect = enabled; }
- void EnableForceSRGB(bool forceSRGB) noexcept { mForceSRGB = forceSRGB; }
static SharedResourcePool instancePool;
@@ -97,6 +94,10 @@ class EffectFactory::Impl
ComPtr mDevice;
+ bool mSharing;
+ bool mUseNormalMapEffect;
+ bool mForceSRGB;
+
private:
using EffectCache = std::map< std::wstring, std::shared_ptr >;
using TextureCache = std::map< std::wstring, ComPtr >;
@@ -108,10 +109,6 @@ class EffectFactory::Impl
EffectCache mEffectNormalMapSkinned;
TextureCache mTextureCache;
- bool mSharing;
- bool mUseNormalMapEffect;
- bool mForceSRGB;
-
std::mutex mutex;
};
@@ -513,17 +510,17 @@ void EffectFactory::ReleaseCache()
void EffectFactory::SetSharing(bool enabled) noexcept
{
- pImpl->SetSharing(enabled);
+ pImpl->mSharing = enabled;
}
void EffectFactory::EnableNormalMapEffect(bool enabled) noexcept
{
- pImpl->EnableNormalMapEffect(enabled);
+ pImpl->mUseNormalMapEffect = enabled;
}
void EffectFactory::EnableForceSRGB(bool forceSRGB) noexcept
{
- pImpl->EnableForceSRGB(forceSRGB);
+ pImpl->mForceSRGB = forceSRGB;
}
void EffectFactory::SetDirectory(_In_opt_z_ const wchar_t* path) noexcept
diff --git a/Src/NPREffect.cpp b/Src/NPREffect.cpp
index 10ba87aa..4f0f288d 100644
--- a/Src/NPREffect.cpp
+++ b/Src/NPREffect.cpp
@@ -10,6 +10,14 @@
#include "pch.h"
#include "EffectCommon.h"
+namespace DirectX
+{
+ namespace EffectDirtyFlags
+ {
+ constexpr int ConstantBufferBones = 0x100000;
+ }
+}
+
using namespace DirectX;
namespace
@@ -32,15 +40,21 @@ namespace
static_assert((sizeof(NPREffectConstants) % 16) == 0, "CB size not padded correctly");
+ XM_ALIGNED_STRUCT(16) BoneConstants
+ {
+ XMVECTOR Bones[SkinnedNPREffect::MaxBones][3];
+ };
+
+ static_assert((sizeof(BoneConstants) % 16) == 0, "CB size not padded correctly");
// Traits type describes our characteristics to the EffectBase template.
struct NPREffectTraits
{
using ConstantBufferType = NPREffectConstants;
- static constexpr int VertexShaderCount = 16;
+ static constexpr int VertexShaderCount = 18;
static constexpr int PixelShaderCount = 6;
- static constexpr int ShaderPermutationCount = 48;
+ static constexpr int ShaderPermutationCount = 54;
static constexpr int ModeCount = 3;
};
@@ -68,10 +82,14 @@ class NPREffect::Impl : public EffectBase
Impl(Impl&&) = default;
Impl& operator=(Impl&&) = default;
+ void Initialize(_In_ ID3D11Device* device, bool enableSkinning);
+
bool vertexColorEnabled;
bool biasedVertexNormals;
bool instancing;
bool textureEnabled;
+ int weightsPerVertex;
+
NPREffect::Mode nprMode;
Microsoft::WRL::ComPtr texture;
Microsoft::WRL::ComPtr matcap;
@@ -79,6 +97,11 @@ class NPREffect::Impl : public EffectBase
int GetCurrentShaderPermutation() const noexcept;
void Apply(_In_ ID3D11DeviceContext* deviceContext);
+
+ BoneConstants boneConstants;
+
+private:
+ ConstantBuffer mBones;
};
@@ -111,6 +134,9 @@ namespace
#include "XboxOneNPREffect_VSNPREffectVcBnTx.inc"
#include "XboxOneNPREffect_VSNPREffectVcBnInstTx.inc"
+#include "XboxOneNPREffect_VSSkinnedNPREffectTx.inc"
+#include "XboxOneNPREffect_VSSkinnedNPREffectTxBn.inc"
+
#include "XboxOneNPREffect_PSCelShading.inc"
#include "XboxOneNPREffect_PSCelShadingTx.inc"
@@ -144,6 +170,9 @@ namespace
#include "NPREffect_VSNPREffectVcBnTx.inc"
#include "NPREffect_VSNPREffectVcBnInstTx.inc"
+#include "NPREffect_VSSkinnedNPREffectTx.inc"
+#include "NPREffect_VSSkinnedNPREffectTxBn.inc"
+
#include "NPREffect_PSCelShading.inc"
#include "NPREffect_PSCelShadingTx.inc"
@@ -159,22 +188,24 @@ namespace
template<>
const ShaderBytecode EffectBase::VertexShaderBytecode[] =
{
- { NPREffect_VSNPREffect, sizeof(NPREffect_VSNPREffect) },
- { NPREffect_VSNPREffectVc, sizeof(NPREffect_VSNPREffectVc) },
- { NPREffect_VSNPREffectBn, sizeof(NPREffect_VSNPREffectBn) },
- { NPREffect_VSNPREffectVcBn, sizeof(NPREffect_VSNPREffectVcBn) },
- { NPREffect_VSNPREffectInst, sizeof(NPREffect_VSNPREffectInst) },
- { NPREffect_VSNPREffectVcInst, sizeof(NPREffect_VSNPREffectVcInst) },
- { NPREffect_VSNPREffectBnInst, sizeof(NPREffect_VSNPREffectBnInst) },
- { NPREffect_VSNPREffectVcBnInst, sizeof(NPREffect_VSNPREffectVcBnInst) },
- { NPREffect_VSNPREffectTx, sizeof(NPREffect_VSNPREffectTx) },
- { NPREffect_VSNPREffectVcTx, sizeof(NPREffect_VSNPREffectVcTx) },
- { NPREffect_VSNPREffectBnTx, sizeof(NPREffect_VSNPREffectBnTx) },
- { NPREffect_VSNPREffectVcBnTx, sizeof(NPREffect_VSNPREffectVcBnTx) },
- { NPREffect_VSNPREffectInstTx, sizeof(NPREffect_VSNPREffectInstTx) },
- { NPREffect_VSNPREffectVcInstTx, sizeof(NPREffect_VSNPREffectVcInstTx) },
- { NPREffect_VSNPREffectBnInstTx, sizeof(NPREffect_VSNPREffectBnInstTx) },
- { NPREffect_VSNPREffectVcBnInstTx, sizeof(NPREffect_VSNPREffectVcBnInstTx) },
+ { NPREffect_VSNPREffect, sizeof(NPREffect_VSNPREffect) },
+ { NPREffect_VSNPREffectVc, sizeof(NPREffect_VSNPREffectVc) },
+ { NPREffect_VSNPREffectBn, sizeof(NPREffect_VSNPREffectBn) },
+ { NPREffect_VSNPREffectVcBn, sizeof(NPREffect_VSNPREffectVcBn) },
+ { NPREffect_VSNPREffectInst, sizeof(NPREffect_VSNPREffectInst) },
+ { NPREffect_VSNPREffectVcInst, sizeof(NPREffect_VSNPREffectVcInst) },
+ { NPREffect_VSNPREffectBnInst, sizeof(NPREffect_VSNPREffectBnInst) },
+ { NPREffect_VSNPREffectVcBnInst, sizeof(NPREffect_VSNPREffectVcBnInst) },
+ { NPREffect_VSNPREffectTx, sizeof(NPREffect_VSNPREffectTx) },
+ { NPREffect_VSNPREffectVcTx, sizeof(NPREffect_VSNPREffectVcTx) },
+ { NPREffect_VSNPREffectBnTx, sizeof(NPREffect_VSNPREffectBnTx) },
+ { NPREffect_VSNPREffectVcBnTx, sizeof(NPREffect_VSNPREffectVcBnTx) },
+ { NPREffect_VSNPREffectInstTx, sizeof(NPREffect_VSNPREffectInstTx) },
+ { NPREffect_VSNPREffectVcInstTx, sizeof(NPREffect_VSNPREffectVcInstTx) },
+ { NPREffect_VSNPREffectBnInstTx, sizeof(NPREffect_VSNPREffectBnInstTx) },
+ { NPREffect_VSNPREffectVcBnInstTx, sizeof(NPREffect_VSNPREffectVcBnInstTx) },
+ { NPREffect_VSSkinnedNPREffectTx, sizeof(NPREffect_VSSkinnedNPREffectTx) },
+ { NPREffect_VSSkinnedNPREffectTxBn, sizeof(NPREffect_VSSkinnedNPREffectTxBn) },
};
@@ -244,6 +275,14 @@ const int EffectBase::VertexShaderIndices[] =
15, // instancing + vertex color (biased vertex normal) + cel shading + texture
15, // instancing + vertex color (biased vertex normal) + gooch shading + texture
15, // instancing + vertex color (biased vertex normal) + matcap shading + texture
+
+ 16, // skinning + cel shading
+ 16, // skinning + gooch shading
+ 16, // skinning + matcap shading
+
+ 17, // skinning (biased vertex normal) + cel shading
+ 17, // skinning (biased vertex normal) + gooch shading
+ 17, // skinning (biased vertex normal) + matcap shading
};
@@ -325,6 +364,14 @@ const int EffectBase::PixelShaderIndices[] =
3, // instancing + vertex color (biased vertex normal) + cel shading + texture
4, // instancing + vertex color (biased vertex normal) + gooch shading + texture
5, // instancing + vertex color (biased vertex normal) + matcap shading + texture
+
+ 3, // skinning + cel shading
+ 4, // skinning + gooch shading
+ 5, // skinning + matcap shading
+
+ 3, // skinning (biased vertex normal) + cel shading
+ 4, // skinning (biased vertex normal) + gooch shading
+ 5, // skinning (biased vertex normal) + matcap shading
};
#pragma endregion
@@ -340,13 +387,17 @@ NPREffect::Impl::Impl(_In_ ID3D11Device* device)
biasedVertexNormals(false),
instancing(false),
textureEnabled(false),
+ weightsPerVertex(0),
nprMode(NPREffect::Mode_Cel)
{
static_assert(static_cast(std::size(EffectBase::VertexShaderIndices)) == NPREffectTraits::ShaderPermutationCount, "array/max mismatch");
static_assert(static_cast(std::size(EffectBase::VertexShaderBytecode)) == NPREffectTraits::VertexShaderCount, "array/max mismatch");
static_assert(static_cast(std::size(EffectBase::PixelShaderBytecode)) == NPREffectTraits::PixelShaderCount, "array/max mismatch");
static_assert(static_cast(std::size(EffectBase::PixelShaderIndices)) == NPREffectTraits::ShaderPermutationCount, "array/max mismatch");
+}
+void NPREffect::Impl::Initialize(_In_ ID3D11Device* device, bool enableSkinning)
+{
constants.lightDirectionAndCelBands = s_defaultLightDir;
constants.diffuseColorAndAlpha = s_defaultDiffuse;
constants.specularColorAndSpecularThreshold = s_defaultSpecular;
@@ -355,13 +406,41 @@ NPREffect::Impl::Impl(_In_ ID3D11Device* device)
constants.goochCoolColorAndAlpha = s_defaultCool;
constants.goochWarmColorAndBeta = s_defaultWarm;
constants.eyePosition = g_XMZero;
-}
+ if (enableSkinning)
+ {
+ textureEnabled = true;
+ weightsPerVertex = 4;
+
+ mBones.Create(device);
+
+ for (size_t j = 0; j < SkinnedNPREffect::MaxBones; ++j)
+ {
+ boneConstants.Bones[j][0] = g_XMIdentityR0;
+ boneConstants.Bones[j][1] = g_XMIdentityR1;
+ boneConstants.Bones[j][2] = g_XMIdentityR2;
+ }
+ }
+}
int NPREffect::Impl::GetCurrentShaderPermutation() const noexcept
{
int permutation = static_cast(nprMode);
+ if (weightsPerVertex > 0)
+ {
+ if (biasedVertexNormals)
+ {
+ // Compressed normals need to be scaled and biased in the vertex shader.
+ permutation += 3;
+ }
+
+ // Vertex skinning does not support vertex colors or instancing, always includes a texture.
+ permutation += 48;
+
+ return permutation;
+ }
+
// Support vertex coloring?
if (vertexColorEnabled)
{
@@ -403,13 +482,35 @@ void NPREffect::Impl::Apply(_In_ ID3D11DeviceContext* deviceContext)
constants.worldViewProj,
constants.eyePosition);
+ if (weightsPerVertex > 0)
+ {
+ #if defined(_XBOX_ONE) && defined(_TITLE)
+ void* grfxMemoryBone;
+ mBones.SetData(deviceContext, boneConstants, &grfxMemoryBone);
+
+ ComPtr deviceContextX;
+ ThrowIfFailed(deviceContext->QueryInterface(IID_GRAPHICS_PPV_ARGS(deviceContextX.GetAddressOf())));
+
+ deviceContextX->VSSetPlacementConstantBuffer(1, mBones.GetBuffer(), grfxMemoryBone);
+ #else
+ if (dirtyFlags & EffectDirtyFlags::ConstantBufferBones)
+ {
+ mBones.SetData(deviceContext, boneConstants);
+ dirtyFlags &= ~EffectDirtyFlags::ConstantBufferBones;
+ }
+
+ ID3D11Buffer* buffer = mBones.GetBuffer();
+ deviceContext->VSSetConstantBuffers(1, 1, &buffer);
+ #endif
+ }
+
// Set texture.
switch (nprMode)
{
case Mode_MatCap:
if (textureEnabled)
{
- ID3D11ShaderResourceView* srvs[] = { texture.Get(), matcap.Get() };
+ ID3D11ShaderResourceView* srvs[] = { (texture) ? texture.Get() : GetDefaultTexture(), matcap.Get() };
deviceContext->PSSetShaderResources(0, 2, srvs);
}
else
@@ -422,7 +523,7 @@ void NPREffect::Impl::Apply(_In_ ID3D11DeviceContext* deviceContext)
default:
if (textureEnabled)
{
- ID3D11ShaderResourceView* srv = texture.Get();
+ ID3D11ShaderResourceView* srv = (texture) ? texture.Get() : GetDefaultTexture();
deviceContext->PSSetShaderResources(0, 1, &srv);
}
break;
@@ -434,10 +535,11 @@ void NPREffect::Impl::Apply(_In_ ID3D11DeviceContext* deviceContext)
// Public constructor.
-NPREffect::NPREffect(_In_ ID3D11Device* device)
+NPREffect::NPREffect(_In_ ID3D11Device* device, bool skinningEnabled)
: pImpl(std::make_unique(device))
-{}
-
+{
+ pImpl->Initialize(device, skinningEnabled);
+}
NPREffect::NPREffect(NPREffect&&) noexcept = default;
NPREffect& NPREffect::operator= (NPREffect&&) noexcept = default;
@@ -623,6 +725,11 @@ void NPREffect::SetColorAndAlpha(FXMVECTOR value)
// Texture settings.
void NPREffect::SetTextureEnabled(bool value)
{
+ if (!value && (pImpl->weightsPerVertex > 0))
+ {
+ throw std::invalid_argument("Texturing is alaways enabled for SkinnedNPREffect");
+ }
+
pImpl->textureEnabled = value;
}
@@ -742,6 +849,11 @@ void NPREffect::DisableRimLighting()
// Vertex color setting.
void NPREffect::SetVertexColorEnabled(bool value)
{
+ if (value && (pImpl->weightsPerVertex > 0))
+ {
+ throw std::invalid_argument("Per-vertex color is not supported for SkinnedNPREffect");
+ }
+
pImpl->vertexColorEnabled = value;
}
@@ -756,5 +868,71 @@ void NPREffect::SetBiasedVertexNormals(bool value)
// Instancing settings.
void NPREffect::SetInstancingEnabled(bool value)
{
+ if (value && (pImpl->weightsPerVertex > 0))
+ {
+ throw std::invalid_argument("Instancing is not supported for SkinnedNPREffect");
+ }
+
pImpl->instancing = value;
}
+
+
+//--------------------------------------------------------------------------------------
+// SkinnedNPREffect
+//--------------------------------------------------------------------------------------
+
+SkinnedNPREffect::~SkinnedNPREffect()
+{}
+
+// Animation settings.
+void SkinnedNPREffect::SetWeightsPerVertex(int value)
+{
+ if ((value != 1) &&
+ (value != 2) &&
+ (value != 4))
+ {
+ throw std::invalid_argument("WeightsPerVertex must be 1, 2, or 4");
+ }
+
+ pImpl->weightsPerVertex = value;
+}
+
+
+void SkinnedNPREffect::SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count)
+{
+ if (count > MaxBones)
+ throw std::invalid_argument("count parameter exceeds MaxBones");
+
+ auto boneConstant = pImpl->boneConstants.Bones;
+
+ for (size_t i = 0; i < count; i++)
+ {
+ #if DIRECTX_MATH_VERSION >= 313
+ XMStoreFloat3x4A(reinterpret_cast(&boneConstant[i]), value[i]);
+ #else
+ // Xbox One XDK has an older version of DirectXMath
+ XMMATRIX boneMatrix = XMMatrixTranspose(value[i]);
+
+ boneConstant[i][0] = boneMatrix.r[0];
+ boneConstant[i][1] = boneMatrix.r[1];
+ boneConstant[i][2] = boneMatrix.r[2];
+ #endif
+ }
+
+ pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferBones;
+}
+
+
+void SkinnedNPREffect::ResetBoneTransforms()
+{
+ auto boneConstant = pImpl->boneConstants.Bones;
+
+ for (size_t i = 0; i < MaxBones; ++i)
+ {
+ boneConstant[i][0] = g_XMIdentityR0;
+ boneConstant[i][1] = g_XMIdentityR1;
+ boneConstant[i][2] = g_XMIdentityR2;
+ }
+
+ pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferBones;
+}
diff --git a/Src/NPREffectFactory.cpp b/Src/NPREffectFactory.cpp
new file mode 100644
index 00000000..95139786
--- /dev/null
+++ b/Src/NPREffectFactory.cpp
@@ -0,0 +1,455 @@
+//--------------------------------------------------------------------------------------
+// File: NPREffectFactory.cpp
+//
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+//
+// https://go.microsoft.com/fwlink/?LinkId=248929
+//--------------------------------------------------------------------------------------
+
+#include "pch.h"
+#include "Effects.h"
+#include "DemandCreate.h"
+#include "SharedResourcePool.h"
+
+#include "DDSTextureLoader.h"
+#include "WICTextureLoader.h"
+
+using namespace DirectX;
+using Microsoft::WRL::ComPtr;
+
+namespace
+{
+ template
+ void SetMaterialProperties(_In_ T* effect, const NPREffectFactory::EffectInfo& info, NPREffect::Mode mode)
+ {
+ effect->SetMode(mode);
+
+ effect->EnableDefaultLighting();
+
+ effect->SetAlpha(info.alpha);
+
+ // Most DirectX Tool Kit effects do not have an ambient material color.
+
+ XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
+ effect->SetDiffuseColor(color);
+
+ if (info.specularColor.x != 0 || info.specularColor.y != 0 || info.specularColor.z != 0)
+ {
+ color = XMLoadFloat3(&info.specularColor);
+ effect->SetSpecularColor(color);
+ }
+ else
+ {
+ effect->DisableSpecular();
+ }
+
+ if (info.biasedVertexNormals)
+ {
+ effect->SetBiasedVertexNormals(true);
+ }
+ }
+}
+
+// Internal NPREffectFactory implementation class. Only one of these helpers is allocated
+// per D3D device, even if there are multiple public facing NPREffectFactory instances.
+class NPREffectFactory::Impl
+{
+public:
+ explicit Impl(_In_ ID3D11Device* device)
+ : mPath{},
+ mMode(NPREffect::Mode_Cel),
+ mDevice(device),
+ mSharing(true),
+ mForceSRGB(false),
+ mUseEmissiveForMatCap(true)
+ {
+ if (!device)
+ throw std::invalid_argument("Direct3D device is null");
+ }
+
+ Impl(const Impl&) = delete;
+ Impl& operator=(const Impl&) = delete;
+
+ Impl(Impl&&) = delete;
+ Impl& operator=(Impl&&) = delete;
+
+ std::shared_ptr CreateEffect(_In_ NPREffectFactory* factory, _In_ const EffectFactory::EffectInfo& info, _In_opt_ ID3D11DeviceContext* deviceContext);
+ void CreateTexture(_In_z_ const wchar_t* texture, _In_opt_ ID3D11DeviceContext* deviceContext, _Outptr_ ID3D11ShaderResourceView** textureView);
+
+ void ReleaseCache();
+
+ static SharedResourcePool instancePool;
+
+ wchar_t mPath[MAX_PATH];
+
+ NPREffect::Mode mMode;
+
+ ComPtr mMatCap;
+ ComPtr mDevice;
+
+ bool mSharing;
+ bool mForceSRGB;
+ bool mUseEmissiveForMatCap;
+
+private:
+ using EffectCache = std::map< std::wstring, std::shared_ptr >;
+ using TextureCache = std::map< std::wstring, ComPtr >;
+
+ EffectCache mEffectCache;
+ EffectCache mEffectCacheSkinning;
+ EffectCache mEffectCacheDualTexture;
+ TextureCache mTextureCache;
+
+ std::mutex mutex;
+};
+
+
+// Global instance pool.
+SharedResourcePool NPREffectFactory::Impl::instancePool;
+
+
+_Use_decl_annotations_
+std::shared_ptr NPREffectFactory::Impl::CreateEffect(NPREffectFactory* factory, const EffectFactory::EffectInfo& info, ID3D11DeviceContext* deviceContext)
+{
+ if (info.enableSkinning)
+ {
+ // SkinnedNPREffect
+ if (mSharing && info.name && *info.name)
+ {
+ auto it = mEffectCacheSkinning.find(info.name);
+ if (mSharing && it != mEffectCacheSkinning.end())
+ {
+ return it->second;
+ }
+ }
+
+ auto effect = std::make_shared(mDevice.Get());
+
+ SetMaterialProperties(effect.get(), info, mMode);
+
+ if (info.diffuseTexture && *info.diffuseTexture)
+ {
+ ComPtr srv;
+ factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
+ effect->SetTexture(srv.Get());
+ }
+
+ if (mMode == NPREffect::Mode_MatCap)
+ {
+ if (mUseEmissiveForMatCap && info.emissiveTexture && *info.emissiveTexture)
+ {
+ ComPtr srv;
+ factory->CreateTexture(info.emissiveTexture, deviceContext, srv.GetAddressOf());
+ effect->SetMatCap(srv.Get());
+ }
+ else
+ {
+ effect->SetMatCap(mMatCap.Get());
+ }
+ }
+
+ if (mSharing && info.name && *info.name)
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(info.name, effect);
+ mEffectCacheSkinning.insert(v);
+ }
+
+ return std::move(effect);
+ }
+ else if (info.enableDualTexture)
+ {
+ // DualTextureEffect
+ if (mSharing && info.name && *info.name)
+ {
+ auto it = mEffectCacheDualTexture.find(info.name);
+ if (mSharing && it != mEffectCacheDualTexture.end())
+ {
+ return it->second;
+ }
+ }
+
+ auto effect = std::make_shared(mDevice.Get());
+
+ // Dual texture effect doesn't support lighting (usually it's lightmaps)
+
+ effect->SetAlpha(info.alpha);
+
+ if (info.perVertexColor)
+ {
+ effect->SetVertexColorEnabled(true);
+ }
+
+ const XMVECTOR color = XMLoadFloat3(&info.diffuseColor);
+ effect->SetDiffuseColor(color);
+
+ if (info.diffuseTexture && *info.diffuseTexture)
+ {
+ ComPtr srv;
+
+ factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
+
+ effect->SetTexture(srv.Get());
+ }
+
+ if (info.emissiveTexture && *info.emissiveTexture)
+ {
+ ComPtr srv;
+
+ factory->CreateTexture(info.emissiveTexture, deviceContext, srv.GetAddressOf());
+
+ effect->SetTexture2(srv.Get());
+ }
+ else if (info.specularTexture && *info.specularTexture)
+ {
+ // If there's no emissive texture specified, use the specular texture as the second texture
+ ComPtr srv;
+
+ factory->CreateTexture(info.specularTexture, deviceContext, srv.GetAddressOf());
+
+ effect->SetTexture2(srv.Get());
+ }
+
+ if (mSharing && info.name && *info.name)
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(info.name, effect);
+ mEffectCacheDualTexture.insert(v);
+ }
+
+ return std::move(effect);
+ }
+ else
+ {
+ // NPREffect
+ if (mSharing && info.name && *info.name)
+ {
+ auto it = mEffectCache.find(info.name);
+ if (mSharing && it != mEffectCache.end())
+ {
+ return it->second;
+ }
+ }
+
+ auto effect = std::make_shared(mDevice.Get());
+
+ SetMaterialProperties(effect.get(), info, mMode);
+
+ if (info.perVertexColor)
+ {
+ effect->SetVertexColorEnabled(true);
+ }
+
+ if (info.diffuseTexture && *info.diffuseTexture)
+ {
+ ComPtr srv;
+
+ factory->CreateTexture(info.diffuseTexture, deviceContext, srv.GetAddressOf());
+
+ effect->SetTexture(srv.Get());
+ effect->SetTextureEnabled(true);
+ }
+
+ if (mMode == NPREffect::Mode_MatCap)
+ {
+ // TODO: Use emissiveTexture or specularTexture for matcap?
+ effect->SetMatCap(mMatCap.Get());
+ }
+
+ if (mSharing && info.name && *info.name)
+ {
+ std::lock_guard lock(mutex);
+ EffectCache::value_type v(info.name, effect);
+ mEffectCache.insert(v);
+ }
+
+ return std::move(effect);
+ }
+}
+
+_Use_decl_annotations_
+void NPREffectFactory::Impl::CreateTexture(const wchar_t* name, ID3D11DeviceContext* deviceContext, ID3D11ShaderResourceView** textureView)
+{
+ if (!name || !textureView)
+ throw std::invalid_argument("name and textureView parameters can't be null");
+
+#if defined(_XBOX_ONE) && defined(_TITLE)
+ UNREFERENCED_PARAMETER(deviceContext);
+#endif
+
+ auto it = mTextureCache.find(name);
+
+ if (mSharing && it != mTextureCache.end())
+ {
+ ID3D11ShaderResourceView* srv = it->second.Get();
+ srv->AddRef();
+ *textureView = srv;
+ }
+ else
+ {
+ wchar_t fullName[MAX_PATH] = {};
+ wcscpy_s(fullName, mPath);
+ wcscat_s(fullName, name);
+
+ WIN32_FILE_ATTRIBUTE_DATA fileAttr = {};
+ if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))
+ {
+ // Try Current Working Directory (CWD)
+ wcscpy_s(fullName, name);
+ if (!GetFileAttributesExW(fullName, GetFileExInfoStandard, &fileAttr))
+ {
+ DebugTrace("ERROR: NPREffectFactory could not find texture file '%ls'\n", name);
+ throw std::system_error(std::error_code(static_cast(GetLastError()), std::system_category()), "NPREffectFactory::CreateTexture");
+ }
+ }
+
+ wchar_t ext[_MAX_EXT] = {};
+ _wsplitpath_s(name, nullptr, 0, nullptr, 0, nullptr, 0, ext, _MAX_EXT);
+ const bool isdds = _wcsicmp(ext, L".dds") == 0;
+
+ if (isdds)
+ {
+ HRESULT hr = CreateDDSTextureFromFileEx(
+ mDevice.Get(), fullName, 0,
+ D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
+ mForceSRGB ? DDS_LOADER_FORCE_SRGB : DDS_LOADER_DEFAULT, nullptr, textureView);
+ if (FAILED(hr))
+ {
+ DebugTrace("ERROR: CreateDDSTextureFromFile failed (%08X) for '%ls'\n",
+ static_cast(hr), fullName);
+ throw std::runtime_error("NPREffectFactory::CreateDDSTextureFromFile");
+ }
+ }
+ #if !defined(_XBOX_ONE) || !defined(_TITLE)
+ else if (deviceContext)
+ {
+ std::lock_guard lock(mutex);
+ HRESULT hr = CreateWICTextureFromFileEx(
+ mDevice.Get(), deviceContext, fullName, 0,
+ D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
+ mForceSRGB ? WIC_LOADER_FORCE_SRGB : WIC_LOADER_DEFAULT, nullptr, textureView);
+ if (FAILED(hr))
+ {
+ DebugTrace("ERROR: CreateWICTextureFromFile failed (%08X) for '%ls'\n",
+ static_cast(hr), fullName);
+ throw std::runtime_error("NPREffectFactory::CreateWICTextureFromFile");
+ }
+ }
+ #endif
+ else
+ {
+ HRESULT hr = CreateWICTextureFromFileEx(
+ mDevice.Get(), fullName, 0,
+ D3D11_USAGE_DEFAULT, D3D11_BIND_SHADER_RESOURCE, 0, 0,
+ mForceSRGB ? WIC_LOADER_FORCE_SRGB : WIC_LOADER_DEFAULT, nullptr, textureView);
+ if (FAILED(hr))
+ {
+ DebugTrace("ERROR: CreateWICTextureFromFile failed (%08X) for '%ls'\n",
+ static_cast(hr), fullName);
+ throw std::runtime_error("NPREffectFactory::CreateWICTextureFromFile");
+ }
+ }
+
+ if (mSharing && *name && it == mTextureCache.end())
+ {
+ std::lock_guard lock(mutex);
+ TextureCache::value_type v(name, *textureView);
+ mTextureCache.insert(v);
+ }
+ }
+}
+
+void NPREffectFactory::Impl::ReleaseCache()
+{
+ std::lock_guard lock(mutex);
+ mEffectCache.clear();
+ mEffectCacheSkinning.clear();
+ mEffectCacheDualTexture.clear();
+ mTextureCache.clear();
+}
+
+
+
+//--------------------------------------------------------------------------------------
+// NPREffectFactory
+//--------------------------------------------------------------------------------------
+
+NPREffectFactory::NPREffectFactory(_In_ ID3D11Device* device)
+ : pImpl(Impl::instancePool.DemandCreate(device))
+{}
+
+
+NPREffectFactory::NPREffectFactory(NPREffectFactory&&) noexcept = default;
+NPREffectFactory& NPREffectFactory::operator= (NPREffectFactory&&) noexcept = default;
+NPREffectFactory::~NPREffectFactory() = default;
+
+
+_Use_decl_annotations_
+std::shared_ptr NPREffectFactory::CreateEffect(const EffectInfo& info, ID3D11DeviceContext* deviceContext)
+{
+ return pImpl->CreateEffect(this, info, deviceContext);
+}
+
+_Use_decl_annotations_
+void NPREffectFactory::CreateTexture(const wchar_t* name, ID3D11DeviceContext* deviceContext, ID3D11ShaderResourceView** textureView)
+{
+ return pImpl->CreateTexture(name, deviceContext, textureView);
+}
+
+void NPREffectFactory::ReleaseCache()
+{
+ pImpl->ReleaseCache();
+}
+
+void NPREffectFactory::SetSharing(bool enabled) noexcept
+{
+ pImpl->mSharing = enabled;
+}
+
+void NPREffectFactory::EnableForceSRGB(bool forceSRGB) noexcept
+{
+ pImpl->mForceSRGB = forceSRGB;
+}
+
+void NPREffectFactory::SetDirectory(_In_opt_z_ const wchar_t* path) noexcept
+{
+ if (path && *path != 0)
+ {
+ wcscpy_s(pImpl->mPath, path);
+ size_t len = wcsnlen(pImpl->mPath, MAX_PATH);
+ if (len > 0 && len < (MAX_PATH - 1))
+ {
+ // Ensure it has a trailing slash
+ if (pImpl->mPath[len - 1] != L'\\')
+ {
+ pImpl->mPath[len] = L'\\';
+ pImpl->mPath[len + 1] = 0;
+ }
+ }
+ }
+ else
+ *pImpl->mPath = 0;
+}
+
+void NPREffectFactory::SetMode(NPREffect::Mode mode) noexcept
+{
+ pImpl->mMode = mode;
+}
+
+void NPREffectFactory::SetDefaultMatCap(_In_opt_ ID3D11ShaderResourceView* textureView) noexcept
+{
+ pImpl->mMatCap = textureView;
+}
+
+
+void NPREffectFactory::SetEmissiveAsMatCap(bool value) noexcept
+{
+ pImpl->mUseEmissiveForMatCap = value;
+}
+
+
+ID3D11Device* NPREffectFactory::GetDevice() const noexcept
+{
+ return pImpl->mDevice.Get();
+}
diff --git a/Src/PBREffectFactory.cpp b/Src/PBREffectFactory.cpp
index 89a1c994..a48bdd1b 100644
--- a/Src/PBREffectFactory.cpp
+++ b/Src/PBREffectFactory.cpp
@@ -116,8 +116,6 @@ class PBREffectFactory::Impl
_Outptr_ ID3D11ShaderResourceView** textureView);
void ReleaseCache();
- void SetSharing(bool enabled) noexcept { mSharing = enabled; }
- void EnableForceSRGB(bool forceSRGB) noexcept { mForceSRGB = forceSRGB; }
static SharedResourcePool instancePool;
@@ -125,6 +123,9 @@ class PBREffectFactory::Impl
ComPtr mDevice;
+ bool mSharing;
+ bool mForceSRGB;
+
private:
using EffectCache = std::map< std::wstring, std::shared_ptr >;
using TextureCache = std::map< std::wstring, ComPtr >;
@@ -133,9 +134,6 @@ class PBREffectFactory::Impl
EffectCache mEffectCacheSkinning;
TextureCache mTextureCache;
- bool mSharing;
- bool mForceSRGB;
-
std::mutex mutex;
};
@@ -341,12 +339,12 @@ void PBREffectFactory::ReleaseCache()
void PBREffectFactory::SetSharing(bool enabled) noexcept
{
- pImpl->SetSharing(enabled);
+ pImpl->mSharing = enabled;
}
void PBREffectFactory::EnableForceSRGB(bool forceSRGB) noexcept
{
- pImpl->EnableForceSRGB(forceSRGB);
+ pImpl->mForceSRGB = forceSRGB;
}
void PBREffectFactory::SetDirectory(_In_opt_z_ const wchar_t* path) noexcept
diff --git a/Src/Shaders/CompileShaders.cmd b/Src/Shaders/CompileShaders.cmd
index 4ecfff9f..d996659a 100644
--- a/Src/Shaders/CompileShaders.cmd
+++ b/Src/Shaders/CompileShaders.cmd
@@ -246,6 +246,9 @@ call :CompileShader%1 NPREffect vs VSNPREffectBnInstTx
call :CompileShader%1 NPREffect vs VSNPREffectVcInstTx
call :CompileShader%1 NPREffect vs VSNPREffectVcBnInstTx
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTx
+call :CompileShader%1 NPREffect vs VSSkinnedNPREffectTxBn
+
call :CompileShader%1 NPREffect ps PSCelShading
call :CompileShader%1 NPREffect ps PSCelShadingTx
diff --git a/Src/Shaders/NPREffect.fx b/Src/Shaders/NPREffect.fx
index 3f668f7d..93d001ce 100644
--- a/Src/Shaders/NPREffect.fx
+++ b/Src/Shaders/NPREffect.fx
@@ -41,9 +41,16 @@ cbuffer Parameters : register(b0)
float4x4 WorldViewProj : packoffset(c15);
};
+cbuffer SkinningParameters : register(b1)
+{
+ float4x3 Bones[72];
+}
+
#include "Structures.fxh"
#include "Utilities.fxh"
+#include "Skinning.fxh"
+
VSOutputPixelLighting ComputeCommonVS(float4 position, float3 normal)
{
@@ -224,6 +231,28 @@ VSOutputPixelLightingTx VSNPREffectVcBnInstTx(VSInputNmTxVcInst vin)
}
+// Vertex shader: skinning (four bones) + texture.
+VSOutputPixelLightingTx VSSkinnedNPREffectTx(VSInputNmTxWeights vin)
+{
+ float3 normal = Skin(vin, vin.Normal, 4);
+
+ VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord);
+ vout.Diffuse = float4(DiffuseColor, Alpha);
+ return vout;
+}
+
+VSOutputPixelLightingTx VSSkinnedNPREffectTxBn(VSInputNmTxWeights vin)
+{
+ float3 normal = BiasX2(vin.Normal);
+
+ normal = Skin(vin, normal, 4);
+
+ VSOutputPixelLightingTx vout = ComputeCommonVSTx(vin.Position, normal, vin.TexCoord);
+ vout.Diffuse = float4(DiffuseColor, Alpha);
+ return vout;
+}
+
+
//--- Cel shading ---
float Quantize(float intensity, float bands)
{