-
-
Notifications
You must be signed in to change notification settings - Fork 21.5k
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
Optimize StyleBoxFlat.draw()
#94240
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -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); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
const real_t angle_sine = sin(pt_angle); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
{ | ||||||
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. | ||||||
|
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For consistency.