diff --git a/src/handwriting/canvas_rasterizer.rs b/src/handwriting/canvas_rasterizer.rs index 83af8d9..5918ce4 100644 --- a/src/handwriting/canvas_rasterizer.rs +++ b/src/handwriting/canvas_rasterizer.rs @@ -9,7 +9,7 @@ use egui::{ load::SizedTexture, }; -use crate::rasterizer::{PxBoundingBox, rasterize_onto, triangle_bounding_box}; +use crate::rasterizer::{PxBoundingBox, rasterize_triangle_onto, triangle_bounding_box}; use super::StrokeBlendMode; @@ -61,11 +61,6 @@ impl CanvasRasterizer { 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; @@ -96,44 +91,27 @@ impl CanvasRasterizer { point_to_pixel: TSTransform, triangles: impl Iterator + Clone, ) { - // calculate smallest bounding box that encompasses all triangles - let triangles_bounding_box = triangles - .clone() - .map(|t| triangle_bounding_box(&t, point_to_pixel)) - .reduce(|a, b| a.union(&b)); + for triangle in triangles { + let triangle_bounding_box = triangle_bounding_box(&triangle, point_to_pixel); + for chunk in chunks_from_bounding_box(triangle_bounding_box) { + let Some(tile) = self.tiles.get_mut(&chunk) else { + continue; + }; - let Some(triangles_bounding_box) = triangles_bounding_box else { - return; // no triangles - }; - - // get all tiles that are encompassed by the bounding box - // TODO: smarter iteration: don't iterate over all tiles and filter - let mut n = 0; - self.tiles - .values_mut() - // skip tiles which won't be touched - .filter(|tile| tile.bounding_box.overlaps_with(&triangles_bounding_box)) - // calculate TSTransform for tile - .map(|tile| { let mut point_to_tile_pixel = point_to_pixel; point_to_tile_pixel.translation -= Vec2::new( tile.bounding_box.x_from as f32, tile.bounding_box.y_from as f32, ); - (point_to_tile_pixel, tile) - }) - // rasterize triangles onto the tile - .for_each(|(tile_point_to_pixel, tile)| { - tile.texture_is_dirty = true; - rasterize_onto::( - &mut tile.image, - tile_point_to_pixel, - triangles.clone(), - ); - n += 1; - }); - log::error!("rasterizing touched {n} tiles"); + tile.texture_is_dirty = true; + rasterize_triangle_onto::( + &mut tile.image, + point_to_tile_pixel, + triangle, + ); + } + } } /// `at` defines the location in screen-coordinates where the canvas should be drawn. @@ -181,3 +159,18 @@ impl CanvasRasterizer { } } } + +/// Get all chunk indices that overlaps with a PxBoundingBox. +fn chunks_from_bounding_box( + triangle_bounding_box: PxBoundingBox, +) -> impl Iterator { + let x_from_chunk = triangle_bounding_box.x_from / CHUNK_SIZE; + let y_from_chunk = triangle_bounding_box.y_from / CHUNK_SIZE; + let x_to_chunk = triangle_bounding_box.x_to.saturating_sub(1) / CHUNK_SIZE; + let y_to_chunk = triangle_bounding_box.y_to.saturating_sub(1) / CHUNK_SIZE; + + let xs = x_from_chunk..=x_to_chunk; + let ys = y_from_chunk..=y_to_chunk; + + ys.flat_map(move |yi| xs.clone().map(move |xi| [xi, yi])) +} diff --git a/src/rasterizer.rs b/src/rasterizer.rs index 076a125..d6ff67e 100644 --- a/src/rasterizer.rs +++ b/src/rasterizer.rs @@ -87,6 +87,17 @@ pub fn rasterize_onto<'a, Blend: BlendFn>( } } +/// Rasterize a single triangles onto an image, +/// +/// Triangle positions must be in image-local point-coords. +pub fn rasterize_triangle_onto<'a, Blend: BlendFn>( + image: &mut ColorImage, + point_to_pixel: TSTransform, + triangle: [&'a Vertex; 3], +) { + rasterize_onto::(image, point_to_pixel, [triangle].into_iter()); +} + /// A bounding box, measured in pixels. #[derive(Debug, PartialEq, Eq)] pub struct PxBoundingBox {