diff --git a/frontend/src/app/render_wasm/api.cljs b/frontend/src/app/render_wasm/api.cljs index 9ed04e556e..caf29baf3e 100644 --- a/frontend/src/app/render_wasm/api.cljs +++ b/frontend/src/app/render_wasm/api.cljs @@ -236,17 +236,13 @@ (h/call wasm/internal-module "_add_shape_radial_fill"))) (some? image) - (let [id (dm/get-prop image :id) + (let [heap (mem/get-heap-u32) + offset (mem/alloc-bytes sr-fills/IMAGE-BYTE-SIZE) + id (dm/get-prop image :id) buffer (uuid/get-u32 id) cached-image? (h/call wasm/internal-module "_is_image_cached" (aget buffer 0) (aget buffer 1) (aget buffer 2) (aget buffer 3))] - (h/call wasm/internal-module "_add_shape_image_fill" - (aget buffer 0) - (aget buffer 1) - (aget buffer 2) - (aget buffer 3) - opacity - (dm/get-prop image :width) - (dm/get-prop image :height)) + (sr-fills/write-image-fill! offset heap id opacity (dm/get-prop image :width) (dm/get-prop image :height)) + (h/call wasm/internal-module "_add_shape_image_fill") (when (== cached-image? 0) (store-image id)))))) fills)) diff --git a/frontend/src/app/render_wasm/serializers/fills.cljs b/frontend/src/app/render_wasm/serializers/fills.cljs index 685030e558..32ee70887a 100644 --- a/frontend/src/app/render_wasm/serializers/fills.cljs +++ b/frontend/src/app/render_wasm/serializers/fills.cljs @@ -1,5 +1,6 @@ (ns app.render-wasm.serializers.fills (:require + [app.common.uuid :as uuid] [app.render-wasm.serializers.color :as clr])) (def SOLID-BYTE-SIZE 4) @@ -10,6 +11,22 @@ (.setUint32 dview offset argb true) (+ offset 4))) +(def IMAGE-BYTE-SIZE 28) + +(defn write-image-fill! + [offset heap-u32 id opacity width height] + (js/console.log "write-image-fill!" (str id) opacity width height) + (let [dview (js/DataView. (.-buffer heap-u32)) + uuid-buffer (uuid/get-u32 id)] + (.setUint32 dview offset (aget uuid-buffer 0) true) + (.setUint32 dview (+ offset 4) (aget uuid-buffer 1) true) + (.setUint32 dview (+ offset 8) (aget uuid-buffer 2) true) + (.setUint32 dview (+ offset 12) (aget uuid-buffer 3) true) + (.setFloat32 dview (+ offset 16) opacity true) + (.setInt32 dview (+ offset 20) width true) + (.setInt32 dview (+ offset 24) height true) + (+ offset 28))) + (def ^:private GRADIENT-STOP-SIZE 8) (def ^:private GRADIENT-BASE-SIZE 28) ;; TODO: Define in shape model diff --git a/render-wasm/src/shapes/fills.rs b/render-wasm/src/shapes/fills.rs index 948b962728..0263bdd94f 100644 --- a/render-wasm/src/shapes/fills.rs +++ b/render-wasm/src/shapes/fills.rs @@ -98,11 +98,20 @@ impl Gradient { pub struct ImageFill { id: Uuid, opacity: u8, - height: i32, width: i32, + height: i32, } impl ImageFill { + pub fn new(id: Uuid, opacity: u8, width: i32, height: i32) -> Self { + Self { + id, + opacity, + width, + height, + } + } + pub fn size(&self) -> (i32, i32) { (self.width, self.height) } @@ -124,15 +133,6 @@ pub enum Fill { } impl Fill { - pub fn new_image_fill(id: Uuid, opacity: u8, (width, height): (i32, i32)) -> Self { - Self::Image(ImageFill { - id, - opacity, - height, - width, - }) - } - pub fn to_paint(&self, rect: &Rect, anti_alias: bool) -> skia::Paint { match self { Self::Solid(SolidColor(color)) => { diff --git a/render-wasm/src/wasm/fills.rs b/render-wasm/src/wasm/fills.rs index c5dbf19e04..9d74a85797 100644 --- a/render-wasm/src/wasm/fills.rs +++ b/render-wasm/src/wasm/fills.rs @@ -1,9 +1,9 @@ mod gradient; +mod image; mod solid; use crate::mem; use crate::shapes; -use crate::utils::uuid_from_u32_quartet; use crate::with_current_shape; use crate::STATE; @@ -37,22 +37,12 @@ pub extern "C" fn add_shape_radial_fill() { } #[no_mangle] -pub extern "C" fn add_shape_image_fill( - a: u32, - b: u32, - c: u32, - d: u32, - alpha: f32, - width: i32, - height: i32, -) { +pub extern "C" fn add_shape_image_fill() { with_current_shape!(state, |shape: &mut Shape| { - let id = uuid_from_u32_quartet(a, b, c, d); - shape.add_fill(shapes::Fill::new_image_fill( - id, - (alpha * 0xff as f32).floor() as u8, - (width, height), - )); + let bytes = mem::bytes(); + let image_fill = shapes::ImageFill::try_from(&bytes[..]).expect("Invalid image fill data"); + + shape.add_fill(shapes::Fill::Image(image_fill)); }); } diff --git a/render-wasm/src/wasm/fills/image.rs b/render-wasm/src/wasm/fills/image.rs new file mode 100644 index 0000000000..a233b817d4 --- /dev/null +++ b/render-wasm/src/wasm/fills/image.rs @@ -0,0 +1,66 @@ +use crate::{shapes::ImageFill, utils::uuid_from_u32_quartet}; + +const RAW_IMAGE_DATA_SIZE: usize = 28; + +#[derive(Debug, Clone, Copy, PartialEq)] +#[repr(C)] +pub struct RawImageFillData { + a: u32, + b: u32, + c: u32, + d: u32, + opacity: f32, + width: i32, + height: i32, +} + +impl From for ImageFill { + fn from(value: RawImageFillData) -> Self { + let id = uuid_from_u32_quartet(value.a, value.b, value.c, value.d); + let opacity = (value.opacity * 255.).floor() as u8; + + Self::new(id, opacity, value.width, value.height) + } +} + +impl From<[u8; RAW_IMAGE_DATA_SIZE]> for RawImageFillData { + fn from(value: [u8; RAW_IMAGE_DATA_SIZE]) -> Self { + let a = u32::from_le_bytes([value[0], value[1], value[2], value[3]]); + let b = u32::from_le_bytes([value[4], value[5], value[6], value[7]]); + let c = u32::from_le_bytes([value[8], value[9], value[10], value[11]]); + let d = u32::from_le_bytes([value[12], value[13], value[14], value[15]]); + let opacity = f32::from_le_bytes([value[16], value[17], value[18], value[19]]); + let width = i32::from_le_bytes([value[20], value[21], value[22], value[23]]); + let height = i32::from_le_bytes([value[24], value[25], value[26], value[27]]); + + Self { + a, + b, + c, + d, + opacity, + width, + height, + } + } +} + +impl TryFrom<&[u8]> for RawImageFillData { + type Error = String; + + fn try_from(value: &[u8]) -> Result { + let data: [u8; RAW_IMAGE_DATA_SIZE] = value + .try_into() + .map_err(|_| "Invalid image fill data".to_string())?; + Ok(Self::from(data)) + } +} + +impl TryFrom<&[u8]> for ImageFill { + type Error = String; + + fn try_from(value: &[u8]) -> Result { + let raw_image_data = RawImageFillData::try_from(value)?; + Ok(raw_image_data.into()) + } +} diff --git a/render-wasm/src/wasm/strokes.rs b/render-wasm/src/wasm/strokes.rs index 575890d0f3..72b6ea43d5 100644 --- a/render-wasm/src/wasm/strokes.rs +++ b/render-wasm/src/wasm/strokes.rs @@ -1,6 +1,5 @@ use crate::mem; use crate::shapes; -use crate::utils::uuid_from_u32_quartet; use crate::with_current_shape; use crate::STATE; @@ -68,23 +67,13 @@ pub extern "C" fn add_shape_stroke_radial_fill() { } #[no_mangle] -pub extern "C" fn add_shape_image_stroke( - a: u32, - b: u32, - c: u32, - d: u32, - alpha: f32, - width: i32, - height: i32, -) { +pub extern "C" fn add_shape_image_stroke() { with_current_shape!(state, |shape: &mut Shape| { - let id = uuid_from_u32_quartet(a, b, c, d); + let bytes = mem::bytes(); + let image_fill = shapes::ImageFill::try_from(&bytes[..]).expect("Invalid image fill data"); + shape - .set_stroke_fill(shapes::Fill::new_image_fill( - id, - (alpha * 0xff as f32).floor() as u8, - (width, height), - )) + .set_stroke_fill(shapes::Fill::Image(image_fill)) .expect("could not add stroke image fill"); }); }