From 3eb24e7f5ff76b5ae212c81895d05af3f9934925 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bel=C3=A9n=20Albeza?= Date: Thu, 14 Nov 2024 12:08:50 +0100 Subject: [PATCH] :recycle: Refactor State (wasm) --- render-wasm/src/main.rs | 18 ++------- render-wasm/src/render.rs | 85 ++++++--------------------------------- render-wasm/src/state.rs | 73 +++++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 87 deletions(-) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index 6244840b1..a812e91bd 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -4,12 +4,12 @@ pub mod state; pub mod utils; use skia_safe as skia; -use uuid::Uuid; use crate::state::State; use crate::utils::uuid_from_u32_quartet; static mut STATE: Option> = None; + extern "C" { fn emscripten_GetProcAddress( name: *const ::std::os::raw::c_char, @@ -45,25 +45,13 @@ pub unsafe extern "C" fn resize_surface(width: i32, height: i32) { #[no_mangle] pub unsafe extern "C" fn draw_all_shapes(zoom: f32, pan_x: f32, pan_y: f32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); - - reset_canvas(); - render::scale(state, zoom, zoom); - render::translate(state, pan_x, pan_y); - - render::render_shape_tree(state, Uuid::nil()); - - render::flush(state); + state.draw_all_shapes(zoom, pan_x, pan_y); } #[no_mangle] pub extern "C" fn reset_canvas() { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); - state - .render_state - .surface - .canvas() - .clear(skia_safe::Color::TRANSPARENT); - state.render_state.surface.canvas().reset_matrix(); + state.render_state().reset_canvas(); } #[no_mangle] diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index fab6878a2..6a7426c9c 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -1,9 +1,5 @@ use skia_safe as skia; use skia_safe::gpu::{self, gl::FramebufferInfo, DirectContext}; -use uuid::Uuid; - -use crate::shapes::Shape; -use crate::state::State; struct GpuState { pub context: DirectContext, @@ -66,78 +62,23 @@ impl RenderState { let surface = self.gpu_state.create_surface(width, height); self.surface = surface; } -} -pub(crate) fn flush(state: &mut State) { - state - .render_state - .gpu_state - .context - .flush_and_submit_surface(&mut state.render_state.surface, None); -} - -pub(crate) fn translate(state: &mut State, dx: f32, dy: f32) { - state.render_state.surface.canvas().translate((dx, dy)); -} - -pub(crate) fn scale(state: &mut State, sx: f32, sy: f32) { - state.render_state.surface.canvas().scale((sx, sy)); -} - -pub(crate) fn render_shape_tree(state: &mut State, id: Uuid) { - let shape = state.shapes.get(&id).unwrap(); - - // This is needed so the next non-children shape does not carry this shape's transform - state.render_state.surface.canvas().save(); - - render_single_shape(&mut state.render_state.surface, shape); - - // draw all the children shapes - let shape_ids = shape.children.clone(); - for shape_id in shape_ids { - render_shape_tree(state, shape_id); + pub fn flush(&mut self) { + self.gpu_state + .context + .flush_and_submit_surface(&mut self.surface, None) } - state.render_state.surface.canvas().restore(); -} + pub fn translate(&mut self, dx: f32, dy: f32) { + self.surface.canvas().translate((dx, dy)); + } -fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) { - let r = skia::Rect::new( - shape.selrect.x1, - shape.selrect.y1, - shape.selrect.x2, - shape.selrect.y2, - ); + pub fn scale(&mut self, sx: f32, sy: f32) { + self.surface.canvas().scale((sx, sy)); + } - // Check transform-matrix code from common/src/app/common/geom/shapes/transforms.cljc - let mut matrix = skia::Matrix::new_identity(); - let (translate_x, translate_y) = shape.translation(); - let (scale_x, scale_y) = shape.scale(); - let (skew_x, skew_y) = shape.skew(); - - matrix.set_all( - scale_x, - skew_x, - translate_x, - skew_y, - scale_y, - translate_y, - 0., - 0., - 1., - ); - - let mut center = r.center(); - matrix.post_translate(center); - center.negate(); - matrix.pre_translate(center); - - surface.canvas().concat(&matrix); - - // TODO: use blend mode for the shape as a whole, not in each fill - for fill in shape.fills().rev() { - let mut p = fill.to_paint(); - p.set_blend_mode(shape.blend_mode.into()); - surface.canvas().draw_rect(r, &p); + pub fn reset_canvas(&mut self) { + self.surface.canvas().clear(skia_safe::Color::TRANSPARENT); + self.surface.canvas().reset_matrix(); } } diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 3672f40cf..edbe561a0 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -27,6 +27,38 @@ impl<'a> State<'a> { } } + pub fn render_state(&'a mut self) -> &'a mut RenderState { + &mut self.render_state + } + + pub fn draw_all_shapes(&mut self, zoom: f32, pan_x: f32, pan_y: f32) { + self.render_state.reset_canvas(); + + self.render_state.scale(zoom, zoom); + self.render_state.translate(pan_x, pan_y); + + self.render_shape_tree(Uuid::nil()); + + self.render_state.flush(); + } + + fn render_shape_tree(&mut self, id: Uuid) { + let shape = self.shapes.get(&id).unwrap(); + + // This is needed so the next non-children shape does not carry this shape's transform + self.render_state.surface.canvas().save(); + + render_single_shape(&mut self.render_state.surface, shape); + + // draw all the children shapes + let shape_ids = shape.children.clone(); + for shape_id in shape_ids { + self.render_shape_tree(shape_id); + } + + self.render_state.surface.canvas().restore(); + } + pub fn use_shape(&'a mut self, id: Uuid) { if !self.shapes.contains_key(&id) { let new_shape = Shape::new(id); @@ -41,3 +73,44 @@ impl<'a> State<'a> { self.current_shape.as_deref_mut() } } + +fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) { + let r = skia::Rect::new( + shape.selrect.x1, + shape.selrect.y1, + shape.selrect.x2, + shape.selrect.y2, + ); + + // Check transform-matrix code from common/src/app/common/geom/shapes/transforms.cljc + let mut matrix = skia::Matrix::new_identity(); + let (translate_x, translate_y) = shape.translation(); + let (scale_x, scale_y) = shape.scale(); + let (skew_x, skew_y) = shape.skew(); + + matrix.set_all( + scale_x, + skew_x, + translate_x, + skew_y, + scale_y, + translate_y, + 0., + 0., + 1., + ); + + let mut center = r.center(); + matrix.post_translate(center); + center.negate(); + matrix.pre_translate(center); + + surface.canvas().concat(&matrix); + + // TODO: use blend mode for the shape as a whole, not in each fill + for fill in shape.fills().rev() { + let mut p = fill.to_paint(); + p.set_blend_mode(shape.blend_mode.into()); + surface.canvas().draw_rect(r, &p); + } +}