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

StyleBox fake AA improvements (make anti aliasing size a float property) [3.x] #51589

Merged
merged 1 commit into from
Aug 12, 2021
Merged
Show file tree
Hide file tree
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
2 changes: 1 addition & 1 deletion doc/classes/StyleBoxFlat.xml
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@
<member name="anti_aliasing" type="bool" setter="set_anti_aliased" getter="is_anti_aliased" default="true">
Antialiasing draws a small ring around the edges, which fades to transparency. As a result, edges look much smoother. This is only noticeable when using rounded corners.
</member>
<member name="anti_aliasing_size" type="int" setter="set_aa_size" getter="get_aa_size" default="1">
<member name="anti_aliasing_size" type="float" setter="set_aa_size" getter="get_aa_size" default="0.625">
This changes the size of the faded ring. Higher values can be used to achieve a "blurry" effect.
</member>
<member name="bg_color" type="Color" setter="set_bg_color" getter="get_bg_color" default="Color( 0.6, 0.6, 0.6, 1 )">
Expand Down
147 changes: 79 additions & 68 deletions scene/resources/style_box.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,6 @@ void StyleBox::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_default_margin", "margin", "offset"), &StyleBox::set_default_margin);
ClassDB::bind_method(D_METHOD("get_default_margin", "margin"), &StyleBox::get_default_margin);

//ClassDB::bind_method(D_METHOD("set_default_margin"),&StyleBox::set_default_margin);
//ClassDB::bind_method(D_METHOD("get_default_margin"),&StyleBox::get_default_margin);

ClassDB::bind_method(D_METHOD("get_margin", "margin"), &StyleBox::get_margin);
ClassDB::bind_method(D_METHOD("get_minimum_size"), &StyleBox::get_minimum_size);
ClassDB::bind_method(D_METHOD("get_center_size"), &StyleBox::get_center_size);
Expand Down Expand Up @@ -501,18 +498,20 @@ bool StyleBoxFlat::is_anti_aliased() const {
return anti_aliased;
}

