diff --git a/frontend/src/app/render_wasm.cljs b/frontend/src/app/render_wasm.cljs index 4560ecdb6..24f7d801b 100644 --- a/frontend/src/app/render_wasm.cljs +++ b/frontend/src/app/render_wasm.cljs @@ -79,23 +79,23 @@ ;; These values correspond to skia::BlendMode representation ;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html (let [encoded-blend (case blend-mode - :normal 3 - :darken 16 - :multiply 24 - :color-burn 19 - :lighten 17 - :screen 14 - :color-dodge 18 - :overlay 15 - :soft-light 21 - :hard-light 20 - :difference 22 - :exclusion 23 - :hue 25 - :saturation 26 - :color 27 - :luminosity 28 - 3)] + :normal 3 + :darken 16 + :multiply 24 + :color-burn 19 + :lighten 17 + :screen 14 + :color-dodge 18 + :overlay 15 + :soft-light 21 + :hard-light 20 + :difference 22 + :exclusion 23 + :hue 25 + :saturation 26 + :color 27 + :luminosity 28 + 3)] (._set_shape_blend_mode ^js internal-module encoded-blend))) (defn set-objects diff --git a/render-wasm/src/render.rs b/render-wasm/src/render.rs index 6a7426c9c..80469da32 100644 --- a/render-wasm/src/render.rs +++ b/render-wasm/src/render.rs @@ -28,7 +28,7 @@ impl GpuState { } /// Create a Skia surface that will be used for rendering. - fn create_surface(&mut self, width: i32, height: i32) -> skia::Surface { + fn create_target_surface(&mut self, width: i32, height: i32) -> skia::Surface { let backend_render_target = gpu::backend_render_targets::make_gl((width, height), 1, 8, self.framebuffer_info); @@ -46,39 +46,53 @@ impl GpuState { pub(crate) struct RenderState { gpu_state: GpuState, - pub surface: skia::Surface, + pub final_surface: skia::Surface, + pub drawing_surface: skia::Surface, } impl RenderState { pub fn new(width: i32, height: i32) -> RenderState { // This needs to be done once per WebGL context. let mut gpu_state = GpuState::new(); - let surface = gpu_state.create_surface(width, height); + let mut final_surface = gpu_state.create_target_surface(width, height); + let drawing_surface = final_surface + .new_surface_with_dimensions((width, height)) + .unwrap(); - RenderState { gpu_state, surface } + RenderState { + gpu_state, + final_surface, + drawing_surface, + } } pub fn resize(&mut self, width: i32, height: i32) { - let surface = self.gpu_state.create_surface(width, height); - self.surface = surface; + let surface = self.gpu_state.create_target_surface(width, height); + self.final_surface = surface; + self.drawing_surface = self + .final_surface + .new_surface_with_dimensions((width, height)) + .unwrap(); } pub fn flush(&mut self) { self.gpu_state .context - .flush_and_submit_surface(&mut self.surface, None) + .flush_and_submit_surface(&mut self.final_surface, None) } pub fn translate(&mut self, dx: f32, dy: f32) { - self.surface.canvas().translate((dx, dy)); + self.drawing_surface.canvas().translate((dx, dy)); } pub fn scale(&mut self, sx: f32, sy: f32) { - self.surface.canvas().scale((sx, sy)); + self.drawing_surface.canvas().scale((sx, sy)); } pub fn reset_canvas(&mut self) { - self.surface.canvas().clear(skia_safe::Color::TRANSPARENT); - self.surface.canvas().reset_matrix(); + self.drawing_surface + .canvas() + .clear(skia_safe::Color::TRANSPARENT); + self.drawing_surface.canvas().reset_matrix(); } } diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index edbe561a0..88cf47dba 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -1,4 +1,4 @@ -use skia_safe as skia; +use skia_safe::{self as skia, SamplingOptions}; use std::collections::HashMap; use uuid::Uuid; @@ -46,9 +46,14 @@ impl<'a> State<'a> { 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(); + self.render_state.final_surface.canvas().save(); + self.render_state.drawing_surface.canvas().save(); - render_single_shape(&mut self.render_state.surface, shape); + render_single_shape( + &mut self.render_state.final_surface, + &mut self.render_state.drawing_surface, + shape, + ); // draw all the children shapes let shape_ids = shape.children.clone(); @@ -56,7 +61,8 @@ impl<'a> State<'a> { self.render_shape_tree(shape_id); } - self.render_state.surface.canvas().restore(); + self.render_state.final_surface.canvas().restore(); + self.render_state.drawing_surface.canvas().restore(); } pub fn use_shape(&'a mut self, id: Uuid) { @@ -74,7 +80,7 @@ impl<'a> State<'a> { } } -fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) { +fn render_single_shape(surface: &mut skia::Surface, offscreen: &mut skia::Surface, shape: &Shape) { let r = skia::Rect::new( shape.selrect.x1, shape.selrect.y1, @@ -105,12 +111,18 @@ fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) { center.negate(); matrix.pre_translate(center); - surface.canvas().concat(&matrix); + offscreen.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); + offscreen.canvas().draw_rect(r, &fill.to_paint()); } + + let mut paint = skia::Paint::default(); + paint.set_blend_mode(shape.blend_mode.into()); + offscreen.draw( + &mut surface.canvas(), + (0.0, 0.0), + SamplingOptions::new(skia::FilterMode::Linear, skia::MipmapMode::None), + Some(&paint), + ); }