Skip to content

Commit 34bc28a

Browse files
committed
Prototype document network level into node insertion
1 parent 86da69e commit 34bc28a

3 files changed

Lines changed: 340 additions & 1 deletion

File tree

editor/src/messages/portfolio/document/node_graph/document_node_definitions.rs

Lines changed: 111 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use graphene_std::vector::VectorDataTable;
2424
use graphene_std::*;
2525
use std::collections::{HashMap, HashSet, VecDeque};
2626

27+
mod document_node_derive;
28+
2729
pub struct NodePropertiesContext<'a> {
2830
pub persistent_data: &'a PersistentData,
2931
pub responses: &'a mut VecDeque<Message>,
@@ -91,7 +93,7 @@ static DOCUMENT_NODE_TYPES: once_cell::sync::Lazy<Vec<DocumentNodeDefinition>> =
9193
/// Defines the "signature" or "header file"-like metadata for the document nodes, but not the implementation (which is defined in the node registry).
9294
/// The [`DocumentNode`] is the instance while these [`DocumentNodeDefinition`]s are the "classes" or "blueprints" from which the instances are built.
9395
fn static_nodes() -> Vec<DocumentNodeDefinition> {
94-
let mut custom = vec![
96+
let custom = vec![
9597
// TODO: Auto-generate this from its proto node macro
9698
DocumentNodeDefinition {
9799
identifier: "Identity",
@@ -2114,6 +2116,7 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
21142116
},
21152117
];
21162118

2119+
<<<<<<< HEAD
21172120
// Remove struct generics
21182121
for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() {
21192122
let NodeTemplate {
@@ -2217,6 +2220,113 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
22172220
custom.push(node);
22182221
}
22192222
custom
2223+
||||||| parent of de38de1c7 (Prototype document network level into node insertion)
2224+
// Remove struct generics
2225+
for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() {
2226+
let NodeTemplate {
2227+
document_node: DocumentNode { implementation, .. },
2228+
..
2229+
} = node_template;
2230+
if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation {
2231+
if let Some((new_name, _suffix)) = name.rsplit_once("<") {
2232+
*name = Cow::Owned(new_name.to_string())
2233+
}
2234+
};
2235+
}
2236+
let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap();
2237+
'outer: for (id, metadata) in graphene_core::registry::NODE_METADATA.lock().unwrap().iter() {
2238+
use graphene_core::registry::*;
2239+
let id = id.clone();
2240+
2241+
for node in custom.iter() {
2242+
let DocumentNodeDefinition {
2243+
node_template: NodeTemplate {
2244+
document_node: DocumentNode { implementation, .. },
2245+
..
2246+
},
2247+
..
2248+
} = node;
2249+
match implementation {
2250+
DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) if name == &id => continue 'outer,
2251+
_ => (),
2252+
}
2253+
}
2254+
2255+
let NodeMetadata {
2256+
display_name,
2257+
category,
2258+
fields,
2259+
description,
2260+
properties,
2261+
} = metadata;
2262+
let Some(implementations) = &node_registry.get(&id) else { continue };
2263+
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
2264+
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
2265+
let mut input_type = &first_node_io.call_argument;
2266+
if valid_inputs.len() > 1 {
2267+
input_type = &const { generic!(D) };
2268+
}
2269+
let output_type = &first_node_io.return_value;
2270+
2271+
let inputs = fields
2272+
.iter()
2273+
.zip(first_node_io.inputs.iter())
2274+
.enumerate()
2275+
.map(|(index, (field, node_io_ty))| {
2276+
let ty = field.default_type.as_ref().unwrap_or(node_io_ty);
2277+
let exposed = if index == 0 { *ty != fn_type_fut!(Context, ()) } else { field.exposed };
2278+
2279+
match field.value_source {
2280+
RegistryValueSource::None => {}
2281+
RegistryValueSource::Default(data) => return NodeInput::value(TaggedValue::from_primitive_string(data, ty).unwrap_or(TaggedValue::None), exposed),
2282+
RegistryValueSource::Scope(data) => return NodeInput::scope(Cow::Borrowed(data)),
2283+
};
2284+
2285+
if let Some(type_default) = TaggedValue::from_type(ty) {
2286+
return NodeInput::value(type_default, exposed);
2287+
}
2288+
NodeInput::value(TaggedValue::None, true)
2289+
})
2290+
.collect();
2291+
2292+
let node = DocumentNodeDefinition {
2293+
identifier: display_name,
2294+
node_template: NodeTemplate {
2295+
document_node: DocumentNode {
2296+
inputs,
2297+
manual_composition: Some(input_type.clone()),
2298+
implementation: DocumentNodeImplementation::ProtoNode(id.clone().into()),
2299+
visible: true,
2300+
skip_deduplication: false,
2301+
..Default::default()
2302+
},
2303+
persistent_node_metadata: DocumentNodePersistentMetadata {
2304+
// TODO: Store information for input overrides in the node macro
2305+
input_properties: fields
2306+
.iter()
2307+
.map(|f| match f.widget_override {
2308+
RegistryWidgetOverride::None => (f.name, f.description).into(),
2309+
RegistryWidgetOverride::Hidden => PropertiesRow::with_override(f.name, f.description, WidgetOverride::Hidden),
2310+
RegistryWidgetOverride::String(str) => PropertiesRow::with_override(f.name, f.description, WidgetOverride::String(str.to_string())),
2311+
RegistryWidgetOverride::Custom(str) => PropertiesRow::with_override(f.name, f.description, WidgetOverride::Custom(str.to_string())),
2312+
})
2313+
.collect(),
2314+
output_names: vec![output_type.to_string()],
2315+
has_primary_output: true,
2316+
locked: false,
2317+
..Default::default()
2318+
},
2319+
},
2320+
category: category.unwrap_or("UNCATEGORIZED"),
2321+
description: Cow::Borrowed(description),
2322+
properties: *properties,
2323+
};
2324+
custom.push(node);
2325+
}
2326+
custom
2327+
=======
2328+
document_node_derive::post_process_nodes(custom)
2329+
>>>>>>> de38de1c7 (Prototype document network level into node insertion)
22202330
}
22212331

