Anti-alias path ends (#893)

Closes https://github.com/emilk/egui/issues/876
This commit is contained in:
Emil Ernerfeldt 2021-11-14 17:23:51 +01:00 committed by GitHub
parent a0b635dc21
commit 5fee6b7bc5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 26 deletions

View file

@ -5,6 +5,7 @@ All notable changes to the epaint crate will be documented in this file.
## Unreleased ## Unreleased
* `Rgba` now implements `Hash` ([#886](https://github.com/emilk/egui/pull/886)). * `Rgba` now implements `Hash` ([#886](https://github.com/emilk/egui/pull/886)).
* Anti-alias path ends ([#893](https://github.com/emilk/egui/pull/893)).
## 0.15.0 - 2021-10-24 ## 0.15.0 - 2021-10-24

View file

@ -377,11 +377,12 @@ fn stroke_path(
options: &TessellationOptions, options: &TessellationOptions,
out: &mut Mesh, out: &mut Mesh,
) { ) {
if stroke.width <= 0.0 || stroke.color == Color32::TRANSPARENT { let n = path.len() as u32;
if stroke.width <= 0.0 || stroke.color == Color32::TRANSPARENT || n < 2 {
return; return;
} }
let n = path.len() as u32;
let idx = out.vertices.len() as u32; let idx = out.vertices.len() as u32;
if options.anti_alias { if options.anti_alias {
@ -426,8 +427,7 @@ fn stroke_path(
i0 = i1; i0 = i1;
} }
} else { } else {
// thick line // thick anti-aliased line
// TODO: line caps for really thick lines?
/* /*
We paint the line using four edges: outer, inner, inner, outer We paint the line using four edges: outer, inner, inner, outer
@ -439,36 +439,119 @@ fn stroke_path(
. |-----| inner_rad . |-----| inner_rad
*/ */
out.reserve_triangles(6 * n as usize); let inner_rad = 0.5 * (stroke.width - options.aa_size);
out.reserve_vertices(4 * n as usize); let outer_rad = 0.5 * (stroke.width + options.aa_size);
let mut i0 = n - 1; match path_type {
for i1 in 0..n { PathType::Closed => {
let connect_with_previous = path_type == PathType::Closed || i1 > 0; out.reserve_triangles(6 * n as usize);
let inner_rad = 0.5 * (stroke.width - options.aa_size); out.reserve_vertices(4 * n as usize);
let outer_rad = 0.5 * (stroke.width + options.aa_size);
let p1 = &path[i1 as usize];
let p = p1.pos;
let n = p1.normal;
out.colored_vertex(p + n * outer_rad, color_outer);
out.colored_vertex(p + n * inner_rad, color_inner);
out.colored_vertex(p - n * inner_rad, color_inner);
out.colored_vertex(p - n * outer_rad, color_outer);
if connect_with_previous { let mut i0 = n - 1;
out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0); for i1 in 0..n {
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1); let p1 = &path[i1 as usize];
let p = p1.pos;
let n = p1.normal;
out.colored_vertex(p + n * outer_rad, color_outer);
out.colored_vertex(p + n * inner_rad, color_inner);
out.colored_vertex(p - n * inner_rad, color_inner);
out.colored_vertex(p - n * outer_rad, color_outer);
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1); out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2); out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2); out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3); out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
i0 = i1;
}
}
PathType::Open => {
// Anti-alias the ends by extruding the outer edge and adding
// two more triangles to each end:
// | aa | | aa |
// _________________ ___
// | \ added / | aa_size
// | \ ___p___ / | ___
// | | | |
// | | opa | |
// | | que | |
// | | | |
// (in the future it would be great with an option to add a circular end instead)
out.reserve_triangles(6 * n as usize + 4);
out.reserve_vertices(4 * n as usize);
{
let end = &path[0];
let p = end.pos;
let n = end.normal;
let back_extrude = n.rot90() * options.aa_size;
out.colored_vertex(p + n * outer_rad + back_extrude, color_outer);
out.colored_vertex(p + n * inner_rad, color_inner);
out.colored_vertex(p - n * inner_rad, color_inner);
out.colored_vertex(p - n * outer_rad + back_extrude, color_outer);
out.add_triangle(idx + 0, idx + 1, idx + 2);
out.add_triangle(idx + 0, idx + 2, idx + 3);
}
let mut i0 = 0;
for i1 in 1..n - 1 {
let point = &path[i1 as usize];
let p = point.pos;
let n = point.normal;
out.colored_vertex(p + n * outer_rad, color_outer);
out.colored_vertex(p + n * inner_rad, color_inner);
out.colored_vertex(p - n * inner_rad, color_inner);
out.colored_vertex(p - n * outer_rad, color_outer);
out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
i0 = i1;
}
{
let i1 = n - 1;
let end = &path[i1 as usize];
let p = end.pos;
let n = end.normal;
let back_extrude = -n.rot90() * options.aa_size;
out.colored_vertex(p + n * outer_rad + back_extrude, color_outer);
out.colored_vertex(p + n * inner_rad, color_inner);
out.colored_vertex(p - n * inner_rad, color_inner);
out.colored_vertex(p - n * outer_rad + back_extrude, color_outer);
out.add_triangle(idx + 4 * i0 + 0, idx + 4 * i0 + 1, idx + 4 * i1 + 0);
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i1 + 0, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 1, idx + 4 * i0 + 2, idx + 4 * i1 + 1);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 2, idx + 4 * i0 + 3, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i0 + 3, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
// The extension:
out.add_triangle(idx + 4 * i1 + 0, idx + 4 * i1 + 1, idx + 4 * i1 + 2);
out.add_triangle(idx + 4 * i1 + 0, idx + 4 * i1 + 2, idx + 4 * i1 + 3);
}
} }
i0 = i1;
} }
} }
} else { } else {
// not anti-aliased:
out.reserve_triangles(2 * n as usize); out.reserve_triangles(2 * n as usize);
out.reserve_vertices(2 * n as usize); out.reserve_vertices(2 * n as usize);