Fix visual glitch on the right side of highly rounded rectangles (#4244)
* Part of https://github.com/emilk/egui/issues/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">
This commit is contained in:
parent
4d4cb3d20d
commit
947b5813d7
|
|
@ -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;
|
||||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue