diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index cef013c9..d1b03c81 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -98,11 +98,20 @@ pub enum DocumentMessage { delta: (f64, f64), mirror_distance: bool, }, - NodeGraphFrameGenerate, + NodeGraphFrameClear { + layer_path: Vec, + node_id: NodeId, + cached_index: usize, + }, + NodeGraphFrameGenerate { + layer_path: Vec, + }, NodeGraphFrameImaginate { + layer_path: Vec, imaginate_node: Vec, }, NodeGraphFrameImaginateRandom { + layer_path: Vec, imaginate_node: Vec, then_generate: bool, }, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 67cc4995..ce8d2872 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -512,23 +512,36 @@ impl MessageHandler { - if let Some(message) = self.call_node_graph_frame(document_id, preferences, persistent_data, None) { + NodeGraphFrameClear { + layer_path, + node_id, + cached_index: input_index, + } => { + let value = graph_craft::document::value::TaggedValue::RcImage(None); + responses.push_back(NodeGraphMessage::SetInputValue { node_id, input_index, value }.into()); + responses.push_back(NodeGraphFrameGenerate { layer_path }.into()); + } + NodeGraphFrameGenerate { layer_path } => { + if let Some(message) = self.call_node_graph_frame(document_id, layer_path, preferences, persistent_data, None) { responses.push_back(message); } } - NodeGraphFrameImaginate { imaginate_node } => { - if let Some(message) = self.call_node_graph_frame(document_id, preferences, persistent_data, Some(imaginate_node)) { + NodeGraphFrameImaginate { layer_path, imaginate_node } => { + if let Some(message) = self.call_node_graph_frame(document_id, layer_path, preferences, persistent_data, Some(imaginate_node)) { responses.push_back(message); } } - NodeGraphFrameImaginateRandom { imaginate_node, then_generate } => { + NodeGraphFrameImaginateRandom { + layer_path, + imaginate_node, + then_generate, + } => { // Set a random seed input responses.push_back( NodeGraphMessage::SetInputValue { node_id: *imaginate_node.last().unwrap(), // Needs to match the index of the seed parameter in `pub const IMAGINATE_NODE: DocumentNodeType` in `document_node_type.rs` - input_index: 2, + input_index: 1, value: graph_craft::document::value::TaggedValue::F64((generate_uuid() >> 1) as f64), } .into(), @@ -536,7 +549,7 @@ impl MessageHandler { @@ -651,13 +664,13 @@ impl MessageHandler>) -> Option { - let layer_path = { - let mut selected_nodegraph_layers = self.selected_layers_with_type(LayerDataTypeDiscriminant::NodeGraphFrame); - - // Get what is hopefully the only selected nodegraph layer - match selected_nodegraph_layers.next() { - // Continue only if there are no additional nodegraph layers also selected - Some(layer_path) if selected_nodegraph_layers.next().is_none() => layer_path.to_owned(), - _ => return None, - } - }; - + pub fn call_node_graph_frame( + &mut self, + document_id: u64, + layer_path: Vec, + _preferences: &PreferencesMessageHandler, + persistent_data: &PersistentData, + imaginate_node: Option>, + ) -> Option { // Prepare the node graph input image let Some(node_network) = self.document_legacy.layer(&layer_path).ok().and_then(|layer|layer.as_node_graph().ok()) else { @@ -1034,7 +1043,7 @@ impl DocumentMessageHandler { }; // Skip processing under node graph frame input if not connected - if !node_network.connected_to_output(node_network.inputs[0]) { + if !node_network.connected_to_output(node_network.inputs[0], false) { return Some( PortfolioMessage::ProcessNodeGraphFrame { document_id, 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 d371dee9..226ed020 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 @@ -455,7 +455,7 @@ impl MessageHandler { @@ -513,8 +513,10 @@ impl MessageHandler { @@ -613,7 +615,7 @@ impl MessageHandler Vec { +pub fn input_properties(_document_node: &DocumentNode, _node_id: NodeId, context: &mut NodePropertiesContext) -> Vec { let information = WidgetHolder::text_widget("The graph's input is the artwork under the frame layer"); + let layer_path = context.layer_path.to_vec(); let refresh_button = TextButton::new("Refresh Input") .tooltip("Refresh the artwork under the frame") - .on_update(|_| DocumentMessage::NodeGraphFrameGenerate.into()) + .on_update(move |_| DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }.into()) .widget_holder(); vec![LayoutGroup::Row { widgets: vec![information] }, LayoutGroup::Row { widgets: vec![refresh_button] }] } @@ -804,8 +805,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte .tooltip("Generate with a new random seed") .on_update({ let imaginate_node = imaginate_node.clone(); + let layer_path = context.layer_path.to_vec(); move |_| { DocumentMessage::NodeGraphFrameImaginateRandom { + layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), then_generate: true, } @@ -818,8 +821,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte .tooltip("Fill layer frame by generating a new image") .on_update({ let imaginate_node = imaginate_node.clone(); + let layer_path = context.layer_path.to_vec(); move |_| { DocumentMessage::NodeGraphFrameImaginate { + layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), } .into() @@ -830,7 +835,17 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte TextButton::new("Clear") .tooltip("Remove generated image from the layer frame") .disabled(cached_data.is_none()) - .on_update(update_value(|_| TaggedValue::RcImage(None), node_id, cached_index)) + .on_update({ + let layer_path = context.layer_path.to_vec(); + move |_| { + DocumentMessage::NodeGraphFrameClear { + node_id, + layer_path: layer_path.clone(), + cached_index, + } + .into() + } + }) .widget_holder(), ]), } @@ -852,8 +867,10 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte .tooltip("Set a new random seed") .on_update({ let imaginate_node = imaginate_node.clone(); + let layer_path = context.layer_path.to_vec(); move |_| { DocumentMessage::NodeGraphFrameImaginateRandom { + layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), then_generate: false, } @@ -881,7 +898,8 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte transform, }); // Compute the transform input to the node graph frame - let transform: glam::DAffine2 = context.executor.compute_input(context.network, &imaginate_node, 1, image_frame).unwrap_or_default(); + let image_frame: graphene_core::raster::ImageFrame = context.executor.compute_input(context.network, &imaginate_node, 0, image_frame).unwrap_or_default(); + let transform = image_frame.transform; let resolution = { use document_legacy::document::pick_safe_imaginate_resolution; diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 107c5c85..c0970650 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -149,8 +149,14 @@ impl NodeGraphExecutor { }; let use_base_image = self.compute_input::(&network, &imaginate_node, get("Adapt Input Image"), Cow::Borrowed(&image_frame))?; - let base_image = if use_base_image { - let image: Image = self.compute_input(&network, &imaginate_node, get("Input Image"), Cow::Borrowed(&image_frame))?; + let input_image_frame: Option = if use_base_image { + Some(self.compute_input::(&network, &imaginate_node, get("Input Image"), Cow::Borrowed(&image_frame))?) + } else { + None + }; + + let image_transform = input_image_frame.as_ref().map(|image_frame| image_frame.transform); + let base_image = if let Some(ImageFrame { image, .. }) = input_image_frame { // Only use if has size if image.width > 0 && image.height > 0 { let (image_data, size) = Self::encode_img(image, Some(resolution), image::ImageOutputFormat::Png)?; @@ -164,7 +170,7 @@ impl NodeGraphExecutor { None }; - let mask_image = if base_image.is_some() { + let mask_image = if let Some(transform) = image_transform { let mask_path: Option> = self.compute_input(&network, &imaginate_node, get("Masking Layer"), Cow::Borrowed(&image_frame))?; // Calculate the size of the node graph frame diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 1e0f0136..2a22c6f0 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -533,7 +533,7 @@ impl NodeNetwork { } /// Check if the specified node id is connected to the output - pub fn connected_to_output(&self, target_node_id: NodeId) -> bool { + pub fn connected_to_output(&self, target_node_id: NodeId, ignore_imaginate: bool) -> bool { // If the node is the output then return true if self.outputs.iter().any(|&NodeOutput { node_id, .. }| node_id == target_node_id) { return true; @@ -546,6 +546,11 @@ impl NodeNetwork { already_visited.extend(self.outputs.iter().map(|output| output.node_id)); while let Some(node) = stack.pop() { + // Skip the imaginate node inputs + if ignore_imaginate && node.name == "Imaginate" { + continue; + } + for input in &node.inputs { if let &NodeInput::Node { node_id: ref_id, .. } = input { // Skip if already viewed