#include "RmlManager.h" extern ID3D11Device* g_pd3dDevice; extern ID3D11DeviceContext* g_pImmediateContext; extern ID3D11RenderTargetView* g_pRenderTargetView; RmlManager& RmlManager::Get() { static RmlManager instance; return instance; } RmlManager::RmlManager() : m_initialised(false) , m_context(nullptr) { } RmlManager::~RmlManager() { Shutdown(); } bool RmlManager::Init(int viewport_width, int viewport_height) { if (m_initialised) return true; m_file_interface = std::make_unique(); m_system_interface = std::make_unique(); m_renderer = std::make_unique(g_pd3dDevice, g_pImmediateContext); if (!m_renderer->IsInitialised()) { app.DebugPrintf("[RmlManager] Renderer failed to initialise\n"); return false; } // Set asset path for RmlUi files (relative to exe directory) Rml::String assetPath = utils.GetExeDir().string() + "/Assets/UI"; m_file_interface->SetAssetPath(assetPath); Rml::SetRenderInterface(m_renderer.get()); Rml::SetSystemInterface(m_system_interface.get()); Rml::SetFileInterface(m_file_interface.get()); if (!Rml::Initialise()) { app.DebugPrintf("[RmlManager] RmlUi Core failed to initialise\n"); return false; } // GabsPuN: Hardcoded. Is this really needed? /* // Load default fonts Rml::LoadFontFace("C:/Windows/Fonts/segoeui.ttf", false); Rml::LoadFontFace("C:/Windows/Fonts/segoeuib.ttf", false); Rml::LoadFontFace("C:/Windows/Fonts/segoeuii.ttf", false); Rml::LoadFontFace("C:/Windows/Fonts/segoeuiz.ttf", false); */ // Minecraft's UI fonts (from tryashtar/minecraft-ttf) if (!Rml::LoadFontFace(assetPath + "/fonts/Mojangles.ttf", "Minecraft Default", Rml::Style::FontStyle::Normal, Rml::Style::FontWeight::Normal, false)) app.DebugPrintf("[RmlManager] FAILED loading Mojangles.ttf\n"); if (!Rml::LoadFontFace(assetPath + "/fonts/MinecraftTen.ttf", "Minecraft Default", Rml::Style::FontStyle::Normal, Rml::Style::FontWeight::Bold, true)) app.DebugPrintf("[RmlManager] FAILED loading MinecraftTen.ttf\n"); m_context = Rml::CreateContext("main", Rml::Vector2i(viewport_width, viewport_height)); if (!m_context) { app.DebugPrintf("[RmlManager] Failed to create RmlUi context\n"); Rml::Shutdown(); return false; } app.DebugPrintf("[RmlManager] Context created (%dx%d)\n", viewport_width, viewport_height); m_renderer->SetViewport(viewport_width, viewport_height); m_initialised = true; app.DebugPrintf("[RmlManager] Initialised (%dx%d)\n", viewport_width, viewport_height); return true; } void RmlManager::Shutdown() { if (!m_initialised) return; if (m_context) { m_context->UnloadAllDocuments(); Rml::RemoveContext(m_context->GetName()); m_context = nullptr; } Rml::Shutdown(); m_renderer.reset(); m_system_interface.reset(); m_file_interface.reset(); m_initialised = false; app.DebugPrintf("[RmlManager] Shutdown\n"); } void RmlManager::Update() { if (!m_initialised || !m_context) return; m_context->Update(); } void RmlManager::Render() { if (!m_initialised || !m_context) return; // Ensure we render to the backbuffer (gamma post-process may have restored a // different RTV). Use the singleton backbuffer RTV that the rest of the engine // binds at frame start. if (g_pRenderTargetView) { ID3D11DepthStencilView* nullDSV = nullptr; g_pImmediateContext->OMSetRenderTargets(1, &g_pRenderTargetView, nullDSV); } // Clear any SRV still bound from gamma post-process so it doesn't // interfere with RmlUi's own texture binding. ID3D11ShaderResourceView* nullSRV[1] = { nullptr }; g_pImmediateContext->PSSetShaderResources(0, 1, nullSRV); m_renderer->BeginFrame(); //GabsPuN: This DebugPrintf is called each frame when RMLUI is not used. /* int docCount = 0; for (int i = 0; i < m_context->GetNumDocuments(); i++) { auto* doc = m_context->GetDocument(i); if (doc && doc->IsVisible()) docCount++; } if (docCount == 0) app.DebugPrintf("[RmlManager] WARNING: No visible documents in context\n"); */ m_context->Render(); m_renderer->EndFrame(); } void RmlManager::OnResize(int width, int height) { if (!m_initialised || !m_context) return; m_context->SetDimensions(Rml::Vector2i(width, height)); m_renderer->SetViewport(width, height); }