diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 371aa2d72f..b6131e95b8 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -890,6 +890,20 @@ impl RenderState { ) } + pub fn get_aligned_tile_bounds(&mut self, tile: tiles::Tile) -> Rect { + let scale = self.get_scale(); + let start_tile_x = + (self.viewbox.area.left * scale / tiles::TILE_SIZE).floor() * tiles::TILE_SIZE; + let start_tile_y = + (self.viewbox.area.top * scale / tiles::TILE_SIZE).floor() * tiles::TILE_SIZE; + Rect::from_xywh( + (tile.0 as f32 * tiles::TILE_SIZE) - start_tile_x, + (tile.1 as f32 * tiles::TILE_SIZE) - start_tile_y, + tiles::TILE_SIZE, + tiles::TILE_SIZE, + ) + } + // Returns the bounds of the current tile relative to the viewbox, // aligned to the nearest tile grid origin. // @@ -899,18 +913,7 @@ impl RenderState { // with the global tile grid, which is useful for rendering tiles in a /// consistent and predictable layout. pub fn get_current_aligned_tile_bounds(&mut self) -> Rect { - let tiles::Tile(tile_x, tile_y) = self.current_tile.unwrap(); - let scale = self.get_scale(); - let start_tile_x = - (self.viewbox.area.left * scale / tiles::TILE_SIZE).floor() * tiles::TILE_SIZE; - let start_tile_y = - (self.viewbox.area.top * scale / tiles::TILE_SIZE).floor() * tiles::TILE_SIZE; - Rect::from_xywh( - (tile_x as f32 * tiles::TILE_SIZE) - start_tile_x, - (tile_y as f32 * tiles::TILE_SIZE) - start_tile_y, - tiles::TILE_SIZE, - tiles::TILE_SIZE, - ) + self.get_aligned_tile_bounds(self.current_tile.unwrap()) } pub fn render_shape_tree_partial_uncached( @@ -1174,29 +1177,32 @@ impl RenderState { modifiers: &HashMap, ) { let TileRect(rsx, rsy, rex, rey) = self.get_tiles_for_shape(shape, tree, modifiers); + let old_tiles: HashSet = self + .tiles + .get_tiles_of(shape.id) + .map_or(HashSet::new(), |tiles| tiles.iter().cloned().collect()); let new_tiles: HashSet = (rsx..=rex) .flat_map(|x| (rsy..=rey).map(move |y| tiles::Tile(x, y))) .collect(); - // Update tiles where the shape was - if let Some(tiles) = self.tiles.get_tiles_of(shape.id) { - for tile in tiles.iter() { - self.surfaces.remove_cached_tile_surface(*tile); - } - // Remove shape from tiles not used - let diff: HashSet<_> = tiles.difference(&new_tiles).cloned().collect(); - for tile in diff.iter() { - self.tiles.remove_shape_at(*tile, shape.id); - } + // First, remove the shape from all tiles where it was previously located + for tile in old_tiles { + self.remove_cached_tile_shape(tile, shape.id); } - // Update tiles matching the actual selrect + // Then, add the shape to the new tiles for tile in new_tiles { self.tiles.add_shape_at(tile, shape.id); - self.surfaces.remove_cached_tile_surface(tile); } } + pub fn remove_cached_tile_shape(&mut self, tile: tiles::Tile, id: Uuid) { + let rect = self.get_aligned_tile_bounds(tile); + self.surfaces + .remove_cached_tile_surface(tile, rect, self.background_color); + self.tiles.remove_shape_at(tile, id); + } + pub fn rebuild_tiles_shallow( &mut self, tree: &ShapesPool, @@ -1205,7 +1211,7 @@ impl RenderState { ) { performance::begin_measure!("rebuild_tiles_shallow"); self.tiles.invalidate(); - self.surfaces.remove_cached_tiles(); + self.surfaces.remove_cached_tiles(self.background_color); let mut nodes = vec![Uuid::nil()]; while let Some(shape_id) = nodes.pop() { if let Some(shape) = tree.get(&shape_id) { @@ -1235,7 +1241,7 @@ impl RenderState { ) { performance::begin_measure!("rebuild_tiles"); self.tiles.invalidate(); - self.surfaces.remove_cached_tiles(); + self.surfaces.remove_cached_tiles(self.background_color); let mut nodes = vec![Uuid::nil()]; while let Some(shape_id) = nodes.pop() { if let Some(shape) = tree.get(&shape_id) { diff --git a/render-wasm/src/render/surfaces.rs b/render-wasm/src/render/surfaces.rs index 792e5d8727..4c33e569e9 100644 --- a/render-wasm/src/render/surfaces.rs +++ b/render-wasm/src/render/surfaces.rs @@ -303,7 +303,16 @@ impl Surfaces { self.tiles.has(tile) } - pub fn remove_cached_tile_surface(&mut self, tile: Tile) -> bool { + pub fn remove_cached_tile_surface( + &mut self, + tile: Tile, + rect: skia::Rect, + color: skia::Color, + ) -> bool { + // Clear the specific tile area in the cache surface with color + let mut paint = skia::Paint::default(); + paint.set_color(color); + self.cache.canvas().draw_rect(rect, &paint); self.tiles.remove(tile) } @@ -320,8 +329,9 @@ impl Surfaces { .draw_image_rect(&image, None, rect, &skia::Paint::default()); } - pub fn remove_cached_tiles(&mut self) { + pub fn remove_cached_tiles(&mut self, color: skia::Color) { self.tiles.clear(); + self.cache.canvas().clear(color); } } diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index d3774b8955..bab9e60add 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -105,8 +105,7 @@ impl State { for x in rsx..=rex { for y in rsy..=rey { let tile = tiles::Tile(x, y); - self.render_state.surfaces.remove_cached_tile_surface(tile); - self.render_state.tiles.remove_shape_at(tile, id); + self.render_state.remove_cached_tile_shape(tile, id); } } }