Browse Source

Restored antialiased lines by emulation using triangle strips

Yuri Roubinsky 4 years ago
parent
commit
3ec972fc95

+ 6 - 0
doc/classes/CanvasItem.xml

@@ -41,6 +41,8 @@
 			</argument>
 			<argument index="6" name="width" type="float" default="1.0">
 			</argument>
+			<argument index="7" name="antialiased" type="bool" default="false">
+			</argument>
 			<description>
 				Draws an arc between the given angles. The larger the value of [code]point_count[/code], the smoother the curve.
 			</description>
@@ -181,6 +183,8 @@
 			</argument>
 			<argument index="2" name="width" type="float" default="1.0">
 			</argument>
+			<argument index="3" name="antialiased" type="bool" default="false">
+			</argument>
 			<description>
 				Draws interconnected line segments with a uniform [code]color[/code] and [code]width[/code].
 			</description>
@@ -194,6 +198,8 @@
 			</argument>
 			<argument index="2" name="width" type="float" default="1.0">
 			</argument>
+			<argument index="3" name="antialiased" type="bool" default="false">
+			</argument>
 			<description>
 				Draws interconnected line segments with a uniform [code]width[/code] and segment-by-segment coloring. Colors assigned to line segments match by index between [code]points[/code] and [code]colors[/code].
 			</description>

+ 2 - 2
scene/gui/graph_edit.cpp

@@ -659,9 +659,9 @@ void GraphEdit::_draw_cos_line(CanvasItem *p_where, const Vector2 &p_from, const
 	colors.push_back(p_to_color);
 
 #ifdef TOOLS_ENABLED
-	p_where->draw_polyline_colors(points, colors, Math::floor(2 * EDSCALE));
+	p_where->draw_polyline_colors(points, colors, Math::floor(2 * EDSCALE), true);
 #else
-	p_where->draw_polyline_colors(points, colors, 2);
+	p_where->draw_polyline_colors(points, colors, 2, true);
 #endif
 }
 

+ 9 - 9
scene/main/canvas_item.cpp

@@ -742,21 +742,21 @@ void CanvasItem::draw_line(const Point2 &p_from, const Point2 &p_to, const Color
 	RenderingServer::get_singleton()->canvas_item_add_line(canvas_item, p_from, p_to, p_color, p_width);
 }
 
-void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
+void CanvasItem::draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width, bool p_antialiased) {
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
 	Vector<Color> colors;
 	colors.push_back(p_color);
-	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width);
+	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, colors, p_width, p_antialiased);
 }
 
-void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
 	ERR_FAIL_COND_MSG(!drawing, "Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.");
 
-	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width);
+	RenderingServer::get_singleton()->canvas_item_add_polyline(canvas_item, p_points, p_colors, p_width, p_antialiased);
 }
 
-void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width) {
+void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width, bool p_antialiased) {
 	Vector<Point2> points;
 	points.resize(p_point_count);
 	const float delta_angle = p_end_angle - p_start_angle;
@@ -765,7 +765,7 @@ void CanvasItem::draw_arc(const Vector2 &p_center, float p_radius, float p_start
 		points.set(i, p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius);
 	}
 
-	draw_polyline(points, p_color, p_width);
+	draw_polyline(points, p_color, p_width, p_antialiased);
 }
 
 void CanvasItem::draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width) {
@@ -1144,9 +1144,9 @@ void CanvasItem::_bind_methods() {
 	//ClassDB::bind_method(D_METHOD("get_transform"),&CanvasItem::get_transform);
 
 	ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width"), &CanvasItem::draw_line, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width"), &CanvasItem::draw_polyline, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0));
-	ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width"), &CanvasItem::draw_arc, DEFVAL(1.0));
+	ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
+	ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
 	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));

+ 3 - 3
scene/main/canvas_item.h

@@ -331,9 +331,9 @@ public:
 	/* DRAWING API */
 
 	void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
