mirror of
https://github.com/emilk/egui.git
synced 2026-08-30 05:10:03 -04:00
1101
epaint/src/bezier.rs
Normal file
1101
epaint/src/bezier.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -87,6 +87,7 @@
|
||||
#![allow(clippy::float_cmp)]
|
||||
#![allow(clippy::manual_range_contains)]
|
||||
|
||||
mod bezier;
|
||||
pub mod color;
|
||||
pub mod image;
|
||||
mod mesh;
|
||||
@@ -104,6 +105,7 @@ pub mod textures;
|
||||
pub mod util;
|
||||
|
||||
pub use {
|
||||
bezier::{CubicBezierShape, QuadraticBezierShape},
|
||||
color::{Color32, Rgba},
|
||||
image::{AlphaImage, ColorImage, ImageData, ImageDelta},
|
||||
mesh::{Mesh, Mesh16, Vertex},
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::{
|
||||
text::{FontId, Fonts, Galley},
|
||||
Color32, Mesh, Stroke,
|
||||
};
|
||||
use crate::{CubicBezierShape, QuadraticBezierShape};
|
||||
use emath::*;
|
||||
|
||||
/// A paint primitive such as a circle or a piece of text.
|
||||
@@ -26,6 +27,8 @@ pub enum Shape {
|
||||
Rect(RectShape),
|
||||
Text(TextShape),
|
||||
Mesh(Mesh),
|
||||
QuadraticBezier(QuadraticBezierShape),
|
||||
CubicBezier(CubicBezierShape),
|
||||
}
|
||||
|
||||
/// ## Constructors
|
||||
@@ -187,6 +190,16 @@ impl Shape {
|
||||
Shape::Mesh(mesh) => {
|
||||
mesh.translate(delta);
|
||||
}
|
||||
Shape::QuadraticBezier(bezier_shape) => {
|
||||
bezier_shape.points[0] += delta;
|
||||
bezier_shape.points[1] += delta;
|
||||
bezier_shape.points[2] += delta;
|
||||
}
|
||||
Shape::CubicBezier(cubie_curve) => {
|
||||
for p in &mut cubie_curve.points {
|
||||
*p += delta;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,5 +43,13 @@ pub fn adjust_colors(shape: &mut Shape, adjust_color: &impl Fn(&mut Color32)) {
|
||||
adjust_color(&mut v.color);
|
||||
}
|
||||
}
|
||||
Shape::QuadraticBezier(quatratic) => {
|
||||
adjust_color(&mut quatratic.fill);
|
||||
adjust_color(&mut quatratic.stroke.color);
|
||||
}
|
||||
Shape::CubicBezier(bezier) => {
|
||||
adjust_color(&mut bezier.fill);
|
||||
adjust_color(&mut bezier.stroke.color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -195,8 +195,12 @@ impl PaintStats {
|
||||
self.add(shape);
|
||||
}
|
||||
}
|
||||
Shape::Noop | Shape::Circle { .. } | Shape::LineSegment { .. } | Shape::Rect { .. } => {
|
||||
}
|
||||
Shape::Noop
|
||||
| Shape::Circle { .. }
|
||||
| Shape::LineSegment { .. }
|
||||
| Shape::Rect { .. }
|
||||
| Shape::CubicBezier(_)
|
||||
| Shape::QuadraticBezier(_) => {}
|
||||
Shape::Path(path_shape) => {
|
||||
self.shape_path += AllocInfo::from_slice(&path_shape.points);
|
||||
}
|
||||
|
||||
@@ -286,6 +286,12 @@ pub struct TessellationOptions {
|
||||
|
||||
/// If true, no clipping will be done.
|
||||
pub debug_ignore_clip_rects: bool,
|
||||
|
||||
/// The maximum distance between the original curve and the flattened curve.
|
||||
pub bezier_tolerence: f32,
|
||||
|
||||
/// The default value will be 1.0e-5, it will be used during float compare.
|
||||
pub epsilon: f32,
|
||||
}
|
||||
|
||||
impl Default for TessellationOptions {
|
||||
@@ -299,6 +305,8 @@ impl Default for TessellationOptions {
|
||||
debug_paint_text_rects: false,
|
||||
debug_paint_clip_rects: false,
|
||||
debug_ignore_clip_rects: false,
|
||||
bezier_tolerence: 0.1,
|
||||
epsilon: 1.0e-5,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -710,9 +718,93 @@ impl Tessellator {
|
||||
}
|
||||
self.tessellate_text(tex_size, text_shape, out);
|
||||
}
|
||||
Shape::QuadraticBezier(quadratic_shape) => {
|
||||
self.tessellate_quadratic_bezier(quadratic_shape, out);
|
||||
}
|
||||
Shape::CubicBezier(cubic_shape) => self.tessellate_cubic_bezier(cubic_shape, out),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn tessellate_quadratic_bezier(
|
||||
&mut self,
|
||||
quadratic_shape: QuadraticBezierShape,
|
||||
out: &mut Mesh,
|
||||
) {
|
||||
let options = &self.options;
|
||||
let clip_rect = self.clip_rect;
|
||||
|
||||
if options.coarse_tessellation_culling
|
||||
&& !quadratic_shape.bounding_rect().intersects(clip_rect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let points = quadratic_shape.flatten(Some(options.bezier_tolerence));
|
||||
|
||||
self.tessellate_bezier_complete(
|
||||
&points,
|
||||
quadratic_shape.fill,
|
||||
quadratic_shape.closed,
|
||||
quadratic_shape.stroke,
|
||||
out,
|
||||
);
|
||||
}
|
||||
|
||||
pub(crate) fn tessellate_cubic_bezier(
|
||||
&mut self,
|
||||
cubic_shape: CubicBezierShape,
|
||||
out: &mut Mesh,
|
||||
) {
|
||||
let options = &self.options;
|
||||
let clip_rect = self.clip_rect;
|
||||
if options.coarse_tessellation_culling && !cubic_shape.bounding_rect().intersects(clip_rect)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
let points_vec =
|
||||
cubic_shape.flatten_closed(Some(options.bezier_tolerence), Some(options.epsilon));
|
||||
|
||||
for points in points_vec {
|
||||
self.tessellate_bezier_complete(
|
||||
&points,
|
||||
cubic_shape.fill,
|
||||
cubic_shape.closed,
|
||||
cubic_shape.stroke,
|
||||
out,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn tessellate_bezier_complete(
|
||||
&mut self,
|
||||
points: &[Pos2],
|
||||
fill: Color32,
|
||||
closed: bool,
|
||||
stroke: Stroke,
|
||||
out: &mut Mesh,
|
||||
) {
|
||||
self.scratchpad_path.clear();
|
||||
if closed {
|
||||
self.scratchpad_path.add_line_loop(points);
|
||||
} else {
|
||||
self.scratchpad_path.add_open_points(points);
|
||||
}
|
||||
if fill != Color32::TRANSPARENT {
|
||||
crate::epaint_assert!(
|
||||
closed,
|
||||
"You asked to fill a path that is not closed. That makes no sense."
|
||||
);
|
||||
self.scratchpad_path.fill(fill, &self.options, out);
|
||||
}
|
||||
let typ = if closed {
|
||||
PathType::Closed
|
||||
} else {
|
||||
PathType::Open
|
||||
};
|
||||
self.scratchpad_path.stroke(typ, stroke, &self.options, out);
|
||||
}
|
||||
|
||||
pub(crate) fn tessellate_path(&mut self, path_shape: PathShape, out: &mut Mesh) {
|
||||
if path_shape.points.len() < 2 {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user