NodeGraph.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144
  1. using System.Collections;
  2. using System.Diagnostics;
  3. using PixiEditor.ChangeableDocument.Changeables.Graph.Interfaces;
  4. using PixiEditor.ChangeableDocument.Changeables.Graph.Nodes;
  5. using PixiEditor.ChangeableDocument.Rendering;
  6. using PixiEditor.DrawingApi.Core;
  7. namespace PixiEditor.ChangeableDocument.Changeables.Graph;
  8. public class NodeGraph : IReadOnlyNodeGraph, IDisposable
  9. {
  10. private readonly List<Node> _nodes = new();
  11. public IReadOnlyCollection<Node> Nodes => _nodes;
  12. public OutputNode? OutputNode => Nodes.OfType<OutputNode>().FirstOrDefault();
  13. IReadOnlyCollection<IReadOnlyNode> IReadOnlyNodeGraph.AllNodes => Nodes;
  14. IReadOnlyNode IReadOnlyNodeGraph.OutputNode => OutputNode;
  15. public void AddNode(Node node)
  16. {
  17. if (Nodes.Contains(node))
  18. {
  19. return;
  20. }
  21. _nodes.Add(node);
  22. }
  23. public void RemoveNode(Node node)
  24. {
  25. if (!Nodes.Contains(node))
  26. {
  27. return;
  28. }
  29. _nodes.Remove(node);
  30. }
  31. public Queue<IReadOnlyNode> CalculateExecutionQueue(IReadOnlyNode outputNode)
  32. {
  33. var finalQueue = new HashSet<IReadOnlyNode>();
  34. var queueNodes = new Queue<IReadOnlyNode>();
  35. queueNodes.Enqueue(outputNode);
  36. while (queueNodes.Count > 0)
  37. {
  38. var node = queueNodes.Dequeue();
  39. if (finalQueue.Contains(node))
  40. {
  41. continue;
  42. }
  43. bool canAdd = true;
  44. foreach (var input in node.InputProperties)
  45. {
  46. if (input.Connection == null)
  47. {
  48. continue;
  49. }
  50. if (finalQueue.Contains(input.Connection.Node))
  51. {
  52. continue;
  53. }
  54. canAdd = false;
  55. if (finalQueue.Contains(input.Connection.Node))
  56. {
  57. finalQueue.Remove(input.Connection.Node);
  58. finalQueue.Add(input.Connection.Node);
  59. }
  60. if (!queueNodes.Contains(input.Connection.Node))
  61. {
  62. queueNodes.Enqueue(input.Connection.Node);
  63. }
  64. }
  65. if (canAdd)
  66. {
  67. finalQueue.Add(node);
  68. }
  69. else
  70. {
  71. queueNodes.Enqueue(node);
  72. }
  73. }
  74. return new Queue<IReadOnlyNode>(finalQueue);
  75. }
  76. void IReadOnlyNodeGraph.AddNode(IReadOnlyNode node) => AddNode((Node)node);
  77. void IReadOnlyNodeGraph.RemoveNode(IReadOnlyNode node) => RemoveNode((Node)node);
  78. public void Dispose()
  79. {
  80. foreach (var node in Nodes)
  81. {
  82. node.Dispose();
  83. }
  84. }
  85. public bool TryTraverse(Action<IReadOnlyNode> action)
  86. {
  87. if(OutputNode == null) return false;
  88. var queue = CalculateExecutionQueue(OutputNode);
  89. while (queue.Count > 0)
  90. {
  91. var node = queue.Dequeue();
  92. action(node);
  93. }
  94. return true;
  95. }
  96. public Texture? Execute(RenderingContext context)
  97. {
  98. if (OutputNode == null) return null;
  99. var queue = CalculateExecutionQueue(OutputNode);
  100. while (queue.Count > 0)
  101. {
  102. var node = queue.Dequeue();
  103. if (node is Node typedNode)
  104. {
  105. typedNode.ExecuteInternal(context);
  106. }
  107. else
  108. {
  109. node.Execute(context);
  110. }
  111. }
  112. return OutputNode.Input.Value;
  113. }
  114. }