0
Fork 0
mirror of https://github.com/penpot/penpot.git synced 2025-01-21 06:02:32 -05:00

🎉 Implement drawing with blend mode (single fill)

This commit is contained in:
Belén Albeza 2024-11-13 16:39:26 +01:00
parent 7458165e51
commit 966e942a7f
5 changed files with 87 additions and 15 deletions

View file

@ -20,6 +20,7 @@
(defonce wasm-set-shape-transform (constantly nil))
(defonce wasm-set-shape-rotation (constantly nil))
(defonce wasm-set-shape-fills (constantly nil))
(defonce wasm-set-shape-blend-mode (constantly nil))
(defonce wasm-set-shape-children (constantly nil))
(cr/defrecord Shape [id name type x y width height rotation selrect points
@ -115,11 +116,12 @@
(when *wasm-sync*
(wasm-use-shape (:id coll))
(case k
:selrect (wasm-set-shape-selrect v)
:rotation (wasm-set-shape-rotation v)
:transform (wasm-set-shape-transform v)
:fills (wasm-set-shape-fills v)
:shapes (wasm-set-shape-children v)
:selrect (wasm-set-shape-selrect v)
:rotation (wasm-set-shape-rotation v)
:transform (wasm-set-shape-transform v)
:fills (wasm-set-shape-fills v)
:blend-mode (wasm-set-shape-blend-mode v)
:shapes (wasm-set-shape-children v)
nil))
(let [delegate (.-delegate ^ShapeProxy coll)
delegate' (assoc delegate k v)]

View file

@ -74,24 +74,50 @@
[r g b] (cc/hex->rgb (:fill-color fill))]
(._add_shape_solid_fill ^js internal-module r g b a))))
(defn set-shape-blend-mode
[blend-mode]
;; 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)]
(._set_shape_blend_mode ^js internal-module encoded-blend)))
(defn set-objects
[objects]
(let [shapes (into [] xform (vals objects))
total-shapes (count shapes)]
(loop [index 0]
(when (< index total-shapes)
(let [shape (nth shapes index)
id (dm/get-prop shape :id)
selrect (dm/get-prop shape :selrect)
rotation (dm/get-prop shape :rotation)
transform (dm/get-prop shape :transform)
fills (dm/get-prop shape :fills)
children (dm/get-prop shape :shapes)]
(let [shape (nth shapes index)
id (dm/get-prop shape :id)
selrect (dm/get-prop shape :selrect)
rotation (dm/get-prop shape :rotation)
transform (dm/get-prop shape :transform)
fills (dm/get-prop shape :fills)
children (dm/get-prop shape :shapes)
blend-mode (dm/get-prop shape :blend-mode)]
(use-shape id)
(set-shape-selrect selrect)
(set-shape-rotation rotation)
(set-shape-transform transform)
(set-shape-fills fills)
(set-shape-blend-mode blend-mode)
(set-shape-children children)
(recur (inc index)))))))
@ -155,4 +181,5 @@
(set! app.common.types.shape.impl/wasm-set-shape-transform set-shape-transform)
(set! app.common.types.shape.impl/wasm-set-shape-rotation set-shape-rotation)
(set! app.common.types.shape.impl/wasm-set-shape-fills set-shape-fills)
(set! app.common.types.shape.impl/wasm-set-shape-blend-mode set-shape-blend-mode)
(set! app.common.types.shape.impl/wasm-set-shape-children set-shape-children)

View file

@ -128,6 +128,14 @@ pub extern "C" fn clear_shape_fills() {
}
}
#[no_mangle]
pub extern "C" fn set_shape_blend_mode(mode: i32) {
let state = unsafe { STATE.as_mut() }.expect("got an invalid state pointer");
if let Some(shape) = state.current_shape() {
shape.set_blend_mode(shapes::BlendMode::from(mode));
}
}
fn main() {
render::init_gl();
}

View file

@ -141,7 +141,10 @@ fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) {
surface.canvas().concat(&matrix);
// TODO: use blend mode for the shape as a whole, not in each fill
for fill in shape.fills().rev() {
surface.canvas().draw_rect(r, &fill.to_paint());
let mut p = fill.to_paint();
p.set_blend_mode(shape.blend_mode.into());
surface.canvas().draw_rect(r, &p);
}
}

View file

@ -72,7 +72,6 @@ impl Fill {
p.set_color(*color);
p.set_style(skia::PaintStyle::Fill);
p.set_anti_alias(true);
// TODO: get proper blend mode. See https://tree.taiga.io/project/penpot/task/9275
p.set_blend_mode(skia::BlendMode::SrcOver);
p
}
@ -80,15 +79,43 @@ impl Fill {
}
}
#[derive(Debug, PartialEq, Clone, Copy)]
pub struct BlendMode(skia::BlendMode);
impl Default for BlendMode {
fn default() -> Self {
BlendMode(skia::BlendMode::SrcOver)
}
}
impl From<i32> for BlendMode {
fn from(value: i32) -> Self {
if value <= skia::BlendMode::Luminosity as i32 {
unsafe { Self(std::mem::transmute(value)) }
} else {
Self::default()
}
}
}
impl Into<skia::BlendMode> for BlendMode {
fn into(self) -> skia::BlendMode {
match self {
Self(skia_blend) => skia_blend,
}
}
}
#[derive(Debug, Clone)]
pub struct Shape {
pub id: Uuid,
pub children: Vec::<Uuid>,
pub children: Vec<Uuid>,
pub kind: Kind,
pub selrect: Rect,
pub transform: Matrix,
pub rotation: f32,
fills: Vec<Fill>,
pub blend_mode: BlendMode,
}
impl Shape {
@ -101,6 +128,7 @@ impl Shape {
transform: Matrix::identity(),
rotation: 0.,
fills: vec![],
blend_mode: BlendMode::default(),
}
}
@ -127,4 +155,8 @@ impl Shape {
pub fn clear_fills(&mut self) {
self.fills.clear();
}
pub fn set_blend_mode(&mut self, mode: BlendMode) {
self.blend_mode = mode;
}
}