Files
GabsPuNs-Project_Zenith_Main/Minecraft.Client/Windows64/RmlUi_Renderer_D3D11.cpp
GabsPuNs 3937b2d98c Use Nearest-Neigbor. Remove Neo Legacy Stuff
Nearest-Neighbor is the default filter used in Minecraft for the UI.
Hardcore mode never existed in console version. Someone just added it with fake 4J comments.
2026-06-11 17:04:49 -04:00

803 lines
22 KiB
C++

#pragma push_macro("byte")
#pragma push_macro("GetNextSibling")
#pragma push_macro("GetFirstChild")
#undef byte
#undef GetNextSibling
#undef GetFirstChild
#include "RmlUi_Renderer_D3D11.h"
#include <RmlUi/Core/Core.h>
#include <RmlUi/Core/FileInterface.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#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<float>(width);
float b = static_cast<float>(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<char*>(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<FLOAT>(m_width);
vp.Height = static_cast<FLOAT>(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<const Rml::Vertex> vertices, Rml::Span<const int> indices)
{
auto* geom = new CompiledGeometry();
geom->num_vertices = static_cast<int>(vertices.size());
geom->num_indices = static_cast<int>(indices.size());
geom->vertex_buffer = nullptr;
geom->index_buffer = nullptr;
// Convert Rml::Vertex to RmlD3D11Vertex
std::vector<RmlD3D11Vertex> 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<UINT>(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<UINT>(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<unsigned short> indices16(indices.size());
for (size_t i = 0; i < indices.size(); i++)
indices16[i] = static_cast<unsigned short>(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<char*>(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 <wincodec.h>
#pragma comment(lib, "windowscodecs.lib")
static bool LoadImageWithWIC(const unsigned char* file_data, size_t file_size, std::vector<unsigned char>& 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<BYTE*>(file_data), static_cast<DWORD>(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<int>(w);
out_h = static_cast<int>(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<UINT>(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<long>(file_interface->Tell(file_handle));
file_interface->Seek(file_handle, 0, SEEK_SET);
std::vector<unsigned char> 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<unsigned char> 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<UINT>(w);
desc.Height = static_cast<UINT>(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<UINT>(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<const Rml::byte> source_data, Rml::Vector2i source_dimensions)
{
int w = source_dimensions.x;
int h = source_dimensions.y;
D3D11_TEXTURE2D_DESC desc = {};
desc.Width = static_cast<UINT>(w);
desc.Height = static_cast<UINT>(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<UINT>(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")