//-------------------------------------------------------------------------------------- // File: DualTextureEffect.cpp // // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- #include "pch.h" #include "EffectCommon.h" using namespace DirectX; using Microsoft::WRL::ComPtr; // Constant buffer layout. Must match the shader! struct DualTextureEffectConstants { XMVECTOR diffuseColor; XMVECTOR fogColor; XMVECTOR fogVector; XMMATRIX worldViewProj; }; static_assert((sizeof(DualTextureEffectConstants) % 16) == 0, "CB size not padded correctly"); // Traits type describes our characteristics to the EffectBase template. struct DualTextureEffectTraits { using ConstantBufferType = DualTextureEffectConstants; static constexpr int VertexShaderCount = 4; static constexpr int PixelShaderCount = 2; static constexpr int ShaderPermutationCount = 4; }; // Internal DualTextureEffect implementation class. class DualTextureEffect::Impl : public EffectBase { public: Impl(_In_ ID3D11Device* device); bool vertexColorEnabled; EffectColor color; ComPtr texture2; int GetCurrentShaderPermutation() const noexcept; void Apply(_In_ ID3D11DeviceContext* deviceContext); }; // Include the precompiled shader code. namespace { #if defined(_XBOX_ONE) && defined(_TITLE) #include "Shaders/Compiled/XboxOneDualTextureEffect_VSDualTexture.inc" #include "Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureNoFog.inc" #include "Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureVc.inc" #include "Shaders/Compiled/XboxOneDualTextureEffect_VSDualTextureVcNoFog.inc" #include "Shaders/Compiled/XboxOneDualTextureEffect_PSDualTexture.inc" #include "Shaders/Compiled/XboxOneDualTextureEffect_PSDualTextureNoFog.inc" #else #include "Shaders/Compiled/DualTextureEffect_VSDualTexture.inc" #include "Shaders/Compiled/DualTextureEffect_VSDualTextureNoFog.inc" #include "Shaders/Compiled/DualTextureEffect_VSDualTextureVc.inc" #include "Shaders/Compiled/DualTextureEffect_VSDualTextureVcNoFog.inc" #include "Shaders/Compiled/DualTextureEffect_PSDualTexture.inc" #include "Shaders/Compiled/DualTextureEffect_PSDualTextureNoFog.inc" #endif } template<> const ShaderBytecode EffectBase::VertexShaderBytecode[] = { { DualTextureEffect_VSDualTexture, sizeof(DualTextureEffect_VSDualTexture) }, { DualTextureEffect_VSDualTextureNoFog, sizeof(DualTextureEffect_VSDualTextureNoFog) }, { DualTextureEffect_VSDualTextureVc, sizeof(DualTextureEffect_VSDualTextureVc) }, { DualTextureEffect_VSDualTextureVcNoFog, sizeof(DualTextureEffect_VSDualTextureVcNoFog) }, }; template<> const int EffectBase::VertexShaderIndices[] = { 0, // basic 1, // no fog 2, // vertex color 3, // vertex color, no fog }; template<> const ShaderBytecode EffectBase::PixelShaderBytecode[] = { { DualTextureEffect_PSDualTexture, sizeof(DualTextureEffect_PSDualTexture) }, { DualTextureEffect_PSDualTextureNoFog, sizeof(DualTextureEffect_PSDualTextureNoFog) }, }; template<> const int EffectBase::PixelShaderIndices[] = { 0, // basic 1, // no fog 0, // vertex color 1, // vertex color, no fog }; // Global pool of per-device DualTextureEffect resources. template<> SharedResourcePool::DeviceResources> EffectBase::deviceResourcesPool = {}; // Constructor. DualTextureEffect::Impl::Impl(_In_ ID3D11Device* device) : EffectBase(device), vertexColorEnabled(false) { static_assert(_countof(EffectBase::VertexShaderIndices) == DualTextureEffectTraits::ShaderPermutationCount, "array/max mismatch"); static_assert(_countof(EffectBase::VertexShaderBytecode) == DualTextureEffectTraits::VertexShaderCount, "array/max mismatch"); static_assert(_countof(EffectBase::PixelShaderBytecode) == DualTextureEffectTraits::PixelShaderCount, "array/max mismatch"); static_assert(_countof(EffectBase::PixelShaderIndices) == DualTextureEffectTraits::ShaderPermutationCount, "array/max mismatch"); } int DualTextureEffect::Impl::GetCurrentShaderPermutation() const noexcept { int permutation = 0; // Use optimized shaders if fog is disabled. if (!fog.enabled) { permutation += 1; } // Support vertex coloring? if (vertexColorEnabled) { permutation += 2; } return permutation; } // Sets our state onto the D3D device. void DualTextureEffect::Impl::Apply(_In_ ID3D11DeviceContext* deviceContext) { // Compute derived parameter values. matrices.SetConstants(dirtyFlags, constants.worldViewProj); fog.SetConstants(dirtyFlags, matrices.worldView, constants.fogVector); color.SetConstants(dirtyFlags, constants.diffuseColor); // Set the textures. ID3D11ShaderResourceView* textures[2] = { texture.Get(), texture2.Get(), }; deviceContext->PSSetShaderResources(0, 2, textures); // Set shaders and constant buffers. ApplyShaders(deviceContext, GetCurrentShaderPermutation()); } // Public constructor. DualTextureEffect::DualTextureEffect(_In_ ID3D11Device* device) : pImpl(std::make_unique(device)) { } // Move constructor. DualTextureEffect::DualTextureEffect(DualTextureEffect&& moveFrom) noexcept : pImpl(std::move(moveFrom.pImpl)) { } // Move assignment. DualTextureEffect& DualTextureEffect::operator= (DualTextureEffect&& moveFrom) noexcept { pImpl = std::move(moveFrom.pImpl); return *this; } // Public destructor. DualTextureEffect::~DualTextureEffect() { } // IEffect methods. void DualTextureEffect::Apply(_In_ ID3D11DeviceContext* deviceContext) { pImpl->Apply(deviceContext); } void DualTextureEffect::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) { pImpl->GetVertexShaderBytecode(pImpl->GetCurrentShaderPermutation(), pShaderByteCode, pByteCodeLength); } // Camera settings. void XM_CALLCONV DualTextureEffect::SetWorld(FXMMATRIX value) { pImpl->matrices.world = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::FogVector; } void XM_CALLCONV DualTextureEffect::SetView(FXMMATRIX value) { pImpl->matrices.view = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector; } void XM_CALLCONV DualTextureEffect::SetProjection(FXMMATRIX value) { pImpl->matrices.projection = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj; } void XM_CALLCONV DualTextureEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection) { pImpl->matrices.world = world; pImpl->matrices.view = view; pImpl->matrices.projection = projection; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition | EffectDirtyFlags::FogVector; } // Material settings. void XM_CALLCONV DualTextureEffect::SetDiffuseColor(FXMVECTOR value) { pImpl->color.diffuseColor = value; pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor; } void DualTextureEffect::SetAlpha(float value) { pImpl->color.alpha = value; pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor; } void XM_CALLCONV DualTextureEffect::SetColorAndAlpha(FXMVECTOR value) { pImpl->color.diffuseColor = value; pImpl->color.alpha = XMVectorGetW(value); pImpl->dirtyFlags |= EffectDirtyFlags::MaterialColor; } // Fog settings. void DualTextureEffect::SetFogEnabled(bool value) { pImpl->fog.enabled = value; pImpl->dirtyFlags |= EffectDirtyFlags::FogEnable; } void DualTextureEffect::SetFogStart(float value) { pImpl->fog.start = value; pImpl->dirtyFlags |= EffectDirtyFlags::FogVector; } void DualTextureEffect::SetFogEnd(float value) { pImpl->fog.end = value; pImpl->dirtyFlags |= EffectDirtyFlags::FogVector; } void XM_CALLCONV DualTextureEffect::SetFogColor(FXMVECTOR value) { pImpl->constants.fogColor = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBuffer; } // Vertex color setting. void DualTextureEffect::SetVertexColorEnabled(bool value) { pImpl->vertexColorEnabled = value; } // Texture settings. void DualTextureEffect::SetTexture(_In_opt_ ID3D11ShaderResourceView* value) { pImpl->texture = value; } void DualTextureEffect::SetTexture2(_In_opt_ ID3D11ShaderResourceView* value) { pImpl->texture2 = value; }