void StyleBoxFlat::set_aa_size(const int &p_aa_size) {
aa_size = CLAMP(p_aa_size, 1, 5);
void StyleBoxFlat::set_aa_size(const real_t &p_aa_size) {
aa_size = CLAMP(p_aa_size, 0.01, 10);
emit_changed();
}
int StyleBoxFlat::get_aa_size() const {

float StyleBoxFlat::get_aa_size() const {
return aa_size;
}

void StyleBoxFlat::set_corner_detail(const int &p_corner_detail) {
corner_detail = CLAMP(p_corner_detail, 1, 20);
emit_changed();
}

int StyleBoxFlat::get_corner_detail() const {
return corner_detail;
}
Expand All @@ -521,31 +520,32 @@ Size2 StyleBoxFlat::get_center_size() const {
return Size2();
}

inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const int corner_radius[4], int *inner_corner_radius) {
int border_left = inner_rect.position.x - style_rect.position.x;
int border_top = inner_rect.position.y - style_rect.position.y;
int border_right = style_rect.size.width - inner_rect.size.width - border_left;
int border_bottom = style_rect.size.height - inner_rect.size.height - border_top;
inline void set_inner_corner_radius(const Rect2 style_rect, const Rect2 inner_rect, const real_t corner_radius[4], real_t *inner_corner_radius) {
real_t border_left = inner_rect.position.x - style_rect.position.x;
real_t border_top = inner_rect.position.y - style_rect.position.y;
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;

int rad;
//tl
real_t rad;

// Top left.
rad = MIN(border_top, border_left);
inner_corner_radius[0] = MAX(corner_radius[0] - rad, 0);

//tr
// Top right;
rad = MIN(border_top, border_right);
inner_corner_radius[1] = MAX(corner_radius[1] - rad, 0);

//br
// Bottom right.
rad = MIN(border_bottom, border_right);
inner_corner_radius[2] = MAX(corner_radius[2] - rad, 0);

//bl
// Bottom left.
rad = MIN(border_bottom, border_left);
inner_corner_radius[3] = MAX(corner_radius[3] - rad, 0);
}

inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color> &colors, const Rect2 &style_rect, const int corner_radius[4],
inline void draw_ring(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 bool fill_center = false) {
int vert_offset = verts.size();
if (!vert_offset) {
Expand All @@ -554,17 +554,17 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color

int adapted_corner_detail = (corner_radius[0] == 0 && corner_radius[1] == 0 && corner_radius[2] == 0 && corner_radius[3] == 0) ? 1 : corner_detail;

int ring_corner_radius[4];
real_t ring_corner_radius[4];
set_inner_corner_radius(style_rect, ring_rect, corner_radius, ring_corner_radius);

//corner radius center points
// Corner radius center points.
Vector<Point2> outer_points;
outer_points.push_back(ring_rect.position + Vector2(ring_corner_radius[0], ring_corner_radius[0])); //tl
outer_points.push_back(Point2(ring_rect.position.x + ring_rect.size.x - ring_corner_radius[1], ring_rect.position.y + ring_corner_radius[1])); //tr
outer_points.push_back(ring_rect.position + ring_rect.size - Vector2(ring_corner_radius[2], ring_corner_radius[2])); //br
outer_points.push_back(Point2(ring_rect.position.x + ring_corner_radius[3], ring_rect.position.y + ring_rect.size.y - ring_corner_radius[3])); //bl

int inner_corner_radius[4];
real_t inner_corner_radius[4];
set_inner_corner_radius(style_rect, inner_rect, corner_radius, inner_corner_radius);

Vector<Point2> inner_points;
Expand All @@ -573,11 +573,11 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color
inner_points.push_back(inner_rect.position + inner_rect.size - Vector2(inner_corner_radius[2], inner_corner_radius[2])); //br
inner_points.push_back(Point2(inner_rect.position.x + inner_corner_radius[3], inner_rect.position.y + inner_rect.size.y - inner_corner_radius[3])); //bl

//calculate the vert array
// Calculate the vertices.
for (int corner_index = 0; corner_index < 4; corner_index++) {
for (int detail = 0; detail <= adapted_corner_detail; detail++) {
for (int inner_outer = 0; inner_outer < 2; inner_outer++) {
float radius;
real_t radius;
Color color;
Point2 corner_point;
if (inner_outer == 0) {
Expand All @@ -599,43 +599,43 @@ inline void draw_ring(Vector<Vector2> &verts, Vector<int> &indices, Vector<Color

int ring_vert_count = verts.size() - vert_offset;

//fill the indices and the colors for the border
// Fill the indices and the colors for the border.
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));
}

if (fill_center) {
//fill the indices and the colors for the center
//Fill the indices and the colors for the center.
for (int index = 0; index < ring_vert_count / 2; index += 2) {
int i = index;
//poly 1
// Polygon 1.
indices.push_back(vert_offset + i);
indices.push_back(vert_offset + ring_vert_count - 4 - i);
indices.push_back(vert_offset + i + 2);
//poly 2
// Polygon 2.
indices.push_back(vert_offset + i);
indices.push_back(vert_offset + ring_vert_count - 2 - i);
indices.push_back(vert_offset + ring_vert_count - 4 - i);
}
}
}

inline void adapt_values(int p_index_a, int p_index_b, int *adapted_values, const int *p_values, const real_t p_width, const int p_max_a, const int p_max_b) {
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) {
float factor;
int newValue;
real_t factor;
real_t new_value;

factor = (float)p_width / (float)(p_values[p_index_a] + p_values[p_index_b]);
factor = (real_t)p_width / (real_t)(p_values[p_index_a] + p_values[p_index_b]);

newValue = (int)(p_values[p_index_a] * factor);
if (newValue < adapted_values[p_index_a]) {
adapted_values[p_index_a] = newValue;
new_value = (p_values[p_index_a] * factor);
if (new_value < adapted_values[p_index_a]) {
adapted_values[p_index_a] = new_value;
}
newValue = (int)(p_values[p_index_b] * factor);
if (newValue < adapted_values[p_index_b]) {
adapted_values[p_index_b] = newValue;
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]);
Expand All @@ -658,7 +658,6 @@ Rect2 StyleBoxFlat::get_draw_rect(const Rect2 &p_rect) const {
}

void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
//PREPARATIONS
bool draw_border = (border_width[0] > 0) || (border_width[1] > 0) || (border_width[2] > 0) || (border_width[3] > 0);
bool draw_shadow = (shadow_size > 0);
if (!draw_border && !draw_center && !draw_shadow) {
Expand All @@ -672,23 +671,22 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {

bool rounded_corners = (corner_radius[0] > 0) || (corner_radius[1] > 0) || (corner_radius[2] > 0) || (corner_radius[3] > 0);
bool aa_on = rounded_corners && anti_aliased;
float aa_size_grow = 0.5 * ((float)aa_size + 1.0);

bool blend_on = blend_border && draw_border;

Color border_color_alpha = Color(border_color.r, border_color.g, border_color.b, 0);
Color border_color_blend = (draw_center ? bg_color : border_color_alpha);
Color border_color_inner = blend_on ? border_color_blend : border_color;

//adapt borders (prevent weird overlapping/glitchy drawings)
int width = MAX(style_rect.size.width, 0);
int height = MAX(style_rect.size.height, 0);
int adapted_border[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
// Adapt borders (prevent weird overlapping/glitchy drawings).
real_t width = MAX(style_rect.size.width, 0);
real_t height = MAX(style_rect.size.height, 0);
real_t adapted_border[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
adapt_values(MARGIN_TOP, MARGIN_BOTTOM, adapted_border, border_width, height, height, height);
adapt_values(MARGIN_LEFT, MARGIN_RIGHT, adapted_border, border_width, width, width, width);

//adapt corners (prevent weird overlapping/glitchy drawings)
int adapted_corner[4] = { INT_MAX, INT_MAX, INT_MAX, INT_MAX };
// Adapt corners (prevent weird overlapping/glitchy drawings).
real_t adapted_corner[4] = { 1000000.0, 1000000.0, 1000000.0, 1000000.0 };
adapt_values(CORNER_TOP_RIGHT, CORNER_BOTTOM_RIGHT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]);
adapt_values(CORNER_TOP_LEFT, CORNER_BOTTOM_LEFT, adapted_corner, corner_radius, height, height - adapted_border[MARGIN_BOTTOM], height - adapted_border[MARGIN_TOP]);
adapt_values(CORNER_TOP_LEFT, CORNER_TOP_RIGHT, adapted_corner, corner_radius, width, width - adapted_border[MARGIN_RIGHT], width - adapted_border[MARGIN_LEFT]);
Expand All @@ -700,7 +698,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
if (aa_on) {
for (int i = 0; i < 4; i++) {
if (border_width[i] > 0) {
border_style_rect = border_style_rect.grow_margin((Margin)i, -aa_size_grow);
border_style_rect = border_style_rect.grow_margin((Margin)i, -aa_size);
}
}
}
Expand All @@ -710,7 +708,7 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
Vector<Color> colors;
Vector<Point2> uvs;

//DRAW SHADOW
// Create shadow
if (draw_shadow) {
Rect2 shadow_inner_rect = style_rect;
shadow_inner_rect.position += shadow_offset;
Expand All @@ -729,35 +727,35 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {
}
}

//DRAW border
if (draw_border) {
// Create border (no AA).
if (draw_border && !aa_on) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
border_style_rect, infill_rect, border_color_inner, border_color, corner_detail);
}

//DRAW INFILL
// Create infill (no AA).
if (draw_center && (!aa_on || blend_on || !draw_border)) {
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
infill_rect, infill_rect, bg_color, bg_color, corner_detail, true);
}

if (aa_on) {
int aa_border_width[4];
int aa_fill_width[4];
real_t aa_border_width[4];
real_t aa_fill_width[4];
if (draw_border) {
for (int i = 0; i < 4; i++) {
if (border_width[i] > 0) {
aa_border_width[i] = aa_size_grow;
aa_border_width[i] = aa_size;
aa_fill_width[i] = 0;
} else {
aa_border_width[i] = 0;
aa_fill_width[i] = aa_size_grow;
aa_fill_width[i] = aa_size;
}
}
} else {
for (int i = 0; i < 4; i++) {
aa_border_width[i] = 0;
aa_fill_width[i] = aa_size_grow;
aa_fill_width[i] = aa_size;
}
}

Expand All @@ -766,45 +764,58 @@ void StyleBoxFlat::draw(RID p_canvas_item, const Rect2 &p_rect) const {

if (draw_center) {
if (!blend_on && draw_border) {
//DRAW INFILL WITHIN BORDER AA
Rect2 infill_inner_rect_aa = infill_inner_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP],
aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]);
// Create infill within AA border.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
infill_inner_rect, infill_inner_rect, bg_color, bg_color, corner_detail, true);
infill_inner_rect_aa, infill_inner_rect_aa, bg_color, bg_color, corner_detail, true);
}

if (!blend_on || !draw_border) {
Rect2 infill_aa_rect = infill_rect.grow_individual(aa_fill_width[MARGIN_LEFT], aa_fill_width[MARGIN_TOP],
Rect2 infill_rect_aa = infill_rect.grow_individual(aa_fill_width[MARGIN_LEFT], aa_fill_width[MARGIN_TOP],
aa_fill_width[MARGIN_RIGHT], aa_fill_width[MARGIN_BOTTOM]);

Color alpha_bg = Color(bg_color.r, bg_color.g, bg_color.b, 0);

//INFILL AA
// Create infill fake AA gradient.
draw_ring(verts, indices, colors, style_rect, adapted_corner,
infill_aa_rect, infill_rect, bg_color, alpha_bg, corner_detail);
infill_rect_aa, infill_rect, bg_color, alpha_bg, corner_detail);
}
}

if (draw_border) {
Rect2 infill_rect_aa = infill_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP],
aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]);
Rect2 style_rect_aa = style_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP],
aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]);
Rect2 border_style_rect_aa = border_style_rect.grow_individual(aa_border_width[MARGIN_LEFT], aa_border_width[MARGIN_TOP],
aa_border_width[MARGIN_RIGHT], aa_border_width[MARGIN_BOTTOM]);

