diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index a26206d6..be733c74 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -31,7 +31,7 @@ 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; -use graph_craft::document::{NodeId, NodeInput}; +use graph_craft::document::{NodeId, NodeInput, NodeNetwork}; use graphene_core::raster::ImageFrame; use graphene_core::text::Font; @@ -579,8 +579,7 @@ impl MessageHandler ModifyInputsContext<'a> { }); } - fn transform_set(&mut self, transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, bounds: LayerBounds, skip_rerender: bool) { + fn transform_set(&mut self, mut transform: DAffine2, transform_in: TransformIn, parent_transform: DAffine2, current_transform: Option, bounds: LayerBounds, skip_rerender: bool) { self.modify_inputs("Transform", skip_rerender, |inputs| { + let current_transform_node = transform_utils::get_current_transform(inputs); + let to = match transform_in { TransformIn::Local => DAffine2::IDENTITY, TransformIn::Scope { scope } => scope * parent_transform, TransformIn::Viewport => parent_transform, }; let pivot = DAffine2::from_translation(bounds.layerspace_pivot(transform_utils::get_current_normalized_pivot(inputs))); + + if let Some(current_transform) = current_transform.filter(|transform| transform.inverse().is_finite() && current_transform_node.inverse().is_finite()) { + // this_transform * upstream_transforms = current_transform + // So this_transform.inverse() * current_transform = upstream_transforms + let upstream_transform = (pivot * current_transform_node * pivot.inverse()).inverse() * current_transform; + // desired_final_transform = this_transform * upstream_transform + // So this_transform = desired_final_transform * upstream_transform.inverse() + transform = transform * upstream_transform.inverse(); + } + let transform = pivot.inverse() * to.inverse() * transform * pivot; transform_utils::update_transform(inputs, transform); }); @@ -262,9 +274,10 @@ impl MessageHandler { let parent_transform = document.multiply_transforms(&layer[..layer.len() - 1]).unwrap_or_default(); + let current_transform = document.layer(&layer).ok().map(|layer| layer.transform); let bounds = LayerBounds::new(document, &layer); if let Some(mut modify_inputs) = ModifyInputsContext::new(&layer, document, node_graph, responses) { - modify_inputs.transform_set(transform, transform_in, parent_transform, bounds, skip_rerender); + modify_inputs.transform_set(transform, transform_in, parent_transform, current_transform, bounds, skip_rerender); } let transform = transform.to_cols_array(); responses.add(match transform_in { diff --git a/node-graph/gcore/src/raster/image.rs b/node-graph/gcore/src/raster/image.rs index a0fcbc9b..80a3ba6a 100644 --- a/node-graph/gcore/src/raster/image.rs +++ b/node-graph/gcore/src/raster/image.rs @@ -243,6 +243,13 @@ where impl ImageFrame

{ pub const fn empty() -> Self { + Self { + image: Image::empty(), + transform: DAffine2::ZERO, + } + } + + pub const fn identity() -> Self { Self { image: Image::empty(), transform: DAffine2::IDENTITY, @@ -307,7 +314,7 @@ pub struct ExtractImageFrame; impl<'a: 'input, 'input> Node<'input, EditorApi<'a>> for ExtractImageFrame { type Output = ImageFrame; fn eval(&'input self, mut editor_api: EditorApi<'a>) -> Self::Output { - editor_api.image_frame.take().unwrap_or(ImageFrame::empty()) + editor_api.image_frame.take().unwrap_or(ImageFrame::identity()) } } diff --git a/node-graph/graph-craft/src/document.rs b/node-graph/graph-craft/src/document.rs index 4dcba194..62a8b349 100644 --- a/node-graph/graph-craft/src/document.rs +++ b/node-graph/graph-craft/src/document.rs @@ -330,8 +330,10 @@ impl NodeNetwork { pub fn push_node(&mut self, mut node: DocumentNode, connect_to_previous: bool) -> NodeId { let id = self.nodes.len().try_into().expect("Too many nodes in network"); // Set the correct position for the new node - if let Some(pos) = self.original_outputs().first().and_then(|first| self.nodes.get(&first.node_id)).map(|n| n.metadata.position) { - node.metadata.position = pos + IVec2::new(8, 0); + if node.metadata.position == IVec2::default() { + if let Some(pos) = self.original_outputs().first().and_then(|first| self.nodes.get(&first.node_id)).map(|n| n.metadata.position) { + node.metadata.position = pos + IVec2::new(8, 0); + } } if connect_to_previous && !self.outputs.is_empty() { let input = NodeInput::node(self.outputs[0].node_id, self.outputs[0].node_output_index);