Krzysztof Krysiński 13 stundas atpakaļ
vecāks
revīzija
c3142c381f

+ 79 - 2
src/PixiEditor.ChangeableDocument/Changeables/Graph/GraphUtils.cs

@@ -22,9 +22,86 @@ public static class GraphUtils
                 continue;
             }
 
-            if (considerFlowNodes && node is IExecutionFlowNode flowNode)
+            if (considerFlowNodes && node is IExecutionFlowNode flowNode && !nodesToExclude.Contains(node))
             {
-                foreach (var handled in flowNode.HandledNodes)
+                var handledNodes = flowNode.HandledNodes;
+                foreach (var handled in handledNodes)
+                {
+                    nodesToExclude.Add(handled);
+                }
+            }
+
+            bool canAdd = true;
+
+            foreach (var input in node.InputProperties)
+            {
+                if (input.Connection == null)
+                {
+                    continue;
+                }
+
+                if (finalQueue.Contains(input.Connection.Node))
+                {
+                    continue;
+                }
+
+                if (branchFilter != null && !branchFilter(input))
+                {
+                    continue;
+                }
+
+                canAdd = false;
+
+                if (finalQueue.Contains(input.Connection.Node))
+                {
+                    finalQueue.Remove(input.Connection.Node);
+                    finalQueue.Add(input.Connection.Node);
+                }
+
+                if (!queueNodes.Contains(input.Connection.Node))
+                {
+                    queueNodes.Enqueue(input.Connection.Node);
+                }
+            }
+
+            if (canAdd)
+            {
+                finalQueue.Add(node);
+            }
+            else
+            {
+                queueNodes.Enqueue(node);
+            }
+        }
+
+        finalQueue = new HashSet<IReadOnlyNode>(finalQueue.Except(nodesToExclude));
+
+        return new Queue<IReadOnlyNode>(finalQueue);
+    }
+
+    public static Queue<IReadOnlyNode> CalculateExecutionQueue(IReadOnlyNode outputNode,
+        bool considerFlowNodes,
+        bool ignoreOutputFlowNode,
+        Func<IInputProperty, bool>? branchFilter = null)
+    {
+        var finalQueue = new HashSet<IReadOnlyNode>();
+        var queueNodes = new Queue<IReadOnlyNode>();
+        var nodesToExclude = new HashSet<IReadOnlyNode>();
+        queueNodes.Enqueue(outputNode);
+
+        while (queueNodes.Count > 0)
+        {
+            var node = queueNodes.Dequeue();
+
+            if (finalQueue.Contains(node))
+            {
+                continue;
+            }
+
+            if (considerFlowNodes && node is IExecutionFlowNode flowNode && !nodesToExclude.Contains(node) && !(ignoreOutputFlowNode && node == outputNode))
+            {
+                var handledNodes = flowNode.HandledNodes;
+                foreach (var handled in handledNodes)
                 {
                     nodesToExclude.Add(handled);
                 }

+ 47 - 34
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Utility/RepeatNodeEnd.cs

@@ -7,7 +7,7 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Utility;
 
 [NodeInfo("RepeatEnd")]
 [PairNode(typeof(RepeatNodeStart), "RepeatZone", false)]
-public class RepeatNodeEnd : Node, IPairNode
+public class RepeatNodeEnd : Node, IPairNode, IExecutionFlowNode
 {
     public InputProperty<object> Input { get; }
     public OutputProperty<object> Output { get; }
@@ -34,38 +34,7 @@ public class RepeatNodeEnd : Node, IPairNode
             }
         }
 
-        int iterations = startNode.Iterations.Value;
-        var queue = GraphUtils.CalculateExecutionQueue(this, false, (input => input.Connection?.Node != startNode));
-
-        for (int i = 0; i < iterations; i++)
-        {
-            startNode.CurrentIteration.Value = i;
-            foreach (var node in queue)
-            {
-                if (node is RepeatNodeStart or RepeatNodeEnd)
-                {
-                    continue;
-                }
-
-                node.Execute(context);
-            }
-
-            startNode.Output.Value = Input.Value;
-        }
-        startNode.CurrentIteration.Value = 0;
-        if (iterations <= 0)
-        {
-            Output.Value = startNode.Input.Value;
-        }
-        else
-        {
-            Output.Value = Input.Value;
-        }
-    }
-
-    private object GetOutput(ShaderFuncContext context)
-    {
-        return null;
+        Output.Value = Input.Value;
     }
 
     public override Node CreateCopy()
@@ -76,17 +45,61 @@ public class RepeatNodeEnd : Node, IPairNode
     private RepeatNodeStart FindStartNode()
     {
         RepeatNodeStart startNode = null;
+        int nestingCount = 0;
         TraverseBackwards(node =>
         {
-            if (node is RepeatNodeStart leftNode)
+            if (node is RepeatNodeEnd && node != this)
+            {
+                nestingCount++;
+            }
+            if (node is RepeatNodeStart leftNode && nestingCount == 0)
             {
                 startNode = leftNode;
                 return false;
             }
+            if (node is RepeatNodeStart)
+            {
+                nestingCount--;
+            }
 
             return true;
         });
 
         return startNode;
     }
+
+    public HashSet<IReadOnlyNode> HandledNodes => CalculateHandledNodes();
+
+    private HashSet<IReadOnlyNode> CalculateHandledNodes()
+    {
+        HashSet<IReadOnlyNode> handled = new();
+
+        startNode = FindStartNode();
+
+        int nestingCount = 0;
+        var queue = GraphUtils.CalculateExecutionQueue(this, false, property => property.Connection.Node != startNode);
+
+        foreach (var node in queue)
+        {
+            if (node is RepeatNodeStart && node != this)
+            {
+                nestingCount++;
+            }
+            if (node is RepeatNodeEnd leftNode && nestingCount == 0)
+            {
+                if (leftNode == this)
+                {
+                    break;
+                }
+                nestingCount--;
+            }
+
+            if (node != this && node != startNode)
+            {
+                handled.Add(node);
+            }
+        }
+
+        return handled;
+    }
 }

