From 6fb4ece167e649c1be907c934a68c3c87e123c01 Mon Sep 17 00:00:00 2001 From: Relintai Date: Fri, 25 Aug 2023 21:26:46 +0200 Subject: [PATCH] PaintPolygon2D modularize polygon preprocessing. --- .../nodes/polygon_2d/paint_polygon_2d.cpp | 319 ++++++++++-------- .../paint/nodes/polygon_2d/paint_polygon_2d.h | 5 + 2 files changed, 180 insertions(+), 144 deletions(-) diff --git a/modules/paint/nodes/polygon_2d/paint_polygon_2d.cpp b/modules/paint/nodes/polygon_2d/paint_polygon_2d.cpp index 826a3862e..1ddf24dd0 100644 --- a/modules/paint/nodes/polygon_2d/paint_polygon_2d.cpp +++ b/modules/paint/nodes/polygon_2d/paint_polygon_2d.cpp @@ -89,162 +89,163 @@ bool PaintPolygon2D::_edit_is_selected_on_click(const Point2 &p_point, double p_ } #endif +void PaintPolygon2D::_prepare_render_data(Vector &r_points, Vector &r_uvs, Vector &r_colors, Vector &r_indices) { + int len = polygon.size(); + if ((invert || polygons.size() == 0) && internal_vertices > 0) { + //if no polygons are around, internal vertices must not be drawn, else let them be + len -= internal_vertices; + } + + if (len <= 0) { + return; + } + + r_points.resize(len); + + { + PoolVector::Read polyr = polygon.read(); + for (int i = 0; i < len; i++) { + r_points.write[i] = polyr[i] + offset; + } + } + + if (invert) { + Rect2 bounds; + int highest_idx = -1; + float highest_y = -1e20; + float sum = 0; + + for (int i = 0; i < len; i++) { + if (i == 0) { + bounds.position = r_points[i]; + } else { + bounds.expand_to(r_points[i]); + } + if (r_points[i].y > highest_y) { + highest_idx = i; + highest_y = r_points[i].y; + } + int ni = (i + 1) % len; + sum += (r_points[ni].x - r_points[i].x) * (r_points[ni].y + r_points[i].y); + } + + bounds = bounds.grow(invert_border); + + Vector2 ep[7] = { + Vector2(r_points[highest_idx].x, r_points[highest_idx].y + invert_border), + Vector2(bounds.position + bounds.size), + Vector2(bounds.position + Vector2(bounds.size.x, 0)), + Vector2(bounds.position), + Vector2(bounds.position + Vector2(0, bounds.size.y)), + Vector2(r_points[highest_idx].x - CMP_EPSILON, r_points[highest_idx].y + invert_border), + Vector2(r_points[highest_idx].x - CMP_EPSILON, r_points[highest_idx].y), + }; + + if (sum > 0) { + SWAP(ep[1], ep[4]); + SWAP(ep[2], ep[3]); + SWAP(ep[5], ep[0]); + SWAP(ep[6], r_points.write[highest_idx]); + } + + r_points.resize(r_points.size() + 7); + for (int i = r_points.size() - 1; i >= highest_idx + 7; i--) { + r_points.write[i] = r_points[i - 7]; + } + + for (int i = 0; i < 7; i++) { + r_points.write[highest_idx + i + 1] = ep[i]; + } + + len = r_points.size(); + } + + if (texture.is_valid()) { + Transform2D texmat(tex_rot, tex_ofs); + texmat.scale(tex_scale); + Size2 tex_size = texture->get_size(); + + r_uvs.resize(len); + + if (r_points.size() == uv.size()) { + PoolVector::Read uvr = uv.read(); + + for (int i = 0; i < len; i++) { + r_uvs.write[i] = texmat.xform(uvr[i]) / tex_size; + } + + } else { + for (int i = 0; i < len; i++) { + r_uvs.write[i] = texmat.xform(r_points[i]) / tex_size; + } + } + } + + if (vertex_colors.size() == r_points.size()) { + r_colors.resize(len); + PoolVector::Read color_r = vertex_colors.read(); + for (int i = 0; i < len; i++) { + r_colors.write[i] = color_r[i]; + } + } else { + r_colors.push_back(color); + } + + if (invert || polygons.size() == 0) { + r_indices = Geometry::triangulate_polygon(r_points); + + } else { + //draw individual polygons + + for (int i = 0; i < polygons.size(); i++) { + PoolVector src_indices = polygons[i]; + int ic = src_indices.size(); + if (ic < 3) { + continue; + } + PoolVector::Read r = src_indices.read(); + + Vector tmp_r_points; + tmp_r_points.resize(ic); + + for (int j = 0; j < ic; j++) { + int idx = r[j]; + ERR_CONTINUE(idx < 0 || idx >= r_points.size()); + tmp_r_points.write[j] = r_points[r[j]]; + } + Vector indices = Geometry::triangulate_polygon(tmp_r_points); + int ic2 = indices.size(); + const int *r2 = indices.ptr(); + + int bic = r_indices.size(); + r_indices.resize(bic + ic2); + int *w2 = r_indices.ptrw(); + + for (int j = 0; j < ic2; j++) { + w2[j + bic] = r[r2[j]]; + } + } + } +} + void PaintPolygon2D::_notification(int p_what) { switch (p_what) { case NOTIFICATION_DRAW: { + _rendered_image.unref(); + if (polygon.size() < 3) { return; } Vector points; Vector uvs; - Vector bones; - Vector weights; - - int len = polygon.size(); - if ((invert || polygons.size() == 0) && internal_vertices > 0) { - //if no polygons are around, internal vertices must not be drawn, else let them be - len -= internal_vertices; - } - - if (len <= 0) { - return; - } - points.resize(len); - - { - PoolVector::Read polyr = polygon.read(); - for (int i = 0; i < len; i++) { - points.write[i] = polyr[i] + offset; - } - } - - if (invert) { - Rect2 bounds; - int highest_idx = -1; - float highest_y = -1e20; - float sum = 0; - - for (int i = 0; i < len; i++) { - if (i == 0) { - bounds.position = points[i]; - } else { - bounds.expand_to(points[i]); - } - if (points[i].y > highest_y) { - highest_idx = i; - highest_y = points[i].y; - } - int ni = (i + 1) % len; - sum += (points[ni].x - points[i].x) * (points[ni].y + points[i].y); - } - - bounds = bounds.grow(invert_border); - - Vector2 ep[7] = { - Vector2(points[highest_idx].x, points[highest_idx].y + invert_border), - Vector2(bounds.position + bounds.size), - Vector2(bounds.position + Vector2(bounds.size.x, 0)), - Vector2(bounds.position), - Vector2(bounds.position + Vector2(0, bounds.size.y)), - Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y + invert_border), - Vector2(points[highest_idx].x - CMP_EPSILON, points[highest_idx].y), - }; - - if (sum > 0) { - SWAP(ep[1], ep[4]); - SWAP(ep[2], ep[3]); - SWAP(ep[5], ep[0]); - SWAP(ep[6], points.write[highest_idx]); - } - - points.resize(points.size() + 7); - for (int i = points.size() - 1; i >= highest_idx + 7; i--) { - points.write[i] = points[i - 7]; - } - - for (int i = 0; i < 7; i++) { - points.write[highest_idx + i + 1] = ep[i]; - } - - len = points.size(); - } - - if (texture.is_valid()) { - Transform2D texmat(tex_rot, tex_ofs); - texmat.scale(tex_scale); - Size2 tex_size = texture->get_size(); - - uvs.resize(len); - - if (points.size() == uv.size()) { - PoolVector::Read uvr = uv.read(); - - for (int i = 0; i < len; i++) { - uvs.write[i] = texmat.xform(uvr[i]) / tex_size; - } - - } else { - for (int i = 0; i < len; i++) { - uvs.write[i] = texmat.xform(points[i]) / tex_size; - } - } - } - Vector colors; - if (vertex_colors.size() == points.size()) { - colors.resize(len); - PoolVector::Read color_r = vertex_colors.read(); - for (int i = 0; i < len; i++) { - colors.write[i] = color_r[i]; - } - } else { - colors.push_back(color); - } + Vector indices; - // Vector indices = Geometry::triangulate_polygon(points); - // RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, texture.is_valid() ? texture->get_rid() : RID()); + _prepare_render_data(points, uvs, colors, indices); - if (invert || polygons.size() == 0) { - Vector indices = Geometry::triangulate_polygon(points); - if (indices.size()) { - RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, RID(), antialiased); - } - } else { - //draw individual polygons - Vector total_indices; - for (int i = 0; i < polygons.size(); i++) { - PoolVector src_indices = polygons[i]; - int ic = src_indices.size(); - if (ic < 3) { - continue; - } - PoolVector::Read r = src_indices.read(); - - Vector tmp_points; - tmp_points.resize(ic); - - for (int j = 0; j < ic; j++) { - int idx = r[j]; - ERR_CONTINUE(idx < 0 || idx >= points.size()); - tmp_points.write[j] = points[r[j]]; - } - Vector indices = Geometry::triangulate_polygon(tmp_points); - int ic2 = indices.size(); - const int *r2 = indices.ptr(); - - int bic = total_indices.size(); - total_indices.resize(bic + ic2); - int *w2 = total_indices.ptrw(); - - for (int j = 0; j < ic2; j++) { - w2[j + bic] = r[r2[j]]; - } - } - - if (total_indices.size()) { - RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), total_indices, points, colors, uvs, bones, weights, texture.is_valid() ? texture->get_rid() : RID(), -1, RID(), antialiased); - } + if (indices.size()) { + RS::get_singleton()->canvas_item_add_triangle_array(get_canvas_item(), indices, points, colors, uvs, Vector(), Vector(), texture.is_valid() ? texture->get_rid() : RID(), -1, RID(), antialiased); } } break; @@ -386,6 +387,36 @@ Vector2 PaintPolygon2D::get_offset() const { return offset; } +Ref PaintPolygon2D::_get_rendered_image() { + if (_rendered_image.is_valid()) { + return _rendered_image; + } + + if (_size.x == 0 || _size.y == 0) { + return Ref(); + } + + if (polygon.size() < 3) { + return Ref(); + } + + Vector points; + Vector uvs; + Vector colors; + Vector indices; + + _prepare_render_data(points, uvs, colors, indices); + + if (indices.size() == 0) { + return Ref(); + } + + _rendered_image.instance(); + _rendered_image->create(_size.x, _size.y, false, Image::FORMAT_RGBA8); + + return _rendered_image; +} + void PaintPolygon2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_polygon", "polygon"), &PaintPolygon2D::set_polygon); ClassDB::bind_method(D_METHOD("get_polygon"), &PaintPolygon2D::get_polygon); diff --git a/modules/paint/nodes/polygon_2d/paint_polygon_2d.h b/modules/paint/nodes/polygon_2d/paint_polygon_2d.h index 2a707040e..869c4e27b 100644 --- a/modules/paint/nodes/polygon_2d/paint_polygon_2d.h +++ b/modules/paint/nodes/polygon_2d/paint_polygon_2d.h @@ -55,8 +55,11 @@ class PaintPolygon2D : public PaintNode { Vector2 offset; mutable bool rect_cache_dirty; mutable Rect2 item_rect; + Ref _rendered_image; protected: + void _prepare_render_data(Vector &r_points, Vector &r_uvs, Vector &r_colors, Vector &r_indices); + void _notification(int p_what); static void _bind_methods(); @@ -119,6 +122,8 @@ public: void set_offset(const Vector2 &p_offset); Vector2 get_offset() const; + virtual Ref _get_rendered_image(); + PaintPolygon2D(); virtual ~PaintPolygon2D(); };