mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 13:20:05 -04:00
Fix anti-aliasing of filled paths with counter-clockwise winding order
Part of https://github.com/emilk/egui/issues/1226
This commit is contained in:
@@ -94,6 +94,8 @@ impl Shape {
|
||||
}
|
||||
|
||||
/// A convex polygon with a fill and optional stroke.
|
||||
///
|
||||
/// The most performant winding order is clockwise.
|
||||
#[inline]
|
||||
pub fn convex_polygon(
|
||||
points: Vec<Pos2>,
|
||||
@@ -259,6 +261,7 @@ impl From<CircleShape> for Shape {
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||
pub struct PathShape {
|
||||
/// Filled paths should prefer clockwise order.
|
||||
pub points: Vec<Pos2>,
|
||||
/// If true, connect the first and last of the points together.
|
||||
/// This is required if `fill != TRANSPARENT`.
|
||||
@@ -294,6 +297,8 @@ impl PathShape {
|
||||
}
|
||||
|
||||
/// A convex polygon with a fill and optional stroke.
|
||||
///
|
||||
/// The most performant winding order is clockwise.
|
||||
#[inline]
|
||||
pub fn convex_polygon(
|
||||
points: Vec<Pos2>,
|
||||
@@ -455,7 +460,7 @@ pub struct TextShape {
|
||||
/// This will NOT replace background color nor strikethrough/underline color.
|
||||
pub override_text_color: Option<Color32>,
|
||||
|
||||
/// Rotate text by this many radians clock-wise.
|
||||
/// Rotate text by this many radians clockwise.
|
||||
/// The pivot is `pos` (the upper left corner of the text).
|
||||
pub angle: f32,
|
||||
}
|
||||
|
||||
@@ -172,8 +172,12 @@ impl Path {
|
||||
}
|
||||
|
||||
/// The path is taken to be closed (i.e. returning to the start again).
|
||||
pub fn fill(&self, color: Color32, options: &TessellationOptions, out: &mut Mesh) {
|
||||
fill_closed_path(&self.0, color, options, out);
|
||||
///
|
||||
/// Calling this may reverse the vertices in the path if they are wrong winding order.
|
||||
///
|
||||
/// The preferred winding order is clockwise.
|
||||
pub fn fill(&mut self, color: Color32, options: &TessellationOptions, out: &mut Mesh) {
|
||||
fill_closed_path(&mut self.0, color, options, out);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -196,10 +200,10 @@ pub mod path {
|
||||
let min = rect.min;
|
||||
let max = rect.max;
|
||||
path.reserve(4);
|
||||
path.push(pos2(min.x, min.y));
|
||||
path.push(pos2(max.x, min.y));
|
||||
path.push(pos2(max.x, max.y));
|
||||
path.push(pos2(min.x, max.y));
|
||||
path.push(pos2(min.x, min.y)); // left top
|
||||
path.push(pos2(max.x, min.y)); // right top
|
||||
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);
|
||||
@@ -346,9 +350,27 @@ impl TessellationOptions {
|
||||
}
|
||||
}
|
||||
|
||||
fn cw_signed_area(path: &[PathPoint]) -> f64 {
|
||||
if let Some(last) = path.last() {
|
||||
let mut previous = last.pos;
|
||||
let mut area = 0.0;
|
||||
for p in path {
|
||||
area += (previous.x * p.pos.y - p.pos.x * previous.y) as f64;
|
||||
previous = p.pos;
|
||||
}
|
||||
area
|
||||
} else {
|
||||
0.0
|
||||
}
|
||||
}
|
||||
|
||||
/// Tessellate the given convex area into a polygon.
|
||||
///
|
||||
/// Calling this may reverse the vertices in the path if they are wrong winding order.
|
||||
///
|
||||
/// The preferred winding order is clockwise.
|
||||
fn fill_closed_path(
|
||||
path: &[PathPoint],
|
||||
path: &mut [PathPoint],
|
||||
color: Color32,
|
||||
options: &TessellationOptions,
|
||||
out: &mut Mesh,
|
||||
@@ -359,6 +381,14 @@ fn fill_closed_path(
|
||||
|
||||
let n = path.len() as u32;
|
||||
if options.anti_alias {
|
||||
if cw_signed_area(path) < 0.0 {
|
||||
// Wrong winding order - fix:
|
||||
path.reverse();
|
||||
for point in path.iter_mut() {
|
||||
point.normal = -point.normal;
|
||||
}
|
||||
}
|
||||
|
||||
out.reserve_triangles(3 * n as usize);
|
||||
out.reserve_vertices(2 * n as usize);
|
||||
let color_outer = Color32::TRANSPARENT;
|
||||
|
||||
Reference in New Issue
Block a user