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 2f8f097f..0f6bb5bb 100644 --- a/editor/src/messages/portfolio/document/utility_types/network_interface.rs +++ b/editor/src/messages/portfolio/document/utility_types/network_interface.rs @@ -618,6 +618,7 @@ impl NodeNetworkInterface { } NodeInput::Scope(_) => todo!(), NodeInput::Inline(_) => todo!(), + NodeInput::Reflection(_) => todo!(), } } } @@ -4418,7 +4419,7 @@ impl NodeNetworkInterface { if post_node.input_index() == 1 || matches!(post_node, InputConnector::Export(_)) || !post_node.node_id().is_some_and(|post_node_id| self.is_layer(&post_node_id, network_path)) { match post_node_input { // Create a new stack - NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) => { + NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) | NodeInput::Reflection(_) => { self.create_wire(&OutputConnector::node(layer.to_node(), 0), &post_node, network_path); let final_layer_position = after_move_post_layer_position + IVec2::new(-8, 3); @@ -4444,7 +4445,7 @@ impl NodeNetworkInterface { } else { match post_node_input { // Move to the bottom of the stack - NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) => { + NodeInput::Value { .. } | NodeInput::Scope(_) | NodeInput::Inline(_) | NodeInput::Reflection(_) => { // TODO: Calculate height of bottom layer by getting height of upstream nodes instead of setting to 3 let offset = after_move_post_layer_position - previous_layer_position + IVec2::new(0, 3); self.shift_absolute_node_position(&layer.to_node(), offset, network_path); diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index d8727afe..82b790d0 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -7,6 +7,7 @@ pub use graphene_core::uuid::generate_uuid; use graphene_core::{Cow, MemoHash, ProtoNodeIdentifier, Type}; use glam::IVec2; +use log::Metadata; use rustc_hash::FxHashMap; use std::collections::hash_map::DefaultHasher; use std::collections::HashMap; @@ -15,7 +16,7 @@ use std::hash::{Hash, Hasher}; pub mod value; #[repr(transparent)] -#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, specta::Type)] +#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, serde::Serialize, serde::Deserialize, specta::Type, DynAny)] pub struct NodeId(pub u64); // TODO: Find and replace all `NodeId(generate_uuid())` with `NodeId::new()`. @@ -308,6 +309,7 @@ impl DocumentNode { NodeInput::Network { import_type, .. } => (ProtoNodeInput::ManualComposition(import_type), ConstructionArgs::Nodes(vec![])), NodeInput::Inline(inline) => (ProtoNodeInput::None, ConstructionArgs::Inline(inline)), NodeInput::Scope(_) => unreachable!("Scope input was not resolved"), + NodeInput::Reflection(_) => unreachable!("Reflection input was not resolved"), } }; assert!(!self.inputs.iter().any(|input| matches!(input, NodeInput::Network { .. })), "received non resolved parameter"); @@ -355,6 +357,9 @@ pub enum NodeInput { /// Input that is extracted from the parent scopes the node resides in. The string argument is the key. Scope(Cow<'static, str>), + /// Input that is extracted from the parent scopes the node resides in. The string argument is the key. + Reflection(DocumentNodeMetadata), + /// A Rust source code string. Allows us to insert literal Rust code. Only used for GPU compilation. /// We can use this whenever we spin up Rustc. Sort of like inline assembly, but because our language is Rust, it acts as inline Rust. Inline(InlineRust), @@ -373,6 +378,12 @@ impl InlineRust { } } +#[derive(Debug, Clone, PartialEq, Hash, DynAny)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +pub enum DocumentNodeMetadata { + DocumentNodePath, +} + impl NodeInput { pub const fn node(node_id: NodeId, output_index: usize) -> Self { Self::Node { node_id, output_index, lambda: false } @@ -412,6 +423,7 @@ impl NodeInput { NodeInput::Network { .. } => true, NodeInput::Inline(_) => false, NodeInput::Scope(_) => false, + NodeInput::Reflection(_) => false, } } /// Network node inputs in the document network are not displayed, but still exist in the compiled network @@ -422,6 +434,7 @@ impl NodeInput { NodeInput::Network { .. } => !is_document_network, NodeInput::Inline(_) => false, NodeInput::Scope(_) => false, + NodeInput::Reflection(_) => false, } } @@ -432,6 +445,7 @@ impl NodeInput { NodeInput::Network { import_type, .. } => import_type.clone(), NodeInput::Inline(_) => panic!("ty() called on NodeInput::Inline"), NodeInput::Scope(_) => unreachable!("ty() called on NodeInput::Scope"), + NodeInput::Reflection(_) => concrete!(Metadata), } } @@ -1022,7 +1036,7 @@ impl NodeNetwork { return; }; - // Replace value exports with value nodes, added inside nested network + // Replace value and reflection imports with value nodes, added inside nested network Self::replace_value_inputs_with_nodes( &mut inner_network.exports, &mut inner_network.nodes, @@ -1076,6 +1090,7 @@ impl NodeNetwork { // TODO use correct output index nested_node.inputs[nested_input_index] = NodeInput::node(*import_id, 0); } + NodeInput::Reflection(_) => unreachable!("Reflection inputs should have been replaced with value nodes"), } } } @@ -1120,35 +1135,43 @@ impl NodeNetwork { for export in inputs { let export: &mut NodeInput = export; let previous_export = std::mem::replace(export, NodeInput::network(concrete!(()), 0)); - if let NodeInput::Value { tagged_value, exposed } = previous_export { - let value_node_id = gen_id(); - let merged_node_id = map_ids(id, value_node_id); - let mut original_location = OriginalLocation { - path: Some(path.to_vec()), - dependants: vec![vec![id]], - ..Default::default() - }; - if let Some(path) = &mut original_location.path { - path.push(value_node_id); + println!("export {:?}", previous_export); + let (tagged_value, exposed) = match previous_export { + NodeInput::Value { tagged_value, exposed } => (tagged_value, exposed), + NodeInput::Reflection(reflect) => match reflect { + DocumentNodeMetadata::DocumentNodePath => (TaggedValue::NodePath(path.to_vec()).into(), false), + }, + previous_export => { + *export = previous_export; + continue; } - collection.insert( - merged_node_id, - DocumentNode { - inputs: vec![NodeInput::Value { tagged_value, exposed }], - implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()), - original_location, - ..Default::default() - }, - ); - *export = NodeInput::Node { - node_id: merged_node_id, - output_index: 0, - lambda: false, - }; - } else { - *export = previous_export; + }; + let value_node_id = gen_id(); + let merged_node_id = map_ids(id, value_node_id); + let mut original_location = OriginalLocation { + path: Some(path.to_vec()), + dependants: vec![vec![id]], + ..Default::default() + }; + + if let Some(path) = &mut original_location.path { + path.push(value_node_id); } + collection.insert( + merged_node_id, + DocumentNode { + inputs: vec![NodeInput::Value { tagged_value, exposed }], + implementation: DocumentNodeImplementation::ProtoNode("graphene_core::value::ClonedNode".into()), + original_location, + ..Default::default() + }, + ); + *export = NodeInput::Node { + node_id: merged_node_id, + output_index: 0, + lambda: false, + }; } } diff --git a/node-graph/graph-craft/src/document/value.rs b/node-graph/graph-craft/src/document/value.rs index ca54c368..32b62b4b 100644 --- a/node-graph/graph-craft/src/document/value.rs +++ b/node-graph/graph-craft/src/document/value.rs @@ -1,4 +1,5 @@ use super::DocumentNode; +use crate::document::NodeId; pub use crate::imaginate_input::{ImaginateCache, ImaginateController, ImaginateMaskStartingFill, ImaginateSamplingMethod}; use crate::proto::{Any as DAny, FutureAny}; use crate::wasm_application_io::WasmEditorApi; @@ -138,6 +139,8 @@ tagged_value! { F64Array4([f64; 4]), #[serde(alias = "VecF32")] // TODO: Eventually remove this alias (probably starting late 2024) VecF64(Vec), + VecU64(Vec), + NodePath(Vec), VecDVec2(Vec), RedGreenBlue(graphene_core::raster::RedGreenBlue), RedGreenBlueAlpha(graphene_core::raster::RedGreenBlueAlpha),