22222332
// pub static IMAGINATE_NODE: Lazy<DocumentNodeDefinition> = Lazy::new(|| DocumentNodeDefinition {
Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
use super::DocumentNodeDefinition;
2+
use crate::messages::portfolio::document::utility_types::network_interface::{
3+
DocumentNodeMetadata, DocumentNodePersistentMetadata, NodeNetworkMetadata, NodeNetworkPersistentMetadata, NodePersistentMetadata, NodePosition, NodeTemplate, NodeTypePersistentMetadata,
4+
PropertiesRow, WidgetOverride,
5+
};
6+
use graph_craft::ProtoNodeIdentifier;
7+
use graph_craft::concrete;
8+
use graph_craft::document::value::*;
9+
use graph_craft::document::*;
10+
use graphene_std::registry::*;
11+
use graphene_std::*;
12+
use std::collections::{HashMap, HashSet};
13+
14+
pub(super) fn post_process_nodes(mut custom: Vec<DocumentNodeDefinition>) -> Vec<DocumentNodeDefinition> {
15+
// Remove struct generics
16+
for DocumentNodeDefinition { node_template, .. } in custom.iter_mut() {
17+
let NodeTemplate {
18+
document_node: DocumentNode { implementation, .. },
19+
..
20+
} = node_template;
21+
if let DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) = implementation {
22+
if let Some((new_name, _suffix)) = name.rsplit_once("<") {
23+
*name = Cow::Owned(new_name.to_string())
24+
}
25+
};
26+
}
27+
let node_registry = graphene_core::registry::NODE_REGISTRY.lock().unwrap();
28+
'outer: for (id, metadata) in NODE_METADATA.lock().unwrap().iter() {
29+
let id = id.clone();
30+
31+
for node in custom.iter() {
32+
let DocumentNodeDefinition {
33+
node_template: NodeTemplate {
34+
document_node: DocumentNode { implementation, .. },
35+
..
36+
},
37+
..
38+
} = node;
39+
match implementation {
40+
DocumentNodeImplementation::ProtoNode(ProtoNodeIdentifier { name }) if name == &id => continue 'outer,
41+
_ => (),
42+
}
43+
}
44+
45+
let NodeMetadata {
46+
display_name,
47+
category,
48+
fields,
49+
description,
50+
properties,
51+
} = metadata;
52+
let Some(implementations) = &node_registry.get(&id) else { continue };
53+
let valid_inputs: HashSet<_> = implementations.iter().map(|(_, node_io)| node_io.call_argument.clone()).collect();
54+
let first_node_io = implementations.first().map(|(_, node_io)| node_io).unwrap_or(const { &NodeIOTypes::empty() });
55+
let mut node_io_types = vec![HashSet::new(); fields.len()];
56+
for (_, node_io) in implementations.iter() {
57+
for (i, ty) in node_io.inputs.iter().enumerate() {
58+
node_io_types[i].insert(ty.clone());
59+
}
60+
}
61+
let mut input_type = &first_node_io.call_argument;
62+
if valid_inputs.len() > 1 {
63+
input_type = &const { generic!(D) };
64+
}
65+
let output_type = &first_node_io.return_value;
66+
67+
let inputs: Vec<_> = fields
68+
.iter()
69+
.zip(first_node_io.inputs.iter())
70+
.enumerate()
71+
.map(|(index, (field, node_io_ty))| {
72+
let ty = field.default_type.as_ref().unwrap_or(node_io_ty);
73+
let exposed = if index == 0 { *ty != fn_type_fut!(Context, ()) } else { field.exposed };
74+
75+
match field.value_source {
76+
RegistryValueSource::None => {}
77+
RegistryValueSource::Default(data) => return NodeInput::value(TaggedValue::from_primitive_string(data, ty).unwrap_or(TaggedValue::None), exposed),
78+
RegistryValueSource::Scope(data) => return NodeInput::scope(Cow::Borrowed(data)),
79+
};
80+
81+
if let Some(type_default) = TaggedValue::from_type(ty) {
82+
return NodeInput::value(type_default, exposed);
83+
}
84+
NodeInput::value(TaggedValue::None, true)
85+
})
86+
.collect();
87+
let input_count = inputs.len();
88+
let network_inputs = (0..input_count).map(|i| NodeInput::node(NodeId(i as u64), 0)).collect();
89+
let identity_node = ProtoNodeIdentifier::new("graphene_core::ops::IdentityNode");
90+
let into_node_registry = &interpreted_executor::node_registry::NODE_REGISTRY;
91+
let mut nodes: HashMap<_, _, _> = node_io_types
92+
.iter()
93+
.enumerate()
94+
.map(|(i, inputs)| {
95+
(
96+
NodeId(i as u64),
97+
match inputs.len() {
98+
1 => {
99+
let input = inputs.iter().next().unwrap();
100+
let input_ty = input.nested_type();
101+
let into_node_identifier = ProtoNodeIdentifier {
102+
name: format!("graphene_core::ops::IntoNode<{}>", input_ty.clone()).into(),
103+
};
104+
let proto_node = if into_node_registry.iter().any(|(ident, _)| {
105+
let ident = ident.name.as_ref();
106+
// log::debug!("checking: {} against {}", ident, into_node_identifier.name.as_ref());
107+
ident == into_node_identifier.name.as_ref()
108+
}) {
109+
// log::debug!("placing {}", into_node_identifier.name.as_ref());
110+
into_node_identifier
111+
} else {
112+
identity_node.clone()
113+
};
114+
DocumentNode {
115+
inputs: vec![NodeInput::network(input.clone(), i)],
116+
// manual_composition: Some(fn_input.clone()),
117+
implementation: DocumentNodeImplementation::ProtoNode(proto_node),
118+
visible: true,
119+
..Default::default()
120+
}
121+
}
122+
_ => DocumentNode {
123+
inputs: vec![NodeInput::network(generic!(X), i)],
124+
implementation: DocumentNodeImplementation::ProtoNode(identity_node.clone()),
125+
visible: true,
126+
..Default::default()
127+
},
128+
},
129+
)
130+
})
131+
.collect();
132+
133+
let document_node = DocumentNode {
134+
inputs: network_inputs,
135+
manual_composition: Some(input_type.clone()),
136+
implementation: DocumentNodeImplementation::ProtoNode(id.clone().into()),
137+
visible: true,
138+
skip_deduplication: false,
139+
..Default::default()
140+
};
141+
let mut node_names: HashMap<NodeId, String> = nodes
142+
.iter()
143+
.map(|(id, node)| (*id, node.implementation.get_proto_node().unwrap().name.rsplit_once("::").unwrap().1.to_string()))
144+
.collect();
145+
nodes.insert(NodeId(input_count as u64), document_node);
146+
node_names.insert(NodeId(input_count as u64), display_name.to_string());
147+
let node_type_metadata = |id: NodeId| {
148+
NodeTypePersistentMetadata::Node(NodePersistentMetadata::new(NodePosition::Absolute(if id.0 == input_count as u64 {
149+
IVec2::default()
150+
} else {
151+
IVec2 { x: -10, y: id.0 as i32 }
152+
})))
153+
};
154+
155+
let node = DocumentNodeDefinition {
156+
identifier: display_name,
157+
node_template: NodeTemplate {
158+
document_node: DocumentNode {
159+
inputs,
160+
manual_composition: Some(input_type.clone()),
161+
implementation: DocumentNodeImplementation::Network(NodeNetwork {
162+
exports: vec![NodeInput::Node {
163+
node_id: NodeId(input_count as u64),
164+
output_index: 0,
165+
lambda: false,
166+
}],
167+
nodes,
168+
scope_injections: Default::default(),
169+
}),
170+
visible: true,
171+
skip_deduplication: false,
172+
..Default::default()
173+
},
174+
persistent_node_metadata: DocumentNodePersistentMetadata {
175+
// TODO: Store information for input overrides in the node macro
176+
input_properties: fields
177+
.iter()
178+
.map(|f| match f.widget_override {
179+
RegistryWidgetOverride::None => (f.name, f.description).into(),
180+
RegistryWidgetOverride::Hidden => PropertiesRow::with_override(f.name, f.description, WidgetOverride::Hidden),
181+
RegistryWidgetOverride::String(str) => PropertiesRow::with_override(f.name, f.description, WidgetOverride::String(str.to_string())),
182+
RegistryWidgetOverride::Custom(str) => PropertiesRow::with_override(f.name, f.description, WidgetOverride::Custom(str.to_string())),
183+
})
184+
.collect(),
185+
output_names: vec![output_type.to_string()],
186+
has_primary_output: true,
187+
locked: false,
188+
189+
network_metadata: Some(NodeNetworkMetadata {
190+
persistent_metadata: NodeNetworkPersistentMetadata {
191+
node_metadata: node_names
192+
.into_iter()
193+
.map(|(id, display_name)| {
194+
let node_type_metadata = node_type_metadata(id);
195+
(
196+
id,
197+
DocumentNodeMetadata {
198+
persistent_metadata: DocumentNodePersistentMetadata {
199+
display_name,
200+
node_type_metadata,
201+
..Default::default()
202+
},
203+
..Default::default()
204+
},
205+
)
206+
})
207+
.collect(),
208+
..Default::default()
209+
},
210+
..Default::default()
211+
}),
212+
213+
..Default::default()
214+
},
215+
},
216+
category: category.unwrap_or("UNCATEGORIZED"),
217+
description: Cow::Borrowed(description),
218+
properties: *properties,
219+
};
220+
custom.push(node);
221+
}
222+
custom
223+
}

editor/src/messages/portfolio/document/utility_types/network_interface.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6515,6 +6515,12 @@ pub struct NodePersistentMetadata {
65156515
position: NodePosition,
65166516
}
65176517

6518+
impl NodePersistentMetadata {
6519+
pub fn new(position: NodePosition) -> Self {
6520+
Self { position }
6521+
}
6522+
}
6523+
65186524
/// A layer can either be position as Absolute or in a Stack
65196525
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
65206526
pub enum LayerPosition {

0 commit comments

Comments
 (0)