Skip to content

Commit

Permalink
Fix visual glitch on the right side of highly rounded rectangles (#4244)
Browse files Browse the repository at this point in the history
* Part of #4238

When one side of a rectangle is all rounding we need to take care not to
produce duplicated vertices in the rectangle path generator.

The old code only handled three sides, but forgot the last side (the
right side).
The new code handles the right side, and also handles the other sides
more robustly (with a floating point eps) and efficiently (in a single
pass).

The glitch was most notable in shadows with a high blur width.

Examples of the glitch:

<img width="203" alt="Screenshot 2024-03-26 at 20 15 38"
src="https://github.com/emilk/egui/assets/1148717/dc1c0a06-35f0-4fda-a011-0e37d18454a0">

<img width="220" alt="Screenshot 2024-03-27 at 09 48 48"
src="https://github.com/emilk/egui/assets/1148717/c278b28e-c3f9-4c82-ba20-0480621efd2f">

<img width="33" alt="Screenshot 2024-03-27 at 09 49 21"
src="https://github.com/emilk/egui/assets/1148717/379ddf77-6590-4444-9c2e-67ab1e071f0f">
  • Loading branch information
emilk authored Mar 27, 2024
1 parent 4d4cb3d commit 947b581
Showing 1 changed file with 29 additions and 7 deletions.
36 changes: 29 additions & 7 deletions crates/epaint/src/tessellator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,7 @@ pub mod path {
let min = rect.min;
let max = rect.max;

let r = clamp_radius(rounding, rect);
let r = clamp_rounding(rounding, rect);

if r == Rounding::ZERO {
let min = rect.min;
Expand All @@ -531,11 +531,33 @@ pub mod path {
path.push(pos2(max.x, max.y)); // right bottom
path.push(pos2(min.x, max.y)); // left bottom
} else {
add_circle_quadrant(path, pos2(max.x - r.se, max.y - r.se), r.se, 0.0);
add_circle_quadrant(path, pos2(min.x + r.sw, max.y - r.sw), r.sw, 1.0);
add_circle_quadrant(path, pos2(min.x + r.nw, min.y + r.nw), r.nw, 2.0);
add_circle_quadrant(path, pos2(max.x - r.ne, min.y + r.ne), r.ne, 3.0);
path.dedup(); // We get duplicates for thin rectangles, producing visual artifats
// We need to avoid duplicated vertices, because that leads to visual artifacts later.
// Duplicated vertices can happen when one side is all rounding, with no straight edge between.
let eps = f32::EPSILON * rect.size().max_elem();

add_circle_quadrant(path, pos2(max.x - r.se, max.y - r.se), r.se, 0.0); // south east

if rect.width() <= r.se + r.sw + eps {
path.pop(); // avoid duplicated vertex
}

add_circle_quadrant(path, pos2(min.x + r.sw, max.y - r.sw), r.sw, 1.0); // south west

if rect.height() <= r.sw + r.nw + eps {
path.pop(); // avoid duplicated vertex
}

add_circle_quadrant(path, pos2(min.x + r.nw, min.y + r.nw), r.nw, 2.0); // north west

if rect.width() <= r.nw + r.ne + eps {
path.pop(); // avoid duplicated vertex
}

add_circle_quadrant(path, pos2(max.x - r.ne, min.y + r.ne), r.ne, 3.0); // north east

if rect.height() <= r.ne + r.se + eps {
path.pop(); // avoid duplicated vertex
}
}
}

Expand Down Expand Up @@ -589,7 +611,7 @@ pub mod path {
}

// Ensures the radius of each corner is within a valid range
fn clamp_radius(rounding: Rounding, rect: Rect) -> Rounding {
fn clamp_rounding(rounding: Rounding, rect: Rect) -> Rounding {
let half_width = rect.width() * 0.5;
let half_height = rect.height() * 0.5;
let max_cr = half_width.min(half_height);
Expand Down

0 comments on commit 947b581

Please sign in to comment.