diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 3510b415d8f..f84d2ea359a 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -769,6 +769,49 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, } } +static Vector2 compute_polyline_segment_dir(const Vector &p_points, int p_index, const Vector2 &p_prev_segment_dir) { + int point_count = p_points.size(); + + bool is_last_point = (p_index == point_count - 1); + + Vector2 segment_dir; + + if (is_last_point) { + segment_dir = p_prev_segment_dir; + } else { + segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized(); + + if (segment_dir.is_zero_approx()) { + segment_dir = p_prev_segment_dir; + } + } + + return segment_dir; +} + +static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) { + Vector2 bisector; + float length = 1.0f; + + bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized(); + + float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir)); + float sin_angle = sinf(angle); + + if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) { + length = 1.0f / sin_angle; + length = CLAMP(length, -3.0f, 3.0f); + } else { + bisector = p_segment_dir.orthogonal(); + } + + if (bisector.is_zero_approx()) { + bisector = p_segment_dir.orthogonal(); + } + + return bisector * length; +} + void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector &p_points, const Vector &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); Item *canvas_item = canvas_item_owner.get_or_null(p_item); @@ -777,11 +820,30 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector indices; - int pc = p_points.size(); - int pc2 = pc * 2; + int point_count = p_points.size(); + int polyline_point_count = point_count * 2; - Vector2 prev_t; - int j2; + bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]); + Vector2 first_segment_dir; + Vector2 last_segment_dir; + + // Search for first non-zero vector between two segments. + for (int i = 1; i < point_count; i++) { + first_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!first_segment_dir.is_zero_approx()) { + break; + } + } + + // Search for last non-zero vector between two segments. + for (int i = point_count - 1; i >= 1; i--) { + last_segment_dir = (p_points[i] - p_points[i - 1]).normalized(); + + if (!last_segment_dir.is_zero_approx()) { + break; + } + } Item::CommandPolygon *pline = canvas_item->alloc_command(); ERR_FAIL_COND(!pline); @@ -789,8 +851,8 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vectoralloc_command(); ERR_FAIL_COND(!pline_begin); @@ -898,79 +960,81 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vectorprimitive = RS::PRIMITIVE_TRIANGLE_STRIP; @@ -1039,33 +1105,41 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector