handwritin: Grow and shrink the canvas without refreshing

This commit is contained in:
2025-06-23 21:50:10 +02:00
parent 61669e15bd
commit eaf0c3cb55
2 changed files with 33 additions and 26 deletions

View File

@ -18,6 +18,7 @@ const CHUNK_SIZE: usize = 64;
/// Rasterize onto a resizeable canvas. /// Rasterize onto a resizeable canvas.
#[derive(Default)] #[derive(Default)]
pub struct CanvasRasterizer { pub struct CanvasRasterizer {
image_size: [usize; 2],
tiles: HashMap<[usize; 2], Tile>, tiles: HashMap<[usize; 2], Tile>,
} }
@ -49,12 +50,30 @@ impl Tile {
} }
impl CanvasRasterizer { 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) { 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| { let chunk = |max: usize| {
(0..) (0..)
.step_by(CHUNK_SIZE) .step_by(CHUNK_SIZE)
@ -62,6 +81,7 @@ impl CanvasRasterizer {
.enumerate() .enumerate()
}; };
// create new tiles where we need them
for (xi, _x) in chunk(width) { for (xi, _x) in chunk(width) {
for (yi, _y) in chunk(height) { for (yi, _y) in chunk(height) {
self.tiles 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>( pub fn rasterize<'a>(
&mut self, &mut self,
point_to_pixel: TSTransform, point_to_pixel: TSTransform,

View File

@ -105,20 +105,9 @@ struct MeshContext {
pub pixels_per_point: f32, pub pixels_per_point: f32,
/// Canvas size in points
pub size: Vec2,
pub stroke: Stroke, 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 { impl Default for Handwriting {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -379,7 +368,6 @@ impl Handwriting {
let new_context = MeshContext { let new_context = MeshContext {
ui_theme: ui.ctx().theme(), ui_theme: ui.ctx().theme(),
pixels_per_point: ui.pixels_per_point(), pixels_per_point: ui.pixels_per_point(),
size: mesh_rect.size(),
stroke: style.stroke, stroke: style.stroke,
}; };
@ -388,6 +376,13 @@ impl Handwriting {
self.e.refresh_texture = true; 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 self.e.refresh_texture {
// ...if we do, rasterize the entire texture from scratch // ...if we do, rasterize the entire texture from scratch
self.refresh_texture(style, new_context); 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); // 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 point_to_pixel = TSTransform::from_scaling(mesh_context.pixels_per_point);
let triangles = mesh_triangles(&self.e.mesh); 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 self.e
.canvas_rasterizer .canvas_rasterizer
.rasterize(point_to_pixel, triangles); .rasterize(point_to_pixel, triangles);