From 9e06e70aa2e085a29d1e21731225e16bc16aba70 Mon Sep 17 00:00:00 2001 From: Keavon Chambers Date: Sun, 17 Dec 2023 04:17:17 -0800 Subject: [PATCH] New node: Copy to Points (#1513) * New node: Copy to Points * Remove dead code --- .../document_node_types.rs | 44 +++++++++++------- .../node_properties.rs | 14 ++++++ node-graph/gcore/src/vector/vector_nodes.rs | 46 +++++++++++++++---- .../interpreted-executor/src/node_registry.rs | 3 +- 4 files changed, 80 insertions(+), 27 deletions(-) diff --git a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs index 2505b1cb..67044d2c 100644 --- a/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs +++ b/editor/src/messages/portfolio/document/node_graph/node_graph_message_handler/document_node_types.rs @@ -2235,19 +2235,6 @@ fn static_nodes() -> Vec { properties: node_properties::stroke_properties, ..Default::default() }, - DocumentNodeDefinition { - name: "Repeat", - category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::RepeatNode<_, _>"), - inputs: vec![ - DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), - DocumentInputType::value("Direction", TaggedValue::DVec2((100., 0.).into()), false), - DocumentInputType::value("Count", TaggedValue::U32(10), false), - ], - outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], - properties: node_properties::repeat_properties, - ..Default::default() - }, DocumentNodeDefinition { name: "Bounding Box", category: "Vector", @@ -2257,12 +2244,25 @@ fn static_nodes() -> Vec { properties: node_properties::node_no_properties, ..Default::default() }, + DocumentNodeDefinition { + name: "Repeat", + category: "Vector", + implementation: NodeImplementation::proto("graphene_core::vector::RepeatNode<_, _>"), + inputs: vec![ + DocumentInputType::value("Instance", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), + DocumentInputType::value("Direction", TaggedValue::DVec2((100., 0.).into()), false), + DocumentInputType::value("Count", TaggedValue::U32(10), false), + ], + outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], + properties: node_properties::repeat_properties, + ..Default::default() + }, DocumentNodeDefinition { name: "Circular Repeat", category: "Vector", implementation: NodeImplementation::proto("graphene_core::vector::CircularRepeatNode<_, _, _>"), inputs: vec![ - DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), + DocumentInputType::value("Instance", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), DocumentInputType::value("Angle Offset", TaggedValue::F32(0.), false), DocumentInputType::value("Radius", TaggedValue::F32(5.), false), DocumentInputType::value("Count", TaggedValue::U32(10), false), @@ -2271,6 +2271,18 @@ fn static_nodes() -> Vec { properties: node_properties::circular_repeat_properties, ..Default::default() }, + DocumentNodeDefinition { + name: "Copy to Points", + category: "Vector", + implementation: NodeImplementation::proto("graphene_core::vector::CopyToPoints<_>"), + inputs: vec![ + DocumentInputType::value("Points", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), + DocumentInputType::value("Instance", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true), + ], + outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], + properties: node_properties::copy_to_points_properties, + ..Default::default() + }, DocumentNodeDefinition { name: "Resample Points", category: "Vector", @@ -2284,9 +2296,9 @@ fn static_nodes() -> Vec { ..Default::default() }, DocumentNodeDefinition { - name: "Spline from Points", + name: "Splines from Points", category: "Vector", - implementation: NodeImplementation::proto("graphene_core::vector::SplineFromPointsNode"), + implementation: NodeImplementation::proto("graphene_core::vector::SplinesFromPointsNode"), inputs: vec![DocumentInputType::value("Vector Data", TaggedValue::VectorData(graphene_core::vector::VectorData::empty()), true)], outputs: vec![DocumentOutputType::new("Vector", FrontendGraphDataType::Subpath)], properties: node_properties::node_no_properties, 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 6d5d278a..4ad44f5c 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 @@ -309,6 +309,14 @@ fn font_inputs(document_node: &DocumentNode, node_id: NodeId, index: usize, name (first_widgets, second_widgets) } +fn vector_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, blank_assist: bool) -> Vec { + let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Vector, blank_assist); + + widgets.push(TextLabel::new("Vector data must be supplied through the graph").widget_holder()); + + widgets +} + fn number_widget(document_node: &DocumentNode, node_id: NodeId, index: usize, name: &str, number_props: NumberInput, blank_assist: bool) -> Vec { let mut widgets = start_widgets(document_node, node_id, index, name, FrontendGraphDataType::Number, blank_assist); @@ -2107,6 +2115,12 @@ pub fn circular_repeat_properties(document_node: &DocumentNode, node_id: NodeId, vec![LayoutGroup::Row { widgets: angle_offset }, LayoutGroup::Row { widgets: radius }, LayoutGroup::Row { widgets: count }] } +pub fn copy_to_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { + let instance = vector_widget(document_node, node_id, 1, "Spacing", true); + + vec![LayoutGroup::Row { widgets: instance }] +} + pub fn resample_points_properties(document_node: &DocumentNode, node_id: NodeId, _context: &mut NodePropertiesContext) -> Vec { let spacing = number_widget(document_node, node_id, 1, "Spacing", NumberInput::default().min(1.), true); diff --git a/node-graph/gcore/src/vector/vector_nodes.rs b/node-graph/gcore/src/vector/vector_nodes.rs index 50e7a580..b1bf0d8b 100644 --- a/node-graph/gcore/src/vector/vector_nodes.rs +++ b/node-graph/gcore/src/vector/vector_nodes.rs @@ -110,23 +110,18 @@ pub struct CircularRepeatNode { #[node_macro::node_fn(CircularRepeatNode)] fn circular_repeat_vector_data(mut vector_data: VectorData, angle_offset: f32, radius: f32, count: u32) -> VectorData { - // repeat the vector data - let VectorData { subpaths, transform, .. } = &vector_data; - - let mut new_subpaths: Vec> = Vec::with_capacity(subpaths.len() * count as usize); + let mut new_subpaths: Vec> = Vec::with_capacity(vector_data.subpaths.len() * count as usize); let bounding_box = vector_data.bounding_box().unwrap(); let center = (bounding_box[0] + bounding_box[1]) / 2.; - //let inverse = transform.inverse(); - //let radius_transform = DAffine2::from_translation(DVec2::new(0., radius as f64)); let base_transform = DVec2::new(0., radius as f64) - center; for i in 0..count { let angle = (2. * std::f64::consts::PI / count as f64) * i as f64 + angle_offset.to_radians() as f64; let rotation = DAffine2::from_angle(angle); let transform = DAffine2::from_translation(center) * rotation * DAffine2::from_translation(base_transform); - for mut subpath in subpaths.clone() { + for mut subpath in vector_data.subpaths.clone() { subpath.apply_transform(transform); new_subpaths.push(subpath); } @@ -148,6 +143,37 @@ fn generate_bounding_box(vector_data: VectorData) -> VectorData { )]) } +#[derive(Debug, Clone, Copy)] +pub struct CopyToPoints { + instance: Instance, +} + +#[node_macro::node_fn(CopyToPoints)] +fn copy_to_points(points: VectorData, instance: VectorData) -> VectorData { + let points_list = points.subpaths.iter().flat_map(|s| s.anchors()); + + let instance_bounding_box = instance.bounding_box().unwrap_or_default(); + let instance_center = DAffine2::from_translation(-0.5 * (instance_bounding_box[0] + instance_bounding_box[1])); + + let mut instanced_subpaths: Vec> = Vec::new(); + for point in points_list { + let transform = DAffine2::from_translation(point) * instance_center; + + for mut subpath in instance.subpaths.clone() { + subpath.apply_transform(transform); + instanced_subpaths.push(subpath); + } + } + + VectorData { + subpaths: instanced_subpaths, + transform: DAffine2::IDENTITY, + style: instance.style, + alpha_blending: instance.alpha_blending, + mirror_angle: instance.mirror_angle, + } +} + #[derive(Debug, Clone, Copy)] pub struct ResamplePoints { spacing: Spacing, @@ -175,10 +201,10 @@ fn resample_points(mut vector_data: VectorData, spacing: f64) -> VectorData { } #[derive(Debug, Clone, Copy)] -pub struct SplineFromPointsNode {} +pub struct SplinesFromPointsNode {} -#[node_macro::node_fn(SplineFromPointsNode)] -fn spline_from_points(mut vector_data: VectorData) -> VectorData { +#[node_macro::node_fn(SplinesFromPointsNode)] +fn splines_from_points(mut vector_data: VectorData) -> VectorData { for subpath in &mut vector_data.subpaths { *subpath = Subpath::new_cubic_spline(subpath.anchors()); } diff --git a/node-graph/interpreted-executor/src/node_registry.rs b/node-graph/interpreted-executor/src/node_registry.rs index 5fb55d15..95e7c557 100644 --- a/node-graph/interpreted-executor/src/node_registry.rs +++ b/node-graph/interpreted-executor/src/node_registry.rs @@ -837,8 +837,9 @@ fn node_registry() -> HashMap, input: Footprint, params: [ImageFrame]), register_node!(graphene_std::raster::MandelbrotNode, input: Footprint, params: []), + register_node!(graphene_core::vector::CopyToPoints<_>, input: VectorData, params: [VectorData]), register_node!(graphene_core::vector::ResamplePoints<_>, input: VectorData, params: [f64]), - register_node!(graphene_core::vector::SplineFromPointsNode, input: VectorData, params: []), + register_node!(graphene_core::vector::SplinesFromPointsNode, input: VectorData, params: []), register_node!(graphene_core::vector::generator_nodes::CircleGenerator<_>, input: (), params: [f32]), register_node!(graphene_core::vector::generator_nodes::EllipseGenerator<_, _>, input: (), params: [f32, f32]), register_node!(graphene_core::vector::generator_nodes::RectangleGenerator<_, _>, input: (), params: [f32, f32]),