Feature/gradient#202
Conversation
There was a problem hiding this comment.
Code Review
This pull request introduces support for gradient fills and text rendering within the HUD overlay system, adding a new Gradient struct and a Paint variant type to support both solid colors and gradients. The ImguiHudRenderer and EntityOverlay have been updated to handle these gradients, and the example HUD application has been extended with options to configure and animate them. The feedback highlights two important issues: first, in EntityOverlay::add_2d_box, the gradient fill should be drawn before the borders to prevent obscuring them; second, in ImguiHudRenderer::add_gradient_text, the color components should be clamped to [0, 255] before passing them to IM_COL32 to avoid potential overflow and color corruption.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| 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; | ||
| } |
There was a problem hiding this comment.
In add_2d_box with a gradient fill, the gradient rectangle is drawn after the outline and box polylines. Since the gradient rectangle is a filled shape, drawing it last will overlay it on top of the borders, partially or completely obscuring them (especially if the gradient is opaque). To ensure the borders remain fully visible and crisp, the gradient fill should be drawn first as the background layer.
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();
m_renderer->add_gradient_rectangle(m_canvas.top_left_corner, m_canvas.bottom_right_corner, fill_gradient);
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);
return *this;
}| 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); |
There was a problem hiding this comment.
When converting the floating-point color components to 8-bit integers for IM_COL32, there is a risk of value overflow if any component is slightly outside the [0.f, 1.f] range (e.g., due to floating-point precision inaccuracies or HDR colors). Because IM_COL32 does not perform clamping internally, values outside [0, 255] will overflow and corrupt adjacent color channels. Using std::clamp ensures the values are safely bounded.
const auto alpha = std::clamp(static_cast<int>(((vertex.col >> IM_COL32_A_SHIFT) & 0xff) * color.w), 0, 255);
vertex.col = IM_COL32(std::clamp(static_cast<int>(color.x * 255.f), 0, 255),
std::clamp(static_cast<int>(color.y * 255.f), 0, 255),
std::clamp(static_cast<int>(color.z * 255.f), 0, 255), alpha);
No description provided.