diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 551164f71..8419d5d2c 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -9,6 +9,7 @@ (:require [app.common.data.macros :as dm] [app.common.math :as mth] + [app.common.svg.path :as path] [app.common.uuid :as uuid] [app.config :as cf] [app.render-wasm.helpers :as h] @@ -186,6 +187,18 @@ (store-image id)))))) fills)) +(defn set-shape-path-content + [content] + (let [buffer (path/content->buffer content) + size (.-byteLength buffer) + ptr (h/call internal-module "_alloc_bytes" size) + heap (gobj/get ^js internal-module "HEAPU8") + mem (js/Uint8Array. (.-buffer heap) ptr size)] + (.set mem (js/Uint8Array. buffer) + (h/call internal-module "_set_shape_path_content" (count content)) + (js/console.log mem) + (js/console.log buffer)))) + (defn- translate-blend-mode [blend-mode] (case blend-mode @@ -237,6 +250,7 @@ (loop [index 0 pending []] (if (< index total-shapes) (let [shape (nth shapes index) + type (dm/get-prop shape :type) id (dm/get-prop shape :id) selrect (dm/get-prop shape :selrect) rotation (dm/get-prop shape :rotation) @@ -245,7 +259,8 @@ children (dm/get-prop shape :shapes) blend-mode (dm/get-prop shape :blend-mode) opacity (dm/get-prop shape :opacity) - hidden (dm/get-prop shape :hidden)] + hidden (dm/get-prop shape :hidden) + content (dm/get-prop shape :content)] (use-shape id) (set-shape-selrect selrect) @@ -255,6 +270,7 @@ (set-shape-children children) (set-shape-opacity opacity) (set-shape-hidden hidden) + (when (and (some? content) (= type :path)) (set-shape-path-content content)) (let [pending-fills (doall (set-shape-fills fills))] (recur (inc index) (into pending pending-fills)))) pending))] @@ -282,9 +298,9 @@ (defn- debug-flags [] - (let [debug-options 0] - (when (dbg/enabled? :wasm-viewbox) - (bit-or debug-options 2r00000000000000000000000000000001)))) + (cond-> 0 + (dbg/enabled? :wasm-viewbox) + (bit-or 2r00000000000000000000000000000001))) (defn assign-canvas [canvas] diff --git a/frontend/src/app/render_wasm/path.cljs b/frontend/src/app/render_wasm/path.cljs new file mode 100644 index 000000000..19a4d93c3 --- /dev/null +++ b/frontend/src/app/render_wasm/path.cljs @@ -0,0 +1,72 @@ +(ns app.render-wasm.path) + +(def command-size 28) + +#_(defn content->buffer + "Converts the path content into binary format." + [content] + (let [total (count content) + buffer (new js/ArrayBuffer (* total command-size)) + dview (new js/DataView buffer)] + (loop [index 0] + (when (< index total) + (let [segment (nth content index) + offset (* index command-size)] + (case (:command segment) + :move-to + (let [{:keys [x y]} (:params segment)] + (.setUint16 dview (+ offset 0) 1) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + :line-to + (let [{:keys [x y]} (:params segment)] + (.setUint16 dview (+ offset 0) 2) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + :curve-to + (let [{:keys [c1x c1y c2x c2y x y]} (:params segment)] + (.setUint16 dview (+ offset 0) 3) + (.setFloat32 dview (+ offset 4) c1x) + (.setFloat32 dview (+ offset 8) c1y) + (.setFloat32 dview (+ offset 12) c2x) + (.setFloat32 dview (+ offset 16) c2y) + (.setFloat32 dview (+ offset 20) x) + (.setFloat32 dview (+ offset 24) y)) + + :close-path + (.setUint16 dview (+ offset 0) 4)) + (recur (inc index))))) + buffer)) + +#_(defn buffer->content + "Converts the a buffer to a path content vector" + [buffer] + (assert (instance? js/ArrayBuffer buffer) "expected ArrayBuffer instance") + (let [total (/ (.-byteLength buffer) command-size) + dview (new js/DataView buffer)] + (loop [index 0 + result []] + (if (< index total) + (let [offset (* index command-size) + type (.getUint16 dview (+ offset 0)) + command (case type + 1 :move-to + 2 :line-to + 3 :curve-to + 4 :close-path) + params (case type + 1 {:x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 2 {:x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 3 {:c1x (.getFloat32 dview (+ offset 4)) + :c1y (.getFloat32 dview (+ offset 8)) + :c2x (.getFloat32 dview (+ offset 12)) + :c2y (.getFloat32 dview (+ offset 16)) + :x (.getFloat32 dview (+ offset 20)) + :y (.getFloat32 dview (+ offset 24))} + 4 {})] + (recur (inc index) + (conj result {:command command + :params params}))) + result)))) diff --git a/frontend/src/app/render_wasm/shape.cljs b/frontend/src/app/render_wasm/shape.cljs index 6290dbe79..3a2909669 100644 --- a/frontend/src/app/render_wasm/shape.cljs +++ b/frontend/src/app/render_wasm/shape.cljs @@ -10,6 +10,7 @@ [app.common.types.shape :as shape] ;; [app.common.svg.path :as path] [app.render-wasm.api :as api] + [app.render-wasm.path :as path] [clojure.core :as c] [cuerdas.core :as str])) @@ -120,6 +121,7 @@ :opacity (api/set-shape-opacity v) :hidden (api/set-shape-hidden v) :shapes (api/set-shape-children v) + :content (api/set-shape-path-content v) nil) ;; when something synced with wasm ;; is modified, we need to request diff --git a/render-wasm/src/main.rs b/render-wasm/src/main.rs index efa0566bf..b32236593 100644 --- a/render-wasm/src/main.rs +++ b/render-wasm/src/main.rs @@ -103,16 +103,15 @@ pub extern "C" fn use_shape(a: u32, b: u32, c: u32, d: u32) { } #[no_mangle] -pub unsafe extern "C" fn set_shape_selrect(left: f32, top: f32, right: f32, bottom: f32) { +pub extern "C" fn set_shape_selrect(left: f32, top: f32, right: f32, bottom: f32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); - if let Some(shape) = state.current_shape() { shape.selrect.set_ltrb(left, top, right, bottom); } } #[no_mangle] -pub unsafe extern "C" fn set_shape_rotation(rotation: f32) { +pub extern "C" fn set_shape_rotation(rotation: f32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); if let Some(shape) = state.current_shape() { shape.rotation = rotation; @@ -120,7 +119,7 @@ pub unsafe extern "C" fn set_shape_rotation(rotation: f32) { } #[no_mangle] -pub unsafe extern "C" fn set_shape_transform(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) { +pub extern "C" fn set_shape_transform(a: f32, b: f32, c: f32, d: f32, e: f32, f: f32) { let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); if let Some(shape) = state.current_shape() { shape.transform.a = a; @@ -271,6 +270,24 @@ pub extern "C" fn set_shape_hidden(hidden: bool) { } } +#[no_mangle] +pub extern "C" fn set_shape_path_content(n_segments: u32) { + let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer"); + + if let Some(shape) = state.current_shape() { + let len = n_segments as usize; + + unsafe { + let buffer = Vec::::from_raw_parts( + mem::buffer_ptr() as *mut shapes::RawPathData, + len, + len, + ); + mem::free_bytes(); + } + } +} + fn main() { init_gl(); } diff --git a/render-wasm/src/shapes.rs b/render-wasm/src/shapes.rs index 11785885e..1586d2f62 100644 --- a/render-wasm/src/shapes.rs +++ b/render-wasm/src/shapes.rs @@ -5,9 +5,11 @@ use uuid::Uuid; mod blend; mod fills; mod images; +mod paths; pub use blend::*; pub use fills::*; pub use images::*; +pub use paths::*; #[derive(Debug, Clone, Copy)] pub enum Kind { diff --git a/render-wasm/src/shapes/paths.rs b/render-wasm/src/shapes/paths.rs new file mode 100644 index 000000000..0232aa93d --- /dev/null +++ b/render-wasm/src/shapes/paths.rs @@ -0,0 +1,4 @@ +#[derive(Debug)] +pub struct RawPathData { + data: [u8; 28], +}