gradient text + box fill

This commit is contained in:
2026-07-11 18:05:20 +03:00
parent 78d92a3c0f
commit 176f5b2aa1
9 changed files with 233 additions and 87 deletions
+43 -3
View File
@@ -4,6 +4,7 @@
#include "main_window.hpp"
#include "omath/hud/renderer_realizations/imgui_renderer.hpp"
#include <GLFW/glfw3.h>
#include <cmath>
#include <imgui.h>
#include <imgui_impl_glfw.h>
#include <imgui_impl_opengl3.h>
@@ -83,6 +84,15 @@ namespace imgui_desktop::gui
ImGui::Checkbox("Dashed", &m_show_dashed_box);
ImGui::ColorEdit4("Color##box", reinterpret_cast<float*>(&m_box_color), ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Fill##box", reinterpret_cast<float*>(&m_box_fill), ImGuiColorEditFlags_NoInputs);
ImGui::Checkbox("Gradient fill", &m_gradient_box_fill);
ImGui::Checkbox("Animate gradients", &m_animate_gradients);
if (m_gradient_box_fill)
{
ImGui::ColorEdit4("Gradient top##box", reinterpret_cast<float*>(&m_box_gradient_top),
ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Gradient bottom##box", reinterpret_cast<float*>(&m_box_gradient_bottom),
ImGuiColorEditFlags_NoInputs);
}
ImGui::ColorEdit4("Outline##box", reinterpret_cast<float*>(&m_box_outline), ImGuiColorEditFlags_NoInputs);
ImGui::SliderFloat("Thickness", &m_box_thickness, 0.5f, 5.f);
ImGui::SliderFloat("Corner ratio", &m_corner_ratio, 0.05f, 0.5f);
@@ -121,6 +131,14 @@ namespace imgui_desktop::gui
if (ImGui::CollapsingHeader("Labels", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Checkbox("Outlined", &m_outlined);
ImGui::Checkbox("Gradient centered label", &m_gradient_label);
if (m_gradient_label)
{
ImGui::ColorEdit4("Gradient left##lbl", reinterpret_cast<float*>(&m_label_gradient_left),
ImGuiColorEditFlags_NoInputs);
ImGui::ColorEdit4("Gradient right##lbl", reinterpret_cast<float*>(&m_label_gradient_right),
ImGuiColorEditFlags_NoInputs);
}
ImGui::SliderFloat("Offset##lbl", &m_label_offset, 0.f, 15.f);
ImGui::Checkbox("Right##lbl", &m_show_right_labels);
ImGui::SameLine();
@@ -196,6 +214,28 @@ namespace imgui_desktop::gui
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)
{
if (!m_animate_gradients)
return color;
auto hsv = color.to_hsv();
hsv.hue = std::fmod(hsv.hue + static_cast<float>(ImGui::GetTime()) * 0.15f + hue_offset, 1.f);
const auto animated = omath::Color::from_hsv(hsv).value();
return omath::Color{animated.x, animated.y, animated.z, color.value().w};
};
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 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}}
: Paint{omath::Color::from_rgba(255, 255, 255, 255)};
auto outline_helper = [](const bool is_outline) -> Outlined
{
@@ -205,7 +245,7 @@ namespace imgui_desktop::gui
std::make_shared<omath::hud::ImguiHudRenderer>())
.contents(
// ── Boxes ────────────────────────────────────────────────────
when(m_show_box, Box{m_box_color, m_box_fill, m_box_outline, m_box_thickness}),
when(m_show_box, Box{m_box_color, box_fill, m_box_outline, m_box_thickness}),
when(m_show_cornered_box, CorneredBox{omath::Color::from_rgba(255, 0, 255, 255), m_box_fill,
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}),
@@ -254,8 +294,8 @@ namespace imgui_desktop::gui
when(m_show_bottom_bar, bar),
when(m_show_bottom_dashed_bar, dbar),
when(m_show_centered_bottom,
Centered{Label{omath::Color::from_rgba(255, 255, 255, 255), m_label_offset,
outline_helper(m_outlined), "PlayerName"}}),
Centered{Label{centered_label_color, m_label_offset, outline_helper(m_outlined),
"Gradient PlayerName"}}),
when(m_show_bottom_labels, Label{omath::Color::from_rgba(200, 200, 0, 255),
m_label_offset, outline_helper(m_outlined), "42m"}),
},
+11 -4
View File
@@ -30,8 +30,12 @@ namespace imgui_desktop::gui
// Box
omath::Color m_box_color{1.f, 1.f, 1.f, 1.f};
omath::Color m_box_fill{0.f, 0.f, 0.f, 0.f};
omath::Color m_box_gradient_top{0.1f, 0.6f, 1.f, 0.55f};
omath::Color m_box_gradient_bottom{0.7f, 0.1f, 1.f, 0.15f};
omath::Color m_box_outline{0.f, 0.f, 0.f, 0.f};
float m_box_thickness = 1.f, m_corner_ratio = 0.2f;
bool m_gradient_box_fill = true;
bool m_animate_gradients = false;
bool m_show_box = true, m_show_cornered_box = true, m_show_dashed_box = false;
// Dashed box
@@ -43,17 +47,20 @@ 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_show_right_bar = true, m_show_left_bar = true;
bool m_show_top_bar = true, m_show_bottom_bar = 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;
bool m_show_top_dashed_bar = false, m_show_bottom_dashed_bar = false;
bool m_show_top_dashed_bar = false, m_show_bottom_dashed_bar = false;
float m_bar_dash_len = 6.f, m_bar_dash_gap = 4.f;
// Labels
float m_label_offset = 3.f;
omath::Color m_label_gradient_left{0.f, 0.8f, 1.f, 1.f};
omath::Color m_label_gradient_right{1.f, 0.2f, 0.7f, 1.f};
bool m_outlined = true;
bool m_gradient_label = true;
bool m_show_right_labels = true, m_show_left_labels = true;
bool m_show_top_labels = true, m_show_bottom_labels = true;
bool m_show_top_labels = true, m_show_bottom_labels = true;
bool m_show_centered_top = true, m_show_centered_bottom = true;
// Skeleton
+25 -14
View File
@@ -30,6 +30,9 @@ namespace omath::hud
EntityOverlay& add_2d_box(const Color& box_color, const Color& fill_color = Color{0.f, 0.f, 0.f, 0.f},
const Color& outline_color = Color{0.f, 0.f, 0.f, 0.f}, float thickness = 1.f);
EntityOverlay& add_2d_box(const Color& box_color, const Gradient& fill_gradient,
const Color& outline_color = Color{0.f, 0.f, 0.f, 0.f}, float thickness = 1.f);
EntityOverlay& add_cornered_2d_box(const Color& box_color, const Color& fill_color = Color{0.f, 0.f, 0.f, 0.f},
const Color& outline_color = Color{0.f, 0.f, 0.f, 0.f},
float corner_ratio_len = 0.2f, float thickness = 1.f);
@@ -65,26 +68,27 @@ namespace omath::hud
float offset = 5.f);
// ── Labels ───────────────────────────────────────────────────────
EntityOverlay& add_right_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_right_label(const widget::Paint& color, float offset, widget::Outlined outlined,
const std::string_view& text);
EntityOverlay& add_left_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_left_label(const widget::Paint& color, float offset, widget::Outlined outlined,
const std::string_view& text);
EntityOverlay& add_top_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_top_label(const widget::Paint& color, float offset, widget::Outlined outlined,
std::string_view text);
EntityOverlay& add_bottom_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_bottom_label(const widget::Paint& color, float offset, widget::Outlined outlined,
std::string_view text);
EntityOverlay& add_centered_top_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_centered_top_label(const widget::Paint& color, float offset, widget::Outlined outlined,
const std::string_view& text);
EntityOverlay& add_centered_bottom_label(const Color& color, float offset, widget::Outlined outlined,
EntityOverlay& add_centered_bottom_label(const widget::Paint& color, float offset, widget::Outlined outlined,
const std::string_view& text);
template<typename... Args>
EntityOverlay& add_right_label(const Color& color, const float offset, const widget::Outlined outlined,
requires(sizeof...(Args) > 0)
EntityOverlay& add_right_label(const widget::Paint& color, const float offset, const widget::Outlined outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_right_label(color, offset, outlined,
@@ -92,7 +96,8 @@ namespace omath::hud
}
template<typename... Args>
EntityOverlay& add_left_label(const Color& color, const float offset, const widget::Outlined outlined,
requires(sizeof...(Args) > 0)
EntityOverlay& add_left_label(const widget::Paint& color, const float offset, const widget::Outlined outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_left_label(color, offset, outlined,
@@ -100,7 +105,8 @@ namespace omath::hud
}
template<typename... Args>
EntityOverlay& add_top_label(const Color& color, const float offset, const widget::Outlined outlined,
requires(sizeof...(Args) > 0)
EntityOverlay& add_top_label(const widget::Paint& color, const float offset, const widget::Outlined outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_top_label(color, offset, outlined,
@@ -108,7 +114,8 @@ namespace omath::hud
}
template<typename... Args>
EntityOverlay& add_bottom_label(const Color& color, const float offset, const widget::Outlined outlined,
requires(sizeof...(Args) > 0)
EntityOverlay& add_bottom_label(const widget::Paint& color, const float offset, const widget::Outlined outlined,
std::format_string<Args...> fmt, Args&&... args)
{
return add_bottom_label(color, offset, outlined,
@@ -116,15 +123,18 @@ namespace omath::hud
}
template<typename... Args>
EntityOverlay& add_centered_top_label(const Color& color, const float offset, const widget::Outlined outlined,
std::format_string<Args...> fmt, Args&&... args)
requires(sizeof...(Args) > 0)
EntityOverlay& add_centered_top_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, std::format_string<Args...> fmt,
Args&&... args)
{
return add_centered_top_label(color, offset, outlined,
std::string_view{std::vformat(fmt.get(), std::make_format_args(args...))});
}
template<typename... Args>
EntityOverlay& add_centered_bottom_label(const Color& color, const float offset,
requires(sizeof...(Args) > 0)
EntityOverlay& add_centered_bottom_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, std::format_string<Args...> fmt,
Args&&... args)
{
@@ -242,7 +252,8 @@ namespace omath::hud
void dispatch(const widget::AimDot& aim_dot);
void dispatch(const widget::ProjectileAim& proj_widget);
void draw_progress_ring(const Vector2<float>& center, const widget::ProgressRing& ring);
void draw_outlined_text(const Vector2<float>& position, const Color& color, const std::string_view& text);
void draw_label(const Vector2<float>& position, const widget::Paint& paint, widget::Outlined outlined,
const std::string_view& text);
void draw_dashed_line(const Vector2<float>& from, const Vector2<float>& to, const Color& color, float dash_len,
float gap_len, float thickness) const;
void draw_dashed_fill(const Vector2<float>& origin, const Vector2<float>& step_dir,
+15 -5
View File
@@ -2,6 +2,7 @@
// Created by orange on 15.03.2026.
//
#pragma once
#include "gradient.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include "omath/utility/color.hpp"
#include <any>
@@ -12,6 +13,16 @@
namespace omath::hud::widget
{
struct Paint : std::variant<Color, Gradient>
{
using std::variant<Color, Gradient>::variant;
constexpr Paint(const float red, const float green, const float blue, const float alpha)
: std::variant<Color, Gradient>(Color{red, green, blue, alpha})
{
}
};
// ── Overloaded helper for std::visit ──────────────────────────────────────
template<typename... Ts>
struct Overloaded : Ts...
@@ -25,7 +36,7 @@ namespace omath::hud::widget
struct Box
{
Color color;
Color fill{0.f, 0.f, 0.f, 0.f};
Paint fill{Color{0.f, 0.f, 0.f, 0.f}};
Color outline{0.f, 0.f, 0.f, 0.f};
float thickness = 1.f;
};
@@ -92,7 +103,6 @@ namespace omath::hud::widget
Figure figure = Figure::SQUARE;
};
// ── Side-agnostic widgets (used inside XxxSide containers) ────────────────
/// A filled bar. `size` is width for left/right sides, height for top/bottom.
@@ -121,7 +131,7 @@ namespace omath::hud::widget
struct Label
{
Color color;
Paint color;
float offset;
Outlined outlined;
std::string_view text;
@@ -172,8 +182,8 @@ namespace omath::hud::widget
struct None
{
}; ///< No-op placeholder — used by widget::when for disabled elements.
using SideWidget =
std::variant<None, Bar, DashedBar, Label, Centered<Label>, SpaceVertical, SpaceHorizontal, ProgressRing, Icon>;
using SideWidget = std::variant<None, Bar, DashedBar, Label, Centered<Label>, SpaceVertical, SpaceHorizontal,
ProgressRing, Icon>;
// ── Side containers ───────────────────────────────────────────────────────
// Storing std::initializer_list<SideWidget> is safe here: the backing array
+13
View File
@@ -0,0 +1,13 @@
#pragma once
#include "omath/utility/color.hpp"
namespace omath::hud
{
struct Gradient
{
Color top_left;
Color top_right;
Color bottom_right;
Color bottom_left;
};
} // namespace omath::hud
@@ -2,6 +2,7 @@
// Created by orange on 13.03.2026.
//
#pragma once
#include "gradient.hpp"
#include "omath/linear_algebra/vector2.hpp"
#include "omath/utility/color.hpp"
#include <any>
@@ -25,6 +26,12 @@ namespace omath::hud
virtual void add_filled_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) = 0;
virtual void add_gradient_rectangle(const Vector2<float>& min, const Vector2<float>& max,
const Gradient& gradient)
{
add_filled_rectangle(min, max, gradient.top_left);
}
virtual void add_circle(const Vector2<float>& center, float radius, const Color& color, float thickness,
int segments = 0) = 0;
@@ -41,6 +48,12 @@ namespace omath::hud
virtual void add_text(const Vector2<float>& position, const Color& color, const std::string_view& text) = 0;
virtual void add_gradient_text(const Vector2<float>& position, const Gradient& gradient,
const std::string_view& text)
{
add_text(position, gradient.top_left, text);
}
[[nodiscard]]
virtual Vector2<float> calc_text_size(const std::string_view& text) = 0;
};
@@ -13,10 +13,13 @@ namespace omath::hud
~ImguiHudRenderer() override;
void add_line(const Vector2<float>& line_start, const Vector2<float>& line_end, const Color& color,
float thickness) override;
void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color, float thickness) override;
void add_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color,
float thickness) override;
void add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color) override;
void add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
void add_filled_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color) override;
void add_gradient_rectangle(const Vector2<float>& min, const Vector2<float>& max,
const Gradient& gradient) override;
void add_circle(const Vector2<float>& center, float radius, const Color& color, float thickness,
int segments = 0) override;
void add_filled_circle(const Vector2<float>& center, float radius, const Color& color,
@@ -26,8 +29,10 @@ namespace omath::hud
void add_image(const std::any& texture_id, const Vector2<float>& min, const Vector2<float>& max,
const Color& tint = Color{1.f, 1.f, 1.f, 1.f}) override;
void add_text(const Vector2<float>& position, const Color& color, const std::string_view& text) override;
void add_gradient_text(const Vector2<float>& position, const Gradient& gradient,
const std::string_view& text) override;
[[nodiscard]]
Vector2<float> calc_text_size(const std::string_view& text) override;
};
} // namespace omath::hud
#endif // OMATH_IMGUI_INTEGRATION
#endif // OMATH_IMGUI_INTEGRATION
+64 -50
View File
@@ -20,6 +20,20 @@ namespace omath::hud
return *this;
}
EntityOverlay& EntityOverlay::add_2d_box(const Color& box_color, const Gradient& fill_gradient,
const Color& outline_color, const float thickness)
{
const auto points = m_canvas.as_array();
if (outline_color.value().w > 0.f)
m_renderer->add_polyline({points.data(), points.size()}, outline_color, thickness + 2.f);
m_renderer->add_polyline({points.data(), points.size()}, box_color, thickness);
m_renderer->add_gradient_rectangle(m_canvas.top_left_corner, m_canvas.bottom_right_corner, fill_gradient);
return *this;
}
EntityOverlay& EntityOverlay::add_cornered_2d_box(const Color& box_color, const Color& fill_color,
const Color& outline_color, const float corner_ratio_len,
const float thickness)
@@ -38,11 +52,9 @@ namespace omath::hud
};
// Left Side
draw_corner_line(m_canvas.top_left_corner,
m_canvas.top_left_corner + Vector2<float>{corner_line_length, 0.f});
draw_corner_line(m_canvas.top_left_corner, m_canvas.top_left_corner + Vector2<float>{corner_line_length, 0.f});
draw_corner_line(m_canvas.top_left_corner,
m_canvas.top_left_corner + Vector2<float>{0.f, corner_line_length});
draw_corner_line(m_canvas.top_left_corner, m_canvas.top_left_corner + Vector2<float>{0.f, corner_line_length});
draw_corner_line(m_canvas.bottom_left_corner,
m_canvas.bottom_left_corner - Vector2<float>{0.f, corner_line_length});
@@ -98,28 +110,21 @@ namespace omath::hud
return *this;
}
EntityOverlay& EntityOverlay::add_right_label(const Color& color, const float offset,
const widget::Outlined outlined,
const std::string_view& text)
EntityOverlay& EntityOverlay::add_right_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, const std::string_view& text)
{
if (outlined == widget::Outlined::On)
draw_outlined_text(m_text_cursor_right + Vector2<float>{offset, 0.f}, color, text);
else
m_renderer->add_text(m_text_cursor_right + Vector2<float>{offset, 0.f}, color, text.data());
draw_label(m_text_cursor_right + Vector2<float>{offset, 0.f}, color, outlined, text);
m_text_cursor_right.y += m_renderer->calc_text_size(text.data()).y;
return *this;
}
EntityOverlay& EntityOverlay::add_top_label(const Color& color, const float offset, const widget::Outlined outlined,
const std::string_view text)
EntityOverlay& EntityOverlay::add_top_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, const std::string_view text)
{
m_text_cursor_top.y -= m_renderer->calc_text_size(text.data()).y;
if (outlined == widget::Outlined::On)
draw_outlined_text(m_text_cursor_top + Vector2<float>{0.f, -offset}, color, text);
else
m_renderer->add_text(m_text_cursor_top + Vector2<float>{0.f, -offset}, color, text.data());
draw_label(m_text_cursor_top + Vector2<float>{0.f, -offset}, color, outlined, text);
return *this;
}
@@ -366,16 +371,31 @@ namespace omath::hud
return *this;
}
void EntityOverlay::draw_outlined_text(const Vector2<float>& position, const Color& color,
const std::string_view& text)
void EntityOverlay::draw_label(const Vector2<float>& position, const widget::Paint& paint,
const widget::Outlined outlined, const std::string_view& text)
{
static constexpr std::array outline_offsets = {
Vector2<float>{-1, -1}, Vector2<float>{-1, 0}, Vector2<float>{-1, 1}, Vector2<float>{0, -1},
Vector2<float>{0, 1}, Vector2<float>{1, -1}, Vector2<float>{1, 0}, Vector2<float>{1, 1}};
if (outlined == widget::Outlined::On)
{
static constexpr std::array outline_offsets = {
Vector2<float>{-1, -1}, Vector2<float>{-1, 0}, Vector2<float>{-1, 1}, Vector2<float>{0, -1},
Vector2<float>{0, 1}, Vector2<float>{1, -1}, Vector2<float>{1, 0}, Vector2<float>{1, 1}};
for (const auto& outline_offset : outline_offsets)
m_renderer->add_text(position + outline_offset, Color{0.f, 0.f, 0.f, 1.f}, text.data());
m_renderer->add_text(position, color, text.data());
for (const auto& outline_offset : outline_offsets)
m_renderer->add_text(position + outline_offset, Color{0.f, 0.f, 0.f, 1.f}, text);
}
std::visit(
widget::Overloaded{
[&](const Color& color)
{
m_renderer->add_text(position, color, text);
},
[&](const Gradient& gradient)
{
m_renderer->add_gradient_text(position, gradient, text);
},
},
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)
@@ -393,38 +413,33 @@ namespace omath::hud
return *this;
}
EntityOverlay& EntityOverlay::add_bottom_label(const Color& color, const float offset, const widget::Outlined outlined,
const std::string_view text)
EntityOverlay& EntityOverlay::add_bottom_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, const std::string_view text)
{
const auto text_size = m_renderer->calc_text_size(text);
if (outlined == widget::Outlined::On)
draw_outlined_text(m_text_cursor_bottom + Vector2<float>{0.f, offset}, color, text);
else
m_renderer->add_text(m_text_cursor_bottom + Vector2<float>{0.f, offset}, color, text);
draw_label(m_text_cursor_bottom + Vector2<float>{0.f, offset}, color, outlined, text);
m_text_cursor_bottom.y += text_size.y;
return *this;
}
EntityOverlay& EntityOverlay::add_left_label(const Color& color, const float offset, const widget::Outlined outlined,
const std::string_view& text)
EntityOverlay& EntityOverlay::add_left_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, const std::string_view& text)
{
const auto text_size = m_renderer->calc_text_size(text);
const auto pos = m_text_cursor_left + Vector2<float>{-(offset + text_size.x), 0.f};
if (outlined == widget::Outlined::On)
draw_outlined_text(pos, color, text);
else
m_renderer->add_text(pos, color, text);
draw_label(pos, color, outlined, text);
m_text_cursor_left.y += text_size.y;
return *this;
}
EntityOverlay& EntityOverlay::add_centered_bottom_label(const Color& color, const float offset, const widget::Outlined outlined,
EntityOverlay& EntityOverlay::add_centered_bottom_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined,
const std::string_view& text)
{
const auto text_size = m_renderer->calc_text_size(text);
@@ -432,18 +447,15 @@ namespace omath::hud
m_canvas.bottom_left_corner.x + (m_canvas.bottom_right_corner.x - m_canvas.bottom_left_corner.x) / 2.f;
const auto pos = Vector2<float>{box_center_x - text_size.x / 2.f, m_text_cursor_bottom.y + offset};
if (outlined == widget::Outlined::On)
draw_outlined_text(pos, color, text);
else
m_renderer->add_text(pos, color, text);
draw_label(pos, color, outlined, text);
m_text_cursor_bottom.y += text_size.y;
return *this;
}
EntityOverlay& EntityOverlay::add_centered_top_label(const Color& color, const float offset, const widget::Outlined outlined,
const std::string_view& text)
EntityOverlay& EntityOverlay::add_centered_top_label(const widget::Paint& color, const float offset,
const widget::Outlined outlined, const std::string_view& text)
{
const auto text_size = m_renderer->calc_text_size(text);
const auto box_center_x =
@@ -452,10 +464,7 @@ namespace omath::hud
m_text_cursor_top.y -= text_size.y;
const auto pos = Vector2<float>{box_center_x - text_size.x / 2.f, m_text_cursor_top.y - offset};
if (outlined == widget::Outlined::On)
draw_outlined_text(pos, color, text);
else
m_renderer->add_text(pos, color, text);
draw_label(pos, color, outlined, text);
return *this;
}
@@ -601,7 +610,12 @@ namespace omath::hud
// ── widget dispatch ───────────────────────────────────────────────────────
void EntityOverlay::dispatch(const widget::Box& box)
{
add_2d_box(box.color, box.fill, box.outline, box.thickness);
std::visit(
[&](const auto& fill)
{
add_2d_box(box.color, fill, box.outline, box.thickness);
},
box.fill);
}
void EntityOverlay::dispatch(const widget::CorneredBox& cornered_box)
@@ -878,4 +892,4 @@ namespace omath::hud
child);
}
} // namespace omath::hud
} // namespace omath::hud
@@ -28,7 +28,7 @@ namespace omath::hud
void ImguiHudRenderer::add_filled_polyline(const std::span<const Vector2<float>>& vertexes, const Color& color)
{
ImGui::GetBackgroundDrawList()->AddConvexPolyFilled(reinterpret_cast<const ImVec2*>(vertexes.data()),
static_cast<int>(vertexes.size()), color.to_im_color());
static_cast<int>(vertexes.size()), color.to_im_color());
}
void ImguiHudRenderer::add_rectangle(const Vector2<float>& min, const Vector2<float>& max, const Color& color)
@@ -42,30 +42,39 @@ namespace omath::hud
ImGui::GetBackgroundDrawList()->AddRectFilled(min.to_im_vec2(), max.to_im_vec2(), color.to_im_color());
}
void ImguiHudRenderer::add_circle(const Vector2<float>& center, const float radius, const Color& color,
const float thickness, const int segments)
void ImguiHudRenderer::add_gradient_rectangle(const Vector2<float>& min, const Vector2<float>& max,
const Gradient& gradient)
{
ImGui::GetBackgroundDrawList()->AddCircle(center.to_im_vec2(), radius, color.to_im_color(), segments, thickness);
ImGui::GetBackgroundDrawList()->AddRectFilledMultiColor(
min.to_im_vec2(), max.to_im_vec2(), gradient.top_left.to_im_color(), gradient.top_right.to_im_color(),
gradient.bottom_right.to_im_color(), gradient.bottom_left.to_im_color());
}
void ImguiHudRenderer::add_circle(const Vector2<float>& center, const float radius, const Color& color,
const float thickness, const int segments)
{
ImGui::GetBackgroundDrawList()->AddCircle(center.to_im_vec2(), radius, color.to_im_color(), segments,
thickness);
}
void ImguiHudRenderer::add_filled_circle(const Vector2<float>& center, const float radius, const Color& color,
const int segments)
const int segments)
{
ImGui::GetBackgroundDrawList()->AddCircleFilled(center.to_im_vec2(), radius, color.to_im_color(), segments);
}
void ImguiHudRenderer::add_arc(const Vector2<float>& center, const float radius, const float a_min, const float a_max,
const Color& color, const float thickness, const int segments)
void ImguiHudRenderer::add_arc(const Vector2<float>& center, const float radius, const float a_min,
const float a_max, const Color& color, const float thickness, const int segments)
{
ImGui::GetBackgroundDrawList()->PathArcTo(center.to_im_vec2(), radius, a_min, a_max, segments);
ImGui::GetBackgroundDrawList()->PathStroke(color.to_im_color(), ImDrawFlags_None, thickness);
}
void ImguiHudRenderer::add_image(const std::any& texture_id, const Vector2<float>& min, const Vector2<float>& max,
const Color& tint)
const Color& tint)
{
ImGui::GetBackgroundDrawList()->AddImage(std::any_cast<ImTextureID>(texture_id), min.to_im_vec2(),
max.to_im_vec2(), {0, 0}, {1, 1}, tint.to_im_color());
max.to_im_vec2(), {0, 0}, {1, 1}, tint.to_im_color());
}
void ImguiHudRenderer::add_text(const Vector2<float>& position, const Color& color, const std::string_view& text)
@@ -73,6 +82,30 @@ namespace omath::hud
ImGui::GetBackgroundDrawList()->AddText(position.to_im_vec2(), color.to_im_color(), text.data(),
text.data() + text.size());
}
void ImguiHudRenderer::add_gradient_text(const Vector2<float>& position, const Gradient& gradient,
const std::string_view& text)
{
auto* draw_list = ImGui::GetBackgroundDrawList();
const int vertex_start = draw_list->VtxBuffer.Size;
draw_list->AddText(position.to_im_vec2(), IM_COL32_WHITE, text.data(), text.data() + text.size());
const auto size = calc_text_size(text);
const float width = std::max(size.x, 1.f);
const float height = std::max(size.y, 1.f);
for (int i = vertex_start; i < draw_list->VtxBuffer.Size; ++i)
{
auto& vertex = draw_list->VtxBuffer[i];
const float x = std::clamp((vertex.pos.x - position.x) / width, 0.f, 1.f);
const float y = std::clamp((vertex.pos.y - position.y) / height, 0.f, 1.f);
const auto top = gradient.top_left.value() * (1.f - x) + gradient.top_right.value() * x;
const auto bottom = gradient.bottom_left.value() * (1.f - x) + gradient.bottom_right.value() * x;
const auto color = top * (1.f - y) + bottom * y;
const auto alpha = static_cast<int>(((vertex.col >> IM_COL32_A_SHIFT) & 0xff) * color.w);
vertex.col = IM_COL32(static_cast<int>(color.x * 255.f), static_cast<int>(color.y * 255.f),
static_cast<int>(color.z * 255.f), alpha);
}
}
[[nodiscard]]
Vector2<float> ImguiHudRenderer::calc_text_size(const std::string_view& text)
{