diff --git a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs index 5ad641afd..8eb3841da 100644 --- a/frontend/src/app/main/ui/workspace/viewport_wasm.cljs +++ b/frontend/src/app/main/ui/workspace/viewport_wasm.cljs @@ -285,16 +285,11 @@ (mf/with-effect [base-objects canvas-init?] (when @canvas-init? - (wasm.api/set-objects base-objects) - (wasm.api/draw-objects zoom vbox))) - - (mf/with-effect [modifiers canvas-init?] - (when (and @canvas-init? modifiers) - (wasm.api/draw-objects zoom vbox))) + (wasm.api/set-objects base-objects))) (mf/with-effect [vbox canvas-init?] - (let [frame-id (when @canvas-init? (wasm.api/draw-objects zoom vbox))] - (partial wasm.api/cancel-draw frame-id))) + (when @canvas-init? + (wasm.api/set-view zoom vbox))) (hooks/setup-dom-events zoom disable-paste in-viewport? read-only? drawing-tool drawing-path?) (hooks/setup-viewport-size vport viewport-ref) diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 06ff6f95b..dd38899cd 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -13,13 +13,27 @@ [app.render-wasm.helpers :as h] [promesa.core :as p])) +(defonce internal-frame-id nil) (defonce internal-module #js {}) -(defn create-shape - [id] - (let [buffer (uuid/get-u32 id)] - (h/call internal-module "_create_shape" - (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3)))) +;; This should never be called from the outside. +;; This function receives a "time" parameter that we're not using but maybe in the future could be useful (it is the time since +;; the window started rendering elements so it could be useful to measure time between frames). +(defn- render + [_] + (h/call internal-module "_render") + (set! internal-frame-id nil)) + +(defn cancel-render + [] + (when internal-frame-id + (js/cancelAnimationFrame internal-frame-id) + (set! internal-frame-id nil))) + +(defn request-render + [] + (when internal-frame-id (cancel-render)) + (set! internal-frame-id (js/requestAnimationFrame render))) (defn use-shape [id] @@ -105,6 +119,11 @@ ;; https://rust-skia.github.io/doc/skia_safe/enum.BlendMode.html (h/call internal-module "_set_shape_blend_mode" (translate-blend-mode blend-mode))) +(defn set-view + [zoom vbox] + (h/call internal-module "_set_view" zoom (- (:x vbox)) (- (:y vbox))) + (request-render)) + (defn set-objects [objects] (let [shapes (into [] (vals objects)) @@ -127,23 +146,11 @@ (set-shape-fills fills) (set-shape-blend-mode blend-mode) (set-shape-children children) - (recur (inc index))))))) - -(defn draw-objects - [zoom vbox] - (js/requestAnimationFrame - (fn [] - (let [pan-x (- (dm/get-prop vbox :x)) - pan-y (- (dm/get-prop vbox :y))] - (h/call internal-module "_draw_all_shapes" zoom pan-x pan-y))))) - -(defn cancel-draw - [frame-id] - (when (some? frame-id) - (js/cancelAnimationFrame frame-id))) + (recur (inc index)))))) + (request-render)) (def ^:private canvas-options - #js {:antialias true + #js {:antialias false :depth true :stencil true :alpha true}) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index a754848f0..98df40cbe 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -101,7 +101,11 @@ :fills (api/set-shape-fills v) :blend-mode (api/set-shape-blend-mode v) :shapes (api/set-shape-children v) - nil)) + nil) + ;; when something synced with wasm + ;; is modified, we need to request + ;; a new render. + (api/request-render)) (let [delegate (.-delegate ^ShapeProxy self) delegate' (assoc delegate k v)] (if (identical? delegate' delegate) diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index a812e91bd..3b5f3f2a3 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -2,6 +2,7 @@ pub mod render; pub mod shapes; pub mod state; pub mod utils; +pub mod view; use skia_safe as skia; @@ -43,9 +44,9 @@ 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) { +pub unsafe extern "C" fn render() { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); - state.draw_all_shapes(zoom, pan_x, pan_y); + state.draw_all_shapes(state.view.zoom, state.view.x, state.view.y); } #[no_mangle] @@ -54,6 +55,14 @@ pub extern "C" fn reset_canvas() { state.render_state().reset_canvas(); } +#[no_mangle] +pub extern "C" fn set_view(zoom: f32, x: f32, y: f32) { + let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); + state.view.x = x; + state.view.y = y; + state.view.zoom = zoom; +} + #[no_mangle] pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); diff --git a/render-wasm/src/state.rs b/render-wasm/src/state.rs index 4718f3b0c..630bfa051 100644 --- a/render-wasm/src/state.rs +++ b/render-wasm/src/state.rs @@ -3,6 +3,7 @@ use uuid::Uuid; use crate::render::RenderState; use crate::shapes::Shape; +use crate::view::View; /// This struct holds the state of the Rust application between JS calls. /// @@ -14,6 +15,7 @@ pub(crate) struct State<'a> { pub current_id: Option, pub current_shape: Option<&'a mut Shape>, pub shapes: HashMap, + pub view: View, } impl<'a> State<'a> { @@ -23,6 +25,11 @@ impl<'a> State<'a> { current_id: None, current_shape: None, shapes: HashMap::with_capacity(capacity), + view: View { + x: 0., + y: 0., + zoom: 1., + } } } diff --git a/render-wasm/src/view.rs b/render-wasm/src/view.rs new file mode 100644 index 000000000..c2c857384 --- /dev/null +++ b/render-wasm/src/view.rs @@ -0,0 +1,6 @@ +pub(crate) struct View +{ + pub x: f32, + pub y: f32, + pub zoom: f32, +}