mirror of
https://github.com/penpot/penpot.git
synced 2025-02-08 08:09:14 -05:00
🎉 Implement drawing with blend mode (single fill)
This commit is contained in:
parent
7458165e51
commit
966e942a7f
5 changed files with 87 additions and 15 deletions
|
@ -20,6 +20,7 @@
|
||||||
(defonce wasm-set-shape-transform (constantly nil))
|
(defonce wasm-set-shape-transform (constantly nil))
|
||||||
(defonce wasm-set-shape-rotation (constantly nil))
|
(defonce wasm-set-shape-rotation (constantly nil))
|
||||||
(defonce wasm-set-shape-fills (constantly nil))
|
(defonce wasm-set-shape-fills (constantly nil))
|
||||||
|
(defonce wasm-set-shape-blend-mode (constantly nil))
|
||||||
(defonce wasm-set-shape-children (constantly nil))
|
(defonce wasm-set-shape-children (constantly nil))
|
||||||
|
|
||||||
(cr/defrecord Shape [id name type x y width height rotation selrect points
|
(cr/defrecord Shape [id name type x y width height rotation selrect points
|
||||||
|
@ -119,6 +120,7 @@
|
||||||
:rotation (wasm-set-shape-rotation v)
|
:rotation (wasm-set-shape-rotation v)
|
||||||
:transform (wasm-set-shape-transform v)
|
:transform (wasm-set-shape-transform v)
|
||||||
:fills (wasm-set-shape-fills v)
|
:fills (wasm-set-shape-fills v)
|
||||||
|
:blend-mode (wasm-set-shape-blend-mode v)
|
||||||
:shapes (wasm-set-shape-children v)
|
:shapes (wasm-set-shape-children v)
|
||||||
nil))
|
nil))
|
||||||
(let [delegate (.-delegate ^ShapeProxy coll)
|
(let [delegate (.-delegate ^ShapeProxy coll)
|
||||||
|
|
|
@ -74,6 +74,30 @@
|
||||||
[r g b] (cc/hex->rgb (:fill-color fill))]
|
[r g b] (cc/hex->rgb (:fill-color fill))]
|
||||||
(._add_shape_solid_fill ^js internal-module r g b a))))
|
(._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
|
(defn set-objects
|
||||||
[objects]
|
[objects]
|
||||||
(let [shapes (into [] xform (vals objects))
|
(let [shapes (into [] xform (vals objects))
|
||||||
|
@ -86,12 +110,14 @@
|
||||||
rotation (dm/get-prop shape :rotation)
|
rotation (dm/get-prop shape :rotation)
|
||||||
transform (dm/get-prop shape :transform)
|
transform (dm/get-prop shape :transform)
|
||||||
fills (dm/get-prop shape :fills)
|
fills (dm/get-prop shape :fills)
|
||||||
children (dm/get-prop shape :shapes)]
|
children (dm/get-prop shape :shapes)
|
||||||
|
blend-mode (dm/get-prop shape :blend-mode)]
|
||||||
(use-shape id)
|
(use-shape id)
|
||||||
(set-shape-selrect selrect)
|
(set-shape-selrect selrect)
|
||||||
(set-shape-rotation rotation)
|
(set-shape-rotation rotation)
|
||||||
(set-shape-transform transform)
|
(set-shape-transform transform)
|
||||||
(set-shape-fills fills)
|
(set-shape-fills fills)
|
||||||
|
(set-shape-blend-mode blend-mode)
|
||||||
(set-shape-children children)
|
(set-shape-children children)
|
||||||
(recur (inc index)))))))
|
(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-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-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-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)
|
(set! app.common.types.shape.impl/wasm-set-shape-children set-shape-children)
|
||||||
|
|
|
@ -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() {
|
fn main() {
|
||||||
render::init_gl();
|
render::init_gl();
|
||||||
}
|
}
|
||||||
|
|
|
@ -141,7 +141,10 @@ fn render_single_shape(surface: &mut skia::Surface, shape: &Shape) {
|
||||||
|
|
||||||
surface.canvas().concat(&matrix);
|
surface.canvas().concat(&matrix);
|
||||||
|
|
||||||
|
// TODO: use blend mode for the shape as a whole, not in each fill
|
||||||
for fill in shape.fills().rev() {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,7 +72,6 @@ impl Fill {
|
||||||
p.set_color(*color);
|
p.set_color(*color);
|
||||||
p.set_style(skia::PaintStyle::Fill);
|
p.set_style(skia::PaintStyle::Fill);
|
||||||
p.set_anti_alias(true);
|
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.set_blend_mode(skia::BlendMode::SrcOver);
|
||||||
p
|
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)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Shape {
|
pub struct Shape {
|
||||||
pub id: Uuid,
|
pub id: Uuid,
|
||||||
pub children: Vec::<Uuid>,
|
pub children: Vec<Uuid>,
|
||||||
pub kind: Kind,
|
pub kind: Kind,
|
||||||
pub selrect: Rect,
|
pub selrect: Rect,
|
||||||
pub transform: Matrix,
|
pub transform: Matrix,
|
||||||
pub rotation: f32,
|
pub rotation: f32,
|
||||||
fills: Vec<Fill>,
|
fills: Vec<Fill>,
|
||||||
|
pub blend_mode: BlendMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Shape {
|
impl Shape {
|
||||||
|
@ -101,6 +128,7 @@ impl Shape {
|
||||||
transform: Matrix::identity(),
|
transform: Matrix::identity(),
|
||||||
rotation: 0.,
|
rotation: 0.,
|
||||||
fills: vec![],
|
fills: vec![],
|
||||||
|
blend_mode: BlendMode::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -127,4 +155,8 @@ impl Shape {
|
||||||
pub fn clear_fills(&mut self) {
|
pub fn clear_fills(&mut self) {
|
||||||
self.fills.clear();
|
self.fills.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_blend_mode(&mut self, mode: BlendMode) {
|
||||||
|
self.blend_mode = mode;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue