The only problem is that Direct3D 11 has a separate function to create each type of shader, so in order to make it generic I originally came up with a solution which I qualify as "horrible hack".
In DirectX 11 the ID3D11Device has some methods like:
HRESULT __stdcall ID3D11Device::CreateVertexShader(
[in] const void *pShaderBytecode,
[in] SIZE_T BytecodeLength,
[in] ID3D11ClassLinkage *pClassLinkage,
[out] ID3D11VertexShader **ppVertexShader);
HRESULT __stdcall ID3D11Device::CreatePixelShader(
[in] const void *pShaderBytecode,
[in] SIZE_T BytecodeLength,
[in] ID3D11ClassLinkage *pClassLinkage,
[out] ID3D11PixelShader **ppPixelShader
);
And ID3D11VertexShader and ID3D11PixelShader are both inheriting publicly from ID3D11DeviceChild:
ID3D11VertexShader : public ID3D11DeviceChild { ... }
ID3D11PixelShader : public ID3D11DeviceChild { ... }
Now the trick was to define a function pointer CreateShader that has the following prototype:
typedef HRESULT (__stdcall ID3D11Device::*CreateShader)(const void *,SIZE_T, ID3D11ClassLinkage*,ID3D11DeviceChild**);
The only difference is the last argument which points to the superclass of the shader classes.
Now I only have to pass this function pointer pointing to the right method of the ID3D11Device when I create my shader.
The problem with that is that I have to pass the shader as its base type, which is supposed to work according to the rules of C++ except, however the (wise) compiler complained when I tried to do it implicitly.
That forced me to create a ID3D11DeviceChild* and assign the ID3D11*Shader to it, then pass it to the method.
In other word it look even more horrible; that's where templates come to help.
I decided to template the loadShader method, and use the shader type to select the appropriate ID3D11::Create* method.
Since function templates cannot have defaults, I created a helper structure:
template <class Shader>
struct CreateShaderHelper
{
typedef typename HRESULT (__stdcall ID3D11Device::*FuncType)(const void *,SIZE_T, ClassLinkage*,Shader**);
};
Now I can re-write the loadShader method like this:template <class Shader>
int loadShader(const char* name,
const char* defines,
const char* profile,
typename CreateShaderHelper<Shader>::FuncType shader_creator,
ConstantBuffer& cbuff,
Shader*& outShader,
ID3D11ShaderReflection*& outShaderReflect)
{
...
if ((device->*shader_creator)(shader_buffer->GetBufferPointer(),shader_buffer->GetBufferSize(),&outShader) == S_OK)
{
...
}
}