#pragma push_macro("byte") #pragma push_macro("GetNextSibling") #pragma push_macro("GetFirstChild") #undef byte #undef GetNextSibling #undef GetFirstChild #include "RmlUi_Renderer_D3D11.h" #include #include #include #include #pragma comment(lib, "d3dcompiler.lib") // ---- Embedded HLSL shaders ---- static const char* g_vs_hlsl = R"( cbuffer Projection : register(b0) { float4x4 proj; float2 translate; }; struct VS_IN { float2 pos : POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; }; struct VS_OUT { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; }; VS_OUT main(VS_IN input) { VS_OUT output; float2 p = input.pos + translate; output.pos = mul(proj, float4(p, 0.0, 1.0)); output.tex = input.tex; output.col = input.col; return output; } )"; static const char* g_ps_textured_hlsl = R"( struct PS_IN { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; }; Texture2D tex : register(t0); SamplerState samp : register(s0); float4 main(PS_IN input) : SV_Target { float4 tex_col = tex.Sample(samp, input.tex); return input.col * tex_col; } )"; static const char* g_ps_color_hlsl = R"( struct PS_IN { float4 pos : SV_POSITION; float2 tex : TEXCOORD0; float4 col : COLOR0; }; float4 main(PS_IN input) : SV_Target { return input.col; } )"; RenderInterface_D3D11::RenderInterface_D3D11(ID3D11Device* device, ID3D11DeviceContext* context) : m_device(device) , m_context(context) , m_initialised(false) , m_vertex_shader(nullptr) , m_pixel_shader_textured(nullptr) , m_pixel_shader_color(nullptr) , m_input_layout(nullptr) , m_blend_state(nullptr) , m_depth_state(nullptr) , m_raster_state(nullptr) , m_sampler_state(nullptr) , m_projection_cb(nullptr) , m_transform_active(false) , m_scissor_enabled(false) , m_white_texture(nullptr) , m_width(0) , m_height(0) , m_next_geometry_handle(1) , m_next_texture_handle(1) { // Initialise COM for WIC image loading HRESULT com_hr = CoInitializeEx(nullptr, COINIT_APARTMENTTHREADED); if (FAILED(com_hr) && com_hr != RPC_E_CHANGED_MODE) { app.DebugPrintf("[RmlUi] CoInitializeEx failed: 0x%08X\n", com_hr); } m_projection = Rml::Matrix4f::Identity(); if (!CompileShaders()) { app.DebugPrintf("[RmlUi] Failed to compile shaders!\n"); return; } if (!CreateStateObjects()) { app.DebugPrintf("[RmlUi] Failed to create state objects!\n"); return; } // Create 1x1 white texture for untextured geometry { unsigned char white_pixel[4] = { 255, 255, 255, 255 }; D3D11_SUBRESOURCE_DATA init_data = {}; init_data.pSysMem = white_pixel; init_data.SysMemPitch = 4; D3D11_TEXTURE2D_DESC desc = {}; desc.Width = 1; desc.Height = 1; desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; ID3D11Texture2D* tex = nullptr; if (SUCCEEDED(m_device->CreateTexture2D(&desc, &init_data, &tex))) { D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; srv_desc.Format = desc.Format; srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srv_desc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(tex, &srv_desc, &m_white_texture); tex->Release(); } } m_initialised = true; } RenderInterface_D3D11::~RenderInterface_D3D11() { if (m_white_texture) m_white_texture->Release(); if (m_projection_cb) m_projection_cb->Release(); if (m_sampler_state) m_sampler_state->Release(); if (m_raster_state) m_raster_state->Release(); if (m_depth_state) m_depth_state->Release(); if (m_blend_state) m_blend_state->Release(); if (m_input_layout) m_input_layout->Release(); if (m_vertex_shader) m_vertex_shader->Release(); if (m_pixel_shader_textured) m_pixel_shader_textured->Release(); if (m_pixel_shader_color) m_pixel_shader_color->Release(); for (auto* g : m_geometry_lookup) { if (g) { if (g->vertex_buffer) g->vertex_buffer->Release(); if (g->index_buffer) g->index_buffer->Release(); delete g; } } for (auto* t : m_texture_lookup) { if (t) { if (t->srv) t->srv->Release(); delete t; } } } bool RenderInterface_D3D11::CompileShaders() { HRESULT hr; // Vertex shader ID3DBlob* vs_blob = nullptr; ID3DBlob* error_blob = nullptr; hr = D3DCompile(g_vs_hlsl, strlen(g_vs_hlsl), "vs", nullptr, nullptr, "main", "vs_4_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, &vs_blob, &error_blob); if (FAILED(hr)) { if (error_blob) { app.DebugPrintf("[RmlUi] VS compile error: %s\n", (const char*)error_blob->GetBufferPointer()); error_blob->Release(); } return false; } hr = m_device->CreateVertexShader(vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), nullptr, &m_vertex_shader); if (FAILED(hr)) { vs_blob->Release(); return false; } // Input layout D3D11_INPUT_ELEMENT_DESC layout[] = { { "POSITION", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(RmlD3D11Vertex, position), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, offsetof(RmlD3D11Vertex, texcoord), D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, offsetof(RmlD3D11Vertex, color), D3D11_INPUT_PER_VERTEX_DATA, 0 }, }; hr = m_device->CreateInputLayout(layout, 3, vs_blob->GetBufferPointer(), vs_blob->GetBufferSize(), &m_input_layout); vs_blob->Release(); if (FAILED(hr)) return false; // Textured pixel shader ID3DBlob* ps_blob = nullptr; hr = D3DCompile(g_ps_textured_hlsl, strlen(g_ps_textured_hlsl), "ps_tex", nullptr, nullptr, "main", "ps_4_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, &ps_blob, &error_blob); if (FAILED(hr)) { if (error_blob) { app.DebugPrintf("[RmlUi] PS textured compile error: %s\n", (const char*)error_blob->GetBufferPointer()); error_blob->Release(); } return false; } hr = m_device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nullptr, &m_pixel_shader_textured); ps_blob->Release(); if (FAILED(hr)) return false; // Color-only pixel shader hr = D3DCompile(g_ps_color_hlsl, strlen(g_ps_color_hlsl), "ps_col", nullptr, nullptr, "main", "ps_4_0", D3DCOMPILE_ENABLE_STRICTNESS, 0, &ps_blob, &error_blob); if (FAILED(hr)) { if (error_blob) { app.DebugPrintf("[RmlUi] PS color compile error: %s\n", (const char*)error_blob->GetBufferPointer()); error_blob->Release(); } return false; } hr = m_device->CreatePixelShader(ps_blob->GetBufferPointer(), ps_blob->GetBufferSize(), nullptr, &m_pixel_shader_color); ps_blob->Release(); if (FAILED(hr)) return false; return true; } bool RenderInterface_D3D11::CreateStateObjects() { HRESULT hr; // Blend state: premultiplied alpha blending D3D11_BLEND_DESC blend_desc = {}; blend_desc.RenderTarget[0].BlendEnable = TRUE; blend_desc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; 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_INV_SRC_ALPHA; blend_desc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blend_desc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; hr = m_device->CreateBlendState(&blend_desc, &m_blend_state); if (FAILED(hr)) return false; // Depth-stencil state: disable depth testing D3D11_DEPTH_STENCIL_DESC ds_desc = {}; ds_desc.DepthEnable = FALSE; ds_desc.StencilEnable = FALSE; hr = m_device->CreateDepthStencilState(&ds_desc, &m_depth_state); if (FAILED(hr)) return false; // Rasterizer state: no culling, scissor enabled D3D11_RASTERIZER_DESC rast_desc = {}; rast_desc.FillMode = D3D11_FILL_SOLID; rast_desc.CullMode = D3D11_CULL_NONE; rast_desc.ScissorEnable = TRUE; rast_desc.DepthClipEnable = TRUE; rast_desc.AntialiasedLineEnable = FALSE; rast_desc.MultisampleEnable = FALSE; rast_desc.FrontCounterClockwise = FALSE; hr = m_device->CreateRasterizerState(&rast_desc, &m_raster_state); if (FAILED(hr)) return false; // Sampler state: Nearest-Neighbor, clamp D3D11_SAMPLER_DESC samp_desc = {}; samp_desc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; samp_desc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP; samp_desc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP; samp_desc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP; samp_desc.MaxLOD = FLT_MAX; hr = m_device->CreateSamplerState(&samp_desc, &m_sampler_state); if (FAILED(hr)) return false; // Constant buffer: float4x4 + float2 (translation). // D3D11 requires constant buffer sizes to be multiples of 16 bytes. // HLSL layout: float4x4(64) + float2(8) = 72, padded to 80. constexpr UINT kCBufferSize = 80; D3D11_BUFFER_DESC cb_desc = {}; cb_desc.ByteWidth = kCBufferSize; cb_desc.Usage = D3D11_USAGE_DYNAMIC; cb_desc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; cb_desc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; hr = m_device->CreateBuffer(&cb_desc, nullptr, &m_projection_cb); if (FAILED(hr)) return false; return true; } void RenderInterface_D3D11::SetViewport(int width, int height) { m_width = width; m_height = height; // Orthographic projection: maps pixel coords to clip space // (0,0) = top-left, (width,height) = bottom-right float l = 0.0f; float r = static_cast(width); float b = static_cast(height); float t = 0.0f; float n = -1.0f; float f = 1.0f; m_projection = Rml::Matrix4f::ProjectOrtho(l, r, b, t, n, f); // Update constant buffer (matrix + zero translation) D3D11_MAPPED_SUBRESOURCE mapped; if (SUCCEEDED(m_context->Map(m_projection_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) { memcpy(mapped.pData, &m_projection, sizeof(Rml::Matrix4f)); float zero[2] = { 0, 0 }; memcpy(static_cast(mapped.pData) + sizeof(Rml::Matrix4f), zero, sizeof(zero)); m_context->Unmap(m_projection_cb, 0); } } void RenderInterface_D3D11::BeginFrame() { if (!m_initialised) return; // Set viewport D3D11_VIEWPORT vp; vp.TopLeftX = 0; vp.TopLeftY = 0; vp.Width = static_cast(m_width); vp.Height = static_cast(m_height); vp.MinDepth = 0.0f; vp.MaxDepth = 1.0f; m_context->RSSetViewports(1, &vp); // Set states m_context->IASetInputLayout(m_input_layout); m_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_context->VSSetConstantBuffers(0, 1, &m_projection_cb); m_context->OMSetBlendState(m_blend_state, nullptr, 0xffffffff); m_context->OMSetDepthStencilState(m_depth_state, 0); m_context->RSSetState(m_raster_state); m_context->PSSetSamplers(0, 1, &m_sampler_state); } void RenderInterface_D3D11::EndFrame() { } // ---- Geometry ---- Rml::CompiledGeometryHandle RenderInterface_D3D11::CompileGeometry(Rml::Span vertices, Rml::Span indices) { auto* geom = new CompiledGeometry(); geom->num_vertices = static_cast(vertices.size()); geom->num_indices = static_cast(indices.size()); geom->vertex_buffer = nullptr; geom->index_buffer = nullptr; // Convert Rml::Vertex to RmlD3D11Vertex std::vector converted(vertices.size()); for (size_t i = 0; i < vertices.size(); i++) { converted[i].position[0] = vertices[i].position.x; converted[i].position[1] = vertices[i].position.y; converted[i].texcoord[0] = vertices[i].tex_coord.x; converted[i].texcoord[1] = vertices[i].tex_coord.y; converted[i].color[0] = vertices[i].colour.red; converted[i].color[1] = vertices[i].colour.green; converted[i].color[2] = vertices[i].colour.blue; converted[i].color[3] = vertices[i].colour.alpha; } geom->vertex_stride = sizeof(RmlD3D11Vertex); // Create vertex buffer D3D11_BUFFER_DESC vb_desc = {}; vb_desc.ByteWidth = static_cast(vertices.size() * sizeof(RmlD3D11Vertex)); vb_desc.Usage = D3D11_USAGE_IMMUTABLE; vb_desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; D3D11_SUBRESOURCE_DATA vb_data = {}; vb_data.pSysMem = converted.data(); if (FAILED(m_device->CreateBuffer(&vb_desc, &vb_data, &geom->vertex_buffer))) { delete geom; return 0; } // Create index buffer bool large_indices = vertices.size() > 65535; geom->index_format = large_indices ? DXGI_FORMAT_R32_UINT : DXGI_FORMAT_R16_UINT; geom->index_stride = large_indices ? 4 : 2; D3D11_BUFFER_DESC ib_desc = {}; ib_desc.ByteWidth = static_cast(indices.size() * geom->index_stride); ib_desc.Usage = D3D11_USAGE_IMMUTABLE; ib_desc.BindFlags = D3D11_BIND_INDEX_BUFFER; if (large_indices) { D3D11_SUBRESOURCE_DATA ib_data = {}; ib_data.pSysMem = indices.data(); if (FAILED(m_device->CreateBuffer(&ib_desc, &ib_data, &geom->index_buffer))) { geom->vertex_buffer->Release(); delete geom; return 0; } } else { // Convert indices to 16-bit std::vector indices16(indices.size()); for (size_t i = 0; i < indices.size(); i++) indices16[i] = static_cast(indices[i]); D3D11_SUBRESOURCE_DATA ib_data = {}; ib_data.pSysMem = indices16.data(); if (FAILED(m_device->CreateBuffer(&ib_desc, &ib_data, &geom->index_buffer))) { geom->vertex_buffer->Release(); delete geom; return 0; } } // Assign handle Rml::CompiledGeometryHandle handle = m_next_geometry_handle++; if (handle >= m_geometry_lookup.size()) m_geometry_lookup.resize(handle + 1, nullptr); m_geometry_lookup[handle] = geom; return handle; } void RenderInterface_D3D11::RenderGeometry(Rml::CompiledGeometryHandle geometry, Rml::Vector2f translation, Rml::TextureHandle texture) { if (!m_initialised) return; if (geometry == 0 || geometry >= m_geometry_lookup.size()) return; CompiledGeometry* geom = m_geometry_lookup[geometry]; if (!geom) return; // Look up texture ID3D11ShaderResourceView* texture_srv = m_white_texture; if (texture != 0 && texture < m_texture_lookup.size()) { TextureData* tex_data = m_texture_lookup[texture]; if (tex_data) texture_srv = tex_data->srv; } DrawCompiledGeometry(geom, translation, texture_srv); } void RenderInterface_D3D11::DrawCompiledGeometry(CompiledGeometry* geom, const Rml::Vector2f& translation, ID3D11ShaderResourceView* texture_srv) { // Compute the transform matrix (projection, possibly combined with element transform). // Translation is NOT baked into the matrix — it's uploaded as a separate cbuffer member // and applied in the vertex shader before the projection. Rml::Matrix4f transform_mat; if (m_transform_active) transform_mat = m_projection * m_transform; else transform_mat = m_projection; // Update constant buffer: matrix (64 bytes) + translation (8 bytes) D3D11_MAPPED_SUBRESOURCE mapped; if (SUCCEEDED(m_context->Map(m_projection_cb, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) { memcpy(mapped.pData, &transform_mat, sizeof(Rml::Matrix4f)); float trans[2] = { translation.x, translation.y }; memcpy(static_cast(mapped.pData) + sizeof(Rml::Matrix4f), trans, sizeof(trans)); m_context->Unmap(m_projection_cb, 0); } // Select pixel shader if (texture_srv == m_white_texture) { m_context->PSSetShader(m_pixel_shader_color, nullptr, 0); } else { m_context->PSSetShader(m_pixel_shader_textured, nullptr, 0); m_context->PSSetShaderResources(0, 1, &texture_srv); } // Set scissor rect if (m_scissor_enabled) { m_context->RSSetScissorRects(1, &m_scissor_rect); } else { D3D11_RECT full_rect = { 0, 0, m_width, m_height }; m_context->RSSetScissorRects(1, &full_rect); } m_context->VSSetShader(m_vertex_shader, nullptr, 0); m_context->VSSetConstantBuffers(0, 1, &m_projection_cb); // Set vertex buffer UINT stride = geom->vertex_stride; UINT offset = 0; m_context->IASetVertexBuffers(0, 1, &geom->vertex_buffer, &stride, &offset); m_context->IASetIndexBuffer(geom->index_buffer, geom->index_format, 0); m_context->DrawIndexed(geom->num_indices, 0, 0); // Cleanup texture binding if (texture_srv != m_white_texture) { ID3D11ShaderResourceView* null_srv[1] = { nullptr }; m_context->PSSetShaderResources(0, 1, null_srv); } } void RenderInterface_D3D11::ReleaseGeometry(Rml::CompiledGeometryHandle geometry) { if (geometry == 0 || geometry >= m_geometry_lookup.size()) return; CompiledGeometry* geom = m_geometry_lookup[geometry]; if (geom) { if (geom->vertex_buffer) geom->vertex_buffer->Release(); if (geom->index_buffer) geom->index_buffer->Release(); delete geom; } m_geometry_lookup[geometry] = nullptr; } // ---- Textures ---- // Include WIC for texture loading #include #pragma comment(lib, "windowscodecs.lib") static bool LoadImageWithWIC(const unsigned char* file_data, size_t file_size, std::vector& out_rgba, int& out_w, int& out_h) { HRESULT hr; IWICImagingFactory* factory = nullptr; hr = CoCreateInstance(CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&factory)); if (FAILED(hr) || !factory) return false; IWICStream* stream = nullptr; hr = factory->CreateStream(&stream); if (FAILED(hr)) { factory->Release(); return false; } hr = stream->InitializeFromMemory(const_cast(file_data), static_cast(file_size)); if (FAILED(hr)) { stream->Release(); factory->Release(); return false; } IWICBitmapDecoder* decoder = nullptr; hr = factory->CreateDecoderFromStream(stream, nullptr, WICDecodeMetadataCacheOnLoad, &decoder); stream->Release(); if (FAILED(hr)) { factory->Release(); return false; } IWICBitmapFrameDecode* frame = nullptr; hr = decoder->GetFrame(0, &frame); if (FAILED(hr)) { decoder->Release(); factory->Release(); return false; } UINT w = 0, h = 0; frame->GetSize(&w, &h); out_w = static_cast(w); out_h = static_cast(h); // Convert to 32bpp BGRA (WIC native format) then swap to RGBA IWICFormatConverter* converter = nullptr; hr = factory->CreateFormatConverter(&converter); if (SUCCEEDED(hr)) { hr = converter->Initialize(frame, GUID_WICPixelFormat32bppBGRA, WICBitmapDitherTypeNone, nullptr, 0.0, WICBitmapPaletteTypeCustom); if (SUCCEEDED(hr)) { out_rgba.resize(w * h * 4); hr = converter->CopyPixels(nullptr, w * 4, static_cast(out_rgba.size()), out_rgba.data()); if (SUCCEEDED(hr)) { // Swap BGRA -> RGBA for (size_t i = 0; i < w * h; i++) { unsigned char tmp = out_rgba[i * 4]; out_rgba[i * 4] = out_rgba[i * 4 + 2]; out_rgba[i * 4 + 2] = tmp; } } } converter->Release(); } frame->Release(); decoder->Release(); factory->Release(); return !out_rgba.empty(); } Rml::TextureHandle RenderInterface_D3D11::LoadTexture(Rml::Vector2i& texture_dimensions, const Rml::String& source) { Rml::FileInterface* file_interface = Rml::GetFileInterface(); Rml::FileHandle file_handle = file_interface->Open(source); if (!file_handle) return 0; file_interface->Seek(file_handle, 0, SEEK_END); long file_size = static_cast(file_interface->Tell(file_handle)); file_interface->Seek(file_handle, 0, SEEK_SET); std::vector file_data(file_size); file_interface->Read(file_data.data(), file_size, file_handle); file_interface->Close(file_handle); int w = 0, h = 0; std::vector rgba; if (!LoadImageWithWIC(file_data.data(), file_data.size(), rgba, w, h)) { app.DebugPrintf("[RmlUi] Failed to load texture: %s\n", source.c_str()); return 0; } texture_dimensions.x = w; texture_dimensions.y = h; D3D11_TEXTURE2D_DESC desc = {}; desc.Width = static_cast(w); desc.Height = static_cast(h); desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA init_data = {}; init_data.pSysMem = rgba.data(); init_data.SysMemPitch = static_cast(w * 4); ID3D11Texture2D* tex = nullptr; if (FAILED(m_device->CreateTexture2D(&desc, &init_data, &tex))) return 0; ID3D11ShaderResourceView* srv = nullptr; D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; srv_desc.Format = desc.Format; srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srv_desc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(tex, &srv_desc, &srv); tex->Release(); if (!srv) return 0; auto* tex_data = new TextureData(); tex_data->srv = srv; tex_data->width = w; tex_data->height = h; Rml::TextureHandle handle = m_next_texture_handle++; if (handle >= m_texture_lookup.size()) m_texture_lookup.resize(handle + 1, nullptr); m_texture_lookup[handle] = tex_data; return handle; } Rml::TextureHandle RenderInterface_D3D11::GenerateTexture(Rml::Span source_data, Rml::Vector2i source_dimensions) { int w = source_dimensions.x; int h = source_dimensions.y; D3D11_TEXTURE2D_DESC desc = {}; desc.Width = static_cast(w); desc.Height = static_cast(h); desc.MipLevels = 1; desc.ArraySize = 1; desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; desc.SampleDesc.Count = 1; desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; D3D11_SUBRESOURCE_DATA init_data = {}; init_data.pSysMem = source_data.data(); init_data.SysMemPitch = static_cast(w * 4); ID3D11Texture2D* tex = nullptr; if (FAILED(m_device->CreateTexture2D(&desc, &init_data, &tex))) return 0; ID3D11ShaderResourceView* srv = nullptr; D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc = {}; srv_desc.Format = desc.Format; srv_desc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; srv_desc.Texture2D.MipLevels = 1; m_device->CreateShaderResourceView(tex, &srv_desc, &srv); tex->Release(); if (!srv) return 0; auto* tex_data = new TextureData(); tex_data->srv = srv; tex_data->width = w; tex_data->height = h; Rml::TextureHandle handle = m_next_texture_handle++; if (handle >= m_texture_lookup.size()) m_texture_lookup.resize(handle + 1, nullptr); m_texture_lookup[handle] = tex_data; return handle; } void RenderInterface_D3D11::ReleaseTexture(Rml::TextureHandle texture) { if (texture == 0 || texture >= m_texture_lookup.size()) return; TextureData* tex_data = m_texture_lookup[texture]; if (tex_data) { if (tex_data->srv) tex_data->srv->Release(); delete tex_data; } m_texture_lookup[texture] = nullptr; } // ---- Scissor ---- void RenderInterface_D3D11::EnableScissorRegion(bool enable) { m_scissor_enabled = enable; } void RenderInterface_D3D11::SetScissorRegion(Rml::Rectanglei region) { m_scissor_rect.left = region.Left(); m_scissor_rect.top = region.Top(); m_scissor_rect.right = region.Right(); m_scissor_rect.bottom = region.Bottom(); } // ---- Transform ---- void RenderInterface_D3D11::SetTransform(const Rml::Matrix4f* transform) { if (transform) { m_transform = *transform; m_transform_active = true; } else { m_transform = Rml::Matrix4f::Identity(); m_transform_active = false; } } #pragma pop_macro("GetFirstChild") #pragma pop_macro("GetNextSibling") #pragma pop_macro("byte")