Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Optimize StyleBoxFlat.draw() #94240

Merged
merged 1 commit into from
Oct 1, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 70 additions & 77 deletions scene/resources/style_box_flat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
Comment on lines +266 to +271
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
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);
const real_t quarter_arc_rad = Math_PI / 2.0;
const Point2 style_rect_center = style_rect.get_center();
const int colors_size = colors.size();
const int verts_size = verts.size();
const int new_verts_amount = (adapted_corner_detail + 1) * (draw_border ? 8 : 4);

For consistency.

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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const real_t angle_cosine = cos(pt_angle);
const real_t angle_cosine = Math::cos(pt_angle);

const real_t angle_sine = sin(pt_angle);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const real_t angle_sine = sin(pt_angle);
const real_t angle_sine = Math::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;
}
}
}
Expand All @@ -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;
}
}

Expand All @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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.
Expand Down
Loading