mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-15 22:28:10 +08:00
Add the 'Blend Shapes' and 'Origins to Polyline' nodes; generalize the 'Morph' node to >2 states (#3405)
* New nodes: 'Morph' and 'Multi-Morph' * Blend Shapes node * Add the 'Index Points' node * Fix failing test
This commit is contained in:
@@ -416,6 +416,539 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
description: Cow::Borrowed("Creates a new Artboard which can be used as a working surface."),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Blend Shapes",
|
||||
category: "Vector",
|
||||
// [IMPORTS]2 -> 0[0:Floor]
|
||||
// [0:Floor]0 -> 0[1:Subtract]
|
||||
// "1: f64" -> 1[1:Subtract]
|
||||
// "(): ()" -> 0[2:Instance Index]
|
||||
// "0: u32" -> 1[2:Instance Index]
|
||||
// [2:Instance Index]0 -> 0[3:Divide]
|
||||
// [1:Subtract]0 -> 1[3:Divide]
|
||||
// [IMPORTS]1 -> 0[4:Position on Path]
|
||||
// [3:Divide]0 -> 1[4:Position on Path]
|
||||
// "false: bool" -> 2[4:Position on Path]
|
||||
// "false: bool" -> 3[4:Position on Path]
|
||||
// "(): ()" -> 0[5:Instance Vector]
|
||||
// [5:Instance Vector]0 -> 0[6:Reset Transform]
|
||||
// "true: bool" -> 1[6:Reset Transform]
|
||||
// "false: bool" -> 2[6:Reset Transform]
|
||||
// "false: bool" -> 3[6:Reset Transform]
|
||||
// [12:Flatten Vector]0 -> 0[7:Instance Map]
|
||||
// [6:Reset Transform]0 -> 1[7:Instance Map]
|
||||
// [7:Instance Map]0 -> 0[8:Morph]
|
||||
// [15:Multiply]0 -> 1[8:Morph]
|
||||
// [8:Morph]0 -> 0[9:Transform]
|
||||
// [4:Position on Path]0 -> 1[9:Transform]
|
||||
// "0: f64" -> 2[9:Transform]
|
||||
// "(0, 0): DVec2" -> 3[9:Transform]
|
||||
// "(0, 0): DVec2" -> 4[9:Transform]
|
||||
// [IMPORTS]1 -> 0[10:Count Points]
|
||||
// [10:Count Points]0 -> 0[11:Equals]
|
||||
// [13:Count Elements]0 -> 1[11:Equals]
|
||||
// [IMPORTS]0 -> 0[12:Flatten Vector]
|
||||
// [12:Flatten Vector]0 -> 0[13:Count Elements]
|
||||
// [13:Count Elements]0 -> 0[14:Subtract]
|
||||
// "1: f64" -> 1[14:Subtract]
|
||||
// [3:Divide]0 -> 0[15:Multiply]
|
||||
// [14:Subtract]0 -> 1[15:Multiply]
|
||||
// [12:Flatten Vector]0 -> 0[16:Morph]
|
||||
// [15:Multiply]0 -> 1[16:Morph]
|
||||
// [11:Equals]0 -> 0[17:Switch]
|
||||
// [9:Transform]0 -> 1[17:Switch]
|
||||
// [16:Morph]0 -> 2[17:Switch]
|
||||
// [17:Switch]0 -> 0[18:Instance Repeat]
|
||||
// [0:Floor]0 -> 1[18:Instance Repeat]
|
||||
// [IMPORTS]3 -> 2[18:Instance Repeat]
|
||||
// [18:Instance Repeat]0 -> 0[EXPORTS]
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(18), 0)],
|
||||
nodes: [
|
||||
// 0: Floor
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::floor::IDENTIFIER),
|
||||
inputs: vec![NodeInput::import(concrete!(f64), 2)],
|
||||
..Default::default()
|
||||
},
|
||||
// 1: Subtract
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::subtract::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0), NodeInput::value(TaggedValue::F64(1.), false)],
|
||||
..Default::default()
|
||||
},
|
||||
// 2: Instance Index
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_index::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::None, false), NodeInput::value(TaggedValue::U32(0), false)],
|
||||
..Default::default()
|
||||
},
|
||||
// 3: Divide
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::divide::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0), NodeInput::node(NodeId(1), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 4: Position on Path
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::position_on_path::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::import(generic!(T), 1),
|
||||
NodeInput::node(NodeId(3), 0),
|
||||
NodeInput::value(TaggedValue::Bool(false), false),
|
||||
NodeInput::value(TaggedValue::Bool(false), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
// 5: Instance Vector
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_vector::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::None, false)],
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Reset Transform
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::reset_transform::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::node(NodeId(5), 0),
|
||||
NodeInput::value(TaggedValue::Bool(true), false),
|
||||
NodeInput::value(TaggedValue::Bool(false), false),
|
||||
NodeInput::value(TaggedValue::Bool(false), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
// 7: Instance Map
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_map::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(12), 0), NodeInput::node(NodeId(6), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 8: Morph
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::morph::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(7), 0), NodeInput::node(NodeId(15), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 9: Transform
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::transform::IDENTIFIER),
|
||||
inputs: vec![
|
||||
NodeInput::node(NodeId(8), 0),
|
||||
NodeInput::node(NodeId(4), 0),
|
||||
NodeInput::value(TaggedValue::F64(0.), false),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ONE), false),
|
||||
NodeInput::value(TaggedValue::DVec2(DVec2::ZERO), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
// 10: Count Points
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::count_points::IDENTIFIER),
|
||||
inputs: vec![NodeInput::import(generic!(T), 1)],
|
||||
..Default::default()
|
||||
},
|
||||
// 11: Equals
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::equals::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(10), 0), NodeInput::node(NodeId(13), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 12: Flatten Vector
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic_nodes::graphic::flatten_vector::IDENTIFIER),
|
||||
inputs: vec![NodeInput::import(generic!(T), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 13: Count Elements
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::count_elements::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(12), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 14: Subtract
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::subtract::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(13), 0), NodeInput::value(TaggedValue::F64(1.), false)],
|
||||
..Default::default()
|
||||
},
|
||||
// 15: Multiply
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(math_nodes::multiply::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(3), 0), NodeInput::node(NodeId(14), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 16: Morph
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::morph::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(12), 0), NodeInput::node(NodeId(15), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 17: Switch
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(logic::switch::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(11), 0), NodeInput::node(NodeId(9), 0), NodeInput::node(NodeId(16), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 18: Instance Repeat
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_repeat::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(17), 0), NodeInput::node(NodeId(0), 0), NodeInput::import(generic!(T), 3)],
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::Vector(Default::default()), true),
|
||||
NodeInput::value(TaggedValue::F64(10.), false),
|
||||
NodeInput::value(TaggedValue::Bool(Default::default()), false),
|
||||
],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![("Content", "TODO").into(), ("Path", "TODO").into(), ("Count", "TODO").into(), ("Reverse", "TODO").into()],
|
||||
output_names: vec!["Out".to_string()],
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
// 0: Floor
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 1: Subtract
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 2: Instance Index
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, -2)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 3: Divide
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, -2)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 4: Position on Path
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, -3)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 5: Instance Vector
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Reset Transform
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 2)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 7: Instance Map
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 8: Morph
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 9: Transform
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(35, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 10: Count Points
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 4)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 11: Equals
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 4)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 12: Flatten Vector
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 6)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 13: Count Elements
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 8)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 14: Subtract
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 8)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 15: Multiply
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 7)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 16: Morph
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, 6)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 17: Switch
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(42, 4)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 18: Instance Repeat
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(49, -1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Origins to Polyline",
|
||||
category: "Vector",
|
||||
// "(): ()" -> 0[0:Instance Vector]
|
||||
// [0:Instance Vector]0 -> 0[1:Extract Transform]
|
||||
// [1:Extract Transform]0 -> 0[2:Decompose Translation]
|
||||
// [2:Decompose Translation]0 -> 0[3:Vec2 to Point]
|
||||
// [IMPORTS]0 -> 0[4:Flatten Vector]
|
||||
// [4:Flatten Vector]0 -> 0[5:Instance Map]
|
||||
// [3:Vec2 to Point]0 -> 1[5:Instance Map]
|
||||
// [5:Instance Map]0 -> 0[6: Flatten Path]
|
||||
// [6:Flatten Path]0 -> 0[7:Points to Polyline]
|
||||
// "false: bool" -> 1[7:Points to Polyline]
|
||||
// [7:Points to Polyline]0 -> 0[EXPORTS]
|
||||
node_template: NodeTemplate {
|
||||
document_node: DocumentNode {
|
||||
implementation: DocumentNodeImplementation::Network(NodeNetwork {
|
||||
exports: vec![NodeInput::node(NodeId(7), 0)],
|
||||
nodes: [
|
||||
// 0: Instance Vector
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_vector::IDENTIFIER),
|
||||
inputs: vec![NodeInput::value(TaggedValue::None, false)],
|
||||
..Default::default()
|
||||
},
|
||||
// 1: Extract Transform
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::extract_transform::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(0), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 2: Decompose Translation
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(transform_nodes::decompose_translation::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(1), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 3: Vec2 to Point
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::vec_2_to_point::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(2), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 4: Flatten Vector
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(graphic_nodes::graphic::flatten_vector::IDENTIFIER),
|
||||
inputs: vec![NodeInput::import(generic!(T), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 5: Instance Map
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector_nodes::instance_map::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(4), 0), NodeInput::node(NodeId(3), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Flatten Path
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::flatten_path::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(5), 0)],
|
||||
..Default::default()
|
||||
},
|
||||
// 7: Points to Polyline
|
||||
DocumentNode {
|
||||
implementation: DocumentNodeImplementation::ProtoNode(vector::points_to_polyline::IDENTIFIER),
|
||||
inputs: vec![NodeInput::node(NodeId(6), 0), NodeInput::value(TaggedValue::Bool(false), false)],
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
}),
|
||||
inputs: vec![NodeInput::value(TaggedValue::Vector(Default::default()), true)],
|
||||
..Default::default()
|
||||
},
|
||||
persistent_node_metadata: DocumentNodePersistentMetadata {
|
||||
input_metadata: vec![("Vector", "TODO").into()],
|
||||
output_names: vec!["Vector".to_string()],
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 0)),
|
||||
network_metadata: Some(NodeNetworkMetadata {
|
||||
persistent_metadata: NodeNetworkPersistentMetadata {
|
||||
node_metadata: [
|
||||
// 0: Instance Vector
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(0, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 1: Extract Transform
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(7, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 2: Decompose Transform
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(14, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 3: Vec2 to Point
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 1)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 4: Flatten Vector
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(21, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 5: Instance Map
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(28, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 6: Flatten Path
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(35, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
// 7: Points to Polyline
|
||||
DocumentNodeMetadata {
|
||||
persistent_metadata: DocumentNodePersistentMetadata {
|
||||
node_type_metadata: NodeTypePersistentMetadata::node(IVec2::new(42, 0)),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
},
|
||||
]
|
||||
.into_iter()
|
||||
.enumerate()
|
||||
.map(|(id, node)| (NodeId(id as u64), node))
|
||||
.collect(),
|
||||
..Default::default()
|
||||
},
|
||||
..Default::default()
|
||||
}),
|
||||
..Default::default()
|
||||
},
|
||||
},
|
||||
description: Cow::Borrowed("TODO"),
|
||||
properties: None,
|
||||
},
|
||||
DocumentNodeDefinition {
|
||||
identifier: "Load Image",
|
||||
category: "Web Request",
|
||||
@@ -745,13 +1278,13 @@ fn static_nodes() -> Vec<DocumentNodeDefinition> {
|
||||
exports: vec![NodeInput::value(TaggedValue::None, false), NodeInput::node(NodeId(0), 0), NodeInput::node(NodeId(1), 0)],
|
||||
nodes: [
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::import(concrete!(Table<Raster<CPU>>), 0), NodeInput::value(TaggedValue::XY(XY::X), false)],
|
||||
inputs: vec![NodeInput::import(concrete!(DVec2), 0), NodeInput::value(TaggedValue::XY(XY::X), false)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
},
|
||||
DocumentNode {
|
||||
inputs: vec![NodeInput::import(concrete!(Table<Raster<CPU>>), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)],
|
||||
inputs: vec![NodeInput::import(concrete!(DVec2), 0), NodeInput::value(TaggedValue::XY(XY::Y), false)],
|
||||
implementation: DocumentNodeImplementation::ProtoNode(extract_xy::extract_xy::IDENTIFIER),
|
||||
call_argument: generic!(T),
|
||||
..Default::default()
|
||||
|
||||
@@ -154,6 +154,7 @@ pub(crate) fn property_from_type(
|
||||
Some("PixelLength") => number_widget(default_info, number_input.min(min(0.)).unit(unit.unwrap_or(" px"))).into(),
|
||||
Some("Length") => number_widget(default_info, number_input.min(min(0.))).into(),
|
||||
Some("Fraction") => number_widget(default_info, number_input.mode_range().min(min(0.)).max(max(1.))).into(),
|
||||
Some("Progression") => progression_widget(default_info, number_input.min(min(0.))).into(),
|
||||
Some("SignedInteger") => number_widget(default_info, number_input.int()).into(),
|
||||
Some("IntegerCount") => number_widget(default_info, number_input.int().min(min(1.))).into(),
|
||||
Some("SeedValue") => number_widget(default_info, number_input.int().min(min(0.))).into(),
|
||||
@@ -794,6 +795,50 @@ pub fn font_inputs(parameter_widgets_info: ParameterWidgetsInfo) -> (Vec<WidgetH
|
||||
(first_widgets, second_widgets)
|
||||
}
|
||||
|
||||
// Two number fields beside one another, the first for the fractional part (decimals, range mode) and the second for the whole part (integers, increment mode)
|
||||
pub fn progression_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec<WidgetHolder> {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
let mut widgets = start_widgets(parameter_widgets_info);
|
||||
|
||||
let Some(document_node) = document_node else { return Vec::new() };
|
||||
let Some(input) = document_node.inputs.get(index) else {
|
||||
log::warn!("A widget failed to be built because its node's input index is invalid.");
|
||||
return vec![];
|
||||
};
|
||||
if let Some(&TaggedValue::F64(x)) = input.as_non_exposed_value() {
|
||||
let whole_part = x.trunc();
|
||||
let fractional_part = x.fract();
|
||||
|
||||
widgets.extend_from_slice(&[
|
||||
Separator::new(SeparatorType::Unrelated).widget_holder(),
|
||||
number_props
|
||||
.clone()
|
||||
.label("Progress")
|
||||
.mode_range()
|
||||
.min(0.)
|
||||
.max(0.99999)
|
||||
.value(Some(fractional_part))
|
||||
.on_update(update_value(move |input: &NumberInput| TaggedValue::F64(whole_part + input.value.unwrap()), node_id, index))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
TextLabel::new("+").widget_holder(),
|
||||
Separator::new(SeparatorType::Related).widget_holder(),
|
||||
number_props
|
||||
.label("Element #")
|
||||
.mode_increment()
|
||||
.min(0.)
|
||||
.is_integer(true)
|
||||
.value(Some(whole_part))
|
||||
.on_update(update_value(move |input: &NumberInput| TaggedValue::F64(input.value.unwrap() + fractional_part), node_id, index))
|
||||
.on_commit(commit_value)
|
||||
.widget_holder(),
|
||||
])
|
||||
}
|
||||
widgets
|
||||
}
|
||||
|
||||
pub fn number_widget(parameter_widgets_info: ParameterWidgetsInfo, number_props: NumberInput) -> Vec<WidgetHolder> {
|
||||
let ParameterWidgetsInfo { document_node, node_id, index, .. } = parameter_widgets_info;
|
||||
|
||||
|
||||
@@ -1582,6 +1582,53 @@ fn migrate_node(node_id: &NodeId, node: &DocumentNode, network_path: &[NodeId],
|
||||
}
|
||||
}
|
||||
|
||||
// Migrate from the old source/target "Morph" node to the new vector table based "Morph" node.
|
||||
// This doesn't produce exactly equivalent results in cases involving input vector tables with multiple rows.
|
||||
// The old version would zip the source and target table rows, interpoleating each pair together.
|
||||
// The migrated version will instead deeply flatten both merged tables and morph sequentially between all source vectors and all target vector elements.
|
||||
// This migration assumes most usages didn't involve multiple parallel vector elements, and instead morphed from a single source to a single target vector element.
|
||||
if reference == "Morph" && inputs_count == 3 {
|
||||
// Old signature:
|
||||
// async fn morph(_: impl Ctx, source: Table<Vector>, #[expose] target: Table<Vector>, #[default(0.5)] time: Fraction) -> Table<Vector> { ... }
|
||||
//
|
||||
// New signature:
|
||||
// async fn morph<I: IntoGraphicTable>(_: impl Ctx, content: #[implementations(Table<Graphic>, Table<Vector>)] content: I, progression: Progression) -> Table<Vector> { ... }
|
||||
|
||||
let mut node_template = resolve_document_node_type(reference)?.default_node_template();
|
||||
let old_inputs = document.network_interface.replace_inputs(node_id, network_path, &mut node_template)?;
|
||||
|
||||
// Create a new Merge node
|
||||
let Some(merge_node_type) = resolve_document_node_type("Merge") else {
|
||||
log::error!("Could not get merge node from definition when upgrading morph");
|
||||
return None;
|
||||
};
|
||||
let merge_template = merge_node_type.default_node_template();
|
||||
let merge_node_id = NodeId::new();
|
||||
|
||||
// Decide on the placement position of the new Merge node
|
||||
let Some(morph_position) = document.network_interface.position_from_downstream_node(node_id, network_path) else {
|
||||
log::error!("Could not get position for morph node {node_id}");
|
||||
return None;
|
||||
};
|
||||
let merge_position = morph_position + IVec2::new(-7, 0);
|
||||
|
||||
// Insert the new Merge node into the network
|
||||
document.network_interface.insert_node(merge_node_id, merge_template, network_path);
|
||||
document.network_interface.set_to_node_or_layer(&merge_node_id, network_path, false);
|
||||
document.network_interface.shift_absolute_node_position(&merge_node_id, merge_position, network_path);
|
||||
|
||||
// Connect the old 'source' and 'target' inputs to the new Merge node
|
||||
document.network_interface.set_input(&InputConnector::node(merge_node_id, 0), old_inputs[0].clone(), network_path);
|
||||
document.network_interface.set_input(&InputConnector::node(merge_node_id, 1), old_inputs[1].clone(), network_path);
|
||||
|
||||
// Connect the new Merge node to the 'content' input of the Morph node
|
||||
document
|
||||
.network_interface
|
||||
.set_input(&InputConnector::node(*node_id, 0), NodeInput::node(merge_node_id, 0), network_path);
|
||||
// Connect the old 'progression' input to the new 'progression' input of the Morph node
|
||||
document.network_interface.set_input(&InputConnector::node(*node_id, 1), old_inputs[2].clone(), network_path);
|
||||
}
|
||||
|
||||
// Add context features to nodes that don't have them (fine-grained context caching migration)
|
||||
if node.context_features == graphene_std::ContextDependencies::default()
|
||||
&& let Some(reference) = document.network_interface.reference(node_id, network_path).cloned().flatten()
|
||||
|
||||
Reference in New Issue
Block a user