فهرست منبع

Optimize StyleBoxFlat.draw()

MewPurPur 1 سال پیش
والد
کامیت
71ac6b7476
1فایلهای تغییر یافته به همراه70 افزوده شده و 77 حذف شده
  1. 70 77
      scene/resources/style_box_flat.cpp

+ 70 - 77
scene/resources/style_box_flat.cpp

@@ -226,33 +226,16 @@ inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_re
 	real_t border_right = style_rect.size.width - inner_rect.size.width - border_left;
 	real_t border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
 
-	real_t rad;
-
-	// Top left.
-	rad = MIN(border_top, border_left);
-	inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);
-
-	// Top right;
-	rad = MIN(border_top, border_right);
-	inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);
-
-	// Bottom right.
-	rad = MIN(border_bottom, border_right);
-	inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);
-
-	// Bottom left.
-	rad = MIN(border_bottom, border_left);
-	inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
+	inner_corner_radius[0] = MAX(corner_radius[0] - MIN(border_top, border_left), 0); // Top left.
+	inner_corner_radius[1] = MAX(corner_radius[1] - MIN(border_top, border_right), 0); // Top right.
+	inner_corner_radius[2] = MAX(corner_radius[2] - MIN(border_bottom, border_right), 0); // Bottom right.
+	inner_corner_radius[3] = MAX(corner_radius[3] - MIN(border_bottom, border_left), 0); // Bottom left.
 }
 
 inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const real_t corner_radius[4],
 		const Rect2 &ring_rect, const Rect2 &inner_rect, const Color &inner_color, const Color &outer_color, const int corner_detail, const Vector2 &skew, bool is_filled = false) {
 	int vert_offset = verts.size();
-	if (!vert_offset) {
-		vert_offset = 0;
-	}
-
-	int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;
+	int adapted_corner_detail = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0) ? corner_detail : 1;
 
 	bool draw_border = !is_filled;
 
@@ -280,30 +263,44 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
 
 	// If the center is filled, we do not draw the border and directly use the inner ring as reference. Because all calls to this
 	// method either draw a ring or a filled rounded rectangle, but not both.
