From 18493f3c4e530f5d2587639734d1872385993d24 Mon Sep 17 00:00:00 2001 From: Yaohua Xiong Date: Sun, 5 Nov 2023 12:25:29 +0800 Subject: [PATCH] Extend CanvasItem::draw_circle() Make it possible to draw unfilled circle, like draw_rect(). --- doc/classes/CanvasItem.xml | 7 ++++++- scene/main/canvas_item.cpp | 34 +++++++++++++++++++++++++++++++--- scene/main/canvas_item.h | 2 +- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml index 84efd11b4369..6a5c3a62e001 100644 --- a/doc/classes/CanvasItem.xml +++ b/doc/classes/CanvasItem.xml @@ -76,8 +76,13 @@ + + - Draws a colored, filled circle. See also [method draw_arc], [method draw_polyline] and [method draw_polygon]. + Draws a circle. See also [method draw_arc], [method draw_polyline] and [method draw_polygon]. + If [param filled] is [code]true[/code], the cricle will be filled with the [param color] specified. If [param filled] is [code]false[/code], the circle will be drawn as a stroke with the [param color] and [param width] specified. + If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code]. + [b]Note:[/b] [param width] is only effective if [param filled] is [code]false[/code]. diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp index a350b97bc8e5..8f2485bc2469 100644 --- a/scene/main/canvas_item.cpp +++ b/scene/main/canvas_item.cpp @@ -700,11 +700,39 @@ void CanvasItem::draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_fil } } -void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color) { +void CanvasItem::draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color, bool p_filled, real_t p_width) { ERR_THREAD_GUARD; ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal."); - RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color); + if (p_filled) { + if (p_width != -1.0) { + WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\"."); + } + + RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius, p_color); + } else if (p_width >= 2.0 * p_radius) { + RenderingServer::get_singleton()->canvas_item_add_circle(canvas_item, p_pos, p_radius + 0.5 * p_width, p_color); + } else { + // Tessellation count hardcoded. Keep in sync with the same variable in 'RendererCanvasCull::canvas_item_add_circle()' + const int circle_points = 64; + + Vector points; + points.resize(circle_points + 1); + + Vector2 *points_ptr = points.ptrw(); + const real_t circle_point_step = Math_TAU / circle_points; + + for (int i = 0; i < circle_points + 1; i++) { + float angle = i * circle_point_step; + points_ptr[i].x = Math::cos(angle) * p_radius; + points_ptr[i].y = Math::sin(angle) * p_radius; + points_ptr[i] += p_pos; + } + + Vector colors = { p_color }; + + RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, points, colors, p_width); + } } void CanvasItem::draw_texture(const Ref &p_texture, const Point2 &p_pos, const Color &p_modulate) { @@ -1133,7 +1161,7 @@ void CanvasItem::_bind_methods() { ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0)); - ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle); + ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color", "filled", "width"), &CanvasItem::draw_circle, DEFVAL(true), DEFVAL(-1.0)); ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1))); ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false)); ClassDB::bind_method(D_METHOD("draw_texture_rect_region", "texture", "rect", "src_rect", "modulate", "transpose", "clip_uv"), &CanvasItem::draw_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false), DEFVAL(true)); diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h index 36f0e179241a..1018f4074e99 100644 --- a/scene/main/canvas_item.h +++ b/scene/main/canvas_item.h @@ -268,7 +268,7 @@ class CanvasItem : public Node { void draw_multiline(const Vector &p_points, const Color &p_color, real_t p_width = -1.0); void draw_multiline_colors(const Vector &p_points, const Vector &p_colors, real_t p_width = -1.0); void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, real_t p_width = -1.0); - void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color); + void draw_circle(const Point2 &p_pos, real_t p_radius, const Color &p_color, bool p_filled = true, real_t p_width = -1.0); void draw_texture(const Ref &p_texture, const Point2 &p_pos, const Color &p_modulate = Color(1, 1, 1, 1)); void draw_texture_rect(const Ref &p_texture, const Rect2 &p_rect, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false); void draw_texture_rect_region(const Ref &p_texture, const Rect2 &p_rect, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false, bool p_clip_uv = false);