diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 004f5a9fb..1e1445120 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -2414,7 +2414,7 @@ impl DocumentMessageHandler { /// Create a network interface with a single export fn default_document_network_interface() -> NodeNetworkInterface { let mut network_interface = NodeNetworkInterface::default(); - network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroup::default()), -1, "", &[]); + network_interface.add_export(TaggedValue::ArtboardGroup(graphene_core::ArtboardGroupTable::default()), -1, "", &[]); network_interface } diff --git a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs index 9a45e0d08..a86c650df 100644 --- a/editor/src/messages/portfolio/document/graph_operation/utility_types.rs +++ b/editor/src/messages/portfolio/document/graph_operation/utility_types.rs @@ -126,7 +126,7 @@ impl<'a> ModifyInputsContext<'a> { /// Creates an artboard as the primary export for the document network pub fn create_artboard(&mut self, new_id: NodeId, artboard: Artboard) -> LayerNodeIdentifier { let artboard_node_template = resolve_document_node_type("Artboard").expect("Node").node_template_input_override([ - Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroup::default()), true)), + Some(NodeInput::value(TaggedValue::ArtboardGroup(graphene_std::ArtboardGroupTable::default()), true)), Some(NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroupTable::default()), true)), Some(NodeInput::value(TaggedValue::IVec2(artboard.location), false)), Some(NodeInput::value(TaggedValue::IVec2(artboard.dimensions), false)), diff --git a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs index 2894e446b..beaf5e59b 100644 --- a/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs +++ b/editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs @@ -295,7 +295,7 @@ fn static_nodes() -> Vec { DocumentNode { manual_composition: Some(concrete!(Context)), inputs: vec![ - NodeInput::network(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(ArtboardGroup))), 0), + NodeInput::network(graphene_core::Type::Fn(Box::new(concrete!(Context)), Box::new(concrete!(ArtboardGroupTable))), 0), NodeInput::node(NodeId(1), 0), NodeInput::Reflection(graph_craft::document::DocumentNodeMetadata::DocumentNodePath), ], @@ -310,7 +310,7 @@ fn static_nodes() -> Vec { ..Default::default() }), inputs: vec![ - NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroup::default()), true), + NodeInput::value(TaggedValue::ArtboardGroup(ArtboardGroupTable::default()), true), NodeInput::value(TaggedValue::GraphicGroup(GraphicGroupTable::default()), true), NodeInput::value(TaggedValue::IVec2(glam::IVec2::ZERO), false), NodeInput::value(TaggedValue::IVec2(glam::IVec2::new(1920, 1080)), false), @@ -544,7 +544,7 @@ fn static_nodes() -> Vec { nodes: [ DocumentNode { inputs: vec![NodeInput::network(concrete!(ImageFrameTable), 0)], - implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrame>")), // TODO: Possibly change `ImageFrame` to something else + implementation: DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier::new("graphene_core::ops::IntoNode<_, ImageFrameTable>")), ..Default::default() }, DocumentNode { @@ -571,7 +571,7 @@ fn static_nodes() -> Vec { .collect(), ..Default::default() }), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)], + inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)], ..Default::default() }, persistent_node_metadata: DocumentNodePersistentMetadata { @@ -809,8 +809,8 @@ fn static_nodes() -> Vec { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_std::raster::MaskImageNode"), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), ], ..Default::default() }, @@ -832,8 +832,8 @@ fn static_nodes() -> Vec { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_std::raster::InsertChannelNode"), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), NodeInput::value(TaggedValue::RedGreenBlue(RedGreenBlue::default()), false), ], ..Default::default() @@ -856,10 +856,10 @@ fn static_nodes() -> Vec { implementation: DocumentNodeImplementation::proto("graphene_std::raster::CombineChannelsNode"), inputs: vec![ NodeInput::value(TaggedValue::None, false), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), ], ..Default::default() }, @@ -929,7 +929,7 @@ fn static_nodes() -> Vec { ..Default::default() }), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)], + inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)], ..Default::default() }, persistent_node_metadata: DocumentNodePersistentMetadata { @@ -1011,8 +1011,8 @@ fn static_nodes() -> Vec { ..Default::default() }), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), NodeInput::value(TaggedValue::BrushStrokes(Vec::new()), false), NodeInput::value(TaggedValue::BrushCache(BrushCache::new_proto()), false), ], @@ -1061,7 +1061,7 @@ fn static_nodes() -> Vec { node_template: NodeTemplate { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_core::memo::MemoNode"), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)], + inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)], manual_composition: Some(concrete!(Context)), ..Default::default() }, @@ -1080,7 +1080,7 @@ fn static_nodes() -> Vec { node_template: NodeTemplate { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_core::memo::ImpureMemoNode"), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)], + inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)], manual_composition: Some(concrete!(Context)), ..Default::default() }, @@ -1112,7 +1112,10 @@ fn static_nodes() -> Vec { .collect(), ..Default::default() }), - inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), false)], + inputs: vec![ + NodeInput::value(TaggedValue::None, false), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), false), + ], ..Default::default() }, persistent_node_metadata: DocumentNodePersistentMetadata { @@ -1825,7 +1828,7 @@ fn static_nodes() -> Vec { .collect(), ..Default::default() }), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true)], + inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true)], ..Default::default() }, persistent_node_metadata: DocumentNodePersistentMetadata { @@ -1881,7 +1884,7 @@ fn static_nodes() -> Vec { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_std::executor::MapGpuSingleImageNode"), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), NodeInput::value(TaggedValue::DocumentNode(DocumentNode::default()), true), ], ..Default::default() @@ -1923,7 +1926,7 @@ fn static_nodes() -> Vec { document_node: DocumentNode { implementation: DocumentNodeImplementation::proto("graphene_core::raster::BrightnessContrastNode"), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::F64(0.), false), NodeInput::value(TaggedValue::Bool(false), false), @@ -2799,7 +2802,7 @@ pub static IMAGINATE_NODE: Lazy = Lazy::new(|| DocumentN ..Default::default() }), inputs: vec![ - NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::empty()), true), + NodeInput::value(TaggedValue::ImageFrame(ImageFrameTable::one_empty_image()), true), NodeInput::scope("editor-api"), NodeInput::value(TaggedValue::ImaginateController(Default::default()), false), NodeInput::value(TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index diff --git a/editor/src/messages/portfolio/document/utility_types/network_interface.rs b/editor/src/messages/portfolio/document/utility_types/network_interface.rs index 3f74f9e48..fcdde4f10 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -468,8 +468,8 @@ impl NodeNetworkInterface { InputConnector::Node { node_id, input_index } => (node_id, input_index), InputConnector::Export(export_index) => { let Some((encapsulating_node_id, encapsulating_node_id_path)) = network_path.split_last() else { - // The outermost network export defaults to an ArtboardGroup. - return Some((concrete!(graphene_core::ArtboardGroup), TypeSource::OuterMostExportDefault)); + // The outermost network export defaults to an ArtboardGroupTable. + return Some((concrete!(graphene_core::ArtboardGroupTable), TypeSource::OuterMostExportDefault)); }; let output_type = self.output_types(encapsulating_node_id, encapsulating_node_id_path).into_iter().nth(export_index).flatten(); diff --git a/node-graph/gcore/src/application_io.rs b/node-graph/gcore/src/application_io.rs index f2cd89842..a8c889ca0 100644 --- a/node-graph/gcore/src/application_io.rs +++ b/node-graph/gcore/src/application_io.rs @@ -49,6 +49,7 @@ impl TransformMut for SurfaceFrame { } } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for SurfaceFrame { type Static = SurfaceFrame; } @@ -90,6 +91,7 @@ impl PartialEq for ImageTexture { } } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for ImageTexture { type Static = ImageTexture; } @@ -128,6 +130,7 @@ impl Size for SurfaceHandle { } } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for SurfaceHandle { type Static = SurfaceHandle; } @@ -138,6 +141,7 @@ pub struct SurfaceHandleFrame { pub transform: DAffine2, } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for SurfaceHandleFrame { type Static = SurfaceHandleFrame; } @@ -317,6 +321,7 @@ impl Debug for EditorApi { } } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for EditorApi { type Static = EditorApi; } diff --git a/node-graph/gcore/src/graphic_element.rs b/node-graph/gcore/src/graphic_element.rs index d10fa2000..3ccad36c9 100644 --- a/node-graph/gcore/src/graphic_element.rs +++ b/node-graph/gcore/src/graphic_element.rs @@ -238,6 +238,12 @@ pub struct Artboard { pub clip: bool, } +impl Default for Artboard { + fn default() -> Self { + Self::new(IVec2::ZERO, IVec2::new(1920, 1080)) + } +} + impl Artboard { pub fn new(location: IVec2, dimensions: IVec2) -> Self { Self { @@ -251,23 +257,38 @@ impl Artboard { } } -/// Contains multiple artboards. -#[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)] -#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] -pub struct ArtboardGroup { - pub artboards: Vec<(Artboard, Option)>, -} +// TODO: Eventually remove this migration document upgrade code +pub fn migrate_artboard_group<'de, D: serde::Deserializer<'de>>(deserializer: D) -> Result { + use serde::Deserialize; -impl ArtboardGroup { - pub fn new() -> Self { - Default::default() + #[derive(Clone, Default, Debug, Hash, PartialEq, DynAny)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub struct ArtboardGroup { + pub artboards: Vec<(Artboard, Option)>, } - fn append_artboard(&mut self, artboard: Artboard, node_id: Option) { - self.artboards.push((artboard, node_id)); + #[derive(serde::Serialize, serde::Deserialize)] + #[serde(untagged)] + enum EitherFormat { + ArtboardGroup(ArtboardGroup), + ArtboardGroupTable(ArtboardGroupTable), } + + Ok(match EitherFormat::deserialize(deserializer)? { + EitherFormat::ArtboardGroup(artboard_group) => { + let mut table = ArtboardGroupTable::empty(); + for (artboard, source_node_id) in artboard_group.artboards { + table.push(artboard); + *table.instances_mut().last().unwrap().source_node_id = source_node_id; + } + table + } + EitherFormat::ArtboardGroupTable(artboard_group_table) => artboard_group_table, + }) } +pub type ArtboardGroupTable = Instances; + #[node_macro::node(category(""))] async fn layer(_: impl Ctx, stack: GraphicGroupTable, mut element: GraphicElement, node_path: Vec) -> GraphicGroupTable { let mut stack = stack; @@ -385,15 +406,13 @@ async fn to_artboard + 'n>( } #[node_macro::node(category(""))] -async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroup, artboard: Artboard, node_path: Vec) -> ArtboardGroup { - // let mut artboards = artboards.eval(ctx.clone()).await; - // let artboard = artboard.eval(ctx).await; - // let foot = ctx.footprint(); - // log::debug!("{:?}", foot); +async fn append_artboard(_ctx: impl Ctx, mut artboards: ArtboardGroupTable, artboard: Artboard, node_path: Vec) -> ArtboardGroupTable { // Get the penultimate element of the node path, or None if the path is too short. // This is used to get the ID of the user-facing "Artboard" node (which encapsulates this internal "Append Artboard" node). let encapsulating_node_id = node_path.get(node_path.len().wrapping_sub(2)).copied(); - artboards.append_artboard(artboard, encapsulating_node_id); + + artboards.push(artboard); + *artboards.instances_mut().last().unwrap().source_node_id = encapsulating_node_id; artboards } diff --git a/node-graph/gcore/src/graphic_element/renderer.rs b/node-graph/gcore/src/graphic_element/renderer.rs index 0b73ded93..a0f087b3e 100644 --- a/node-graph/gcore/src/graphic_element/renderer.rs +++ b/node-graph/gcore/src/graphic_element/renderer.rs @@ -9,7 +9,7 @@ use crate::transform::{Footprint, Transform}; use crate::uuid::{generate_uuid, NodeId}; use crate::vector::style::{Fill, Stroke, ViewMode}; use crate::vector::{PointId, VectorDataTable}; -use crate::{Artboard, ArtboardGroup, Color, GraphicElement, GraphicGroupTable, RasterFrame}; +use crate::{Artboard, ArtboardGroupTable, Color, GraphicElement, GraphicGroupTable, RasterFrame}; use bezier_rs::Subpath; use dyn_any::DynAny; @@ -790,38 +790,38 @@ impl GraphicElementRendered for Artboard { } } -impl GraphicElementRendered for ArtboardGroup { +impl GraphicElementRendered for ArtboardGroupTable { fn render_svg(&self, render: &mut SvgRender, render_params: &RenderParams) { - for (artboard, _) in &self.artboards { - artboard.render_svg(render, render_params); + for artboard in self.instances() { + artboard.instance.render_svg(render, render_params); } } fn bounding_box(&self, transform: DAffine2) -> Option<[DVec2; 2]> { - self.artboards.iter().filter_map(|(element, _)| element.bounding_box(transform)).reduce(Quad::combine_bounds) + self.instances().filter_map(|instance| instance.instance.bounding_box(transform)).reduce(Quad::combine_bounds) } fn collect_metadata(&self, metadata: &mut RenderMetadata, footprint: Footprint, _element_id: Option) { - for (artboard, element_id) in &self.artboards { - artboard.collect_metadata(metadata, footprint, *element_id); + for instance in self.instances() { + instance.instance.collect_metadata(metadata, footprint, *instance.source_node_id); } } fn add_upstream_click_targets(&self, click_targets: &mut Vec) { - for (artboard, _) in &self.artboards { - artboard.add_upstream_click_targets(click_targets); + for instance in self.instances() { + instance.instance.add_upstream_click_targets(click_targets); } } #[cfg(feature = "vello")] fn render_to_vello(&self, scene: &mut Scene, transform: DAffine2, context: &mut RenderContext) { - for (artboard, _) in &self.artboards { - artboard.render_to_vello(scene, transform, context) + for instance in self.instances() { + instance.instance.render_to_vello(scene, transform, context) } } fn contains_artboard(&self) -> bool { - !self.artboards.is_empty() + self.instances().count() > 0 } } diff --git a/node-graph/gcore/src/instances.rs b/node-graph/gcore/src/instances.rs index b86fb8b46..6bd232cc4 100644 --- a/node-graph/gcore/src/instances.rs +++ b/node-graph/gcore/src/instances.rs @@ -2,18 +2,17 @@ use crate::application_io::{ImageTexture, TextureFrameTable}; use crate::raster::image::{Image, ImageFrameTable}; use crate::raster::Pixel; use crate::transform::{Transform, TransformMut}; +use crate::uuid::NodeId; use crate::vector::{InstanceId, VectorData, VectorDataTable}; use crate::{AlphaBlending, GraphicElement, GraphicGroup, GraphicGroupTable, RasterFrame}; use dyn_any::StaticType; + use glam::{DAffine2, DVec2}; use std::hash::Hash; #[derive(Clone, Debug, serde::Serialize, serde::Deserialize)] -pub struct Instances -where - T: Into + StaticType + 'static, -{ +pub struct Instances { id: Vec, #[serde(alias = "instances")] instance: Vec, @@ -21,15 +20,44 @@ where transform: Vec, #[serde(default = "one_alpha_blending_default")] alpha_blending: Vec, + #[serde(default = "one_source_node_id_default")] + source_node_id: Vec>, } -impl + StaticType + 'static> Instances { +impl Instances { pub fn new(instance: T) -> Self { Self { id: vec![InstanceId::generate()], instance: vec![instance], transform: vec![DAffine2::IDENTITY], alpha_blending: vec![AlphaBlending::default()], + source_node_id: vec![None], + } + } + + pub fn empty() -> Self { + Self { + id: Vec::new(), + instance: Vec::new(), + transform: Vec::new(), + alpha_blending: Vec::new(), + source_node_id: Vec::new(), + } + } + + pub fn push(&mut self, instance: T) -> InstanceMut { + self.id.push(InstanceId::generate()); + self.instance.push(instance); + self.transform.push(DAffine2::IDENTITY); + self.alpha_blending.push(AlphaBlending::default()); + self.source_node_id.push(None); + + InstanceMut { + id: self.id.last_mut().expect("Shouldn't be empty"), + instance: self.instance.last_mut().expect("Shouldn't be empty"), + transform: self.transform.last_mut().expect("Shouldn't be empty"), + alpha_blending: self.alpha_blending.last_mut().expect("Shouldn't be empty"), + source_node_id: self.source_node_id.last_mut().expect("Shouldn't be empty"), } } @@ -39,6 +67,7 @@ impl + StaticType + 'static> Instances { instance: self.instance.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())), transform: self.transform.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())), alpha_blending: self.alpha_blending.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())), + source_node_id: self.source_node_id.first().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", self.instance.len())), } } @@ -50,47 +79,52 @@ impl + StaticType + 'static> Instances { instance: self.instance.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)), transform: self.transform.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)), alpha_blending: self.alpha_blending.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)), + source_node_id: self.source_node_id.first_mut().unwrap_or_else(|| panic!("ONE INSTANCE EXPECTED, FOUND {}", length)), } } pub fn instances(&self) -> impl Iterator> { - assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances)", self.instance.len()); + // assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances)", self.instance.len()); self.id .iter() .zip(self.instance.iter()) .zip(self.transform.iter()) .zip(self.alpha_blending.iter()) - .map(|(((id, instance), transform), alpha_blending)| Instance { + .zip(self.source_node_id.iter()) + .map(|((((id, instance), transform), alpha_blending), source_node_id)| Instance { id, instance, transform, alpha_blending, + source_node_id, }) } pub fn instances_mut(&mut self) -> impl Iterator> { - assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances_mut)", self.instance.len()); + // assert!(self.instance.len() == 1, "ONE INSTANCE EXPECTED, FOUND {} (instances_mut)", self.instance.len()); self.id .iter_mut() .zip(self.instance.iter_mut()) .zip(self.transform.iter_mut()) .zip(self.alpha_blending.iter_mut()) - .map(|(((id, instance), transform), alpha_blending)| InstanceMut { + .zip(self.source_node_id.iter_mut()) + .map(|((((id, instance), transform), alpha_blending), source_node_id)| InstanceMut { id, instance, transform, alpha_blending, + source_node_id, }) } } -impl + Default + Hash + StaticType + 'static> Default for Instances { +impl Default for Instances { fn default() -> Self { Self::new(T::default()) } } -impl + Hash + StaticType + 'static> core::hash::Hash for Instances { +impl core::hash::Hash for Instances { fn hash(&self, state: &mut H) { self.id.hash(state); for instance in &self.instance { @@ -99,13 +133,14 @@ impl + Hash + StaticType + 'static> core::hash::Hash for } } -impl + PartialEq + StaticType + 'static> PartialEq for Instances { +impl PartialEq for Instances { fn eq(&self, other: &Self) -> bool { self.id == other.id && self.instance.len() == other.instance.len() && { self.instance.iter().zip(other.instance.iter()).all(|(a, b)| a == b) } } } -unsafe impl + StaticType + 'static> dyn_any::StaticType for Instances { +#[cfg(feature = "dyn-any")] +unsafe impl StaticType for Instances { type Static = Instances; } @@ -115,6 +150,9 @@ fn one_daffine2_default() -> Vec { fn one_alpha_blending_default() -> Vec { vec![AlphaBlending::default()] } +fn one_source_node_id_default() -> Vec> { + vec![None] +} #[derive(Copy, Clone, Debug)] pub struct Instance<'a, T> { @@ -122,6 +160,7 @@ pub struct Instance<'a, T> { pub instance: &'a T, pub transform: &'a DAffine2, pub alpha_blending: &'a AlphaBlending, + pub source_node_id: &'a Option, } #[derive(Debug)] pub struct InstanceMut<'a, T> { @@ -129,6 +168,7 @@ pub struct InstanceMut<'a, T> { pub instance: &'a mut T, pub transform: &'a mut DAffine2, pub alpha_blending: &'a mut AlphaBlending, + pub source_node_id: &'a mut Option, } // GRAPHIC ELEMENT @@ -235,8 +275,6 @@ impl TransformMut for InstanceMut<'_, Image

> { // IMAGE FRAME TABLE impl Transform for ImageFrameTable

where - P: dyn_any::StaticType, - P::Static: Pixel, GraphicElement: From>, { fn transform(&self) -> DAffine2 { @@ -245,8 +283,6 @@ where } impl TransformMut for ImageFrameTable

where - P: dyn_any::StaticType, - P::Static: Pixel, GraphicElement: From>, { fn transform_mut(&mut self) -> &mut DAffine2 { diff --git a/node-graph/gcore/src/lib.rs b/node-graph/gcore/src/lib.rs index e419bc4cf..883513f8b 100644 --- a/node-graph/gcore/src/lib.rs +++ b/node-graph/gcore/src/lib.rs @@ -51,6 +51,8 @@ pub mod registry; pub use context::*; use core::any::TypeId; +use core::pin::Pin; +pub use dyn_any::{StaticTypeSized, WasmNotSend, WasmNotSync}; pub use memo::MemoHash; pub use raster::Color; pub use types::Cow; @@ -148,10 +150,6 @@ impl<'i, I: 'i, O: 'i, N: Node<'i, I, Output = O> + ?Sized> Node<'i, I> for allo } } -use dyn_any::StaticTypeSized; - -use core::pin::Pin; - #[cfg(feature = "alloc")] impl<'i, I, O: 'i> Node<'i, I> for Pin + 'i>> { type Output = O; @@ -172,5 +170,3 @@ pub use crate::application_io::{SurfaceFrame, SurfaceId}; pub type WasmSurfaceHandle = application_io::SurfaceHandle; #[cfg(feature = "wasm")] pub type WasmSurfaceHandleFrame = application_io::SurfaceHandleFrame; - -pub use dyn_any::{WasmNotSend, WasmNotSync}; diff --git a/node-graph/gcore/src/raster/adjustments.rs b/node-graph/gcore/src/raster/adjustments.rs index d19a559e8..5021f8ae1 100644 --- a/node-graph/gcore/src/raster/adjustments.rs +++ b/node-graph/gcore/src/raster/adjustments.rs @@ -734,8 +734,6 @@ impl Adjust for GradientStops { } impl Adjust

for ImageFrameTable

where - P: dyn_any::StaticType, - P::Static: Pixel, GraphicElement: From>, { fn adjust(&mut self, map_fn: impl Fn(&P) -> P) { @@ -1382,8 +1380,6 @@ impl MultiplyAlpha for GraphicGroupTable { } impl MultiplyAlpha for ImageFrameTable

where - P: dyn_any::StaticType, - P::Static: Pixel, GraphicElement: From>, { fn multiply_alpha(&mut self, factor: f64) { diff --git a/node-graph/gcore/src/raster/bbox.rs b/node-graph/gcore/src/raster/bbox.rs index 9a0d90976..96c832314 100644 --- a/node-graph/gcore/src/raster/bbox.rs +++ b/node-graph/gcore/src/raster/bbox.rs @@ -1,4 +1,5 @@ use dyn_any::DynAny; + use glam::{DAffine2, DVec2}; #[cfg_attr(not(target_arch = "spirv"), derive(Debug))] diff --git a/node-graph/gcore/src/raster/brush_cache.rs b/node-graph/gcore/src/raster/brush_cache.rs index c00b8a39a..9db6f8ab4 100644 --- a/node-graph/gcore/src/raster/brush_cache.rs +++ b/node-graph/gcore/src/raster/brush_cache.rs @@ -4,8 +4,9 @@ use crate::vector::brush_stroke::BrushStroke; use crate::vector::brush_stroke::BrushStyle; use crate::Color; -use core::hash::Hash; use dyn_any::DynAny; + +use core::hash::Hash; use std::collections::HashMap; use std::sync::Arc; use std::sync::Mutex; @@ -57,7 +58,7 @@ impl BrushCacheImpl { background = core::mem::take(&mut self.blended_image); // Check if the first non-blended stroke is an extension of the last one. - let mut first_stroke_texture = ImageFrameTable::empty(); + let mut first_stroke_texture = ImageFrameTable::one_empty_image(); let mut first_stroke_point_skip = 0; let strokes = input[num_blended_strokes..].to_vec(); if !strokes.is_empty() && self.prev_input.len() > num_blended_strokes { diff --git a/node-graph/gcore/src/raster/curve.rs b/node-graph/gcore/src/raster/curve.rs index 208119def..e6b8076da 100644 --- a/node-graph/gcore/src/raster/curve.rs +++ b/node-graph/gcore/src/raster/curve.rs @@ -176,6 +176,7 @@ pub struct ValueMapperNode { lut: Vec, } +#[cfg(feature = "dyn-any")] unsafe impl StaticType for ValueMapperNode { type Static = ValueMapperNode; } diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index 4a08f305b..1f12f3691 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -1,7 +1,9 @@ use super::discrete_srgb::float_to_srgb_u8; use super::Color; -use crate::{instances::Instances, transform::TransformMut}; -use crate::{AlphaBlending, GraphicElement}; +use crate::instances::Instances; +use crate::transform::TransformMut; +use crate::AlphaBlending; +use crate::GraphicElement; use alloc::vec::Vec; use core::hash::{Hash, Hasher}; use dyn_any::StaticType; @@ -68,6 +70,7 @@ impl Debug for Image

{ } } +#[cfg(feature = "dyn-any")] unsafe impl

StaticType for Image

where P: dyn_any::StaticTypeSized + Pixel, @@ -235,6 +238,8 @@ pub fn migrate_image_frame<'de, D: serde::Deserializer<'de>>(deserializer: D) -> } } } + + #[cfg(feature = "dyn-any")] unsafe impl

StaticType for ImageFrame

where P: dyn_any::StaticTypeSized + Pixel, @@ -279,7 +284,7 @@ pub type ImageFrameTable

= Instances>; /// Construct a 0x0 image frame table. This is useful because ImageFrameTable::default() will return a 1x1 image frame table. impl ImageFrameTable { - pub fn empty() -> Self { + pub fn one_empty_image() -> Self { let mut result = Self::new(Image::default()); *result.transform_mut() = DAffine2::ZERO; result @@ -302,8 +307,7 @@ impl Sample for Image

{ impl

Sample for ImageFrameTable

where - P: Debug + Copy + Pixel + dyn_any::StaticType, - P::Static: Pixel, + P: Debug + Copy + Pixel, GraphicElement: From>, { type Pixel = P; @@ -323,8 +327,7 @@ where impl

Bitmap for ImageFrameTable

where - P: Copy + Pixel + dyn_any::StaticType, - P::Static: Pixel, + P: Copy + Pixel, GraphicElement: From>, { type Pixel = P; @@ -350,8 +353,7 @@ where impl

BitmapMut for ImageFrameTable

where - P: Copy + Pixel + dyn_any::StaticType, - P::Static: Pixel, + P: Copy + Pixel, GraphicElement: From>, { fn get_pixel_mut(&mut self, x: u32, y: u32) -> Option<&mut Self::Pixel> { diff --git a/node-graph/gcore/src/registry.rs b/node-graph/gcore/src/registry.rs index 483d33323..c28715ec7 100644 --- a/node-graph/gcore/src/registry.rs +++ b/node-graph/gcore/src/registry.rs @@ -1,9 +1,10 @@ use crate::transform::Footprint; -use crate::{NodeIO, NodeIOTypes, Type}; +use crate::{Node, NodeIO, NodeIOTypes, Type, WasmNotSend}; -use dyn_any::DynAny; +use dyn_any::{DynAny, StaticType}; use std::collections::HashMap; +use std::marker::PhantomData; use std::ops::Deref; use std::pin::Pin; use std::sync::{LazyLock, Mutex}; @@ -153,11 +154,6 @@ impl NodeContainer { } } -use crate::Node; -use crate::WasmNotSend; -use dyn_any::StaticType; -use std::marker::PhantomData; - /// Boxes the input and downcasts the output. /// Wraps around a node taking Box and returning Box #[derive(Clone)] @@ -166,7 +162,11 @@ pub struct DowncastBothNode { _i: PhantomData, _o: PhantomData, } -impl<'input, O: 'input + StaticType + WasmNotSend, I: 'input + StaticType + WasmNotSend> Node<'input, I> for DowncastBothNode { +impl<'input, O, I> Node<'input, I> for DowncastBothNode +where + O: 'input + StaticType + WasmNotSend, + I: 'input + StaticType + WasmNotSend, +{ type Output = DynFuture<'input, O>; #[inline] fn eval(&'input self, input: I) -> Self::Output { @@ -234,9 +234,11 @@ pub struct DynAnyNode { _o: PhantomData, } -impl<'input, _I: 'input + StaticType + WasmNotSend, _O: 'input + StaticType + WasmNotSend, N: 'input> Node<'input, Any<'input>> for DynAnyNode<_I, _O, N> +impl<'input, _I, _O, N> Node<'input, Any<'input>> for DynAnyNode<_I, _O, N> where - N: Node<'input, _I, Output = DynFuture<'input, _O>>, + _I: 'input + dyn_any::StaticType + WasmNotSend, + _O: 'input + dyn_any::StaticType + WasmNotSend, + N: 'input + Node<'input, _I, Output = DynFuture<'input, _O>>, { type Output = FutureAny<'input>; #[inline] @@ -275,9 +277,11 @@ where self.node.serialize() } } -impl<'input, _I: 'input + StaticType, _O: 'input + StaticType, N: 'input> DynAnyNode<_I, _O, N> +impl<'input, _I, _O, N> DynAnyNode<_I, _O, N> where - N: Node<'input, _I, Output = DynFuture<'input, _O>>, + _I: 'input + dyn_any::StaticType, + _O: 'input + dyn_any::StaticType, + N: 'input + Node<'input, _I, Output = DynFuture<'input, _O>>, { pub const fn new(node: N) -> Self { Self { diff --git a/node-graph/gcore/src/transform.rs b/node-graph/gcore/src/transform.rs index dbab82213..94a988532 100644 --- a/node-graph/gcore/src/transform.rs +++ b/node-graph/gcore/src/transform.rs @@ -2,7 +2,7 @@ use crate::application_io::TextureFrameTable; use crate::raster::bbox::AxisAlignedBbox; use crate::raster::image::ImageFrameTable; use crate::vector::VectorDataTable; -use crate::{Artboard, ArtboardGroup, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl}; +use crate::{Artboard, ArtboardGroupTable, CloneVarArgs, Color, Context, Ctx, ExtractAll, GraphicGroupTable, OwnedContextImpl}; use glam::{DAffine2, DVec2}; @@ -132,7 +132,7 @@ impl From<()> for Footprint { } #[node_macro::node(category("Debug"))] -fn cull(_: impl Ctx, #[implementations(VectorDataTable, GraphicGroupTable, Artboard, ImageFrameTable, ArtboardGroup)] data: T) -> T { +fn cull(_: impl Ctx, #[implementations(VectorDataTable, GraphicGroupTable, Artboard, ImageFrameTable, ArtboardGroupTable)] data: T) -> T { data } diff --git a/node-graph/gcore/src/types.rs b/node-graph/gcore/src/types.rs index a71dcd44d..221ea6cd2 100644 --- a/node-graph/gcore/src/types.rs +++ b/node-graph/gcore/src/types.rs @@ -2,7 +2,6 @@ use core::any::TypeId; #[cfg(not(feature = "std"))] pub use alloc::borrow::Cow; -use dyn_any::StaticType; #[cfg(feature = "std")] pub use std::borrow::Cow; @@ -220,7 +219,8 @@ impl Default for Type { } } -unsafe impl StaticType for Type { +#[cfg(feature = "dyn-any")] +unsafe impl dyn_any::StaticType for Type { type Static = Self; } @@ -269,7 +269,7 @@ impl Type { } impl Type { - pub fn new() -> Self { + pub fn new() -> Self { Self::Concrete(TypeDescriptor { id: Some(TypeId::of::()), name: Cow::Borrowed(core::any::type_name::()), @@ -278,6 +278,7 @@ impl Type { align: core::mem::align_of::(), }) } + pub fn size(&self) -> Option { match self { Self::Generic(_) => None, diff --git a/node-graph/gcore/src/uuid.rs b/node-graph/gcore/src/uuid.rs index 789dbc03e..93ca73f0a 100644 --- a/node-graph/gcore/src/uuid.rs +++ b/node-graph/gcore/src/uuid.rs @@ -1,6 +1,7 @@ -use dyn_any::DynAny; pub use uuid_generation::*; +use dyn_any::DynAny; + #[derive(Clone, Copy, serde::Serialize, serde::Deserialize, specta::Type)] pub struct Uuid( #[serde(with = "u64_string")] diff --git a/node-graph/gcore/src/vector/brush_stroke.rs b/node-graph/gcore/src/vector/brush_stroke.rs index d840da421..afe01530a 100644 --- a/node-graph/gcore/src/vector/brush_stroke.rs +++ b/node-graph/gcore/src/vector/brush_stroke.rs @@ -3,6 +3,7 @@ use crate::raster::BlendMode; use crate::Color; use dyn_any::DynAny; + use glam::DVec2; use std::hash::{Hash, Hasher}; diff --git a/node-graph/gcore/src/vector/style.rs b/node-graph/gcore/src/vector/style.rs index cc8b14f31..4b3396fb5 100644 --- a/node-graph/gcore/src/vector/style.rs +++ b/node-graph/gcore/src/vector/style.rs @@ -5,6 +5,7 @@ use crate::renderer::format_transform_matrix; use crate::Color; use dyn_any::DynAny; + use glam::{DAffine2, DVec2}; use std::fmt::{self, Display, Write}; diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 4c1a42b0f..b3f6c963b 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -670,6 +670,7 @@ async fn subpath_segment_lengths(_: impl Ctx, vector_data: VectorDataTable) -> V #[node_macro::node(name("Spline"), category("Vector"), path(graphene_core::vector))] async fn spline(_: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTable { + let original_transform = vector_data.transform(); let vector_data = vector_data.one_instance_mut().instance; // Exit early if there are no points to generate splines from. @@ -707,7 +708,9 @@ async fn spline(_: impl Ctx, mut vector_data: VectorDataTable) -> VectorDataTabl } vector_data.segment_domain = segment_domain; - VectorDataTable::new(vector_data.clone()) + let mut result = VectorDataTable::new(vector_data.clone()); + *result.transform_mut() = original_transform; + result } #[node_macro::node(category("Vector"), path(graphene_core::vector))] diff --git a/node-graph/gpu-executor/src/lib.rs b/node-graph/gpu-executor/src/lib.rs index 216c470c1..f87a7ece9 100644 --- a/node-graph/gpu-executor/src/lib.rs +++ b/node-graph/gpu-executor/src/lib.rs @@ -1,8 +1,8 @@ -use dyn_any::{StaticType, StaticTypeSized}; use graphene_core::raster::{color::RGBA16F, Image, Pixel, SRGBA8}; use graphene_core::*; use bytemuck::{Pod, Zeroable}; +use dyn_any::{StaticType, StaticTypeSized}; use glam::UVec3; use std::borrow::Cow; diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index 0981477d2..60b43f3a2 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -115,6 +115,19 @@ macro_rules! tagged_value { } tagged_value! { + // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame"))] + ImageFrame(graphene_core::raster::image::ImageFrameTable), + // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::vector::migrate_vector_data"))] + VectorData(graphene_core::vector::VectorDataTable), + // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_graphic_group"))] + GraphicGroup(graphene_core::GraphicGroupTable), + // TODO: Eventually remove this migration document upgrade code + #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_artboard_group"))] + ArtboardGroup(graphene_core::ArtboardGroupTable), + GraphicElement(graphene_core::GraphicElement), String(String), U32(u32), U64(u64), @@ -130,19 +143,14 @@ tagged_value! { DAffine2(DAffine2), Image(graphene_core::raster::Image), ImaginateCache(ImaginateCache), - // TODO: Eventually remove this migration document upgrade code - #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::raster::image::migrate_image_frame"))] - ImageFrame(graphene_core::raster::image::ImageFrameTable), Color(graphene_core::raster::color::Color), + OptionalColor(Option), Subpaths(Vec>), BlendMode(BlendMode), LuminanceCalculation(LuminanceCalculation), ImaginateSamplingMethod(ImaginateSamplingMethod), ImaginateMaskStartingFill(ImaginateMaskStartingFill), ImaginateController(ImaginateController), - // TODO: Eventually remove this migration document upgrade code - #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::vector::migrate_vector_data"))] - VectorData(graphene_core::vector::VectorDataTable), Fill(graphene_core::vector::style::Fill), Stroke(graphene_core::vector::style::Stroke), F64Array4([f64; 4]), @@ -170,7 +178,6 @@ tagged_value! { // TODO: Eventually remove this alias document upgrade code #[cfg_attr(feature = "serde", serde(alias = "GradientPositions"))] GradientStops(graphene_core::vector::style::GradientStops), - OptionalColor(Option), // TODO: Eventually remove this alias document upgrade code #[cfg_attr(feature = "serde", serde(alias = "ManipulatorGroupIds"))] PointIds(Vec), @@ -178,11 +185,6 @@ tagged_value! { BrushStrokes(Vec), BrushCache(BrushCache), DocumentNode(DocumentNode), - // TODO: Eventually remove this migration document upgrade code - #[cfg_attr(feature = "serde", serde(deserialize_with = "graphene_core::migrate_graphic_group"))] - GraphicGroup(graphene_core::GraphicGroupTable), - GraphicElement(graphene_core::GraphicElement), - ArtboardGroup(graphene_core::ArtboardGroup), Curve(graphene_core::raster::curve::Curve), Footprint(graphene_core::transform::Footprint), Palette(Vec), diff --git a/node-graph/graph-craft/src/imaginate_input.rs b/node-graph/graph-craft/src/imaginate_input.rs index e442fd581..383280cf4 100644 --- a/node-graph/graph-craft/src/imaginate_input.rs +++ b/node-graph/graph-craft/src/imaginate_input.rs @@ -1,11 +1,10 @@ use dyn_any::DynAny; use graphene_core::Color; + use std::borrow::Cow; use std::fmt::Debug; -use std::sync::{ - atomic::{AtomicBool, Ordering}, - Arc, Mutex, -}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; #[derive(Default, Debug, Clone, DynAny, specta::Type)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] diff --git a/node-graph/graph-craft/src/proto.rs b/node-graph/graph-craft/src/proto.rs index cb71106c8..29e6e0c75 100644 --- a/node-graph/graph-craft/src/proto.rs +++ b/node-graph/graph-craft/src/proto.rs @@ -923,12 +923,12 @@ mod test { assert_eq!( ids, vec![ - NodeId(12083027370457564588), - NodeId(10127202135369428481), - NodeId(3781642984881236270), - NodeId(12160249450476233602), - NodeId(17962581471057044127), - NodeId(7906594012485169109) + NodeId(907133870432995942), + NodeId(13049623730817360317), + NodeId(2177355904460308500), + NodeId(17479234042764485524), + NodeId(10988236038173832469), + NodeId(11097818235165626738), ] ); } diff --git a/node-graph/graph-craft/src/wasm_application_io.rs b/node-graph/graph-craft/src/wasm_application_io.rs index ec792439a..13d96e70f 100644 --- a/node-graph/graph-craft/src/wasm_application_io.rs +++ b/node-graph/graph-craft/src/wasm_application_io.rs @@ -1,8 +1,8 @@ -use dyn_any::StaticType; use graphene_core::application_io::SurfaceHandleFrame; use graphene_core::application_io::{ApplicationError, ApplicationIo, ResourceFuture, SurfaceHandle, SurfaceId}; use wgpu_executor::WgpuExecutor; +use dyn_any::StaticType; #[cfg(target_arch = "wasm32")] use js_sys::{Object, Reflect}; use std::collections::HashMap; diff --git a/node-graph/gstd/src/any.rs b/node-graph/gstd/src/any.rs index 209cfd917..5b118f78a 100644 --- a/node-graph/gstd/src/any.rs +++ b/node-graph/gstd/src/any.rs @@ -1,13 +1,11 @@ +use dyn_any::StaticType; pub use graph_craft::proto::{Any, NodeContainer, TypeErasedBox, TypeErasedNode}; use graph_craft::proto::{DynFuture, FutureAny, SharedNodeContainer}; +pub use graphene_core::registry::{DowncastBothNode, DynAnyNode, FutureWrapperNode, PanicNode}; use graphene_core::NodeIO; use graphene_core::WasmNotSend; pub use graphene_core::{generic, ops, Node}; -use dyn_any::StaticType; - -pub use graphene_core::registry::{DowncastBothNode, DynAnyNode, FutureWrapperNode, PanicNode}; - pub trait IntoTypeErasedNode<'n> { fn into_type_erased(self) -> TypeErasedBox<'n>; } diff --git a/node-graph/gstd/src/brush.rs b/node-graph/gstd/src/brush.rs index fa9a9e6bb..b74f3c906 100644 --- a/node-graph/gstd/src/brush.rs +++ b/node-graph/gstd/src/brush.rs @@ -90,8 +90,7 @@ fn brush_stamp_generator(diameter: f64, color: Color, hardness: f64, flow: f64) #[node_macro::node(skip_impl)] fn blit(mut target: ImageFrameTable

, texture: Image

, positions: Vec, blend_mode: BlendFn) -> ImageFrameTable

where - P: Pixel + Alpha + std::fmt::Debug + dyn_any::StaticType, - P::Static: Pixel, + P: Pixel + Alpha + std::fmt::Debug, BlendFn: for<'any_input> Node<'any_input, (P, P), Output = P>, GraphicElement: From>, { diff --git a/node-graph/gstd/src/gpu_nodes.rs b/node-graph/gstd/src/gpu_nodes.rs index a89f64486..7a0c5925f 100644 --- a/node-graph/gstd/src/gpu_nodes.rs +++ b/node-graph/gstd/src/gpu_nodes.rs @@ -14,8 +14,7 @@ use wgpu_executor::{Bindgroup, PipelineLayout, Shader, ShaderIO, ShaderInput, Wg use glam::{DAffine2, DVec2, Mat2, Vec2}; use std::collections::HashMap; -use std::sync::Arc; -use std::sync::Mutex; +use std::sync::{Arc, Mutex}; use crate::wasm_application_io::WasmApplicationIo; @@ -81,7 +80,7 @@ async fn map_gpu<'a: 'input>(image: ImageFrameTable, node: DocumentNode, let name = "placeholder".to_string(); let Ok(compute_pass_descriptor) = create_compute_pass_descriptor(node, image_frame_table, executor).await else { log::error!("Error creating compute pass descriptor in 'map_gpu()"); - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); }; self.cache.lock().as_mut().unwrap().insert(name, compute_pass_descriptor.clone()); log::error!("created compute pass"); @@ -338,7 +337,7 @@ async fn blend_gpu_image(_: impl Ctx, foreground: ImageFrameTable, backgr let proto_networks: Result, _> = compiler.compile(network.clone()).collect(); let Ok(proto_networks_result) = proto_networks else { log::error!("Error compiling network in 'blend_gpu_image()"); - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); }; let proto_networks = proto_networks_result; log::debug!("compiling shader"); diff --git a/node-graph/gstd/src/raster.rs b/node-graph/gstd/src/raster.rs index ec04071a7..8b16832cb 100644 --- a/node-graph/gstd/src/raster.rs +++ b/node-graph/gstd/src/raster.rs @@ -47,7 +47,7 @@ fn sample_image(ctx: impl ExtractFootprint + Clone + Send, image_frame: ImageFra // If the image would not be visible, return an empty image if size.x <= 0. || size.y <= 0. { - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); } let image_buffer = image::Rgba32FImage::from_raw(image.width, image.height, data).expect("Failed to convert internal image format into image-rs data type."); @@ -257,8 +257,7 @@ fn mask_image< #[node_macro::node(skip_impl)] async fn blend_image_tuple<_P, MapFn, _Fg>(images: (ImageFrameTable<_P>, _Fg), map_fn: &'n MapFn) -> ImageFrameTable<_P> where - _P: Alpha + Pixel + Debug + Send + dyn_any::StaticType, - _P::Static: Pixel, + _P: Alpha + Pixel + Debug + Send, MapFn: for<'any_input> Node<'any_input, (_P, _P), Output = _P> + 'n + Clone, _Fg: Sample + Transform + Clone + Send + 'n, GraphicElement: From>, @@ -513,7 +512,7 @@ fn noise_pattern( // If the image would not be visible, return an empty image if size.x <= 0. || size.y <= 0. { - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); } let footprint_scale = footprint.scale(); @@ -639,7 +638,7 @@ fn mandelbrot(ctx: impl ExtractFootprint + Send) -> ImageFrameTable { // If the image would not be visible, return an empty image if size.x <= 0. || size.y <= 0. { - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); } let scale = footprint.scale(); diff --git a/node-graph/gstd/src/wasm_application_io.rs b/node-graph/gstd/src/wasm_application_io.rs index 1b1caecb1..5487a5807 100644 --- a/node-graph/gstd/src/wasm_application_io.rs +++ b/node-graph/gstd/src/wasm_application_io.rs @@ -77,7 +77,7 @@ async fn load_resource<'a: 'n>(_: impl Ctx, _primary: (), #[scope("editor-api")] #[node_macro::node(category("Network"))] fn decode_image(_: impl Ctx, data: Arc<[u8]>) -> ImageFrameTable { let Some(image) = image::load_from_memory(data.as_ref()).ok() else { - return ImageFrameTable::empty(); + return ImageFrameTable::one_empty_image(); }; let image = image.to_rgba32f(); let image = Image { @@ -216,7 +216,7 @@ async fn render<'a: 'n, T: 'n + GraphicElementRendered + WasmNotSend>( Context -> ImageFrameTable, Context -> GraphicGroupTable, Context -> graphene_core::Artboard, - Context -> graphene_core::ArtboardGroup, + Context -> graphene_core::ArtboardGroupTable, Context -> Option, Context -> Vec, Context -> bool, diff --git a/node-graph/interpreted-executor/src/dynamic_executor.rs b/node-graph/interpreted-executor/src/dynamic_executor.rs index f55ee6a22..eb1276315 100644 --- a/node-graph/interpreted-executor/src/dynamic_executor.rs +++ b/node-graph/interpreted-executor/src/dynamic_executor.rs @@ -114,7 +114,10 @@ impl DynamicExecutor { } } -impl Executor for &DynamicExecutor { +impl Executor for &DynamicExecutor +where + I: StaticType + 'static + Send + Sync + std::panic::UnwindSafe, +{ fn execute(&self, input: I) -> LocalFuture>> { Box::pin(async move { use futures::FutureExt; @@ -225,14 +228,21 @@ impl BorrowTree { } /// Evaluate the output node of the [`BorrowTree`]. - pub async fn eval<'i, I: StaticType + 'i + Send + Sync, O: StaticType + 'i>(&'i self, id: NodeId, input: I) -> Option { + pub async fn eval<'i, I, O>(&'i self, id: NodeId, input: I) -> Option + where + I: StaticType + 'i + Send + Sync, + O: StaticType + 'i, + { let (node, _path) = self.nodes.get(&id).cloned()?; let output = node.eval(Box::new(input)); dyn_any::downcast::(output.await).ok().map(|o| *o) } /// Evaluate the output node of the [`BorrowTree`] and cast it to a tagged value. /// This ensures that no borrowed data can escape the node graph. - pub async fn eval_tagged_value(&self, id: NodeId, input: I) -> Result { + pub async fn eval_tagged_value(&self, id: NodeId, input: I) -> Result + where + I: StaticType + 'static + Send + Sync + UnwindSafe, + { let (node, _path) = self.nodes.get(&id).cloned().ok_or("Output node not found in executor")?; let output = node.eval(Box::new(input)); TaggedValue::try_from_any(output.await)