diff --git a/examples/example_hud/gui/main_window.cpp b/examples/example_hud/gui/main_window.cpp index ab34eee..73f0e41 100644 --- a/examples/example_hud/gui/main_window.cpp +++ b/examples/example_hud/gui/main_window.cpp @@ -109,6 +109,7 @@ namespace imgui_desktop::gui ImGui::ColorEdit4("BG##bar", reinterpret_cast(&m_bar_bg_color), ImGuiColorEditFlags_NoInputs); ImGui::ColorEdit4("Outline##bar", reinterpret_cast(&m_bar_outline_color), ImGuiColorEditFlags_NoInputs); + ImGui::Checkbox("Gradient bars", &m_gradient_bars); ImGui::SliderFloat("Width##bar", &m_bar_width, 1.f, 20.f); ImGui::SliderFloat("Value##bar", &m_bar_value, 0.f, 1.f); ImGui::SliderFloat("Offset##bar", &m_bar_offset, 1.f, 20.f); @@ -211,7 +212,6 @@ namespace imgui_desktop::gui using namespace omath::hud::widget; using omath::hud::when; const auto* vp = ImGui::GetMainViewport(); - const Bar bar{m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_offset}; const DashedBar dbar{m_bar_color, m_bar_outline_color, m_bar_bg_color, m_bar_width, m_bar_value, m_bar_dash_len, m_bar_dash_gap, m_bar_offset}; const auto animated_color = [&](const omath::Color& color, const float hue_offset) @@ -226,15 +226,27 @@ namespace imgui_desktop::gui }; const auto box_gradient_top = animated_color(m_box_gradient_top, 0.f); const auto box_gradient_bottom = animated_color(m_box_gradient_bottom, 0.5f); - const auto label_gradient_left = animated_color(m_label_gradient_left, 0.f); - const auto label_gradient_right = animated_color(m_label_gradient_right, 0.5f); + const auto red = omath::Color{1.f, 0.f, 0.f, 1.f}; + const auto green = omath::Color{0.f, 1.f, 0.f, 1.f}; + const auto bar_value_color = omath::Color{red.value() * (1.f - m_bar_value) + green.value() * m_bar_value}; + const Paint vertical_bar_color = + m_gradient_bars ? Paint{omath::hud::Gradient{bar_value_color, bar_value_color, red, red}} + : Paint{m_bar_color}; + const Paint horizontal_bar_color = + m_gradient_bars ? Paint{omath::hud::Gradient{red, bar_value_color, bar_value_color, red}} + : Paint{m_bar_color}; + const Bar vertical_bar{vertical_bar_color, m_bar_outline_color, m_bar_bg_color, + m_bar_width, m_bar_value, m_bar_offset}; + const Bar horizontal_bar{horizontal_bar_color, m_bar_outline_color, m_bar_bg_color, + m_bar_width, m_bar_value, m_bar_offset}; const Paint box_fill = m_gradient_box_fill ? Paint{omath::hud::Gradient{box_gradient_top, box_gradient_top, box_gradient_bottom, box_gradient_bottom}} : Paint{m_box_fill}; const Paint centered_label_color = - m_gradient_label ? Paint{omath::hud::Gradient{label_gradient_left, label_gradient_right, - label_gradient_right, label_gradient_left}} + m_gradient_label ? Paint{omath::hud::Gradient{m_label_gradient_left, m_label_gradient_right, + m_label_gradient_right, m_label_gradient_left, + m_animate_gradients}} : Paint{omath::Color::from_rgba(255, 255, 255, 255)}; auto outline_helper = [](const bool is_outline) -> Outlined @@ -250,7 +262,7 @@ namespace imgui_desktop::gui m_box_outline, m_corner_ratio, m_box_thickness}), when(m_show_dashed_box, DashedBox{m_dash_color, m_dash_len, m_dash_gap, m_dash_thickness}), RightSide{ - when(m_show_right_bar, bar), + when(m_show_right_bar, vertical_bar), when(m_show_right_dashed_bar, dbar), when(m_show_right_labels, Label{{0.f, 1.f, 0.f, 1.f}, m_label_offset, @@ -270,7 +282,7 @@ namespace imgui_desktop::gui m_ring_thickness, m_ring_offset}), }, LeftSide{ - when(m_show_left_bar, bar), + when(m_show_left_bar, vertical_bar), when(m_show_left_dashed_bar, dbar), when(m_show_left_labels, Label{omath::Color::from_rgba(255, 128, 0, 255), m_label_offset, @@ -280,7 +292,7 @@ namespace imgui_desktop::gui outline_helper(m_outlined), "Level: 42"}), }, TopSide{ - when(m_show_top_bar, bar), + when(m_show_top_bar, horizontal_bar), when(m_show_top_dashed_bar, dbar), when(m_show_centered_top, Centered{Label{omath::Color::from_rgba(0, 255, 255, 255), m_label_offset, @@ -291,7 +303,7 @@ namespace imgui_desktop::gui outline_helper(m_outlined), "*BLEEDING*"}), }, BottomSide{ - when(m_show_bottom_bar, bar), + when(m_show_bottom_bar, horizontal_bar), when(m_show_bottom_dashed_bar, dbar), when(m_show_centered_bottom, Centered{Label{centered_label_color, m_label_offset, outline_helper(m_outlined), diff --git a/examples/example_hud/gui/main_window.hpp b/examples/example_hud/gui/main_window.hpp index a2bb7a7..153adc6 100644 --- a/examples/example_hud/gui/main_window.hpp +++ b/examples/example_hud/gui/main_window.hpp @@ -47,6 +47,7 @@ namespace imgui_desktop::gui omath::Color m_bar_bg_color{0.f, 0.f, 0.f, 0.5f}; omath::Color m_bar_outline_color{0.f, 0.f, 0.f, 1.f}; float m_bar_width = 4.f, m_bar_value = 0.75f, m_bar_offset = 5.f; + bool m_gradient_bars = true; bool m_show_right_bar = true, m_show_left_bar = true; bool m_show_top_bar = true, m_show_bottom_bar = true; bool m_show_right_dashed_bar = false, m_show_left_dashed_bar = false; diff --git a/include/omath/hud/entity_overlay.hpp b/include/omath/hud/entity_overlay.hpp index 723c895..e2bf608 100644 --- a/include/omath/hud/entity_overlay.hpp +++ b/include/omath/hud/entity_overlay.hpp @@ -41,16 +41,16 @@ namespace omath::hud float thickness = 1.f); // ── Bars ───────────────────────────────────────────────────────── - EntityOverlay& add_right_bar(const Color& color, const Color& outline_color, const Color& bg_color, float width, - float ratio, float offset = 5.f); + EntityOverlay& add_right_bar(const widget::Paint& color, const Color& outline_color, const Color& bg_color, + float width, float ratio, float offset = 5.f); - EntityOverlay& add_left_bar(const Color& color, const Color& outline_color, const Color& bg_color, float width, - float ratio, float offset = 5.f); + EntityOverlay& add_left_bar(const widget::Paint& color, const Color& outline_color, const Color& bg_color, + float width, float ratio, float offset = 5.f); - EntityOverlay& add_top_bar(const Color& color, const Color& outline_color, const Color& bg_color, float height, - float ratio, float offset = 5.f); + EntityOverlay& add_top_bar(const widget::Paint& color, const Color& outline_color, const Color& bg_color, + float height, float ratio, float offset = 5.f); - EntityOverlay& add_bottom_bar(const Color& color, const Color& outline_color, const Color& bg_color, + EntityOverlay& add_bottom_bar(const widget::Paint& color, const Color& outline_color, const Color& bg_color, float height, float ratio, float offset = 5.f); EntityOverlay& add_right_dashed_bar(const Color& color, const Color& outline_color, const Color& bg_color, @@ -254,6 +254,8 @@ namespace omath::hud void draw_progress_ring(const Vector2& center, const widget::ProgressRing& ring); void draw_label(const Vector2& position, const widget::Paint& paint, widget::Outlined outlined, const std::string_view& text); + void draw_filled_rectangle(const Vector2& min, const Vector2& max, + const widget::Paint& paint) const; void draw_dashed_line(const Vector2& from, const Vector2& to, const Color& color, float dash_len, float gap_len, float thickness) const; void draw_dashed_fill(const Vector2& origin, const Vector2& step_dir, diff --git a/include/omath/hud/entity_overlay_widgets.hpp b/include/omath/hud/entity_overlay_widgets.hpp index 3d2d4fd..aefb2ef 100644 --- a/include/omath/hud/entity_overlay_widgets.hpp +++ b/include/omath/hud/entity_overlay_widgets.hpp @@ -108,7 +108,7 @@ namespace omath::hud::widget /// A filled bar. `size` is width for left/right sides, height for top/bottom. struct Bar { - Color color; + Paint color; Color outline; Color bg; float size; diff --git a/include/omath/hud/gradient.hpp b/include/omath/hud/gradient.hpp index 419dbc9..60665a3 100644 --- a/include/omath/hud/gradient.hpp +++ b/include/omath/hud/gradient.hpp @@ -9,5 +9,8 @@ namespace omath::hud Color top_right; Color bottom_right; Color bottom_left; + bool animated = false; + float animation_speed = 4.f; + float animation_spread = 0.7f; }; } // namespace omath::hud diff --git a/source/hud/entity_overlay.cpp b/source/hud/entity_overlay.cpp index 98d570a..b33c534 100644 --- a/source/hud/entity_overlay.cpp +++ b/source/hud/entity_overlay.cpp @@ -76,8 +76,9 @@ namespace omath::hud return *this; } - EntityOverlay& EntityOverlay::add_right_bar(const Color& color, const Color& outline_color, const Color& bg_color, - const float width, float ratio, const float offset) + EntityOverlay& EntityOverlay::add_right_bar(const widget::Paint& color, const Color& outline_color, + const Color& bg_color, const float width, float ratio, + const float offset) { ratio = std::clamp(ratio, 0.f, 1.f); const auto max_bar_height = std::abs(m_canvas.top_right_corner.y - m_canvas.bottom_right_corner.y); @@ -85,7 +86,7 @@ namespace omath::hud const auto bar_start = Vector2{m_text_cursor_right.x + offset, m_canvas.bottom_right_corner.y}; m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height), bg_color); - m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height * ratio), color); + draw_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height * ratio), color); m_renderer->add_rectangle(bar_start - Vector2(1.f, 0.f), bar_start + Vector2(width, -max_bar_height), outline_color); @@ -93,8 +94,9 @@ namespace omath::hud return *this; } - EntityOverlay& EntityOverlay::add_left_bar(const Color& color, const Color& outline_color, const Color& bg_color, - const float width, float ratio, const float offset) + EntityOverlay& EntityOverlay::add_left_bar(const widget::Paint& color, const Color& outline_color, + const Color& bg_color, const float width, float ratio, + const float offset) { ratio = std::clamp(ratio, 0.f, 1.f); const auto max_bar_height = std::abs(m_canvas.top_left_corner.y - m_canvas.bottom_right_corner.y); @@ -102,7 +104,7 @@ namespace omath::hud const auto bar_start = Vector2{m_text_cursor_left.x - (offset + width), m_canvas.bottom_left_corner.y}; m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height), bg_color); - m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height * ratio), color); + draw_filled_rectangle(bar_start, bar_start + Vector2(width, -max_bar_height * ratio), color); m_renderer->add_rectangle(bar_start - Vector2(1.f, 0.f), bar_start + Vector2(width, -max_bar_height), outline_color); @@ -128,8 +130,9 @@ namespace omath::hud return *this; } - EntityOverlay& EntityOverlay::add_top_bar(const Color& color, const Color& outline_color, const Color& bg_color, - const float height, float ratio, const float offset) + EntityOverlay& EntityOverlay::add_top_bar(const widget::Paint& color, const Color& outline_color, + const Color& bg_color, const float height, float ratio, + const float offset) { ratio = std::clamp(ratio, 0.f, 1.f); const auto max_bar_width = std::abs(m_canvas.top_left_corner.x - m_canvas.bottom_right_corner.x); @@ -137,7 +140,7 @@ namespace omath::hud const auto bar_start = Vector2{m_canvas.top_left_corner.x, m_text_cursor_top.y - offset}; m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width, -height), bg_color); - m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width * ratio, -height), color); + draw_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width * ratio, -height), color); m_renderer->add_rectangle(bar_start, bar_start + Vector2(max_bar_width, -height), outline_color); m_text_cursor_top.y -= offset + height; @@ -397,15 +400,35 @@ namespace omath::hud }, paint); } - EntityOverlay& EntityOverlay::add_bottom_bar(const Color& color, const Color& outline_color, const Color& bg_color, - const float height, float ratio, const float offset) + + void EntityOverlay::draw_filled_rectangle(const Vector2& min, const Vector2& max, + const widget::Paint& paint) const + { + const Vector2 top_left{std::min(min.x, max.x), std::min(min.y, max.y)}; + const Vector2 bottom_right{std::max(min.x, max.x), std::max(min.y, max.y)}; + std::visit( + widget::Overloaded{ + [&](const Color& color) + { + m_renderer->add_filled_rectangle(top_left, bottom_right, color); + }, + [&](const Gradient& gradient) + { + m_renderer->add_gradient_rectangle(top_left, bottom_right, gradient); + }, + }, + paint); + } + EntityOverlay& EntityOverlay::add_bottom_bar(const widget::Paint& color, const Color& outline_color, + const Color& bg_color, const float height, float ratio, + const float offset) { ratio = std::clamp(ratio, 0.f, 1.f); const auto max_bar_width = std::abs(m_canvas.bottom_right_corner.x - m_canvas.bottom_left_corner.x); const auto bar_start = Vector2{m_canvas.bottom_left_corner.x, m_text_cursor_bottom.y + offset}; m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width, height), bg_color); - m_renderer->add_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width * ratio, height), color); + draw_filled_rectangle(bar_start, bar_start + Vector2(max_bar_width * ratio, height), color); m_renderer->add_rectangle(bar_start, bar_start + Vector2(max_bar_width, height), outline_color); m_text_cursor_bottom.y += offset + height; diff --git a/source/hud/renderer_realizations/imgui_renderer.cpp b/source/hud/renderer_realizations/imgui_renderer.cpp index 4e08dc9..65e15b3 100644 --- a/source/hud/renderer_realizations/imgui_renderer.cpp +++ b/source/hud/renderer_realizations/imgui_renderer.cpp @@ -4,7 +4,9 @@ #include "omath/hud/renderer_realizations/imgui_renderer.hpp" #ifdef OMATH_IMGUI_INTEGRATION +#include #include +#include namespace omath::hud { @@ -87,6 +89,34 @@ namespace omath::hud const std::string_view& text) { auto* draw_list = ImGui::GetBackgroundDrawList(); + if (gradient.animated) + { + const float animation_offset = static_cast(ImGui::GetTime()) * gradient.animation_speed; + float cursor_x = position.x; + const char* glyph_start = text.data(); + const char* const text_end = text.data() + text.size(); + int glyph_index = 0; + while (glyph_start < text_end) + { + unsigned int codepoint; + const int glyph_size = ImTextCharFromUtf8(&codepoint, glyph_start, text_end); + if (glyph_size <= 0) + break; + static_cast(codepoint); + + const char* const glyph_end = glyph_start + glyph_size; + const float blend = + (std::sin(animation_offset + static_cast(glyph_index) * gradient.animation_spread) + 1.f) + * 0.5f; + const auto color = gradient.top_left.value() * (1.f - blend) + gradient.top_right.value() * blend; + draw_list->AddText({cursor_x, position.y}, Color{color}.to_im_color(), glyph_start, glyph_end); + cursor_x += ImGui::CalcTextSize(glyph_start, glyph_end).x; + glyph_start = glyph_end; + ++glyph_index; + } + return; + } + const int vertex_start = draw_list->VtxBuffer.Size; draw_list->AddText(position.to_im_vec2(), IM_COL32_WHITE, text.data(), text.data() + text.size());