Merge pull request #94240 from MewPurPur/optimize-styleboxflat
Optimize `StyleBoxFlat.draw()`
This commit is contained in:
commit
eaac033168
1 changed files with 69 additions and 76 deletions
|
@ -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;
|
||||
real_t quarter_arc_rad = Math_PI / 2.0;
|
||||
Point2 style_rect_center = style_rect.get_center();
|
||||
|
||||
for (int corner_index = 0; corner_index < 4; corner_index++) {
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue