@@ -16,10 +16,13 @@ use crate::messages::prelude::*;
16
16
use crate :: messages:: tool:: utility_types:: { HintData , HintGroup , ToolType } ;
17
17
use crate :: node_graph_executor:: { ExportConfig , NodeGraphExecutor } ;
18
18
19
+ use bezier_rs:: Subpath ;
20
+ use glam:: IVec2 ;
19
21
use graph_craft:: document:: value:: TaggedValue ;
20
22
use graph_craft:: document:: { DocumentNodeImplementation , NodeId , NodeInput } ;
21
23
use graphene_core:: text:: { Font , TypesettingConfig } ;
22
24
use graphene_std:: vector:: style:: { Fill , FillType , Gradient } ;
25
+ use graphene_std:: vector:: { VectorData , VectorDataTable } ;
23
26
use interpreted_executor:: dynamic_executor:: IntrospectError ;
24
27
25
28
use std:: sync:: Arc ;
@@ -480,6 +483,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
480
483
( "graphene_core::raster::VibranceNode" , "graphene_core::raster::adjustments::VibranceNode" ) ,
481
484
( "graphene_core::text::TextGeneratorNode" , "graphene_core::text::TextNode" ) ,
482
485
( "graphene_core::transform::SetTransformNode" , "graphene_core::transform::ReplaceTransformNode" ) ,
486
+ ( "graphene_core::vector::SplinesFromPointsNode" , "graphene_core::vector::SplineNode" ) ,
483
487
( "graphene_core::vector::generator_nodes::EllipseGenerator" , "graphene_core::vector::generator_nodes::EllipseNode" ) ,
484
488
( "graphene_core::vector::generator_nodes::LineGenerator" , "graphene_core::vector::generator_nodes::LineNode" ) ,
485
489
( "graphene_core::vector::generator_nodes::PathGenerator" , "graphene_core::vector::generator_nodes::PathNode" ) ,
@@ -488,7 +492,6 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
488
492
"graphene_core::vector::generator_nodes::RegularPolygonGenerator" ,
489
493
"graphene_core::vector::generator_nodes::RegularPolygonNode" ,
490
494
) ,
491
- ( "graphene_core::vector::generator_nodes::SplineGenerator" , "graphene_core::vector::generator_nodes::SplineNode" ) ,
492
495
( "graphene_core::vector::generator_nodes::StarGenerator" , "graphene_core::vector::generator_nodes::StarNode" ) ,
493
496
( "graphene_std::executor::BlendGpuImageNode" , "graphene_std::gpu_nodes::BlendGpuImageNode" ) ,
494
497
( "graphene_std::raster::SampleNode" , "graphene_std::raster::SampleImageNode" ) ,
@@ -637,6 +640,77 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageData<'_>> for PortfolioMes
637
640
}
638
641
}
639
642
643
+ // Rename the old "Splines from Points" node to "Spline" and upgrade it to the new "Spline" node
644
+ if reference == "Splines from Points" {
645
+ document. network_interface . set_reference ( node_id, & [ ] , Some ( "Spline" . to_string ( ) ) ) ;
646
+ }
647
+
648
+ // Upgrade the old "Spline" node to the new "Spline" node
649
+ if reference == "Spline" {
650
+ // Retrieve the proto node identifier and verify it is the old "Spline" node, otherwise skip it if this is the new "Spline" node
651
+ let identifier = document. network_interface . implementation ( node_id, & [ ] ) . and_then ( |implementation| implementation. get_proto_node ( ) ) ;
652
+ if identifier. map ( |identifier| & identifier. name ) != Some ( & "graphene_core::vector::generator_nodes::SplineNode" . into ( ) ) {
653
+ continue ;
654
+ }
655
+
656
+ // Obtain the document node for the given node ID, extract the vector points, and create vector data from the list of points
657
+ let node = document. network_interface . document_node ( node_id, & [ ] ) . unwrap ( ) ;
658
+ let Some ( TaggedValue :: VecDVec2 ( points) ) = node. inputs . get ( 1 ) . and_then ( |tagged_value| tagged_value. as_value ( ) ) else {
659
+ log:: error!( "The old Spline node's input at index 1 is not a TaggedValue::VecDVec2" ) ;
660
+ continue ;
661
+ } ;
662
+ let vector_data = VectorData :: from_subpath ( Subpath :: from_anchors_linear ( points. to_vec ( ) , false ) ) ;
663
+
664
+ // Retrieve the output connectors linked to the "Spline" node's output port
665
+ let spline_outputs = document
666
+ . network_interface
667
+ . outward_wires ( & [ ] )
668
+ . unwrap ( )
669
+ . get ( & OutputConnector :: node ( * node_id, 0 ) )
670
+ . expect ( "Vec of InputConnector Spline node is connected to its output port 0." )
671
+ . clone ( ) ;
672
+
673
+ // Get the node's current position in the graph
674
+ let Some ( node_position) = document. network_interface . position ( node_id, & [ ] ) else {
675
+ log:: error!( "Could not get position of spline node." ) ;
676
+ continue ;
677
+ } ;
678
+
679
+ // Get the "Path" node definition and fill it in with the vector data and default vector modification
680
+ let path_node_type = resolve_document_node_type ( "Path" ) . expect ( "Path node does not exist." ) ;
681
+ let path_node = path_node_type. node_template_input_override ( [
682
+ Some ( NodeInput :: value ( TaggedValue :: VectorData ( VectorDataTable :: new ( vector_data) ) , true ) ) ,
683
+ Some ( NodeInput :: value ( TaggedValue :: VectorModification ( Default :: default ( ) ) , false ) ) ,
684
+ ] ) ;
685
+
686
+ // Get the "Spline" node definition and wire it up with the "Path" node as input
687
+ let spline_node_type = resolve_document_node_type ( "Spline" ) . expect ( "Spline node does not exist." ) ;
688
+ let spline_node = spline_node_type. node_template_input_override ( [ Some ( NodeInput :: node ( NodeId ( 1 ) , 0 ) ) ] ) ;
689
+
690
+ // Create a new node group with the "Path" and "Spline" nodes and generate new node IDs for them
691
+ let nodes = vec ! [ ( NodeId ( 1 ) , path_node) , ( NodeId ( 0 ) , spline_node) ] ;
692
+ let new_ids = nodes. iter ( ) . map ( |( id, _) | ( * id, NodeId :: new ( ) ) ) . collect :: < HashMap < _ , _ > > ( ) ;
693
+ let new_spline_id = * new_ids. get ( & NodeId ( 0 ) ) . unwrap ( ) ;
694
+ let new_path_id = * new_ids. get ( & NodeId ( 1 ) ) . unwrap ( ) ;
695
+
696
+ // Remove the old "Spline" node from the document
697
+ document. network_interface . delete_nodes ( vec ! [ * node_id] , false , & [ ] ) ;
698
+
699
+ // Insert the new "Path" and "Spline" nodes into the network interface with generated IDs
700
+ document. network_interface . insert_node_group ( nodes. clone ( ) , new_ids, & [ ] ) ;
701
+
702
+ // Reposition the new "Spline" node to match the original "Spline" node's position
703
+ document. network_interface . shift_node ( & new_spline_id, node_position, & [ ] ) ;
704
+
705
+ // Reposition the new "Path" node with an offset relative to the original "Spline" node's position
706
+ document. network_interface . shift_node ( & new_path_id, node_position + IVec2 :: new ( -7 , 0 ) , & [ ] ) ;
707
+
708
+ // Redirect each output connection from the old node to the new "Spline" node's output port
709
+ for input_connector in spline_outputs {
710
+ document. network_interface . set_input ( & input_connector, NodeInput :: node ( new_spline_id, 0 ) , & [ ] ) ;
711
+ }
712
+ }
713
+
640
714
// Upgrade Text node to include line height and character spacing, which were previously hardcoded to 1, from https://github.com/GraphiteEditor/Graphite/pull/2016
641
715
if reference == "Text" && inputs_count != 8 {
642
716
let node_definition = resolve_document_node_type ( reference) . unwrap ( ) ;
0 commit comments