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();
196 if(
event.type == os::events::mouse_button ||
event.type == os::events::mouse_motion)
198 auto hover_element = ui_context_->GetHoverElement();
199 if(!is_root_element(ctx, hover_element))
206 if(
event.type == os::events::key_down)
208 if(
event.key.code == os::key::code::f2)
210 bool new_visible = !Rml::Debugger::IsVisible();
211 Rml::Debugger::SetVisible(new_visible);
215 if(
event.type == os::events::display_content_scale_changed)
224 if(
event.type == os::events::window)
226 if(
event.window.type == os::window_event_id::size_changed)
236auto ui_system::is_root_element(
rtti::context& ctx, Rml::Element* element) ->
bool
248 if(element->GetTagName() ==
"#root")
253 auto& ecs_system = ctx.get_cached<ecs>();
254 auto& scene = ecs_system.get_scene();
255 auto& registry = *scene.registry;
258 auto view = registry.view<ui_document_component>();
262 auto& ui_comp = view.get<ui_document_component>(
entity);
263 if(ui_comp.document == element)
279 auto load_font = [&](
const std::string& path) ->
void
282 Rml::LoadFontFace(font_path,
false);
286 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Thin.ttf");
287 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ThinItalic.ttf");
288 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraLight.ttf");
289 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraLightItalic.ttf");
290 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Light.ttf");
291 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-LightItalic.ttf");
292 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Regular.ttf");
293 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Italic.ttf");
294 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Medium.ttf");
295 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-MediumItalic.ttf");
296 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-SemiBold.ttf");
297 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-SemiBoldItalic.ttf");
298 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Bold.ttf");
299 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-BoldItalic.ttf");
300 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraBold.ttf");
301 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-ExtraBoldItalic.ttf");
302 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-Black.ttf");
303 load_font(
"engine:/data/fonts/Inter/static/28pt/Inter-BlackItalic.ttf");
314 if(component.document)
316 component.document->Close();
317 component.document =
nullptr;
329void ui_system::update_ui_document_components(
rtti::context& ctx)
344 auto mouse_delta_x =
input.manager.get_mouse().get_axis_value(0);
345 auto mouse_delta_y =
input.manager.get_mouse().get_axis_value(1);
347 if(math::epsilonNotEqual(mouse_delta_x, 0.0f, math::epsilon<float>()) || math::epsilonNotEqual(mouse_delta_y, 0.0f, math::epsilon<float>()))
349 auto mouse_x =
input.manager.get_mouse().get_position().x;
350 auto mouse_y =
input.manager.get_mouse().get_position().y;
351 ui_context_->ProcessMouseMove(mouse_x, mouse_y, 0);
357 auto& scene = ecs_system.get_scene();
358 auto& registry = *scene.registry;
360 registry.view<camera_component>().each(
361 [&](
auto e,
auto&& camera)
363 auto viewport = camera.get_viewport_size();
365 ui_context_->SetDimensions(Rml::Vector2i(viewport.width, viewport.height));
371 auto view = registry.view<ui_document_component>();
375 auto& ui_comp = view.get<ui_document_component>(
entity);
377 bool active = registry.all_of<active_component>(
entity);
381 if(ui_comp.version != ui_comp.asset.version())
385 ui_comp.document->Close();
386 ui_comp.document =
nullptr;
398 if(!ui_comp.is_loaded())
400 load_ui_document(ui_comp);
403 if(!ui_comp.document)
408 bool active_and_enabled = active && ui_comp.is_enabled();
409 if(active_and_enabled)
411 if(!ui_comp.document->IsVisible())
413 ui_comp.document->Show();
418 if( ui_comp.document->IsVisible())
420 ui_comp.document->Hide();
427auto ui_system::load_ui_document(ui_document_component& component) ->
bool
431 APPLOG_ERROR(
"Cannot load UI document: RmlUi context not available");
435 auto asset = component.asset.get();
446 Rml::String url_safe_path = Rml::StringUtilities::Replace(real.string(),
':',
'|');
449 auto raw_document = ui_context_->LoadDocumentFromMemory(asset->content, url_safe_path);
452 APPLOG_ERROR(
"Failed to load UI document: {}", component.asset.id());
455 raw_document->ReloadStyleSheet();
457 raw_document->SetId(
"body");
459 if(component.document)
461 component.document->Close();
464 component.document = raw_document;
465 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.