Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion demo-artwork/changing-seasons.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/isometric-fountain.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/marbled-mandelbrot.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/painted-dreams.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/parametric-dunescape.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/procedural-string-lights.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/red-dress.graphite

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion demo-artwork/valley-of-spires.graphite

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -433,17 +433,17 @@ impl<'a> ModifyInputsContext<'a> {
return None;
};

// If inserting a 'Path' node, insert a 'Flatten Path' node if the type is `Graphic`.
// If inserting a 'Path' node, insert a 'Combine Paths' node if the type is `Graphic`.
// TODO: Allow the 'Path' node to operate on `List` data by utilizing the reference (index or ID?) for each item.
if node_definition.identifier == "Path" {
let layer_input_type = self.network_interface.input_type(&InputConnector::node(output_layer.to_node(), 1), &[]);
if layer_input_type.compiled_element_name().as_deref() == Some("Graphic") {
let Some(flatten_path_definition) = resolve_proto_node_type(graphene_std::vector_nodes::flatten_path::IDENTIFIER) else {
log::error!("Flatten Path does not exist in ModifyInputsContext::existing_node_id");
let Some(combine_paths_definition) = resolve_proto_node_type(graphene_std::vector_nodes::combine_paths::IDENTIFIER) else {
log::error!("Combine Paths does not exist in ModifyInputsContext::existing_node_id");
return None;
};
let node_id = NodeId::new();
self.network_interface.insert_node(node_id, flatten_path_definition.default_node_template(), &[]);
self.network_interface.insert_node(node_id, combine_paths_definition.default_node_template(), &[]);
self.network_interface.move_node_to_chain_start(&node_id, output_layer, &[], self.import);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -806,9 +806,9 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
inputs: vec![NodeInput::node(NodeId(4), 0), NodeInput::node(NodeId(3), 0)],
..Default::default()
},
// 6: Flatten Path
// 6: Combine Paths
DocumentNode {
implementation: DocumentNodeImplementation::ProtoNode(vector::flatten_path::IDENTIFIER),
implementation: DocumentNodeImplementation::ProtoNode(vector::combine_paths::IDENTIFIER),
inputs: vec![NodeInput::node(NodeId(5), 0)],
..Default::default()
},
Expand Down Expand Up @@ -883,7 +883,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
},
..Default::default()
},
// 6: Flatten Path
// 6: Combine Paths
DocumentNodeMetadata {
persistent_metadata: DocumentNodePersistentMetadata {
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(35, 0)),
Expand Down Expand Up @@ -1239,7 +1239,7 @@ fn document_node_definitions() -> HashMap<DefinitionIdentifier, DocumentNodeDefi
description: Cow::Borrowed(
"Decomposes the X and Y components of a vec2.\n\
\n\
The inverse of this node is \"Vec2 Value\", which can have either or both its X and Y parameters exposed as graph inputs.",
The inverse of this node is **Combine Vec2**, which composes a vec2 from its X and Y components.",
),
properties: None,
},
Expand Down
22 changes: 19 additions & 3 deletions editor/src/messages/portfolio/document_migration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,8 +294,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
],
},
NodeReplacement {
node: graphene_std::math_nodes::length::IDENTIFIER,
aliases: &["graphene_math_nodes::LengthNode", "graphene_core::ops::LenghtNode"],
node: graphene_std::math_nodes::magnitude::IDENTIFIER,
aliases: &["math_nodes::LengthNode", "graphene_math_nodes::LengthNode", "graphene_core::ops::LenghtNode"],
},
Comment thread
Keavon marked this conversation as resolved.
NodeReplacement {
node: graphene_std::math_nodes::less_than::IDENTIFIER,
Expand Down Expand Up @@ -420,6 +420,8 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
node: graphene_std::math_nodes::as_u_64::IDENTIFIER,
aliases: &["graphene_math_nodes::ToU64Node", "graphene_core::ops::ToU64Node", "math_nodes::ToU64Node"],
},
// The old 'Vec2 Value' node took separate X and Y inputs, a role now filled by 'Combine Vec2', while the new 'Vec2 Value' node takes a single vec2 input.
// Old references (including these older aliases) are remapped here to `vec_2_value::IDENTIFIER` so the per-node migration in `migrate_node` can detect the leftover 3-input shape and convert it into a 'Combine Vec2' node.
NodeReplacement {
node: graphene_std::math_nodes::vec_2_value::IDENTIFIER,
aliases: &[
Expand Down Expand Up @@ -803,7 +805,7 @@ const NODE_REPLACEMENTS: &[NodeReplacement<'static>] = &[
aliases: &["graphene_core::vector::vector_nodes::FillNode", "graphene_core::vector::FillNode"],
},
NodeReplacement {
node: graphene_std::vector::flatten_path::IDENTIFIER,
node: graphene_std::vector::combine_paths::IDENTIFIER,
aliases: &[
"graphene_core::vector::vector_nodes::FlattenPathNode",
"graphene_core::vector::FlattenVectorElementsNode",
Expand Down Expand Up @@ -2021,6 +2023,20 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
.set_input(&InputConnector::node(*node_id, 2), NodeInput::value(TaggedValue::Bool(false), false), network_path);
}

// Convert the old 'Vec2 Value' node, identified by its leftover 3-input shape with separate X and Y inputs,
// into the 'Combine Vec2' node which now fills that role (the new 'Vec2 Value' node instead takes a single vec2 input)
if reference == DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::vec_2_value::IDENTIFIER) && inputs_count == 3 {
let combine_vec2_reference = DefinitionIdentifier::ProtoNode(graphene_std::math_nodes::combine_vec_2::IDENTIFIER);
let mut node_template = resolve_document_node_type(&combine_vec2_reference)?.default_node_template();
document.network_interface.replace_implementation(node_id, network_path, &mut node_template);

let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;

document.network_interface.set_input(&InputConnector::node(*node_id, 0), old_inputs[0].clone(), network_path);
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[1].clone(), network_path);
document.network_interface.set_input(&InputConnector::node(*node_id, 2), old_inputs[2].clone(), network_path);
}

// Upgrade the Mirror node to add the `keep_original` boolean input
if reference == DefinitionIdentifier::ProtoNode(graphene_std::graphic::mirror::IDENTIFIER) && inputs_count == 3 {
let mut node_template = resolve_document_node_type(&reference)?.default_node_template();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -101,21 +101,21 @@ pub fn merge_layers(document: &DocumentMessageHandler, first_layer: LayerNodeIde
delete_children: false,
});

// Add a Flatten Path node after the merge
let flatten_node_id = NodeId::new();
let flatten_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::flatten_path::IDENTIFIER)
.expect("Failed to create flatten node")
// Add a Combine Paths node after the merge
let combine_paths_node_id = NodeId::new();
let combine_paths_node = document_node_definitions::resolve_proto_node_type(graphene_std::vector::combine_paths::IDENTIFIER)
.expect("Failed to create combine paths node")
.default_node_template();
responses.add(NodeGraphMessage::InsertNode {
node_id: flatten_node_id,
node_template: Box::new(flatten_node),
node_id: combine_paths_node_id,
node_template: Box::new(combine_paths_node),
});
responses.add(NodeGraphMessage::MoveNodeToChainStart {
node_id: flatten_node_id,
node_id: combine_paths_node_id,
parent: first_layer,
});

