Optimize meshing
This commit is contained in:
parent
6bee26ca59
commit
4fcea59929
8 changed files with 89 additions and 46 deletions
|
@ -157,8 +157,8 @@ fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) {
|
||||||
));
|
));
|
||||||
|
|
||||||
// Draw a minus:
|
// Draw a minus:
|
||||||
ui.add_paint_cmd(PaintCmd::Line {
|
ui.add_paint_cmd(PaintCmd::LineSegment {
|
||||||
points: vec![
|
points: [
|
||||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||||
pos2(small_icon_rect.right(), 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 {
|
if !state.open {
|
||||||
// Draw it as a plus:
|
// Draw it as a plus:
|
||||||
ui.add_paint_cmd(PaintCmd::Line {
|
ui.add_paint_cmd(PaintCmd::LineSegment {
|
||||||
points: vec![
|
points: [
|
||||||
pos2(small_icon_rect.center().x, small_icon_rect.top()),
|
pos2(small_icon_rect.center().x, small_icon_rect.top()),
|
||||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||||
],
|
],
|
||||||
|
|
|
@ -256,7 +256,7 @@ fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) {
|
||||||
|
|
||||||
while w < 12.0 {
|
while w < 12.0 {
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
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,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
|
|
|
@ -8,6 +8,7 @@ pub struct Vec2 {
|
||||||
pub y: f32,
|
pub y: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn vec2(x: f32, y: f32) -> Vec2 {
|
pub fn vec2(x: f32, y: f32) -> Vec2 {
|
||||||
Vec2 { x, y }
|
Vec2 { x, y }
|
||||||
}
|
}
|
||||||
|
@ -39,6 +40,7 @@ impl Vec2 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn rot90(self) -> Self {
|
pub fn rot90(self) -> Self {
|
||||||
vec2(self.y, -self.x)
|
vec2(self.y, -self.x)
|
||||||
}
|
}
|
||||||
|
@ -212,6 +214,13 @@ pub fn pos2(x: f32, y: f32) -> Pos2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pos2 {
|
impl Pos2 {
|
||||||
|
pub fn to_vec2(self) -> Vec2 {
|
||||||
|
Vec2 {
|
||||||
|
x: self.x,
|
||||||
|
y: self.y,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dist(self: Self, other: Self) -> f32 {
|
pub fn dist(self: Self, other: Self) -> f32 {
|
||||||
(self - other).length()
|
(self - other).length()
|
||||||
}
|
}
|
||||||
|
|
|
@ -147,6 +147,7 @@ impl Path {
|
||||||
self.0.clear();
|
self.0.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
pub fn add_point(&mut self, pos: Pos2, normal: Vec2) {
|
pub fn add_point(&mut self, pos: Pos2, normal: Vec2) {
|
||||||
self.0.push(PathPoint { pos, normal });
|
self.0.push(PathPoint { pos, normal });
|
||||||
}
|
}
|
||||||
|
@ -160,22 +161,33 @@ 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]) {
|
pub fn add_line(&mut self, points: &[Pos2]) {
|
||||||
let n = points.len();
|
let n = points.len();
|
||||||
assert!(n >= 2);
|
assert!(n >= 2);
|
||||||
|
|
||||||
self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
|
if n == 2 {
|
||||||
for i in 1..n - 1 {
|
// Common case optimization:
|
||||||
let n0 = (points[i] - points[i - 1]).normalized().rot90();
|
self.add_line_segment([points[0], points[1]]);
|
||||||
let n1 = (points[i + 1] - points[i]).normalized().rot90();
|
} else {
|
||||||
let v = (n0 + n1) / 2.0;
|
self.add_point(points[0], (points[1] - points[0]).normalized().rot90());
|
||||||
let normal = v / v.length_sq();
|
for i in 1..n - 1 {
|
||||||
self.add_point(points[i], normal); // TODO: handle VERY sharp turns better
|
let n0 = (points[i] - points[i - 1]).normalized().rot90();
|
||||||
|
let n1 = (points[i + 1] - points[i]).normalized().rot90();
|
||||||
|
let v = (n0 + n1) / 2.0;
|
||||||
|
let normal = v / v.length_sq();
|
||||||
|
self.add_point(points[i], normal); // TODO: handle VERY sharp turns better
|
||||||
|
}
|
||||||
|
self.add_point(
|
||||||
|
points[n - 1],
|
||||||
|
(points[n - 1] - points[n - 2]).normalized().rot90(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
self.add_point(
|
|
||||||
points[n - 1],
|
|
||||||
(points[n - 1] - points[n - 2]).normalized().rot90(),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_rectangle(&mut self, rect: Rect) {
|
pub fn add_rectangle(&mut self, rect: Rect) {
|
||||||
|
@ -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 {
|
match command {
|
||||||
PaintCmd::Circle {
|
PaintCmd::Circle {
|
||||||
center,
|
center,
|
||||||
|
@ -395,7 +416,6 @@ pub fn mesh_command(options: MesherOptions, fonts: &Fonts, command: PaintCmd, ou
|
||||||
outline,
|
outline,
|
||||||
radius,
|
radius,
|
||||||
} => {
|
} => {
|
||||||
let mut path = Path::default();
|
|
||||||
path.add_circle(center, radius);
|
path.add_circle(center, radius);
|
||||||
if let Some(color) = fill_color {
|
if let Some(color) = fill_color {
|
||||||
fill_closed_path(out_mesh, options, &path.0, 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) => {
|
PaintCmd::Mesh(mesh) => {
|
||||||
out_mesh.append(&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,
|
points,
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
} => {
|
} => {
|
||||||
let n = points.len();
|
let n = points.len();
|
||||||
if n >= 2 {
|
if n >= 2 {
|
||||||
let mut path = Path::default();
|
|
||||||
path.add_line(&points);
|
path.add_line(&points);
|
||||||
paint_path(out_mesh, options, Open, &path.0, color, width);
|
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.min = rect.min.max(pos2(-1e7, -1e7));
|
||||||
rect.max = rect.max.min(pos2(1e7, 1e7));
|
rect.max = rect.max.min(pos2(1e7, 1e7));
|
||||||
|
|
||||||
let mut path = Path::default();
|
|
||||||
path.add_rounded_rectangle(rect, corner_radius);
|
path.add_rounded_rectangle(rect, corner_radius);
|
||||||
if let Some(fill_color) = fill_color {
|
if let Some(fill_color) = fill_color {
|
||||||
fill_closed_path(out_mesh, options, &path.0, fill_color);
|
fill_closed_path(out_mesh, options, &path.0, fill_color);
|
||||||
|
@ -512,6 +538,8 @@ pub fn mesh_paint_commands(
|
||||||
fonts: &Fonts,
|
fonts: &Fonts,
|
||||||
commands: Vec<(Rect, PaintCmd)>,
|
commands: Vec<(Rect, PaintCmd)>,
|
||||||
) -> Vec<(Rect, Mesh)> {
|
) -> Vec<(Rect, Mesh)> {
|
||||||
|
let mut reused_path = Path::default();
|
||||||
|
|
||||||
let mut batches = PaintBatches::default();
|
let mut batches = PaintBatches::default();
|
||||||
for (clip_rect, cmd) in commands {
|
for (clip_rect, cmd) in commands {
|
||||||
// TODO: cull(clip_rect, cmd)
|
// TODO: cull(clip_rect, cmd)
|
||||||
|
@ -522,6 +550,7 @@ pub fn mesh_paint_commands(
|
||||||
if options.debug_paint_clip_rects && !clip_rect.is_empty() {
|
if options.debug_paint_clip_rects && !clip_rect.is_empty() {
|
||||||
let out_mesh = &mut batches.last_mut().unwrap().1;
|
let out_mesh = &mut batches.last_mut().unwrap().1;
|
||||||
mesh_command(
|
mesh_command(
|
||||||
|
&mut reused_path,
|
||||||
options,
|
options,
|
||||||
fonts,
|
fonts,
|
||||||
PaintCmd::Rect {
|
PaintCmd::Rect {
|
||||||
|
@ -536,7 +565,7 @@ pub fn mesh_paint_commands(
|
||||||
}
|
}
|
||||||
|
|
||||||
let out_mesh = &mut batches.last_mut().unwrap().1;
|
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
|
batches
|
||||||
|
|
|
@ -78,7 +78,12 @@ pub enum PaintCmd {
|
||||||
outline: Option<Outline>,
|
outline: Option<Outline>,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
},
|
},
|
||||||
Line {
|
LineSegment {
|
||||||
|
points: [Pos2; 2],
|
||||||
|
color: Color,
|
||||||
|
width: f32,
|
||||||
|
},
|
||||||
|
LinePath {
|
||||||
points: Vec<Pos2>,
|
points: Vec<Pos2>,
|
||||||
color: Color,
|
color: Color,
|
||||||
width: f32,
|
width: f32,
|
||||||
|
@ -111,9 +116,9 @@ pub enum PaintCmd {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PaintCmd {
|
impl PaintCmd {
|
||||||
pub fn line_segment(seg: (Pos2, Pos2), color: Color, width: f32) -> Self {
|
pub fn line_segment(points: [Pos2; 2], color: Color, width: f32) -> Self {
|
||||||
Self::Line {
|
Self::LineSegment {
|
||||||
points: vec![seg.0, seg.1],
|
points,
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,17 +369,17 @@ impl Ui {
|
||||||
|
|
||||||
if too_wide {
|
if too_wide {
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.left_top(), rect.left_bottom()),
|
[rect.left_top(), rect.left_bottom()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.left_center(), rect.right_center()),
|
[rect.left_center(), rect.right_center()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.right_top(), rect.right_bottom()),
|
[rect.right_top(), rect.right_bottom()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
|
@ -387,17 +387,17 @@ impl Ui {
|
||||||
|
|
||||||
if too_high {
|
if too_high {
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.left_top(), rect.right_top()),
|
[rect.left_top(), rect.right_top()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.center_top(), rect.center_bottom()),
|
[rect.center_top(), rect.center_bottom()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
self.add_paint_cmd(PaintCmd::line_segment(
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
(rect.left_bottom(), rect.right_bottom()),
|
[rect.left_bottom(), rect.right_bottom()],
|
||||||
color,
|
color,
|
||||||
width,
|
width,
|
||||||
));
|
));
|
||||||
|
@ -594,11 +594,11 @@ impl Ui {
|
||||||
let line_start = child_rect.min - indent * 0.5;
|
let line_start = child_rect.min - indent * 0.5;
|
||||||
let line_start = line_start.round(); // TODO: round to pixel instead
|
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);
|
let line_end = pos2(line_start.x, line_start.y + size.y - 8.0);
|
||||||
self.add_paint_cmd(PaintCmd::Line {
|
self.add_paint_cmd(PaintCmd::line_segment(
|
||||||
points: vec![line_start, line_end],
|
[line_start, line_end],
|
||||||
color: gray(150, 255),
|
gray(150, 255),
|
||||||
width: self.style.line_width,
|
self.style.line_width,
|
||||||
});
|
));
|
||||||
|
|
||||||
self.reserve_space(indent + size, None)
|
self.reserve_space(indent + size, None)
|
||||||
}
|
}
|
||||||
|
|
|
@ -160,11 +160,11 @@ impl Widget for Hyperlink {
|
||||||
let y = ui.round_to_pixel(y);
|
let y = ui.round_to_pixel(y);
|
||||||
let min_x = pos.x + fragment.min_x();
|
let min_x = pos.x + fragment.min_x();
|
||||||
let max_x = pos.x + fragment.max_x();
|
let max_x = pos.x + fragment.max_x();
|
||||||
ui.add_paint_cmd(PaintCmd::Line {
|
ui.add_paint_cmd(PaintCmd::line_segment(
|
||||||
points: vec![pos2(min_x, y), pos2(max_x, y)],
|
[pos2(min_x, y), pos2(max_x, y)],
|
||||||
color,
|
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;
|
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||||
|
|
||||||
if *self.checked {
|
if *self.checked {
|
||||||
ui.add_paint_cmd(PaintCmd::Line {
|
ui.add_paint_cmd(PaintCmd::LinePath {
|
||||||
points: vec![
|
points: vec![
|
||||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||||
|
@ -422,7 +422,7 @@ impl Widget for Separator {
|
||||||
Direction::Horizontal => {
|
Direction::Horizontal => {
|
||||||
let interact = ui.reserve_space(vec2(self.min_spacing, available_space.y), None);
|
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.top() - extra),
|
||||||
pos2(interact.rect.center().x, interact.rect.bottom() + extra),
|
pos2(interact.rect.center().x, interact.rect.bottom() + extra),
|
||||||
],
|
],
|
||||||
|
@ -432,7 +432,7 @@ impl Widget for Separator {
|
||||||
Direction::Vertical => {
|
Direction::Vertical => {
|
||||||
let interact = ui.reserve_space(vec2(available_space.x, self.min_spacing), None);
|
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.left() - extra, interact.rect.center().y),
|
||||||
pos2(interact.rect.right() + 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,
|
points,
|
||||||
color: self.color,
|
color: self.color,
|
||||||
width: self.line_width,
|
width: self.line_width,
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
interact.rect.min
|
interact.rect.min
|
||||||
};
|
};
|
||||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
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,
|
color::WHITE,
|
||||||
ui.style().text_cursor_width,
|
ui.style().text_cursor_width,
|
||||||
));
|
));
|
||||||
|
|
Loading…
Reference in a new issue