From ed6140b4a7dd0d3aa44a5f3c92f5296e4f4c8c82 Mon Sep 17 00:00:00 2001 From: 0HyperCube <78500760+0HyperCube@users.noreply.github.com> Date: Wed, 12 Apr 2023 18:50:42 +0100 Subject: [PATCH] Brush tool live preview (#1116) * Disable vector preview for brush tool * Fix brush preview * Fix warping * Left and right square brackets to change size * Add linear interpolation * Modfiy existing selected brush layer * Resolve warnings --------- Co-authored-by: Dennis Kobert Co-authored-by: Keavon Chambers --- editor/src/consts.rs | 3 + editor/src/messages/frontend/utility_types.rs | 3 +- .../messages/input_mapper/default_mapping.rs | 5 +- .../document/document_message_handler.rs | 1 + .../messages/tool/tool_messages/brush_tool.rs | 93 ++++++++++++++----- .../tool/tool_messages/freehand_tool.rs | 6 +- .../tool/tool_messages/select_tool.rs | 6 -- .../tool/tool_messages/spline_tool.rs | 2 +- editor/src/node_graph_executor.rs | 17 ++-- frontend/src-tauri/src/main.rs | 2 + .../src/components/panels/LayerTree.svelte | 1 + frontend/src/state-providers/portfolio.ts | 2 +- frontend/src/wasm-communication/editor.ts | 6 +- frontend/src/wasm-communication/messages.ts | 2 + frontend/wasm/src/editor_api.rs | 24 ++++- node-graph/gcore/src/value.rs | 2 +- node-graph/gstd/src/raster.rs | 3 +- .../interpreted-executor/src/executor.rs | 2 +- .../interpreted-executor/src/node_registry.rs | 2 +- node-graph/node-macro/src/lib.rs | 6 +- 20 files changed, 130 insertions(+), 58 deletions(-) diff --git a/editor/src/consts.rs b/editor/src/consts.rs index b8f3bb9f..02f972a3 100644 --- a/editor/src/consts.rs +++ b/editor/src/consts.rs @@ -62,6 +62,9 @@ pub const CREATE_CURVE_THRESHOLD: f64 = 5.; // Line tool pub const LINE_ROTATE_SNAP_ANGLE: f64 = 15.; +// Brush tool +pub const BRUSH_SIZE_CHANGE_KEYBOARD: f64 = 5.; + // Scrollbars pub const SCROLLBAR_SPACING: f64 = 0.1; pub const ASYMPTOTIC_EFFECT: f64 = 0.5; diff --git a/editor/src/messages/frontend/utility_types.rs b/editor/src/messages/frontend/utility_types.rs index 2c2008b9..2b2d04c0 100644 --- a/editor/src/messages/frontend/utility_types.rs +++ b/editor/src/messages/frontend/utility_types.rs @@ -11,12 +11,13 @@ pub struct FrontendDocumentDetails { pub id: u64, } -#[derive(PartialEq, Eq, Clone, Debug, Serialize, Deserialize, specta::Type)] +#[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] pub struct FrontendImageData { pub path: Vec, pub mime: String, #[serde(skip)] pub image_data: std::sync::Arc>, + pub transform: Option<[f64; 6]>, } #[derive(Clone, Copy, Debug, Default, Eq, PartialEq, Serialize, Deserialize, specta::Type)] diff --git a/editor/src/messages/input_mapper/default_mapping.rs b/editor/src/messages/input_mapper/default_mapping.rs index ed317c90..82da9b21 100644 --- a/editor/src/messages/input_mapper/default_mapping.rs +++ b/editor/src/messages/input_mapper/default_mapping.rs @@ -1,4 +1,4 @@ -use crate::consts::{BIG_NUDGE_AMOUNT, NUDGE_AMOUNT}; +use crate::consts::{BIG_NUDGE_AMOUNT, BRUSH_SIZE_CHANGE_KEYBOARD, NUDGE_AMOUNT}; use crate::messages::input_mapper::key_mapping::MappingVariant; use crate::messages::input_mapper::utility_types::input_keyboard::{Key, KeyStates}; use crate::messages::input_mapper::utility_types::macros::*; @@ -6,6 +6,7 @@ use crate::messages::input_mapper::utility_types::misc::MappingEntry; use crate::messages::input_mapper::utility_types::misc::{KeyMappingEntries, Mapping}; use crate::messages::portfolio::document::utility_types::clipboards::Clipboard; use crate::messages::prelude::*; +use crate::messages::tool::tool_messages::brush_tool::BrushToolMessageOptionsUpdate; use glam::DVec2; @@ -209,6 +210,8 @@ pub fn default_mapping() -> Mapping { entry!(PointerMove; action_dispatch=BrushToolMessage::PointerMove), entry!(KeyDown(Lmb); action_dispatch=BrushToolMessage::DragStart), entry!(KeyUp(Lmb); action_dispatch=BrushToolMessage::DragStop), + entry!(KeyDown(BracketLeft); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(-BRUSH_SIZE_CHANGE_KEYBOARD))), + entry!(KeyDown(BracketRight); action_dispatch=BrushToolMessage::UpdateOptions(BrushToolMessageOptionsUpdate::ChangeDiameter(BRUSH_SIZE_CHANGE_KEYBOARD))), // // ToolMessage entry!(KeyDown(KeyV); action_dispatch=ToolMessage::ActivateToolSelect), diff --git a/editor/src/messages/portfolio/document/document_message_handler.rs b/editor/src/messages/portfolio/document/document_message_handler.rs index 38f239cd..80b1f19c 100644 --- a/editor/src/messages/portfolio/document/document_message_handler.rs +++ b/editor/src/messages/portfolio/document/document_message_handler.rs @@ -1628,6 +1628,7 @@ impl DocumentMessageHandler { path: path.clone(), image_data: data.image_data.clone(), mime: node_graph_frame.mime.clone(), + transform: None, }); } } diff --git a/editor/src/messages/tool/tool_messages/brush_tool.rs b/editor/src/messages/tool/tool_messages/brush_tool.rs index 8713394e..d7d7b68a 100644 --- a/editor/src/messages/tool/tool_messages/brush_tool.rs +++ b/editor/src/messages/tool/tool_messages/brush_tool.rs @@ -1,6 +1,7 @@ use crate::messages::frontend::utility_types::MouseCursorIcon; use crate::messages::input_mapper::utility_types::input_keyboard::MouseMotion; use crate::messages::layout::utility_types::layout_widget::{Layout, LayoutGroup, PropertyHolder, WidgetLayout}; +use crate::messages::layout::utility_types::misc::LayoutTarget; use crate::messages::layout::utility_types::widget_prelude::*; use crate::messages::layout::utility_types::widgets::input_widgets::NumberInput; use crate::messages::prelude::*; @@ -9,11 +10,9 @@ use crate::messages::tool::utility_types::{DocumentToolData, EventToMessageMap, use crate::messages::tool::utility_types::{HintData, HintGroup, HintInfo}; use document_legacy::LayerId; -use document_legacy::Operation; use graph_craft::document::value::TaggedValue; use graph_craft::document::{DocumentNode, DocumentNodeImplementation, NodeInput, NodeNetwork}; use graph_craft::{concrete, Type, TypeDescriptor}; -use graphene_core::vector::style::Stroke; use graphene_core::Cow; use glam::DVec2; @@ -60,6 +59,7 @@ pub enum BrushToolMessage { #[remain::sorted] #[derive(PartialEq, Clone, Debug, Serialize, Deserialize, specta::Type)] pub enum BrushToolMessageOptionsUpdate { + ChangeDiameter(f64), Diameter(f64), Flow(f64), Hardness(f64), @@ -119,6 +119,18 @@ impl<'a> MessageHandler> for BrushTo fn process_message(&mut self, message: ToolMessage, responses: &mut VecDeque, tool_data: &mut ToolActionHandlerData<'a>) { if let ToolMessage::Brush(BrushToolMessage::UpdateOptions(action)) = message { match action { + BrushToolMessageOptionsUpdate::ChangeDiameter(change) => { + let needs_rounding = ((self.options.diameter + change.abs() / 2.) % change.abs() - change.abs() / 2.).abs() > 0.5; + if needs_rounding && change > 0. { + self.options.diameter = (self.options.diameter / change.abs()).ceil() * change.abs(); + } else if needs_rounding && change < 0. { + self.options.diameter = (self.options.diameter / change.abs()).floor() * change.abs(); + } else { + self.options.diameter = (self.options.diameter / change.abs()).round() * change.abs() + change; + } + self.options.diameter = self.options.diameter.max(1.); + self.register_properties(responses, LayoutTarget::ToolOptions); + } BrushToolMessageOptionsUpdate::Diameter(diameter) => self.options.diameter = diameter, BrushToolMessageOptionsUpdate::Hardness(hardness) => self.options.hardness = hardness, BrushToolMessageOptionsUpdate::Flow(flow) => self.options.flow = flow, @@ -137,11 +149,13 @@ impl<'a> MessageHandler> for BrushTo DragStart, DragStop, Abort, + UpdateOptions, ), Drawing => actions!(BrushToolMessageDiscriminant; DragStop, PointerMove, Abort, + UpdateOptions, ), } } @@ -166,6 +180,19 @@ struct BrushToolData { path: Option>, } +impl BrushToolData { + fn update_points(&self, responses: &mut VecDeque) { + if let Some(layer_path) = self.path.clone() { + responses.add(NodeGraphMessage::SetQualifiedInputValue { + layer_path, + node_path: vec![0], + input_index: 1, + value: TaggedValue::VecDVec2(self.points.clone()), + }); + } + } +} + impl Fsm for BrushToolFsmState { type ToolData = BrushToolData; type ToolOptions = BrushOptions; @@ -189,8 +216,15 @@ impl Fsm for BrushToolFsmState { match (self, event) { (Ready, DragStart) => { responses.push_back(DocumentMessage::StartTransaction.into()); - responses.push_back(DocumentMessage::DeselectAllLayers.into()); - tool_data.path = Some(document.get_path_for_new_layer()); + let existing_points = load_existing_points(document); + let new_layer = existing_points.is_none(); + if let Some((layer_path, points)) = existing_points { + tool_data.path = Some(layer_path); + tool_data.points = points; + } else { + responses.push_back(DocumentMessage::DeselectAllLayers.into()); + tool_data.path = Some(document.get_path_for_new_layer()); + } let pos = transform.inverse().transform_point2(input.mouse.position); @@ -200,7 +234,11 @@ impl Fsm for BrushToolFsmState { tool_data.hardness = tool_options.hardness; tool_data.flow = tool_options.flow; - add_polyline(tool_data, global_tool_data, responses); + if new_layer { + add_brush_render(tool_data, global_tool_data, responses); + } else { + tool_data.update_points(responses); + } Drawing } @@ -208,17 +246,22 @@ impl Fsm for BrushToolFsmState { let pos = transform.inverse().transform_point2(input.mouse.position); if tool_data.points.last() != Some(&pos) { + // Linear interpolation for when the mouse has moved a lot between frames + if let Some(&last_point) = tool_data.points.last() { + let distance = (last_point - pos).length(); + let extra_points = (distance / (tool_data.diameter / 2.)).floor() as usize; + tool_data.points.extend((0..extra_points).map(|i| last_point.lerp(pos, (i as f64 + 1.) / (extra_points as f64 + 1.)))); + } + tool_data.points.push(pos); } - add_polyline(tool_data, global_tool_data, responses); + tool_data.update_points(responses); Drawing } (Drawing, DragStop) | (Drawing, Abort) => { if !tool_data.points.is_empty() { - responses.push_back(remove_preview(tool_data)); - add_brush_render(tool_data, global_tool_data, responses); responses.push_back(DocumentMessage::CommitTransaction.into()); } else { responses.push_back(DocumentMessage::AbortTransaction.into()); @@ -250,21 +293,6 @@ impl Fsm for BrushToolFsmState { } } -fn remove_preview(data: &BrushToolData) -> Message { - Operation::DeleteLayer { path: data.path.clone().unwrap() }.into() -} - -fn add_polyline(data: &BrushToolData, tool_data: &DocumentToolData, responses: &mut VecDeque) { - let layer_path = data.path.clone().unwrap(); - let subpath = bezier_rs::Subpath::from_anchors(data.points.iter().copied(), false); - graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses); - - responses.add(GraphOperationMessage::StrokeSet { - layer: layer_path, - stroke: Stroke::new(tool_data.primary_color.apply_opacity(data.flow as f32 / 100.), data.diameter), - }); -} - fn add_brush_render(data: &BrushToolData, tool_data: &DocumentToolData, responses: &mut VecDeque) { let layer_path = data.path.clone().unwrap(); let brush_node = DocumentNode { @@ -288,3 +316,22 @@ fn add_brush_render(data: &BrushToolData, tool_data: &DocumentToolData, response network.push_output_node(); graph_modification_utils::new_custom_layer(network, layer_path.clone(), responses); } + +fn load_existing_points(document: &DocumentMessageHandler) -> Option<(Vec, Vec)> { + if document.selected_layers().count() != 1 { + return None; + } + let layer_path = document.selected_layers().next()?.to_vec(); + let network = document.document_legacy.layer(&layer_path).ok().and_then(|layer| layer.as_node_graph().ok())?; + let brush_node = network.nodes.get(&0)?; + if brush_node.implementation != DocumentNodeImplementation::Unresolved("graphene_std::brush::BrushNode".into()) { + return None; + } + let points_input = brush_node.inputs.get(1)?; + let NodeInput::Value { + tagged_value: TaggedValue::VecDVec2(points), + .. + } = points_input else { return None }; + + Some((layer_path, points.clone())) +} diff --git a/editor/src/messages/tool/tool_messages/freehand_tool.rs b/editor/src/messages/tool/tool_messages/freehand_tool.rs index d050942d..66ee6649 100644 --- a/editor/src/messages/tool/tool_messages/freehand_tool.rs +++ b/editor/src/messages/tool/tool_messages/freehand_tool.rs @@ -11,7 +11,7 @@ use document_legacy::LayerId; use document_legacy::Operation; use graphene_core::vector::style::Stroke; -use glam::{DAffine2, DVec2}; +use glam::DVec2; use serde::{Deserialize, Serialize}; #[derive(Default)] @@ -217,9 +217,9 @@ fn remove_preview(data: &FreehandToolData) -> Message { } fn add_polyline(data: &FreehandToolData, tool_data: &DocumentToolData, responses: &mut VecDeque) { - let layer_path = data.path.clone().unwrap(); let subpath = bezier_rs::Subpath::from_anchors(data.points.iter().copied(), false); - let position = subpath.bounding_box().unwrap_or_default().into_iter().sum::() / 2.; + + let layer_path = data.path.clone().unwrap(); graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses); responses.add(GraphOperationMessage::StrokeSet { diff --git a/editor/src/messages/tool/tool_messages/select_tool.rs b/editor/src/messages/tool/tool_messages/select_tool.rs index bcceaf4a..7a99d2b0 100644 --- a/editor/src/messages/tool/tool_messages/select_tool.rs +++ b/editor/src/messages/tool/tool_messages/select_tool.rs @@ -971,12 +971,6 @@ fn rerender_selected_layers(tool_data: &mut SelectToolData, responses: &mut VecD } } -fn rerender_duplicated_layers(tool_data: &mut SelectToolData, responses: &mut VecDeque) { - for layer_path in tool_data.not_duplicated_layers.iter().flatten() { - responses.add(DocumentMessage::NodeGraphFrameGenerate { layer_path: layer_path.clone() }); - } -} - // TODO: Majorly clean up these next five functions fn drag_shallowest_manipulation( diff --git a/editor/src/messages/tool/tool_messages/spline_tool.rs b/editor/src/messages/tool/tool_messages/spline_tool.rs index 321dcfed..be0fc052 100644 --- a/editor/src/messages/tool/tool_messages/spline_tool.rs +++ b/editor/src/messages/tool/tool_messages/spline_tool.rs @@ -262,10 +262,10 @@ fn add_spline(tool_data: &SplineToolData, global_tool_data: &DocumentToolData, s } let subpath = bezier_rs::Subpath::new_cubic_spline(points); - let position = subpath.bounding_box().unwrap_or_default().into_iter().sum::() / 2.; let layer_path = tool_data.path.clone().unwrap(); graph_modification_utils::new_vector_layer(vec![subpath], layer_path.clone(), responses); + responses.add(GraphOperationMessage::StrokeSet { layer: layer_path.clone(), stroke: Stroke::new(global_tool_data.primary_color, tool_data.weight), diff --git a/editor/src/node_graph_executor.rs b/editor/src/node_graph_executor.rs index 55bdf8b9..9dbe3b32 100644 --- a/editor/src/node_graph_executor.rs +++ b/editor/src/node_graph_executor.rs @@ -269,9 +269,17 @@ impl NodeGraphExecutor { // Attempt to downcast to an image frame let ImageFrame { image, transform } = dyn_any::downcast(boxed_node_graph_output).map(|image_frame| *image_frame)?; + // Don't update the frame's transform if the new transform is DAffine2::ZERO. + let transform = (!transform.abs_diff_eq(DAffine2::ZERO, f64::EPSILON)).then_some(transform.to_cols_array()); + // If no image was generated, clear the frame if image.width == 0 || image.height == 0 { responses.push_back(DocumentMessage::FrameClear.into()); + + // Update the transform based on the graph output + if let Some(transform) = transform { + responses.push_back(Operation::SetLayerTransform { path: layer_path.clone(), transform }.into()); + } } else { // Update the image data let (image_data, _size) = Self::encode_img(image, None, image::ImageOutputFormat::Bmp)?; @@ -289,17 +297,10 @@ impl NodeGraphExecutor { path: layer_path.clone(), image_data, mime, + transform, }]; responses.push_back(FrontendMessage::UpdateImageData { document_id, image_data }.into()); } - - // Don't update the frame's transform if the new transform is DAffine2::ZERO. - if !transform.abs_diff_eq(DAffine2::ZERO, f64::EPSILON) { - // Update the transform based on the graph output - let transform = transform.to_cols_array(); - responses.push_back(Operation::SetLayerTransform { path: layer_path.clone(), transform }.into()); - responses.push_back(Operation::SetLayerVisibility { path: layer_path, visible: true }.into()); - } } Ok(()) diff --git a/frontend/src-tauri/src/main.rs b/frontend/src-tauri/src/main.rs index ced9a2ab..4f49123f 100644 --- a/frontend/src-tauri/src/main.rs +++ b/frontend/src-tauri/src/main.rs @@ -98,11 +98,13 @@ fn handle_message(message: String) -> String { for image in image_data { let path = image.path.clone(); let mime = image.mime.clone(); + let transform = image.transform.clone(); images.insert(format!("{:?}_{}", &image.path, document_id), image); stub_data.push(FrontendImageData { path, mime, image_data: Arc::new(Vec::new()), + transform, }); } FrontendMessage::UpdateImageData { document_id, image_data: stub_data } diff --git a/frontend/src/components/panels/LayerTree.svelte b/frontend/src/components/panels/LayerTree.svelte index 18e0dc41..ecc97d1b 100644 --- a/frontend/src/components/panels/LayerTree.svelte +++ b/frontend/src/components/panels/LayerTree.svelte @@ -529,6 +529,7 @@ } &::placeholder { + opacity: 1; color: inherit; font-style: italic; } diff --git a/frontend/src/state-providers/portfolio.ts b/frontend/src/state-providers/portfolio.ts index d13bec84..5cefd0d4 100644 --- a/frontend/src/state-providers/portfolio.ts +++ b/frontend/src/state-providers/portfolio.ts @@ -113,7 +113,7 @@ export function createPortfolioState(editor: Editor) { image.src = blobURL; await image.decode(); - editor.instance.setImageBlobURL(updateImageData.documentId, element.path, blobURL, image.naturalWidth, image.naturalHeight); + editor.instance.setImageBlobURL(updateImageData.documentId, element.path, blobURL, image.naturalWidth, image.naturalHeight, element.transform); }); }); editor.subscriptions.subscribeJsMessage(TriggerNodeGraphFrameGenerate, async (triggerNodeGraphFrameGenerate) => { diff --git a/frontend/src/wasm-communication/editor.ts b/frontend/src/wasm-communication/editor.ts index 6b549186..300146c6 100644 --- a/frontend/src/wasm-communication/editor.ts +++ b/frontend/src/wasm-communication/editor.ts @@ -11,7 +11,7 @@ export type Editor = Readonly>; let wasmImport: WasmRawInstance | undefined; let editorInstance: WasmEditorInstance | undefined; -export async function updateImage(path: BigUint64Array, mime: string, imageData: Uint8Array, documentId: bigint): Promise { +export async function updateImage(path: BigUint64Array, mime: string, imageData: Uint8Array, transform: Float64Array, documentId: bigint): Promise { const blob = new Blob([imageData], { type: mime }); const blobURL = URL.createObjectURL(blob); @@ -21,7 +21,7 @@ export async function updateImage(path: BigUint64Array, mime: string, imageData: image.src = blobURL; await image.decode(); - editorInstance?.setImageBlobURL(documentId, path, blobURL, image.naturalWidth, image.naturalHeight); + editorInstance?.setImageBlobURL(documentId, path, blobURL, image.naturalWidth, image.naturalHeight,transform); } export async function fetchImage(path: BigUint64Array, mime: string, documentId: bigint, url: string): Promise { @@ -35,7 +35,7 @@ export async function fetchImage(path: BigUint64Array, mime: string, documentId: image.src = blobURL; await image.decode(); - editorInstance?.setImageBlobURL(documentId, path, blobURL, image.naturalWidth, image.naturalHeight); + editorInstance?.setImageBlobURL(documentId, path, blobURL, image.naturalWidth, image.naturalHeight, undefined); } const tauri = "__TAURI_METADATA__" in window && import("@tauri-apps/api"); diff --git a/frontend/src/wasm-communication/messages.ts b/frontend/src/wasm-communication/messages.ts index 0f6d0393..4f0b7e40 100644 --- a/frontend/src/wasm-communication/messages.ts +++ b/frontend/src/wasm-communication/messages.ts @@ -768,6 +768,8 @@ export class ImaginateImageData { readonly mime!: string; readonly imageData!: Uint8Array; + + readonly transform!: Float64Array ; } export class DisplayDialogDismiss extends JsMessage {} diff --git a/frontend/wasm/src/editor_api.rs b/frontend/wasm/src/editor_api.rs index 7e27de46..d8c52d51 100644 --- a/frontend/wasm/src/editor_api.rs +++ b/frontend/wasm/src/editor_api.rs @@ -32,7 +32,7 @@ pub fn set_random_seed(seed: u64) { /// This avoids creating a json with a list millions of numbers long. #[wasm_bindgen(module = "@graphite/wasm-communication/editor")] extern "C" { - fn updateImage(path: Vec, mime: String, imageData: &[u8], document_id: u64); + fn updateImage(path: Vec, mime: String, imageData: &[u8], transform: js_sys::Float64Array, document_id: u64); fn fetchImage(path: Vec, mime: String, document_id: u64, identifier: String); //fn dispatchTauri(message: String) -> String; fn dispatchTauri(message: String); @@ -114,7 +114,16 @@ impl JsEditorHandle { if let FrontendMessage::UpdateImageData { document_id, image_data } = message { for image in image_data { #[cfg(not(feature = "tauri"))] - updateImage(image.path, image.mime, &image.image_data, document_id); + { + let transform = if let Some(transform_val) = image.transform { + let transform = js_sys::Float64Array::new_with_length(6); + transform.copy_from(&transform_val); + transform + } else { + js_sys::Float64Array::default() + }; + updateImage(image.path, image.mime, &image.image_data, transform, document_id); + } #[cfg(feature = "tauri")] fetchImage(image.path.clone(), image.mime, document_id, format!("http://localhost:3001/image/{:?}_{}", &image.path, document_id)); } @@ -495,15 +504,22 @@ impl JsEditorHandle { /// Sends the blob URL generated by JS to the Image layer #[wasm_bindgen(js_name = setImageBlobURL)] - pub fn set_image_blob_url(&self, document_id: u64, layer_path: Vec, blob_url: String, width: f64, height: f64) { + pub fn set_image_blob_url(&self, document_id: u64, layer_path: Vec, blob_url: String, width: f64, height: f64, transform: Option) { let resolution = (width, height); let message = PortfolioMessage::SetImageBlobUrl { document_id, - layer_path, + layer_path: layer_path.clone(), blob_url, resolution, }; self.dispatch(message); + + if let Some(array) = transform.filter(|array| array.length() == 6) { + let mut transform: [f64; 6] = [0.; 6]; + array.copy_to(&mut transform); + let message = document_legacy::Operation::SetLayerTransform { path: layer_path, transform }; + self.dispatch(message); + } } /// Sends the blob URL generated by JS to the Imaginate layer in the respective document diff --git a/node-graph/gcore/src/value.rs b/node-graph/gcore/src/value.rs index 9890f0d2..1498c9dc 100644 --- a/node-graph/gcore/src/value.rs +++ b/node-graph/gcore/src/value.rs @@ -1,5 +1,5 @@ use core::marker::PhantomData; -use dyn_any::{DynAny, StaticType, StaticTypeSized}; +use dyn_any::{StaticType, StaticTypeSized}; use crate::Node; diff --git a/node-graph/gstd/src/raster.rs b/node-graph/gstd/src/raster.rs index 85ac2431..dfded595 100644 --- a/node-graph/gstd/src/raster.rs +++ b/node-graph/gstd/src/raster.rs @@ -274,7 +274,8 @@ fn blend_image_tuple(images: (ImageFrame, ImageFrame), map_fn: &'any_inpu where MapFn: for<'any_input> Node<'any_input, (Color, Color), Output = Color> + 'input + Clone, { - let (mut background, foreground) = images; + let (background, foreground) = images; + let node = BlendImageNode::new(ClonedNode::new(background), ValueNode::new(map_fn.clone())); node.eval(foreground) } diff --git a/node-graph/interpreted-executor/src/executor.rs b/node-graph/interpreted-executor/src/executor.rs index a499bada..c83e22d2 100644 --- a/node-graph/interpreted-executor/src/executor.rs +++ b/node-graph/interpreted-executor/src/executor.rs @@ -7,7 +7,7 @@ use graph_craft::document::value::UpcastNode; use graph_craft::document::NodeId; use graph_craft::executor::Executor; use graph_craft::proto::{ConstructionArgs, ProtoNetwork, ProtoNode, TypingContext}; -use graph_craft::{Type, TypeDescriptor}; +use graph_craft::Type; use graphene_std::any::{Any, TypeErasedPinned, TypeErasedPinnedRef}; use crate::node_registry; diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 6ea2a302..907b504e 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -21,7 +21,7 @@ use graph_craft::proto::NodeConstructor; use graphene_core::{concrete, fn_type, generic, value_fn}; use graphene_std::memo::{CacheNode, LetNode}; -use graphene_std::raster::{BlendImageTupleNode, MapImageFrameNode}; +use graphene_std::raster::BlendImageTupleNode; use crate::executor::NodeContainer; diff --git a/node-graph/node-macro/src/lib.rs b/node-graph/node-macro/src/lib.rs index fb853b1d..630664ba 100644 --- a/node-graph/node-macro/src/lib.rs +++ b/node-graph/node-macro/src/lib.rs @@ -2,8 +2,8 @@ use proc_macro::TokenStream; use proc_macro2::Span; use quote::{format_ident, ToTokens}; use syn::{ - parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PatType, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, - TypeParam, TypeParamBound, WhereClause, WherePredicate, + parse_macro_input, punctuated::Punctuated, token::Comma, FnArg, GenericParam, Ident, ItemFn, Lifetime, Pat, PatIdent, PathArguments, PredicateType, ReturnType, Token, TraitBound, Type, TypeParam, + TypeParamBound, WhereClause, WherePredicate, }; #[proc_macro_attribute] @@ -51,7 +51,7 @@ pub fn node_fn(attr: TokenStream, item: TokenStream) -> TokenStream { .filter(|gen| { if let GenericParam::Type(ty) = gen { !function.sig.inputs.iter().take(1).any(|param_ty| match param_ty { - FnArg::Typed(pat_ty) => pat_ty.ty.to_token_stream().to_string() == ty.ident.to_string(), + FnArg::Typed(pat_ty) => ty.ident == pat_ty.ty.to_token_stream().to_string(), _ => false, }) } else {