#include "grender.h" #include "freetype/freetype.h" #include #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) * 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 ); }