+ 64 - 15
src/PixiEditor.ChangeableDocument/Changeables/Graph/Nodes/Utility/RepeatNodeStart.cs

@@ -6,13 +6,18 @@ namespace PixiEditor.ChangeableDocument.Changeables.Graph.Nodes.Utility;
 
 [NodeInfo("RepeatStart")]
 [PairNode(typeof(RepeatNodeEnd), "RepeatZone", true)]
-public class RepeatNodeStart : Node, IExecutionFlowNode
+public class RepeatNodeStart : Node, IPairNode
 {
     public InputProperty<int> Iterations { get; }
     public InputProperty<object> Input { get; }
     public OutputProperty<int> CurrentIteration { get; }
     public OutputProperty<object> Output { get; }
 
+    public Guid OtherNode { get; set; }
+    private RepeatNodeEnd? endNode;
+
+    private bool iterationInProgress = false;
+
     public RepeatNodeStart()
     {
         Iterations = CreateInput<int>("Iterations", "ITERATIONS", 1);
@@ -23,36 +28,80 @@ public class RepeatNodeStart : Node, IExecutionFlowNode
 
     protected override void OnExecute(RenderContext context)
     {
+        if (iterationInProgress)
+        {
+            return;
+        }
+
+        endNode = FindEndNode();
+        if (endNode == null)
+        {
+            return;
+        }
+
+        OtherNode = endNode?.Id ?? Guid.Empty;
+
+        int iterations = Iterations.Value;
+        var queue = GraphUtils.CalculateExecutionQueue(endNode, true, true,
+            property => property.Connection?.Node != this);
+
         Output.Value = Input.Value;
-        CurrentIteration.Value = 0;
-    }
+        iterationInProgress = true;
+        for (int i = 0; i < iterations; i++)
+        {
+            CurrentIteration.Value = i + 1;
+            foreach (var node in queue)
+            {
+                if (node == this)
+                {
+                    continue;
+                }
 
-    public override Node CreateCopy()
-    {
-        return new RepeatNodeStart();
-    }
+                node.Execute(context);
+            }
 
-    public HashSet<IReadOnlyNode> HandledNodes => CalculateHandledNodes();
+            Output.Value = endNode.Output.Value;
+        }
 
-    private HashSet<IReadOnlyNode> CalculateHandledNodes()
-    {
-        HashSet<IReadOnlyNode> handled = new();
+        if (iterations > 0)
+        {
+            Output.Value = Input.Value;
+        }
 
+        iterationInProgress = false;
+    }
+
+    private RepeatNodeEnd FindEndNode()
+    {
+        RepeatNodeEnd repeatNodeEnd = null;
+        int nestingCount = 0;
+        HashSet<Guid> visitedNodes = new HashSet<Guid>();
         TraverseForwards(node =>
         {
-            if (node is RepeatNodeEnd)
+            if (node is RepeatNodeStart && node != this)
+            {
+                nestingCount++;
+            }
+
+            if (node is RepeatNodeEnd rightNode && nestingCount == 0 && rightNode.OtherNode == Id)
             {
+                repeatNodeEnd = rightNode;
                 return false;
             }
 
-            if (node != this)
+            if (node is RepeatNodeEnd && visitedNodes.Add(node.Id))
             {
-                handled.Add(node);
+                nestingCount--;
             }
 
             return true;
         });
 
-        return handled;
+        return repeatNodeEnd;
+    }
+
+    public override Node CreateCopy()
+    {
+        return new RepeatNodeStart();
     }
 }

+ 9 - 2
src/PixiEditor/ViewModels/Document/NodeGraphViewModel.cs

@@ -150,7 +150,13 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler, IDisposabl
             return;
 
         var lastKnownFramesPartOf = node.Frames.OfType<NodeZoneViewModel>().ToHashSet();
-        var startLookup = Frames.OfType<NodeZoneViewModel>().ToDictionary(x => x.Start);
+        var zones = Frames.OfType<NodeZoneViewModel>();
+        Dictionary<INodeHandler, NodeZoneViewModel>? startLookup = new Dictionary<INodeHandler, NodeZoneViewModel>();
+        foreach (var zone in zones)
+        {
+            startLookup.TryAdd(zone.Start, zone);
+        }
+
         var currentlyPartOf = new HashSet<NodeZoneViewModel>();
 
         node.TraverseBackwards(x =>
@@ -311,7 +317,8 @@ internal class NodeGraphViewModel : ViewModelBase, INodeGraphHandler, IDisposabl
 
     public void UpdatePropertyValue(INodeHandler node, string property, object? value)
     {
-        Internals.ActionAccumulator.AddFinishedActions(new UpdatePropertyValue_Action(node.Id, property, value), new EndUpdatePropertyValue_Action());
+        Internals.ActionAccumulator.AddFinishedActions(new UpdatePropertyValue_Action(node.Id, property, value),
+            new EndUpdatePropertyValue_Action());
     }
 
     public void BeginUpdatePropertyValue(INodeHandler node, string property, object value)