Here's some more wrapper code. This is the init function.
// this init code is run once and only once
void MeshRenderSys::init()
{
m_device = _getSystem<RenderSystem>()->getDevice();
m_context = _getSystem<RenderSystem>()->getContext();
// vertex buffer
BufferDescription vdescr = {};
vdescr.usage = BufferUsageType::Dynamic;
vdescr.size = sizeof(Vertex) * kVertexBufferSize;
vdescr.bindType = BufferBindType::Vertex;
vdescr.access = BufferAccessType::Write;
// index buffer
BufferDescription idescr = {};
idescr.usage = BufferUsageType::Dynamic;
idescr.size = sizeof(uint) * kVertexBufferSize;
idescr.bindType = BufferBindType::Index;
idescr.access = BufferAccessType::Write;
// uniform buffer
BufferDescription udescr = {};
udescr.usage = BufferUsageType::Dynamic;
udescr.size = sizeof(MeshUniforms);
udescr.bindType = BufferBindType::Constant;
udescr.access = BufferAccessType::Write;
m_vertexBuffer = m_device->createBuffer(BufferType::Vertex, vdescr);
m_indexBuffer = m_device->createBuffer(BufferType::Index, idescr);
m_uniformBuffer = m_device->createBuffer(BufferType::Uniform, udescr);
}
And here's there createBuffer function referenced here
IBuffer* D3DRenderDevice::createBuffer(BufferType type, BufferDescription descr)
{
D3DBuffer* buffer = new D3DBuffer(type);
ID3D11Buffer** d3dBuffer = buffer->getBuffer();
D3D11_BUFFER_DESC d3dDescr = d3dCreateD3DBufferDescription(descr); // merely creates a d3d buffer descr from my abstract buffer descr class
HRESULT result = m_device->CreateBuffer(
&d3dDescr,
NULL,
d3dBuffer);
ASSERT(result >= 0);
return static_cast<IBuffer*>(buffer);
}
Here's the abstract input layout code. Also only run once
void MeshRenderSys::initShaderLayout()
{
ShaderSys* shaderSystem = _getSystem<ShaderSys>();
// input layout
vector<InputLayoutItem> inputLayout;
inputLayout.push_back({ "POSITION", DatatypeFormat::R32G32B32_Float });
inputLayout.push_back({ "NORMAL", DatatypeFormat::R32G32B32_Float });
inputLayout.push_back({ "BINORMAL", DatatypeFormat::R32G32B32_Float });
inputLayout.push_back({ "TANGENT", DatatypeFormat::R32G32B32_Float });
inputLayout.push_back({ "COLOR", DatatypeFormat::R32G32B32A32_Float });
inputLayout.push_back({ "TEXCOORD", DatatypeFormat::R32G32_Float });
inputLayout.push_back({ "BLENDINDICES", DatatypeFormat::R32G32B32A32_Uint });
inputLayout.push_back({ "BLENDWEIGHT", DatatypeFormat::R32G32B32A32_Float });
ASSERT(shaderSystem->isShaderLoaded("shaders.shader", ShaderType::Vert));
IShader* shader = shaderSystem->getVertexShader("shaders.shader");
m_layout = m_device->createInputLayout(inputLayout, shader);
}
and the code it wraps
IInputLayout* D3DRenderDevice::createInputLayout(vector<InputLayoutItem> layoutItems, IShader* shader)
{
ASSERT(shader != nullptr);
ASSERT(shader->getType() == ShaderType::Vert);
D3DInputLayout* layout = new D3DInputLayout();
ID3D11InputLayout** d3dLayout = layout->getLayout();
D3DShader* d3dShader = static_cast<D3DShader*>(shader);
D3D11_INPUT_ELEMENT_DESC* descr = d3dInputElementDescription(layoutItems);
HRESULT result = m_device->CreateInputLayout(descr, layoutItems.size(),
(*d3dShader->getBlob())->GetBufferPointer(), (*d3dShader->getBlob())->GetBufferSize(),
d3dLayout);
ASSERT(result >= 0);
return static_cast<IInputLayout*>(layout);
}
and here's an expanded version of the render code I have above with more of the context
void MeshRenderSys::render(RenderPass pass, RenderOptions options)
{
// start draw pass
ShaderSys* shaderSys = _getSystem<ShaderSys>();
LightingSystem* lightingSys = _getSystem<LightingSystem>();
CoCamera* coCam = _getSystem<CameraSystem>()->getPrimaryCam();
// wait until shaders are loaded to start drawing
if (shaderSys->isShaderLoaded("shaders.shader", ShaderType::Vert) &&
shaderSys->isShaderLoaded("shaders.shader", ShaderType::Frag))
{
// set shaders
shaderSys->setShader("shaders.shader", ShaderType::Vert);
shaderSys->setShader("shaders.shader", ShaderType::Frag);
// create input layout if it hasn't be done yet
if (m_layout == nullptr)
{
initShaderLayout();
}
//set vert layout
m_context->setInputLayout(m_layout);
for (int i = 0; i < m_sortedMeshes.size(); i++)
{
CoMesh* coMesh = std::get<0>(m_sortedMeshes[i]);
Resource<Mesh>* meshRes = coMesh->getMesh().get();
Entity* meshEnt = coMesh->getEntity();
Entity* camEnt = coCam->getEntity();
if (meshRes != nullptr)
{
bool render = true;
// frustum culling
if (!coCam->isBoxInsideFrustumFast(coMesh->getBounds(), meshEnt))
{
render = false;
}
if (render)
{
Mesh* mesh = meshRes->get();
ASSERT(mesh != nullptr);
// ===================== uniform buffer ================================
vector<MeshUniforms> uniforms;
MeshUniforms test = {};
test.worldMat = mat4(meshEnt->position(), meshEnt->rotation(), meshEnt->scale()).transposed();
test.viewMat = coCam->getViewMatrix().transposed();
test.projectionMat = coCam->getProjectionMatrix().transposed();
ASSERT(lightingSys->getLights().size() <= 1); // don't support multiple lights yet
CoDirectionalLight* light = lightingSys->getLights()[0];
test.cameraPosition = vec4(camEnt->position(), 0.f);
test.ambientLightColor = vec4(.15f, .15f, .15f, 1.f);
test.directionalLightDir = vec4(light->getEntity()->rotation().toEuler(), 0.f);
test.directionalLightColor = color::toVec(light->getColor());
test.specularLightColor = vec4(1.f, 1.f, 1.f, 1.f);
test.specularLightIntensity = 0.2f;
test.materialAlpha = coMesh->getMaterial()->getAlpha();
FogSystem* fogSys = _getSystem<FogSystem>();
if (fogSys != nullptr)
{
test.fogTypeMask |= 1 << (int32)fogSys->getFogType();
test.fogColor = color::toVec(fogSys->getFogColor());
test.fogNear = fogSys->getFogNear();
test.fogFar = fogSys->getFogFar();
test.fogDensity = fogSys->getFogDensity();
}
else
{
test.fogTypeMask = 0;
test.fogColor = color::toVec(color::white());
test.fogNear = 0.f;
test.fogFar = 0.f;
test.fogDensity = 0.f;
}
//textures
Texture2D* textures[kNumTextureSlots];
test.textureUseMask = 0;
test.textureOffset = vec2(0.f, 0.0f);
for (int i = 0; i < kNumTextureSlots; i++)
{
textures[i] = nullptr;
}
if (coMesh->getDiffuseTex() != nullptr)
{
textures[TEXTURE_SLOT_DIFFUSE] = coMesh->getDiffuseTex();
test.textureUseMask |= 1 << TEXTURE_SLOT_DIFFUSE;
}
if (coMesh->getBlendTex() != nullptr)
{
textures[TEXTURE_SLOT_BLEND] = coMesh->getBlendTex();
test.textureUseMask |= 1 << TEXTURE_SLOT_BLEND;
}
if (coMesh->getAlphaTex() != nullptr)
{
textures[TEXTURE_SLOT_ALPHA] = coMesh->getAlphaTex();
test.textureUseMask |= 1 << TEXTURE_SLOT_ALPHA;
}
if (coMesh->getLightTex() != nullptr)
{
textures[TEXTURE_SLOT_LIGHT] = coMesh->getLightTex();
test.textureUseMask |= 1 << TEXTURE_SLOT_LIGHT;
}
if (coMesh->getNormalTex() != nullptr)
{
textures[TEXTURE_SLOT_NORMAL] = coMesh->getNormalTex();
test.textureUseMask |= 1 << TEXTURE_SLOT_NORMAL;
}
if (coReflect != nullptr && !options.reflect.reflectionPass)
{
textures[TEXTURE_SLOT_REFLECT] = coReflect->getReflectTexture();
test.textureUseMask |= 1 << TEXTURE_SLOT_REFLECT;
}
// animations
if (mesh->getArmature() != nullptr)
{
vector<mat4> boneMats = coMesh->getBoneMatrices();
ASSERT(mesh->getArmature()->bones.size() < kMaxBones);
int maxBones = int_min(kMaxBones, mesh->getArmature()->bones.size());
for (int bIndex = 0; bIndex < maxBones; bIndex++)
{
test.bones[bIndex] = boneMats[bIndex];
}
}
uniforms.push_back(test);
// ===================== uniform buffer end ================================
// map buffers
m_context->copyDataToBuffer((void*)mesh->getVerts().data(),
sizeof(Vertex) * mesh->getVerts().size(),
m_vertexBuffer);
m_context->copyDataToBuffer((void*)mesh->getIndices().data(),
sizeof(uint) * mesh->getIndices().size(),
m_indexBuffer);
m_context->copyDataToBuffer((void*)uniforms.data(),
sizeof(MeshUniforms) * uniforms.size(),
m_uniformBuffer);
// render
ISamplerState* sampler = shaderSys->getSamplerState();
m_context->setVertexBuffer(m_vertexBuffer);
m_context->setIndexBuffer(m_indexBuffer);
m_context->setUniformBuffer(m_uniformBuffer, ShaderType::Vert);
m_context->setUniformBuffer(m_uniformBuffer, ShaderType::Frag);
m_context->setTopology(PrimativeTopology::TriangleList);
m_context->setSamplerState(sampler);
Texture2D** textureArr = &textures[0];
m_context->setTextures(textureArr, kNumTextureSlots);
m_context->drawIndexed(mesh->getIndices().size());
}
}
}
}
}
And my device init, because why not
void D3DSystem::createSwapchain(SwapchainDescription swapchainDescription,
ISwapChain* &outSwapchain,
IRenderDevice* &outRenderDevice,
IRenderContext* &outRenderContext)
{
// get abstract window handle and cast it to the platform dependent window handle
shared_ptr<IWindowHandle> window = _getSystem<OSSystem>()->getOS()->getWindowHandle();
ASSERT(window != nullptr);
WindowsWindowHandle* winWindow = static_cast<WindowsWindowHandle*>(window.get());
ASSERT(winWindow != nullptr);
HWND hwnd = winWindow->getHWND();
DXGI_SWAP_CHAIN_DESC descr = d3dSwapchainDescription(swapchainDescription, hwnd);
D3DSwapChain* swapchain = new D3DSwapChain();
D3DRenderDevice* device = new D3DRenderDevice();
D3DRenderContext* context = new D3DRenderContext();
IDXGISwapChain** d3dSwapchainHandle = swapchain->getSwapchain();
ID3D11Device** d3dDeviceHandle = device->getDevice();
ID3D11DeviceContext** d3dContextHandle = context->getContext();
HRESULT result = D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_DEBUG, // TODO: switch on debug versus release
NULL,
NULL,
D3D11_SDK_VERSION,
&descr,
d3dSwapchainHandle,
d3dDeviceHandle,
NULL,
d3dContextHandle);
ASSERT(result >= 0);
outSwapchain = static_cast<ISwapChain*>(swapchain);
outRenderDevice = static_cast<IRenderDevice*>(device);
outRenderContext = static_cast<IRenderContext*>(context);
}
If there's any more context I can provide let me know, but that's a lot of it.
As for checking leaks in my wrapper code, there's very few places in the entire app where I use new, so I'm skeptical. But I will do due diligence and triple check I'm not leaking anything.