-	void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
-	void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
-	void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0);
+	void draw_polyline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
+	void draw_polyline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
+	void draw_arc(const Vector2 &p_center, float p_radius, float p_start_angle, float p_end_angle, int p_point_count, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
 	void draw_multiline(const Vector<Point2> &p_points, const Color &p_color, float p_width = 1.0);
 	void draw_multiline_colors(const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
 	void draw_rect(const Rect2 &p_rect, const Color &p_color, bool p_filled = true, float p_width = 1.0);

+ 99 - 54
servers/rendering/rendering_server_canvas.cpp

@@ -540,59 +540,108 @@ void RenderingServerCanvas::canvas_item_add_line(RID p_item, const Point2 &p_fro
 	}
 }
 
-void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {
+void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
 	ERR_FAIL_COND(p_points.size() < 2);
 	Item *canvas_item = canvas_item_owner.getornull(p_item);
 	ERR_FAIL_COND(!canvas_item);
 
+	Vector<int> indices;
+	int pc = p_points.size();
+	int pc2 = pc * 2;
+
+	Vector2 prev_t;
+	int j2;
+
 	Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
 	ERR_FAIL_COND(!pline);
 
-	if (true || p_width <= 1) {
-#define TODO make thick lines possible
-		Vector<int> indices;
-		int pc = p_points.size();
-		indices.resize((pc - 1) * 2);
-		{
-			int *iptr = indices.ptrw();
-			for (int i = 0; i < (pc - 1); i++) {
-				iptr[i * 2 + 0] = i;
-				iptr[i * 2 + 1] = i + 1;
-			}
-		}
+	PackedColorArray colors;
+	PackedVector2Array points;
 
-		pline->primitive = RS::PRIMITIVE_LINES;
-		pline->polygon.create(indices, p_points, p_colors);
-	} else {
-#if 0
-		//make a trianglestrip for drawing the line...
-		Vector2 prev_t;
-		pline->triangles.resize(p_points.size() * 2);
-		if (p_antialiased) {
-			pline->lines.resize(p_points.size() * 2);
-		}
+	colors.resize(pc2);
+	points.resize(pc2);
 
-		if (p_colors.size() == 0) {
-			pline->triangle_colors.push_back(Color(1, 1, 1, 1));
-			if (p_antialiased) {
-				pline->line_colors.push_back(Color(1, 1, 1, 1));
-			}
-		} else if (p_colors.size() == 1) {
-			pline->triangle_colors = p_colors;
-			pline->line_colors = p_colors;
-		} else {
-			if (p_colors.size() != p_points.size()) {
-				pline->triangle_colors.push_back(p_colors[0]);
-				pline->line_colors.push_back(p_colors[0]);
+	Vector2 *points_ptr = points.ptrw();
+	Color *colors_ptr = colors.ptrw();
+
+	if (p_antialiased) {
+		PackedColorArray colors_top;
+		PackedVector2Array points_top;
+
+		colors_top.resize(pc2);
+		points_top.resize(pc2);
+
+		PackedColorArray colors_bottom;
+		PackedVector2Array points_bottom;
+
+		colors_bottom.resize(pc2);
+		points_bottom.resize(pc2);
+
+		Item::CommandPolygon *pline_top = canvas_item->alloc_command<Item::CommandPolygon>();
+		ERR_FAIL_COND(!pline_top);
+
+		Item::CommandPolygon *pline_bottom = canvas_item->alloc_command<Item::CommandPolygon>();
+		ERR_FAIL_COND(!pline_bottom);
+
+		//make three trianglestrip's for drawing the antialiased line...
+
+		Vector2 *points_top_ptr = points_top.ptrw();
+		Vector2 *points_bottom_ptr = points_bottom.ptrw();
+
+		Color *colors_top_ptr = colors_top.ptrw();
+		Color *colors_bottom_ptr = colors_bottom.ptrw();
+
+		for (int i = 0, j = 0; i < pc; i++, j += 2) {
+			Vector2 t;
+			if (i == pc - 1) {
+				t = prev_t;
 			} else {
-				pline->triangle_colors.resize(pline->triangles.size());
-				pline->line_colors.resize(pline->lines.size());
+				t = (p_points[i + 1] - p_points[i]).normalized().tangent();
+				if (i == 0) {
+					prev_t = t;
+				}
 			}
+
+			j2 = j + 1;
+
+			Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+			Vector2 pos = p_points[i];
+
+			points_ptr[j] = pos + tangent;
+			points_ptr[j2] = pos - tangent;
+
+			points_top_ptr[j] = pos + tangent + tangent;
+			points_top_ptr[j2] = pos + tangent;
+
+			points_bottom_ptr[j] = pos - tangent;
+			points_bottom_ptr[j2] = pos - tangent - tangent;
+
+			Color color = p_colors[i];
+			Color color2 = Color(color.r, color.g, color.b, 0);
+
+			colors_ptr[j] = color;
+			colors_ptr[j2] = color;
+
+			colors_top_ptr[j] = color2;
+			colors_top_ptr[j2] = color;
+
+			colors_bottom_ptr[j] = color;
+			colors_bottom_ptr[j2] = color2;
+
+			prev_t = t;
 		}
 
-		for (int i = 0; i < p_points.size(); i++) {
+		pline_top->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+		pline_top->polygon.create(indices, points_top, colors_top);
+
+		pline_bottom->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+		pline_bottom->polygon.create(indices, points_bottom, colors_bottom);
+	} else {
+		//make a trianglestrip for drawing the line...
+
+		for (int i = 0, j = 0; i < pc; i++, j += 2) {
 			Vector2 t;
-			if (i == p_points.size() - 1) {
+			if (i == pc - 1) {
 				t = prev_t;
 			} else {
 				t = (p_points[i + 1] - p_points[i]).normalized().tangent();
@@ -601,29 +650,25 @@ void RenderingServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Po
 				}
 			}
 
+			j2 = j + 1;
+
 			Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
 
-			if (p_antialiased) {
-				pline->lines.write[i] = p_points[i] + tangent;
-				pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent;
-				if (pline->line_colors.size() > 1) {
-					pline->line_colors.write[i] = p_colors[i];
-					pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i];
-				}
-			}
+			Vector2 pos = p_points[j];
+			Color color = p_colors[j2];
 
-			pline->triangles.write[i * 2 + 0] = p_points[i] + tangent;
-			pline->triangles.write[i * 2 + 1] = p_points[i] - tangent;
+			points_ptr[j] = pos + tangent;
+			points_ptr[j2] = pos - tangent;
 
-			if (pline->triangle_colors.size() > 1) {
-				pline->triangle_colors.write[i * 2 + 0] = p_colors[i];
-				pline->triangle_colors.write[i * 2 + 1] = p_colors[i];
-			}
+			colors_ptr[j] = color;
+			colors_ptr[j2] = color;
 
 			prev_t = t;
 		}
-#endif
 	}
+
+	pline->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
+	pline->polygon.create(indices, points, colors);
 }
 
 void RenderingServerCanvas::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) {

+ 1 - 1
servers/rendering/rendering_server_canvas.h

@@ -192,7 +192,7 @@ public:
 	void canvas_item_set_update_when_visible(RID p_item, bool p_update);
 
 	void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0);
-	void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+	void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
 	void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
 	void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
 	void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);

+ 1 - 1
servers/rendering/rendering_server_raster.h

@@ -717,7 +717,7 @@ public:
 	BIND2(canvas_item_set_draw_behind_parent, RID, bool)
 
 	BIND5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
-	BIND4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+	BIND5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
 	BIND4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
 	BIND3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
 	BIND4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)

+ 1 - 1
servers/rendering/rendering_server_wrap_mt.h

@@ -618,7 +618,7 @@ public:
 	FUNC2(canvas_item_set_draw_behind_parent, RID, bool)
 
 	FUNC5(canvas_item_add_line, RID, const Point2 &, const Point2 &, const Color &, float)
-	FUNC4(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float)
+	FUNC5(canvas_item_add_polyline, RID, const Vector<Point2> &, const Vector<Color> &, float, bool)
 	FUNC4(canvas_item_add_multiline, RID, const Vector<Point2> &, const Vector<Color> &, float)
 	FUNC3(canvas_item_add_rect, RID, const Rect2 &, const Color &)
 	FUNC4(canvas_item_add_circle, RID, const Point2 &, float, const Color &)

+ 1 - 1
servers/rendering_server.h

@@ -1175,7 +1175,7 @@ public:
 	};
 
 	virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0) = 0;
-	virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+	virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
 	virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
 	virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
 	virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;