diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs index 77d3d562..0c05b532 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler.rs @@ -58,14 +58,14 @@ impl FrontendGraphDataType { } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct NodeGraphInput { +pub struct FrontendGraphInput { #[serde(rename = "dataType")] data_type: FrontendGraphDataType, name: String, } #[derive(Clone, Debug, Eq, PartialEq, serde::Serialize, serde::Deserialize, specta::Type)] -pub struct NodeGraphOutput { +pub struct FrontendGraphOutput { #[serde(rename = "dataType")] data_type: FrontendGraphDataType, name: String, @@ -77,13 +77,13 @@ pub struct FrontendNode { #[serde(rename = "displayName")] pub display_name: String, #[serde(rename = "primaryInput")] - pub primary_input: Option, + pub primary_input: Option, #[serde(rename = "exposedInputs")] - pub exposed_inputs: Vec, + pub exposed_inputs: Vec, #[serde(rename = "primaryOutput")] - pub primary_output: Option, + pub primary_output: Option, #[serde(rename = "exposedOutputs")] - pub exposed_outputs: Vec, + pub exposed_outputs: Vec, pub position: (i32, i32), pub disabled: bool, pub previewed: bool, @@ -291,34 +291,26 @@ impl NodeGraphMessageHandler { let mut nodes = Vec::new(); for (id, node) in &network.nodes { + // TODO: This should be based on the graph runtime type inference system in order to change the colors of node connectors to match the data type in use let Some(node_type) = document_node_types::resolve_document_node_type(&node.name) else { warn!("Node '{}' does not exist in library", node.name); continue; }; - let primary_input = node - .inputs - .first() - .filter(|input| input.is_exposed()) - .and_then(|_| node_type.inputs.get(0)) - .map(|input_type| input_type.data_type); - let exposed_inputs = node - .inputs - .iter() - .zip(node_type.inputs.iter()) - .skip(1) - .filter(|(input, _)| input.is_exposed()) - .map(|(_, input_type)| NodeGraphInput { - data_type: input_type.data_type, - name: input_type.name.to_string(), - }) - .collect(); + // Inputs + let mut inputs = node.inputs.iter().zip(node_type.inputs.iter().map(|input_type| FrontendGraphInput { + data_type: input_type.data_type, + name: input_type.name.to_string(), + })); + let primary_input = inputs.next().filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type); + let exposed_inputs = inputs.filter(|(input, _)| input.is_exposed()).map(|(_, input_type)| input_type).collect(); - let mut outputs = node_type.outputs.iter().map(|output_type| NodeGraphOutput { + // Outputs + let mut outputs = node_type.outputs.iter().map(|output_type| FrontendGraphOutput { data_type: output_type.data_type, name: output_type.name.to_string(), }); - let primary_output = outputs.next(); + let primary_output = if node.has_primary_output { outputs.next() } else { None }; let _graph_identifier = GraphIdentifier::new(layer_id); 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 1abf870c..62e4b244 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 @@ -101,7 +101,7 @@ pub struct DocumentNodeType { pub identifier: NodeImplementation, pub inputs: Vec, pub outputs: Vec, - pub primary_output: bool, + pub has_primary_output: bool, pub properties: fn(&DocumentNode, NodeId, &mut NodePropertiesContext) -> Vec, pub manual_composition: Option, } @@ -114,7 +114,7 @@ impl Default for DocumentNodeType { identifier: Default::default(), inputs: Default::default(), outputs: Default::default(), - primary_output: Default::default(), + has_primary_output: true, properties: node_properties::no_properties, manual_composition: Default::default(), } @@ -836,12 +836,6 @@ fn static_nodes() -> Vec { implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::raster::ExtractAlphaNode<>")), ..Default::default() }, - DocumentNode { - name: "EmptyOutput".to_string(), - inputs: vec![NodeInput::value(TaggedValue::ImageFrame(ImageFrame::empty()), false)], - implementation: DocumentNodeImplementation::Unresolved(NodeIdentifier::new("graphene_core::ops::IdNode")), - ..Default::default() - }, ] .into_iter() .enumerate() @@ -852,13 +846,12 @@ fn static_nodes() -> Vec { }), inputs: vec![DocumentInputType::value("Image", TaggedValue::ImageFrame(ImageFrame::empty()), true)], outputs: vec![ - DocumentOutputType::new("Empty", FrontendGraphDataType::Raster), DocumentOutputType::new("Red", FrontendGraphDataType::Raster), DocumentOutputType::new("Green", FrontendGraphDataType::Raster), DocumentOutputType::new("Blue", FrontendGraphDataType::Raster), DocumentOutputType::new("Alpha", FrontendGraphDataType::Raster), ], - primary_output: false, + has_primary_output: false, ..Default::default() }, DocumentNodeType { @@ -2468,6 +2461,7 @@ impl DocumentNodeType { DocumentNode { name: self.name.to_string(), inputs, + has_primary_output: self.has_primary_output, implementation: self.generate_implementation(), metadata, manual_composition: self.manual_composition.clone(), diff --git a/frontend/src/components/views/Graph.svelte b/frontend/src/components/views/Graph.svelte index 8df57754..e0ce98ee 100644 --- a/frontend/src/components/views/Graph.svelte +++ b/frontend/src/components/views/Graph.svelte @@ -681,9 +681,9 @@ viewBox="0 0 8 8" class="port" data-port="input" - data-datatype={node.primaryInput} - style:--data-color={`var(--color-data-${node.primaryInput})`} - style:--data-color-dim={`var(--color-data-${node.primaryInput}-dim)`} + data-datatype={node.primaryInput?.dataType} + style:--data-color={`var(--color-data-${node.primaryInput?.dataType})`} + style:--data-color-dim={`var(--color-data-${node.primaryInput?.dataType}-dim)`} > {node.primaryInput} data @@ -768,15 +768,15 @@ {/if}
- {#if node.primaryInput} + {#if node.primaryInput?.dataType} {node.primaryInput} data @@ -835,7 +835,7 @@ diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index d350da16..334ccbde 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -81,13 +81,13 @@ export class FrontendDocumentDetails extends DocumentDetails { export type FrontendGraphDataType = "general" | "raster" | "color" | "vector" | "vec2" | "graphic" | "artboard"; -export class NodeGraphInput { +export class FrontendGraphInput { readonly dataType!: FrontendGraphDataType; readonly name!: string; } -export class NodeGraphOutput { +export class FrontendGraphOutput { readonly dataType!: FrontendGraphDataType; readonly name!: string; @@ -98,13 +98,13 @@ export class FrontendNode { readonly displayName!: string; - readonly primaryInput!: FrontendGraphDataType | undefined; + readonly primaryInput!: FrontendGraphInput | undefined; - readonly exposedInputs!: NodeGraphInput[]; + readonly exposedInputs!: FrontendGraphInput[]; - readonly primaryOutput!: NodeGraphOutput | undefined; + readonly primaryOutput!: FrontendGraphOutput | undefined; - readonly exposedOutputs!: NodeGraphOutput[]; + readonly exposedOutputs!: FrontendGraphOutput[]; @TupleToVec2 readonly position!: XY | undefined; diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 967c3be4..987cb844 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -31,12 +31,20 @@ impl DocumentNodeMetadata { } } -#[derive(Clone, Debug, PartialEq, Hash, DynAny, Default)] +/// Utility function for providing a default boolean value to serde. +#[inline(always)] +fn return_true() -> bool { + true +} + +#[derive(Clone, Debug, PartialEq, Hash, DynAny)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DocumentNode { pub name: String, pub inputs: Vec, pub manual_composition: Option, + #[serde(default = "return_true")] + pub has_primary_output: bool, pub implementation: DocumentNodeImplementation, pub metadata: DocumentNodeMetadata, #[serde(default)] @@ -47,6 +55,22 @@ pub struct DocumentNode { pub path: Option>, } +impl Default for DocumentNode { + fn default() -> Self { + Self { + name: Default::default(), + inputs: Default::default(), + manual_composition: Default::default(), + has_primary_output: true, + implementation: Default::default(), + metadata: Default::default(), + skip_deduplication: Default::default(), + hash: Default::default(), + path: Default::default(), + } + } +} + impl DocumentNode { pub fn populate_first_network_input(&mut self, node_id: NodeId, output_index: usize, offset: usize, lambda: bool) { let (index, _) = self