From eaf0c3cb554cdbd944fa41e4758bf04dd1a89f2f Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Mon, 23 Jun 2025 21:50:10 +0200 Subject: [PATCH] handwritin: Grow and shrink the canvas without refreshing --- src/handwriting/canvas_rasterizer.rs | 37 +++++++++++++++++++--------- src/handwriting/mod.rs | 22 ++++++----------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/src/handwriting/canvas_rasterizer.rs b/src/handwriting/canvas_rasterizer.rs index af9f17e..83af8d9 100644 --- a/src/handwriting/canvas_rasterizer.rs +++ b/src/handwriting/canvas_rasterizer.rs @@ -18,6 +18,7 @@ const CHUNK_SIZE: usize = 64; /// Rasterize onto a resizeable canvas. #[derive(Default)] pub struct CanvasRasterizer { + image_size: [usize; 2], tiles: HashMap<[usize; 2], Tile>, } @@ -49,12 +50,30 @@ impl Tile { } impl CanvasRasterizer { - //pub fn clear(&mut self) { - // self.image = ColorImage::new(self.image.size, Color32::TRANSPARENT); - // self.texture_is_dirty = true; - //} - pub fn set_size(&mut self, width: usize, height: usize) { + self.image_size = [width, height]; + self.populate_tiles(); + } + + pub fn clear(&mut self) { + log::error!("clearing all tiles"); + self.tiles.clear(); + self.populate_tiles(); + } + + pub fn clear_and_set_size(&mut self, width: usize, height: usize) { + self.image_size = [width, height]; + self.clear(); + } + + fn populate_tiles(&mut self) { + let [width, height] = self.image_size; + + // discard tiles that are out of bounds + self.tiles.retain(|_, tile| { + tile.bounding_box.x_from <= width && tile.bounding_box.y_from <= height + }); + let chunk = |max: usize| { (0..) .step_by(CHUNK_SIZE) @@ -62,6 +81,7 @@ impl CanvasRasterizer { .enumerate() }; + // create new tiles where we need them for (xi, _x) in chunk(width) { for (yi, _y) in chunk(height) { self.tiles @@ -71,13 +91,6 @@ impl CanvasRasterizer { } } - pub fn clear_and_set_size(&mut self, width: usize, height: usize) { - log::error!("clearing all tiles"); - self.tiles.clear(); - - self.set_size(width, height); - } - pub fn rasterize<'a>( &mut self, point_to_pixel: TSTransform, diff --git a/src/handwriting/mod.rs b/src/handwriting/mod.rs index b97bb3e..af2cb43 100644 --- a/src/handwriting/mod.rs +++ b/src/handwriting/mod.rs @@ -105,20 +105,9 @@ struct MeshContext { pub pixels_per_point: f32, - /// Canvas size in points - pub size: Vec2, - pub stroke: Stroke, } -impl MeshContext { - /// Calculate canvas size in pixels - pub fn pixel_size(&self) -> [usize; 2] { - let Vec2 { x, y } = self.size * self.pixels_per_point; - [x, y].map(|f| f.ceil() as usize) - } -} - impl Default for Handwriting { fn default() -> Self { Self { @@ -379,7 +368,6 @@ impl Handwriting { let new_context = MeshContext { ui_theme: ui.ctx().theme(), pixels_per_point: ui.pixels_per_point(), - size: mesh_rect.size(), stroke: style.stroke, }; @@ -388,6 +376,13 @@ impl Handwriting { self.e.refresh_texture = true; } + let [px_width, px_height] = { + let Vec2 { x, y } = mesh_rect.size() * new_context.pixels_per_point; + [x, y].map(|f| f.ceil() as usize) + }; + + self.e.canvas_rasterizer.set_size(px_width, px_height); + if self.e.refresh_texture { // ...if we do, rasterize the entire texture from scratch self.refresh_texture(style, new_context); @@ -457,11 +452,10 @@ impl Handwriting { // debug_assert!(vertex.pos.y.is_finite(), "{} must be finite", vertex.pos.y); //} - let [px_x, px_y] = mesh_context.pixel_size(); let point_to_pixel = TSTransform::from_scaling(mesh_context.pixels_per_point); let triangles = mesh_triangles(&self.e.mesh); - self.e.canvas_rasterizer.clear_and_set_size(px_x, px_y); + self.e.canvas_rasterizer.clear(); self.e .canvas_rasterizer .rasterize(point_to_pixel, triangles);