// Create border.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
border_style_rect_aa, ((blend_on) ? infill_rect : infill_rect_aa), border_color_inner, border_color, corner_detail);

if (!blend_on) {
//DRAW INNER BORDER AA
// Create inner border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
infill_rect, infill_inner_rect, border_color_blend, border_color, corner_detail);
infill_rect_aa, infill_rect, border_color_blend, border_color, corner_detail);
}

//DRAW OUTER BORDER AA
// Create outer border fake AA gradient.
draw_ring(verts, indices, colors, border_style_rect, adapted_corner,
style_rect, border_style_rect, border_color, border_color_alpha, corner_detail);
style_rect_aa, border_style_rect_aa, border_color, border_color_alpha, corner_detail);
}
}

//COMPUTE UV COORDINATES
Rect2 uv_rect = style_rect.grow(aa_on ? aa_size_grow : 0);
// Compute UV coordinates.
Rect2 uv_rect = style_rect.grow(aa_on ? aa_size : 0);
uvs.resize(verts.size());
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;
}

//DRAWING
// Draw stylebox.
VisualServer *vs = VisualServer::get_singleton();
vs->canvas_item_add_triangle_array(p_canvas_item, indices, verts, colors, uvs);
}
Expand Down Expand Up @@ -897,7 +908,7 @@ void StyleBoxFlat::_bind_methods() {

ADD_GROUP("Anti Aliasing", "anti_aliasing_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "anti_aliasing"), "set_anti_aliased", "is_anti_aliased");
ADD_PROPERTY(PropertyInfo(Variant::INT, "anti_aliasing_size", PROPERTY_HINT_RANGE, "1,5,1"), "set_aa_size", "get_aa_size");
ADD_PROPERTY(PropertyInfo(Variant::REAL, "anti_aliasing_size", PROPERTY_HINT_RANGE, "0.01,10,0.001"), "set_aa_size", "get_aa_size");
}

StyleBoxFlat::StyleBoxFlat() {
Expand All @@ -912,7 +923,7 @@ StyleBoxFlat::StyleBoxFlat() {
shadow_size = 0;
shadow_offset = Point2(0, 0);
corner_detail = 8;
aa_size = 1;
aa_size = 0.625;

border_width[0] = 0;
border_width[1] = 0;
Expand Down
Loading