diff --git a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs index 350f4479..bc6ed212 100644 --- a/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/graph_operation_message_handler.rs @@ -107,7 +107,6 @@ impl<'a> ModifyInputsContext<'a> { } else { // The user has connected another node to the output. Insert a layer node between the output and the node. let mut node = resolve_document_node_type("Layer").expect("Layer node").default_document_node(); - self.add_empty_stack(&mut node); let node_id = self.insert_between(generate_uuid(), NodeOutput::new(node_id, output_index), output, node, 0, 0, IVec2::new(-8, 0))?; NodeOutput::new(node_id, 0) }; @@ -116,7 +115,6 @@ impl<'a> ModifyInputsContext<'a> { self.insert_between(new_id, sibling_layer, output, node, 7, 0, IVec2::new(0, 3)) } else { let mut layer_node = resolve_document_node_type("Layer").expect("Node").default_document_node(); - self.add_empty_stack(&mut layer_node); self.insert_node_before(new_id, output_node_id, input_index, layer_node, IVec2::new(-5, 3)) }; @@ -131,15 +129,7 @@ impl<'a> ModifyInputsContext<'a> { new_id } - fn add_empty_stack(&mut self, node: &mut DocumentNode) { - let empty_stack = resolve_document_node_type("Empty Stack").expect("EmptyStack node").default_document_node(); - let empty_id = generate_uuid(); - self.network.nodes.insert(empty_id, empty_stack); - *node.inputs.last_mut().unwrap() = NodeInput::node(empty_id, 0); - } - fn insert_artboard(&mut self, artboard: Artboard, layer: NodeId) -> Option { - let cull_node = resolve_document_node_type("Cull").expect("Node").default_document_node(); let artboard_node = resolve_document_node_type("Artboard").expect("Node").to_document_node_default_inputs( [ None, @@ -152,8 +142,7 @@ impl<'a> ModifyInputsContext<'a> { ); self.responses.add(NodeGraphMessage::SendGraph { should_rerender: true }); let cull_id = generate_uuid(); - self.insert_node_before(cull_id, layer, 0, cull_node, IVec2::new(-8, 0)); - self.insert_node_before(generate_uuid(), cull_id, 0, artboard_node, IVec2::new(-8, 0)) + self.insert_node_before(generate_uuid(), layer, 0, artboard_node, IVec2::new(-8, 0)) } fn insert_vector_data(&mut self, subpaths: Vec>, layer: NodeId) { diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 62e4b244..8ca330e3 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -262,15 +262,6 @@ fn static_nodes() -> Vec { properties: node_properties::artboard_properties, ..Default::default() }, - DocumentNodeType { - name: "Empty Stack", - category: "Hidden", - identifier: NodeImplementation::proto("graphene_core::transform::CullNode<_>"), - manual_composition: Some(concrete!(Footprint)), - inputs: vec![DocumentInputType::value("Graphic Group", TaggedValue::GraphicGroup(GraphicGroup::EMPTY), false)], - outputs: vec![DocumentOutputType::new("Out", FrontendGraphDataType::Artboard)], - ..Default::default() - }, DocumentNodeType { name: "Input Frame", category: "Ignore", @@ -2486,6 +2477,7 @@ impl DocumentNodeType { pub fn wrap_network_in_scope(mut network: NodeNetwork, hash: u64) -> NodeNetwork { network.generate_node_paths(&[]); + network.resolve_empty_stacks(); let node_ids = network.nodes.keys().copied().collect::>(); for id in node_ids { network.flatten(id); diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index e754d04e..55cde476 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -1,6 +1,6 @@ use crate::document::value::TaggedValue; use crate::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, ProtoNodeInput}; -use graphene_core::{NodeIdentifier, Type}; +use graphene_core::{GraphicGroup, NodeIdentifier, Type}; use dyn_any::{DynAny, StaticType}; use glam::IVec2; @@ -1006,6 +1006,45 @@ impl NodeNetwork { self.nodes.extend(extraction_nodes); } + /// Due to the adaptive resolution system, nodes that take a `GraphicGroup` as input must call the upstream node with the `Footprint` parameter. + /// + /// However, in the case of the default input, we must insert a node that takes an input of `Footprint` and returns `GraphicGroup::Empty`, in order to satisfy the type system. + /// This is because the standard value node takes in `()`. + pub fn resolve_empty_stacks(&mut self) { + const EMPTY_STACK: &str = "Empty Stack"; + + let new_id = generate_uuid(); + let mut used = false; + + // We filter out the newly inserted empty stack in case `resolve_empty_stacks` runs multiple times. + for node in self.nodes.values_mut().filter(|node| node.name != EMPTY_STACK) { + for input in &mut node.inputs { + if matches!( + input, + NodeInput::Value { + tagged_value: TaggedValue::GraphicGroup(GraphicGroup::EMPTY), + .. + } + ) { + *input = NodeInput::node(new_id, 0); + used = true; + } + } + } + + // Only insert the node if necessary. + if used { + let new_node = DocumentNode { + name: EMPTY_STACK.to_string(), + implementation: DocumentNodeImplementation::proto("graphene_core::transform::CullNode<_>"), + manual_composition: Some(concrete!(graphene_core::transform::Footprint)), + inputs: vec![NodeInput::value(TaggedValue::GraphicGroup(graphene_core::GraphicGroup::EMPTY), false)], + ..Default::default() + }; + self.nodes.insert(new_id, new_node); + } + } + /// Creates a proto network for evaluating each output of this network. pub fn into_proto_networks(self) -> impl Iterator { let mut nodes: Vec<_> = self.nodes.into_iter().map(|(id, node)| (id, node.resolve_proto_node())).collect(); @@ -1089,7 +1128,7 @@ mod test { fn map_ids() { let mut network = add_network(); network.map_ids(|id| id + 1); - let maped_add = NodeNetwork { + let mapped_add = NodeNetwork { inputs: vec![1, 1], outputs: vec![NodeOutput::new(2, 0)], nodes: [ @@ -1116,7 +1155,7 @@ mod test { .collect(), ..Default::default() }; - assert_eq!(network, maped_add); + assert_eq!(network, mapped_add); } #[test] diff --git a/node-graph/graph-craft/src/graphene_compiler.rs b/node-graph/graph-craft/src/graphene_compiler.rs index f6fe73e7..cc090464 100644 --- a/node-graph/graph-craft/src/graphene_compiler.rs +++ b/node-graph/graph-craft/src/graphene_compiler.rs @@ -10,6 +10,7 @@ pub struct Compiler {} impl Compiler { pub fn compile(&self, mut network: NodeNetwork) -> Result, String> { println!("flattening"); + network.resolve_empty_stacks(); let node_ids = network.nodes.keys().copied().collect::>(); for id in node_ids { network.flatten(id);