// Add a path node after the flatten node
// Add a path node after the combine paths node
let path_node_id = NodeId::new();
let path_node = document_node_definitions::resolve_network_node_type("Path")
.expect("Failed to create path node")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,7 @@ impl ShapeState {
(point.as_handle().is_some() && self.ignore_handles) || (point.as_anchor().is_some() && self.ignore_anchors)
}

/// Applies a dummy vector modification to the layer. In the case where a group containing some vector data is selected, this triggers the creation of a Flatten Path node.
/// Applies a dummy vector modification to the layer. In the case where a group containing some vector data is selected, this triggers the creation of a Combine Paths node.
fn add_dummy_modification_to_trigger_graph_reorganization(layer: LayerNodeIdentifier, start_point: PointId, _end_point: PointId, responses: &mut VecDeque<Message>) {
// Apply a zero-delta to one of the points to trigger reorganization
let dummy_modification = VectorModificationType::ApplyPointDelta {
Expand Down
2 changes: 1 addition & 1 deletion node-graph/libraries/rendering/src/renderer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1623,7 +1623,7 @@ impl Render for List<Vector> {
}

// If this item carries a snapshot of upstream graphic content (e.g. it was produced by Boolean Operation,
// Flatten Path, Morph, or any other destructive merge), recurse into that snapshot so the editor can
// Combine Paths, Morph, or any other destructive merge), recurse into that snapshot so the editor can
// surface the original child layers' click targets.
let upstream_nested_layers = self.attribute_cloned_or_default::<List<Graphic>>(ATTR_EDITOR_MERGED_LAYERS, index);
if !upstream_nested_layers.is_empty() {
Expand Down
2 changes: 1 addition & 1 deletion node-graph/nodes/gcore/src/extract_xy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use glam::{DVec2, IVec2, UVec2};

/// Obtains the X or Y component of a vec2.
///
/// The inverse of this node is "Vec2 Value", which can have either or both its X and Y parameters exposed as graph inputs.
/// The inverse of this node is **Combine Vec2**, which composes a vec2 from its X and Y components.
#[node_macro::node(name("Extract XY"), category("Math: Vector"))]
fn extract_xy<T: Into<DVec2>>(_: impl Ctx, #[implementations(DVec2, IVec2, UVec2)] vector: Item<T>, axis: Item<XY>) -> Item<f64> {
let vector = vector.into_element();
Expand Down
2 changes: 1 addition & 1 deletion node-graph/nodes/graphic/src/graphic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ pub async fn flatten_vector<T: IntoGraphicList>(_: impl Ctx, #[implementations(L
// TODO: we stash the pre-flattened list on the output so `List<Vector>::collect_metadata` can recurse into it,
// TODO: which conflates render output with editor metadata and forces the pre-compensation dance below.
// TODO: The cleaner fix is to drive each layer's metadata from its own Monitor's captured `(Context, List<Graphic>)`,
// TODO: at which point this attribute (and the equivalents in Boolean Operation, Solidify Stroke, Flatten Path,
// TODO: at which point this attribute (and the equivalents in Boolean Operation, Solidify Stroke, Combine Paths,
// TODO: Morph, Rasterize) become unnecessary.
if !output.is_empty() {
// Item 0 carries a composed transform inherited from the flattened input, but the merged_layers
Expand Down
28 changes: 22 additions & 6 deletions node-graph/nodes/math/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -975,8 +975,8 @@ fn percentage_value(_: impl Ctx, _primary: (), percentage: Item<Percentage>) ->

/// Constructs a two-dimensional vector value which may be set to any XY pair.
#[node_macro::node(category("Value"), name("Vec2 Value"))]
fn vec2_value(_: impl Ctx, _primary: (), x: Item<f64>, y: Item<f64>) -> Item<DVec2> {
Item::new_from_element(DVec2::new(*x.element(), *y.element()))
fn vec2_value(_: impl Ctx, _primary: (), #[name("Vec2")] vec2: Item<DVec2>) -> Item<DVec2> {
Comment thread
Keavon marked this conversation as resolved.
vec2
}

/// Constructs a color value which may be set to any color.
Expand Down Expand Up @@ -1073,6 +1073,23 @@ fn footprint_value(_: impl Ctx, _primary: (), transform: Item<DAffine2>, #[defau
})
}

/// Composes a vec2 from its X and Y components.
///
/// The inverse of this node is **Split Vec2**, which decomposes a vec2 back into its X and Y components.
#[node_macro::node(category("Math: Vector"), name("Combine Vec2"))]
fn combine_vec2(
_: impl Ctx,
_primary: (),
/// The X component of the vec2.
#[expose]
x: Item<f64>,
/// The Y component of the vec2.
#[expose]
y: Item<f64>,
) -> Item<DVec2> {
Item::new_from_element(DVec2::new(*x.element(), *y.element()))
}

/// The dot product operation (`·`) calculates the degree of similarity of a vec2 pair based on their angles and lengths.
///
/// Calculated as `‖a‖‖b‖cos(θ)`, it represents the product of their lengths (`‖a‖‖b‖`) scaled by the alignment of their directions (`cos(θ)`).
Expand Down Expand Up @@ -1152,10 +1169,9 @@ fn angle_to<T: ToPosition, U: ToPosition>(
Item::from_parts(result, attributes)
}

// TODO: Rename to "Magnitude"
/// The magnitude operator (`‖x‖`) calculates the length of a vec2, which is the distance from the base to the tip of the arrow represented by the vector.
#[node_macro::node(category("Math: Vector"))]
fn length(_: impl Ctx, vector: Item<DVec2>) -> Item<f64> {
fn magnitude(_: impl Ctx, vector: Item<DVec2>) -> Item<f64> {
let (vector, attributes) = vector.into_parts();

Item::from_parts(vector.length(), attributes)
Expand Down Expand Up @@ -1185,9 +1201,9 @@ mod test {
}

#[test]
pub fn length_function() {
pub fn magnitude_function() {
let vector = Item::new_from_element(DVec2::new(3., 4.));
assert_eq!(length((), vector).into_element(), 5.);
assert_eq!(magnitude((), vector).into_element(), 5.);
}

#[test]
Expand Down
8 changes: 4 additions & 4 deletions node-graph/nodes/repeat/src/repeat_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ mod test {
Item::new_from_element(count),
)
.await;
let vector_list = List::new_from_item(vector_nodes::flatten_path(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector = vector_list.element(0).unwrap();
assert_eq!(vector.region_manipulator_groups().count(), 3);
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
Expand All @@ -340,7 +340,7 @@ mod test {
Item::new_from_element(1),
)
.await;
let vector_list = List::new_from_item(vector_nodes::flatten_path(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector = vector_list.element(0).unwrap();
assert_eq!(vector.region_manipulator_groups().count(), 1);

Expand All @@ -362,7 +362,7 @@ mod test {
Item::new_from_element(count),
)
.await;
let vector_list = List::new_from_item(vector_nodes::flatten_path(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector = vector_list.element(0).unwrap();
assert_eq!(vector.region_manipulator_groups().count(), 8);
for (index, (_, manipulator_groups)) in vector.region_manipulator_groups().enumerate() {
Expand All @@ -381,7 +381,7 @@ mod test {
Item::new_from_element(8),
)
.await;
let vector_list = List::new_from_item(vector_nodes::flatten_path(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector_list = List::new_from_item(vector_nodes::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(repeated))).await);
let vector = vector_list.element(0).unwrap();
assert_eq!(vector.region_manipulator_groups().count(), 8);

Expand Down
11 changes: 5 additions & 6 deletions node-graph/nodes/vector/src/vector_nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1560,9 +1560,8 @@ async fn map_points(ctx: impl Ctx + CloneVarArgs + ExtractAll, content: Item<Vec
}

/// Combines every vector path across the input into a single compound path.
// TODO: Rename to "Combine Paths" with a document migration
#[node_macro::node(category("Vector"), path(graphene_core::vector))]
pub async fn flatten_path<T: IntoGraphicList>(_: impl Ctx, #[implementations(List<Graphic>, List<Vector>)] content: T) -> Item<Vector> {
pub async fn combine_paths<T: IntoGraphicList>(_: impl Ctx, #[implementations(List<Graphic>, List<Vector>)] content: T) -> Item<Vector> {
let graphic_list = content.into_graphic_list();
let flattened = graphic_list.clone().into_flattened_list::<Vector>();

Expand Down Expand Up @@ -3597,12 +3596,12 @@ mod test {
Item::new_from_element(0),
)
.await;
let flatten_path = List::new_from_item(super::flatten_path(Footprint::default(), List::new_from_element(Graphic::Vector(copy_to_points))).await);
let flattened_copy_to_points = flatten_path.element(0).unwrap();
let combined = List::new_from_item(super::combine_paths(Footprint::default(), List::new_from_element(Graphic::Vector(copy_to_points))).await);
let combined_copy_to_points = combined.element(0).unwrap();

assert_eq!(flattened_copy_to_points.region_manipulator_groups().count(), expected_points.len());
assert_eq!(combined_copy_to_points.region_manipulator_groups().count(), expected_points.len());

for (index, (_, manipulator_groups)) in flattened_copy_to_points.region_manipulator_groups().enumerate() {
for (index, (_, manipulator_groups)) in combined_copy_to_points.region_manipulator_groups().enumerate() {
let offset = expected_points[index];
let manipulator_groups_anchors = manipulator_groups.iter().map(|manipulators| manipulators.anchor).collect::<Vec<DVec2>>();
assert_eq!(
Expand Down
Loading