summaryrefslogtreecommitdiff
path: root/dwm/grender.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dwm/grender.cpp')
-rw-r--r--dwm/grender.cpp1288
1 files changed, 1288 insertions, 0 deletions
diff --git a/dwm/grender.cpp b/dwm/grender.cpp
new file mode 100644
index 0000000..9fd3151
--- /dev/null
+++ b/dwm/grender.cpp
@@ -0,0 +1,1288 @@
+#include "grender.h"
+#include "freetype/freetype.h"
+#include <d3dcompiler.h>
+
+#define xors( s ) s
+
+// assignment with conditional expression
+#pragma warning(disable : 4706)
+
+// TODO OT: UNDEF THIS
+#define RENDER_DEBUG 1
+
+static char const *d3d11_vert_shader = xors(
+ R"(
+ struct VS_INPUT
+ {
+ float2 pos : POSITION;
+ float2 uv : TEXCOORD;
+ float4 col : COLOR;
+ };
+
+ struct PS_INPUT
+ {
+ float4 pos : SV_POSITION;
+ float2 uv : TEXCOORD;
+ float4 col : COLOR;
+ };
+
+ cbuffer CONSTANTS : register(b0)
+ {
+ float2 screen_size;
+ };
+
+ PS_INPUT main(VS_INPUT input)
+ {
+ PS_INPUT output;
+ output.pos = float4(input.pos.x / screen_size.x * 2.f - 1.f, (-input.pos.y) / screen_size.y * 2.f + 1.f, 0.0f, 1.0f);
+ output.uv = input.uv;
+ output.col = input.col;
+ return output;
+ }
+ )"
+);
+
+static char const *d3d11_pixel_shader = xors(
+ R"(
+ struct PS_INPUT
+ {
+ float4 pos : SV_POSITION;
+ float2 uv : TEXCOORD;
+ float4 col : COLOR;
+ };
+
+ float4 main(PS_INPUT input) : SV_TARGET
+ {
+ return input.col;
+ }
+ )"
+);
+
+static char const *d3d11_pixel_shader_textured = xors(
+ R"(
+ struct PS_INPUT
+ {
+ float4 pos : SV_POSITION;
+ float2 uv : TEXCOORD;
+ float4 col : COLOR;
+ };
+
+ Texture2D texture0 : register(t0);
+ SamplerState sampler0 : register(s0);
+
+ float4 main(PS_INPUT input) : SV_TARGET
+ {
+ float4 out_col = texture0.Sample(sampler0, input.uv);
+ return input.col * out_col;
+ }
+ )"
+);
+
+// TODO OT:
+// find correct d3dcompiler export, u have ur api shit to handle it.
+HRESULT
+D3DCompile(
+ char const *src, size_t len, char const *entry_point, char const *target, UINT flags, UINT shader_flags,
+ ID3DBlob **blob, ID3DBlob **error_blob
+)
+{
+ // return D3DCompile( src, len, nullptr, nullptr, nullptr, entry_point, target, flags, shader_flags, blob, error_blob );
+
+ static pD3DCompile D3DCompile_ = (pD3DCompile)GetProcAddress(GetModuleHandleA("d3dcompiler_47.dll"), "D3DCompile");
+ return D3DCompile_(src, len, nullptr, nullptr, nullptr, entry_point, target, flags, shader_flags, blob, error_blob);
+}
+
+D3D11_RENDERDATA* d3d11_init() {
+ D3D11_RENDERDATA* data = new D3D11_RENDERDATA;
+ memset( data, 0, sizeof(D3D11_RENDERDATA) - sizeof(std::vector<void*>) * 2);
+
+
+ return data;
+}
+
+bool d3d11_init_shaders( D3D11_RENDERDATA* data ) {
+ ID3DBlob* error_blob;
+
+ if( !!D3DCompile(
+ d3d11_vert_shader,
+ strlen( d3d11_vert_shader ),
+ xors("main"), xors("vs_4_0"),
+ 0, 0,
+ &data->vs_blob,
+ &error_blob )
+ ) {
+#if RENDER_DEBUG
+ printf( "d3d11_init_shaders() : error creating vertex shader: %s\n", (char*)error_blob->GetBufferPointer() );
+#endif
+ return false;
+ }
+
+ if( !!data->device->CreateVertexShader(
+ data->vs_blob->GetBufferPointer(),
+ data->vs_blob->GetBufferSize(),
+ nullptr,
+ &data->vertex_shader
+ ) ) {
+ return false;
+ }
+
+ if( !!D3DCompile(
+ d3d11_pixel_shader,
+ strlen( d3d11_pixel_shader ),
+ xors("main"), xors("ps_4_0"),
+ 0, 0,
+ &data->ps_blob,
+ &error_blob ) ) {
+ return false;
+ }
+
+ if( !!data->device->CreatePixelShader(
+ data->ps_blob->GetBufferPointer(),
+ data->ps_blob->GetBufferSize(),
+ nullptr,
+ &data->pixel_shader
+ ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_init_shaders() : error creating pixel shader: %s\n", (char*)error_blob->GetBufferPointer() );
+#endif
+ return false;
+ }
+
+ if( !!D3DCompile(
+ d3d11_pixel_shader_textured,
+ strlen( d3d11_pixel_shader_textured ),
+ xors("main"), xors("ps_4_0"),
+ 0, 0,
+ &data->ps_blob_textured,
+ &error_blob ) ) {
+ return false;
+ }
+
+ if( !!data->device->CreatePixelShader(
+ data->ps_blob_textured->GetBufferPointer(),
+ data->ps_blob_textured->GetBufferSize(),
+ nullptr,
+ &data->pixel_shader_textured
+ ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_init_shaders() : error creating textured pixel shader: %s\n", (char*)error_blob->GetBufferPointer() );
+#endif
+ return false;
+ }
+
+ D3D11_INPUT_ELEMENT_DESC input_element_desc[] = {
+ { xors("POSITION"), 0, DXGI_FORMAT_R32G32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { xors("TEXCOORD"), 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(D3D11_VERTEX, uv), D3D11_INPUT_PER_VERTEX_DATA, 0 },
+ { xors("COLOR"), 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, offsetof(D3D11_VERTEX, col), D3D11_INPUT_PER_VERTEX_DATA, 0 }
+ };
+
+ data->device->CreateInputLayout(
+ input_element_desc,
+ 3,
+ data->vs_blob->GetBufferPointer(),
+ data->vs_blob->GetBufferSize(),
+ &data->input_layout
+ );
+
+ return true;
+}
+
+bool d3d11_init_resources( D3D11_RENDERDATA* data ) {
+ D3D11_BUFFER_DESC buffer_desc;
+ buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
+ buffer_desc.ByteWidth = sizeof(D3D11_VERTEX) * 8192; // ye baby
+ buffer_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
+ buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ buffer_desc.MiscFlags = 0;
+
+ D3D11_SUBRESOURCE_DATA subresource_data;
+ subresource_data.pSysMem = nullptr;
+
+ HRESULT hr;
+ if( !!( hr = data->device->CreateBuffer( &buffer_desc, nullptr, &data->vertex_buffer ) ) ) {
+ return false;
+ }
+
+ if( !!data->device->CreateRenderTargetView( data->back_buffer, nullptr, &data->render_target_view ) ) {
+ return false;
+ }
+
+ data->back_buffer->Release();
+ data->back_buffer = nullptr;
+
+ D3D11_BLEND_DESC blend_desc;
+ blend_desc.AlphaToCoverageEnable = false;
+ blend_desc.IndependentBlendEnable = false;
+ blend_desc.RenderTarget[0].BlendEnable = true;
+ blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA;
+ blend_desc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA;
+ blend_desc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD;
+ blend_desc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE;
+ blend_desc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO;
+ blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD;
+ blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
+
+ if( !!data->device->CreateBlendState( &blend_desc, &data->blend_state ) ) {
+ return false;
+ }
+
+ D3D11_RASTERIZER_DESC rasterizer_desc;
+ rasterizer_desc.FillMode = D3D11_FILL_SOLID;
+ rasterizer_desc.CullMode = D3D11_CULL_NONE;
+ rasterizer_desc.ScissorEnable = false;
+ rasterizer_desc.DepthClipEnable = false;
+
+ if( !!data->device->CreateRasterizerState( &rasterizer_desc, &data->rasterizer_state ) ) {
+ return false;
+ }
+
+ D3D11_DEPTH_STENCIL_DESC depth_stencil_desc;
+ depth_stencil_desc.DepthEnable = false;
+ depth_stencil_desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
+ depth_stencil_desc.DepthFunc = D3D11_COMPARISON_LESS;
+ depth_stencil_desc.StencilEnable = false;
+ depth_stencil_desc.StencilReadMask = 0xFF;
+ depth_stencil_desc.StencilWriteMask = 0xFF;
+ depth_stencil_desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
+ depth_stencil_desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR;
+ depth_stencil_desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
+ depth_stencil_desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
+ depth_stencil_desc.BackFace = depth_stencil_desc.FrontFace;
+
+ if( !!data->device->CreateDepthStencilState( &depth_stencil_desc, &data->depth_stencil_state ) ) {
+ return false;
+ }
+
+ // constant buffer
+ D3D11_BUFFER_DESC constant_buffer_desc;
+ constant_buffer_desc.Usage = D3D11_USAGE_DYNAMIC;
+ constant_buffer_desc.ByteWidth = sizeof(DXMAT4X4);
+ constant_buffer_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
+ constant_buffer_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+ constant_buffer_desc.MiscFlags = 0;
+ constant_buffer_desc.StructureByteStride = 0;
+
+ if( !!data->device->CreateBuffer( &constant_buffer_desc, nullptr, &data->constant_buffer ) ) {
+ return false;
+ }
+
+ for( auto& it : data->textures ) {
+ if( it->rgba )
+ d3d11_texture_init( data, it );
+ }
+
+ return true;
+}
+
+#define RELEASE_RSRC(x) if( x ) x->Release(); x = nullptr;
+
+void d3d11_destroy_resources( D3D11_RENDERDATA* data ) {
+ RELEASE_RSRC( data->input_layout );
+ RELEASE_RSRC( data->blend_state );
+ RELEASE_RSRC( data->rasterizer_state );
+ RELEASE_RSRC( data->depth_stencil_state );
+
+ RELEASE_RSRC( data->vertex_shader );
+ RELEASE_RSRC( data->pixel_shader );
+ RELEASE_RSRC( data->pixel_shader_textured );
+
+ RELEASE_RSRC( data->vs_blob );
+ RELEASE_RSRC( data->ps_blob );
+ RELEASE_RSRC( data->ps_blob_textured );
+ RELEASE_RSRC( data->render_target_view );
+
+ RELEASE_RSRC( data->vertex_buffer );
+ RELEASE_RSRC( data->constant_buffer );
+ for( auto& it : data->textures ) {
+ RELEASE_RSRC( it->srv );
+ RELEASE_RSRC( it->tex2d );
+ }
+}
+
+#undef RELEASE_RSRC
+
+void d3d11_on_swapchain_lost( D3D11_RENDERDATA* data ) {
+ d3d11_destroy_resources( data );
+
+ if( !data->device ) {
+ data->clip = { 0, 0, (LONG)data->display[0], (LONG)data->display[1] };
+ }
+
+ data->swapchain->GetDevice( __uuidof( ID3D11Device ), ( LPVOID* )&data->device );
+ data->device->GetImmediateContext( &data->context );
+ data->swapchain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&data->back_buffer );
+
+ if( !d3d11_init_shaders( data ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_on_swapchain_lost() : error initializing shaders\n" );
+#endif
+ return;
+ }
+
+ if( !d3d11_init_resources( data ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_on_swapchain_lost() : error initializing resources\n" );
+#endif
+ }
+}
+
+void d3d11_texture_init( D3D11_RENDERDATA* data, D3D11_TEXTURE* tex ) {
+ D3D11_TEXTURE2D_DESC texture_desc;
+ memset( &texture_desc, 0, sizeof( texture_desc ) );
+
+ texture_desc.Width = tex->w;
+ texture_desc.Height = tex->h;
+ texture_desc.MipLevels = 1;
+ texture_desc.ArraySize = 1;
+ texture_desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
+ texture_desc.SampleDesc.Count = 1;
+ texture_desc.SampleDesc.Quality = 0;
+ texture_desc.Usage = D3D11_USAGE_DEFAULT;
+ texture_desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
+ texture_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
+
+ D3D11_SUBRESOURCE_DATA resource_data;
+ memset( &resource_data, 0, sizeof( resource_data ) );
+ resource_data.pSysMem = tex->rgba;
+ resource_data.SysMemPitch = tex->w * 4;
+ resource_data.SysMemSlicePitch = tex->w * tex->h * 4;
+
+ HRESULT hr;
+ if( !!( hr = data->device->CreateTexture2D( &texture_desc, &resource_data, &tex->tex2d ) ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_texture_init() : error creating texture2d %x\n", hr );
+#endif
+ }
+
+ D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
+ memset( &srv_desc, 0, sizeof(srv_desc) );
+ srv_desc.Format = texture_desc.Format;
+ srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
+ srv_desc.Texture2D.MipLevels = 1;
+
+ if( !!data->device->CreateShaderResourceView( tex->tex2d, &srv_desc, &tex->srv ) ) {
+#if RENDER_DEBUG
+ printf( "d3d11_texture_init() : error creating shader resource view\n" );
+#endif
+ }
+}
+
+D3D11_TEXTURE* d3d11_texture_create( D3D11_RENDERDATA* data, UINT8* rgba, I32 width, I32 height ) {
+ D3D11_TEXTURE* tex = (D3D11_TEXTURE*)malloc( sizeof(D3D11_TEXTURE) );
+ tex->w = width;
+ tex->h = height;
+ tex->rgba = rgba;
+
+ d3d11_texture_init( data, tex );
+
+ data->textures.push_back( tex );
+ return tex;
+}
+
+void d3d11_texture_destroy( D3D11_RENDERDATA* data, D3D11_TEXTURE* tex ) {
+ for( auto it = data->textures.begin(); it != data->textures.end(); ++it ) {
+ if( *it == tex ) {
+ data->textures.erase( it );
+ break;
+ }
+ }
+
+ if( tex->srv )
+ tex->srv->Release();
+ if( tex->tex2d )
+ tex->tex2d->Release();
+
+ free( tex );
+}
+
+void d3d11_on_present( D3D11_RENDERDATA* data, void* swapchain ) {
+ if( swapchain != data->swapchain ) {
+ data->swapchain = (IDXGISwapChain*)swapchain;
+ d3d11_on_swapchain_lost( data );
+ }
+
+ DXGI_SWAP_CHAIN_DESC desc;
+ data->swapchain->GetDesc( &desc );
+
+ if( data->display[0] != (float)desc.BufferDesc.Width
+ || data->display[1] != (float)desc.BufferDesc.Height )
+ d3d11_on_swapchain_lost( data );
+
+ data->display[0] = (float)desc.BufferDesc.Width;
+ data->display[1] = (float)desc.BufferDesc.Height;
+
+ F32 blend_factor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
+ data->context->OMSetBlendState( data->blend_state, blend_factor, 0xFFFFFFFF );
+ data->context->OMSetDepthStencilState( data->depth_stencil_state, 0 );
+ data->context->RSSetState( data->rasterizer_state );
+
+ D3D11_VIEWPORT viewport;
+ viewport.Width = data->display[0];
+ viewport.Height = data->display[1];
+ viewport.MinDepth = 0.0f;
+ viewport.MaxDepth = 1.0f;
+ viewport.TopLeftX = viewport.TopLeftY = 0;
+ data->context->RSSetViewports( 1, &viewport );
+
+ data->context->GSSetShader( nullptr, nullptr, 0 );
+ data->context->HSSetShader( nullptr, nullptr, 0 );
+ data->context->DSSetShader( nullptr, nullptr, 0 );
+ data->context->CSSetShader( nullptr, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->constant_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, data->display, sizeof(DXVEC2) );
+ data->context->Unmap( data->constant_buffer, 0 );
+ data->context->VSSetConstantBuffers( 0, 1, &data->constant_buffer );
+
+ data->context->OMSetRenderTargets( 1, &data->render_target_view, nullptr );
+ d3d11_set_clip( data, &data->clip );
+}
+
+void d3d11_set_clip( D3D11_RENDERDATA* data, RECT* clip ) {
+ if( clip ) {
+ D3D11_RECT rect;
+ rect.left = clip->left;
+ rect.top = clip->top;
+ rect.right = clip->right;
+ rect.bottom = clip->bottom;
+ data->context->RSSetScissorRects( 1, &rect );
+ data->clip = *clip;
+ } else {
+ data->clip = { 0, 0, (I32)data->display[0], (I32)data->display[1] };
+ data->context->RSSetScissorRects( 0, nullptr );
+ }
+}
+
+void d3d11_get_clip( D3D11_RENDERDATA* data, RECT* clip ) {
+ *clip = data->clip;
+}
+
+/*
+          ,、     ,、
+        r'ー》'´`⌒ヾ‐》,     / ̄ ̄ ̄ ̄ ̄
+         i  iミ ノ リハリ/!   .|
+        ! i゙瓦゚ ヮ゚ノ!' i|  < Mikku Mikku♪
+        !l! ! と.フリ{つ!i! l    |
+        ノリ | v/_j_、 i!l !   \_____
+        ゞノ  ~じ'フ~ル'ノ   _.__       lヽ,,lヽ
+             _| ::|_      | |Θ|=つ≡つ;;)   )
+        | ̄ ̄ ̄| ̄ ̄|_ |_|≡つ=つ  と   i
+        |___|__|_|  |_| ミクミクミクミクしーJ
+
+
+ */
+
+void d3d11_line( D3D11_RENDERDATA* data, DXVEC2 pos, DXVEC2 pos2, FCLR col ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX vertices[] = {
+ { pos.x, pos.y, 0.0f, 0.0f, col },
+ { pos2.x, pos2.y, 0.0f, 0.0f, col }
+ };
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(vertices) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINELIST );
+
+ data->context->Draw( 2, 0 );
+}
+
+
+void d3d11_rect( D3D11_RENDERDATA* data, DXVEC2 pos, DXVEC2 size, FCLR col ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX vertices[] = {
+ { pos.x , pos.y , 0.0f, 0.0f, col },
+ { pos.x + size.x, pos.y , 0.0f, 1.0f, col },
+ { pos.x + size.x, pos.y + size.y, 0.0f, 0.0f, col },
+ { pos.x , pos.y + size.y, 0.0f, 1.0f, col },
+ { pos.x , pos.y , 0.0f, 0.0f, col }
+ };
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(vertices) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP );
+
+ data->context->Draw( 5, 0 );
+}
+
+void d3d11_frect( D3D11_RENDERDATA* data, DXVEC2 pos, DXVEC2 size, FCLR col ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX vertices[] = {
+ { pos.x, pos.y, 0.0f, 0.0f, col },
+ { pos.x + size.x, pos.y, 0.0f, 1.0f, col },
+ { pos.x, pos.y + size.y, 0.0f, 0.0f, col },
+ { pos.x + size.x, pos.y + size.y, 0.0f, 1.0f, col }
+ };
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(vertices) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
+
+ data->context->Draw( 4, 0 );
+}
+
+void d3d11_textured_frect( D3D11_RENDERDATA* data, DXVEC2 pos, DXVEC2 size, D3D11_TEXTURE* texture, FCLR col ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX vertices[] = {
+ { pos.x, pos.y, 0.0f, 0.0f, col },
+ { pos.x + size.x, pos.y, 1.0f, 0.0f, col },
+ { pos.x, pos.y + size.y, 0.0f, 1.0f, col },
+ { pos.x + size.x, pos.y + size.y, 1.0f, 1.0f, col }
+ };
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader_textured, nullptr, 0 );
+ data->context->PSSetShaderResources( 0, 1, &texture->srv );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(vertices) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
+
+ data->context->Draw( 4, 0 );
+}
+
+void d3d11_gradient_frect(
+ D3D11_RENDERDATA* data,
+ DXVEC2 pos,
+ DXVEC2 size,
+ FCLR tl,
+ FCLR tr,
+ FCLR bl,
+ FCLR br
+) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX vertices[] = {
+ { pos.x, pos.y, 0.0f, 0.0f, tl },
+ { pos.x + size.x, pos.y, 0.0f, 1.0f, tr },
+ { pos.x, pos.y + size.y, 0.0f, 0.0f, bl },
+ { pos.x + size.x, pos.y + size.y, 0.0f, 1.0f, br }
+ };
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(vertices) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
+
+ data->context->Draw( 4, 0 );
+}
+
+
+void d3d11_fcircle( D3D11_RENDERDATA* data, DXVEC2 pos, F32 radius, FCLR col, I32 res ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * (res * 2) );
+ for( I32 i = 0; i < res * 2; i += 2 ) {
+ F32 sin = sinf( (float)i / res * 2.f * 3.14159265358979323846f );
+ F32 cos = cosf( (float)i / res * 2.f * 3.14159265358979323846f );
+ vertices[i].x = pos.x;
+ vertices[i].y = pos.y;
+ vertices[i].uv.x = 0.5f;
+ vertices[i].uv.y = 0.5f;
+ vertices[i].col = col;
+
+ vertices[i + 1].x = pos.x + sin * radius;
+ vertices[i + 1].y = pos.y + cos * radius;
+ vertices[i + 1].uv.x = 0.5f + ( sin * radius * 0.5f ) / radius;
+ vertices[i + 1].uv.y = 0.5f + ( cos * radius * 0.5f ) / radius;
+ vertices[i + 1].col = col;
+ }
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * (res + 2) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
+
+ data->context->Draw( res + 2, 0 );
+ free( vertices );
+}
+
+void d3d11_circle( D3D11_RENDERDATA* data, DXVEC2 pos, F32 radius, FCLR col, I32 res ) {
+ UINT stride = sizeof(D3D11_VERTEX);
+ UINT offset = 0;
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * (res + 1) );
+ for( I32 i = 0; i < res + 1; ++i ) {
+ F32 sin = sinf( (float)i / (float)res * 2.f * 3.14159265358979323846f );
+ F32 cos = cosf( (float)i / (float)res * 2.f * 3.14159265358979323846f );
+
+ vertices[i].x = pos.x + sin * radius;
+ vertices[i].y = pos.y + cos * radius;
+ vertices[i].uv.x = 0.5f + ( sin * radius * 0.5f ) / radius;
+ vertices[i].uv.y = 0.5f + ( cos * radius * 0.5f ) / radius;
+ vertices[i].col = col;
+ }
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * (res + 1) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP );
+
+ data->context->Draw( res + 1, 0 );
+ free( vertices );
+}
+
+void d3d11_arc( D3D11_RENDERDATA* data, DXVEC2 pos, F32 radius, F32 start_angle, F32 end_angle, FCLR col, I32 res ) {
+ U32 stride = sizeof(D3D11_VERTEX);
+ U32 offset = 0;
+
+ start_angle = start_angle * (3.14159265358979323846f / 180.f);
+ end_angle = end_angle * (3.14159265358979323846f / 180.f);
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * (res + 1) );
+ for( I32 i = 0; i < res + 1; ++i ) {
+ F32 sin = sinf( (float)i / (float)res * ( end_angle - start_angle ) + start_angle );
+ F32 cos = cosf( (float)i / (float)res * ( end_angle - start_angle ) + start_angle );
+
+ vertices[i].x = pos.x + sin * radius;
+ vertices[i].y = pos.y + cos * radius;
+ vertices[i].uv.x = 0.5f + ( sin * radius * 0.5f ) / radius;
+ vertices[i].uv.y = 0.5f + ( cos * radius * 0.5f ) / radius;
+ vertices[i].col = col;
+ }
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * (res + 1) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP );
+
+ data->context->Draw( res + 1, 0 );
+ free( vertices );
+}
+
+void d3d11_farc( D3D11_RENDERDATA* data, DXVEC2 pos, F32 radius, F32 start_angle, F32 end_angle, FCLR col, I32 res ) {
+ return d3d11_farc_2clr( data, pos, radius, start_angle, end_angle, col, col, res );
+}
+
+void d3d11_farc_2clr(
+ D3D11_RENDERDATA* data,
+ DXVEC2 pos,
+ F32 radius,
+ F32 start_angle,
+ F32 end_angle,
+ FCLR col1,
+ FCLR col2,
+ I32 res
+) {
+ U32 stride = sizeof(D3D11_VERTEX);
+ U32 offset = 0;
+
+ start_angle = start_angle * (3.14159265358979323846f / 180.f);
+ end_angle = end_angle * (3.14159265358979323846f / 180.f);
+ F32 step = ( end_angle - start_angle ) / (res - 1);
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * (res * 2) );
+ for( I32 i = 0; i < res * 2; i += 2 ) {
+ F32 sin = sinf( (float)(i / 2) * step + start_angle );
+ F32 cos = cosf( (float)(i / 2) * step + start_angle );
+
+ vertices[i].x = pos.x;
+ vertices[i].y = pos.y;
+ vertices[i].uv.x = 0.5f;
+ vertices[i].uv.y = 0.5f;
+ vertices[i].col = col1;
+
+ vertices[i + 1].x = pos.x + cos * radius;
+ vertices[i + 1].y = pos.y + sin * radius;
+ vertices[i + 1].uv.x = 0.5f + ( sin * radius * 0.5f ) / radius;
+ vertices[i + 1].uv.y = 0.5f + ( cos * radius * 0.5f ) / radius;
+ vertices[i + 1].col = col2;
+ }
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * (res * 2) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP );
+
+ data->context->Draw( res * 2, 0 );
+ free( vertices );
+}
+
+void d3d11_thick_circle( D3D11_RENDERDATA* data, DXVEC2 pos, F32 radius_in, F32 radius_out, FCLR col, I32 res ) {
+ UINT stride = sizeof( D3D11_VERTEX );
+ UINT offset = 0;
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * (res * 6) );
+ F32 step = (2 * 3.14159265358979323846f) / (res - 1);
+
+ for( I32 i = 0; i < res; ++i ) {
+ F32 t1 = step * i;
+ F32 t2 = step * (i + 1);
+
+ F32 s1 = sinf( t1 );
+ F32 c1 = cosf( t1 );
+
+ F32 s2 = sinf( t2 );
+ F32 c2 = cosf( t2 );
+
+ D3D11_VERTEX bl = { pos.x + c1 * radius_in, pos.y + s1 * radius_in, 0, 0, col };
+ D3D11_VERTEX tl = { pos.x + c1 * radius_out, pos.y + s1 * radius_out, 0, 0, col };
+ D3D11_VERTEX br = { pos.x + c2 * radius_in, pos.y + s2 * radius_in, 0, 0, col };
+ D3D11_VERTEX tr = { pos.x + c2 * radius_out, pos.y + s2 * radius_out, 0, 0, col };
+
+ vertices[i * 6] = tl;
+ vertices[i * 6 + 1] = tr;
+ vertices[i * 6 + 2] = bl;
+ vertices[i * 6 + 3] = bl;
+ vertices[i * 6 + 4] = tr;
+ vertices[i * 6 + 5] = br;
+ }
+
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader, nullptr, 0 );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * (res * 6) );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
+
+ data->context->Draw( res * 6, 0 );
+ free( vertices );
+}
+
+
+void d3d11_rounded_rect( D3D11_RENDERDATA* data, DXVEC2 pos, DXVEC2 size, F32 radius, FCLR col, I32 flags ) {
+ if( size.x <= 6 && flags == 0xFFFF ) {
+ d3d11_line( data, { pos.x, pos.y + 1 }, { pos.x, pos.y + size.y - 1 }, col );
+
+ if( size.x > 2 ) {
+ for( I32 i = 0; i < size.x - 2; ++i ) {
+ d3d11_line( data, { pos.x + i + 1, pos.y }, { pos.x + i + 1, pos.y + size.y }, col );
+ }
+ }
+
+ d3d11_line( data, { pos.x + size.x - 1, pos.y + 1 }, { pos.x + size.x - 1, pos.y + size.y - 1 }, col );
+ return;
+ }
+
+ d3d11_frect( data, { pos.x + radius, pos.y }, { size.x - radius * 2, size.y }, col );
+ d3d11_frect( data, { pos.x, pos.y + radius }, { size.x, size.y - radius * 2 }, col );
+
+ if( flags & e_top_left )
+ d3d11_farc( data, { pos.x + radius, pos.y + radius }, radius, 270.f, 360.f, col );
+ else if( radius > size.x && radius > size.y )
+ d3d11_frect( data, { pos.x, pos.y }, { radius, radius }, col );
+
+ if( flags & e_top_right )
+ d3d11_farc( data, { pos.x + size.x - radius, pos.y + radius }, radius, 270.f, 360.f, col );
+ else if( radius > size.x && radius > size.y )
+ d3d11_frect( data, { pos.x + size.x - radius, pos.y }, { radius, radius }, col );
+
+ if( flags & e_bottom_left )
+ d3d11_farc( data, { pos.x + radius, pos.y + size.y - radius }, radius, 90.f, 180.f, col );
+ else if( radius > size.x && radius > size.y )
+ d3d11_frect( data, { pos.x, pos.y + size.y - radius }, { radius, radius }, col );
+
+ if( flags & e_bottom_right )
+ d3d11_farc( data, { pos.x + size.x - radius, pos.y + size.y - radius }, radius, 0.f, 90.f, col );
+ else
+ d3d11_frect( data, { pos.x + size.x - radius, pos.y + size.y - radius }, { radius, radius }, col );
+}
+
+
+/*
+
+ _
+ _|_.__ __|_ ._ _ !
+ | |(/_(/_|_\/|_)(/_ !
+ / | !
+
+
+                     ___,... __
+               ,. '"´       `丶、
+                  〃- ─=ミv' 彡=‐ -ミ、
+               /7         '´       ト 、
+              /_ノl                |ミ、\
+           〈〈´  |       jミ'ヘ        |  `>〉
+              ヾミ、|   i  //  ヽ  |   1-‐'"
+              `ト|   |ノ//'   `弋、 |   j|
+             j |   |≠ヵ    ヵ≠i|   jl
+               从|   代リ     弋リ1   从
+                /fハ!  | ''''  ,   '''' j  ,小ハ、
+           ノ |!∧  ト、  rっ   ノ! 从!i|
+            ノ少ヘ | 个r .__.. ィ彡 |/ \!
+            /   V 八   /   /   \
+             /    八   \ 〃   /       ハ
+            ハ   :.. : ヽ   /    / l.::   /  !
+          j  ヽ   :: !  \/    /  !//   |
+          |    \::ノ:  /   /   ::{ ..::    |
+            ノ ::..     |:. 〃/)(\    .:!..:::/ .:   |
+         」 ::... ヾ::.. |::../∠ュr_ゝ ヽ .::::|:ノ..::::_..  〉
+            |::  ̄ ̄7ー-^{  ー {j ー  }ーヘ ̄  イ
+        ___}::   ノ   ゝ '´/\` /   } ....:::::}
+    ー=彡'"゙ {:::....  ト-‐ァ¬'"´   `¬=r‐-/.::::::::::/
+   、__ノ ..:.:.:八::::::::::|:::::/|==─‐--─==|:::/.:::::::::,イ
+     フ .:.:.:.:.:.:.:.ヽ:::::::|::/.::|          |i/.:::::/.::|
+*/
+
+D3D11_FONT *
+d3d11_font_create(
+ D3D11_RENDERDATA *data, char const *font_name, U32 font_size, UINT8 *font_data, U32 font_data_size
+)
+{
+ D3D11_FONT* font = (D3D11_FONT*)malloc( sizeof(D3D11_FONT) );
+ memset( font, 0, sizeof(D3D11_FONT) );
+
+ font->name = font_name;
+ font->size = font_size;
+ font->font_data = font_data;
+ font->font_data_size = font_data_size;
+ font->d3d11 = data;
+
+ d3d11_font_init( font );
+
+ return font;
+}
+
+U32 d3d11_font_count_glyphs( D3D11_FONT* font ) {
+ U32 ret = 0;
+ U32 idx;
+ U32 charcode = FT_Get_First_Char( font->face, &idx );
+ while( idx != 0 ) {
+ ++ret;
+ charcode = FT_Get_Next_Char( font->face, charcode, &idx );
+ }
+
+ return ret;
+}
+
+void d3d11_font_create_bitmap( D3D11_FONT* font ) {
+ U32 char_width = (U32)ceil((float)font->face->size->metrics.max_advance / 64.f) + 1;
+ U32 char_height = (U32)ceil((float)font->face->size->metrics.height / 64.f) + 3;
+
+ U32 glyph_count = d3d11_font_count_glyphs( font );
+ if( glyph_count == 0 )
+ return;
+ if( glyph_count > 0xFFFF )
+ glyph_count = 0xFFFF;
+
+ U32 root = (U32)ceil( sqrt( glyph_count ) );
+ U32 max_width = (root + 1) * char_width;
+ U32 max_height = (root + 1) * char_height;
+
+ font->bitmap = (U32*)malloc( sizeof(U32) * max_width * max_height );
+ memset( font->bitmap, 0, sizeof(U32) * max_width * max_height );
+
+ font->bitmap_width = max_width;
+ font->bitmap_height = max_height;
+ font->char_width = char_width;
+ font->char_height = char_height;
+
+ U32 cur_x = 1, cur_y = 1;
+ for( U32 c = 0; c < 0xFFFF; ++c ) {
+ U32 idx = FT_Get_Char_Index( font->face, c );
+ if( !idx || !!FT_Load_Char( font->face, c, FT_LOAD_DEFAULT ) )
+ continue;
+
+ if( c == ' ' ) {
+ font->blank_spacing = font->face->glyph->metrics.horiAdvance >> 6;
+ continue;
+ }
+
+ if( !font->face->glyph )
+ continue;
+ I32 w = font->face->glyph->metrics.width >> 6, h = font->face->glyph->metrics.height >> 6;
+ if( w > font->size && w > h * 3 )
+ continue; // dumb sanity check.
+ if( h - (int)font->size > 1 ) // this will rape the stack if its more than 2.
+ continue;
+ if( c == 0xfdfd )
+ continue; //in theory its checked above but this is cursed. fuck shitskin muzzies, learn to write.
+
+ if( !!FT_Load_Char( font->face, c, FT_LOAD_RENDER ) )
+ continue;
+
+ FT_Bitmap* bitmap = &font->face->glyph->bitmap;
+ UINT8 pixel;
+ U32 dest_x, dest_y;
+ for( U32 y = 0; y < bitmap->rows; ++y ) {
+ for( U32 x = 0; x < bitmap->width; ++x ) {
+ dest_x = x + cur_x;
+ dest_y = y + cur_y;
+
+ UINT8 pixel = bitmap->buffer[x + bitmap->pitch * y];
+ U32 out_pixel = 0x00FFFFFF;
+
+ out_pixel |= ((U32)(pixel) << 24);
+ font->bitmap[dest_x + max_width * dest_y] = out_pixel;
+ }
+ }
+
+ font->glyphs[c] = (FONT_GLYPH*)malloc( sizeof(FONT_GLYPH) );
+ font->glyphs[c]->offset_x = (float)cur_x;
+ font->glyphs[c]->offset_y = (float)cur_y - 1;
+ font->glyphs[c]->width = (float)bitmap->width;
+ font->glyphs[c]->height = (float)bitmap->rows + 3;
+ font->glyphs[c]->advance_x = (float)(font->face->glyph->metrics.horiAdvance >> 6);
+ font->glyphs[c]->advance_y = char_height - (float)(font->face->glyph->metrics.horiBearingY >> 6);
+ font->glyphs[c]->bearing_x = (float)(font->face->glyph->metrics.horiBearingX >> 6);
+
+ if( cur_x + char_width > max_width ) {
+ cur_x = 1;
+ cur_y += char_height;
+ } else {
+ cur_x += char_width;
+ }
+ }
+}
+
+void d3d11_font_create_atlas( D3D11_FONT* font ) {
+ font->atlas = d3d11_texture_create(
+ font->d3d11,
+ (UINT8*)font->bitmap,
+ font->bitmap_width,
+ font->bitmap_height
+ );
+}
+
+void d3d11_font_init( D3D11_FONT* font ) {
+ FT_Library libft;
+
+ // invalid font size.
+ if( font->size < 2 ) {
+ return;
+ }
+
+ // better to init every time because thread safety. it takes a miniscule amt of time
+ // comparing to parsing fonts anyway.
+ FT_Init_FreeType( &libft );
+ U32 err;
+ if( !font->font_data ) {
+ char buf[256];
+ sprintf( buf, "C:\\Windows\\Fonts\\%s", font->name );
+ err = FT_New_Face( libft, buf, 0, &font->face );
+ }
+ else
+ err = FT_New_Memory_Face( libft, font->font_data, font->font_data_size, 0, &font->face );
+
+ if( err ) {
+#if RENDER_DEBUG
+ printf( "d3d11_font_init(%s) : failed to load font: %x\n", font->name, err );
+#endif
+ return;
+ }
+
+ err = FT_Set_Pixel_Sizes( font->face, 0, font->size );
+ if( err ) {
+#if RENDER_DEBUG
+ printf( "d3d11_font_init(%s) : failed to set font size: %x\n", font->name, err );
+#endif
+ return;
+ }
+
+ d3d11_font_create_bitmap( font );
+ d3d11_font_create_atlas( font );
+
+ FT_Done_Face( font->face );
+ FT_Done_FreeType( libft );
+}
+
+void d3d11_font_destroy( D3D11_FONT* font ) {
+ for( U32 c = 0; c < 0xFFFF; ++c ) {
+ if( font->glyphs[c] ) {
+ free( font->glyphs[c] );
+ }
+ }
+
+ d3d11_texture_destroy( font->d3d11, font->atlas );
+ free( font->bitmap );
+ free( font );
+}
+
+void
+d3d11_font_calc_vertices_uvs(D3D11_FONT *font, DXVEC2 origin, wchar_t const *text, D3D11_VERTEX *vertices, FCLR col)
+{
+ U32 len = 0; for( ; text[len] != '\0'; len++ );
+
+ F32 cur_x = origin.x, cur_y = origin.y - font->char_height / 2 + 3;
+ for( U32 i = 0; i < len; ++i ) {
+ D3D11_VERTEX* v = &vertices[i * 6];
+
+ if( text[i] == '\n' || text[i] == ' ' ) {
+ D3D11_VERTEX v0;
+ memset( &v0, 0, sizeof(D3D11_VERTEX) );
+
+ v0.x = cur_y;
+ v0.y = cur_y;
+
+ v[0] = v[1] = v[2] = v[3] = v[4] = v[5] = v0;
+ if( text[i] == '\n' ) {
+ cur_x = origin.x;
+ cur_y += (float)font->char_height;
+ }
+ else {
+ cur_x += font->blank_spacing > 0 ? (float)font->blank_spacing : (float)font->char_width / 2;
+ }
+ continue;
+ }
+
+ U32 c = text[i];
+ if( c >= 0xffff )
+ c = '?';
+
+ FONT_GLYPH* glyph = font->glyphs[c];
+ if( !glyph ) {
+ if( font->glyphs['?'] )
+ glyph = font->glyphs['?'];
+ else
+ continue;
+ }
+
+ F32 final_y = ceilf(cur_y + glyph->advance_y);
+ F32 final_x = ceilf(cur_x + glyph->bearing_x);
+
+ v[0].x = final_x; v[0].y = final_y;
+ v[1].x = final_x + glyph->width; v[1].y = final_y;
+ v[2].x = final_x; v[2].y = ceilf(final_y + glyph->height);
+ v[3].x = final_x + glyph->width; v[3].y = ceilf(final_y + glyph->height);
+ v[4].x = final_x; v[4].y = ceilf(final_y + glyph->height);
+ v[5].x = final_x + glyph->width; v[5].y = final_y;
+
+ v[0].uv = { glyph->offset_x / (float)font->bitmap_width, glyph->offset_y / (float)font->bitmap_height };
+ v[1].uv = { (glyph->offset_x + glyph->width) / (float)font->bitmap_width, glyph->offset_y / (float)font->bitmap_height };
+ v[2].uv = { glyph->offset_x / (float)font->bitmap_width, (glyph->offset_y + glyph->height) / (float)font->bitmap_height };
+ v[3].uv = { (glyph->offset_x + glyph->width) / (float)font->bitmap_width, (glyph->offset_y + glyph->height) / (float)font->bitmap_height };
+ v[4].uv = { glyph->offset_x / (float)font->bitmap_width, (glyph->offset_y + glyph->height) / (float)font->bitmap_height };
+ v[5].uv = { (glyph->offset_x + glyph->width) / (float)font->bitmap_width, glyph->offset_y / (float)font->bitmap_height };
+
+ v[0].col = v[1].col = v[2].col = v[3].col = v[4].col = v[5].col = col;
+
+ cur_x += glyph->advance_x;
+ }
+}
+
+void
+d3d11_font_drawW(D3D11_FONT *font, DXVEC2 pos, wchar_t const *text, FCLR col)
+{
+ if( !font || !font->bitmap || !font->atlas )
+ return;
+
+ U32 stride = sizeof(D3D11_VERTEX);
+ U32 offset = 0;
+ U32 len;
+ for( len = 0; !!text[len]; ++len );
+
+ D3D11_VERTEX* vertices = (D3D11_VERTEX*)malloc( sizeof(D3D11_VERTEX) * len * 6 );
+ d3d11_font_calc_vertices_uvs( font, pos, text, vertices, col );
+
+ D3D11_RENDERDATA* data = font->d3d11;
+ data->context->IASetInputLayout( data->input_layout );
+
+ data->context->VSSetShader( data->vertex_shader, nullptr, 0 );
+ data->context->PSSetShader( data->pixel_shader_textured, nullptr, 0 );
+ data->context->PSSetShaderResources( 0, 1, &font->atlas->srv );
+
+ D3D11_MAPPED_SUBRESOURCE mapped_resource;
+ if( !!data->context->Map( data->vertex_buffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped_resource ) ) {
+ return;
+ }
+
+ memcpy( mapped_resource.pData, vertices, sizeof(D3D11_VERTEX) * len * 6 );
+ data->context->Unmap( data->vertex_buffer, 0 );
+
+ data->context->IASetVertexBuffers( 0, 1, &data->vertex_buffer, &stride, &offset );
+ data->context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
+
+ data->context->Draw( len * 6, 0 );
+ free( vertices );
+}
+
+void
+d3d11_font_drawA(D3D11_FONT *font, DXVEC2 pos, char const *text, FCLR col)
+{
+ if( !font || !font->bitmap || !font->atlas )
+ return;
+
+ UINT len = (UINT)strlen( text );
+ wchar_t* wide = (wchar_t*)malloc( (len + 1) * sizeof(wchar_t) );
+ memset( wide, 0, (len + 1) * sizeof(wchar_t) );
+
+ for( UINT i = 0; i < len; ++i ) {
+ wide[i] = (wchar_t)text[i];
+ }
+
+ d3d11_font_drawW( font, pos, wide, col );
+ free( wide );
+}
+
+void
+d3d11_font_get_extentW(D3D11_FONT *font, wchar_t const *text, DXVEC2 *extent)
+{
+ if( !font || !font->bitmap || !font->atlas )
+ return;
+
+ F32 cur_x = 0, cur_y = -(float)font->char_height / 2 + (float)font->char_height - 3;
+ UINT len; for( len = 0; !!text[len]; ++len );
+
+ if( !len ) {
+ extent->x = 0;
+ extent->y = 0;
+ return;
+ }
+
+ for( UINT i = 0; i < len; ++i ) {
+ if( text[i] == '\n' || text[i] == ' ' ) {
+ if( text[i] == '\n' ) {
+ cur_x = 0;
+ cur_y += (float)font->char_height - 3;
+ }
+ else {
+ cur_x += font->blank_spacing > 0 ? (float)font->blank_spacing : (float)font->char_width / 2;
+ }
+ continue;
+ }
+
+ U32 c = text[i];
+ FONT_GLYPH* glyph = font->glyphs[c];
+ if( !glyph ) {
+ if( font->glyphs['?'] )
+ glyph = font->glyphs['?'];
+ else
+ continue;
+ }
+
+ cur_x += glyph->advance_x;
+ }
+
+ extent->x = cur_x;
+ extent->y = cur_y;
+}
+
+void
+d3d11_font_get_extentA(D3D11_FONT *font, char const *text, DXVEC2 *extent)
+{
+ if( !font || !font->bitmap || !font->atlas )
+ return;
+
+ UINT len = (UINT)strlen( text );
+ wchar_t* wide = (wchar_t*)malloc( (len + 1) * sizeof(wchar_t) );
+ memset( wide, 0, (len + 1) * sizeof(wchar_t) );
+
+ for( UINT i = 0; i < len; ++i ) {
+ wide[i] = (wchar_t)text[i];
+ }
+
+ d3d11_font_get_extentW( font, wide, extent );
+ free( wide );
+}