//-------------------------------------------------------------------------------------- // File: DGSLEffect.cpp // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- #include "pch.h" #include "EffectCommon.h" #include "DemandCreate.h" // // Based on the Visual Studio 3D Starter Kit // // http://aka.ms/vs3dkit // namespace DirectX { namespace EffectDirtyFlags { const int ConstantBufferMaterial = 0x10000; const int ConstantBufferLight = 0x20000; const int ConstantBufferObject = 0x40000; const int ConstantBufferMisc = 0x80000; const int ConstantBufferBones = 0x100000; } } using namespace DirectX; using Microsoft::WRL::ComPtr; // Constant buffer layout. Must match the shader! #pragma pack(push,1) // Slot 0 struct MaterialConstants { XMVECTOR Ambient; XMVECTOR Diffuse; XMVECTOR Specular; XMVECTOR Emissive; float SpecularPower; float Padding0; float Padding1; float Padding2; }; // Slot 1 struct LightConstants { XMVECTOR Ambient; XMVECTOR LightColor[DGSLEffect::MaxDirectionalLights]; XMVECTOR LightAttenuation[DGSLEffect::MaxDirectionalLights]; XMVECTOR LightDirection[DGSLEffect::MaxDirectionalLights]; XMVECTOR LightSpecularIntensity[DGSLEffect::MaxDirectionalLights]; UINT IsPointLight[DGSLEffect::MaxDirectionalLights]; UINT ActiveLights; float Padding0; float Padding1; float Padding2; }; // Note - DGSL does not appear to make use of LightAttenuation or IsPointLight. Not sure if it uses ActiveLights either. // Slot 2 struct ObjectConstants { XMMATRIX LocalToWorld4x4; XMMATRIX LocalToProjected4x4; XMMATRIX WorldToLocal4x4; XMMATRIX WorldToView4x4; XMMATRIX UvTransform4x4; XMVECTOR EyePosition; }; // Slot 3 struct MiscConstants { float ViewportWidth; float ViewportHeight; float Time; float Padding1; }; // Slot 4 struct BoneConstants { XMVECTOR Bones[DGSLEffect::MaxBones][3]; }; #pragma pack(pop) static_assert( ( sizeof(MaterialConstants) % 16 ) == 0, "CB size not padded correctly" ); static_assert( ( sizeof(LightConstants) % 16 ) == 0, "CB size not padded correctly" ); static_assert( ( sizeof(ObjectConstants) % 16 ) == 0, "CB size not padded correctly" ); static_assert( ( sizeof(MiscConstants) % 16 ) == 0, "CB size not padded correctly" ); static_assert( ( sizeof(BoneConstants) % 16 ) == 0, "CB size not padded correctly" ); __declspec(align(16)) struct DGSLEffectConstants { MaterialConstants material; LightConstants light; ObjectConstants object; MiscConstants misc; BoneConstants bones; }; struct DGSLEffectTraits { static const int VertexShaderCount = 8; static const int PixelShaderCount = 12; static const ShaderBytecode VertexShaderBytecode[VertexShaderCount]; static const ShaderBytecode PixelShaderBytecode[PixelShaderCount]; }; // Include the precompiled shader code. namespace { #if defined(_XBOX_ONE) && defined(_TITLE) // VS #include "Shaders/Compiled/XboxOneDGSLEffect_main.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_mainVc.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main1Bones.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main1BonesVc.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main2Bones.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main2BonesVc.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main4Bones.inc" #include "Shaders/Compiled/XboxOneDGSLEffect_main4BonesVc.inc" // PS #include "Shaders/Compiled/XboxOneDGSLUnlit_main.inc" #include "Shaders/Compiled/XboxOneDGSLLambert_main.inc" #include "Shaders/Compiled/XboxOneDGSLPhong_main.inc" #include "Shaders/Compiled/XboxOneDGSLUnlit_mainTk.inc" #include "Shaders/Compiled/XboxOneDGSLLambert_mainTk.inc" #include "Shaders/Compiled/XboxOneDGSLPhong_mainTk.inc" #include "Shaders/Compiled/XboxOneDGSLUnlit_mainTx.inc" #include "Shaders/Compiled/XboxOneDGSLLambert_mainTx.inc" #include "Shaders/Compiled/XboxOneDGSLPhong_mainTx.inc" #include "Shaders/Compiled/XboxOneDGSLUnlit_mainTxTk.inc" #include "Shaders/Compiled/XboxOneDGSLLambert_mainTxTk.inc" #include "Shaders/Compiled/XboxOneDGSLPhong_mainTxTk.inc" #else // VS #include "Shaders/Compiled/DGSLEffect_main.inc" #include "Shaders/Compiled/DGSLEffect_mainVc.inc" #include "Shaders/Compiled/DGSLEffect_main1Bones.inc" #include "Shaders/Compiled/DGSLEffect_main1BonesVc.inc" #include "Shaders/Compiled/DGSLEffect_main2Bones.inc" #include "Shaders/Compiled/DGSLEffect_main2BonesVc.inc" #include "Shaders/Compiled/DGSLEffect_main4Bones.inc" #include "Shaders/Compiled/DGSLEffect_main4BonesVc.inc" // PS #include "Shaders/Compiled/DGSLUnlit_main.inc" #include "Shaders/Compiled/DGSLLambert_main.inc" #include "Shaders/Compiled/DGSLPhong_main.inc" #include "Shaders/Compiled/DGSLUnlit_mainTk.inc" #include "Shaders/Compiled/DGSLLambert_mainTk.inc" #include "Shaders/Compiled/DGSLPhong_mainTk.inc" #include "Shaders/Compiled/DGSLUnlit_mainTx.inc" #include "Shaders/Compiled/DGSLLambert_mainTx.inc" #include "Shaders/Compiled/DGSLPhong_mainTx.inc" #include "Shaders/Compiled/DGSLUnlit_mainTxTk.inc" #include "Shaders/Compiled/DGSLLambert_mainTxTk.inc" #include "Shaders/Compiled/DGSLPhong_mainTxTk.inc" #endif } const ShaderBytecode DGSLEffectTraits::VertexShaderBytecode[] = { { DGSLEffect_main, sizeof(DGSLEffect_main) }, { DGSLEffect_mainVc, sizeof(DGSLEffect_mainVc) }, { DGSLEffect_main1Bones, sizeof(DGSLEffect_main1Bones) }, { DGSLEffect_main1BonesVc, sizeof(DGSLEffect_main1BonesVc) }, { DGSLEffect_main2Bones, sizeof(DGSLEffect_main2Bones) }, { DGSLEffect_main2BonesVc, sizeof(DGSLEffect_main2BonesVc) }, { DGSLEffect_main4Bones, sizeof(DGSLEffect_main4Bones) }, { DGSLEffect_main4BonesVc, sizeof(DGSLEffect_main4BonesVc) }, }; const ShaderBytecode DGSLEffectTraits::PixelShaderBytecode[] = { { DGSLUnlit_main, sizeof(DGSLUnlit_main) }, // UNLIT (no texture) { DGSLLambert_main, sizeof(DGSLLambert_main) }, // LAMBERT (no texture) { DGSLPhong_main, sizeof(DGSLPhong_main) }, // PHONG (no texture) { DGSLUnlit_mainTx, sizeof(DGSLUnlit_mainTx) }, // UNLIT (textured) { DGSLLambert_mainTx, sizeof(DGSLLambert_mainTx) }, // LAMBERT (textured) { DGSLPhong_mainTx, sizeof(DGSLPhong_mainTx) }, // PHONG (textured) { DGSLUnlit_mainTk, sizeof(DGSLUnlit_mainTk) }, // UNLIT (no texture, discard) { DGSLLambert_mainTk, sizeof(DGSLLambert_mainTk) }, // LAMBERT (no texture, discard) { DGSLPhong_mainTk, sizeof(DGSLPhong_mainTk) }, // PHONG (no texture, discard) { DGSLUnlit_mainTxTk, sizeof(DGSLUnlit_mainTxTk) }, // UNLIT (textured, discard) { DGSLLambert_mainTxTk, sizeof(DGSLLambert_mainTxTk) }, // LAMBERT (textured, discard) { DGSLPhong_mainTxTk, sizeof(DGSLPhong_mainTxTk) }, // PHONG (textured, discard) }; class DGSLEffect::Impl : public AlignedNew { public: Impl( _In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader, _In_ bool enableSkinning ) : dirtyFlags( INT_MAX ), vertexColorEnabled(false), textureEnabled(false), specularEnabled(false), alphaDiscardEnabled(false), weightsPerVertex( enableSkinning ? 4 : 0 ), mPixelShader( pixelShader ), mCBMaterial( device ), mCBLight( device ), mCBObject( device ), mCBMisc( device ), mDeviceResources( deviceResourcesPool.DemandCreate(device) ) { static_assert( _countof(DGSLEffectTraits::VertexShaderBytecode) == DGSLEffectTraits::VertexShaderCount, "array/max mismatch" ); static_assert( _countof(DGSLEffectTraits::PixelShaderBytecode) == DGSLEffectTraits::PixelShaderCount, "array/max mismatch" ); memset( &constants, 0, sizeof(constants) ); XMMATRIX id = XMMatrixIdentity(); world = id; view = id; projection = id; constants.material.Specular = g_XMOne; constants.material.SpecularPower = 16; constants.object.UvTransform4x4 = id; static_assert( MaxDirectionalLights == 4, "Mismatch with DGSL pipline" ); for( int i = 0; i < MaxDirectionalLights; ++i ) { lightEnabled[i] = (i == 0); lightDiffuseColor[i] = g_XMZero; lightSpecularColor[i] = g_XMOne; constants.light.LightDirection[i] = g_XMNegIdentityR1; constants.light.LightColor[i] = lightEnabled[i] ? lightDiffuseColor[i] : g_XMZero; constants.light.LightSpecularIntensity[i] = lightEnabled[i] ? lightSpecularColor[i] : g_XMZero; } if ( enableSkinning ) { mCBBone.Create( device ); for( size_t j = 0; j < MaxBones; ++j ) { constants.bones.Bones[ j ][0] = g_XMIdentityR0; constants.bones.Bones[ j ][1] = g_XMIdentityR1; constants.bones.Bones[ j ][2] = g_XMIdentityR2; } } } // Methods void Apply( _In_ ID3D11DeviceContext* deviceContext ); void GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength); // Fields DGSLEffectConstants constants; XMMATRIX world; XMMATRIX view; XMMATRIX projection; bool lightEnabled[MaxDirectionalLights]; XMVECTOR lightDiffuseColor[MaxDirectionalLights]; XMVECTOR lightSpecularColor[MaxDirectionalLights]; ComPtr textures[MaxTextures]; int dirtyFlags; bool vertexColorEnabled; bool textureEnabled; bool specularEnabled; bool alphaDiscardEnabled; int weightsPerVertex; private: ConstantBuffer mCBMaterial; ConstantBuffer mCBLight; ConstantBuffer mCBObject; ConstantBuffer mCBMisc; ConstantBuffer mCBBone; ComPtr mPixelShader; int GetCurrentVSPermutation() const; int GetCurrentPSPermutation() const; // Only one of these helpers is allocated per D3D device, even if there are multiple effect instances. class DeviceResources : protected EffectDeviceResources { public: DeviceResources(_In_ ID3D11Device* device) : EffectDeviceResources(device) {} // Gets or lazily creates the vertex shader. ID3D11VertexShader* GetVertexShader( int permutation ) { assert( permutation < DGSLEffectTraits::VertexShaderCount ); return DemandCreateVertexShader(mVertexShaders[permutation], DGSLEffectTraits::VertexShaderBytecode[permutation]); } // Gets or lazily creates the specified pixel shader permutation. ID3D11PixelShader* GetPixelShader( int permutation ) { assert( permutation < DGSLEffectTraits::PixelShaderCount ); return DemandCreatePixelShader(mPixelShaders[permutation], DGSLEffectTraits::PixelShaderBytecode[permutation]); } // Gets or lazily creates the default texture ID3D11ShaderResourceView* GetDefaultTexture() { return EffectDeviceResources::GetDefaultTexture(); } private: ComPtr mVertexShaders[DGSLEffectTraits::VertexShaderCount]; ComPtr mPixelShaders[DGSLEffectTraits::PixelShaderCount]; ComPtr mDefaultTexture; }; // Per-device resources. std::shared_ptr mDeviceResources; static SharedResourcePool deviceResourcesPool; }; SharedResourcePool DGSLEffect::Impl::deviceResourcesPool; void DGSLEffect::Impl::Apply( _In_ ID3D11DeviceContext* deviceContext ) { auto vertexShader = mDeviceResources->GetVertexShader( GetCurrentVSPermutation() ); auto pixelShader = mPixelShader.Get(); if( !pixelShader ) { pixelShader = mDeviceResources->GetPixelShader( GetCurrentPSPermutation() ); } deviceContext->VSSetShader( vertexShader, nullptr, 0 ); deviceContext->PSSetShader( pixelShader, nullptr, 0 ); // Check for any required matrices updates if (dirtyFlags & EffectDirtyFlags::WorldViewProj) { constants.object.LocalToWorld4x4 = XMMatrixTranspose( world ); constants.object.WorldToView4x4 = XMMatrixTranspose( view ); XMMATRIX worldView = XMMatrixMultiply( world, view ); constants.object.LocalToProjected4x4 = XMMatrixTranspose( XMMatrixMultiply( worldView, projection ) ); dirtyFlags &= ~EffectDirtyFlags::WorldViewProj; dirtyFlags |= EffectDirtyFlags::ConstantBufferObject; } if (dirtyFlags & EffectDirtyFlags::WorldInverseTranspose) { XMMATRIX worldInverse = XMMatrixInverse( nullptr, world ); constants.object.WorldToLocal4x4 = XMMatrixTranspose( worldInverse ); dirtyFlags &= ~EffectDirtyFlags::WorldInverseTranspose; dirtyFlags |= EffectDirtyFlags::ConstantBufferObject; } if (dirtyFlags & EffectDirtyFlags::EyePosition) { XMMATRIX viewInverse = XMMatrixInverse( nullptr, view ); constants.object.EyePosition = viewInverse.r[3]; dirtyFlags &= ~EffectDirtyFlags::EyePosition; dirtyFlags |= EffectDirtyFlags::ConstantBufferObject; } #if defined(_XBOX_ONE) && defined(_TITLE) void* grfxMemoryMaterial; mCBMaterial.SetData(deviceContext, constants.material, &grfxMemoryMaterial); void* grfxMemoryLight; mCBLight.SetData(deviceContext, constants.light, &grfxMemoryLight); void* grfxMemoryObject; mCBObject.SetData(deviceContext, constants.object, &grfxMemoryObject); void *grfxMemoryMisc; mCBMisc.SetData(deviceContext, constants.misc, &grfxMemoryMisc); ComPtr deviceContextX; ThrowIfFailed(deviceContext->QueryInterface(IID_GRAPHICS_PPV_ARGS(deviceContextX.GetAddressOf()))); auto buffer = mCBMaterial.GetBuffer(); deviceContextX->VSSetPlacementConstantBuffer( 0, buffer, grfxMemoryMaterial ); deviceContextX->PSSetPlacementConstantBuffer( 0, buffer, grfxMemoryMaterial ); buffer = mCBLight.GetBuffer(); deviceContextX->VSSetPlacementConstantBuffer( 1, buffer, grfxMemoryMaterial ); deviceContextX->PSSetPlacementConstantBuffer( 1, buffer, grfxMemoryMaterial ); buffer = mCBObject.GetBuffer(); deviceContextX->VSSetPlacementConstantBuffer( 2, buffer, grfxMemoryObject ); deviceContextX->PSSetPlacementConstantBuffer( 2, buffer, grfxMemoryObject ); buffer = mCBMisc.GetBuffer(); deviceContextX->VSSetPlacementConstantBuffer( 3, buffer, grfxMemoryMisc ); deviceContextX->PSSetPlacementConstantBuffer( 3, buffer, grfxMemoryMisc ); if ( weightsPerVertex > 0 ) { void* grfxMemoryBone; mCBBone.SetData(deviceContext, constants.bones, &grfxMemoryBone); deviceContextX->VSSetPlacementConstantBuffer( 4, mCBBone.GetBuffer(), grfxMemoryBone ); } #else // Make sure the constant buffers are up to date. if (dirtyFlags & EffectDirtyFlags::ConstantBufferMaterial) { mCBMaterial.SetData(deviceContext, constants.material); dirtyFlags &= ~EffectDirtyFlags::ConstantBufferMaterial; } if (dirtyFlags & EffectDirtyFlags::ConstantBufferLight) { mCBLight.SetData(deviceContext, constants.light); dirtyFlags &= ~EffectDirtyFlags::ConstantBufferLight; } if (dirtyFlags & EffectDirtyFlags::ConstantBufferObject) { mCBObject.SetData(deviceContext, constants.object); dirtyFlags &= ~EffectDirtyFlags::ConstantBufferObject; } if (dirtyFlags & EffectDirtyFlags::ConstantBufferMisc) { mCBMisc.SetData(deviceContext, constants.misc); dirtyFlags &= ~EffectDirtyFlags::ConstantBufferMisc; } if ( weightsPerVertex > 0 ) { if (dirtyFlags & EffectDirtyFlags::ConstantBufferBones) { mCBBone.SetData(deviceContext, constants.bones); dirtyFlags &= ~EffectDirtyFlags::ConstantBufferBones; } ID3D11Buffer* buffers[5] = { mCBMaterial.GetBuffer(), mCBLight.GetBuffer(), mCBObject.GetBuffer(), mCBMisc.GetBuffer(), mCBBone.GetBuffer() }; deviceContext->VSSetConstantBuffers( 0, 5, buffers ); deviceContext->PSSetConstantBuffers( 0, 4, buffers ); } else { ID3D11Buffer* buffers[4] = { mCBMaterial.GetBuffer(), mCBLight.GetBuffer(), mCBObject.GetBuffer(), mCBMisc.GetBuffer() }; deviceContext->VSSetConstantBuffers( 0, 4, buffers ); deviceContext->PSSetConstantBuffers( 0, 4, buffers ); } #endif // Set the textures if ( textureEnabled ) { ID3D11ShaderResourceView* txt[MaxTextures] = { textures[0].Get(), textures[1].Get(), textures[2].Get(), textures[3].Get(), textures[4].Get(), textures[5].Get(), textures[6].Get(), textures[7].Get() }; deviceContext->PSSetShaderResources( 0, MaxTextures, txt ); } else { ID3D11ShaderResourceView* txt[MaxTextures] = { mDeviceResources->GetDefaultTexture(), 0 }; deviceContext->PSSetShaderResources( 0, MaxTextures, txt ); } } void DGSLEffect::Impl::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) { int permutation = GetCurrentVSPermutation(); assert( permutation < DGSLEffectTraits::VertexShaderCount ); _Analysis_assume_( permutation < DGSLEffectTraits::VertexShaderCount ); auto shader = DGSLEffectTraits::VertexShaderBytecode[permutation]; *pShaderByteCode = shader.code; *pByteCodeLength = shader.length; } int DGSLEffect::Impl::GetCurrentVSPermutation() const { int permutation = (vertexColorEnabled) ? 1 : 0; if( weightsPerVertex > 0 ) { // Evaluate 1, 2, or 4 weights per vertex? permutation += 2; if (weightsPerVertex == 2) { permutation += 2; } else if (weightsPerVertex == 4) { permutation += 4; } } return permutation; } int DGSLEffect::Impl::GetCurrentPSPermutation() const { int permutation = 0; if ( constants.light.ActiveLights > 0 ) { permutation = ( specularEnabled ) ? 2 : 1; } if ( textureEnabled ) permutation += 3; if ( alphaDiscardEnabled ) permutation += 6; return permutation; } //-------------------------------------------------------------------------------------- // DGSLEffect //-------------------------------------------------------------------------------------- DGSLEffect::DGSLEffect(_In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader, _In_ bool enableSkinning) : pImpl(new Impl(device, pixelShader, enableSkinning)) { } DGSLEffect::DGSLEffect(DGSLEffect&& moveFrom) : pImpl(std::move(moveFrom.pImpl)) { } DGSLEffect& DGSLEffect::operator= (DGSLEffect&& moveFrom) { pImpl = std::move(moveFrom.pImpl); return *this; } DGSLEffect::~DGSLEffect() { } // IEffect methods void DGSLEffect::Apply(_In_ ID3D11DeviceContext* deviceContext) { pImpl->Apply(deviceContext); } void DGSLEffect::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) { pImpl->GetVertexShaderBytecode( pShaderByteCode, pByteCodeLength ); } // Camera settings void XM_CALLCONV DGSLEffect::SetWorld(FXMMATRIX value) { pImpl->world = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose; } void XM_CALLCONV DGSLEffect::SetView(FXMMATRIX value) { pImpl->view = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::EyePosition; } void XM_CALLCONV DGSLEffect::SetProjection(FXMMATRIX value) { pImpl->projection = value; pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj; } // Material settings void XM_CALLCONV DGSLEffect::SetAmbientColor(FXMVECTOR value) { pImpl->constants.material.Ambient = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void XM_CALLCONV DGSLEffect::SetDiffuseColor(FXMVECTOR value) { pImpl->constants.material.Diffuse = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void XM_CALLCONV DGSLEffect::SetEmissiveColor(FXMVECTOR value) { pImpl->constants.material.Emissive = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void XM_CALLCONV DGSLEffect::SetSpecularColor(FXMVECTOR value) { pImpl->specularEnabled = true; pImpl->constants.material.Specular = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void DGSLEffect::SetSpecularPower(float value) { pImpl->specularEnabled = true; pImpl->constants.material.SpecularPower = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void DGSLEffect::DisableSpecular() { pImpl->specularEnabled = false; pImpl->constants.material.Specular = g_XMZero; pImpl->constants.material.SpecularPower = 1.f; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } void DGSLEffect::SetAlpha(float value) { // Set w to new value, but preserve existing xyz (diffuse color). pImpl->constants.material.Diffuse = XMVectorSetW(pImpl->constants.material.Diffuse, value); pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMaterial; } // Additional settings. void XM_CALLCONV DGSLEffect::SetUVTransform(FXMMATRIX value) { pImpl->constants.object.UvTransform4x4 = XMMatrixTranspose( value ); pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferObject; } void DGSLEffect::SetViewport( float width, float height ) { pImpl->constants.misc.ViewportWidth = width; pImpl->constants.misc.ViewportHeight = height; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMisc; } void DGSLEffect::SetTime( float time ) { pImpl->constants.misc.Time = time; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferMisc; } void DGSLEffect::SetAlphaDiscardEnable(bool value) { pImpl->alphaDiscardEnabled = value; } // Light settings void DGSLEffect::SetLightingEnabled(bool value) { if (value) { if ( !pImpl->constants.light.ActiveLights ) pImpl->constants.light.ActiveLights = 1; } else { pImpl->constants.light.ActiveLights = 0; } pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } void DGSLEffect::SetPerPixelLighting(bool) { // Unsupported interface method. } void XM_CALLCONV DGSLEffect::SetAmbientLightColor(FXMVECTOR value) { pImpl->constants.light.Ambient = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } void DGSLEffect::SetLightEnabled(int whichLight, bool value) { if ( whichLight < 0 || whichLight >= MaxDirectionalLights ) throw std::out_of_range("whichLight parameter out of range"); if ( pImpl->lightEnabled[whichLight] == value ) return; pImpl->lightEnabled[whichLight] = value; if ( value ) { if ( whichLight >= (int)pImpl->constants.light.ActiveLights ) pImpl->constants.light.ActiveLights = static_cast( whichLight + 1 ); pImpl->constants.light.LightColor[whichLight] = pImpl->lightDiffuseColor[whichLight]; pImpl->constants.light.LightSpecularIntensity[whichLight] = pImpl->lightSpecularColor[whichLight]; } else { pImpl->constants.light.LightColor[whichLight] = pImpl->constants.light.LightSpecularIntensity[whichLight] = g_XMZero; } pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } void XM_CALLCONV DGSLEffect::SetLightDirection(int whichLight, FXMVECTOR value) { if ( whichLight < 0 || whichLight >= MaxDirectionalLights ) throw std::out_of_range("whichLight parameter out of range"); // DGSL effects lights do not negate the direction like BasicEffect pImpl->constants.light.LightDirection[whichLight] = XMVectorNegate( value ); pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } void XM_CALLCONV DGSLEffect::SetLightDiffuseColor(int whichLight, FXMVECTOR value) { if ( whichLight < 0 || whichLight >= MaxDirectionalLights ) throw std::out_of_range("whichLight parameter out of range"); pImpl->lightDiffuseColor[whichLight] = value; if ( pImpl->lightEnabled[whichLight] ) { pImpl->constants.light.LightColor[whichLight] = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } } void XM_CALLCONV DGSLEffect::SetLightSpecularColor(int whichLight, FXMVECTOR value) { if ( whichLight < 0 || whichLight >= MaxDirectionalLights ) throw std::out_of_range("whichLight parameter out of range"); pImpl->lightSpecularColor[whichLight] = value; if ( pImpl->lightEnabled[whichLight] ) { pImpl->constants.light.LightSpecularIntensity[whichLight] = value; pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferLight; } } void DGSLEffect::EnableDefaultLighting() { EffectLights::EnableDefaultLighting(this); } // Vertex color setting. void DGSLEffect::SetVertexColorEnabled(bool value) { pImpl->vertexColorEnabled = value; } // Texture settings void DGSLEffect::SetTextureEnabled(bool value) { pImpl->textureEnabled = value; } void DGSLEffect::SetTexture(_In_opt_ ID3D11ShaderResourceView* value) { pImpl->textures[0] = value; } void DGSLEffect::SetTexture2(_In_opt_ ID3D11ShaderResourceView* value) { pImpl->textures[1] = value; } void DGSLEffect::SetTexture(int whichTexture, _In_opt_ ID3D11ShaderResourceView* value) { if ( whichTexture < 0 || whichTexture >= MaxTextures ) throw std::out_of_range("whichTexture parameter out of range"); pImpl->textures[ whichTexture ] = value; } // Animation setting void DGSLEffect::SetWeightsPerVertex(int value) { if ( !pImpl->weightsPerVertex ) { // Safe to ignore since it's only an optimization hint return; } if ((value != 1) && (value != 2) && (value != 4)) { throw std::out_of_range("WeightsPerVertex must be 1, 2, or 4"); } pImpl->weightsPerVertex = value; } void DGSLEffect::SetBoneTransforms(_In_reads_(count) XMMATRIX const* value, size_t count) { if ( !pImpl->weightsPerVertex ) throw std::exception("Skinning not enabled for this effect"); if (count > MaxBones) throw std::out_of_range("count parameter out of range"); auto boneConstant = pImpl->constants.bones.Bones; for (size_t i = 0; i < count; i++) { XMMATRIX boneMatrix = XMMatrixTranspose(value[i]); boneConstant[i][0] = boneMatrix.r[0]; boneConstant[i][1] = boneMatrix.r[1]; boneConstant[i][2] = boneMatrix.r[2]; } pImpl->dirtyFlags |= EffectDirtyFlags::ConstantBufferBones; } void DGSLEffect::ResetBoneTransforms() { if ( !pImpl->weightsPerVertex ) { // Safe to ignore since it just returns things back to default settings return; } auto boneConstant = pImpl->constants.bones.Bones; XMMATRIX id = XMMatrixIdentity(); 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; }