1
0
mirror of https://github.com/emilk/egui.git synced 2026-08-31 05:40:03 -04:00

WIP: clip_rect

This commit is contained in:
Emil Ernerfeldt
2020-04-20 23:33:16 +02:00
parent ffc1768e40
commit 2f02446f6f
14 changed files with 307 additions and 198 deletions

View File

@@ -15,8 +15,6 @@ pub struct Vertex {
pub color: Color,
}
// ----------------------------------------------------------------------------
#[derive(Clone, Debug, Default, Serialize)]
pub struct Mesh {
/// Draw as triangles (i.e. the length is a multiple of three)
@@ -24,6 +22,11 @@ pub struct Mesh {
pub vertices: Vec<Vertex>,
}
/// Grouped by clip rectangles, in pixel coordinates
pub type PaintBatches = Vec<(Rect, Mesh)>;
// ----------------------------------------------------------------------------
impl Mesh {
pub fn append(&mut self, mesh: &Mesh) {
let index_offset = self.vertices.len() as u32;
@@ -373,139 +376,141 @@ pub fn paint_path(
// ----------------------------------------------------------------------------
pub struct Mesher {
pub options: MesherOptions,
/// Where the output goes
pub mesh: Mesh,
}
impl Mesher {
pub fn new(pixels_per_point: f32) -> Mesher {
Mesher {
options: MesherOptions {
anti_alias: true,
aa_size: 1.0 / pixels_per_point,
},
mesh: Default::default(),
pub fn mesh_command(
options: &MesherOptions,
fonts: &Fonts,
command: PaintCmd,
out_mesh: &mut Mesh,
) {
match command {
PaintCmd::Circle {
center,
fill_color,
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);
}
if let Some(outline) = outline {
paint_path(
out_mesh,
options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
}
pub fn paint(&mut self, fonts: &Fonts, commands: &[PaintCmd]) {
let mut path = Path::default();
for cmd in commands {
match cmd {
PaintCmd::Circle {
center,
fill_color,
outline,
radius,
} => {
path.clear();
path.add_circle(*center, *radius);
if let Some(color) = fill_color {
fill_closed_path(&mut self.mesh, &self.options, &path.0, *color);
}
if let Some(outline) = outline {
paint_path(
&mut self.mesh,
&self.options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Mesh(cmd_frame) => {
self.mesh.append(cmd_frame);
}
PaintCmd::Line {
points,
color,
width,
} => {
let n = points.len();
if n >= 2 {
path.clear();
path.add_line(points);
paint_path(&mut self.mesh, &self.options, Open, &path.0, *color, *width);
}
}
PaintCmd::Path {
path,
PaintCmd::Mesh(mesh) => {
out_mesh.append(&mesh);
}
PaintCmd::Line {
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);
}
}
PaintCmd::Path {
path,
closed,
fill_color,
outline,
} => {
if let Some(fill_color) = fill_color {
debug_assert!(
closed,
fill_color,
outline,
} => {
if let Some(fill_color) = fill_color {
debug_assert!(
*closed,
"You asked to fill a path that is not closed. That makes no sense."
);
fill_closed_path(&mut self.mesh, &self.options, &path.0, *fill_color);
}
if let Some(outline) = outline {
paint_path(
&mut self.mesh,
&self.options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Rect {
corner_radius,
fill_color,
outline,
rect,
} => {
path.clear();
path.add_rounded_rectangle(rect, *corner_radius);
if let Some(fill_color) = fill_color {
fill_closed_path(&mut self.mesh, &self.options, &path.0, *fill_color);
}
if let Some(outline) = outline {
paint_path(
&mut self.mesh,
&self.options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Text {
color,
pos,
text,
text_style,
x_offsets,
} => {
let font = &fonts[*text_style];
for (c, x_offset) in text.chars().zip(x_offsets.iter()) {
if let Some(glyph) = font.uv_rect(c) {
let mut top_left = Vertex {
pos: *pos + glyph.offset + vec2(*x_offset, 0.0),
uv: glyph.min,
color: *color,
};
top_left.pos.x = font.round_to_pixel(top_left.pos.x); // Pixel-perfection.
top_left.pos.y = font.round_to_pixel(top_left.pos.y); // Pixel-perfection.
let bottom_right = Vertex {
pos: top_left.pos + glyph.size,
uv: glyph.max,
color: *color,
};
self.mesh.add_rect(top_left, bottom_right);
}
}
"You asked to fill a path that is not closed. That makes no sense."
);
fill_closed_path(out_mesh, options, &path.0, fill_color);
}
if let Some(outline) = outline {
paint_path(
out_mesh,
options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Rect {
corner_radius,
fill_color,
outline,
rect,
} => {
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);
}
if let Some(outline) = outline {
paint_path(
out_mesh,
options,
Closed,
&path.0,
outline.color,
outline.width,
);
}
}
PaintCmd::Text {
color,
pos,
text,
text_style,
x_offsets,
} => {
let font = &fonts[text_style];
for (c, x_offset) in text.chars().zip(x_offsets.iter()) {
if let Some(glyph) = font.uv_rect(c) {
let mut top_left = Vertex {
pos: pos + glyph.offset + vec2(*x_offset, 0.0),
uv: glyph.min,
color: color,
};
top_left.pos.x = font.round_to_pixel(top_left.pos.x); // Pixel-perfection.
top_left.pos.y = font.round_to_pixel(top_left.pos.y); // Pixel-perfection.
let bottom_right = Vertex {
pos: top_left.pos + glyph.size,
uv: glyph.max,
color: color,
};
out_mesh.add_rect(top_left, bottom_right);
}
}
}
}
}
pub fn mesh_paint_commands(
options: &MesherOptions,
fonts: &Fonts,
commands: Vec<(Rect, PaintCmd)>,
) -> Vec<(Rect, Mesh)> {
let mut batches = PaintBatches::default();
for (clip_rect, cmd) in commands {
// TODO: cull(clip_rect, cmd)
if batches.is_empty() || batches.last().unwrap().0 != clip_rect {
batches.push((clip_rect, Mesh::default()));
}
let out_mesh = &mut batches.last_mut().unwrap().1;
mesh_command(options, fonts, cmd, out_mesh);
}
batches
}