diff --git a/Cargo.lock b/Cargo.lock index a81728d9..c3767604 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -950,6 +950,7 @@ dependencies = [ "atomic_refcell", "bytemuck", "cint", + "criterion", "emath", "nohash-hasher", "parking_lot", diff --git a/epaint/CHANGELOG.md b/epaint/CHANGELOG.md index a2088af3..90b9522c 100644 --- a/epaint/CHANGELOG.md +++ b/epaint/CHANGELOG.md @@ -5,6 +5,7 @@ All notable changes to the epaint crate will be documented in this file. ## Unreleased +* Added `Shape::dashed_line_many` ([#1027](https://github.com/emilk/egui/pull/1027)). ## 0.16.0 - 2021-12-29 * Anti-alias path ends ([#893](https://github.com/emilk/egui/pull/893)). diff --git a/epaint/Cargo.toml b/epaint/Cargo.toml index 2e406ccb..debfc233 100644 --- a/epaint/Cargo.toml +++ b/epaint/Cargo.toml @@ -63,3 +63,10 @@ single_threaded = ["atomic_refcell"] # Only needed if you plan to use the same fonts from multiple threads. # It comes with a minor performance impact. multi_threaded = ["parking_lot"] + +[dev-dependencies] +criterion = { version = "0.3", default-features = false } + +[[bench]] +name = "benchmark" +harness = false diff --git a/epaint/benches/benchmark.rs b/epaint/benches/benchmark.rs new file mode 100644 index 00000000..3ae5d901 --- /dev/null +++ b/epaint/benches/benchmark.rs @@ -0,0 +1,43 @@ +use criterion::{black_box, criterion_group, criterion_main, Criterion}; + +use epaint::{pos2, Color32, Shape, Stroke}; + +fn single_dashed_lines(c: &mut Criterion) { + c.bench_function("single_dashed_lines", move |b| { + b.iter(|| { + let mut v = Vec::new(); + + let line = [pos2(0.0, 0.0), pos2(50.0, 0.0), pos2(100.0, 1.0)]; + + for _ in 0..100 { + v.extend(Shape::dashed_line( + &line, + Stroke::new(1.5, Color32::RED), + 10.0, + 2.5, + )); + } + + black_box(v); + }); + }); +} + +fn many_dashed_lines(c: &mut Criterion) { + c.bench_function("many_dashed_lines", move |b| { + b.iter(|| { + let mut v = Vec::new(); + + let line = [pos2(0.0, 0.0), pos2(50.0, 0.0), pos2(100.0, 1.0)]; + + for _ in 0..100 { + Shape::dashed_line_many(&line, Stroke::new(1.5, Color32::RED), 10.0, 2.5, &mut v); + } + + black_box(v); + }); + }); +} + +criterion_group!(benches, single_dashed_lines, many_dashed_lines); +criterion_main!(benches); diff --git a/epaint/src/shape.rs b/epaint/src/shape.rs index dba2b243..fa52260e 100644 --- a/epaint/src/shape.rs +++ b/epaint/src/shape.rs @@ -75,6 +75,18 @@ impl Shape { shapes } + /// Turn a line into dashes. If you need to create many dashed lines use this instead of + /// [`Self::dashed_line`] + pub fn dashed_line_many( + points: &[Pos2], + stroke: impl Into, + dash_length: f32, + gap_length: f32, + shapes: &mut Vec, + ) { + dashes_from_line(points, stroke.into(), dash_length, gap_length, shapes); + } + /// A convex polygon with a fill and optional stroke. #[inline] pub fn convex_polygon( @@ -425,27 +437,27 @@ fn dashes_from_line( let end = window[1]; let vector = end - start; let segment_length = vector.length(); + + let mut start_point = start; while position_on_segment < segment_length { let new_point = start + vector * (position_on_segment / segment_length); if drawing_dash { // This is the end point. - if let Shape::Path(PathShape { points, .. }) = shapes.last_mut().unwrap() { - points.push(new_point); - } + shapes.push(Shape::line_segment([start_point, new_point], stroke)); position_on_segment += gap_length; } else { // Start a new dash. - shapes.push(Shape::line(vec![new_point], stroke)); + start_point = new_point; position_on_segment += dash_length; } drawing_dash = !drawing_dash; } + // If the segment ends and the dash is not finished, add the segment's end point. if drawing_dash { - if let Shape::Path(PathShape { points, .. }) = shapes.last_mut().unwrap() { - points.push(end); - } + shapes.push(Shape::line_segment([start_point, end], stroke)); } + position_on_segment -= segment_length; }); }