8#include "glm/ext/scalar_constants.hpp"
9#include "glm/gtc/epsilon.hpp"
21#include <RmlUi/Core/Context.h>
22#include <RmlUi/Core/Core.h>
23#include <RmlUi/Core/ElementDocument.h>
24#include <RmlUi/Core/FileInterface.h>
25#include <RmlUi/Core/StreamMemory.h>
26#include <RmlUi/Core/StyleSheetContainer.h>
27#include <RmlUi/Debugger/Debugger.h>
28#include <RmlUi/Core.h>
44 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
47 auto& ev = ctx.get_cached<
events>();
61 int width = 1024, height = 768;
64 const auto& rend = ctx.get_cached<
renderer>();
68 auto size = window->get_window().get_size();
69 width =
static_cast<int>(
size.w);
70 height =
static_cast<int>(
size.h);
75 ui_context_ = Rml::CreateContext(
"main", Rml::Vector2i(width, height));
87 Rml::Debugger::Initialise(ui_context_);
89 APPLOG_INFO(
"UI system initialized successfully ({}x{})", width, height);
92 register_component_callbacks(ctx);
102 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
108 auto& ecs_system = ctx.get_cached<
ecs>();
109 auto&
scene = ecs_system.get_scene();
120 ui_comp.document->Close();
121 ui_comp.document =
nullptr;
126 Rml::RemoveContext(
"main");
127 ui_context_ =
nullptr;
130 Rml::Debugger::Shutdown();
135 APPLOG_INFO(
"UI system deinitialized successfully");
149 update_ui_document_components(ctx);
152 ui_context_->Update();
168 ui_context_->Render();
197 if(
event.type == os::events::mouse_button ||
event.type == os::events::mouse_motion)
199 auto hover_element = ui_context_->GetHoverElement();
200 if(!is_root_element(ctx, hover_element))
207 if(
event.type == os::events::key_down)
209 if(
event.key.code == os::key::code::f2)
211 bool new_visible = !Rml::Debugger::IsVisible();
212 Rml::Debugger::SetVisible(new_visible);
216 if(
event.type == os::events::display_content_scale_changed)
225 if(
event.type == os::events::window)
227 if(
event.window.type == os::window_event_id::size_changed)
237auto ui_system::is_root_element(
rtti::context& ctx, Rml::Element* element) ->
bool
249 if(element->GetTagName() ==
"#root")
254 auto& ecs_system = ctx.get_cached<ecs>();
255 auto& scene = ecs_system.get_scene();
256 auto& registry = *scene.registry;
259 auto view = registry.view<ui_document_component>();
263 auto& ui_comp = view.get<ui_document_component>(
entity);
264 if(ui_comp.document == element)
272void ui_system::load_font(
const std::string& path)
275 Rml::LoadFontFace(font_path,
false);
276 fonts_loaded_.insert(path);
287 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Thin.ttf");
288 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ThinItalic.ttf");
289 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraLight.ttf");
290 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraLightItalic.ttf");
291 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Light.ttf");
292 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-LightItalic.ttf");
293 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Regular.ttf");
294 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Italic.ttf");
295 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Medium.ttf");
296 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-MediumItalic.ttf");
297 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-SemiBold.ttf");
298 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-SemiBoldItalic.ttf");
299 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Bold.ttf");
300 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-BoldItalic.ttf");
301 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraBold.ttf");
302 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraBoldItalic.ttf");
303 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Black.ttf");
304 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-BlackItalic.ttf");
315 if(component.document)
317 component.document->Close();
318 component.document =
nullptr;
330void ui_system::update_ui_document_components(
rtti::context& ctx)
341 if(
input.manager.is_input_allowed())
343 auto mouse_delta_x =
input.manager.get_mouse().get_axis_value(0);
344 auto mouse_delta_y =
input.manager.get_mouse().get_axis_value(1);
346 if(math::epsilonNotEqual(mouse_delta_x, 0.0f, math::epsilon<float>()) || math::epsilonNotEqual(mouse_delta_y, 0.0f, math::epsilon<float>()))
348 auto mouse_x =
input.manager.get_mouse().get_position().x;
349 auto mouse_y =
input.manager.get_mouse().get_position().y;
350 ui_context_->ProcessMouseMove(mouse_x, mouse_y, 0);
356 auto& scene = ecs_system.get_scene();
357 auto& registry = *scene.registry;
359 registry.view<camera_component>().each(
360 [&](
auto e,
auto&& camera)
362 auto viewport = camera.get_viewport_size();
366 auto work_zone =
input.manager.get_work_zone();
369 ui_context_->SetDimensions(Rml::Vector2i(viewport.width, viewport.height));
373 float ratio_x =
static_cast<float>( viewport.width) /
static_cast<float>(work_zone.w);
374 float ratio_y =
static_cast<float>( viewport.height) /
static_cast<float>(work_zone.h);
375 ui_context_->SetDensityIndependentPixelRatio((ratio_x + ratio_y) * 0.5f);
381 auto view = registry.view<ui_document_component>();
385 auto& ui_comp = view.get<ui_document_component>(
entity);
387 bool active = registry.all_of<active_component>(
entity);
391 if(ui_comp.version != ui_comp.asset.version())
395 ui_comp.document->Close();
396 ui_comp.document =
nullptr;
408 if(!ui_comp.is_loaded())
410 load_ui_document(ui_comp);
413 if(!ui_comp.document)
418 bool active_and_enabled = active && ui_comp.is_enabled();
419 if(active_and_enabled)
421 if(!ui_comp.document->IsVisible())
423 ui_comp.document->Show();
428 if( ui_comp.document->IsVisible())
430 ui_comp.document->Hide();
437auto ui_system::load_ui_document(ui_document_component& component) ->
bool
441 APPLOG_ERROR(
"Cannot load UI document: RmlUi context not available");
445 auto asset = component.asset.get();
456 Rml::String url_safe_path = Rml::StringUtilities::Replace(real.string(),
':',
'|');
459 auto raw_document = ui_context_->LoadDocumentFromMemory(asset->content, url_safe_path);
462 APPLOG_ERROR(
"Failed to load UI document: {}", component.asset.id());
465 raw_document->ReloadStyleSheet();
467 raw_document->SetId(
"body");
469 if(component.document)
471 component.document->Close();
474 component.document = raw_document;
475 component.version = component.asset.version();
std::shared_ptr< frame_buffer > ptr
std::chrono::duration< float > delta_t
#define APPLOG_WARNING(...)
#define APPLOG_ERROR(...)
#define APPLOG_TRACE(...)
path resolve_protocol(const path &_path)
Given the specified path/filename, resolve the final full filename. This will be based on either the ...
auto input_event_handler(Rml::Context *context, const os::event &event) -> bool
Process ospp event and forward to RmlUi context.
void set_viewport(int width, int height)
Update viewport size (call on window resize)
auto initialize(rtti::context &ctx, const char *window_name, int width, int height) -> bool
Initialize the RmlUi backend with engine context.
void shutdown()
Shutdown the RmlUi backend and cleanup resources.
void begin_frame()
Prepare render state for RmlUi rendering Call this before rendering RmlUi context.
void present_frame(const gfx::frame_buffer::ptr &framebuffer)
Present the rendered frame Call this after rendering RmlUi context.
#define APP_SCOPE_PERF(name)
Create a scoped performance timer that only accepts string literals.
Manages the entity-component-system (ECS) operations for the ACE framework.
hpp::event< void(rtti::context &, delta_t)> on_frame_update
auto get_main_window() const -> render_window *
Represents a scene in the ACE framework, managing entities and their relationships.
std::unique_ptr< entt::registry > registry
The registry that manages all entities in the scene.
Component that holds a reference to a UI document for RmlUi rendering.
void on_os_event(rtti::context &ctx, os::event &event)
Handle OS events and forward to RmlUi.
auto init(rtti::context &ctx) -> bool
Initializes the UI system with the given context.
static void on_create_component(entt::registry &r, entt::entity e)
void on_frame_update(rtti::context &ctx, delta_t dt)
Update UI system (called every frame)
void on_frame_render(const gfx::frame_buffer::ptr &output, delta_t dt)
Render UI (called every frame after update)
auto get_context() -> Rml::Context *
Get the main RmlUi context.
static void on_destroy_component(entt::registry &r, entt::entity e)
auto deinit(rtti::context &ctx) -> bool
Deinitializes the UI system with the given context.
void register_component_callbacks(rtti::context &ctx)
Register component creation/destruction callbacks with ECS.
void load_fonts()
Load fonts.