Precompute rounded vertices (#1547)

Co-authored-by: Daniel Buch Hansen <boogiewasthere@gmail.com>
This commit is contained in:
Emil Ernerfeldt 2022-04-30 13:14:33 +02:00 committed by GitHub
parent 3a83a600bb
commit 8303523ccf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 345 additions and 22 deletions

View file

@ -21,6 +21,7 @@ All notable changes to the epaint crate will be documented in this file.
* MSRV (Minimum Supported Rust Version) is now `1.60.0` ([#1467](https://github.com/emilk/egui/pull/1467)). * MSRV (Minimum Supported Rust Version) is now `1.60.0` ([#1467](https://github.com/emilk/egui/pull/1467)).
* Renamed the feature `convert_bytemuck` to `bytemuck` ([#1467](https://github.com/emilk/egui/pull/1467)). * Renamed the feature `convert_bytemuck` to `bytemuck` ([#1467](https://github.com/emilk/egui/pull/1467)).
* Renamed the feature `serialize` to `serde` ([#1467](https://github.com/emilk/egui/pull/1467)). * Renamed the feature `serialize` to `serde` ([#1467](https://github.com/emilk/egui/pull/1467)).
* Optimize tessellation of circles and boxes with rounded corners ([#1547](https://github.com/emilk/egui/pull/1547)).
## 0.17.0 - 2022-02-22 ## 0.17.0 - 2022-02-22

View file

@ -7,7 +7,293 @@
use crate::*; use crate::*;
use emath::*; use emath::*;
use std::f32::consts::TAU;
// ----------------------------------------------------------------------------
#[allow(clippy::approx_constant)]
mod precomputed_vertices {
/*
fn main() {
let n = 64;
println!("pub const CIRCLE_{}: [Vec2; {}] = [", n, n+1);
for i in 0..=n {
let a = std::f64::consts::TAU * i as f64 / n as f64;
println!(" vec2({:.06}, {:.06}),", a.cos(), a.sin());
}
println!("];")
}
*/
use emath::{vec2, Vec2};
pub const CIRCLE_8: [Vec2; 9] = [
vec2(1.000000, 0.000000),
vec2(0.707107, 0.707107),
vec2(0.000000, 1.000000),
vec2(-0.707107, 0.707107),
vec2(-1.000000, 0.000000),
vec2(-0.707107, -0.707107),
vec2(0.000000, -1.000000),
vec2(0.707107, -0.707107),
vec2(1.000000, 0.000000),
];
pub const CIRCLE_16: [Vec2; 17] = [
vec2(1.000000, 0.000000),
vec2(0.923880, 0.382683),
vec2(0.707107, 0.707107),
vec2(0.382683, 0.923880),
vec2(0.000000, 1.000000),
vec2(-0.382684, 0.923880),
vec2(-0.707107, 0.707107),
vec2(-0.923880, 0.382683),
vec2(-1.000000, 0.000000),
vec2(-0.923880, -0.382683),
vec2(-0.707107, -0.707107),
vec2(-0.382684, -0.923880),
vec2(0.000000, -1.000000),
vec2(0.382684, -0.923879),
vec2(0.707107, -0.707107),
vec2(0.923880, -0.382683),
vec2(1.000000, 0.000000),
];
pub const CIRCLE_32: [Vec2; 33] = [
vec2(1.000000, 0.000000),
vec2(0.980785, 0.195090),
vec2(0.923880, 0.382683),
vec2(0.831470, 0.555570),
vec2(0.707107, 0.707107),
vec2(0.555570, 0.831470),
vec2(0.382683, 0.923880),
vec2(0.195090, 0.980785),
vec2(0.000000, 1.000000),
vec2(-0.195090, 0.980785),
vec2(-0.382683, 0.923880),
vec2(-0.555570, 0.831470),
vec2(-0.707107, 0.707107),
vec2(-0.831470, 0.555570),
vec2(-0.923880, 0.382683),
vec2(-0.980785, 0.195090),
vec2(-1.000000, 0.000000),
vec2(-0.980785, -0.195090),
vec2(-0.923880, -0.382683),
vec2(-0.831470, -0.555570),
vec2(-0.707107, -0.707107),
vec2(-0.555570, -0.831470),
vec2(-0.382683, -0.923880),
vec2(-0.195090, -0.980785),
vec2(-0.000000, -1.000000),
vec2(0.195090, -0.980785),
vec2(0.382683, -0.923880),
vec2(0.555570, -0.831470),
vec2(0.707107, -0.707107),
vec2(0.831470, -0.555570),
vec2(0.923880, -0.382683),
vec2(0.980785, -0.195090),
vec2(1.000000, -0.000000),
];
pub const CIRCLE_64: [Vec2; 65] = [
vec2(1.000000, 0.000000),
vec2(0.995185, 0.098017),
vec2(0.980785, 0.195090),
vec2(0.956940, 0.290285),
vec2(0.923880, 0.382683),
vec2(0.881921, 0.471397),
vec2(0.831470, 0.555570),
vec2(0.773010, 0.634393),
vec2(0.707107, 0.707107),
vec2(0.634393, 0.773010),
vec2(0.555570, 0.831470),
vec2(0.471397, 0.881921),
vec2(0.382683, 0.923880),
vec2(0.290285, 0.956940),
vec2(0.195090, 0.980785),
vec2(0.098017, 0.995185),
vec2(0.000000, 1.000000),
vec2(-0.098017, 0.995185),
vec2(-0.195090, 0.980785),
vec2(-0.290285, 0.956940),
vec2(-0.382683, 0.923880),
vec2(-0.471397, 0.881921),
vec2(-0.555570, 0.831470),
vec2(-0.634393, 0.773010),
vec2(-0.707107, 0.707107),
vec2(-0.773010, 0.634393),
vec2(-0.831470, 0.555570),
vec2(-0.881921, 0.471397),
vec2(-0.923880, 0.382683),
vec2(-0.956940, 0.290285),
vec2(-0.980785, 0.195090),
vec2(-0.995185, 0.098017),
vec2(-1.000000, 0.000000),
vec2(-0.995185, -0.098017),
vec2(-0.980785, -0.195090),
vec2(-0.956940, -0.290285),
vec2(-0.923880, -0.382683),
vec2(-0.881921, -0.471397),
vec2(-0.831470, -0.555570),
vec2(-0.773010, -0.634393),
vec2(-0.707107, -0.707107),
vec2(-0.634393, -0.773010),
vec2(-0.555570, -0.831470),
vec2(-0.471397, -0.881921),
vec2(-0.382683, -0.923880),
vec2(-0.290285, -0.956940),
vec2(-0.195090, -0.980785),
vec2(-0.098017, -0.995185),
vec2(-0.000000, -1.000000),
vec2(0.098017, -0.995185),
vec2(0.195090, -0.980785),
vec2(0.290285, -0.956940),
vec2(0.382683, -0.923880),
vec2(0.471397, -0.881921),
vec2(0.555570, -0.831470),
vec2(0.634393, -0.773010),
vec2(0.707107, -0.707107),
vec2(0.773010, -0.634393),
vec2(0.831470, -0.555570),
vec2(0.881921, -0.471397),
vec2(0.923880, -0.382683),
vec2(0.956940, -0.290285),
vec2(0.980785, -0.195090),
vec2(0.995185, -0.098017),
vec2(1.000000, -0.000000),
];
pub const CIRCLE_128: [Vec2; 129] = [
vec2(1.000000, 0.000000),
vec2(0.998795, 0.049068),
vec2(0.995185, 0.098017),
vec2(0.989177, 0.146730),
vec2(0.980785, 0.195090),
vec2(0.970031, 0.242980),
vec2(0.956940, 0.290285),
vec2(0.941544, 0.336890),
vec2(0.923880, 0.382683),
vec2(0.903989, 0.427555),
vec2(0.881921, 0.471397),
vec2(0.857729, 0.514103),
vec2(0.831470, 0.555570),
vec2(0.803208, 0.595699),
vec2(0.773010, 0.634393),
vec2(0.740951, 0.671559),
vec2(0.707107, 0.707107),
vec2(0.671559, 0.740951),
vec2(0.634393, 0.773010),
vec2(0.595699, 0.803208),
vec2(0.555570, 0.831470),
vec2(0.514103, 0.857729),
vec2(0.471397, 0.881921),
vec2(0.427555, 0.903989),
vec2(0.382683, 0.923880),
vec2(0.336890, 0.941544),
vec2(0.290285, 0.956940),
vec2(0.242980, 0.970031),
vec2(0.195090, 0.980785),
vec2(0.146730, 0.989177),
vec2(0.098017, 0.995185),
vec2(0.049068, 0.998795),
vec2(0.000000, 1.000000),
vec2(-0.049068, 0.998795),
vec2(-0.098017, 0.995185),
vec2(-0.146730, 0.989177),
vec2(-0.195090, 0.980785),
vec2(-0.242980, 0.970031),
vec2(-0.290285, 0.956940),
vec2(-0.336890, 0.941544),
vec2(-0.382683, 0.923880),
vec2(-0.427555, 0.903989),
vec2(-0.471397, 0.881921),
vec2(-0.514103, 0.857729),
vec2(-0.555570, 0.831470),
vec2(-0.595699, 0.803208),
vec2(-0.634393, 0.773010),
vec2(-0.671559, 0.740951),
vec2(-0.707107, 0.707107),
vec2(-0.740951, 0.671559),
vec2(-0.773010, 0.634393),
vec2(-0.803208, 0.595699),
vec2(-0.831470, 0.555570),
vec2(-0.857729, 0.514103),
vec2(-0.881921, 0.471397),
vec2(-0.903989, 0.427555),
vec2(-0.923880, 0.382683),
vec2(-0.941544, 0.336890),
vec2(-0.956940, 0.290285),
vec2(-0.970031, 0.242980),
vec2(-0.980785, 0.195090),
vec2(-0.989177, 0.146730),
vec2(-0.995185, 0.098017),
vec2(-0.998795, 0.049068),
vec2(-1.000000, 0.000000),
vec2(-0.998795, -0.049068),
vec2(-0.995185, -0.098017),
vec2(-0.989177, -0.146730),
vec2(-0.980785, -0.195090),
vec2(-0.970031, -0.242980),
vec2(-0.956940, -0.290285),
vec2(-0.941544, -0.336890),
vec2(-0.923880, -0.382683),
vec2(-0.903989, -0.427555),
vec2(-0.881921, -0.471397),
vec2(-0.857729, -0.514103),
vec2(-0.831470, -0.555570),
vec2(-0.803208, -0.595699),
vec2(-0.773010, -0.634393),
vec2(-0.740951, -0.671559),
vec2(-0.707107, -0.707107),
vec2(-0.671559, -0.740951),
vec2(-0.634393, -0.773010),
vec2(-0.595699, -0.803208),
vec2(-0.555570, -0.831470),
vec2(-0.514103, -0.857729),
vec2(-0.471397, -0.881921),
vec2(-0.427555, -0.903989),
vec2(-0.382683, -0.923880),
vec2(-0.336890, -0.941544),
vec2(-0.290285, -0.956940),
vec2(-0.242980, -0.970031),
vec2(-0.195090, -0.980785),
vec2(-0.146730, -0.989177),
vec2(-0.098017, -0.995185),
vec2(-0.049068, -0.998795),
vec2(-0.000000, -1.000000),
vec2(0.049068, -0.998795),
vec2(0.098017, -0.995185),
vec2(0.146730, -0.989177),
vec2(0.195090, -0.980785),
vec2(0.242980, -0.970031),
vec2(0.290285, -0.956940),
vec2(0.336890, -0.941544),
vec2(0.382683, -0.923880),
vec2(0.427555, -0.903989),
vec2(0.471397, -0.881921),
vec2(0.514103, -0.857729),
vec2(0.555570, -0.831470),
vec2(0.595699, -0.803208),
vec2(0.634393, -0.773010),
vec2(0.671559, -0.740951),
vec2(0.707107, -0.707107),
vec2(0.740951, -0.671559),
vec2(0.773010, -0.634393),
vec2(0.803208, -0.595699),
vec2(0.831470, -0.555570),
vec2(0.857729, -0.514103),
vec2(0.881921, -0.471397),
vec2(0.903989, -0.427555),
vec2(0.923880, -0.382683),
vec2(0.941544, -0.336890),
vec2(0.956940, -0.290285),
vec2(0.970031, -0.242980),
vec2(0.980785, -0.195090),
vec2(0.989177, -0.146730),
vec2(0.995185, -0.098017),
vec2(0.998795, -0.049068),
vec2(1.000000, -0.000000),
];
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
@ -50,13 +336,36 @@ impl Path {
} }
pub fn add_circle(&mut self, center: Pos2, radius: f32) { pub fn add_circle(&mut self, center: Pos2, radius: f32) {
let n = (radius * 4.0).round() as i32; // TODO: tweak a bit more use precomputed_vertices::*;
let n = n.clamp(4, 64);
self.reserve(n as usize); // These cutoffs are based on a high-dpi display. TODO: use pixels_per_point here?
for i in 0..n { // same cutoffs as in add_circle_quadrant
let angle = remap(i as f32, 0.0..=n as f32, 0.0..=TAU);
let normal = vec2(angle.cos(), angle.sin()); if radius <= 2.0 {
self.add_point(center + radius * normal, normal); self.0.extend(CIRCLE_8.iter().map(|&n| PathPoint {
pos: center + radius * n,
normal: n,
}));
} else if radius <= 5.0 {
self.0.extend(CIRCLE_16.iter().map(|&n| PathPoint {
pos: center + radius * n,
normal: n,
}));
} else if radius < 18.0 {
self.0.extend(CIRCLE_32.iter().map(|&n| PathPoint {
pos: center + radius * n,
normal: n,
}));
} else if radius < 50.0 {
self.0.extend(CIRCLE_64.iter().map(|&n| PathPoint {
pos: center + radius * n,
normal: n,
}));
} else {
self.0.extend(CIRCLE_128.iter().map(|&n| PathPoint {
pos: center + radius * n,
normal: n,
}));
} }
} }
@ -189,8 +498,7 @@ impl Path {
pub mod path { pub mod path {
//! Helpers for constructing paths //! Helpers for constructing paths
use crate::shape::Rounding; use crate::shape::Rounding;
use emath::*;
use super::*;
/// overwrites existing points /// overwrites existing points
pub fn rounded_rectangle(path: &mut Vec<Pos2>, rect: Rect, rounding: Rounding) { pub fn rounded_rectangle(path: &mut Vec<Pos2>, rect: Rect, rounding: Rounding) {
@ -236,19 +544,33 @@ pub mod path {
// - quadrant 3: right top // - quadrant 3: right top
// * angle 4 * TAU / 4 = right // * angle 4 * TAU / 4 = right
pub fn add_circle_quadrant(path: &mut Vec<Pos2>, center: Pos2, radius: f32, quadrant: f32) { pub fn add_circle_quadrant(path: &mut Vec<Pos2>, center: Pos2, radius: f32, quadrant: f32) {
// TODO: optimize with precalculated vertices for some radii ranges use super::precomputed_vertices::*;
let n = (radius * 0.75).round() as i32; // TODO: tweak a bit more // These cutoffs are based on a high-dpi display. TODO: use pixels_per_point here?
let n = n.clamp(2, 32); // same cutoffs as in add_circle
const RIGHT_ANGLE: f32 = TAU / 4.0;
path.reserve(n as usize + 1); if radius <= 0.0 {
for i in 0..=n { path.push(center);
let angle = remap( } else if radius <= 2.0 {
i as f32, let offset = quadrant as usize * 2;
0.0..=n as f32, let quadrant_vertices = &CIRCLE_8[offset..=offset + 2];
quadrant * RIGHT_ANGLE..=(quadrant + 1.0) * RIGHT_ANGLE, path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
); } else if radius <= 5.0 {
path.push(center + radius * Vec2::angled(angle)); let offset = quadrant as usize * 4;
let quadrant_vertices = &CIRCLE_16[offset..=offset + 4];
path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
} else if radius < 18.0 {
let offset = quadrant as usize * 8;
let quadrant_vertices = &CIRCLE_32[offset..=offset + 8];
path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
} else if radius < 50.0 {
let offset = quadrant as usize * 16;
let quadrant_vertices = &CIRCLE_64[offset..=offset + 16];
path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
} else {
let offset = quadrant as usize * 32;
let quadrant_vertices = &CIRCLE_128[offset..=offset + 32];
path.extend(quadrant_vertices.iter().map(|&n| center + radius * n));
} }
} }