mirror of
https://github.com/ncblakely/GiantsTools
synced 2024-11-16 11:45:38 +01:00
941 lines
28 KiB
C++
941 lines
28 KiB
C++
|
//--------------------------------------------------------------------------------------
|
||
|
// 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;
|
||
|
}
|