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
+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)
{