mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-27 10:48:11 +08:00
Add masking
This commit is contained in:
@@ -16,7 +16,7 @@ use graph_craft::document::value::*;
|
|||||||
use graph_craft::document::*;
|
use graph_craft::document::*;
|
||||||
use graphene_std::ops::XY;
|
use graphene_std::ops::XY;
|
||||||
use graphene_std::raster::brush_cache::BrushCache;
|
use graphene_std::raster::brush_cache::BrushCache;
|
||||||
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, Color, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
|
use graphene_std::raster::{CellularDistanceFunction, CellularReturnType, DomainWarpType, FractalType, NoiseType, RedGreenBlueAlpha};
|
||||||
use graphene_std::raster_types::{CPU, RasterDataTable};
|
use graphene_std::raster_types::{CPU, RasterDataTable};
|
||||||
use graphene_std::text::{Font, TypesettingConfig};
|
use graphene_std::text::{Font, TypesettingConfig};
|
||||||
use graphene_std::transform::Footprint;
|
use graphene_std::transform::Footprint;
|
||||||
|
|||||||
@@ -101,6 +101,7 @@ pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
|||||||
for (graphic_element, source_node_id) in old.elements {
|
for (graphic_element, source_node_id) in old.elements {
|
||||||
graphic_group_table.push(Instance {
|
graphic_group_table.push(Instance {
|
||||||
instance: graphic_element,
|
instance: graphic_element,
|
||||||
|
mask: None,
|
||||||
transform: old.transform,
|
transform: old.transform,
|
||||||
alpha_blending: old.alpha_blending,
|
alpha_blending: old.alpha_blending,
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -116,6 +117,7 @@ pub fn migrate_graphic_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
|||||||
for (graphic_element, source_node_id) in &instance.instance.elements {
|
for (graphic_element, source_node_id) in &instance.instance.elements {
|
||||||
graphic_group_table.push(Instance {
|
graphic_group_table.push(Instance {
|
||||||
instance: graphic_element.clone(),
|
instance: graphic_element.clone(),
|
||||||
|
mask: None,
|
||||||
transform: *instance.transform,
|
transform: *instance.transform,
|
||||||
alpha_blending: *instance.alpha_blending,
|
alpha_blending: *instance.alpha_blending,
|
||||||
source_node_id: *source_node_id,
|
source_node_id: *source_node_id,
|
||||||
@@ -332,6 +334,7 @@ pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D)
|
|||||||
for (artboard, source_node_id) in artboard_group.artboards {
|
for (artboard, source_node_id) in artboard_group.artboards {
|
||||||
table.push(Instance {
|
table.push(Instance {
|
||||||
instance: artboard,
|
instance: artboard,
|
||||||
|
mask: None,
|
||||||
transform: DAffine2::IDENTITY,
|
transform: DAffine2::IDENTITY,
|
||||||
alpha_blending: AlphaBlending::default(),
|
alpha_blending: AlphaBlending::default(),
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -352,6 +355,7 @@ async fn layer(_: impl Ctx, mut stack: GraphicGroupTable, element: GraphicElemen
|
|||||||
|
|
||||||
stack.push(Instance {
|
stack.push(Instance {
|
||||||
instance: element,
|
instance: element,
|
||||||
|
mask: None,
|
||||||
transform: DAffine2::IDENTITY,
|
transform: DAffine2::IDENTITY,
|
||||||
alpha_blending: AlphaBlending::default(),
|
alpha_blending: AlphaBlending::default(),
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -412,6 +416,7 @@ async fn flatten_group(_: impl Ctx, group: GraphicGroupTable, fully_flatten: boo
|
|||||||
_ => {
|
_ => {
|
||||||
output_group_table.push(Instance {
|
output_group_table.push(Instance {
|
||||||
instance: current_element,
|
instance: current_element,
|
||||||
|
mask: None,
|
||||||
transform: *current_instance.transform,
|
transform: *current_instance.transform,
|
||||||
alpha_blending: *current_instance.alpha_blending,
|
alpha_blending: *current_instance.alpha_blending,
|
||||||
source_node_id: reference,
|
source_node_id: reference,
|
||||||
@@ -450,6 +455,7 @@ async fn flatten_vector(_: impl Ctx, group: GraphicGroupTable) -> VectorDataTabl
|
|||||||
for current_element in vector_instance.instance_ref_iter() {
|
for current_element in vector_instance.instance_ref_iter() {
|
||||||
output_group_table.push(Instance {
|
output_group_table.push(Instance {
|
||||||
instance: current_element.instance.clone(),
|
instance: current_element.instance.clone(),
|
||||||
|
mask: None,
|
||||||
transform: *current_instance.transform * *current_element.transform,
|
transform: *current_instance.transform * *current_element.transform,
|
||||||
alpha_blending: AlphaBlending {
|
alpha_blending: AlphaBlending {
|
||||||
blend_mode: current_element.alpha_blending.blend_mode,
|
blend_mode: current_element.alpha_blending.blend_mode,
|
||||||
@@ -514,6 +520,7 @@ async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artb
|
|||||||
|
|
||||||
artboards.push(Instance {
|
artboards.push(Instance {
|
||||||
instance: artboard,
|
instance: artboard,
|
||||||
|
mask: None,
|
||||||
transform: DAffine2::IDENTITY,
|
transform: DAffine2::IDENTITY,
|
||||||
alpha_blending: AlphaBlending::default(),
|
alpha_blending: AlphaBlending::default(),
|
||||||
source_node_id: encapsulating_node_id,
|
source_node_id: encapsulating_node_id,
|
||||||
|
|||||||
@@ -432,6 +432,20 @@ impl GraphicElementRendered for GraphicGroupTable {
|
|||||||
|
|
||||||
attributes.push(mask_type.to_attribute(), selector);
|
attributes.push(mask_type.to_attribute(), selector);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(mask) = instance.mask {
|
||||||
|
let uuid = generate_uuid();
|
||||||
|
let mask_type = if mask.can_reduce_to_clip_path() { MaskType::Clip } else { MaskType::Mask };
|
||||||
|
let mut svg = SvgRender::new();
|
||||||
|
mask.render_svg(&mut svg, &render_params.for_clipper());
|
||||||
|
|
||||||
|
write!(&mut attributes.0.svg_defs, r##"{}"##, svg.svg_defs).unwrap();
|
||||||
|
mask_type.write_to_defs(&mut attributes.0.svg_defs, uuid, svg.svg.to_svg_string());
|
||||||
|
let id = format!("mask-{}", uuid);
|
||||||
|
let selector = format!("url(#{id})");
|
||||||
|
|
||||||
|
attributes.push(mask_type.to_attribute(), selector);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|render| {
|
|render| {
|
||||||
instance.instance.render_svg(render, render_params);
|
instance.instance.render_svg(render, render_params);
|
||||||
@@ -474,6 +488,20 @@ impl GraphicElementRendered for GraphicGroupTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let mut masked = false;
|
||||||
|
if let Some(mask) = instance.mask {
|
||||||
|
let bounds = mask.bounding_box(transform, true);
|
||||||
|
|
||||||
|
if let Some(bounds) = bounds {
|
||||||
|
masked = true;
|
||||||
|
let rect = vello::kurbo::Rect::new(bounds[0].x, bounds[0].y, bounds[1].x, bounds[1].y);
|
||||||
|
|
||||||
|
scene.push_layer(peniko::Mix::Normal, 1., kurbo::Affine::IDENTITY, &rect);
|
||||||
|
mask.render_to_vello(scene, transform, context, &render_params.for_clipper());
|
||||||
|
scene.push_layer(peniko::BlendMode::new(peniko::Mix::Clip, peniko::Compose::SrcIn), 1., kurbo::Affine::IDENTITY, &rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let next_clips = iter.peek().is_some_and(|next_instance| next_instance.instance.had_clip_enabled());
|
let next_clips = iter.peek().is_some_and(|next_instance| next_instance.instance.had_clip_enabled());
|
||||||
if next_clips && mask_instance_state.is_none() {
|
if next_clips && mask_instance_state.is_none() {
|
||||||
mask_instance_state = Some((instance.instance, transform));
|
mask_instance_state = Some((instance.instance, transform));
|
||||||
@@ -502,6 +530,11 @@ impl GraphicElementRendered for GraphicGroupTable {
|
|||||||
instance.instance.render_to_vello(scene, transform, context, render_params);
|
instance.instance.render_to_vello(scene, transform, context, render_params);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if masked {
|
||||||
|
scene.pop_layer();
|
||||||
|
scene.pop_layer();
|
||||||
|
}
|
||||||
|
|
||||||
if layer {
|
if layer {
|
||||||
scene.pop_layer();
|
scene.pop_layer();
|
||||||
}
|
}
|
||||||
@@ -614,6 +647,7 @@ impl GraphicElementRendered for VectorDataTable {
|
|||||||
|
|
||||||
vector_row.push(Instance {
|
vector_row.push(Instance {
|
||||||
instance: fill_instance,
|
instance: fill_instance,
|
||||||
|
mask: None,
|
||||||
alpha_blending: *instance.alpha_blending,
|
alpha_blending: *instance.alpha_blending,
|
||||||
transform: *instance.transform,
|
transform: *instance.transform,
|
||||||
source_node_id: None,
|
source_node_id: None,
|
||||||
@@ -734,6 +768,7 @@ impl GraphicElementRendered for VectorDataTable {
|
|||||||
|
|
||||||
vector_data.push(Instance {
|
vector_data.push(Instance {
|
||||||
instance: fill_instance,
|
instance: fill_instance,
|
||||||
|
mask: None,
|
||||||
alpha_blending: *instance.alpha_blending,
|
alpha_blending: *instance.alpha_blending,
|
||||||
transform: *instance.transform,
|
transform: *instance.transform,
|
||||||
source_node_id: None,
|
source_node_id: None,
|
||||||
|
|||||||
@@ -1,13 +1,17 @@
|
|||||||
use crate::AlphaBlending;
|
use crate::{AlphaBlending, GraphicElement};
|
||||||
use crate::uuid::NodeId;
|
use crate::uuid::NodeId;
|
||||||
use dyn_any::StaticType;
|
use dyn_any::StaticType;
|
||||||
use glam::DAffine2;
|
use glam::DAffine2;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub type Mask = Option<GraphicElement>;
|
||||||
|
|
||||||
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Instances<T> {
|
pub struct Instances<T> {
|
||||||
#[serde(alias = "instances")]
|
#[serde(alias = "instances")]
|
||||||
instance: Vec<T>,
|
instance: Vec<T>,
|
||||||
|
#[serde(default = "one_mask_default")]
|
||||||
|
mask: Vec<Mask>,
|
||||||
#[serde(default = "one_daffine2_default")]
|
#[serde(default = "one_daffine2_default")]
|
||||||
transform: Vec<DAffine2>,
|
transform: Vec<DAffine2>,
|
||||||
#[serde(default = "one_alpha_blending_default")]
|
#[serde(default = "one_alpha_blending_default")]
|
||||||
@@ -20,6 +24,7 @@ impl<T> Instances<T> {
|
|||||||
pub fn new(instance: T) -> Self {
|
pub fn new(instance: T) -> Self {
|
||||||
Self {
|
Self {
|
||||||
instance: vec![instance],
|
instance: vec![instance],
|
||||||
|
mask: vec![None],
|
||||||
transform: vec![DAffine2::IDENTITY],
|
transform: vec![DAffine2::IDENTITY],
|
||||||
alpha_blending: vec![AlphaBlending::default()],
|
alpha_blending: vec![AlphaBlending::default()],
|
||||||
source_node_id: vec![None],
|
source_node_id: vec![None],
|
||||||
@@ -28,6 +33,7 @@ impl<T> Instances<T> {
|
|||||||
|
|
||||||
pub fn push(&mut self, instance: Instance<T>) {
|
pub fn push(&mut self, instance: Instance<T>) {
|
||||||
self.instance.push(instance.instance);
|
self.instance.push(instance.instance);
|
||||||
|
self.mask.push(instance.mask);
|
||||||
self.transform.push(instance.transform);
|
self.transform.push(instance.transform);
|
||||||
self.alpha_blending.push(instance.alpha_blending);
|
self.alpha_blending.push(instance.alpha_blending);
|
||||||
self.source_node_id.push(instance.source_node_id);
|
self.source_node_id.push(instance.source_node_id);
|
||||||
@@ -43,11 +49,13 @@ impl<T> Instances<T> {
|
|||||||
pub fn instance_iter(self) -> impl DoubleEndedIterator<Item = Instance<T>> {
|
pub fn instance_iter(self) -> impl DoubleEndedIterator<Item = Instance<T>> {
|
||||||
self.instance
|
self.instance
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
.zip(self.mask)
|
||||||
.zip(self.transform)
|
.zip(self.transform)
|
||||||
.zip(self.alpha_blending)
|
.zip(self.alpha_blending)
|
||||||
.zip(self.source_node_id)
|
.zip(self.source_node_id)
|
||||||
.map(|(((instance, transform), alpha_blending), source_node_id)| Instance {
|
.map(|((((instance, mask), transform), alpha_blending), source_node_id)| Instance {
|
||||||
instance,
|
instance,
|
||||||
|
mask,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -57,11 +65,13 @@ impl<T> Instances<T> {
|
|||||||
pub fn instance_ref_iter(&self) -> impl DoubleEndedIterator<Item = InstanceRef<T>> + Clone {
|
pub fn instance_ref_iter(&self) -> impl DoubleEndedIterator<Item = InstanceRef<T>> + Clone {
|
||||||
self.instance
|
self.instance
|
||||||
.iter()
|
.iter()
|
||||||
|
.zip(self.mask.iter())
|
||||||
.zip(self.transform.iter())
|
.zip(self.transform.iter())
|
||||||
.zip(self.alpha_blending.iter())
|
.zip(self.alpha_blending.iter())
|
||||||
.zip(self.source_node_id.iter())
|
.zip(self.source_node_id.iter())
|
||||||
.map(|(((instance, transform), alpha_blending), source_node_id)| InstanceRef {
|
.map(|((((instance, mask), transform), alpha_blending), source_node_id)| InstanceRef {
|
||||||
instance,
|
instance,
|
||||||
|
mask,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -71,11 +81,13 @@ impl<T> Instances<T> {
|
|||||||
pub fn instance_mut_iter(&mut self) -> impl DoubleEndedIterator<Item = InstanceMut<T>> {
|
pub fn instance_mut_iter(&mut self) -> impl DoubleEndedIterator<Item = InstanceMut<T>> {
|
||||||
self.instance
|
self.instance
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
.zip(self.mask.iter_mut())
|
||||||
.zip(self.transform.iter_mut())
|
.zip(self.transform.iter_mut())
|
||||||
.zip(self.alpha_blending.iter_mut())
|
.zip(self.alpha_blending.iter_mut())
|
||||||
.zip(self.source_node_id.iter_mut())
|
.zip(self.source_node_id.iter_mut())
|
||||||
.map(|(((instance, transform), alpha_blending), source_node_id)| InstanceMut {
|
.map(|((((instance, mask), transform), alpha_blending), source_node_id)| InstanceMut {
|
||||||
instance,
|
instance,
|
||||||
|
mask,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
source_node_id,
|
source_node_id,
|
||||||
@@ -89,6 +101,7 @@ impl<T> Instances<T> {
|
|||||||
|
|
||||||
Some(InstanceRef {
|
Some(InstanceRef {
|
||||||
instance: &self.instance[index],
|
instance: &self.instance[index],
|
||||||
|
mask: &self.mask[index],
|
||||||
transform: &self.transform[index],
|
transform: &self.transform[index],
|
||||||
alpha_blending: &self.alpha_blending[index],
|
alpha_blending: &self.alpha_blending[index],
|
||||||
source_node_id: &self.source_node_id[index],
|
source_node_id: &self.source_node_id[index],
|
||||||
@@ -102,6 +115,7 @@ impl<T> Instances<T> {
|
|||||||
|
|
||||||
Some(InstanceMut {
|
Some(InstanceMut {
|
||||||
instance: &mut self.instance[index],
|
instance: &mut self.instance[index],
|
||||||
|
mask: &mut self.mask[index],
|
||||||
transform: &mut self.transform[index],
|
transform: &mut self.transform[index],
|
||||||
alpha_blending: &mut self.alpha_blending[index],
|
alpha_blending: &mut self.alpha_blending[index],
|
||||||
source_node_id: &mut self.source_node_id[index],
|
source_node_id: &mut self.source_node_id[index],
|
||||||
@@ -121,6 +135,7 @@ impl<T> Default for Instances<T> {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
instance: Vec::new(),
|
instance: Vec::new(),
|
||||||
|
mask: Vec::new(),
|
||||||
transform: Vec::new(),
|
transform: Vec::new(),
|
||||||
alpha_blending: Vec::new(),
|
alpha_blending: Vec::new(),
|
||||||
source_node_id: Vec::new(),
|
source_node_id: Vec::new(),
|
||||||
@@ -146,6 +161,9 @@ unsafe impl<T: StaticType + 'static> StaticType for Instances<T> {
|
|||||||
type Static = Instances<T>;
|
type Static = Instances<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn one_mask_default() -> Vec<Mask> {
|
||||||
|
vec![None]
|
||||||
|
}
|
||||||
fn one_daffine2_default() -> Vec<DAffine2> {
|
fn one_daffine2_default() -> Vec<DAffine2> {
|
||||||
vec![DAffine2::IDENTITY]
|
vec![DAffine2::IDENTITY]
|
||||||
}
|
}
|
||||||
@@ -159,6 +177,7 @@ fn one_source_node_id_default() -> Vec<Option<NodeId>> {
|
|||||||
#[derive(Copy, Clone, Debug, PartialEq)]
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
||||||
pub struct InstanceRef<'a, T> {
|
pub struct InstanceRef<'a, T> {
|
||||||
pub instance: &'a T,
|
pub instance: &'a T,
|
||||||
|
pub mask: &'a Mask,
|
||||||
pub transform: &'a DAffine2,
|
pub transform: &'a DAffine2,
|
||||||
pub alpha_blending: &'a AlphaBlending,
|
pub alpha_blending: &'a AlphaBlending,
|
||||||
pub source_node_id: &'a Option<NodeId>,
|
pub source_node_id: &'a Option<NodeId>,
|
||||||
@@ -171,6 +190,7 @@ impl<T> InstanceRef<'_, T> {
|
|||||||
{
|
{
|
||||||
Instance {
|
Instance {
|
||||||
instance: self.instance.clone(),
|
instance: self.instance.clone(),
|
||||||
|
mask: self.mask.clone(),
|
||||||
transform: *self.transform,
|
transform: *self.transform,
|
||||||
alpha_blending: *self.alpha_blending,
|
alpha_blending: *self.alpha_blending,
|
||||||
source_node_id: *self.source_node_id,
|
source_node_id: *self.source_node_id,
|
||||||
@@ -181,14 +201,16 @@ impl<T> InstanceRef<'_, T> {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InstanceMut<'a, T> {
|
pub struct InstanceMut<'a, T> {
|
||||||
pub instance: &'a mut T,
|
pub instance: &'a mut T,
|
||||||
|
pub mask: &'a mut Mask,
|
||||||
pub transform: &'a mut DAffine2,
|
pub transform: &'a mut DAffine2,
|
||||||
pub alpha_blending: &'a mut AlphaBlending,
|
pub alpha_blending: &'a mut AlphaBlending,
|
||||||
pub source_node_id: &'a mut Option<NodeId>,
|
pub source_node_id: &'a mut Option<NodeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
#[derive(Clone, Default, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Instance<T> {
|
pub struct Instance<T> {
|
||||||
pub instance: T,
|
pub instance: T,
|
||||||
|
pub mask: Mask,
|
||||||
pub transform: DAffine2,
|
pub transform: DAffine2,
|
||||||
pub alpha_blending: AlphaBlending,
|
pub alpha_blending: AlphaBlending,
|
||||||
pub source_node_id: Option<NodeId>,
|
pub source_node_id: Option<NodeId>,
|
||||||
@@ -201,6 +223,7 @@ impl<T> Instance<T> {
|
|||||||
{
|
{
|
||||||
Instance {
|
Instance {
|
||||||
instance: self.instance.into(),
|
instance: self.instance.into(),
|
||||||
|
mask: self.mask,
|
||||||
transform: self.transform,
|
transform: self.transform,
|
||||||
alpha_blending: self.alpha_blending,
|
alpha_blending: self.alpha_blending,
|
||||||
source_node_id: self.source_node_id,
|
source_node_id: self.source_node_id,
|
||||||
@@ -210,6 +233,7 @@ impl<T> Instance<T> {
|
|||||||
pub fn to_instance_ref(&self) -> InstanceRef<T> {
|
pub fn to_instance_ref(&self) -> InstanceRef<T> {
|
||||||
InstanceRef {
|
InstanceRef {
|
||||||
instance: &self.instance,
|
instance: &self.instance,
|
||||||
|
mask: &self.mask,
|
||||||
transform: &self.transform,
|
transform: &self.transform,
|
||||||
alpha_blending: &self.alpha_blending,
|
alpha_blending: &self.alpha_blending,
|
||||||
source_node_id: &self.source_node_id,
|
source_node_id: &self.source_node_id,
|
||||||
@@ -219,6 +243,7 @@ impl<T> Instance<T> {
|
|||||||
pub fn to_instance_mut(&mut self) -> InstanceMut<T> {
|
pub fn to_instance_mut(&mut self) -> InstanceMut<T> {
|
||||||
InstanceMut {
|
InstanceMut {
|
||||||
instance: &mut self.instance,
|
instance: &mut self.instance,
|
||||||
|
mask: &mut self.mask,
|
||||||
transform: &mut self.transform,
|
transform: &mut self.transform,
|
||||||
alpha_blending: &mut self.alpha_blending,
|
alpha_blending: &mut self.alpha_blending,
|
||||||
source_node_id: &mut self.source_node_id,
|
source_node_id: &mut self.source_node_id,
|
||||||
@@ -228,6 +253,7 @@ impl<T> Instance<T> {
|
|||||||
pub fn to_table(self) -> Instances<T> {
|
pub fn to_table(self) -> Instances<T> {
|
||||||
Instances {
|
Instances {
|
||||||
instance: vec![self.instance],
|
instance: vec![self.instance],
|
||||||
|
mask: vec![self.mask],
|
||||||
transform: vec![self.transform],
|
transform: vec![self.transform],
|
||||||
alpha_blending: vec![self.alpha_blending],
|
alpha_blending: vec![self.alpha_blending],
|
||||||
source_node_id: vec![self.source_node_id],
|
source_node_id: vec![self.source_node_id],
|
||||||
|
|||||||
@@ -393,6 +393,7 @@ pub fn migrate_image_frame_instance<'de, D: serde::Deserializer<'de>>(deserializ
|
|||||||
},
|
},
|
||||||
FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => Instance {
|
FormatVersions::OldImageFrame(image_frame_with_transform_and_blending) => Instance {
|
||||||
instance: Raster::new_cpu(image_frame_with_transform_and_blending.image),
|
instance: Raster::new_cpu(image_frame_with_transform_and_blending.image),
|
||||||
|
mask: None,
|
||||||
transform: image_frame_with_transform_and_blending.transform,
|
transform: image_frame_with_transform_and_blending.transform,
|
||||||
alpha_blending: image_frame_with_transform_and_blending.alpha_blending,
|
alpha_blending: image_frame_with_transform_and_blending.alpha_blending,
|
||||||
source_node_id: None,
|
source_node_id: None,
|
||||||
@@ -461,6 +462,7 @@ impl From<Image<Color>> for Image<SRGBA8> {
|
|||||||
// for image_frame_instance in image_frame_table.instance_iter() {
|
// for image_frame_instance in image_frame_table.instance_iter() {
|
||||||
// result_table.push(Instance {
|
// result_table.push(Instance {
|
||||||
// instance: image_frame_instance.instance,
|
// instance: image_frame_instance.instance,
|
||||||
|
// mask: image_frame_instance.mask,
|
||||||
// transform: image_frame_instance.transform,
|
// transform: image_frame_instance.transform,
|
||||||
// alpha_blending: image_frame_instance.alpha_blending,
|
// alpha_blending: image_frame_instance.alpha_blending,
|
||||||
// source_node_id: image_frame_instance.source_node_id,
|
// source_node_id: image_frame_instance.source_node_id,
|
||||||
|
|||||||
@@ -448,6 +448,7 @@ async fn round_corners(
|
|||||||
for source in source.instance_ref_iter() {
|
for source in source.instance_ref_iter() {
|
||||||
let source_transform = *source.transform;
|
let source_transform = *source.transform;
|
||||||
let source_transform_inverse = source_transform.inverse();
|
let source_transform_inverse = source_transform.inverse();
|
||||||
|
let source_mask = source.mask;
|
||||||
let source = source.instance;
|
let source = source.instance;
|
||||||
|
|
||||||
let upstream_graphic_group = source.upstream_graphic_group.clone();
|
let upstream_graphic_group = source.upstream_graphic_group.clone();
|
||||||
@@ -540,6 +541,7 @@ async fn round_corners(
|
|||||||
|
|
||||||
result_table.push(Instance {
|
result_table.push(Instance {
|
||||||
instance: result,
|
instance: result,
|
||||||
|
mask: source_mask.clone(),
|
||||||
transform: source_transform,
|
transform: source_transform,
|
||||||
alpha_blending: Default::default(),
|
alpha_blending: Default::default(),
|
||||||
source_node_id: None,
|
source_node_id: None,
|
||||||
@@ -788,6 +790,7 @@ async fn auto_tangents(
|
|||||||
|
|
||||||
for source in source.instance_ref_iter() {
|
for source in source.instance_ref_iter() {
|
||||||
let transform = *source.transform;
|
let transform = *source.transform;
|
||||||
|
let mask = source.mask.clone();
|
||||||
let alpha_blending = *source.alpha_blending;
|
let alpha_blending = *source.alpha_blending;
|
||||||
let source_node_id = *source.source_node_id;
|
let source_node_id = *source.source_node_id;
|
||||||
let source = source.instance;
|
let source = source.instance;
|
||||||
@@ -886,6 +889,7 @@ async fn auto_tangents(
|
|||||||
|
|
||||||
result_table.push(Instance {
|
result_table.push(Instance {
|
||||||
instance: result,
|
instance: result,
|
||||||
|
mask,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
source_node_id,
|
source_node_id,
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use crate::instances::Instances;
|
||||||
use dyn_any::DynAny;
|
use dyn_any::DynAny;
|
||||||
use fastnoise_lite;
|
use fastnoise_lite;
|
||||||
use glam::{DAffine2, DVec2, Vec2};
|
use glam::{DAffine2, DVec2, Vec2};
|
||||||
@@ -6,7 +7,9 @@ use graphene_core::raster::bbox::Bbox;
|
|||||||
pub use graphene_core::raster::*;
|
pub use graphene_core::raster::*;
|
||||||
use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
|
use graphene_core::raster_types::{CPU, Raster, RasterDataTable};
|
||||||
use graphene_core::transform::Transform;
|
use graphene_core::transform::Transform;
|
||||||
|
use graphene_core::vector::VectorDataTable;
|
||||||
use graphene_core::{AlphaBlending, Ctx, ExtractFootprint};
|
use graphene_core::{AlphaBlending, Ctx, ExtractFootprint};
|
||||||
|
use graphene_core::{GraphicElement, GraphicGroupTable};
|
||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use rand_chacha::ChaCha8Rng;
|
use rand_chacha::ChaCha8Rng;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
@@ -171,6 +174,7 @@ fn combine_channels(
|
|||||||
// Add this instance to the result table
|
// Add this instance to the result table
|
||||||
result_table.push(Instance {
|
result_table.push(Instance {
|
||||||
instance: Raster::new_cpu(image),
|
instance: Raster::new_cpu(image),
|
||||||
|
mask: None,
|
||||||
transform,
|
transform,
|
||||||
alpha_blending,
|
alpha_blending,
|
||||||
source_node_id: None,
|
source_node_id: None,
|
||||||
@@ -181,14 +185,34 @@ fn combine_channels(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[node_macro::node(category("Raster"))]
|
#[node_macro::node(category("Raster"))]
|
||||||
fn mask(
|
fn mask<T, E>(
|
||||||
_: impl Ctx,
|
_: impl Ctx,
|
||||||
/// The image to be masked.
|
/// The image to be masked.
|
||||||
image: RasterDataTable<CPU>,
|
#[implementations(
|
||||||
|
VectorDataTable,
|
||||||
|
RasterDataTable<CPU>,
|
||||||
|
GraphicGroupTable
|
||||||
|
)]
|
||||||
|
mut image: Instances<T>,
|
||||||
/// The stencil to be used for masking.
|
/// The stencil to be used for masking.
|
||||||
#[expose]
|
#[expose]
|
||||||
stencil: RasterDataTable<CPU>,
|
#[implementations(
|
||||||
) -> RasterDataTable<CPU> {
|
VectorDataTable,
|
||||||
|
RasterDataTable<CPU>,
|
||||||
|
GraphicGroupTable
|
||||||
|
)]
|
||||||
|
stencil: Instances<E>,
|
||||||
|
) -> Instances<T>
|
||||||
|
where
|
||||||
|
Instances<E>: Into<GraphicElement> + Clone,
|
||||||
|
{
|
||||||
|
for instance in image.instance_mut_iter() {
|
||||||
|
*instance.mask = Some(stencil.clone().into());
|
||||||
|
}
|
||||||
|
image
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mask_lambda(image: RasterDataTable<CPU>, stencil: RasterDataTable<CPU>) -> RasterDataTable<CPU> {
|
||||||
// TODO: Support multiple stencil instances
|
// TODO: Support multiple stencil instances
|
||||||
let Some(stencil_instance) = stencil.instance_iter().next() else {
|
let Some(stencil_instance) = stencil.instance_iter().next() else {
|
||||||
// No stencil provided so we return the original image
|
// No stencil provided so we return the original image
|
||||||
|
|||||||
@@ -178,6 +178,7 @@ fn difference<'a>(vector_data: impl DoubleEndedIterator<Item = InstanceRef<'a, V
|
|||||||
instance.style = first_instance.instance.style.clone();
|
instance.style = first_instance.instance.style.clone();
|
||||||
let boolean_intersection_result = Instance {
|
let boolean_intersection_result = Instance {
|
||||||
instance,
|
instance,
|
||||||
|
mask: None,
|
||||||
transform: *first_instance.transform,
|
transform: *first_instance.transform,
|
||||||
alpha_blending: *first_instance.alpha_blending,
|
alpha_blending: *first_instance.alpha_blending,
|
||||||
source_node_id: *first_instance.source_node_id,
|
source_node_id: *first_instance.source_node_id,
|
||||||
|
|||||||
Reference in New Issue
Block a user