1
0
mirror of https://github.com/ncblakely/GiantsTools synced 2024-11-16 19:55:36 +01:00
GiantsTools/Sdk/External/DirectXTK/Src/DGSLEffect.cpp

941 lines
28 KiB
C++
Raw Normal View History

2021-01-24 00:40:09 +01:00
//--------------------------------------------------------------------------------------
// File: DGSLEffect.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"
#include "DemandCreate.h"
//
// Based on the Visual Studio 3D Starter Kit
//
// http://aka.ms/vs3dkit
//
namespace DirectX
{
namespace EffectDirtyFlags
{
constexpr int ConstantBufferMaterial = 0x10000;
constexpr int ConstantBufferLight = 0x20000;
constexpr int ConstantBufferObject = 0x40000;
constexpr int ConstantBufferMisc = 0x80000;
constexpr int ConstantBufferBones = 0x100000;
}
}
using namespace DirectX;
using Microsoft::WRL::ComPtr;
namespace
{
// 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 constexpr int VertexShaderCount = 8;
static constexpr 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<DGSLEffectConstants>
{
public:
Impl(_In_ ID3D11Device* device, _In_opt_ ID3D11PixelShader* pixelShader, _In_ bool enableSkinning) :
constants{},
dirtyFlags(INT_MAX),
vertexColorEnabled(false),
textureEnabled(false),
specularEnabled(false),
alphaDiscardEnabled(false),
weightsPerVertex(enableSkinning ? 4 : 0),
mCBMaterial(device),
mCBLight(device),
mCBObject(device),
mCBMisc(device),
mPixelShader(pixelShader),
mDeviceResources(deviceResourcesPool.DemandCreate(device))
{
static_assert(_countof(DGSLEffectTraits::VertexShaderBytecode) == DGSLEffectTraits::VertexShaderCount, "array/max mismatch");
static_assert(_countof(DGSLEffectTraits::PixelShaderBytecode) == DGSLEffectTraits::PixelShaderCount, "array/max mismatch");
XMMATRIX id = XMMatrixIdentity();
world = id;
view = id;
projection = id;
constants.material.Diffuse = g_XMOne;
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) noexcept;
// Fields
DGSLEffectConstants constants;
XMMATRIX world;
XMMATRIX view;
XMMATRIX projection;
bool lightEnabled[MaxDirectionalLights];
XMVECTOR lightDiffuseColor[MaxDirectionalLights];
XMVECTOR lightSpecularColor[MaxDirectionalLights];
ComPtr<ID3D11ShaderResourceView> textures[MaxTextures];
int dirtyFlags;
bool vertexColorEnabled;
bool textureEnabled;
bool specularEnabled;
bool alphaDiscardEnabled;
int weightsPerVertex;
private:
ConstantBuffer<MaterialConstants> mCBMaterial;
ConstantBuffer<LightConstants> mCBLight;
ConstantBuffer<ObjectConstants> mCBObject;
ConstantBuffer<MiscConstants> mCBMisc;
ConstantBuffer<BoneConstants> mCBBone;
ComPtr<ID3D11PixelShader> mPixelShader;
int GetCurrentVSPermutation() const noexcept;
int GetCurrentPSPermutation() const noexcept;
// 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) noexcept
: EffectDeviceResources(device),
mVertexShaders{},
mPixelShaders{}
{ }
// Gets or lazily creates the vertex shader.
ID3D11VertexShader* GetVertexShader(int permutation)
{
assert(permutation >= 0 && 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 >= 0 && permutation < DGSLEffectTraits::PixelShaderCount);
return DemandCreatePixelShader(mPixelShaders[permutation], DGSLEffectTraits::PixelShaderBytecode[permutation]);
}
// Gets or lazily creates the default texture
ID3D11ShaderResourceView* GetDefaultTexture() { return EffectDeviceResources::GetDefaultTexture(); }
private:
ComPtr<ID3D11VertexShader> mVertexShaders[DGSLEffectTraits::VertexShaderCount];
ComPtr<ID3D11PixelShader> mPixelShaders[DGSLEffectTraits::PixelShaderCount];
};
// Per-device resources.
std::shared_ptr<DeviceResources> mDeviceResources;
static SharedResourcePool<ID3D11Device*, DeviceResources> deviceResourcesPool;
};
// Global pool of per-device DGSLEffect resources.
SharedResourcePool<ID3D11Device*, DGSLEffect::Impl::DeviceResources> 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<ID3D11DeviceContextX> 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(), nullptr };
deviceContext->PSSetShaderResources(0, MaxTextures, txt);
}
}
void DGSLEffect::Impl::GetVertexShaderBytecode(_Out_ void const** pShaderByteCode, _Out_ size_t* pByteCodeLength) noexcept
{
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 noexcept
{
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 noexcept
{
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(std::make_unique<Impl>(device, pixelShader, enableSkinning))
{
}
DGSLEffect::DGSLEffect(DGSLEffect&& moveFrom) noexcept
: pImpl(std::move(moveFrom.pImpl))
{
}
DGSLEffect& DGSLEffect::operator= (DGSLEffect&& moveFrom) noexcept
{
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;
}
void XM_CALLCONV DGSLEffect::SetMatrices(FXMMATRIX world, CXMMATRIX view, CXMMATRIX projection)
{
pImpl->world = world;
pImpl->view = view;
pImpl->projection = projection;
pImpl->dirtyFlags |= EffectDirtyFlags::WorldViewProj | EffectDirtyFlags::WorldInverseTranspose | EffectDirtyFlags::EyePosition;
}
// 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 = XMVectorSelect(pImpl->constants.material.Diffuse, value, g_XMSelect1110);
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;
}
void XM_CALLCONV DGSLEffect::SetColorAndAlpha(FXMVECTOR value)
{
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 >= static_cast<int>(pImpl->constants.light.ActiveLights))
pImpl->constants.light.ActiveLights = static_cast<UINT>(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::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 settings.
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;
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;
}