930 lines
28 KiB
C++
930 lines
28 KiB
C++
|
//--------------------------------------------------------------------------------------
|
||
|
// 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<DGSLEffectConstants>
|
||
|
{
|
||
|
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<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;
|
||
|
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<ID3D11VertexShader> mVertexShaders[DGSLEffectTraits::VertexShaderCount];
|
||
|
ComPtr<ID3D11PixelShader> mPixelShaders[DGSLEffectTraits::PixelShaderCount];
|
||
|
ComPtr<ID3D11ShaderResourceView> mDefaultTexture;
|
||
|
};
|
||
|
|
||
|
// Per-device resources.
|
||
|
std::shared_ptr<DeviceResources> mDeviceResources;
|
||
|
|
||
|
static SharedResourcePool<ID3D11Device*, DeviceResources> deviceResourcesPool;
|
||
|
};
|
||
|
|
||
|
|
||
|
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(), 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<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::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;
|
||
|
}
|