1 #define NOTIFICATION_VALIDATION
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
7 using UnityEditor.Experimental.GraphView;
8 using UnityEditor.Experimental.VFX;
10 using UnityEngine.Profiling;
12 using UnityObject = UnityEngine.Object;
13 using Branch = UnityEditor.VFX.Operator.VFXOperatorDynamicBranch;
15 namespace UnityEditor.VFX.UI
17 internal partial class VFXViewController : Controller<VisualEffectResource>
19 private int m_UseCount;
22 get { return m_UseCount; }
28 RemoveController(this);
33 public enum Priorities
47 get { return m_Name; }
54 string assetPath = AssetDatabase.GetAssetPath(model);
55 if (!string.IsNullOrEmpty(assetPath))
57 return Path.GetFileNameWithoutExtension(assetPath);
65 static HashSet<ScriptableObject>[] NewPrioritizedHashSet()
67 HashSet<ScriptableObject>[] result = new HashSet<ScriptableObject>[(int)Priorities.Count];
69 for (int i = 0; i < (int)Priorities.Count; ++i)
71 result[i] = new HashSet<ScriptableObject>();
77 Priorities GetPriority(VFXObject obj)
79 if (obj is IVFXSlotContainer)
81 return Priorities.Node;
85 return Priorities.Slot;
89 return Priorities.GroupNode;
93 return Priorities.Graph;
95 return Priorities.Default;
98 HashSet<ScriptableObject>[] modifiedModels = NewPrioritizedHashSet();
99 HashSet<ScriptableObject>[] otherModifiedModels = NewPrioritizedHashSet();
101 public void OnObjectModified(VFXObject obj)
103 modifiedModels[(int)GetPriority(obj)].Add(obj);
106 Dictionary<ScriptableObject, List<Action>> m_Notified = new Dictionary<ScriptableObject, List<Action>>();
109 public void RegisterNotification(VFXObject target, Action action)
114 target.onModified += OnObjectModified;
115 List<Action> notifieds;
116 if (m_Notified.TryGetValue(target, out notifieds))
118 #if NOTIFICATION_VALIDATION
119 if (notifieds.Contains(action))
120 Debug.LogError("Adding the same notification twice on:" + target.name);
122 notifieds.Add(action);
126 notifieds = new List<Action>();
127 notifieds.Add(action);
129 m_Notified.Add(target, notifieds);
133 public void UnRegisterNotification(VFXObject target, Action action)
135 if (object.ReferenceEquals(target, null))
138 target.onModified -= OnObjectModified;
139 List<Action> notifieds;
140 if (m_Notified.TryGetValue(target, out notifieds))
142 #if NOTIFICATION_VALIDATION
143 if (!notifieds.Contains(action))
144 Debug.LogError("Removing a non existent notification" + target.name);
146 notifieds.Remove(action);
148 if (m_CurrentlyNotified == target)
150 m_CurrentActions.Remove(action);
155 bool m_InNotify = false;
157 ScriptableObject m_CurrentlyNotified; //this and the next list are used when in case a notification removes a following modification
158 List<Action> m_CurrentActions = new List<Action>();
160 public void NotifyUpdate()
163 Profiler.BeginSample("VFXViewController.NotifyUpdate");
164 if (model == null || m_Graph == null || m_Graph != model.graph)
166 // In this case the asset has been destroyed or reimported after having changed outside.
167 // Lets rebuild everything and clear the undo stack.
169 if (model != null && model.graph != null)
170 InitializeUndoStack();
174 var tmp = modifiedModels;
175 modifiedModels = otherModifiedModels;
176 otherModifiedModels = tmp;
180 foreach (var objs in otherModifiedModels)
182 foreach (var obj in objs)
184 List<Action> notifieds;
185 Profiler.BeginSample("VFXViewController.Notify:" + obj.GetType().Name);
186 if (m_Notified.TryGetValue(obj, out notifieds))
188 m_CurrentlyNotified = obj;
189 m_CurrentActions.Clear();
190 m_CurrentActions.AddRange(notifieds);
191 m_CurrentActions.Reverse();
192 while (m_CurrentActions.Count > 0)
194 var action = m_CurrentActions[m_CurrentActions.Count - 1];
197 m_CurrentActions.RemoveAt(m_CurrentActions.Count - 1);
200 Profiler.EndSample();
202 m_CurrentlyNotified = null;
208 Debug.LogWarningFormat("{0} notification sent this frame", cpt);*/
209 Profiler.EndSample();
213 string newName = ComputeName();
214 if (newName != m_Name)
224 (graph as UnityObject).name = m_Name;
227 NotifyChange(Change.assetName);
230 if (m_DataEdgesMightHaveChangedAsked)
232 m_DataEdgesMightHaveChangedAsked = false;
233 DataEdgesMightHaveChanged();
237 public VFXGraph graph { get {return model != null ? model.graph as VFXGraph : null; }}
239 List<VFXFlowAnchorController> m_FlowAnchorController = new List<VFXFlowAnchorController>();
241 // Model / Controller synchronization
242 private Dictionary<VFXModel, List<VFXNodeController>> m_SyncedModels = new Dictionary<VFXModel, List<VFXNodeController>>();
244 List<VFXDataEdgeController> m_DataEdges = new List<VFXDataEdgeController>();
245 List<VFXFlowEdgeController> m_FlowEdges = new List<VFXFlowEdgeController>();
247 public override IEnumerable<Controller> allChildren
251 return m_SyncedModels.Values.SelectMany(t => t).Cast<Controller>().
252 Concat(m_DataEdges.Cast<Controller>()).
253 Concat(m_FlowEdges.Cast<Controller>()).
254 Concat(m_ParameterControllers.Values.Cast<Controller>()).
255 Concat(m_GroupNodeControllers.Cast<Controller>()).
256 Concat(m_StickyNoteControllers.Cast<Controller>())
261 public void LightApplyChanges()
267 public override void ApplyChanges()
272 foreach (var controller in allChildren)
274 controller.ApplyChanges();
281 if (!object.ReferenceEquals(m_Graph, null))
283 RemoveInvalidateDelegate(m_Graph, InvalidateExpressionGraph);
284 RemoveInvalidateDelegate(m_Graph, IncremenentGraphUndoRedoState);
286 UnRegisterNotification(m_Graph, GraphChanged);
290 if (!object.ReferenceEquals(m_UI, null))
292 UnRegisterNotification(m_UI, UIChanged);
297 public override void OnDisable()
299 Profiler.BeginSample("VFXViewController.OnDisable");
302 Undo.undoRedoPerformed -= SynchronizeUndoRedoState;
303 Undo.willFlushUndoRecord -= WillFlushUndoRecord;
306 Profiler.EndSample();
309 public IEnumerable<VFXNodeController> AllSlotContainerControllers
313 var operatorControllers = m_SyncedModels.Values.SelectMany(t => t).OfType<VFXNodeController>();
314 var blockControllers = (contexts.SelectMany(t => t.blockControllers)).Cast<VFXNodeController>();
316 return operatorControllers.Concat(blockControllers);
320 public bool RecreateNodeEdges()
322 bool changed = false;
323 HashSet<VFXDataEdgeController> unusedEdges = new HashSet<VFXDataEdgeController>();
324 foreach (var e in m_DataEdges)
329 var nodeToUpdate = new HashSet<VFXNodeController>();
331 foreach (var operatorControllers in m_SyncedModels.Values)
333 foreach (var nodeController in operatorControllers)
335 bool nodeChanged = false;
336 foreach (var input in nodeController.inputPorts)
338 nodeChanged |= RecreateInputSlotEdge(unusedEdges, nodeController, input);
340 if (nodeController is VFXContextController)
342 VFXContextController contextController = nodeController as VFXContextController;
344 foreach (var block in contextController.blockControllers)
346 bool blockChanged = false;
347 foreach (var input in block.inputPorts)
349 blockChanged |= RecreateInputSlotEdge(unusedEdges, block, input);
352 nodeToUpdate.Add(block);
353 changed |= blockChanged;
357 nodeToUpdate.Add(nodeController);
359 changed |= nodeChanged;
363 foreach (var edge in unusedEdges)
365 nodeToUpdate.Add(edge.input.sourceNode);
368 m_DataEdges.Remove(edge);
372 foreach (var node in nodeToUpdate)
374 node.UpdateAllEditable();
380 bool m_DataEdgesMightHaveChangedAsked;
382 public void DataEdgesMightHaveChanged()
384 if (m_Syncing) return;
388 m_DataEdgesMightHaveChangedAsked = true;
392 Profiler.BeginSample("VFXViewController.DataEdgesMightHaveChanged");
394 bool change = RecreateNodeEdges();
396 if (change || m_ForceDataEdgeNotification)
398 m_ForceDataEdgeNotification = false;
399 NotifyChange(Change.dataEdge);
402 Profiler.EndSample();
405 public bool RecreateInputSlotEdge(HashSet<VFXDataEdgeController> unusedEdges, VFXNodeController slotContainer, VFXDataAnchorController input)
407 VFXSlot inputSlot = input.model;
408 if (inputSlot == null)
411 bool changed = false;
414 VFXNodeController operatorControllerFrom = null;
416 IVFXSlotContainer targetSlotContainer = inputSlot.refSlot.owner;
417 if (targetSlotContainer == null)
421 if (targetSlotContainer is VFXParameter)
423 VFXParameterController controller = null;
424 if (m_ParameterControllers.TryGetValue(targetSlotContainer as VFXParameter, out controller))
426 operatorControllerFrom = controller.GetParameterForLink(inputSlot);
429 else if (targetSlotContainer is VFXBlock)
431 VFXBlock block = targetSlotContainer as VFXBlock;
432 VFXContext context = block.GetParent();
433 List<VFXNodeController> contextControllers = null;
434 if (m_SyncedModels.TryGetValue(context, out contextControllers) && contextControllers.Count > 0)
436 operatorControllerFrom = (contextControllers[0] as VFXContextController).blockControllers.FirstOrDefault(t => t.model == block);
441 List<VFXNodeController> nodeControllers = null;
442 if (m_SyncedModels.TryGetValue(targetSlotContainer as VFXModel, out nodeControllers) && nodeControllers.Count > 0)
444 operatorControllerFrom = nodeControllers[0];
448 var operatorControllerTo = slotContainer;
450 if (operatorControllerFrom != null && operatorControllerTo != null)
452 var anchorFrom = operatorControllerFrom.outputPorts.FirstOrDefault(o => (o as VFXDataAnchorController).model == inputSlot.refSlot);
453 var anchorTo = input;
455 var edgController = m_DataEdges.FirstOrDefault(t => t.input == anchorTo && t.output == anchorFrom);
457 if (edgController != null)
459 unusedEdges.Remove(edgController);
463 if (anchorFrom != null && anchorTo != null)
465 edgController = new VFXDataEdgeController(anchorTo, anchorFrom);
466 m_DataEdges.Add(edgController);
473 foreach (VFXSlot subSlot in inputSlot.children)
475 VFXDataAnchorController subAnchor = slotContainer.inputPorts.FirstOrDefault(t => t.model == subSlot);
476 if (subAnchor != null) // Can be null for example for hidden values from Vector3Spaceables
478 changed |= RecreateInputSlotEdge(unusedEdges, slotContainer, subAnchor);
485 public IEnumerable<VFXContextController> contexts
487 get { return m_SyncedModels.Values.SelectMany(t => t).OfType<VFXContextController>(); }
489 public IEnumerable<VFXNodeController> nodes
491 get { return m_SyncedModels.Values.SelectMany(t => t); }
494 public void FlowEdgesMightHaveChanged()
496 if (m_Syncing) return;
498 bool change = RecreateFlowEdges();
501 UpdateSystems(); // System will change based on flowEdges
502 NotifyChange(Change.flowEdge);
508 public const int flowEdge = 1;
509 public const int dataEdge = 2;
511 public const int groupNode = 3;
513 public const int assetName = 4;
515 public const int ui = 5;
517 public const int destroy = 666;
520 bool RecreateFlowEdges()
522 bool changed = false;
523 HashSet<VFXFlowEdgeController> unusedEdges = new HashSet<VFXFlowEdgeController>();
524 foreach (var e in m_FlowEdges)
529 var contextControllers = contexts;
530 foreach (var outController in contextControllers.ToArray())
532 var output = outController.model;
533 for (int slotIndex = 0; slotIndex < output.inputFlowSlot.Length; ++slotIndex)
535 var inputFlowSlot = output.inputFlowSlot[slotIndex];
536 foreach (var link in inputFlowSlot.link)
538 var inController = contexts.FirstOrDefault(x => x.model == link.context);
539 if (inController == null)
542 var outputAnchor = inController.flowOutputAnchors.Where(o => o.slotIndex == link.slotIndex).FirstOrDefault();
543 var inputAnchor = outController.flowInputAnchors.Where(o => o.slotIndex == slotIndex).FirstOrDefault();
545 var edgeController = m_FlowEdges.FirstOrDefault(t => t.input == inputAnchor && t.output == outputAnchor);
546 if (edgeController != null)
547 unusedEdges.Remove(edgeController);
550 edgeController = new VFXFlowEdgeController(inputAnchor, outputAnchor);
551 m_FlowEdges.Add(edgeController);
558 foreach (var edge in unusedEdges)
561 m_FlowEdges.Remove(edge);
568 public ReadOnlyCollection<VFXDataEdgeController> dataEdges
570 get { return m_DataEdges.AsReadOnly(); }
572 public ReadOnlyCollection<VFXFlowEdgeController> flowEdges
574 get { return m_FlowEdges.AsReadOnly(); }
577 public bool CreateLink(VFXDataAnchorController input, VFXDataAnchorController output)
584 if( input.sourceNode.viewController != output.sourceNode.viewController)
589 if (!input.CanLink(output))
594 VFXParameter.NodeLinkedSlot resulting = input.CreateLinkTo(output);
596 if (resulting.inputSlot != null && resulting.outputSlot != null)
598 VFXParameterNodeController fromController = output.sourceNode as VFXParameterNodeController;
599 if (fromController != null)
601 if (fromController.infos.linkedSlots == null)
602 fromController.infos.linkedSlots = new List<VFXParameter.NodeLinkedSlot>();
603 fromController.infos.linkedSlots.Add(resulting);
606 VFXParameterNodeController toController = input.sourceNode as VFXParameterNodeController;
607 if( toController != null)
609 var infos = toController.infos;
610 if (infos.linkedSlots == null)
611 infos.linkedSlots = new List<VFXParameter.NodeLinkedSlot>();
612 infos.linkedSlots.Add(resulting);
615 DataEdgesMightHaveChanged();
621 public void AddElement(VFXDataEdgeController edge)
623 var fromAnchor = edge.output;
624 var toAnchor = edge.input;
626 CreateLink(toAnchor, fromAnchor);
630 public void AddElement(VFXFlowEdgeController edge)
632 var flowEdge = (VFXFlowEdgeController)edge;
634 var outputFlowAnchor = flowEdge.output as VFXFlowAnchorController;
635 var inputFlowAnchor = flowEdge.input as VFXFlowAnchorController;
637 var contextOutput = outputFlowAnchor.owner;
638 var contextInput = inputFlowAnchor.owner;
640 contextOutput.LinkTo(contextInput, outputFlowAnchor.slotIndex, inputFlowAnchor.slotIndex);
645 public void Remove(IEnumerable<Controller> removedControllers, bool explicitDelete = false)
647 removedControllers = removedControllers.Except(removedControllers.OfType<VFXContextController>().Where(t => t.model is VFXBlockSubgraphContext)); //refuse to delete VFXBlockSubgraphContext
649 var removedContexts = new HashSet<VFXContextController>(removedControllers.OfType<VFXContextController>());
651 //remove all blocks that are in a removed context.
652 var removed = removedControllers.Where(t => !(t is VFXBlockController) || !removedContexts.Contains((t as VFXBlockController).contextController)).Distinct().ToArray();
654 foreach (var controller in removed)
656 RemoveElement(controller, explicitDelete);
660 bool m_ForceDataEdgeNotification;
662 public void RemoveElement(Controller element, bool explicitDelete = false)
664 if (element is VFXContextController)
666 VFXContextController contextController = ((VFXContextController)element);
667 VFXContext context = contextController.model;
668 contextController.NodeGoingToBeRemoved();
670 // Remove connections from context
671 foreach (var slot in context.inputSlots.Concat(context.outputSlots))
672 slot.UnlinkAll(true, true);
674 // Remove connections from blocks
675 foreach (VFXBlockController blockPres in (element as VFXContextController).blockControllers)
677 foreach (var slot in blockPres.slotContainer.outputSlots.Concat(blockPres.slotContainer.inputSlots))
679 slot.UnlinkAll(true, true);
683 // remove flow connections from context
684 // TODO update data types
689 RemoveFromGroupNodes(element as VFXNodeController);
691 UnityObject.DestroyImmediate(context, true);
693 else if (element is VFXBlockController)
695 var block = element as VFXBlockController;
696 block.NodeGoingToBeRemoved();
697 block.contextController.RemoveBlock(block.model);
699 UnityObject.DestroyImmediate(block.model, true);
701 else if (element is VFXParameterNodeController)
703 var parameter = element as VFXParameterNodeController;
704 parameter.NodeGoingToBeRemoved();
705 parameter.parentController.model.RemoveNode(parameter.infos);
706 RemoveFromGroupNodes(element as VFXNodeController);
707 DataEdgesMightHaveChanged();
709 else if (element is VFXNodeController || element is VFXParameterController)
711 IVFXSlotContainer container = null;
713 if (element is VFXNodeController)
715 VFXNodeController nodeController = (element as VFXNodeController);
716 container = nodeController.model as IVFXSlotContainer;
717 nodeController.NodeGoingToBeRemoved();
718 RemoveFromGroupNodes(element as VFXNodeController);
722 container = (element as VFXParameterController).model;
724 foreach (var parameterNode in m_SyncedModels[container as VFXModel])
726 RemoveFromGroupNodes(parameterNode);
730 VFXSlot slotToClean = null;
733 slotToClean = container.inputSlots.Concat(container.outputSlots)
734 .FirstOrDefault(o => o.HasLink(true));
737 slotToClean.UnlinkAll(true, true);
740 while (slotToClean != null);
742 graph.RemoveChild(container as VFXModel);
744 UnityObject.DestroyImmediate(container as VFXModel, true);
745 DataEdgesMightHaveChanged();
747 else if (element is VFXFlowEdgeController)
749 var flowEdge = element as VFXFlowEdgeController;
752 var inputAnchor = flowEdge.input as VFXFlowAnchorController;
753 var outputAnchor = flowEdge.output as VFXFlowAnchorController;
755 if (inputAnchor != null && outputAnchor != null)
757 var contextInput = inputAnchor.owner as VFXContext;
758 var contextOutput = outputAnchor.owner as VFXContext;
760 if (contextInput != null && contextOutput != null)
761 contextInput.UnlinkFrom(contextOutput, outputAnchor.slotIndex, inputAnchor.slotIndex);
764 else if (element is VFXDataEdgeController)
766 var edge = element as VFXDataEdgeController;
767 var to = edge.input as VFXDataAnchorController;
773 to.sourceNode.OnEdgeFromInputGoingToBeRemoved(to);
774 edge.output.sourceNode.OnEdgeFromOutputGoingToBeRemoved(edge.output,edge.input);
781 m_ForceDataEdgeNotification = true;
784 else if (element is VFXGroupNodeController)
786 RemoveGroupNode(element as VFXGroupNodeController);
788 else if (element is VFXStickyNoteController)
790 RemoveStickyNote(element as VFXStickyNoteController);
794 Debug.LogErrorFormat("Unexpected type : {0}", element.GetType().FullName);
798 protected override void ModelChanged(UnityObject obj)
802 NotifyChange(Change.destroy);
805 RemoveController(this);
809 // a standard equals will return true is the m_Graph is a destroyed object with the same instance ID ( like with a source control revert )
810 if (!object.ReferenceEquals(m_Graph, model.GetOrCreateGraph()))
812 if (!object.ReferenceEquals(m_Graph, null))
814 UnRegisterNotification(m_Graph, GraphChanged);
815 UnRegisterNotification(m_UI, UIChanged);
825 m_Graph = model.GetOrCreateGraph();
826 m_Graph.SanitizeGraph();
830 RegisterNotification(m_Graph, GraphChanged);
832 AddInvalidateDelegate(m_Graph, InvalidateExpressionGraph);
833 AddInvalidateDelegate(m_Graph, IncremenentGraphUndoRedoState);
836 m_UI = m_Graph.UIInfos;
838 RegisterNotification(m_UI, UIChanged);
845 public void AddGroupNode(Vector2 pos)
847 PrivateAddGroupNode(pos);
849 m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
852 public void AddStickyNote(Vector2 position, VFXGroupNodeController group)
854 var ui = graph.UIInfos;
856 var stickyNoteInfo = new VFXUI.StickyNoteInfo
859 position = new Rect(position, Vector2.one * 100),
860 contents = "type something here",
861 theme = StickyNote.Theme.Classic.ToString(),
862 textSize = StickyNote.TextSize.Small.ToString()
865 if (ui.stickyNoteInfos != null)
866 ui.stickyNoteInfos = ui.stickyNoteInfos.Concat(Enumerable.Repeat(stickyNoteInfo, 1)).ToArray();
868 ui.stickyNoteInfos = new VFXUI.StickyNoteInfo[] { stickyNoteInfo };
874 group.AddStickyNote(m_StickyNoteControllers[ui.stickyNoteInfos.Length - 1]);
877 m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
880 void RemoveGroupNode(VFXGroupNodeController groupNode)
882 var ui = graph.UIInfos;
884 int index = groupNode.index;
886 ui.groupInfos = ui.groupInfos.Where((t, i) => i != index).ToArray();
889 m_GroupNodeControllers.RemoveAt(index);
891 for (int i = index; i < m_GroupNodeControllers.Count; ++i)
893 m_GroupNodeControllers[i].index = i;
895 m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
898 void RemoveStickyNote(VFXStickyNoteController stickyNote)
900 var ui = graph.UIInfos;
902 int index = stickyNote.index;
904 ui.stickyNoteInfos = ui.stickyNoteInfos.Where((t, i) => i != index).ToArray();
907 m_StickyNoteControllers.RemoveAt(index);
909 for (int i = index; i < m_StickyNoteControllers.Count; ++i)
911 m_StickyNoteControllers[i].index = i;
914 //Patch group nodes, removing this sticky note and fixing ids that are bigger than index
915 if (ui.groupInfos != null)
917 for (int i = 0; i < ui.groupInfos.Length; ++i)
919 for (int j = 0; j < ui.groupInfos[i].contents.Length; ++j)
921 if (ui.groupInfos[i].contents[j].isStickyNote)
923 if (ui.groupInfos[i].contents[j].id == index)
925 ui.groupInfos[i].contents = ui.groupInfos[i].contents.Where((t, idx) => idx != j).ToArray();
928 else if (ui.groupInfos[i].contents[j].id > index)
930 --(ui.groupInfos[i].contents[j].id);
937 m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
940 void RemoveFromGroupNodes(VFXNodeController node)
942 foreach (var groupNode in m_GroupNodeControllers)
944 if (groupNode.ContainsNode(node))
946 groupNode.RemoveNode(node);
951 protected void GraphChanged()
962 VFXGraphValidation validation = new VFXGraphValidation(m_Graph);
963 validation.ValidateGraph();
965 bool groupNodeChanged = false;
967 Profiler.BeginSample("VFXViewController.GraphChanged:SyncControllerFromModel");
968 SyncControllerFromModel(ref groupNodeChanged);
969 Profiler.EndSample();
971 Profiler.BeginSample("VFXViewController.GraphChanged:NotifyChange(AnyThing)");
972 NotifyChange(AnyThing);
973 Profiler.EndSample();
975 //if( groupNodeChanged)
977 Profiler.BeginSample("VFXViewController.GraphChanged:NotifyChange(Change.groupNode)");
978 NotifyChange(Change.groupNode);
979 Profiler.EndSample();
983 protected void UIChanged()
985 if (m_UI == null) return;
986 if (m_Graph == null) return; // OnModelChange or OnDisable will take care of that later
988 bool groupNodeChanged = false;
989 RecreateUI(ref groupNodeChanged);
991 NotifyChange(Change.ui);
994 public void NotifyParameterControllerChange()
996 DataEdgesMightHaveChanged();
998 NotifyChange(AnyThing);
1001 public void RegisterFlowAnchorController(VFXFlowAnchorController controller)
1003 if (!m_FlowAnchorController.Contains(controller))
1004 m_FlowAnchorController.Add(controller);
1007 public void UnregisterFlowAnchorController(VFXFlowAnchorController controller)
1009 m_FlowAnchorController.Remove(controller);
1012 public static void CollectAncestorOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashParents)
1014 foreach (var slotInput in operatorInput.inputSlots)
1016 var linkedSlots = slotInput.AllChildrenWithLink();
1017 foreach (var linkedSlot in linkedSlots)
1019 RecurseCollectAncestorOperator(linkedSlot.refSlot.owner, hashParents);
1024 public static void RecurseCollectAncestorOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashParents)
1026 if (hashParents.Contains(operatorInput))
1029 hashParents.Add(operatorInput);
1031 foreach (var slotInput in operatorInput.inputSlots)
1033 var linkedSlots = slotInput.AllChildrenWithLink();
1034 foreach (var linkedSlot in linkedSlots)
1036 RecurseCollectAncestorOperator(linkedSlot.refSlot.owner, hashParents);
1041 public static void CollectDescendantOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashChildren)
1043 foreach (var slotOutput in operatorInput.outputSlots)
1045 var linkedSlots = slotOutput.AllChildrenWithLink();
1046 foreach (var linkedSlot in linkedSlots)
1048 foreach (var link in linkedSlot.LinkedSlots)
1050 RecurseCollectDescendantOperator(link.owner, hashChildren);
1056 public static void RecurseCollectDescendantOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashChildren)
1058 if (hashChildren.Contains(operatorInput))
1061 hashChildren.Add(operatorInput);
1062 foreach (var slotOutput in operatorInput.outputSlots)
1064 var linkedSlots = slotOutput.AllChildrenWithLink();
1065 foreach (var linkedSlot in linkedSlots)
1067 foreach (var link in linkedSlot.LinkedSlots)
1069 RecurseCollectDescendantOperator(link.owner, hashChildren);
1075 public IEnumerable<VFXDataAnchorController> GetCompatiblePorts(VFXDataAnchorController startAnchorController, NodeAdapter nodeAdapter)
1077 var cacheLinkData = new VFXDataAnchorController.CanLinkCache();
1079 var direction = startAnchorController.direction;
1080 foreach (var slotContainer in AllSlotContainerControllers)
1082 var sourceSlot = direction == Direction.Input ? slotContainer.outputPorts : slotContainer.inputPorts;
1083 foreach (var slot in sourceSlot)
1085 if (startAnchorController.CanLink(slot, cacheLinkData))
1093 public List<VFXFlowAnchorController> GetCompatiblePorts(VFXFlowAnchorController startAnchorController, NodeAdapter nodeAdapter)
1095 var res = new List<VFXFlowAnchorController>();
1097 var startFlowAnchorController = (VFXFlowAnchorController)startAnchorController;
1098 foreach (var anchorController in m_FlowAnchorController)
1100 VFXContext owner = anchorController.owner;
1101 if (owner == null ||
1102 startAnchorController == anchorController ||
1103 startAnchorController.direction == anchorController.direction ||
1104 owner == startFlowAnchorController.owner)
1107 if (startAnchorController.direction == Direction.Input)
1109 if (VFXFlowAnchorController.CanLink(anchorController, startFlowAnchorController))
1110 res.Add(anchorController);
1114 if (VFXFlowAnchorController.CanLink(startFlowAnchorController, anchorController))
1115 res.Add(anchorController);
1121 public void AddVFXModel(Vector2 pos, VFXModel model)
1123 model.position = pos;
1124 this.graph.AddChild(model);
1127 public VFXContext AddVFXContext(Vector2 pos, VFXModelDescriptor<VFXContext> desc)
1129 VFXContext model = desc.CreateInstance();
1130 AddVFXModel(pos, model);
1134 public VFXOperator AddVFXOperator(Vector2 pos, VFXModelDescriptor<VFXOperator> desc)
1136 var model = desc.CreateInstance();
1137 AddVFXModel(pos, model);
1141 public VFXParameter AddVFXParameter(Vector2 pos, VFXModelDescriptorParameters desc)
1143 var model = desc.CreateInstance();
1144 AddVFXModel(pos, model);
1146 VFXParameter parameter = model as VFXParameter;
1148 Type type = parameter.type;
1150 parameter.collapsed = true;
1153 if (m_ParameterControllers.Count > 0)
1155 order = m_ParameterControllers.Keys.Select(t => t.order).Max() + 1;
1157 parameter.order = order;
1158 parameter.SetSettingValue("m_ExposedName", string.Format("New {0}", type.UserFriendlyName()));
1160 if (!type.IsPrimitive)
1162 parameter.value = VFXTypeExtension.GetDefaultField(type);
1168 public VFXNodeController AddNode(Vector2 tPos, object modelDescriptor, VFXGroupNodeController groupNode)
1170 VFXModel newNode = null;
1171 if (modelDescriptor is VFXModelDescriptor<VFXOperator>)
1173 newNode = AddVFXOperator(tPos, (modelDescriptor as VFXModelDescriptor<VFXOperator>));
1175 else if (modelDescriptor is VFXModelDescriptor<VFXContext>)
1177 newNode = AddVFXContext(tPos, modelDescriptor as VFXModelDescriptor<VFXContext>);
1179 else if (modelDescriptor is VFXModelDescriptorParameters)
1181 newNode = AddVFXParameter(tPos, modelDescriptor as VFXModelDescriptorParameters);
1183 if (newNode != null)
1185 bool groupNodeChanged = false;
1186 SyncControllerFromModel(ref groupNodeChanged);
1188 List<VFXNodeController> nodeControllers = null;
1189 m_SyncedModels.TryGetValue(newNode, out nodeControllers);
1191 if (newNode is VFXParameter)
1193 // Set an exposed name on a new parameter so that uncity is ensured
1194 VFXParameter newParameter = newNode as VFXParameter;
1195 m_ParameterControllers[newParameter].exposedName = string.Format("New {0}", newParameter.type.UserFriendlyName());
1198 NotifyChange(AnyThing);
1200 if (groupNode != null)
1202 groupNode.AddNode(nodeControllers.First());
1205 return nodeControllers[0];
1211 public VFXNodeController AddVFXParameter(Vector2 pos, VFXParameterController parameterController, VFXGroupNodeController groupNode)
1213 if( parameterController.isOutput && parameterController.nodeCount > 0)
1215 return parameterController.nodes.First();
1217 int id = parameterController.model.AddNode(pos);
1219 LightApplyChanges();
1221 var nodeController = GetRootNodeController(parameterController.model, id);
1223 if (groupNode != null)
1225 if (nodeController != null)
1227 groupNode.AddNode(nodeController);
1231 return nodeController;
1236 foreach (var element in allChildren)
1238 element.OnDisable();
1241 m_FlowAnchorController.Clear();
1242 m_SyncedModels.Clear();
1243 m_ParameterControllers.Clear();
1244 m_DataEdges.Clear();
1245 m_FlowEdges.Clear();
1246 m_GroupNodeControllers.Clear();
1247 m_StickyNoteControllers.Clear();
1250 private Dictionary<VFXModel, List<VFXModel.InvalidateEvent>> m_registeredEvent = new Dictionary<VFXModel, List<VFXModel.InvalidateEvent>>();
1251 public void AddInvalidateDelegate(VFXModel model, VFXModel.InvalidateEvent evt)
1253 model.onInvalidateDelegate += evt;
1254 if (!m_registeredEvent.ContainsKey(model))
1256 m_registeredEvent.Add(model, new List<VFXModel.InvalidateEvent>());
1258 m_registeredEvent[model].Add(evt);
1261 public void RemoveInvalidateDelegate(VFXModel model, VFXModel.InvalidateEvent evt)
1263 List<VFXModel.InvalidateEvent> evtList;
1264 if (model != null && m_registeredEvent.TryGetValue(model, out evtList))
1266 model.onInvalidateDelegate -= evt;
1267 evtList.Remove(evt);
1268 if (evtList.Count == 0)
1270 m_registeredEvent.Remove(model);
1275 static Dictionary<VisualEffectResource, VFXViewController> s_Controllers = new Dictionary<VisualEffectResource, VFXViewController>();
1277 public static VFXViewController GetController(VisualEffectResource resource, bool forceUpdate = false)
1279 //TRANSITION : delete VFXAsset as it should be in Library
1280 resource.ValidateAsset();
1282 VFXViewController controller;
1283 if (!s_Controllers.TryGetValue(resource, out controller))
1285 controller = new VFXViewController(resource);
1286 s_Controllers[resource] = controller;
1292 controller.ForceReload();
1299 static void RemoveController(VFXViewController controller)
1301 if (s_Controllers.ContainsKey(controller.model))
1303 controller.OnDisable();
1304 s_Controllers.Remove(controller.model);
1308 VFXViewController(VisualEffectResource vfx) : base(vfx)
1310 ModelChanged(vfx); // This will initialize the graph from the vfx asset.
1312 if (m_FlowAnchorController == null)
1313 m_FlowAnchorController = new List<VFXFlowAnchorController>();
1315 Undo.undoRedoPerformed += SynchronizeUndoRedoState;
1316 Undo.willFlushUndoRecord += WillFlushUndoRecord;
1318 string fileName = System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(vfx));
1319 vfx.name = fileName;
1321 if (m_Graph != null)
1322 m_Graph.BuildParameterInfo();
1325 InitializeUndoStack();
1333 VFXParameter[] parameters = m_ParameterControllers.Keys.OrderBy(t => t.order).ToArray();
1334 if (parameters.Length > 0)
1336 var existingNames = new HashSet<string>();
1338 existingNames.Add(parameters[0].exposedName);
1339 m_ParameterControllers[parameters[0]].order = 0;
1341 for (int i = 1; i < parameters.Length; ++i)
1343 var controller = m_ParameterControllers[parameters[i]];
1344 controller.order = i;
1346 controller.CheckNameUnique(existingNames);
1348 existingNames.Add(parameters[i].exposedName);
1353 public ReadOnlyCollection<VFXGroupNodeController> groupNodes
1355 get {return m_GroupNodeControllers.AsReadOnly(); }
1357 public ReadOnlyCollection<VFXStickyNoteController> stickyNotes
1359 get {return m_StickyNoteControllers.AsReadOnly(); }
1362 List<VFXGroupNodeController> m_GroupNodeControllers = new List<VFXGroupNodeController>();
1363 List<VFXStickyNoteController> m_StickyNoteControllers = new List<VFXStickyNoteController>();
1365 public bool RecreateUI(ref bool groupNodeChanged)
1367 bool changed = false;
1368 var ui = graph.UIInfos;
1370 if (ui.groupInfos != null)
1372 HashSet<VFXNodeID> usedNodeIds = new HashSet<VFXNodeID>();
1373 // first make sure that nodesID are at most in one groupnode.
1375 for (int i = 0; i < ui.groupInfos.Length; ++i)
1377 if (ui.groupInfos[i].contents != null)
1379 for (int j = 0; j < ui.groupInfos[i].contents.Length; ++j)
1381 if (usedNodeIds.Contains(ui.groupInfos[i].contents[j]))
1383 Debug.Log("Element present in multiple groupnodes");
1385 ui.groupInfos[i].contents = ui.groupInfos[i].contents.Where((t, k) => k != j).ToArray();
1389 usedNodeIds.Add(ui.groupInfos[i].contents[j]);
1395 for (int i = m_GroupNodeControllers.Count; i < ui.groupInfos.Length; ++i)
1397 VFXGroupNodeController groupNodeController = new VFXGroupNodeController(this, ui, i);
1398 m_GroupNodeControllers.Add(groupNodeController);
1400 groupNodeChanged = true;
1403 while (ui.groupInfos.Length < m_GroupNodeControllers.Count)
1405 m_GroupNodeControllers.Last().OnDisable();
1406 m_GroupNodeControllers.RemoveAt(m_GroupNodeControllers.Count - 1);
1408 groupNodeChanged = true;
1411 if (ui.stickyNoteInfos != null)
1413 for (int i = m_StickyNoteControllers.Count; i < ui.stickyNoteInfos.Length; ++i)
1415 VFXStickyNoteController stickyNoteController = new VFXStickyNoteController(this, ui, i);
1416 m_StickyNoteControllers.Add(stickyNoteController);
1417 stickyNoteController.ApplyChanges();
1421 while (ui.stickyNoteInfos.Length < m_StickyNoteControllers.Count)
1423 m_StickyNoteControllers.Last().OnDisable();
1424 m_StickyNoteControllers.RemoveAt(m_StickyNoteControllers.Count - 1);
1432 public void ValidateCategoryList()
1436 var ui = graph.UIInfos;
1437 // Validate category list
1438 var categories = ui.categories != null ? ui.categories : new List<VFXUI.CategoryInfo>();
1440 string[] missingCategories = m_ParameterControllers.Select(t => t.Key.category).Where(t => !string.IsNullOrEmpty(t)).Except(categories.Select(t => t.name)).ToArray();
1442 HashSet<string> foundCategories = new HashSet<string>();
1444 for (int i = 0; i < categories.Count; ++i)
1446 string category = categories[i].name;
1447 if (string.IsNullOrEmpty(category) || foundCategories.Contains(category))
1449 categories.RemoveAt(i);
1452 foundCategories.Add(category);
1455 if (missingCategories.Length > 0)
1457 categories.AddRange(missingCategories.Select(t => new VFXUI.CategoryInfo { name = t}));
1458 ui.categories = categories;
1464 public void ForceReload()
1467 ModelChanged(model);
1473 public bool SyncControllerFromModel(ref bool groupNodeChanged)
1476 bool changed = false;
1477 var toRemove = m_SyncedModels.Keys.Except(graph.children).ToList();
1478 foreach (var m in toRemove)
1480 RemoveControllersFromModel(m);
1484 var toAdd = graph.children.Except(m_SyncedModels.Keys).ToList();
1485 foreach (var m in toAdd)
1487 AddControllersFromModel(m);
1492 // make sure every parameter instance is created before we look for edges
1493 foreach (var parameter in m_ParameterControllers.Values)
1495 parameter.UpdateControllers();
1498 changed |= RecreateNodeEdges();
1499 changed |= RecreateFlowEdges();
1501 changed |= RecreateUI(ref groupNodeChanged);
1504 ValidateCategoryList();
1509 Dictionary<VFXParameter, VFXParameterController> m_ParameterControllers = new Dictionary<VFXParameter, VFXParameterController>();
1511 public IEnumerable<VFXParameterController> parameterControllers
1513 get { return m_ParameterControllers.Values; }
1517 public void MoveCategory(string category, int index)
1519 if (graph.UIInfos.categories == null)
1521 int oldIndex = graph.UIInfos.categories.FindIndex(t => t.name == category);
1523 if (oldIndex == -1 || oldIndex == index)
1525 graph.UIInfos.categories.RemoveAt(oldIndex);
1526 if (index < graph.UIInfos.categories.Count)
1527 graph.UIInfos.categories.Insert(index, new VFXUI.CategoryInfo { name = category });
1529 graph.UIInfos.categories.Add(new VFXUI.CategoryInfo { name = category });
1531 graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1534 public bool SetCategoryName(int category, string newName)
1536 if (category >= 0 && graph.UIInfos.categories != null && category < graph.UIInfos.categories.Count)
1538 if (graph.UIInfos.categories[category].name == newName)
1542 if (!graph.UIInfos.categories.Any(t => t.name == newName))
1544 var oldName = graph.UIInfos.categories[category].name;
1545 var catInfo = graph.UIInfos.categories[category];
1546 catInfo.name = newName;
1547 graph.UIInfos.categories[category] = catInfo;
1549 foreach (var parameter in m_ParameterControllers)
1551 if (parameter.Key.category == oldName)
1553 parameter.Key.category = newName;
1558 graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1563 Debug.LogError("Can't change name, category with the same name already exists");
1568 Debug.LogError("Can't change name, category not found");
1574 public void RemoveCategory(string name)
1576 int index = graph.UIInfos.categories.FindIndex(t => t.name == name);
1580 var parametersToRemove = RemoveCategory(index);
1582 Remove(parametersToRemove.Cast<Controller>());
1586 public IEnumerable<VFXParameterController> RemoveCategory(int category)
1588 if (category >= 0 && graph.UIInfos.categories != null && category < graph.UIInfos.categories.Count)
1590 string name = graph.UIInfos.categories[category].name;
1592 graph.UIInfos.categories.RemoveAt(category);
1593 graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1595 return m_ParameterControllers.Values.Where(t => t.model.category == name);
1597 return Enumerable.Empty<VFXParameterController>();
1600 // The default version
1601 public void SetParametersOrder(VFXParameterController controller, int index, bool input)
1603 controller.model.category = string.Empty;
1604 var orderedParameters = m_ParameterControllers.Where(t => t.Value.isOutput == !input).OrderBy(t => t.Value.order).Select(t => t.Value).ToList();
1606 int oldIndex = orderedParameters.IndexOf(controller);
1610 orderedParameters.RemoveAt(oldIndex);
1612 if (oldIndex < index)
1616 controller.isOutput = !input;
1618 if (index < orderedParameters.Count)
1619 orderedParameters.Insert(index, controller);
1621 orderedParameters.Add(controller);
1623 for (int i = 0; i < orderedParameters.Count; ++i)
1625 orderedParameters[i].order = i;
1627 NotifyChange(AnyThing);
1630 //The category version
1631 public void SetParametersOrder(VFXParameterController controller, int index, string category)
1633 controller.isOutput = false;
1634 var orderedParameters = m_ParameterControllers.Where(t => t.Key.category == category).OrderBy(t => t.Value.order).Select(t => t.Value).ToList();
1636 int oldIndex = orderedParameters.IndexOf(controller);
1641 orderedParameters.RemoveAt(oldIndex);
1643 if (oldIndex < index)
1649 controller.model.category = category;
1651 if (index < orderedParameters.Count)
1653 orderedParameters.Insert(index, controller);
1657 orderedParameters.Add(controller);
1660 for (int i = 0; i < orderedParameters.Count; ++i)
1662 orderedParameters[i].order = i;
1664 NotifyChange(AnyThing);
1667 public void SetCategoryExpanded(string category, bool expanded)
1669 if (graph.UIInfos.categories != null)
1671 for (int i = 0; i < graph.UIInfos.categories.Count; ++i)
1673 if (graph.UIInfos.categories[i].name == category)
1675 graph.UIInfos.categories[i] = new VFXUI.CategoryInfo { name = category, collapsed = !expanded };
1679 NotifyChange(AnyThing);
1682 private void AddControllersFromModel(VFXModel model)
1684 List<VFXNodeController> newControllers = new List<VFXNodeController>();
1685 if (model is VFXOperator)
1687 if (model is VFXOperatorNumericCascadedUnified)
1688 newControllers.Add(new VFXCascadedOperatorController(model as VFXOperator, this));
1689 else if (model is VFXOperatorNumericUniform)
1691 newControllers.Add(new VFXNumericUniformOperatorController(model as VFXOperator, this));
1693 else if (model is VFXOperatorNumericUnified)
1695 if (model is IVFXOperatorNumericUnifiedConstrained)
1696 newControllers.Add(new VFXUnifiedConstraintOperatorController(model as VFXOperator, this));
1698 newControllers.Add(new VFXUnifiedOperatorController(model as VFXOperator, this));
1700 else if (model is Branch)
1702 newControllers.Add(new VFXBranchOperatorController(model as VFXOperator, this));
1705 newControllers.Add(new VFXOperatorController(model as VFXOperator, this));
1707 else if (model is VFXContext)
1709 newControllers.Add(new VFXContextController(model as VFXContext, this));
1711 else if (model is VFXParameter)
1713 VFXParameter parameter = model as VFXParameter;
1715 if ( parameter.isOutput)
1717 if(parameter.GetNbInputSlots() < 1)
1719 parameter.AddSlot(VFXSlot.Create(new VFXProperty(typeof(float),"i"),VFXSlot.Direction.kInput));
1721 while (parameter.GetNbInputSlots() > 1)
1723 parameter.RemoveSlot(parameter.inputSlots[1]);
1725 while (parameter.GetNbOutputSlots() > 0)
1727 parameter.RemoveSlot(parameter.outputSlots[0]);
1732 if (parameter.GetNbOutputSlots() < 1)
1734 parameter.AddSlot(VFXSlot.Create(new VFXProperty(typeof(float), "o"), VFXSlot.Direction.kOutput));
1736 while (parameter.GetNbOutputSlots() > 1)
1738 parameter.RemoveSlot(parameter.outputSlots[1]);
1740 while (parameter.GetNbInputSlots() > 0)
1742 parameter.RemoveSlot(parameter.inputSlots[0]);
1746 parameter.ValidateNodes();
1748 m_ParameterControllers[parameter] = new VFXParameterController(parameter, this);
1750 m_SyncedModels[model] = new List<VFXNodeController>();
1753 if (newControllers.Count > 0)
1755 List<VFXNodeController> existingControllers;
1756 if (m_SyncedModels.TryGetValue(model, out existingControllers))
1758 Debug.LogError("adding a model to controllers twice");
1760 m_SyncedModels[model] = newControllers;
1761 foreach (var controller in newControllers)
1763 controller.ForceUpdate();
1768 public void AddControllerToModel(VFXModel model, VFXNodeController controller)
1770 m_SyncedModels[model].Add(controller);
1773 public void RemoveControllerFromModel(VFXModel model, VFXNodeController controller)
1775 m_SyncedModels[model].Remove(controller);
1778 private void RemoveControllersFromModel(VFXModel model)
1780 List<VFXNodeController> controllers = null;
1781 if (m_SyncedModels.TryGetValue(model, out controllers))
1783 foreach (var controller in controllers)
1785 controller.OnDisable();
1787 m_SyncedModels.Remove(model);
1789 if (model is VFXParameter)
1791 m_ParameterControllers[model as VFXParameter].OnDisable();
1792 m_ParameterControllers.Remove(model as VFXParameter);
1796 public VFXNodeController GetNodeController(VFXModel model, int id)
1798 if (model is VFXBlock)
1800 VFXContextController controller = GetRootNodeController(model.GetParent(), 0) as VFXContextController;
1801 if (controller == null)
1803 return controller.blockControllers.FirstOrDefault(t => t.model == model);
1807 return GetRootNodeController(model, id);
1811 public void ChangeEventName(string oldName, string newName)
1813 foreach (var context in m_SyncedModels.Keys.OfType<VFXBasicEvent>())
1815 if (context.eventName == oldName)
1816 context.SetSettingValue("eventName", newName);
1820 public VFXNodeController GetRootNodeController(VFXModel model, int id)
1822 List<VFXNodeController> controller = null;
1823 m_SyncedModels.TryGetValue(model, out controller);
1824 if (controller == null) return null;
1826 return controller.FirstOrDefault(t => t.id == id);
1829 public VFXStickyNoteController GetStickyNoteController(int index)
1831 return m_StickyNoteControllers[index];
1834 public VFXParameterController GetParameterController(VFXParameter parameter)
1836 VFXParameterController controller = null;
1837 m_ParameterControllers.TryGetValue(parameter, out controller);
1841 VFXUI.GroupInfo PrivateAddGroupNode(Vector2 position)
1843 var ui = graph.UIInfos;
1845 var newGroupInfo = new VFXUI.GroupInfo { title = "New Group Node", position = new Rect(position, Vector2.one * 100) };
1847 if (ui.groupInfos != null)
1848 ui.groupInfos = ui.groupInfos.Concat(Enumerable.Repeat(newGroupInfo, 1)).ToArray();
1850 ui.groupInfos = new VFXUI.GroupInfo[] { newGroupInfo };
1852 return ui.groupInfos.Last();
1855 public void GroupNodes(IEnumerable<VFXNodeController> nodes)
1858 foreach( var g in groupNodes) // remove nodes from other exisitings groups
1860 g.RemoveNodes(nodes);
1862 VFXUI.GroupInfo info = PrivateAddGroupNode(Vector2.zero);
1864 info.contents = nodes.Select(t => new VFXNodeID(t.model, t.id)).ToArray();
1866 m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1869 public void PutInSameGroupNodeAs(VFXNodeController target, VFXNodeController example)
1871 var ui = graph.UIInfos;
1872 if (ui.groupInfos == null) return;
1874 foreach (var groupNode in m_GroupNodeControllers)
1876 if (groupNode.nodes.Contains(example))
1878 groupNode.AddNode(target);
1885 List<VFXSystemController> m_Systems = new List<VFXSystemController>();
1887 public ReadOnlyCollection<VFXSystemController> systems
1889 get { return m_Systems.AsReadOnly(); }
1894 public void UpdateSystems()
1898 VFXContext[] directContexts = graph.children.OfType<VFXContext>().ToArray();
1900 HashSet<VFXContext> initializes = new HashSet<VFXContext>(directContexts.Where(t => t.contextType == VFXContextType.Init).ToArray());
1901 HashSet<VFXContext> updates = new HashSet<VFXContext>(directContexts.Where(t => t.contextType == VFXContextType.Update).ToArray());
1903 List<Dictionary<VFXContext, int>> systems = new List<Dictionary<VFXContext, int>>();
1906 while (initializes.Count > 0 || updates.Count > 0)
1910 VFXContext currentContext;
1911 if (initializes.Count > 0)
1913 currentContext = initializes.First();
1914 initializes.Remove(currentContext);
1918 currentContext = updates.First();
1919 updates.Remove(currentContext);
1922 Dictionary<VFXContext, int> system = new Dictionary<VFXContext, int>();
1924 system.Add(currentContext, generation);
1926 var allChildren = currentContext.outputFlowSlot.Where(t => t != null).SelectMany(t => t.link.Select(u => u.context)).Where(t => t != null).ToList();
1927 while (allChildren.Count() > 0)
1931 foreach (var child in allChildren)
1933 initializes.Remove(child);
1934 updates.Remove(child);
1935 system.Add(child, generation);
1938 var allSubChildren = allChildren.SelectMany(t => t.outputFlowSlot.Where(u => u != null).SelectMany(u => u.link.Select(v => v.context).Where(v => v != null)));
1939 var allPreChildren = allChildren.SelectMany(t => t.inputFlowSlot.Where(u => u != null).SelectMany(u => u.link.Select(v => v.context).Where(v => v != null && v.contextType != VFXContextType.Spawner && v.contextType != VFXContextType.SpawnerGPU)));
1941 allChildren = allSubChildren.Concat(allPreChildren).Except(system.Keys).ToList();
1944 if (system.Count > 1)
1945 systems.Add(system);
1948 while (m_Systems.Count() < systems.Count())
1950 VFXSystemController systemController = new VFXSystemController(this,graph.UIInfos);
1951 m_Systems.Add(systemController);
1954 while (m_Systems.Count() > systems.Count())
1956 VFXSystemController systemController = m_Systems.Last();
1957 m_Systems.RemoveAt(m_Systems.Count - 1);
1958 systemController.OnDisable();
1961 for (int i = 0; i < systems.Count(); ++i)
1963 var contextToController = systems[i].Keys.Select(t => new KeyValuePair<VFXContextController, VFXContext>((VFXContextController)GetNodeController(t, 0), t)).Where(t => t.Key != null).ToDictionary(t => t.Value, t => t.Key);
1964 m_Systems[i].contexts = contextToController.Values.ToArray();
1965 m_Systems[i].title = graph.UIInfos.GetNameOfSystem(systems[i].Keys);
1967 VFXContextType type = VFXContextType.None;
1968 VFXContext prevContext = null;
1969 var orderedContexts = contextToController.Keys.OrderBy(t => t.contextType).ThenBy(t => systems[i][t]).ThenBy(t => t.position.x).ThenBy(t => t.position.y).ToArray();
1972 foreach (var context in orderedContexts)
1974 if (context.contextType == type)
1976 if (prevContext != null)
1979 prevContext.letter = letter;
1983 if (letter == 'Z') // loop back to A in the unlikely event that there are more than 26 contexts
1985 else if( letter == 'z')
1987 else if( letter == 'ω')
1989 context.letter = ++letter;
1993 context.letter = '\0';
1994 prevContext = context;
1996 type = context.contextType;
2003 Debug.LogException(e);
2006 private VFXGraph m_Graph;
2010 private VFXView m_View; // Don't call directly as it is lazy initialized