Hello! I am working on a class for my game engine called NXShader which will allow me to load my shaders easily like this:
NXShader(HWND*, WCHAR*, const string&, const string&);
The next thing I would like to add is the ability to dynamically set shader parameters if that makes any sense. Kind of similar to how shader parameters were handled in XNA:
Effect.Parameters["parameter"].SetValue(value);
I want to be able to do something like this with my NXShader class:
NXShader* shader = new NXShader(nullptr, L"Texture.fx", "VS", "PS");
shader->SetParameter(parameter name, value);
But I am not actually sure about to do this. The class is currently set up like this:
Header:
struct MatrixBufferType
{
XMMATRIX World;
XMMATRIX View;
XMMATRIX Projection;
};
struct NEXENGINE_API NXShader
{
public:
NXShader(){}
NXShader(HWND*, WCHAR*, const string&, const string&);
HRESULT Initialize(HWND*);
bool SetShaderParameters(XMMATRIX&, XMMATRIX&, XMMATRIX&);
bool SetShaderParameters(XMMATRIX&, XMMATRIX&, XMMATRIX&, NXTexture2D*);
void Dispose();
HRESULT CompileShaderFromFile(WCHAR*, LPCSTR, LPCSTR, ID3DBlob**);
WCHAR* TargetProfile = L"_4_0";
std::string VertexShaderEntry;
std::string PixelShaderEntry;
WCHAR* Name;
ID3D11VertexShader* VertexShader;
ID3D11PixelShader* PixelShader;
ID3D11InputLayout* Layout;
ID3D11Buffer* MatrixBuffer;
};
Source:
#include "stdafx.h"
#include "NXShader.h"
#include <d3dcompiler.h>
#include "NXTypes.h"
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
namespace NexEngine
{
NXShader::NXShader(HWND* wnd, WCHAR* shaderName, const string& vsEntry, const string& psEntry)
{
Name = shaderName;
VertexShaderEntry = vsEntry;
VertexShader = 0;
PixelShaderEntry = psEntry;
PixelShader = 0;
Layout = 0;
MatrixBuffer = 0;
HRESULT result;
result = Initialize(wnd);
if (FAILED(result))
return;
}
HRESULT NXShader::Initialize(HWND* hwnd)
{
HRESULT result;
D3D11_BUFFER_DESC matrixBufferDesc;
ID3DBlob* pVSBlob = nullptr;
result = CompileShaderFromFile(Name, VertexShaderEntry.c_str(), "vs_4_0", &pVSBlob);
if (FAILED(result))
{
MessageBox(nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
exit(0);
return result;
}
result = NXGPU::GetDevice()->CreateVertexShader(pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), nullptr, &VertexShader);
if (FAILED(result))
{
pVSBlob->Release();
MessageBox(nullptr, L"Failed To Create Vertex Shader.", L"Error", MB_OK);
return result;
}
ID3DBlob* pPSBlob = nullptr;
result = CompileShaderFromFile(Name, PixelShaderEntry.c_str(), "ps_4_0", &pPSBlob);
if (FAILED(result))
{
MessageBox(nullptr,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK);
exit(0);
return result;
}
result = NXGPU::GetDevice()->CreatePixelShader(pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), nullptr, &PixelShader);
pPSBlob->Release();
if (FAILED(result))
{
MessageBox(nullptr, L"Failed To Create Pixel Shader.", L"Error", MB_OK);
return result;
}
pPSBlob = 0;
result = NXGPU::GetDevice()->CreateInputLayout(NXVertex::InputElements, NXVertex::InputElementCount, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &Layout);
pVSBlob->Release();
if (FAILED(result))
{
MessageBox(nullptr, L"Failed To Create Input Layout.", L"Error", MB_OK);
exit(0);
return result;
}
pVSBlob = 0;
matrixBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
matrixBufferDesc.ByteWidth = sizeof(MatrixBufferType);
matrixBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
matrixBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
matrixBufferDesc.MiscFlags = 0;
matrixBufferDesc.StructureByteStride = 0;
result = NXGPU::GetDevice()->CreateBuffer(&matrixBufferDesc, NULL, &MatrixBuffer);
if (FAILED(result))
{
MessageBox(nullptr, L"Faield to Create Matrix Buffer", L"Error", MB_OK);
exit(0);
return result;
}
return S_OK;
}
bool NXShader::SetShaderParameters(XMMATRIX& view, XMMATRIX& world, XMMATRIX& proj)
{
HRESULT result;
D3D11_MAPPED_SUBRESOURCE mappedResource;
MatrixBufferType* dataPtr;
unsigned int bufferNumber;
world = XMMatrixTranspose(world);
view = XMMatrixTranspose(view);
proj = XMMatrixTranspose(proj);
result = NXGPU::GetDeviceContext()->Map(MatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return false;
}
dataPtr = (MatrixBufferType*) mappedResource.pData;
dataPtr->World = world;
dataPtr->View = view;
dataPtr->Projection = proj;
NXGPU::GetDeviceContext()->Unmap(MatrixBuffer, 0);
bufferNumber = 0;
NXGPU::GetDeviceContext()->VSSetConstantBuffers(bufferNumber, 1, &MatrixBuffer);
return true;
}
bool NXShader::SetShaderParameters(XMMATRIX& view, XMMATRIX& world, XMMATRIX& proj, NXTexture2D* texture)
{
HRESULT result;
D3D11_MAPPED_SUBRESOURCE mappedResource;
MatrixBufferType* dataPtr;
unsigned int bufferNumber;
world = XMMatrixTranspose(world);
view = XMMatrixTranspose(view);
proj = XMMatrixTranspose(proj);
result = NXGPU::GetDeviceContext()->Map(MatrixBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
if (FAILED(result))
{
return false;
}
dataPtr = (MatrixBufferType*) mappedResource.pData;
dataPtr->World = world;
dataPtr->View = view;
dataPtr->Projection = proj;
NXGPU::GetDeviceContext()->Unmap(MatrixBuffer, 0);
bufferNumber = 0;
NXGPU::GetDeviceContext()->VSSetConstantBuffers(bufferNumber, 1, &MatrixBuffer);
NXGPU::GetDeviceContext()->PSSetShaderResources(0, 1, &texture->Texture);
return true;
}
void NXShader::Dispose()
{
if (MatrixBuffer)
{
MatrixBuffer->Release();
MatrixBuffer = 0;
}
if (Layout)
{
Layout->Release();
Layout = 0;
}
if (PixelShader)
{
PixelShader->Release();
PixelShader = 0;
}
if (VertexShader)
{
VertexShader->Release();
VertexShader = 0;
}
return;
}
HRESULT NXShader::CompileShaderFromFile(WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut)
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pErrorBlob;
hr = D3DCompileFromFile(szFileName, nullptr, nullptr, szEntryPoint, szShaderModel,
dwShaderFlags, 0, ppBlobOut, &pErrorBlob);
if (FAILED(hr))
{
if (pErrorBlob != nullptr)
OutputDebugStringA((char*) pErrorBlob->GetBufferPointer());
if (pErrorBlob) pErrorBlob->Release();
return hr;
}
if (pErrorBlob) pErrorBlob->Release();
return S_OK;
}
}
I would like to remove the SetShaderParameter bool methods above, and replace them with something like this:
void SetParameter(const string&, float);
void SetParameter(const string&, int);
void SetParameter(const string&, XMMatrix*)
void SetParameter...etc.
This would really help me out. The class can currently compile and load Pixel/Vertex shaders correctly:
But I seem to limited to setting parameters by creating a bunch of constant buffers for each cbuffer in my shaders. Is there a way to do what I am trying to do in DX11? Thanks!