Optimize meshing

This commit is contained in:
Emil Ernerfeldt 2020-05-11 13:11:01 +02:00
parent 6bee26ca59
commit 4fcea59929
8 changed files with 89 additions and 46 deletions

View file

@ -157,8 +157,8 @@ fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) {
));
// Draw a minus:
ui.add_paint_cmd(PaintCmd::Line {
points: vec![
ui.add_paint_cmd(PaintCmd::LineSegment {
points: [
pos2(small_icon_rect.left(), small_icon_rect.center().y),
pos2(small_icon_rect.right(), small_icon_rect.center().y),
],
@ -168,8 +168,8 @@ fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) {
if !state.open {
// Draw it as a plus:
ui.add_paint_cmd(PaintCmd::Line {
points: vec![
ui.add_paint_cmd(PaintCmd::LineSegment {
points: [
pos2(small_icon_rect.center().x, small_icon_rect.top()),
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
],

View file

@ -256,7 +256,7 @@ fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) {
while w < 12.0 {
ui.add_paint_cmd(PaintCmd::line_segment(
(pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)),
[pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)],
color,
width,
));

View file

@ -8,6 +8,7 @@ pub struct Vec2 {
pub y: f32,
}
#[inline(always)]
pub fn vec2(x: f32, y: f32) -> Vec2 {
Vec2 { x, y }
}
@ -39,6 +40,7 @@ impl Vec2 {
}
}
#[inline(always)]
pub fn rot90(self) -> Self {
vec2(self.y, -self.x)
}
@ -212,6 +214,13 @@ pub fn pos2(x: f32, y: f32) -> Pos2 {
}
impl Pos2 {
pub fn to_vec2(self) -> Vec2 {
Vec2 {
x: self.x,
y: self.y,
}
}
pub fn dist(self: Self, other: Self) -> f32 {
(self - other).length()
}

View file

@ -147,6 +147,7 @@ impl Path {
self.0.clear();
}
#[inline(always)]
pub fn add_point(&mut self, pos: Pos2, normal: Vec2) {
self.0.push(PathPoint { pos, normal });
}
@ -160,10 +161,20 @@ impl Path {
}
}
pub fn add_line_segment(&mut self, points: [Pos2; 2]) {
let normal = (points[1] - points[0]).normalized().rot90();
self.add_point(points[0], normal);
self.add_point(points[1], normal);
}
pub fn add_line(&mut self, points: &[Pos2]) {
let n = points.len();
assert!(n >= 2);
if n == 2 {
// Common case optimization:
self.add_line_segment([points[0], points[1]]);
} else {
self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
for i in 1..n - 1 {
let n0 = (points[i] - points[i - 1]).normalized().rot90();
@ -177,6 +188,7 @@ impl Path {
(points[n - 1] - points[n - 2]).normalized().rot90(),
);
}
}
pub fn add_rectangle(&mut self, rect: Rect) {
let min = rect.min;
@ -387,7 +399,16 @@ pub fn paint_path(
// ----------------------------------------------------------------------------
pub fn mesh_command(options: MesherOptions, fonts: &Fonts, command: PaintCmd, out_mesh: &mut Mesh) {
/// path: only used to reuse memory
pub fn mesh_command(
path: &mut Path,
options: MesherOptions,
fonts: &Fonts,
command: PaintCmd,
out_mesh: &mut Mesh,
) {
path.clear();
match command {
PaintCmd::Circle {
center,
@ -395,7 +416,6 @@ pub fn mesh_command(options: MesherOptions, fonts: &Fonts, command: PaintCmd, ou
outline,
radius,
} => {
let mut path = Path::default();
path.add_circle(center, radius);
if let Some(color) = fill_color {
fill_closed_path(out_mesh, options, &path.0, color);
@ -414,14 +434,21 @@ pub fn mesh_command(options: MesherOptions, fonts: &Fonts, command: PaintCmd, ou
PaintCmd::Mesh(mesh) => {
out_mesh.append(&mesh);
}
PaintCmd::Line {
PaintCmd::LineSegment {
points,
color,
width,
} => {
path.add_line_segment(points);
paint_path(out_mesh, options, Open, &path.0, color, width);
}
PaintCmd::LinePath {
points,
color,
width,
} => {
let n = points.len();
if n >= 2 {
let mut path = Path::default();
path.add_line(&points);
paint_path(out_mesh, options, Open, &path.0, color, width);
}
@ -462,7 +489,6 @@ pub fn mesh_command(options: MesherOptions, fonts: &Fonts, command: PaintCmd, ou
rect.min = rect.min.max(pos2(-1e7, -1e7));
rect.max = rect.max.min(pos2(1e7, 1e7));
let mut path = Path::default();
path.add_rounded_rectangle(rect, corner_radius);
if let Some(fill_color) = fill_color {
fill_closed_path(out_mesh, options, &path.0, fill_color);
@ -512,6 +538,8 @@ pub fn mesh_paint_commands(
fonts: &Fonts,
commands: Vec<(Rect, PaintCmd)>,
) -> Vec<(Rect, Mesh)> {
let mut reused_path = Path::default();
let mut batches = PaintBatches::default();
for (clip_rect, cmd) in commands {
// TODO: cull(clip_rect, cmd)
@ -522,6 +550,7 @@ pub fn mesh_paint_commands(
if options.debug_paint_clip_rects && !clip_rect.is_empty() {
let out_mesh = &mut batches.last_mut().unwrap().1;
mesh_command(
&mut reused_path,
options,
fonts,
PaintCmd::Rect {
@ -536,7 +565,7 @@ pub fn mesh_paint_commands(
}
let out_mesh = &mut batches.last_mut().unwrap().1;
mesh_command(options, fonts, cmd, out_mesh);
mesh_command(&mut reused_path, options, fonts, cmd, out_mesh);
}
batches

View file

@ -78,7 +78,12 @@ pub enum PaintCmd {
outline: Option<Outline>,
radius: f32,
},
Line {
LineSegment {
points: [Pos2; 2],
color: Color,
width: f32,
},
LinePath {
points: Vec<Pos2>,
color: Color,
width: f32,
@ -111,9 +116,9 @@ pub enum PaintCmd {
}
impl PaintCmd {
pub fn line_segment(seg: (Pos2, Pos2), color: Color, width: f32) -> Self {
Self::Line {
points: vec![seg.0, seg.1],
pub fn line_segment(points: [Pos2; 2], color: Color, width: f32) -> Self {
Self::LineSegment {
points,
color,
width,
}

View file

@ -369,17 +369,17 @@ impl Ui {
if too_wide {
self.add_paint_cmd(PaintCmd::line_segment(
(rect.left_top(), rect.left_bottom()),
[rect.left_top(), rect.left_bottom()],
color,
width,
));
self.add_paint_cmd(PaintCmd::line_segment(
(rect.left_center(), rect.right_center()),
[rect.left_center(), rect.right_center()],
color,
width,
));
self.add_paint_cmd(PaintCmd::line_segment(
(rect.right_top(), rect.right_bottom()),
[rect.right_top(), rect.right_bottom()],
color,
width,
));
@ -387,17 +387,17 @@ impl Ui {
if too_high {
self.add_paint_cmd(PaintCmd::line_segment(
(rect.left_top(), rect.right_top()),
[rect.left_top(), rect.right_top()],
color,
width,
));
self.add_paint_cmd(PaintCmd::line_segment(
(rect.center_top(), rect.center_bottom()),
[rect.center_top(), rect.center_bottom()],
color,
width,
));
self.add_paint_cmd(PaintCmd::line_segment(
(rect.left_bottom(), rect.right_bottom()),
[rect.left_bottom(), rect.right_bottom()],
color,
width,
));
@ -594,11 +594,11 @@ impl Ui {
let line_start = child_rect.min - indent * 0.5;
let line_start = line_start.round(); // TODO: round to pixel instead
let line_end = pos2(line_start.x, line_start.y + size.y - 8.0);
self.add_paint_cmd(PaintCmd::Line {
points: vec![line_start, line_end],
color: gray(150, 255),
width: self.style.line_width,
});
self.add_paint_cmd(PaintCmd::line_segment(
[line_start, line_end],
gray(150, 255),
self.style.line_width,
));
self.reserve_space(indent + size, None)
}

View file

@ -160,11 +160,11 @@ impl Widget for Hyperlink {
let y = ui.round_to_pixel(y);
let min_x = pos.x + fragment.min_x();
let max_x = pos.x + fragment.max_x();
ui.add_paint_cmd(PaintCmd::Line {
points: vec![pos2(min_x, y), pos2(max_x, y)],
ui.add_paint_cmd(PaintCmd::line_segment(
[pos2(min_x, y), pos2(max_x, y)],
color,
width: ui.style().line_width,
});
ui.style().line_width,
));
}
}
@ -284,7 +284,7 @@ impl<'a> Widget for Checkbox<'a> {
let stroke_color = ui.style().interact(&interact).stroke_color;
if *self.checked {
ui.add_paint_cmd(PaintCmd::Line {
ui.add_paint_cmd(PaintCmd::LinePath {
points: vec![
pos2(small_icon_rect.left(), small_icon_rect.center().y),
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
@ -422,7 +422,7 @@ impl Widget for Separator {
Direction::Horizontal => {
let interact = ui.reserve_space(vec2(self.min_spacing, available_space.y), None);
(
vec![
[
pos2(interact.rect.center().x, interact.rect.top() - extra),
pos2(interact.rect.center().x, interact.rect.bottom() + extra),
],
@ -432,7 +432,7 @@ impl Widget for Separator {
Direction::Vertical => {
let interact = ui.reserve_space(vec2(available_space.x, self.min_spacing), None);
(
vec![
[
pos2(interact.rect.left() - extra, interact.rect.center().y),
pos2(interact.rect.right() + extra, interact.rect.center().y),
],
@ -440,7 +440,7 @@ impl Widget for Separator {
)
}
};
ui.add_paint_cmd(PaintCmd::Line {
ui.add_paint_cmd(PaintCmd::LineSegment {
points,
color: self.color,
width: self.line_width,

View file

@ -96,7 +96,7 @@ impl<'t> Widget for TextEdit<'t> {
interact.rect.min
};
ui.add_paint_cmd(PaintCmd::line_segment(
(cursor_pos, cursor_pos + vec2(0.0, line_spacing)),
[cursor_pos, cursor_pos + vec2(0.0, line_spacing)],
color::WHITE,
ui.style().text_cursor_width,
));