Nuklear/demo/d3d11/nuklear_d3d11.h
vurtun 1b9779ce51 Nuklear now allows custom vertex layouts
I removed the default vertex type and instead create an API to allow the
user to specify the vertex struct layout. Of course you are still
bound on what the library actual has on vertex data but the type and
sequence of the data is now configurable. This commit is quite
experiental and could introduce some bugs, but so far it look fine.
2016-09-02 15:33:49 +02:00

609 lines
20 KiB
C

/*
* Nuklear - v1.00 - public domain
* no warrenty implied; use at your own risk.
* authored from 2015-2016 by Micha Mettke
*/
/*
* ==============================================================
*
* API
*
* ===============================================================
*/
#ifndef NK_D3D11_H_
#define NK_D3D11_H_
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
typedef struct ID3D11Device ID3D11Device;
typedef struct ID3D11DeviceContext ID3D11DeviceContext;
NK_API struct nk_context *nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer);
NK_API void nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas);
NK_API void nk_d3d11_font_stash_end(void);
NK_API int nk_d3d11_handle_event(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam);
NK_API void nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing);
NK_API void nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height);
NK_API void nk_d3d11_shutdown(void);
#endif
/*
* ==============================================================
*
* IMPLEMENTATION
*
* ===============================================================
*/
#ifdef NK_D3D11_IMPLEMENTATION
#define WIN32_LEAN_AND_MEAN
#define COBJMACROS
#include <d3d11.h>
#include <stddef.h>
#include <string.h>
#include <float.h>
#include <assert.h>
#include "nuklear_d3d11_vertex_shader.h"
#include "nuklear_d3d11_pixel_shader.h"
struct nk_d3d11_vertex {
float position[2];
float uv[2];
nk_byte col[4];
};
static struct
{
struct nk_context ctx;
struct nk_font_atlas atlas;
struct nk_buffer cmds;
struct nk_draw_null_texture null;
unsigned int max_vertex_buffer;
unsigned int max_index_buffer;
D3D11_VIEWPORT viewport;
ID3D11Device *device;
ID3D11RasterizerState *rasterizer_state;
ID3D11VertexShader *vertex_shader;
ID3D11InputLayout *input_layout;
ID3D11Buffer *const_buffer;
ID3D11PixelShader *pixel_shader;
ID3D11BlendState *blend_state;
ID3D11Buffer *index_buffer;
ID3D11Buffer *vertex_buffer;
ID3D11ShaderResourceView *font_texture_view;
ID3D11SamplerState *sampler_state;
} d3d11;
NK_API void
nk_d3d11_render(ID3D11DeviceContext *context, enum nk_anti_aliasing AA)
{
const float blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
const UINT stride = sizeof(struct nk_d3d11_vertex);
const UINT offset = 0;
ID3D11DeviceContext_IASetInputLayout(context, d3d11.input_layout);
ID3D11DeviceContext_IASetVertexBuffers(context, 0, 1, &d3d11.vertex_buffer, &stride, &offset);
ID3D11DeviceContext_IASetIndexBuffer(context, d3d11.index_buffer, DXGI_FORMAT_R16_UINT, 0);
ID3D11DeviceContext_IASetPrimitiveTopology(context, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
ID3D11DeviceContext_VSSetShader(context, d3d11.vertex_shader, NULL, 0);
ID3D11DeviceContext_VSSetConstantBuffers(context, 0, 1, &d3d11.const_buffer);
ID3D11DeviceContext_PSSetShader(context, d3d11.pixel_shader, NULL, 0);
ID3D11DeviceContext_PSSetSamplers(context, 0, 1, &d3d11.sampler_state);
ID3D11DeviceContext_OMSetBlendState(context, d3d11.blend_state, blend_factor, 0xffffffff);
ID3D11DeviceContext_RSSetState(context, d3d11.rasterizer_state);
ID3D11DeviceContext_RSSetViewports(context, 1, &d3d11.viewport);
/* Convert from command queue into draw list and draw to screen */
{/* load draw vertices & elements directly into vertex + element buffer */
D3D11_MAPPED_SUBRESOURCE vertices;
D3D11_MAPPED_SUBRESOURCE indices;
const struct nk_draw_command *cmd;
UINT offset = 0;
HRESULT hr;
hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &vertices);
NK_ASSERT(SUCCEEDED(hr));
hr = ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.index_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &indices);
NK_ASSERT(SUCCEEDED(hr));
{/* fill converting configuration */
struct nk_convert_config config;
memset(&config, 0, sizeof(config));
config.global_alpha = 1.0f;
config.shape_AA = AA;
config.line_AA = AA;
config.circle_segment_count = 22;
config.curve_segment_count = 22;
config.arc_segment_count = 22;
config.null = d3d11.null;
{/* setup buffers to load vertices and elements */
struct nk_buffer vbuf, ibuf;
nk_buffer_init_fixed(&vbuf, vertices.pData, (size_t)d3d11.max_vertex_buffer);
nk_buffer_init_fixed(&ibuf, indices.pData, (size_t)d3d11.max_index_buffer);
nk_convert(&d3d11.ctx, &d3d11.cmds, &vbuf, &ibuf, &config);}
}
ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.vertex_buffer, 0);
ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.index_buffer, 0);
/* iterate over and execute each draw command */
nk_draw_foreach(cmd, &d3d11.ctx, &d3d11.cmds)
{
D3D11_RECT scissor;
ID3D11ShaderResourceView *texture_view = (ID3D11ShaderResourceView *)cmd->texture.ptr;
if (!cmd->elem_count) continue;
scissor.left = (LONG)cmd->clip_rect.x;
scissor.right = (LONG)(cmd->clip_rect.x + cmd->clip_rect.w);
scissor.top = (LONG)cmd->clip_rect.y;
scissor.bottom = (LONG)(cmd->clip_rect.y + cmd->clip_rect.h);
ID3D11DeviceContext_PSSetShaderResources(context, 0, 1, &texture_view);
ID3D11DeviceContext_RSSetScissorRects(context, 1, &scissor);
ID3D11DeviceContext_DrawIndexed(context, (UINT)cmd->elem_count, offset, 0);
offset += cmd->elem_count;
}
nk_clear(&d3d11.ctx);}
}
static void
nk_d3d11_get_projection_matrix(int width, int height, float *result)
{
const float L = 0.0f;
const float R = (float)width;
const float T = 0.0f;
const float B = (float)height;
float matrix[4][4] =
{
{ 2.0f / (R - L), 0.0f, 0.0f, 0.0f },
{ 0.0f, 2.0f / (T - B), 0.0f, 0.0f },
{ 0.0f, 0.0f, 0.5f, 0.0f },
{ (R + L) / (L - R), (T + B) / (B - T), 0.5f, 1.0f },
};
memcpy(result, matrix, sizeof(matrix));
}
NK_API void
nk_d3d11_resize(ID3D11DeviceContext *context, int width, int height)
{
D3D11_MAPPED_SUBRESOURCE mapped;
if (SUCCEEDED(ID3D11DeviceContext_Map(context, (ID3D11Resource *)d3d11.const_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped)))
{
nk_d3d11_get_projection_matrix(width, height, (float *)mapped.pData);
ID3D11DeviceContext_Unmap(context, (ID3D11Resource *)d3d11.const_buffer, 0);
d3d11.viewport.Width = (float)width;
d3d11.viewport.Height = (float)height;
}
}
NK_API int
nk_d3d11_handle_event(HWND wnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
switch (msg)
{
case WM_KEYDOWN:
case WM_KEYUP:
case WM_SYSKEYDOWN:
case WM_SYSKEYUP:
{
int down = (lparam >> 31) & 1;
int ctrl = GetKeyState(VK_CONTROL) & (1 << 15);
switch (wparam)
{
case VK_SHIFT:
case VK_LSHIFT:
case VK_RSHIFT:
nk_input_key(&d3d11.ctx, NK_KEY_SHIFT, down);
return 1;
case VK_DELETE:
nk_input_key(&d3d11.ctx, NK_KEY_DEL, down);
return 1;
case VK_RETURN:
nk_input_key(&d3d11.ctx, NK_KEY_ENTER, down);
return 1;
case VK_TAB:
nk_input_key(&d3d11.ctx, NK_KEY_TAB, down);
return 1;
case VK_LEFT:
if (ctrl)
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_LEFT, down);
else
nk_input_key(&d3d11.ctx, NK_KEY_LEFT, down);
return 1;
case VK_RIGHT:
if (ctrl)
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_WORD_RIGHT, down);
else
nk_input_key(&d3d11.ctx, NK_KEY_RIGHT, down);
return 1;
case VK_BACK:
nk_input_key(&d3d11.ctx, NK_KEY_BACKSPACE, down);
return 1;
case VK_HOME:
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_START, down);
nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_START, down);
return 1;
case VK_END:
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_END, down);
nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_END, down);
return 1;
case VK_NEXT:
nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_DOWN, down);
return 1;
case VK_PRIOR:
nk_input_key(&d3d11.ctx, NK_KEY_SCROLL_UP, down);
return 1;
case 'C':
if (ctrl) {
nk_input_key(&d3d11.ctx, NK_KEY_COPY, down);
return 1;
}
break;
case 'V':
if (ctrl) {
nk_input_key(&d3d11.ctx, NK_KEY_PASTE, down);
return 1;
}
break;
case 'X':
if (ctrl) {
nk_input_key(&d3d11.ctx, NK_KEY_CUT, down);
return 1;
}
break;
case 'Z':
if (ctrl) {
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_UNDO, down);
return 1;
}
break;
case 'R':
if (ctrl) {
nk_input_key(&d3d11.ctx, NK_KEY_TEXT_REDO, down);
return 1;
}
break;
}
return 0;
}
case WM_CHAR:
if (wparam >= 32)
{
nk_input_unicode(&d3d11.ctx, (nk_rune)wparam);
return 1;
}
break;
case WM_LBUTTONDOWN:
nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_LBUTTONUP:
nk_input_button(&d3d11.ctx, NK_BUTTON_LEFT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_RBUTTONDOWN:
nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_RBUTTONUP:
nk_input_button(&d3d11.ctx, NK_BUTTON_RIGHT, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_MBUTTONDOWN:
nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 1);
SetCapture(wnd);
return 1;
case WM_MBUTTONUP:
nk_input_button(&d3d11.ctx, NK_BUTTON_MIDDLE, (short)LOWORD(lparam), (short)HIWORD(lparam), 0);
ReleaseCapture();
return 1;
case WM_MOUSEWHEEL:
nk_input_scroll(&d3d11.ctx, (float)(short)HIWORD(wparam) / WHEEL_DELTA);
return 1;
case WM_MOUSEMOVE:
nk_input_motion(&d3d11.ctx, (short)LOWORD(lparam), (short)HIWORD(lparam));
return 1;
}
return 0;
}
static void
nk_d3d11_clipbard_paste(nk_handle usr, struct nk_text_edit *edit)
{
(void)usr;
if (IsClipboardFormatAvailable(CF_UNICODETEXT) && OpenClipboard(NULL))
{
HGLOBAL mem = GetClipboardData(CF_UNICODETEXT);
if (mem)
{
SIZE_T size = GlobalSize(mem) - 1;
if (size)
{
LPCWSTR wstr = (LPCWSTR)GlobalLock(mem);
if (wstr)
{
int utf8size = WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), NULL, 0, NULL, NULL);
if (utf8size)
{
char* utf8 = (char*)malloc(utf8size);
if (utf8)
{
WideCharToMultiByte(CP_UTF8, 0, wstr, size / sizeof(wchar_t), utf8, utf8size, NULL, NULL);
nk_textedit_paste(edit, utf8, utf8size);
free(utf8);
}
}
GlobalUnlock(mem);
}
}
}
CloseClipboard();
}
}
static void
nk_d3d11_clipbard_copy(nk_handle usr, const char *text, int len)
{
(void)usr;
if (OpenClipboard(NULL))
{
int wsize = MultiByteToWideChar(CP_UTF8, 0, text, len, NULL, 0);
if (wsize)
{
HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (wsize + 1) * sizeof(wchar_t));
if (mem)
{
wchar_t* wstr = (wchar_t*)GlobalLock(mem);
if (wstr)
{
MultiByteToWideChar(CP_UTF8, 0, text, len, wstr, wsize);
wstr[wsize] = 0;
GlobalUnlock(mem);
SetClipboardData(CF_UNICODETEXT, mem);
}
}
}
CloseClipboard();
}
}
NK_API struct nk_context*
nk_d3d11_init(ID3D11Device *device, int width, int height, unsigned int max_vertex_buffer, unsigned int max_index_buffer)
{
HRESULT hr;
d3d11.max_vertex_buffer = max_vertex_buffer;
d3d11.max_index_buffer = max_index_buffer;
d3d11.device = device;
ID3D11Device_AddRef(device);
nk_init_default(&d3d11.ctx, 0);
d3d11.ctx.clip.copy = nk_d3d11_clipbard_copy;
d3d11.ctx.clip.paste = nk_d3d11_clipbard_paste;
d3d11.ctx.clip.userdata = nk_handle_ptr(0);
nk_buffer_init_default(&d3d11.cmds);
{/* rasterizer state */
D3D11_RASTERIZER_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
desc.FrontCounterClockwise = FALSE;
desc.DepthBias = 0;
desc.DepthBiasClamp = 0;
desc.SlopeScaledDepthBias = 0.0f;
desc.DepthClipEnable = TRUE;
desc.ScissorEnable = TRUE;
desc.MultisampleEnable = FALSE;
desc.AntialiasedLineEnable = FALSE;
hr = ID3D11Device_CreateRasterizerState(device,&desc, &d3d11.rasterizer_state);
NK_ASSERT(SUCCEEDED(hr));}
/* vertex shader */
{hr = ID3D11Device_CreateVertexShader(device,nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), NULL, &d3d11.vertex_shader);
NK_ASSERT(SUCCEEDED(hr));}
/* input layout */
{const D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(struct nk_d3d11_vertex, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(struct nk_d3d11_vertex, col), D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
hr = ID3D11Device_CreateInputLayout(device,layout, ARRAYSIZE(layout), nk_d3d11_vertex_shader, sizeof(nk_d3d11_vertex_shader), &d3d11.input_layout);
NK_ASSERT(SUCCEEDED(hr));}
/* constant buffer */
{float matrix[4*4];
D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.ByteWidth = sizeof(matrix);
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
{D3D11_SUBRESOURCE_DATA data;
data.pSysMem = matrix;
data.SysMemPitch = 0;
data.SysMemSlicePitch = 0;
nk_d3d11_get_projection_matrix(width, height, matrix);
hr = ID3D11Device_CreateBuffer(device, &desc, &data, &d3d11.const_buffer);
NK_ASSERT(SUCCEEDED(hr));}}
/* pixel shader */
{hr = ID3D11Device_CreatePixelShader(device, nk_d3d11_pixel_shader, sizeof(nk_d3d11_pixel_shader), NULL, &d3d11.pixel_shader);
NK_ASSERT(SUCCEEDED(hr));}
{/* blend state */
D3D11_BLEND_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.AlphaToCoverageEnable = FALSE;
desc.RenderTarget[0].BlendEnable = TRUE;
desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_INV_SRC_ALPHA;
desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
hr = ID3D11Device_CreateBlendState(device, &desc, &d3d11.blend_state);
NK_ASSERT(SUCCEEDED(hr));}
/* vertex buffer */
{D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = max_vertex_buffer;
desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
desc.MiscFlags = 0;
hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.vertex_buffer);
NK_ASSERT(SUCCEEDED(hr));}
/* index buffer */
{D3D11_BUFFER_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Usage = D3D11_USAGE_DYNAMIC;
desc.ByteWidth = max_index_buffer;
desc.BindFlags = D3D11_BIND_INDEX_BUFFER;
desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
hr = ID3D11Device_CreateBuffer(device, &desc, NULL, &d3d11.index_buffer);
NK_ASSERT(SUCCEEDED(hr));}
/* sampler state */
{D3D11_SAMPLER_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
desc.MipLODBias = 0.0f;
desc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
desc.MinLOD = 0.0f;
desc.MaxLOD = FLT_MAX;
hr = ID3D11Device_CreateSamplerState(device, &desc, &d3d11.sampler_state);
NK_ASSERT(SUCCEEDED(hr));}
/* viewport */
{d3d11.viewport.TopLeftX = 0.0f;
d3d11.viewport.TopLeftY = 0.0f;
d3d11.viewport.Width = (float)width;
d3d11.viewport.Height = (float)height;
d3d11.viewport.MinDepth = 0.0f;
d3d11.viewport.MaxDepth = 1.0f;}
return &d3d11.ctx;
}
NK_API void
nk_d3d11_font_stash_begin(struct nk_font_atlas **atlas)
{
nk_font_atlas_init_default(&d3d11.atlas);
nk_font_atlas_begin(&d3d11.atlas);
*atlas = &d3d11.atlas;
}
NK_API void
nk_d3d11_font_stash_end(void)
{
const void *image; int w, h;
image = nk_font_atlas_bake(&d3d11.atlas, &w, &h, NK_FONT_ATLAS_RGBA32);
/* upload font to texture and create texture view */
{ID3D11Texture2D *font_texture;
HRESULT hr;
D3D11_TEXTURE2D_DESC desc;
memset(&desc, 0, sizeof(desc));
desc.Width = (UINT)w;
desc.Height = (UINT)h;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.SampleDesc.Quality = 0;
desc.Usage = D3D11_USAGE_DEFAULT;
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = 0;
{D3D11_SUBRESOURCE_DATA data;
data.pSysMem = image;
data.SysMemPitch = (UINT)(w * 4);
data.SysMemSlicePitch = 0;
hr = ID3D11Device_CreateTexture2D(d3d11.device, &desc, &data, &font_texture);
assert(SUCCEEDED(hr));}
{D3D11_SHADER_RESOURCE_VIEW_DESC srv;
memset(&srv, 0, sizeof(srv));
srv.Format = desc.Format;
srv.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
srv.Texture2D.MipLevels = 1;
srv.Texture2D.MostDetailedMip = 0;
hr = ID3D11Device_CreateShaderResourceView(d3d11.device, (ID3D11Resource *)font_texture, &srv, &d3d11.font_texture_view);
assert(SUCCEEDED(hr));}
ID3D11Texture2D_Release(font_texture);}
nk_font_atlas_end(&d3d11.atlas, nk_handle_ptr(d3d11.font_texture_view), &d3d11.null);
if (d3d11.atlas.default_font)
nk_style_set_font(&d3d11.ctx, &d3d11.atlas.default_font->handle);
}
NK_API
void nk_d3d11_shutdown(void)
{
nk_font_atlas_clear(&d3d11.atlas);
nk_buffer_free(&d3d11.cmds);
nk_free(&d3d11.ctx);
ID3D11SamplerState_Release(d3d11.sampler_state);
ID3D11ShaderResourceView_Release(d3d11.font_texture_view);
ID3D11Buffer_Release(d3d11.vertex_buffer);
ID3D11Buffer_Release(d3d11.index_buffer);
ID3D11BlendState_Release(d3d11.blend_state);
ID3D11PixelShader_Release(d3d11.pixel_shader);
ID3D11Buffer_Release(d3d11.const_buffer);
ID3D11VertexShader_Release(d3d11.vertex_shader);
ID3D11InputLayout_Release(d3d11.input_layout);
ID3D11RasterizerState_Release(d3d11.rasterizer_state);
ID3D11Device_Release(d3d11.device);
}
#endif