-	int max_inner_outer = draw_border ? 2 : 1;
-
-	for (int corner_index = 0; corner_index < 4; corner_index++) {
+	real_t quarter_arc_rad = Math_PI / 2.0;
+	Point2 style_rect_center = style_rect.get_center();
+
+	int colors_size = colors.size();
+	int verts_size = verts.size();
+	int new_verts_amount = (adapted_corner_detail + 1) * (draw_border ? 8 : 4);
+	colors.resize(colors_size + new_verts_amount);
+	verts.resize(verts_size + new_verts_amount);
+	Color *colors_ptr = colors.ptrw();
+	Vector2 *verts_ptr = verts.ptrw();
+
+	for (int corner_idx = 0; corner_idx < 4; corner_idx++) {
 		for (int detail = 0; detail <= adapted_corner_detail; detail++) {
-			for (int inner_outer = 0; inner_outer < max_inner_outer; inner_outer++) {
-				real_t radius;
-				Color color;
-				Point2 corner_point;
-				if (inner_outer == 0) {
-					radius = inner_corner_radius[corner_index];
-					color = inner_color;
-					corner_point = inner_points[corner_index];
-				} else {
-					radius = ring_corner_radius[corner_index];
-					color = outer_color;
-					corner_point = outer_points[corner_index];
-				}
+			int idx_ofs = (adapted_corner_detail + 1) * corner_idx + detail;
+			if (draw_border) {
+				idx_ofs *= 2;
+			}
 
-				const real_t x = radius * (real_t)cos((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.x;
-				const real_t y = radius * (real_t)sin((corner_index + detail / (double)adapted_corner_detail) * (Math_TAU / 4.0) + Math_PI) + corner_point.y;
-				const float x_skew = -skew.x * (y - style_rect.get_center().y);
-				const float y_skew = -skew.y * (x - style_rect.get_center().x);
-				verts.push_back(Vector2(x + x_skew, y + y_skew));
-				colors.push_back(color);
+			const real_t pt_angle = (corner_idx + detail / (double)adapted_corner_detail) * quarter_arc_rad + Math_PI;
+			const real_t angle_cosine = cos(pt_angle);
+			const real_t angle_sine = sin(pt_angle);
+
+			{
+				const real_t x = inner_corner_radius[corner_idx] * angle_cosine + inner_points[corner_idx].x;
+				const real_t y = inner_corner_radius[corner_idx] * angle_sine + inner_points[corner_idx].y;
+				const float x_skew = -skew.x * (y - style_rect_center.y);
+				const float y_skew = -skew.y * (x - style_rect_center.x);
+				verts_ptr[verts_size + idx_ofs] = Vector2(x + x_skew, y + y_skew);
+				colors_ptr[colors_size + idx_ofs] = inner_color;
+			}
+
+			if (draw_border) {
+				const real_t x = ring_corner_radius[corner_idx] * angle_cosine + outer_points[corner_idx].x;
+				const real_t y = ring_corner_radius[corner_idx] * angle_sine + outer_points[corner_idx].y;
+				const float x_skew = -skew.x * (y - style_rect_center.y);
+				const float y_skew = -skew.y * (x - style_rect_center.x);
+				verts_ptr[verts_size + idx_ofs + 1] = Vector2(x + x_skew, y + y_skew);
+				colors_ptr[colors_size + idx_ofs + 1] = outer_color;
 			}
 		}
 	}
@@ -313,10 +310,15 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
 	// Fill the indices and the colors for the border.
 
 	if (draw_border) {
+		int indices_size = indices.size();
+		indices.resize(indices_size + ring_vert_count * 3);
+		int *indices_ptr = indices.ptrw();
+
 		for (int i = 0; i < ring_vert_count; i++) {
-			indices.push_back(vert_offset + ((i + 0) % ring_vert_count));
-			indices.push_back(vert_offset + ((i + 2) % ring_vert_count));
-			indices.push_back(vert_offset + ((i + 1) % ring_vert_count));
+			int idx_ofs = indices_size + i * 3;
+			indices_ptr[idx_ofs] = vert_offset + i % ring_vert_count;
+			indices_ptr[idx_ofs + 1] = vert_offset + (i + 2) % ring_vert_count;
+			indices_ptr[idx_ofs + 2] = vert_offset + (i + 1) % ring_vert_count;
 		}
 	}
 
@@ -327,40 +329,30 @@ inline void draw_rounded_rectangle(Vector<Vector2> &verts, Vector<int> &indices,
 		int stripes_count = ring_vert_count / 2 - 1;
 		int last_vert_id = ring_vert_count - 1;
 
+		int indices_size = indices.size();
+		indices.resize(indices_size + stripes_count * 6);
+		int *indices_ptr = indices.ptrw();
+
 		for (int i = 0; i < stripes_count; i++) {
+			int idx_ofs = indices_size + i * 6;
 			// Polygon 1.
-			indices.push_back(vert_offset + i);
-			indices.push_back(vert_offset + last_vert_id - i - 1);
-			indices.push_back(vert_offset + i + 1);
+			indices_ptr[idx_ofs] = vert_offset + i;
+			indices_ptr[idx_ofs + 1] = vert_offset + last_vert_id - i - 1;
+			indices_ptr[idx_ofs + 2] = vert_offset + i + 1;
 			// Polygon 2.
-			indices.push_back(vert_offset + i);
-			indices.push_back(vert_offset + last_vert_id - 0 - i);
-			indices.push_back(vert_offset + last_vert_id - 1 - i);
+			indices_ptr[idx_ofs + 3] = vert_offset + i;
+			indices_ptr[idx_ofs + 4] = vert_offset + last_vert_id - i;
+			indices_ptr[idx_ofs + 5] = vert_offset + last_vert_id - i - 1;
 		}
 	}
 }
 
 inline void adapt_values(int p_index_a, int p_index_b, real_t *adapted_values, const real_t *p_values, const real_t p_width, const real_t p_max_a, const real_t p_max_b) {
-	if (p_values[p_index_a] + p_values[p_index_b] > p_width) {
-		real_t factor;
-		real_t new_value;
-
-		factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);
-
-		new_value = (p_values[p_index_a] * factor);
-		if (new_value < adapted_values[p_index_a]) {
-			adapted_values[p_index_a] = new_value;
-		}
-		new_value = (p_values[p_index_b] * factor);
-		if (new_value < adapted_values[p_index_b]) {
-			adapted_values[p_index_b] = new_value;
-		}
-	} else {
-		adapted_values[p_index_a] = MIN(p_values[p_index_a], adapted_values[p_index_a]);
-		adapted_values[p_index_b] = MIN(p_values[p_index_b], adapted_values[p_index_b]);
-	}
-	adapted_values[p_index_a] = MIN(p_max_a, adapted_values[p_index_a]);
-	adapted_values[p_index_b] = MIN(p_max_b, adapted_values[p_index_b]);
+	real_t value_a = p_values[p_index_a];
+	real_t value_b = p_values[p_index_b];
+	real_t factor = MIN(1.0, p_width / (value_a + value_b));
+	adapted_values[p_index_a] = MIN(MIN(value_a * factor, p_max_a), adapted_values[p_index_a]);
+	adapted_values[p_index_b] = MIN(MIN(value_b * factor, p_max_b), adapted_values[p_index_b]);
 }
 
 Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
@@ -388,7 +380,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
 	}
 
 	const bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
-	// Only enable antialiasing if it is actually needed. This improve performances
+	// Only enable antialiasing if it is actually needed. This improves performance
 	// and maximizes sharpness for non-skewed StyleBoxes with sharp corners.
 	const bool aa_on = (rounded_corners || !skew.is_zero_approx()) && anti_aliased;
 
@@ -428,7 +420,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
 	Vector<Color> colors;
 	Vector<Point2> uvs;
 
-	// Create shadow
+	// Create shadow.
 	if (draw_shadow) {
 		Rect2 shadow_inner_rect = style_rect;
 		shadow_inner_rect.position += shadow_offset;
@@ -538,9 +530,10 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
 	// Compute UV coordinates.
 	Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
 	uvs.resize(verts.size());
+	Point2 *uvs_ptr = uvs.ptrw();
 	for (int i = 0; i < verts.size(); i++) {
-		uvs.write[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
-		uvs.write[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
+		uvs_ptr[i].x = (verts[i].x - uv_rect.position.x) / uv_rect.size.width;
+		uvs_ptr[i].y = (verts[i].y - uv_rect.position.y) / uv_rect.size.height;
 	}
 
 	// Draw stylebox.