3#include "imgui/imgui.h"
4#include "imgui_widgets/utils.h"
25constexpr ImVec4 memory_label_color{0.42f, 0.42f, 0.42f, 1.0f};
26constexpr ImVec4 memory_value_color{0.50f, 0.50f, 0.50f, 1.0f};
27constexpr ImU32 gpu_bar_color = IM_COL32(58, 121, 187, 165);
28constexpr ImU32 other_system_ram_bar_color = IM_COL32(145, 118, 72, 210);
29constexpr ImU32 process_ram_bar_color = IM_COL32(88, 168, 196, 220);
30constexpr ImU32 memory_bar_track_color = IM_COL32(32, 32, 32, 255);
31constexpr float memory_bar_height = 3.0f;
32constexpr float memory_section_alpha = 0.92f;
34void draw_memory_bar(
float fraction, ImU32 fill_color)
37 const float bar_width = ImGui::GetContentRegionAvail().x;
38 const ImVec2 bar_pos = ImGui::GetCursorScreenPos();
39 ImDrawList* draw_list = ImGui::GetWindowDrawList();
41 draw_list->AddRectFilled(bar_pos,
42 ImVec2(bar_pos.x + bar_width, bar_pos.y + memory_bar_height),
43 memory_bar_track_color,
44 memory_bar_height * 0.5f);
48 draw_list->AddRectFilled(bar_pos,
49 ImVec2(bar_pos.x + bar_width *
fraction, bar_pos.y + memory_bar_height),
51 memory_bar_height * 0.5f);
54 ImGui::Dummy(ImVec2(bar_width, memory_bar_height));
57void draw_stacked_ram_bar(
float process_fraction,
float system_used_fraction)
59 process_fraction = std::clamp(process_fraction, 0.0f, 1.0f);
60 system_used_fraction = std::clamp(system_used_fraction, process_fraction, 1.0f);
61 const float other_used_fraction = system_used_fraction - process_fraction;
63 const float bar_width = ImGui::GetContentRegionAvail().x;
64 const ImVec2 bar_pos = ImGui::GetCursorScreenPos();
65 ImDrawList* draw_list = ImGui::GetWindowDrawList();
66 const float bar_radius = memory_bar_height * 0.5f;
67 const float bar_bottom = bar_pos.y + memory_bar_height;
68 const ImVec2 bar_max(bar_pos.x + bar_width, bar_bottom);
71 draw_list->AddRectFilled(bar_pos, bar_max, memory_bar_track_color, bar_radius);
82 float segment_width = bar_width *
fraction;
83 if(segment_width > 0.0f && segment_width < 1.0f)
88 draw_list->AddRectFilled(ImVec2(
x, bar_pos.y),
89 ImVec2(
x + segment_width, bar_bottom),
95 draw_segment(other_used_fraction, other_system_ram_bar_color);
96 draw_segment(process_fraction, process_ram_bar_color);
98 ImGui::Dummy(ImVec2(bar_width, memory_bar_height));
101void draw_memory_stat_row(
const char* label,
const std::string& value_text,
const char*
tooltip =
nullptr)
103 ImGui::PushStyleColor(ImGuiCol_Text, memory_label_color);
104 ImGui::TextUnformatted(label);
105 ImGui::PopStyleColor();
108 ImGui::SetItemTooltipEx(
"%s",
tooltip);
111 const float value_width = ImGui::CalcTextSize(value_text.c_str()).x;
112 ImGui::PushStyleColor(ImGuiCol_Text, memory_value_color);
113 ImGui::AlignedItem(1.0f, ImGui::GetContentRegionAvail().
x, value_width, [&]() ->
void {
114 ImGui::TextUnformatted(value_text.c_str());
116 ImGui::PopStyleColor();
119void draw_loading_memory_stats()
122 if(stats !=
nullptr &&
stats->gpuMemoryUsed > 0)
124 std::string gpu_text;
125 float gpu_fraction = 0.0f;
127 if(
stats->gpuMemoryMax > 0)
129 const float pct = (
static_cast<float>(
stats->gpuMemoryUsed) /
130 static_cast<float>(
stats->gpuMemoryMax)) *
132 gpu_text = fmt::format(
"{} / {} ({:.0f}%)",
135 static_cast<double>(pct));
136 gpu_fraction = pct / 100.0f;
143 draw_memory_stat_row(
"GPU",
145 "GPU video memory allocated by the renderer vs the device budget.");
146 if(
stats->gpuMemoryMax > 0)
148 draw_memory_bar(gpu_fraction, gpu_bar_color);
155 if(rss_bytes > 0 || system_used_bytes > 0)
157 if(stats !=
nullptr &&
stats->gpuMemoryUsed > 0)
162 if(system_total_bytes > 0 && system_used_bytes > 0)
164 const int64_t other_used_bytes = std::max<int64_t>(0, system_used_bytes - rss_bytes);
165 const float system_pct =
166 (
static_cast<float>(system_used_bytes) /
static_cast<float>(system_total_bytes)) * 100.0f;
167 const float process_pct =
168 (
static_cast<float>(rss_bytes) /
static_cast<float>(system_total_bytes)) * 100.0f;
170 std::string ram_text;
173 ram_text = fmt::format(
"{} ({} Process) / {}",
180 ram_text = fmt::format(
"{} / {}",
185 const std::string ram_tooltip = fmt::format(
186 "Bar = total system RAM.\n"
187 "Amber: other system usage. Cyan (at the used edge): this process.\n"
188 "Dark: free memory.\n"
189 "Used: {:.0f}% of system ({} other + {} process).",
190 static_cast<double>(system_pct),
194 draw_memory_stat_row(
"RAM", ram_text, ram_tooltip.c_str());
195 draw_stacked_ram_bar(process_pct / 100.0f, system_pct / 100.0f);
197 else if(rss_bytes > 0)
199 draw_memory_stat_row(
"RAM",
format_bytes(rss_bytes),
"Process resident memory (RSS).");
204auto has_loading_memory_stats() ->
bool
207 if(stats !=
nullptr &&
stats->gpuMemoryUsed > 0)
224 ev.
on_os_event.connect(sentinel_, 1000,
this, &imgui_interface::on_os_event);
225 ev.on_frame_render.connect(sentinel_, -100000,
this, &imgui_interface::on_frame_ui_render);
238 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
240 const auto& rend = ctx.get_cached<
renderer>();
252 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
260 APPLOG_TRACE(
"{}::{}", hpp::type_name_str(*
this), __func__);
266 const std::string& stage,
269 const std::string& current_job)
273 auto now = std::chrono::steady_clock::now();
274 auto dt = now - last_frame_time_;
276 if(dt < std::chrono::milliseconds(32) && completed != total)
281 last_frame_time_ = now;
291 while(os::poll_event(e))
296 auto& present_pass = window->begin_present_pass();
297 present_pass.clear();
299 for(
int i = 0; i < 1; ++i)
302 draw_loading_overlay(stage, completed, total, current_job);
304 auto& main_surface = window->get_surface();
306 pass.
bind(main_surface.get());
316void imgui_interface::draw_loading_overlay(
const std::string& stage,
319 const std::string& current_job)
321 const auto* viewport = ImGui::GetMainViewport();
324 ImGui::SetNextWindowPos(viewport->WorkPos);
325 ImGui::SetNextWindowSize(viewport->WorkSize);
326 ImGui::SetNextWindowViewport(viewport->ID);
327 ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
328 ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f);
329 ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0.08f, 0.08f, 0.08f, 1.0f));
331 ImGuiWindowFlags backdrop_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse |
332 ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove |
333 ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus |
334 ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoSavedSettings;
336 ImGui::Begin(
"##loading_backdrop",
nullptr, backdrop_flags);
337 ImGui::PopStyleVar(2);
338 ImGui::PopStyleColor();
341 constexpr float card_width = 480.0f;
342 float card_x = viewport->WorkPos.x + (viewport->WorkSize.x - card_width) * 0.5f;
343 float card_y = viewport->WorkPos.y + viewport->WorkSize.y * 0.38f;
344 ImGui::SetNextWindowPos(ImVec2(card_x, card_y));
346 ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 10.0f);
347 ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(32.0f, 28.0f));
348 ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0.16f, 0.16f, 0.16f, 1.0f));
349 ImGui::PushStyleColor(ImGuiCol_Border, ImVec4(0.22f, 0.22f, 0.22f, 1.0f));
351 if(ImGui::BeginChild(
"##loading_card", ImVec2(card_width, 0),
352 ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysUseWindowPadding))
356 auto title_text =
"Unravel Engine";
357 float title_width = ImGui::CalcTextSize(title_text).x;
359 ImGui::AlignedItem(0.5f, ImGui::GetContentRegionAvail().
x, title_width, [&]()
361 ImGui::TextUnformatted(title_text);
370 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(0.25f, 0.25f, 0.25f, 1.0f));
372 ImGui::PopStyleColor();
380 ImGui::TextUnformatted(stage.c_str());
382 auto spinner_size = ImGui::GetTextLineHeight();
385 ImGui::AlignedItem(1.0f, ImGui::GetContentRegionAvail().
x, spinner_size, [&]() {
386 ImSpinner::Spinner<ImSpinner::SpinnerTypeT::e_st_eclipse>(
"spinner",
387 ImSpinner::Radius{spinner_size * 0.5f},
388 ImSpinner::Thickness{4.0f},
389 ImSpinner::Color{ImSpinner::white},
390 ImSpinner::Speed{6.0f});
398 float fraction = (total > 0) ?
static_cast<float>(completed) /
static_cast<float>(total) : 0.0f;
399 constexpr float bar_height = 6.0f;
400 float bar_width = ImGui::GetContentRegionAvail().x;
401 ImVec2 bar_pos = ImGui::GetCursorScreenPos();
403 ImDrawList* draw_list = ImGui::GetWindowDrawList();
406 draw_list->AddRectFilled(bar_pos,
407 ImVec2(bar_pos.x + bar_width, bar_pos.y + bar_height),
408 IM_COL32(30, 30, 30, 255),
414 float fill_width = bar_width *
fraction;
415 draw_list->AddRectFilled(bar_pos,
416 ImVec2(bar_pos.x + fill_width, bar_pos.y + bar_height),
417 IM_COL32(58, 121, 187, 255),
421 ImGui::Dummy(ImVec2(bar_width, bar_height));
427 if(!current_job.empty())
429 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.45f, 0.45f, 0.45f, 1.0f));
430 ImGui::TextWrapped(
"%s", current_job.c_str());
431 ImGui::PopStyleColor();
438 auto progress_text = fmt::format(
"{} / {}", completed, total);
439 float count_width = ImGui::CalcTextSize(progress_text.c_str()).x;
440 ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.55f, 0.55f, 0.55f, 1.0f));
441 ImGui::AlignedItem(1.0f, ImGui::GetContentRegionAvail().
x, count_width, [&]() {
442 ImGui::TextUnformatted(progress_text.c_str());
444 ImGui::PopStyleColor();
451 if(has_loading_memory_stats())
453 ImGui::PushStyleColor(ImGuiCol_Separator, ImVec4(0.22f, 0.22f, 0.22f, 1.0f));
455 ImGui::PopStyleColor();
460 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, memory_section_alpha);
461 draw_loading_memory_stats();
462 ImGui::PopStyleVar();
468 ImGui::PopStyleColor(2);
469 ImGui::PopStyleVar(2);
474void imgui_interface::on_os_event(
rtti::context& ctx, os::event& e)
483 const auto& rend = ctx.
get_cached<renderer>();
484 const auto& main_window = rend.get_main_window();
485 const auto& main_surface = main_window->get_surface();
490 ev.on_frame_ui_render(ctx, dt);
493 pass.bind(main_surface.get());
void render_loading_frame(rtti::context &ctx, const std::string &stage, size_t completed, size_t total, const std::string ¤t_job={})
imgui_interface(rtti::context &ctx)
auto deinit(rtti::context &ctx) -> bool
auto init_finalize(rtti::context &ctx) -> bool
Phase 2: creates the cubemap shader program from compiled editor:/ assets.
auto init_basic(rtti::context &ctx) -> bool
Phase 1: creates ImGui context, embedded shaders, fonts. No asset dependencies.
std::chrono::duration< float > delta_t
void imguiCreate(unravel::render_window *window, float _fontSize, bx::AllocatorI *_allocator)
void imguiProcessEvent(os::event &e)
void imguiBeginFrame(float dt)
void imguiEndFrame(gfx::view_id id)
void imguiCreateCubemapProgram()
#define APPLOG_TRACE(...)
void PushFont(Font::Enum _font)
uint32_t frame(uint8_t _flags)
const stats * get_stats()
auto format_bytes(std::uint64_t bytes, std::uint8_t num_frac) -> std::string
std::vector< math::color > color
#define APP_SCOPE_PERF(name_literal)
Create a scoped performance timer that records to the timeline profiler. Only accepts string literals...
static auto get_max_pass_id() -> gfx::view_id
void bind(const frame_buffer *fb=nullptr) const
hpp::event< void(rtti::context &, os::event &e)> on_os_event
os events
auto get_main_window() const -> render_window *