diff --git a/document-legacy/src/document.rs b/document-legacy/src/document.rs index a180df1e..bd04d441 100644 --- a/document-legacy/src/document.rs +++ b/document-legacy/src/document.rs @@ -2,7 +2,7 @@ use crate::boolean_ops::composite_boolean_operation; use crate::intersection::Quad; use crate::layers::folder_layer::FolderLayer; use crate::layers::layer_info::{Layer, LayerData, LayerDataType, LayerDataTypeDiscriminant}; -use crate::layers::nodegraph_layer::{CachedOutputData, NodeGraphFrameLayer}; +use crate::layers::layer_layer::{CachedOutputData, LayerLayer}; use crate::layers::shape_layer::ShapeLayer; use crate::layers::style::RenderData; use crate::{DocumentError, DocumentResponse, Operation}; @@ -514,13 +514,13 @@ impl Document { Some([vec![DocumentChanged, CreatedLayer { path: path.clone() }], update_thumbnails_upstream(&path)].concat()) } - Operation::AddNodeGraphFrame { + Operation::AddFrame { path, insert_index, transform, network, } => { - let layer = Layer::new(LayerDataType::NodeGraphFrame(NodeGraphFrameLayer { network, ..Default::default() }), transform); + let layer = Layer::new(LayerDataType::Layer(LayerLayer { network, ..Default::default() }), transform); self.set_layer(&path, layer, insert_index)?; @@ -694,11 +694,11 @@ impl Document { Operation::SetLayerBlobUrl { layer_path, blob_url, resolution: _ } => { let layer = self.layer_mut(&layer_path).unwrap_or_else(|_| panic!("Blob URL for invalid layer with path '{:?}'", layer_path)); - let LayerDataType::NodeGraphFrame(node_graph_frame) = &mut layer.data else { - panic!("Incorrectly trying to set the image blob URL for a layer that is not a NodeGraphFrame layer type"); + let LayerDataType::Layer(layer) = &mut layer.data else { + panic!("Incorrectly trying to set the image blob URL for a layer that is not a 'Layer' layer type"); }; - node_graph_frame.cached_output_data = CachedOutputData::BlobURL(blob_url); + layer.cached_output_data = CachedOutputData::BlobURL(blob_url); self.mark_as_dirty(&layer_path)?; Some([vec![DocumentChanged, LayerChanged { path: layer_path.clone() }], update_thumbnails_upstream(&layer_path)].concat()) @@ -706,9 +706,9 @@ impl Document { Operation::ClearBlobURL { path } => { let layer = self.layer_mut(&path).expect("Clearing node graph image for invalid layer"); match &mut layer.data { - LayerDataType::NodeGraphFrame(node_graph) => { - if matches!(node_graph.cached_output_data, CachedOutputData::BlobURL(_)) { - node_graph.cached_output_data = CachedOutputData::None; + LayerDataType::Layer(layer) => { + if matches!(layer.cached_output_data, CachedOutputData::BlobURL(_)) { + layer.cached_output_data = CachedOutputData::None; } } e => panic!("Incorrectly trying to clear the blob URL for layer of type {}", LayerDataTypeDiscriminant::from(&*e)), @@ -737,8 +737,8 @@ impl Document { Some(vec![DocumentChanged, LayerChanged { path }]) } Operation::SetVectorData { path, vector_data } => { - if let LayerDataType::NodeGraphFrame(graph) = &mut self.layer_mut(&path)?.data { - graph.cached_output_data = CachedOutputData::VectorPath(Box::new(vector_data)); + if let LayerDataType::Layer(layer) = &mut self.layer_mut(&path)?.data { + layer.cached_output_data = CachedOutputData::VectorPath(Box::new(vector_data)); } Some(Vec::new()) } diff --git a/document-legacy/src/layers/layer_info.rs b/document-legacy/src/layers/layer_info.rs index d4d0de59..10ee572f 100644 --- a/document-legacy/src/layers/layer_info.rs +++ b/document-legacy/src/layers/layer_info.rs @@ -1,6 +1,6 @@ use super::blend_mode::BlendMode; use super::folder_layer::FolderLayer; -use super::nodegraph_layer::NodeGraphFrameLayer; +use super::layer_layer::LayerLayer; use super::shape_layer::ShapeLayer; use super::style::{PathStyle, RenderData}; use crate::intersection::Quad; @@ -22,24 +22,24 @@ pub enum LayerDataType { Folder(FolderLayer), /// A layer that wraps a [ShapeLayer] struct. Shape(ShapeLayer), - /// A layer that wraps an [NodeGraphFrameLayer] struct. - NodeGraphFrame(NodeGraphFrameLayer), + /// A layer that wraps an [LayerLayer] struct. + Layer(LayerLayer), } impl LayerDataType { pub fn inner(&self) -> &dyn LayerData { match self { - LayerDataType::Shape(s) => s, - LayerDataType::Folder(f) => f, - LayerDataType::NodeGraphFrame(n) => n, + LayerDataType::Shape(shape) => shape, + LayerDataType::Folder(folder) => folder, + LayerDataType::Layer(layer) => layer, } } pub fn inner_mut(&mut self) -> &mut dyn LayerData { match self { - LayerDataType::Shape(s) => s, - LayerDataType::Folder(f) => f, - LayerDataType::NodeGraphFrame(n) => n, + LayerDataType::Shape(shape) => shape, + LayerDataType::Folder(folder) => folder, + LayerDataType::Layer(layer) => layer, } } } @@ -48,8 +48,7 @@ impl LayerDataType { pub enum LayerDataTypeDiscriminant { Folder, Shape, - Text, - NodeGraphFrame, + Layer, } impl fmt::Display for LayerDataTypeDiscriminant { @@ -57,8 +56,7 @@ impl fmt::Display for LayerDataTypeDiscriminant { match self { LayerDataTypeDiscriminant::Folder => write!(f, "Folder"), LayerDataTypeDiscriminant::Shape => write!(f, "Shape"), - LayerDataTypeDiscriminant::Text => write!(f, "Text"), - LayerDataTypeDiscriminant::NodeGraphFrame => write!(f, "Layer"), + LayerDataTypeDiscriminant::Layer => write!(f, "Layer"), } } } @@ -70,7 +68,7 @@ impl From<&LayerDataType> for LayerDataTypeDiscriminant { match data { Folder(_) => LayerDataTypeDiscriminant::Folder, Shape(_) => LayerDataTypeDiscriminant::Shape, - NodeGraphFrame(_) => LayerDataTypeDiscriminant::NodeGraphFrame, + Layer(_) => LayerDataTypeDiscriminant::Layer, } } } @@ -83,8 +81,6 @@ impl<'a> TryFrom<&'a mut Layer> for &'a mut Subpath { fn try_from(layer: &'a mut Layer) -> Result<&'a mut Subpath, Self::Error> { match &mut layer.data { LayerDataType::Shape(layer) => Ok(&mut layer.shape), - // TODO Resolve converting text into a Subpath at the layer level - // LayerDataType::Text(text) => Some(Subpath::new(path_to_shape.to_vec(), viewport_transform, true)), _ => Err("Did not find any shape data in the layer"), } } @@ -96,8 +92,6 @@ impl<'a> TryFrom<&'a Layer> for &'a Subpath { fn try_from(layer: &'a Layer) -> Result<&'a Subpath, Self::Error> { match &layer.data { LayerDataType::Shape(layer) => Ok(&layer.shape), - // TODO Resolve converting text into a Subpath at the layer level - // LayerDataType::Text(text) => Some(Subpath::new(path_to_shape.to_vec(), viewport_transform, true)), _ => Err("Did not find any shape data in the layer"), } } @@ -432,7 +426,7 @@ impl Layer { pub fn as_vector_data(&self) -> Option<&VectorData> { match &self.data { - LayerDataType::NodeGraphFrame(frame) => frame.as_vector_data(), + LayerDataType::Layer(layer) => layer.as_vector_data(), _ => None, } } @@ -454,34 +448,34 @@ impl Layer { } /// Get a mutable reference to the NodeNetwork - /// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::NodeGraphFrame`. + /// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Layer`. pub fn as_node_graph_mut(&mut self) -> Result<&mut graph_craft::document::NodeNetwork, DocumentError> { match &mut self.data { - LayerDataType::NodeGraphFrame(frame) => Ok(&mut frame.network), + LayerDataType::Layer(layer) => Ok(&mut layer.network), _ => Err(DocumentError::NotNodeGraph), } } /// Get a reference to the NodeNetwork - /// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::NodeGraphFrame`. + /// This operation will fail if the [Layer type](Layer::data) is not `LayerDataType::Layer`. pub fn as_node_graph(&self) -> Result<&graph_craft::document::NodeNetwork, DocumentError> { match &self.data { - LayerDataType::NodeGraphFrame(frame) => Ok(&frame.network), + LayerDataType::Layer(layer) => Ok(&layer.network), _ => Err(DocumentError::NotNodeGraph), } } - pub fn as_graph_frame(&self) -> Result<&NodeGraphFrameLayer, DocumentError> { + pub fn as_graph_frame(&self) -> Result<&LayerLayer, DocumentError> { match &self.data { - LayerDataType::NodeGraphFrame(frame) => Ok(frame), + LayerDataType::Layer(layer) => Ok(layer), _ => Err(DocumentError::NotNodeGraph), } } pub fn style(&self) -> Result<&PathStyle, DocumentError> { match &self.data { - LayerDataType::Shape(s) => Ok(&s.style), - LayerDataType::NodeGraphFrame(t) => t.as_vector_data().map(|vector| &vector.style).ok_or(DocumentError::NotShape), + LayerDataType::Shape(shape) => Ok(&shape.style), + LayerDataType::Layer(layer) => layer.as_vector_data().map(|vector| &vector.style).ok_or(DocumentError::NotShape), _ => Err(DocumentError::NotShape), } } diff --git a/document-legacy/src/layers/nodegraph_layer.rs b/document-legacy/src/layers/layer_layer.rs similarity index 97% rename from document-legacy/src/layers/nodegraph_layer.rs rename to document-legacy/src/layers/layer_layer.rs index 643bc5c7..68e89546 100644 --- a/document-legacy/src/layers/nodegraph_layer.rs +++ b/document-legacy/src/layers/layer_layer.rs @@ -18,7 +18,7 @@ pub enum CachedOutputData { } #[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)] -pub struct NodeGraphFrameLayer { +pub struct LayerLayer { /// The document node network that this layer contains pub network: graph_craft::document::NodeNetwork, @@ -26,7 +26,7 @@ pub struct NodeGraphFrameLayer { pub cached_output_data: CachedOutputData, } -impl LayerData for NodeGraphFrameLayer { +impl LayerData for LayerLayer { fn render(&mut self, svg: &mut String, svg_defs: &mut String, transforms: &mut Vec, render_data: &RenderData) -> bool { let transform = self.transform(transforms, render_data.view_mode); let inverse = transform.inverse(); @@ -121,7 +121,7 @@ impl LayerData for NodeGraphFrameLayer { } } -impl NodeGraphFrameLayer { +impl LayerLayer { pub fn transform(&self, transforms: &[DAffine2], mode: ViewMode) -> DAffine2 { let start = match mode { ViewMode::Outline => 0, diff --git a/document-legacy/src/layers/mod.rs b/document-legacy/src/layers/mod.rs index e403f0ac..d08ee447 100644 --- a/document-legacy/src/layers/mod.rs +++ b/document-legacy/src/layers/mod.rs @@ -4,7 +4,7 @@ //! There are currently these different types of layers: //! * [Folder layers](folder_layer::FolderLayer), which encapsulate sub-layers //! * [Shape layers](shape_layer::ShapeLayer), which contain generic SVG [``](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path)s -//! * [Node Graph layers](nodegraph_layer::NodegraphLayer), which contain a node graph frame +//! * [Layer layers](layer_layer::NodegraphLayer), which contain a node graph layer //! //! Refer to the module-level documentation for detailed information on each layer. //! @@ -21,7 +21,7 @@ pub mod folder_layer; /// Contains the base [Layer](layer_info::Layer) type, an abstraction over the different types of layers. pub mod layer_info; /// Contains the [NodegraphLayer](nodegraph_layer::NodegraphLayer) type that contains a node graph. -pub mod nodegraph_layer; +pub mod layer_layer; // TODO: Remove shape layers after rewriting the overlay system /// Contains the [ShapeLayer](shape_layer::ShapeLayer) type, a generic SVG element defined using Bezier paths. pub mod shape_layer; diff --git a/document-legacy/src/operation.rs b/document-legacy/src/operation.rs index 7b81dd36..169f55c7 100644 --- a/document-legacy/src/operation.rs +++ b/document-legacy/src/operation.rs @@ -36,7 +36,7 @@ pub enum Operation { transform: [f64; 6], style: style::PathStyle, }, - AddNodeGraphFrame { + AddFrame { path: Vec, insert_index: isize, transform: [f64; 6], diff --git a/editor/src/dispatcher.rs b/editor/src/dispatcher.rs index 981a951d..3d7b6539 100644 --- a/editor/src/dispatcher.rs +++ b/editor/src/dispatcher.rs @@ -41,7 +41,7 @@ const SIDE_EFFECT_FREE_MESSAGES: &[MessageDiscriminant] = &[ MessageDiscriminant::Frontend(FrontendMessageDiscriminant::UpdateDocumentLayerTreeStructure), MessageDiscriminant::Frontend(FrontendMessageDiscriminant::TriggerFontLoad), MessageDiscriminant::Broadcast(BroadcastMessageDiscriminant::TriggerEvent(BroadcastEventDiscriminant::DocumentIsDirty)), - MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::NodeGraphFrameGenerate)), + MessageDiscriminant::Portfolio(PortfolioMessageDiscriminant::Document(DocumentMessageDiscriminant::InputFrameRasterizeRegionBelowLayer)), ]; impl Dispatcher { diff --git a/editor/src/messages/frontend/frontend_message.rs b/editor/src/messages/frontend/frontend_message.rs index fa0cf739..e4a5ae2a 100644 --- a/editor/src/messages/frontend/frontend_message.rs +++ b/editor/src/messages/frontend/frontend_message.rs @@ -105,16 +105,6 @@ pub enum FrontendMessage { }, TriggerLoadAutoSaveDocuments, TriggerLoadPreferences, - TriggerNodeGraphFrameGenerate { - #[serde(rename = "documentId")] - document_id: u64, - #[serde(rename = "layerPath")] - layer_path: Vec, - svg: String, - size: glam::DVec2, - #[serde(rename = "imaginateNode")] - imaginate_node: Option>, - }, TriggerOpenDocument, TriggerPaste, TriggerRasterDownload { @@ -123,6 +113,16 @@ pub enum FrontendMessage { mime: String, size: (f64, f64), }, + TriggerRasterizeRegionBelowLayer { + #[serde(rename = "documentId")] + document_id: u64, + #[serde(rename = "layerPath")] + layer_path: Vec, + svg: String, + size: glam::DVec2, + #[serde(rename = "imaginateNodePath")] + imaginate_node_path: Option>, + }, TriggerRefreshBoundsOfViewports, TriggerRevokeBlobUrl { url: String, diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index afb1ce99..d3cfccdf 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -145,12 +145,12 @@ pub fn default_mapping() -> Mapping { entry!(KeyDown(Escape); action_dispatch=ImaginateToolMessage::Abort), entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=ImaginateToolMessage::Resize { center: Alt, lock_ratio: Shift }), // - // NodeGraphFrameToolMessage - entry!(KeyDown(Lmb); action_dispatch=NodeGraphFrameToolMessage::DragStart), - entry!(KeyUp(Lmb); action_dispatch=NodeGraphFrameToolMessage::DragStop), - entry!(KeyDown(Rmb); action_dispatch=NodeGraphFrameToolMessage::Abort), - entry!(KeyDown(Escape); action_dispatch=NodeGraphFrameToolMessage::Abort), - entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=NodeGraphFrameToolMessage::Resize { center: Alt, lock_ratio: Shift }), + // FrameToolMessage + entry!(KeyDown(Lmb); action_dispatch=FrameToolMessage::DragStart), + entry!(KeyUp(Lmb); action_dispatch=FrameToolMessage::DragStop), + entry!(KeyDown(Rmb); action_dispatch=FrameToolMessage::Abort), + entry!(KeyDown(Escape); action_dispatch=FrameToolMessage::Abort), + entry!(PointerMove; refresh_keys=[Alt, Shift], action_dispatch=FrameToolMessage::Resize { center: Alt, lock_ratio: Shift }), // // EllipseToolMessage entry!(KeyDown(Lmb); action_dispatch=EllipseToolMessage::DragStart), diff --git a/editor/src/messages/portfolio/document/document_message.rs b/editor/src/messages/portfolio/document/document_message.rs index e202c7bc..498316d7 100644 --- a/editor/src/messages/portfolio/document/document_message.rs +++ b/editor/src/messages/portfolio/document/document_message.rs @@ -87,6 +87,27 @@ pub enum DocumentMessage { }, FrameClear, GroupSelectedLayers, + ImaginateClear { + layer_path: Vec, + node_id: NodeId, + cached_index: usize, + }, + ImaginateGenerate { + layer_path: Vec, + imaginate_node: Vec, + }, + ImaginateRandom { + layer_path: Vec, + imaginate_node: Vec, + then_generate: bool, + }, + ImaginateTerminate { + layer_path: Vec, + node_path: Vec, + }, + InputFrameRasterizeRegionBelowLayer { + layer_path: Vec, + }, LayerChanged { affected_layer_path: Vec, }, @@ -95,27 +116,6 @@ pub enum DocumentMessage { insert_index: isize, reverse_index: bool, }, - 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, - }, - NodeGraphFrameImaginateTerminate { - layer_path: Vec, - node_path: Vec, - }, NudgeSelectedLayers { delta_x: f64, delta_y: f64, diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 90570b7c..8245bf19 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -28,7 +28,7 @@ use document_legacy::document::Document as DocumentLegacy; use document_legacy::layers::blend_mode::BlendMode; use document_legacy::layers::folder_layer::FolderLayer; use document_legacy::layers::layer_info::{LayerDataType, LayerDataTypeDiscriminant}; -use document_legacy::layers::nodegraph_layer::CachedOutputData; +use document_legacy::layers::layer_layer::CachedOutputData; use document_legacy::layers::style::{RenderData, ViewMode}; use document_legacy::{DocumentError, DocumentResponse, LayerId, Operation as DocumentOperation}; use graph_craft::document::value::TaggedValue; @@ -394,18 +394,18 @@ impl MessageHandler { - let mut selected_frame_layers = self.selected_layers_with_type(LayerDataTypeDiscriminant::NodeGraphFrame); - // Get what is hopefully the only selected NodeGraphFrame layer + let mut selected_frame_layers = self.selected_layers_with_type(LayerDataTypeDiscriminant::Layer); + // Get what is hopefully the only selected Layer layer let layer_path = selected_frame_layers.next(); - // Abort if we didn't have any NodeGraphFrame layer, or if there are additional ones also selected + // Abort if we didn't have any Layer layer, or if there are additional ones also selected if layer_path.is_none() || selected_frame_layers.next().is_some() { return; } let layer_path = layer_path.unwrap(); - let layer = self.document_legacy.layer(layer_path).expect("Clearing NodeGraphFrame image for invalid layer"); + let layer = self.document_legacy.layer(layer_path).expect("Clearing Layer image for invalid layer"); let previous_blob_url = match &layer.data { - LayerDataType::NodeGraphFrame(node_graph_frame) => node_graph_frame.as_blob_url(), + LayerDataType::Layer(layer) => layer.as_blob_url(), x => panic!("Cannot find blob url for layer type {}", LayerDataTypeDiscriminant::from(x)), }; @@ -437,6 +437,51 @@ impl MessageHandler { + let value = graph_craft::document::value::TaggedValue::RcImage(None); + responses.add(NodeGraphMessage::SetInputValue { node_id, input_index, value }); + responses.add(InputFrameRasterizeRegionBelowLayer { layer_path }); + } + ImaginateGenerate { layer_path, imaginate_node } => { + if let Some(message) = self.rasterize_region_below_layer(document_id, layer_path, preferences, persistent_data, Some(imaginate_node)) { + responses.add(message); + } + } + ImaginateRandom { + layer_path, + imaginate_node, + then_generate, + } => { + // Set a random seed input + responses.add(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: 1, + value: graph_craft::document::value::TaggedValue::F64((generate_uuid() >> 1) as f64), + }); + + // Generate the image + if then_generate { + responses.add(DocumentMessage::ImaginateGenerate { layer_path, imaginate_node }); + } + } + ImaginateTerminate { layer_path, node_path } => { + responses.add(FrontendMessage::TriggerImaginateTerminate { + document_id, + layer_path, + node_path, + hostname: preferences.imaginate_server_hostname.clone(), + }); + } + InputFrameRasterizeRegionBelowLayer { layer_path } => { + if let Some(message) = self.rasterize_region_below_layer(document_id, layer_path, preferences, persistent_data, None) { + responses.add(message); + } + } LayerChanged { affected_layer_path } => { if let Ok(layer_entry) = self.layer_panel_entry(affected_layer_path.clone(), &render_data) { responses.add(FrontendMessage::UpdateDocumentLayerDetails { data: layer_entry }); @@ -466,51 +511,6 @@ impl MessageHandler { - let value = graph_craft::document::value::TaggedValue::RcImage(None); - responses.add(NodeGraphMessage::SetInputValue { node_id, input_index, value }); - responses.add(NodeGraphFrameGenerate { layer_path }); - } - NodeGraphFrameGenerate { layer_path } => { - if let Some(message) = self.call_node_graph_frame(document_id, layer_path, preferences, persistent_data, None) { - responses.add(message); - } - } - 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.add(message); - } - } - NodeGraphFrameImaginateRandom { - layer_path, - imaginate_node, - then_generate, - } => { - // Set a random seed input - responses.add(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: 1, - value: graph_craft::document::value::TaggedValue::F64((generate_uuid() >> 1) as f64), - }); - - // Generate the image - if then_generate { - responses.add(DocumentMessage::NodeGraphFrameImaginate { layer_path, imaginate_node }); - } - } - NodeGraphFrameImaginateTerminate { layer_path, node_path } => { - responses.add(FrontendMessage::TriggerImaginateTerminate { - document_id, - layer_path, - node_path, - hostname: preferences.imaginate_server_hostname.clone(), - }); - } NudgeSelectedLayers { delta_x, delta_y, @@ -622,7 +622,7 @@ impl MessageHandler { - if let Some(url) = node_graph_frame.as_blob_url() { + LayerDataType::Layer(layer) => { + if let Some(url) = layer.as_blob_url() { responses.add(FrontendMessage::TriggerRevokeBlobUrl { url: url.clone() }); } } other => { - warn!( - "Setting blob URL for invalid layer type, which must be an `Imaginate`, `NodeGraphFrame` or `Image`. Found: `{:?}`", - other - ); + warn!("Setting blob URL for invalid layer type, which must be a `Layer` layer type. Found: `{:?}`", other); return; } } @@ -961,53 +958,54 @@ impl MessageHandler, _preferences: &PreferencesMessageHandler, persistent_data: &PersistentData, - imaginate_node: Option>, + imaginate_node_path: 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 { + let Some(node_network) = self.document_legacy.layer(&layer_path).ok().and_then(|layer| layer.as_node_graph().ok()) else { return None; }; // Check if we use the "Input Frame" node. // TODO: Remove once rasterization is moved into a node. - let input_frame = node_network.nodes.iter().find(|(_, node)| node.name == "Input Frame"); - let input_node_id = input_frame.map(|(&id, _)| id); - let primary_input_type = input_node_id.filter(|&target_node_id| node_network.connected_to_output(target_node_id, true)); + let input_frame_node_id = node_network.nodes.iter().find(|(_, node)| node.name == "Input Frame").map(|(&id, _)| id); + let input_frame_connected_to_graph_output = input_frame_node_id.map_or(false, |target_node_id| node_network.connected_to_output(target_node_id, true)); - // Only calculate the frame if the primary input is an image - let response = if primary_input_type.is_some() { - // Calculate the size of the region to be exported + // If the Input Frame node is connected upstream, rasterize the artwork below this layer by calling into JS + let response = if input_frame_connected_to_graph_output { let old_transforms = self.remove_document_transform(); + + // Calculate the size of the region to be exported and generate an SVG of the artwork below this layer within that region let transform = self.document_legacy.multiply_transforms(&layer_path).unwrap(); let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length()); - let svg = self.render_document(size, transform.inverse(), persistent_data, DocumentRenderMode::OnlyBelowLayerInFolder(&layer_path)); + self.restore_document_transform(old_transforms); - FrontendMessage::TriggerNodeGraphFrameGenerate { + // Once JS asynchronously rasterizes the SVG, it will call the `PortfolioMessage::RenderGraphUsingRasterizedRegionBelowLayer` message with the rasterized image data + FrontendMessage::TriggerRasterizeRegionBelowLayer { document_id, layer_path, svg, size, - imaginate_node, + imaginate_node_path, } .into() } - // Skip processing under node graph frame input if not connected + // Skip taking a round trip through JS since there's nothing to rasterize, and instead directly call the message which would otherwise be called asynchronously from JS else { - PortfolioMessage::ProcessNodeGraphFrame { + PortfolioMessage::RenderGraphUsingRasterizedRegionBelowLayer { document_id, layer_path, - image_data: Default::default(), + input_image_data: vec![], size: (0, 0), - imaginate_node, + imaginate_node_path, } .into() }; @@ -1170,16 +1168,6 @@ impl DocumentMessageHandler { }) } - pub fn selected_visible_text_layers(&self) -> impl Iterator { - self.selected_layers().filter(|path| match self.document_legacy.layer(path) { - Ok(layer) => { - let discriminant: LayerDataTypeDiscriminant = (&layer.data).into(); - layer.visible && discriminant == LayerDataTypeDiscriminant::Text - } - Err(_) => false, - }) - } - pub fn visible_layers(&self) -> impl Iterator { self.all_layers().filter(|path| match self.document_legacy.layer(path) { Ok(layer) => layer.visible, @@ -1543,11 +1531,11 @@ impl DocumentMessageHandler { path.pop(); } } - LayerDataType::NodeGraphFrame(node_graph_frame) => { - if node_graph_frame.cached_output_data == CachedOutputData::None { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: path.clone() }); + LayerDataType::Layer(layer) => { + if layer.cached_output_data == CachedOutputData::None { + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: path.clone() }); } - for node in node_graph_frame.network.nodes.values() { + for node in layer.network.nodes.values() { for input in &node.inputs { if let NodeInput::Value { tagged_value: TaggedValue::Font(font), 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 c18ee2ea..ccf7dc62 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 @@ -76,7 +76,7 @@ impl<'a> ModifyInputsContext<'a> { let layer_path = self.layer.to_vec(); if !skip_rerender { - self.responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path }); + self.responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path }); } else { self.responses.add(DocumentMessage::FrameClear); } 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 e136e3c8..db348d6e 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 @@ -5,7 +5,7 @@ use crate::messages::layout::utility_types::widgets::button_widgets::TextButton; use crate::messages::prelude::*; use document_legacy::document::Document; -use document_legacy::layers::nodegraph_layer::NodeGraphFrameLayer; +use document_legacy::layers::layer_layer::LayerLayer; use document_legacy::LayerId; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeId, NodeInput, NodeNetwork, NodeOutput}; @@ -223,8 +223,8 @@ impl NodeGraphMessageHandler { } /// Collate the properties panel sections for a node graph - pub fn collate_properties(&self, node_graph_frame: &NodeGraphFrameLayer, context: &mut NodePropertiesContext, sections: &mut Vec) { - let mut network = &node_graph_frame.network; + pub fn collate_properties(&self, graph: &LayerLayer, context: &mut NodePropertiesContext, sections: &mut Vec) { + let mut network = &graph.network; for segment in &self.nested_path { network = network.nodes.get(segment).and_then(|node| node.implementation.get_network()).unwrap(); } @@ -493,7 +493,7 @@ impl MessageHandler = Lazy::new(|| DocumentNodeTyp identifier: NodeImplementation::proto("graphene_std::raster::ImaginateNode<_>"), inputs: vec![ DocumentInputType::value("Input Image", TaggedValue::ImageFrame(ImageFrame::empty()), true), - DocumentInputType::value("Seed", TaggedValue::F64(0.), false), // Remember to keep index used in `NodeGraphFrameImaginateRandom` updated with this entry's index + DocumentInputType::value("Seed", TaggedValue::F64(0.), false), // Remember to keep index used in `ImaginateRandom` updated with this entry's index DocumentInputType::value("Resolution", TaggedValue::OptionalDVec2(None), false), DocumentInputType::value("Samples", TaggedValue::F64(30.), false), DocumentInputType::value("Sampling Method", TaggedValue::ImaginateSamplingMethod(ImaginateSamplingMethod::EulerA), false), diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs index 2546bdc1..0114ce7e 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/node_properties.rs @@ -8,7 +8,7 @@ use glam::DVec2; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, NodeId, NodeInput}; use graph_craft::imaginate_input::*; -use graphene_core::raster::{BlendMode, Color, LuminanceCalculation, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice}; +use graphene_core::raster::{BlendMode, Color, ImageFrame, LuminanceCalculation, RedGreenBlue, RelativeAbsolute, SelectiveColorChoice}; use graphene_core::text::Font; use graphene_core::vector::style::{FillType, GradientType, LineCap, LineJoin}; use graphene_core::EditorApi; @@ -460,7 +460,7 @@ pub fn input_properties(_document_node: &DocumentNode, _node_id: NodeId, context let layer_path = context.layer_path.to_vec(); let refresh_button = TextButton::new("Refresh Input") .tooltip("Refresh the artwork under the layer") - .on_update(move |_| DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }.into()) + .on_update(move |_| DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.clone() }.into()) .widget_holder(); vec![LayoutGroup::Row { widgets: vec![information] }, LayoutGroup::Row { widgets: vec![refresh_button] }] } @@ -1035,7 +1035,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte .on_update({ let imaginate_node = imaginate_node.clone(); move |_| { - DocumentMessage::NodeGraphFrameImaginateTerminate { + DocumentMessage::ImaginateTerminate { layer_path: layer_path.clone(), node_path: imaginate_node.clone(), } @@ -1061,7 +1061,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let imaginate_node = imaginate_node.clone(); let layer_path = context.layer_path.to_vec(); move |_| { - DocumentMessage::NodeGraphFrameImaginateRandom { + DocumentMessage::ImaginateRandom { layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), then_generate: true, @@ -1077,7 +1077,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let imaginate_node = imaginate_node.clone(); let layer_path = context.layer_path.to_vec(); move |_| { - DocumentMessage::NodeGraphFrameImaginate { + DocumentMessage::ImaginateGenerate { layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), } @@ -1092,7 +1092,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte .on_update({ let layer_path = context.layer_path.to_vec(); move |_| { - DocumentMessage::NodeGraphFrameClear { + DocumentMessage::ImaginateClear { node_id, layer_path: layer_path.clone(), cached_index, @@ -1123,7 +1123,7 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte let imaginate_node = imaginate_node.clone(); let layer_path = context.layer_path.to_vec(); move |_| { - DocumentMessage::NodeGraphFrameImaginateRandom { + DocumentMessage::ImaginateRandom { layer_path: layer_path.clone(), imaginate_node: imaginate_node.clone(), then_generate: false, @@ -1145,12 +1145,12 @@ pub fn imaginate_properties(document_node: &DocumentNode, node_id: NodeId, conte }; // Create the input to the graph using an empty image - let image_frame = std::borrow::Cow::Owned(EditorApi { + let editor_api = std::borrow::Cow::Owned(EditorApi { image_frame: None, font_cache: Some(&context.persistent_data.font_cache), }); - // Compute the transform input to the node graph frame - let image_frame: graphene_core::raster::ImageFrame = context.executor.compute_input(context.network, &imaginate_node, 0, image_frame).unwrap_or_default(); + // Compute the transform input to the image frame + let image_frame: ImageFrame = context.executor.compute_input(context.network, &imaginate_node, 0, editor_api).unwrap_or_default(); let transform = image_frame.transform; let resolution = { diff --git a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs index babfad39..e9d52068 100644 --- a/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs +++ b/editor/src/messages/portfolio/document/properties_panel/properties_panel_message_handler.rs @@ -45,11 +45,11 @@ impl<'a> MessageHandler WidgetHolder::new(Widget::IconLabel(IconLabel { + LayerDataType::Layer(_) => WidgetHolder::new(Widget::IconLabel(IconLabel { icon: "Layer".into(), tooltip: "Layer".into(), ..Default::default() @@ -266,7 +266,7 @@ pub fn register_artwork_layer_properties( WidgetHolder::unrelated_separator(), WidgetHolder::new(Widget::TextLabel(TextLabel { value: match &layer.data { - LayerDataType::NodeGraphFrame(_) => "Layer".into(), + LayerDataType::Layer(_) => "Layer".into(), other => LayerDataTypeDiscriminant::from(other).to_string(), }, ..TextLabel::default() @@ -298,7 +298,7 @@ pub fn register_artwork_layer_properties( vec![node_section_transform(layer, persistent_data), node_section_stroke(&shape.style.stroke().unwrap_or_default())] } } - LayerDataType::NodeGraphFrame(node_graph_frame) => { + LayerDataType::Layer(layer) => { let mut properties_sections = Vec::new(); let mut context = crate::messages::portfolio::document::node_graph::NodePropertiesContext { @@ -308,9 +308,9 @@ pub fn register_artwork_layer_properties( nested_path: &node_graph_message_handler.nested_path, layer_path: &layer_path, executor, - network: &node_graph_frame.network, + network: &layer.network, }; - node_graph_message_handler.collate_properties(node_graph_frame, &mut context, &mut properties_sections); + node_graph_message_handler.collate_properties(layer, &mut context, &mut properties_sections); properties_sections } diff --git a/editor/src/messages/portfolio/portfolio_message.rs b/editor/src/messages/portfolio/portfolio_message.rs index e4de83e5..a6235bf8 100644 --- a/editor/src/messages/portfolio/portfolio_message.rs +++ b/editor/src/messages/portfolio/portfolio_message.rs @@ -112,12 +112,12 @@ pub enum PortfolioMessage { data: String, }, PrevDocument, - ProcessNodeGraphFrame { + RenderGraphUsingRasterizedRegionBelowLayer { document_id: u64, layer_path: Vec, - image_data: Vec, + input_image_data: Vec, size: (u32, u32), - imaginate_node: Option>, + imaginate_node_path: Option>, }, SelectDocument { document_id: u64, diff --git a/editor/src/messages/portfolio/portfolio_message_handler.rs b/editor/src/messages/portfolio/portfolio_message_handler.rs index b6db8274..0a41d44c 100644 --- a/editor/src/messages/portfolio/portfolio_message_handler.rs +++ b/editor/src/messages/portfolio/portfolio_message_handler.rs @@ -445,18 +445,18 @@ impl MessageHandler { let result = self.executor.evaluate_node_graph( (document_id, &mut self.documents), layer_path, - (image_data, size), - imaginate_node, + (input_image_data, size), + imaginate_node_path, (preferences, &self.persistent_data), responses, ); @@ -664,16 +664,16 @@ impl PortfolioMessageHandler { x.push(*id); x }))), - LayerDataType::NodeGraphFrame(graph_frame) => { + LayerDataType::Layer(layer) => { let input_is_font = |input: &NodeInput| { let NodeInput::Value { tagged_value: TaggedValue::Font(font), .. } = input else { return false; }; font == target_font }; - let should_rerender = graph_frame.network.nodes.values().any(|node| node.inputs.iter().any(input_is_font)); + let should_rerender = layer.network.nodes.values().any(|node| node.inputs.iter().any(input_is_font)); if should_rerender { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path }); } } _ => {} diff --git a/editor/src/messages/prelude.rs b/editor/src/messages/prelude.rs index bef32ca3..dca6d742 100644 --- a/editor/src/messages/prelude.rs +++ b/editor/src/messages/prelude.rs @@ -36,7 +36,7 @@ pub use crate::messages::tool::tool_messages::brush_tool::{BrushToolMessage, Bru pub use crate::messages::tool::tool_messages::ellipse_tool::{EllipseToolMessage, EllipseToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::eyedropper_tool::{EyedropperToolMessage, EyedropperToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::fill_tool::{FillToolMessage, FillToolMessageDiscriminant}; -pub use crate::messages::tool::tool_messages::frame_tool::{NodeGraphFrameToolMessage, NodeGraphFrameToolMessageDiscriminant}; +pub use crate::messages::tool::tool_messages::frame_tool::{FrameToolMessage, FrameToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::freehand_tool::{FreehandToolMessage, FreehandToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::gradient_tool::{GradientToolMessage, GradientToolMessageDiscriminant}; pub use crate::messages::tool::tool_messages::imaginate_tool::{ImaginateToolMessage, ImaginateToolMessageDiscriminant}; diff --git a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs index a16fe69d..841bf6fa 100644 --- a/editor/src/messages/tool/common_functionality/graph_modification_utils.rs +++ b/editor/src/messages/tool/common_functionality/graph_modification_utils.rs @@ -18,13 +18,13 @@ pub fn new_vector_layer(subpaths: Vec>, layer_path: pub fn new_custom_layer(network: NodeNetwork, layer_path: Vec, responses: &mut VecDeque) { responses.add(DocumentMessage::DeselectAllLayers); - responses.add(Operation::AddNodeGraphFrame { + responses.add(Operation::AddFrame { path: layer_path.clone(), insert_index: -1, transform: DAffine2::ZERO.to_cols_array(), network, }); - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path }); } pub fn set_manipulator_mirror_angle(manipulator_groups: &Vec>, layer_path: &Vec, mirror_angle: bool, responses: &mut VecDeque) { diff --git a/editor/src/messages/tool/common_functionality/path_outline.rs b/editor/src/messages/tool/common_functionality/path_outline.rs index 00ac6b0a..ad1fade2 100644 --- a/editor/src/messages/tool/common_functionality/path_outline.rs +++ b/editor/src/messages/tool/common_functionality/path_outline.rs @@ -33,8 +33,8 @@ impl PathOutline { // TODO Purge this area of BezPath and Kurbo // Get the bezpath from the shape or text let subpath = match &document_layer.data { - LayerDataType::Shape(layer_shape) => Some(layer_shape.shape.clone()), - LayerDataType::NodeGraphFrame(frame) => frame.as_vector_data().map(|vector_data| Subpath::from_bezier_crate(&vector_data.subpaths)), + LayerDataType::Shape(shape) => Some(shape.shape.clone()), + LayerDataType::Layer(layer) => layer.as_vector_data().map(|vector_data| Subpath::from_bezier_crate(&vector_data.subpaths)), _ => document_layer.aabb_for_transform(DAffine2::IDENTITY, render_data).map(|[p1, p2]| Subpath::new_rect(p1, p2)), }?; diff --git a/editor/src/messages/tool/tool_message.rs b/editor/src/messages/tool/tool_message.rs index 1f811f9c..8e3e7f98 100644 --- a/editor/src/messages/tool/tool_message.rs +++ b/editor/src/messages/tool/tool_message.rs @@ -84,7 +84,7 @@ pub enum ToolMessage { Imaginate(ImaginateToolMessage), #[remain::unsorted] #[child] - NodeGraphFrame(NodeGraphFrameToolMessage), + Frame(FrameToolMessage), // Messages #[remain::unsorted] @@ -124,7 +124,7 @@ pub enum ToolMessage { #[remain::unsorted] ActivateToolImaginate, #[remain::unsorted] - ActivateToolNodeGraphFrame, + ActivateToolFrame, ActivateTool { tool_type: ToolType, diff --git a/editor/src/messages/tool/tool_messages/frame_tool.rs b/editor/src/messages/tool/tool_messages/frame_tool.rs index 37adf4e7..ae3de04e 100644 --- a/editor/src/messages/tool/tool_messages/frame_tool.rs +++ b/editor/src/messages/tool/tool_messages/frame_tool.rs @@ -13,15 +13,15 @@ use glam::DAffine2; use serde::{Deserialize, Serialize}; #[derive(Default)] -pub struct NodeGraphFrameTool { +pub struct FrameTool { fsm_state: NodeGraphToolFsmState, tool_data: NodeGraphToolData, } #[remain::sorted] -#[impl_message(Message, ToolMessage, NodeGraphFrame)] +#[impl_message(Message, ToolMessage, Frame)] #[derive(PartialEq, Eq, Clone, Debug, Hash, Serialize, Deserialize, specta::Type)] -pub enum NodeGraphFrameToolMessage { +pub enum FrameToolMessage { // Standard messages #[remain::unsorted] Abort, @@ -35,9 +35,9 @@ pub enum NodeGraphFrameToolMessage { }, } -impl PropertyHolder for NodeGraphFrameTool {} +impl PropertyHolder for FrameTool {} -impl<'a> MessageHandler> for NodeGraphFrameTool { +impl<'a> MessageHandler> for FrameTool { fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { self.fsm_state.process_event(message, &mut self.tool_data, tool_data, &(), responses, true); } @@ -46,10 +46,10 @@ impl<'a> MessageHandler> for NodeGra use NodeGraphToolFsmState::*; match self.fsm_state { - Ready => actions!(NodeGraphFrameToolMessageDiscriminant; + Ready => actions!(FrameToolMessageDiscriminant; DragStart, ), - Drawing => actions!(NodeGraphFrameToolMessageDiscriminant; + Drawing => actions!(FrameToolMessageDiscriminant; DragStop, Abort, Resize, @@ -58,7 +58,7 @@ impl<'a> MessageHandler> for NodeGra } } -impl ToolMetadata for NodeGraphFrameTool { +impl ToolMetadata for FrameTool { fn icon_name(&self) -> String { "RasterFrameTool".into() } @@ -66,15 +66,15 @@ impl ToolMetadata for NodeGraphFrameTool { "Frame Tool".into() } fn tool_type(&self) -> crate::messages::tool::utility_types::ToolType { - ToolType::NodeGraphFrame + ToolType::Frame } } -impl ToolTransition for NodeGraphFrameTool { +impl ToolTransition for FrameTool { fn event_to_message_map(&self) -> EventToMessageMap { EventToMessageMap { document_dirty: None, - tool_abort: Some(NodeGraphFrameToolMessage::Abort.into()), + tool_abort: Some(FrameToolMessage::Abort.into()), selection_changed: None, } } @@ -104,12 +104,12 @@ impl Fsm for NodeGraphToolFsmState { _tool_options: &Self::ToolOptions, responses: &mut VecDeque, ) -> Self { - use NodeGraphFrameToolMessage::*; + use FrameToolMessage::*; use NodeGraphToolFsmState::*; let mut shape_data = &mut tool_data.data; - if let ToolMessage::NodeGraphFrame(event) = event { + if let ToolMessage::Frame(event) = event { match (self, event) { (Ready, DragStart) => { shape_data.start(responses, document, input, render_data); @@ -119,7 +119,7 @@ impl Fsm for NodeGraphToolFsmState { let network = node_graph::new_image_network(8, 0); - responses.add(Operation::AddNodeGraphFrame { + responses.add(Operation::AddFrame { path: shape_data.path.clone().unwrap(), insert_index: -1, transform: DAffine2::ZERO.to_cols_array(), @@ -136,7 +136,7 @@ impl Fsm for NodeGraphToolFsmState { } (Drawing, DragStop) => { if let Some(layer_path) = &shape_data.path { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.to_vec() }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.to_vec() }); } input.mouse.finish_transaction(shape_data.viewport_drag_start(document), responses); diff --git a/editor/src/messages/tool/tool_messages/imaginate_tool.rs b/editor/src/messages/tool/tool_messages/imaginate_tool.rs index 3a98fd50..4f68e7fb 100644 --- a/editor/src/messages/tool/tool_messages/imaginate_tool.rs +++ b/editor/src/messages/tool/tool_messages/imaginate_tool.rs @@ -148,8 +148,8 @@ impl Fsm for ImaginateToolFsmState { imaginate_node_type.to_document_node_default_inputs([Some(graph_craft::document::NodeInput::node(transform_node_id, 0))], next_pos()), ); - // Add the node graph frame layer to the document - responses.add(Operation::AddNodeGraphFrame { + // Add a layer with a frame to the document + responses.add(Operation::AddFrame { path: shape_data.path.clone().unwrap(), insert_index: -1, transform: DAffine2::ZERO.to_cols_array(), @@ -167,7 +167,7 @@ impl Fsm for ImaginateToolFsmState { } (Drawing, DragStop) => { if let Some(layer_path) = &shape_data.path { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.to_vec() }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.to_vec() }); } input.mouse.finish_transaction(shape_data.viewport_drag_start(document), responses); diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index 29d7de23..3963e22f 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -377,7 +377,7 @@ impl SelectToolData { // Since the selected layers have now moved back to their original transforms before the drag began, we rerender them to be displayed as if they weren't touched. for layer_path in self.not_duplicated_layers.iter().flatten() { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.clone() }); } } @@ -974,7 +974,7 @@ impl Fsm for SelectToolFsmState { fn rerender_selected_layers(tool_data: &mut SelectToolData, responses: &mut VecDeque) { for layer_path in &tool_data.layers_dragging { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.clone() }); } } @@ -1206,8 +1206,8 @@ fn edit_layer_deepest_manipulation(intersect: &Layer, responses: &mut VecDeque { responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Path }); } - LayerDataType::NodeGraphFrame(graph_frame) if graph_frame.as_vector_data().is_some() => { - if graph_frame.network.nodes.values().any(|node| node.name == "Text") { + LayerDataType::Layer(layer) if layer.as_vector_data().is_some() => { + if layer.network.nodes.values().any(|node| node.name == "Text") { responses.add_front(ToolMessage::ActivateTool { tool_type: ToolType::Text }); responses.add(TextToolMessage::EditSelected); } else { diff --git a/editor/src/messages/tool/tool_messages/text_tool.rs b/editor/src/messages/tool/tool_messages/text_tool.rs index 3eea602e..df2dbb43 100644 --- a/editor/src/messages/tool/tool_messages/text_tool.rs +++ b/editor/src/messages/tool/tool_messages/text_tool.rs @@ -282,7 +282,7 @@ impl TextToolData { let network = new_text_network(String::new(), editing_text.font.clone(), editing_text.font_size as f64); - responses.add(Operation::AddNodeGraphFrame { + responses.add(Operation::AddFrame { path: self.layer_path.clone(), insert_index: -1, transform: DAffine2::ZERO.to_cols_array(), diff --git a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs index 15c00012..19dd9fdd 100644 --- a/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs +++ b/editor/src/messages/tool/transform_layer/transform_layer_message_handler.rs @@ -107,7 +107,7 @@ impl<'a> MessageHandler> for TransformL responses.add(ToolMessage::UpdateHints); responses.add(BroadcastEvent::DocumentIsDirty); for layer_path in document.selected_layers() { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.to_vec() }); + responses.add(DocumentMessage::InputFrameRasterizeRegionBelowLayer { layer_path: layer_path.to_vec() }); } } BeginGrab => { diff --git a/editor/src/messages/tool/utility_types.rs b/editor/src/messages/tool/utility_types.rs index 60fdd3d4..22e897c3 100644 --- a/editor/src/messages/tool/utility_types.rs +++ b/editor/src/messages/tool/utility_types.rs @@ -365,7 +365,7 @@ pub enum ToolType { Detail, Relight, Imaginate, - NodeGraphFrame, + Frame, } enum ToolAvailability { @@ -399,7 +399,7 @@ fn list_tools_in_groups() -> Vec> { ], vec![ // Raster tool group - ToolAvailability::Available(Box::::default()), + ToolAvailability::Available(Box::::default()), ToolAvailability::Available(Box::::default()), ToolAvailability::Available(Box::::default()), ToolAvailability::ComingSoon(ToolEntry { @@ -465,7 +465,7 @@ pub fn tool_message_to_tool_type(tool_message: &ToolMessage) -> ToolType { // ToolMessage::Detail(_) => ToolType::Detail, // ToolMessage::Relight(_) => ToolType::Relight, ToolMessage::Imaginate(_) => ToolType::Imaginate, - ToolMessage::NodeGraphFrame(_) => ToolType::NodeGraphFrame, + ToolMessage::Frame(_) => ToolType::Frame, _ => panic!( "Conversion from ToolMessage to ToolType impossible because the given ToolMessage does not have a matching ToolType. Got: {:?}", tool_message @@ -502,7 +502,7 @@ pub fn tool_type_to_activate_tool_message(tool_type: ToolType) -> ToolMessageDis // ToolType::Detail => ToolMessageDiscriminant::ActivateToolDetail, // ToolType::Relight => ToolMessageDiscriminant::ActivateToolRelight, ToolType::Imaginate => ToolMessageDiscriminant::ActivateToolImaginate, - ToolType::NodeGraphFrame => ToolMessageDiscriminant::ActivateToolNodeGraphFrame, + ToolType::Frame => ToolMessageDiscriminant::ActivateToolFrame, _ => panic!( "Conversion from ToolType to ToolMessage impossible because the given ToolType does not have a matching ToolMessage. Got: {:?}", tool_type diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index bc8ce1f9..b7f57426 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -120,7 +120,7 @@ impl NodeGraphExecutor { fn generate_imaginate( &mut self, network: NodeNetwork, - imaginate_node: Vec, + imaginate_node_path: Vec, (document, document_id): (&mut DocumentMessageHandler, u64), layer_path: Vec, editor_api: EditorApi<'_>, @@ -135,31 +135,31 @@ impl NodeGraphExecutor { let layer = document.document_legacy.layer(&layer_path).map_err(|e| format!("No layer: {e:?}"))?; let transform = layer.transform; - let resolution: Option = self.compute_input(&network, &imaginate_node, get("Resolution"), Cow::Borrowed(&editor_api))?; + let resolution: Option = self.compute_input(&network, &imaginate_node_path, get("Resolution"), Cow::Borrowed(&editor_api))?; let resolution = resolution.unwrap_or_else(|| { let (x, y) = pick_safe_imaginate_resolution((transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length())); DVec2::new(x as f64, y as f64) }); let parameters = ImaginateGenerationParameters { - seed: self.compute_input::(&network, &imaginate_node, get("Seed"), Cow::Borrowed(&editor_api))? as u64, + seed: self.compute_input::(&network, &imaginate_node_path, get("Seed"), Cow::Borrowed(&editor_api))? as u64, resolution: resolution.as_uvec2().into(), - samples: self.compute_input::(&network, &imaginate_node, get("Samples"), Cow::Borrowed(&editor_api))? as u32, + samples: self.compute_input::(&network, &imaginate_node_path, get("Samples"), Cow::Borrowed(&editor_api))? as u32, sampling_method: self - .compute_input::(&network, &imaginate_node, get("Sampling Method"), Cow::Borrowed(&editor_api))? + .compute_input::(&network, &imaginate_node_path, get("Sampling Method"), Cow::Borrowed(&editor_api))? .api_value() .to_string(), - text_guidance: self.compute_input(&network, &imaginate_node, get("Prompt Guidance"), Cow::Borrowed(&editor_api))?, - text_prompt: self.compute_input(&network, &imaginate_node, get("Prompt"), Cow::Borrowed(&editor_api))?, - negative_prompt: self.compute_input(&network, &imaginate_node, get("Negative Prompt"), Cow::Borrowed(&editor_api))?, - image_creativity: Some(self.compute_input::(&network, &imaginate_node, get("Image Creativity"), Cow::Borrowed(&editor_api))? / 100.), - restore_faces: self.compute_input(&network, &imaginate_node, get("Improve Faces"), Cow::Borrowed(&editor_api))?, - tiling: self.compute_input(&network, &imaginate_node, get("Tiling"), Cow::Borrowed(&editor_api))?, + text_guidance: self.compute_input(&network, &imaginate_node_path, get("Prompt Guidance"), Cow::Borrowed(&editor_api))?, + text_prompt: self.compute_input(&network, &imaginate_node_path, get("Prompt"), Cow::Borrowed(&editor_api))?, + negative_prompt: self.compute_input(&network, &imaginate_node_path, get("Negative Prompt"), Cow::Borrowed(&editor_api))?, + image_creativity: Some(self.compute_input::(&network, &imaginate_node_path, get("Image Creativity"), Cow::Borrowed(&editor_api))? / 100.), + restore_faces: self.compute_input(&network, &imaginate_node_path, get("Improve Faces"), Cow::Borrowed(&editor_api))?, + tiling: self.compute_input(&network, &imaginate_node_path, get("Tiling"), Cow::Borrowed(&editor_api))?, }; - let use_base_image = self.compute_input::(&network, &imaginate_node, get("Adapt Input Image"), Cow::Borrowed(&editor_api))?; + let use_base_image = self.compute_input::(&network, &imaginate_node_path, get("Adapt Input Image"), Cow::Borrowed(&editor_api))?; let input_image_frame: Option> = if use_base_image { - Some(self.compute_input::>(&network, &imaginate_node, get("Input Image"), Cow::Borrowed(&editor_api))?) + Some(self.compute_input::>(&network, &imaginate_node_path, get("Input Image"), Cow::Borrowed(&editor_api))?) } else { None }; @@ -180,12 +180,12 @@ impl NodeGraphExecutor { }; let mask_image = if let Some(transform) = image_transform { - let mask_path: Option> = self.compute_input(&network, &imaginate_node, get("Masking Layer"), Cow::Borrowed(&editor_api))?; + let mask_path: Option> = self.compute_input(&network, &imaginate_node_path, get("Masking Layer"), Cow::Borrowed(&editor_api))?; - // Calculate the size of the node graph frame + // Calculate the size of the frame let size = DVec2::new(transform.transform_vector2(DVec2::new(1., 0.)).length(), transform.transform_vector2(DVec2::new(0., 1.)).length()); - // Render the masking layer within the node graph frame + // Render the masking layer within the frame let old_transforms = document.remove_document_transform(); let mask_is_some = mask_path.is_some(); let mask_image = mask_path.filter(|mask_layer_path| document.document_legacy.layer(mask_layer_path).is_ok()).map(|mask_layer_path| { @@ -212,34 +212,34 @@ impl NodeGraphExecutor { parameters: Box::new(parameters), base_image: base_image.map(Box::new), mask_image: mask_image.map(Box::new), - mask_paint_mode: if self.compute_input::(&network, &imaginate_node, get("Inpaint"), Cow::Borrowed(&editor_api))? { + mask_paint_mode: if self.compute_input::(&network, &imaginate_node_path, get("Inpaint"), Cow::Borrowed(&editor_api))? { ImaginateMaskPaintMode::Inpaint } else { ImaginateMaskPaintMode::Outpaint }, - mask_blur_px: self.compute_input::(&network, &imaginate_node, get("Mask Blur"), Cow::Borrowed(&editor_api))? as u32, - imaginate_mask_starting_fill: self.compute_input(&network, &imaginate_node, get("Mask Starting Fill"), Cow::Borrowed(&editor_api))?, + mask_blur_px: self.compute_input::(&network, &imaginate_node_path, get("Mask Blur"), Cow::Borrowed(&editor_api))? as u32, + imaginate_mask_starting_fill: self.compute_input(&network, &imaginate_node_path, get("Mask Starting Fill"), Cow::Borrowed(&editor_api))?, hostname: preferences.imaginate_server_hostname.clone(), refresh_frequency: preferences.imaginate_refresh_frequency, document_id, layer_path, - node_path: imaginate_node, + node_path: imaginate_node_path, } .into()) } - /// Evaluates a node graph, computing either the imaginate node or the entire graph + /// Evaluates a node graph, computing either the Imaginate node or the entire graph pub fn evaluate_node_graph( &mut self, (document_id, documents): (u64, &mut HashMap), layer_path: Vec, - (image_data, (width, height)): (Vec, (u32, u32)), + (input_image_data, (width, height)): (Vec, (u32, u32)), imaginate_node: Option>, persistent_data: (&PreferencesMessageHandler, &PersistentData), responses: &mut VecDeque, ) -> Result<(), String> { - // Reformat the input image data into an f32 image - let image = graphene_core::raster::Image::from_image_data(&image_data, width, height); + // Reformat the input image data into an RGBA f32 image + let image = graphene_core::raster::Image::from_image_data(&input_image_data, width, height); // Get the node graph layer let document = documents.get_mut(&document_id).ok_or_else(|| "Invalid document".to_string())?; @@ -253,11 +253,11 @@ impl NodeGraphExecutor { font_cache: Some(&persistent_data.1.font_cache), }; - let node_graph_frame = match &layer.data { - LayerDataType::NodeGraphFrame(frame) => Ok(frame), + let layer_layer = match &layer.data { + LayerDataType::Layer(layer) => Ok(layer), _ => Err("Invalid layer type".to_string()), }?; - let network = node_graph_frame.network.clone(); + let network = layer_layer.network.clone(); // Special execution path for generating Imaginate (as generation requires IO from outside node graph) if let Some(imaginate_node) = imaginate_node { diff --git a/frontend/src/components/panels/LayerTree.svelte b/frontend/src/components/panels/LayerTree.svelte index b8e0a646..319a4eb1 100644 --- a/frontend/src/components/panels/LayerTree.svelte +++ b/frontend/src/components/panels/LayerTree.svelte @@ -353,16 +353,15 @@ on:dragstart={(e) => draggable && dragStart(e, listing)} on:click={(e) => selectLayerWithModifiers(e, listing)} > - {@const layerType = layerTypeData(listing.entry.layerType)} - + onEditLayerName(listing)}> onEditLayerNameDeselect(listing)} on:keydown={(e) => e.key === "Escape" && onEditLayerNameDeselect(listing)} diff --git a/frontend/src/components/widgets/inputs/DropdownInput.svelte b/frontend/src/components/widgets/inputs/DropdownInput.svelte index 755484a2..6d9418d3 100644 --- a/frontend/src/components/widgets/inputs/DropdownInput.svelte +++ b/frontend/src/components/widgets/inputs/DropdownInput.svelte @@ -129,15 +129,7 @@ &:hover, &.open { - background: var(--color-6-lowergray); - - span { - color: var(--color-f-white); - } - - svg { - fill: var(--color-f-white); - } + background: var(--color-5-dullgray); } &.disabled { diff --git a/frontend/src/components/widgets/inputs/LayerReferenceInput.svelte b/frontend/src/components/widgets/inputs/LayerReferenceInput.svelte index 5a0a6bde..f571e004 100644 --- a/frontend/src/components/widgets/inputs/LayerReferenceInput.svelte +++ b/frontend/src/components/widgets/inputs/LayerReferenceInput.svelte @@ -58,8 +58,8 @@ {droppable ? "Drop" : "Drag"} Layer Here {:else} {#if layerName !== undefined && layerType} - - {layerName || `Untitled ${layerTypeData(layerType).name}`} + + {layerName || `Untitled ${layerType || "[Unknown Layer Type]"}`} {:else} Layer Missing {/if} diff --git a/frontend/src/state-providers/portfolio.ts b/frontend/src/state-providers/portfolio.ts index 5cefd0d4..9948aa97 100644 --- a/frontend/src/state-providers/portfolio.ts +++ b/frontend/src/state-providers/portfolio.ts @@ -15,7 +15,7 @@ import { TriggerImaginateGenerate, TriggerImaginateTerminate, TriggerImaginateCheckServerStatus, - TriggerNodeGraphFrameGenerate, + TriggerRasterizeRegionBelowLayer, UpdateActiveDocument, UpdateOpenDocumentsList, UpdateImageData, @@ -116,21 +116,23 @@ export function createPortfolioState(editor: Editor) { editor.instance.setImageBlobURL(updateImageData.documentId, element.path, blobURL, image.naturalWidth, image.naturalHeight, element.transform); }); }); - editor.subscriptions.subscribeJsMessage(TriggerNodeGraphFrameGenerate, async (triggerNodeGraphFrameGenerate) => { - const { documentId, layerPath, svg, size, imaginateNode } = triggerNodeGraphFrameGenerate; + editor.subscriptions.subscribeJsMessage(TriggerRasterizeRegionBelowLayer, async (triggerRasterizeRegionBelowLayer) => { + const { documentId, layerPath, svg, size, imaginateNodePath } = triggerRasterizeRegionBelowLayer; // Rasterize the SVG to an image file - let imageData; try { - // getImageData may throw an exception if the resolution is too high if (size[0] >= 1 && size[1] >= 1) { - imageData = (await rasterizeSVGCanvas(svg, size[0], size[1])).getContext("2d")?.getImageData(0, 0, size[0], size[1]); + const imageData = (await rasterizeSVGCanvas(svg, size[0], size[1])).getContext("2d")?.getImageData(0, 0, size[0], size[1]); + if (!imageData) return; + + editor.instance.renderGraphUsingRasterizedRegionBelowLayer(documentId, layerPath, new Uint8Array(imageData.data), imageData.width, imageData.height, imaginateNodePath); } - } catch (e) { + } + // getImageData may throw an exception if the resolution is too high + catch (e) { console.error("Failed to rasterize the SVG canvas in JS to be sent back to Rust:", e); } - if (imageData) editor.instance.processNodeGraphFrame(documentId, layerPath, new Uint8Array(imageData.data), imageData.width, imageData.height, imaginateNode); }); editor.subscriptions.subscribeJsMessage(TriggerRevokeBlobUrl, async (triggerRevokeBlobUrl) => { URL.revokeObjectURL(triggerRevokeBlobUrl.url); diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 32bfc49c..b2ec7b9b 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -604,7 +604,7 @@ export class TriggerImaginateTerminate extends JsMessage { readonly hostname!: string; } -export class TriggerNodeGraphFrameGenerate extends JsMessage { +export class TriggerRasterizeRegionBelowLayer extends JsMessage { readonly documentId!: bigint; readonly layerPath!: BigUint64Array; @@ -613,7 +613,7 @@ export class TriggerNodeGraphFrameGenerate extends JsMessage { readonly size!: [number, number]; - readonly imaginateNode!: BigUint64Array | undefined; + readonly imaginateNodePath!: BigUint64Array | undefined; } export class TriggerRefreshBoundsOfViewports extends JsMessage { } @@ -751,23 +751,13 @@ export class LayerMetadata { selected!: boolean; } -export type LayerType = "Folder" | "NodeGraphFrame"; +export type LayerType = "Folder" | "Layer"; export type LayerTypeData = { name: string; icon: IconName; }; -// TODO: Delete this function after renaming NodeGraphFrame to Layer, since it will basically just return its input parameter -export function layerTypeData(layerType: LayerType): LayerTypeData { - const entries: Record = { - NodeGraphFrame: { name: "Layer", icon: "Layer" }, - Folder: { name: "Folder", icon: "Folder" }, - }; - - return entries[layerType] || { name: "Error", icon: "Info" }; -} - export class ImaginateImageData { readonly path!: BigUint64Array; @@ -1397,7 +1387,7 @@ export const messageMakers: Record = { TriggerImaginateCheckServerStatus, TriggerImaginateGenerate, TriggerImaginateTerminate, - TriggerNodeGraphFrameGenerate, + TriggerRasterizeRegionBelowLayer, TriggerFileDownload, TriggerFontLoad, TriggerImport, diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 2c1a27b9..3101243a 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -580,14 +580,22 @@ impl JsEditorHandle { } /// Sends the blob URL generated by JS to the Imaginate layer in the respective document - #[wasm_bindgen(js_name = processNodeGraphFrame)] - pub fn process_node_graph_frame(&self, document_id: u64, layer_path: Vec, image_data: Vec, width: u32, height: u32, imaginate_node: Option>) { - let message = PortfolioMessage::ProcessNodeGraphFrame { + #[wasm_bindgen(js_name = renderGraphUsingRasterizedRegionBelowLayer)] + pub fn render_graph_using_rasterized_region_below_layer( + &self, + document_id: u64, + layer_path: Vec, + input_image_data: Vec, + width: u32, + height: u32, + imaginate_node_path: Option>, + ) { + let message = PortfolioMessage::RenderGraphUsingRasterizedRegionBelowLayer { document_id, layer_path, - image_data, + input_image_data, size: (width, height), - imaginate_node, + imaginate_node_path, }; self.dispatch(message); }