OSDN Git Service

Added Assets for main menu
[mindgames/Mindgames_main.git] / Mindgames / Library / PackageCache / com.unity.visualeffectgraph@6.9.0-preview / Editor / GraphView / Views / Controller / VFXViewController.cs
1 #define NOTIFICATION_VALIDATION
2 using System;
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
5 using System.IO;
6 using System.Linq;
7 using UnityEditor.Experimental.GraphView;
8 using UnityEditor.Experimental.VFX;
9 using UnityEngine;
10 using UnityEngine.Profiling;
11
12 using UnityObject = UnityEngine.Object;
13 using Branch = UnityEditor.VFX.Operator.VFXOperatorDynamicBranch;
14
15 namespace UnityEditor.VFX.UI
16 {
17     internal partial class VFXViewController : Controller<VisualEffectResource>
18     {
19         private int m_UseCount;
20         public int useCount
21         {
22             get { return m_UseCount; }
23             set
24             {
25                 m_UseCount = value;
26                 if (m_UseCount == 0)
27                 {
28                     RemoveController(this);
29                 }
30             }
31         }
32
33         public enum Priorities
34         {
35             Graph,
36             Node,
37             Slot,
38             Default,
39             GroupNode,
40             Count
41         }
42
43         string m_Name;
44
45         public string name
46         {
47             get { return m_Name; }
48         }
49
50         string ComputeName()
51         {
52             if (model == null)
53                 return "";
54             string assetPath = AssetDatabase.GetAssetPath(model);
55             if (!string.IsNullOrEmpty(assetPath))
56             {
57                 return Path.GetFileNameWithoutExtension(assetPath);
58             }
59             else
60             {
61                 return model.name;
62             }
63         }
64
65         static HashSet<ScriptableObject>[] NewPrioritizedHashSet()
66         {
67             HashSet<ScriptableObject>[] result = new HashSet<ScriptableObject>[(int)Priorities.Count];
68
69             for (int i = 0; i < (int)Priorities.Count; ++i)
70             {
71                 result[i] = new HashSet<ScriptableObject>();
72             }
73
74             return result;
75         }
76
77         Priorities GetPriority(VFXObject obj)
78         {
79             if (obj is IVFXSlotContainer)
80             {
81                 return Priorities.Node;
82             }
83             if (obj is VFXSlot)
84             {
85                 return Priorities.Slot;
86             }
87             if (obj is VFXUI)
88             {
89                 return Priorities.GroupNode;
90             }
91             if (obj is VFXGraph)
92             {
93                 return Priorities.Graph;
94             }
95             return Priorities.Default;
96         }
97
98         HashSet<ScriptableObject>[] modifiedModels = NewPrioritizedHashSet();
99         HashSet<ScriptableObject>[] otherModifiedModels = NewPrioritizedHashSet();
100
101         public void OnObjectModified(VFXObject obj)
102         {
103             modifiedModels[(int)GetPriority(obj)].Add(obj);
104         }
105
106         Dictionary<ScriptableObject, List<Action>> m_Notified = new Dictionary<ScriptableObject, List<Action>>();
107
108
109         public void RegisterNotification(VFXObject target, Action action)
110         {
111             if (target == null)
112                 return;
113
114             target.onModified += OnObjectModified;
115             List<Action> notifieds;
116             if (m_Notified.TryGetValue(target, out notifieds))
117             {
118                 #if NOTIFICATION_VALIDATION
119                 if (notifieds.Contains(action))
120                     Debug.LogError("Adding the same notification twice on:" + target.name);
121                 #endif
122                 notifieds.Add(action);
123             }
124             else
125             {
126                 notifieds = new List<Action>();
127                 notifieds.Add(action);
128
129                 m_Notified.Add(target, notifieds);
130             }
131         }
132
133         public void UnRegisterNotification(VFXObject target, Action action)
134         {
135             if (object.ReferenceEquals(target, null))
136                 return;
137
138             target.onModified -= OnObjectModified;
139             List<Action> notifieds;
140             if (m_Notified.TryGetValue(target, out notifieds))
141             {
142                 #if NOTIFICATION_VALIDATION
143                 if (!notifieds.Contains(action))
144                     Debug.LogError("Removing a non existent notification" + target.name);
145                 #endif
146                 notifieds.Remove(action);
147
148                 if (m_CurrentlyNotified == target)
149                 {
150                     m_CurrentActions.Remove(action);
151                 }
152             }
153         }
154
155         bool m_InNotify = false;
156
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>();
159
160         public void NotifyUpdate()
161         {
162             m_InNotify = true;
163             Profiler.BeginSample("VFXViewController.NotifyUpdate");
164             if (model == null || m_Graph == null || m_Graph != model.graph)
165             {
166                 // In this case the asset has been destroyed or reimported after having changed outside.
167                 // Lets rebuild everything and clear the undo stack.
168                 Clear();
169                 if (model != null && model.graph != null)
170                     InitializeUndoStack();
171                 ModelChanged(model);
172             }
173
174             var tmp = modifiedModels;
175             modifiedModels = otherModifiedModels;
176             otherModifiedModels = tmp;
177
178
179             int cpt = 0;
180             foreach (var objs in otherModifiedModels)
181             {
182                 foreach (var obj in objs)
183                 {
184                     List<Action> notifieds;
185                     Profiler.BeginSample("VFXViewController.Notify:" + obj.GetType().Name);
186                     if (m_Notified.TryGetValue(obj, out notifieds))
187                     {
188                         m_CurrentlyNotified = obj;
189                         m_CurrentActions.Clear();
190                         m_CurrentActions.AddRange(notifieds);
191                         m_CurrentActions.Reverse();
192                         while (m_CurrentActions.Count > 0)
193                         {
194                             var action = m_CurrentActions[m_CurrentActions.Count - 1];
195                             action();
196                             cpt++;
197                             m_CurrentActions.RemoveAt(m_CurrentActions.Count - 1);
198                         }
199                     }
200                     Profiler.EndSample();
201                 }
202                 m_CurrentlyNotified = null;
203
204                 objs.Clear();
205             }
206             /*
207             if (cpt > 0)
208                 Debug.LogWarningFormat("{0} notification sent this frame", cpt);*/
209             Profiler.EndSample();
210
211             m_InNotify = false;
212
213             string newName = ComputeName();
214             if (newName != m_Name)
215             {
216                 m_Name = newName;
217
218                 if (model != null)
219                 {
220                     model.name = m_Name;
221                 }
222                 if (graph != null)
223                 {
224                     (graph as UnityObject).name = m_Name;
225                 }
226
227                 NotifyChange(Change.assetName);
228             }
229
230             if (m_DataEdgesMightHaveChangedAsked)
231             {
232                 m_DataEdgesMightHaveChangedAsked = false;
233                 DataEdgesMightHaveChanged();
234             }
235         }
236
237         public VFXGraph graph { get {return model != null ? model.graph as VFXGraph : null; }}
238
239         List<VFXFlowAnchorController> m_FlowAnchorController = new List<VFXFlowAnchorController>();
240
241         // Model / Controller synchronization
242         private Dictionary<VFXModel, List<VFXNodeController>> m_SyncedModels = new Dictionary<VFXModel, List<VFXNodeController>>();
243
244         List<VFXDataEdgeController> m_DataEdges = new List<VFXDataEdgeController>();
245         List<VFXFlowEdgeController> m_FlowEdges = new List<VFXFlowEdgeController>();
246
247         public override IEnumerable<Controller> allChildren
248         {
249             get
250             {
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>())
257                 ;
258             }
259         }
260
261         public void LightApplyChanges()
262         {
263             ModelChanged(model);
264             GraphChanged();
265         }
266
267         public override void ApplyChanges()
268         {
269             ModelChanged(model);
270             GraphChanged();
271
272             foreach (var controller in allChildren)
273             {
274                 controller.ApplyChanges();
275             }
276         }
277
278         void GraphLost()
279         {
280             Clear();
281             if (!object.ReferenceEquals(m_Graph, null))
282             {
283                 RemoveInvalidateDelegate(m_Graph, InvalidateExpressionGraph);
284                 RemoveInvalidateDelegate(m_Graph, IncremenentGraphUndoRedoState);
285
286                 UnRegisterNotification(m_Graph, GraphChanged);
287
288                 m_Graph = null;
289             }
290             if (!object.ReferenceEquals(m_UI, null))
291             {
292                 UnRegisterNotification(m_UI, UIChanged);
293                 m_UI = null;
294             }
295         }
296
297         public override void OnDisable()
298         {
299             Profiler.BeginSample("VFXViewController.OnDisable");
300             GraphLost();
301             ReleaseUndoStack();
302             Undo.undoRedoPerformed -= SynchronizeUndoRedoState;
303             Undo.willFlushUndoRecord -= WillFlushUndoRecord;
304
305             base.OnDisable();
306             Profiler.EndSample();
307         }
308
309         public IEnumerable<VFXNodeController> AllSlotContainerControllers
310         {
311             get
312             {
313                 var operatorControllers = m_SyncedModels.Values.SelectMany(t => t).OfType<VFXNodeController>();
314                 var blockControllers = (contexts.SelectMany(t => t.blockControllers)).Cast<VFXNodeController>();
315
316                 return operatorControllers.Concat(blockControllers);
317             }
318         }
319
320         public bool RecreateNodeEdges()
321         {
322             bool changed = false;
323             HashSet<VFXDataEdgeController> unusedEdges = new HashSet<VFXDataEdgeController>();
324             foreach (var e in m_DataEdges)
325             {
326                 unusedEdges.Add(e);
327             }
328
329             var nodeToUpdate = new HashSet<VFXNodeController>();
330
331             foreach (var operatorControllers in m_SyncedModels.Values)
332             {
333                 foreach (var nodeController in operatorControllers)
334                 {
335                     bool nodeChanged = false;
336                     foreach (var input in nodeController.inputPorts)
337                     {
338                         nodeChanged |= RecreateInputSlotEdge(unusedEdges, nodeController, input);
339                     }
340                     if (nodeController is VFXContextController)
341                     {
342                         VFXContextController contextController = nodeController as VFXContextController;
343
344                         foreach (var block in contextController.blockControllers)
345                         {
346                             bool blockChanged = false;
347                             foreach (var input in block.inputPorts)
348                             {
349                                 blockChanged |= RecreateInputSlotEdge(unusedEdges, block, input);
350                             }
351                             if (blockChanged)
352                                 nodeToUpdate.Add(block);
353                             changed |= blockChanged;
354                         }
355                     }
356                     if (nodeChanged)
357                         nodeToUpdate.Add(nodeController);
358
359                     changed |= nodeChanged;
360                 }
361             }
362
363             foreach (var edge in unusedEdges)
364             {
365                 nodeToUpdate.Add(edge.input.sourceNode);
366                 edge.OnDisable();
367
368                 m_DataEdges.Remove(edge);
369                 changed = true;
370             }
371
372             foreach (var node in nodeToUpdate)
373             {
374                 node.UpdateAllEditable();
375             }
376
377             return changed;
378         }
379
380         bool m_DataEdgesMightHaveChangedAsked;
381
382         public void DataEdgesMightHaveChanged()
383         {
384             if (m_Syncing) return;
385
386             if (m_InNotify)
387             {
388                 m_DataEdgesMightHaveChangedAsked = true;
389                 return;
390             }
391
392             Profiler.BeginSample("VFXViewController.DataEdgesMightHaveChanged");
393
394             bool change = RecreateNodeEdges();
395
396             if (change || m_ForceDataEdgeNotification)
397             {
398                 m_ForceDataEdgeNotification = false;
399                 NotifyChange(Change.dataEdge);
400             }
401
402             Profiler.EndSample();
403         }
404
405         public bool RecreateInputSlotEdge(HashSet<VFXDataEdgeController> unusedEdges, VFXNodeController slotContainer, VFXDataAnchorController input)
406         {
407             VFXSlot inputSlot = input.model;
408             if (inputSlot == null)
409                 return false;
410
411             bool changed = false;
412             if (input.HasLink())
413             {
414                 VFXNodeController operatorControllerFrom = null;
415
416                 IVFXSlotContainer targetSlotContainer = inputSlot.refSlot.owner;
417                 if (targetSlotContainer == null)
418                 {
419                     return false;
420                 }
421                 if (targetSlotContainer is VFXParameter)
422                 {
423                     VFXParameterController controller = null;
424                     if (m_ParameterControllers.TryGetValue(targetSlotContainer as VFXParameter, out controller))
425                     {
426                         operatorControllerFrom = controller.GetParameterForLink(inputSlot);
427                     }
428                 }
429                 else if (targetSlotContainer is VFXBlock)
430                 {
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)
435                     {
436                         operatorControllerFrom = (contextControllers[0] as VFXContextController).blockControllers.FirstOrDefault(t => t.model == block);
437                     }
438                 }
439                 else
440                 {
441                     List<VFXNodeController> nodeControllers = null;
442                     if (m_SyncedModels.TryGetValue(targetSlotContainer as VFXModel, out nodeControllers) && nodeControllers.Count > 0)
443                     {
444                         operatorControllerFrom = nodeControllers[0];
445                     }
446                 }
447
448                 var operatorControllerTo = slotContainer;
449
450                 if (operatorControllerFrom != null && operatorControllerTo != null)
451                 {
452                     var anchorFrom = operatorControllerFrom.outputPorts.FirstOrDefault(o => (o as VFXDataAnchorController).model == inputSlot.refSlot);
453                     var anchorTo = input;
454
455                     var edgController = m_DataEdges.FirstOrDefault(t => t.input == anchorTo && t.output == anchorFrom);
456
457                     if (edgController != null)
458                     {
459                         unusedEdges.Remove(edgController);
460                     }
461                     else
462                     {
463                         if (anchorFrom != null && anchorTo != null)
464                         {
465                             edgController = new VFXDataEdgeController(anchorTo, anchorFrom);
466                             m_DataEdges.Add(edgController);
467                             changed = true;
468                         }
469                     }
470                 }
471             }
472
473             foreach (VFXSlot subSlot in inputSlot.children)
474             {
475                 VFXDataAnchorController subAnchor = slotContainer.inputPorts.FirstOrDefault(t => t.model == subSlot);
476                 if (subAnchor != null) // Can be null for example for hidden values from Vector3Spaceables
477                 {
478                     changed |= RecreateInputSlotEdge(unusedEdges, slotContainer, subAnchor);
479                 }
480             }
481
482             return changed;
483         }
484
485         public IEnumerable<VFXContextController> contexts
486         {
487             get { return m_SyncedModels.Values.SelectMany(t => t).OfType<VFXContextController>(); }
488         }
489         public IEnumerable<VFXNodeController> nodes
490         {
491             get { return m_SyncedModels.Values.SelectMany(t => t); }
492         }
493
494         public void FlowEdgesMightHaveChanged()
495         {
496             if (m_Syncing) return;
497
498             bool change = RecreateFlowEdges();
499             if (change)
500             {
501                 UpdateSystems(); // System will change based on flowEdges
502                 NotifyChange(Change.flowEdge);
503             }
504         }
505
506         public class Change
507         {
508             public const int flowEdge = 1;
509             public const int dataEdge = 2;
510
511             public const int groupNode = 3;
512
513             public const int assetName = 4;
514
515             public const int ui = 5;
516
517             public const int destroy = 666;
518         }
519
520         bool RecreateFlowEdges()
521         {
522             bool changed = false;
523             HashSet<VFXFlowEdgeController> unusedEdges = new HashSet<VFXFlowEdgeController>();
524             foreach (var e in m_FlowEdges)
525             {
526                 unusedEdges.Add(e);
527             }
528
529             var contextControllers = contexts;
530             foreach (var outController in contextControllers.ToArray())
531             {
532                 var output = outController.model;
533                 for (int slotIndex = 0; slotIndex < output.inputFlowSlot.Length; ++slotIndex)
534                 {
535                     var inputFlowSlot = output.inputFlowSlot[slotIndex];
536                     foreach (var link in inputFlowSlot.link)
537                     {
538                         var inController = contexts.FirstOrDefault(x => x.model == link.context);
539                         if (inController == null)
540                             break;
541
542                         var outputAnchor = inController.flowOutputAnchors.Where(o => o.slotIndex == link.slotIndex).FirstOrDefault();
543                         var inputAnchor = outController.flowInputAnchors.Where(o => o.slotIndex == slotIndex).FirstOrDefault();
544
545                         var edgeController = m_FlowEdges.FirstOrDefault(t => t.input == inputAnchor && t.output == outputAnchor);
546                         if (edgeController != null)
547                             unusedEdges.Remove(edgeController);
548                         else
549                         {
550                             edgeController = new VFXFlowEdgeController(inputAnchor, outputAnchor);
551                             m_FlowEdges.Add(edgeController);
552                             changed = true;
553                         }
554                     }
555                 }
556             }
557
558             foreach (var edge in unusedEdges)
559             {
560                 edge.OnDisable();
561                 m_FlowEdges.Remove(edge);
562                 changed = true;
563             }
564
565             return changed;
566         }
567
568         public ReadOnlyCollection<VFXDataEdgeController> dataEdges
569         {
570             get { return m_DataEdges.AsReadOnly(); }
571         }
572         public ReadOnlyCollection<VFXFlowEdgeController> flowEdges
573         {
574             get { return m_FlowEdges.AsReadOnly(); }
575         }
576
577         public bool CreateLink(VFXDataAnchorController input, VFXDataAnchorController output)
578         {
579             if (input == null)
580             {
581                 return false;
582             }
583
584             if( input.sourceNode.viewController != output.sourceNode.viewController)
585             {
586                 return false;
587             }
588
589             if (!input.CanLink(output))
590             {
591                 return false;
592             }
593
594             VFXParameter.NodeLinkedSlot resulting = input.CreateLinkTo(output);
595
596             if (resulting.inputSlot != null && resulting.outputSlot != null)
597             {
598                 VFXParameterNodeController fromController = output.sourceNode as VFXParameterNodeController;
599                 if (fromController != null)
600                 {
601                     if (fromController.infos.linkedSlots == null)
602                         fromController.infos.linkedSlots = new List<VFXParameter.NodeLinkedSlot>();
603                     fromController.infos.linkedSlots.Add(resulting);
604                 }
605
606                 VFXParameterNodeController toController = input.sourceNode as VFXParameterNodeController;
607                 if( toController != null)
608                 {
609                     var infos = toController.infos;
610                     if (infos.linkedSlots == null)
611                         infos.linkedSlots = new List<VFXParameter.NodeLinkedSlot>();
612                     infos.linkedSlots.Add(resulting);
613                 }
614
615                 DataEdgesMightHaveChanged();
616                 return true;
617             }
618             return false;
619         }
620
621         public void AddElement(VFXDataEdgeController edge)
622         {
623             var fromAnchor = edge.output;
624             var toAnchor = edge.input;
625
626             CreateLink(toAnchor, fromAnchor);
627             edge.OnDisable();
628         }
629
630         public void AddElement(VFXFlowEdgeController edge)
631         {
632             var flowEdge = (VFXFlowEdgeController)edge;
633
634             var outputFlowAnchor = flowEdge.output as VFXFlowAnchorController;
635             var inputFlowAnchor = flowEdge.input as VFXFlowAnchorController;
636
637             var contextOutput = outputFlowAnchor.owner;
638             var contextInput = inputFlowAnchor.owner;
639
640             contextOutput.LinkTo(contextInput, outputFlowAnchor.slotIndex, inputFlowAnchor.slotIndex);
641
642             edge.OnDisable();
643         }
644
645         public void Remove(IEnumerable<Controller> removedControllers, bool explicitDelete = false)
646         {
647             removedControllers = removedControllers.Except(removedControllers.OfType<VFXContextController>().Where(t => t.model is VFXBlockSubgraphContext)); //refuse to delete VFXBlockSubgraphContext
648
649             var removedContexts = new HashSet<VFXContextController>(removedControllers.OfType<VFXContextController>());
650
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();
653
654             foreach (var controller in removed)
655             {
656                 RemoveElement(controller, explicitDelete);
657             }
658         }
659
660         bool m_ForceDataEdgeNotification;
661
662         public void RemoveElement(Controller element, bool explicitDelete = false)
663         {
664             if (element is VFXContextController)
665             {
666                 VFXContextController contextController = ((VFXContextController)element);
667                 VFXContext context = contextController.model;
668                 contextController.NodeGoingToBeRemoved();
669
670                 // Remove connections from context
671                 foreach (var slot in context.inputSlots.Concat(context.outputSlots))
672                     slot.UnlinkAll(true, true);
673
674                 // Remove connections from blocks
675                 foreach (VFXBlockController blockPres in (element as VFXContextController).blockControllers)
676                 {
677                     foreach (var slot in blockPres.slotContainer.outputSlots.Concat(blockPres.slotContainer.inputSlots))
678                     {
679                         slot.UnlinkAll(true, true);
680                     }
681                 }
682
683                 // remove flow connections from context
684                 // TODO update data types
685                 context.UnlinkAll();
686                 // Detach from graph
687                 context.Detach();
688
689                 RemoveFromGroupNodes(element as VFXNodeController);
690
691                 UnityObject.DestroyImmediate(context, true);
692             }
693             else if (element is VFXBlockController)
694             {
695                 var block = element as VFXBlockController;
696                 block.NodeGoingToBeRemoved();
697                 block.contextController.RemoveBlock(block.model);
698
699                 UnityObject.DestroyImmediate(block.model, true);
700             }
701             else if (element is VFXParameterNodeController)
702             {
703                 var parameter = element as VFXParameterNodeController;
704                 parameter.NodeGoingToBeRemoved();
705                 parameter.parentController.model.RemoveNode(parameter.infos);
706                 RemoveFromGroupNodes(element as VFXNodeController);
707                 DataEdgesMightHaveChanged();
708             }
709             else if (element is VFXNodeController || element is VFXParameterController)
710             {
711                 IVFXSlotContainer container = null;
712
713                 if (element is VFXNodeController)
714                 {
715                     VFXNodeController nodeController = (element as VFXNodeController);
716                     container = nodeController.model as IVFXSlotContainer;
717                     nodeController.NodeGoingToBeRemoved();
718                     RemoveFromGroupNodes(element as VFXNodeController);
719                 }
720                 else
721                 {
722                     container = (element as VFXParameterController).model;
723
724                     foreach (var parameterNode in m_SyncedModels[container as VFXModel])
725                     {
726                         RemoveFromGroupNodes(parameterNode);
727                     }
728                 }
729
730                 VFXSlot slotToClean = null;
731                 do
732                 {
733                     slotToClean = container.inputSlots.Concat(container.outputSlots)
734                         .FirstOrDefault(o => o.HasLink(true));
735                     if (slotToClean)
736                     {
737                         slotToClean.UnlinkAll(true, true);
738                     }
739                 }
740                 while (slotToClean != null);
741
742                 graph.RemoveChild(container as VFXModel);
743
744                 UnityObject.DestroyImmediate(container as VFXModel, true);
745                 DataEdgesMightHaveChanged();
746             }
747             else if (element is VFXFlowEdgeController)
748             {
749                 var flowEdge = element as VFXFlowEdgeController;
750
751
752                 var inputAnchor = flowEdge.input as VFXFlowAnchorController;
753                 var outputAnchor = flowEdge.output as VFXFlowAnchorController;
754
755                 if (inputAnchor != null && outputAnchor != null)
756                 {
757                     var contextInput = inputAnchor.owner as VFXContext;
758                     var contextOutput = outputAnchor.owner as VFXContext;
759
760                     if (contextInput != null && contextOutput != null)
761                         contextInput.UnlinkFrom(contextOutput, outputAnchor.slotIndex, inputAnchor.slotIndex);
762                 }
763             }
764             else if (element is VFXDataEdgeController)
765             {
766                 var edge = element as VFXDataEdgeController;
767                 var to = edge.input as VFXDataAnchorController;
768
769                 if (to != null)
770                 {
771                     if( explicitDelete )
772                     {
773                          to.sourceNode.OnEdgeFromInputGoingToBeRemoved(to);
774                          edge.output.sourceNode.OnEdgeFromOutputGoingToBeRemoved(edge.output,edge.input);
775                     }
776                     var slot = to.model;
777                     if (slot != null)
778                     {
779                         slot.UnlinkAll();
780                     }
781                     m_ForceDataEdgeNotification = true;
782                 }
783             }
784             else if (element is VFXGroupNodeController)
785             {
786                 RemoveGroupNode(element as VFXGroupNodeController);
787             }
788             else if (element is VFXStickyNoteController)
789             {
790                 RemoveStickyNote(element as VFXStickyNoteController);
791             }
792             else
793             {
794                 Debug.LogErrorFormat("Unexpected type : {0}", element.GetType().FullName);
795             }
796         }
797
798         protected override void ModelChanged(UnityObject obj)
799         {
800             if (model == null)
801             {
802                 NotifyChange(Change.destroy);
803                 GraphLost();
804
805                 RemoveController(this);
806                 return;
807             }
808
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()))
811             {
812                 if (!object.ReferenceEquals(m_Graph, null))
813                 {
814                     UnRegisterNotification(m_Graph, GraphChanged);
815                     UnRegisterNotification(m_UI, UIChanged);
816                 }
817                 if (m_Graph != null)
818                 {
819                     GraphLost();
820                 }
821                 else
822                 {
823                     Clear();
824                 }
825                 m_Graph =  model.GetOrCreateGraph();
826                 m_Graph.SanitizeGraph();
827
828                 if (m_Graph != null)
829                 {
830                     RegisterNotification(m_Graph, GraphChanged);
831
832                     AddInvalidateDelegate(m_Graph, InvalidateExpressionGraph);
833                     AddInvalidateDelegate(m_Graph, IncremenentGraphUndoRedoState);
834
835
836                     m_UI = m_Graph.UIInfos;
837
838                     RegisterNotification(m_UI, UIChanged);
839
840                     GraphChanged();
841                 }
842             }
843         }
844
845         public void AddGroupNode(Vector2 pos)
846         {
847             PrivateAddGroupNode(pos);
848
849             m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
850         }
851
852         public void AddStickyNote(Vector2 position, VFXGroupNodeController group)
853         {
854             var ui = graph.UIInfos;
855
856             var stickyNoteInfo = new VFXUI.StickyNoteInfo
857             {
858                 title = "Title",
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()
863             };
864
865             if (ui.stickyNoteInfos != null)
866                 ui.stickyNoteInfos = ui.stickyNoteInfos.Concat(Enumerable.Repeat(stickyNoteInfo, 1)).ToArray();
867             else
868                 ui.stickyNoteInfos = new VFXUI.StickyNoteInfo[] { stickyNoteInfo };
869
870             if (group != null)
871             {
872                 LightApplyChanges();
873
874                 group.AddStickyNote(m_StickyNoteControllers[ui.stickyNoteInfos.Length - 1]);
875             }
876
877             m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
878         }
879
880         void RemoveGroupNode(VFXGroupNodeController groupNode)
881         {
882             var ui = graph.UIInfos;
883
884             int index = groupNode.index;
885
886             ui.groupInfos = ui.groupInfos.Where((t, i) => i != index).ToArray();
887
888             groupNode.Remove();
889             m_GroupNodeControllers.RemoveAt(index);
890
891             for (int i = index; i < m_GroupNodeControllers.Count; ++i)
892             {
893                 m_GroupNodeControllers[i].index = i;
894             }
895             m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
896         }
897
898         void RemoveStickyNote(VFXStickyNoteController stickyNote)
899         {
900             var ui = graph.UIInfos;
901
902             int index = stickyNote.index;
903
904             ui.stickyNoteInfos = ui.stickyNoteInfos.Where((t, i) => i != index).ToArray();
905
906             stickyNote.Remove();
907             m_StickyNoteControllers.RemoveAt(index);
908
909             for (int i = index; i < m_StickyNoteControllers.Count; ++i)
910             {
911                 m_StickyNoteControllers[i].index = i;
912             }
913
914             //Patch group nodes, removing this sticky note and fixing ids that are bigger than index
915             if (ui.groupInfos != null)
916             {
917                 for (int i = 0; i < ui.groupInfos.Length; ++i)
918                 {
919                     for (int j = 0; j < ui.groupInfos[i].contents.Length; ++j)
920                     {
921                         if (ui.groupInfos[i].contents[j].isStickyNote)
922                         {
923                             if (ui.groupInfos[i].contents[j].id == index)
924                             {
925                                 ui.groupInfos[i].contents = ui.groupInfos[i].contents.Where((t, idx) => idx != j).ToArray();
926                                 j--;
927                             }
928                             else if (ui.groupInfos[i].contents[j].id > index)
929                             {
930                                 --(ui.groupInfos[i].contents[j].id);
931                             }
932                         }
933                     }
934                 }
935             }
936
937             m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
938         }
939
940         void RemoveFromGroupNodes(VFXNodeController node)
941         {
942             foreach (var groupNode in m_GroupNodeControllers)
943             {
944                 if (groupNode.ContainsNode(node))
945                 {
946                     groupNode.RemoveNode(node);
947                 }
948             }
949         }
950
951         protected void GraphChanged()
952         {
953             if (m_Graph == null)
954             {
955                 if (model != null)
956                 {
957                     ModelChanged(model);
958                 }
959                 return;
960             }
961
962             VFXGraphValidation validation = new VFXGraphValidation(m_Graph);
963             validation.ValidateGraph();
964
965             bool groupNodeChanged = false;
966
967             Profiler.BeginSample("VFXViewController.GraphChanged:SyncControllerFromModel");
968             SyncControllerFromModel(ref groupNodeChanged);
969             Profiler.EndSample();
970
971             Profiler.BeginSample("VFXViewController.GraphChanged:NotifyChange(AnyThing)");
972             NotifyChange(AnyThing);
973             Profiler.EndSample();
974
975             //if( groupNodeChanged)
976             {
977                 Profiler.BeginSample("VFXViewController.GraphChanged:NotifyChange(Change.groupNode)");
978                 NotifyChange(Change.groupNode);
979                 Profiler.EndSample();
980             }
981         }
982
983         protected void UIChanged()
984         {
985             if (m_UI == null) return;
986             if (m_Graph == null) return; // OnModelChange or OnDisable will take care of that later
987
988             bool groupNodeChanged = false;
989             RecreateUI(ref groupNodeChanged);
990
991             NotifyChange(Change.ui);
992         }
993
994         public void NotifyParameterControllerChange()
995         {
996             DataEdgesMightHaveChanged();
997             if (!m_Syncing)
998                 NotifyChange(AnyThing);
999         }
1000
1001         public void RegisterFlowAnchorController(VFXFlowAnchorController controller)
1002         {
1003             if (!m_FlowAnchorController.Contains(controller))
1004                 m_FlowAnchorController.Add(controller);
1005         }
1006
1007         public void UnregisterFlowAnchorController(VFXFlowAnchorController controller)
1008         {
1009             m_FlowAnchorController.Remove(controller);
1010         }
1011
1012         public static void CollectAncestorOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashParents)
1013         {
1014             foreach (var slotInput in operatorInput.inputSlots)
1015             {
1016                 var linkedSlots = slotInput.AllChildrenWithLink();
1017                 foreach (var linkedSlot in linkedSlots)
1018                 {
1019                     RecurseCollectAncestorOperator(linkedSlot.refSlot.owner, hashParents);
1020                 }
1021             }
1022         }
1023
1024         public static void RecurseCollectAncestorOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashParents)
1025         {
1026             if (hashParents.Contains(operatorInput))
1027                 return;
1028
1029             hashParents.Add(operatorInput);
1030
1031             foreach (var slotInput in operatorInput.inputSlots)
1032             {
1033                 var linkedSlots = slotInput.AllChildrenWithLink();
1034                 foreach (var linkedSlot in linkedSlots)
1035                 {
1036                     RecurseCollectAncestorOperator(linkedSlot.refSlot.owner, hashParents);
1037                 }
1038             }
1039         }
1040
1041         public static void CollectDescendantOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashChildren)
1042         {
1043             foreach (var slotOutput in operatorInput.outputSlots)
1044             {
1045                 var linkedSlots = slotOutput.AllChildrenWithLink();
1046                 foreach (var linkedSlot in linkedSlots)
1047                 {
1048                     foreach (var link in linkedSlot.LinkedSlots)
1049                     {
1050                         RecurseCollectDescendantOperator(link.owner, hashChildren);
1051                     }
1052                 }
1053             }
1054         }
1055
1056         public static void RecurseCollectDescendantOperator(IVFXSlotContainer operatorInput, HashSet<IVFXSlotContainer> hashChildren)
1057         {
1058             if (hashChildren.Contains(operatorInput))
1059                 return;
1060
1061             hashChildren.Add(operatorInput);
1062             foreach (var slotOutput in operatorInput.outputSlots)
1063             {
1064                 var linkedSlots = slotOutput.AllChildrenWithLink();
1065                 foreach (var linkedSlot in linkedSlots)
1066                 {
1067                     foreach (var link in linkedSlot.LinkedSlots)
1068                     {
1069                         RecurseCollectDescendantOperator(link.owner, hashChildren);
1070                     }
1071                 }
1072             }
1073         }
1074
1075         public IEnumerable<VFXDataAnchorController> GetCompatiblePorts(VFXDataAnchorController startAnchorController, NodeAdapter nodeAdapter)
1076         {
1077             var cacheLinkData = new VFXDataAnchorController.CanLinkCache();
1078
1079             var direction = startAnchorController.direction;
1080             foreach (var slotContainer in AllSlotContainerControllers)
1081             {
1082                 var sourceSlot = direction == Direction.Input ? slotContainer.outputPorts : slotContainer.inputPorts;
1083                 foreach (var slot in sourceSlot)
1084                 {
1085                     if (startAnchorController.CanLink(slot, cacheLinkData))
1086                     {
1087                         yield return slot;
1088                     }
1089                 }
1090             }
1091         }
1092
1093         public List<VFXFlowAnchorController> GetCompatiblePorts(VFXFlowAnchorController startAnchorController, NodeAdapter nodeAdapter)
1094         {
1095             var res = new List<VFXFlowAnchorController>();
1096
1097             var startFlowAnchorController = (VFXFlowAnchorController)startAnchorController;
1098             foreach (var anchorController in m_FlowAnchorController)
1099             {
1100                 VFXContext owner = anchorController.owner;
1101                 if (owner == null ||
1102                     startAnchorController == anchorController ||
1103                     startAnchorController.direction == anchorController.direction ||
1104                     owner == startFlowAnchorController.owner)
1105                     continue;
1106
1107                 if (startAnchorController.direction == Direction.Input)
1108                 {
1109                     if (VFXFlowAnchorController.CanLink(anchorController, startFlowAnchorController))
1110                         res.Add(anchorController);
1111                 }
1112                 else
1113                 {
1114                     if (VFXFlowAnchorController.CanLink(startFlowAnchorController, anchorController))
1115                         res.Add(anchorController);
1116                 }
1117             }
1118             return res;
1119         }
1120
1121         public void AddVFXModel(Vector2 pos, VFXModel model)
1122         {
1123             model.position = pos;
1124             this.graph.AddChild(model);
1125         }
1126
1127         public VFXContext AddVFXContext(Vector2 pos, VFXModelDescriptor<VFXContext> desc)
1128         {
1129             VFXContext model = desc.CreateInstance();
1130             AddVFXModel(pos, model);
1131             return model;
1132         }
1133
1134         public VFXOperator AddVFXOperator(Vector2 pos, VFXModelDescriptor<VFXOperator> desc)
1135         {
1136             var model = desc.CreateInstance();
1137             AddVFXModel(pos, model);
1138             return model;
1139         }
1140
1141         public VFXParameter AddVFXParameter(Vector2 pos, VFXModelDescriptorParameters desc)
1142         {
1143             var model = desc.CreateInstance();
1144             AddVFXModel(pos, model);
1145
1146             VFXParameter parameter = model as VFXParameter;
1147
1148             Type type = parameter.type;
1149
1150             parameter.collapsed = true;
1151
1152             int order = 0;
1153             if (m_ParameterControllers.Count > 0)
1154             {
1155                 order = m_ParameterControllers.Keys.Select(t => t.order).Max() + 1;
1156             }
1157             parameter.order = order;
1158             parameter.SetSettingValue("m_ExposedName", string.Format("New {0}", type.UserFriendlyName()));
1159
1160             if (!type.IsPrimitive)
1161             {
1162                 parameter.value = VFXTypeExtension.GetDefaultField(type);
1163             }
1164
1165             return model;
1166         }
1167
1168         public VFXNodeController AddNode(Vector2 tPos, object modelDescriptor, VFXGroupNodeController groupNode)
1169         {
1170             VFXModel newNode = null;
1171             if (modelDescriptor is VFXModelDescriptor<VFXOperator>)
1172             {
1173                 newNode = AddVFXOperator(tPos, (modelDescriptor as VFXModelDescriptor<VFXOperator>));
1174             }
1175             else if (modelDescriptor is VFXModelDescriptor<VFXContext>)
1176             {
1177                 newNode = AddVFXContext(tPos, modelDescriptor as VFXModelDescriptor<VFXContext>);
1178             }
1179             else if (modelDescriptor is VFXModelDescriptorParameters)
1180             {
1181                 newNode = AddVFXParameter(tPos, modelDescriptor as VFXModelDescriptorParameters);
1182             }
1183             if (newNode != null)
1184             {
1185                 bool groupNodeChanged = false;
1186                 SyncControllerFromModel(ref groupNodeChanged);
1187
1188                 List<VFXNodeController> nodeControllers = null;
1189                 m_SyncedModels.TryGetValue(newNode, out nodeControllers);
1190
1191                 if (newNode is VFXParameter)
1192                 {
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());
1196                 }
1197
1198                 NotifyChange(AnyThing);
1199
1200                 if (groupNode != null)
1201                 {
1202                     groupNode.AddNode(nodeControllers.First());
1203                 }
1204
1205                 return nodeControllers[0];
1206             }
1207
1208             return null;
1209         }
1210
1211         public VFXNodeController AddVFXParameter(Vector2 pos, VFXParameterController parameterController, VFXGroupNodeController groupNode)
1212         {
1213             if( parameterController.isOutput && parameterController.nodeCount > 0)
1214             {
1215                 return parameterController.nodes.First();
1216             }
1217             int id = parameterController.model.AddNode(pos);
1218
1219             LightApplyChanges();
1220
1221             var nodeController = GetRootNodeController(parameterController.model, id);
1222
1223             if (groupNode != null)
1224             {
1225                 if (nodeController != null)
1226                 {
1227                     groupNode.AddNode(nodeController);
1228                 }
1229             }
1230
1231             return nodeController;
1232         }
1233
1234         public void Clear()
1235         {
1236             foreach (var element in allChildren)
1237             {
1238                 element.OnDisable();
1239             }
1240
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();
1248         }
1249
1250         private Dictionary<VFXModel, List<VFXModel.InvalidateEvent>> m_registeredEvent = new Dictionary<VFXModel, List<VFXModel.InvalidateEvent>>();
1251         public void AddInvalidateDelegate(VFXModel model, VFXModel.InvalidateEvent evt)
1252         {
1253             model.onInvalidateDelegate += evt;
1254             if (!m_registeredEvent.ContainsKey(model))
1255             {
1256                 m_registeredEvent.Add(model, new List<VFXModel.InvalidateEvent>());
1257             }
1258             m_registeredEvent[model].Add(evt);
1259         }
1260
1261         public void RemoveInvalidateDelegate(VFXModel model, VFXModel.InvalidateEvent evt)
1262         {
1263             List<VFXModel.InvalidateEvent> evtList;
1264             if (model != null && m_registeredEvent.TryGetValue(model, out evtList))
1265             {
1266                 model.onInvalidateDelegate -= evt;
1267                 evtList.Remove(evt);
1268                 if (evtList.Count == 0)
1269                 {
1270                     m_registeredEvent.Remove(model);
1271                 }
1272             }
1273         }
1274
1275         static Dictionary<VisualEffectResource, VFXViewController> s_Controllers = new Dictionary<VisualEffectResource, VFXViewController>();
1276
1277         public static VFXViewController GetController(VisualEffectResource resource, bool forceUpdate = false)
1278         {
1279             //TRANSITION : delete VFXAsset as it should be in Library
1280             resource.ValidateAsset();
1281
1282             VFXViewController controller;
1283             if (!s_Controllers.TryGetValue(resource, out controller))
1284             {
1285                 controller = new VFXViewController(resource);
1286                 s_Controllers[resource] = controller;
1287             }
1288             else
1289             {
1290                 if (forceUpdate)
1291                 {
1292                     controller.ForceReload();
1293                 }
1294             }
1295
1296             return controller;
1297         }
1298
1299         static void RemoveController(VFXViewController controller)
1300         {
1301             if (s_Controllers.ContainsKey(controller.model))
1302             {
1303                 controller.OnDisable();
1304                 s_Controllers.Remove(controller.model);
1305             }
1306         }
1307
1308         VFXViewController(VisualEffectResource vfx) : base(vfx)
1309         {
1310             ModelChanged(vfx); // This will initialize the graph from the vfx asset.
1311
1312             if (m_FlowAnchorController == null)
1313                 m_FlowAnchorController = new List<VFXFlowAnchorController>();
1314
1315             Undo.undoRedoPerformed += SynchronizeUndoRedoState;
1316             Undo.willFlushUndoRecord += WillFlushUndoRecord;
1317
1318             string fileName = System.IO.Path.GetFileNameWithoutExtension(AssetDatabase.GetAssetPath(vfx));
1319             vfx.name = fileName;
1320
1321             if (m_Graph != null)
1322                 m_Graph.BuildParameterInfo();
1323
1324
1325             InitializeUndoStack();
1326             GraphChanged();
1327
1328             Sanitize();
1329         }
1330
1331         void Sanitize()
1332         {
1333             VFXParameter[] parameters = m_ParameterControllers.Keys.OrderBy(t => t.order).ToArray();
1334             if (parameters.Length > 0)
1335             {
1336                 var existingNames = new HashSet<string>();
1337
1338                 existingNames.Add(parameters[0].exposedName);
1339                 m_ParameterControllers[parameters[0]].order = 0;
1340
1341                 for (int i = 1; i < parameters.Length; ++i)
1342                 {
1343                     var controller = m_ParameterControllers[parameters[i]];
1344                     controller.order = i;
1345
1346                     controller.CheckNameUnique(existingNames);
1347
1348                     existingNames.Add(parameters[i].exposedName);
1349                 }
1350             }
1351         }
1352
1353         public ReadOnlyCollection<VFXGroupNodeController> groupNodes
1354         {
1355             get {return m_GroupNodeControllers.AsReadOnly(); }
1356         }
1357         public ReadOnlyCollection<VFXStickyNoteController> stickyNotes
1358         {
1359             get {return m_StickyNoteControllers.AsReadOnly(); }
1360         }
1361
1362         List<VFXGroupNodeController> m_GroupNodeControllers = new List<VFXGroupNodeController>();
1363         List<VFXStickyNoteController> m_StickyNoteControllers = new List<VFXStickyNoteController>();
1364
1365         public bool RecreateUI(ref bool groupNodeChanged)
1366         {
1367             bool changed = false;
1368             var ui = graph.UIInfos;
1369
1370             if (ui.groupInfos != null)
1371             {
1372                 HashSet<VFXNodeID> usedNodeIds = new HashSet<VFXNodeID>();
1373                 // first make sure that nodesID are at most in one groupnode.
1374
1375                 for (int i = 0; i < ui.groupInfos.Length; ++i)
1376                 {
1377                     if (ui.groupInfos[i].contents != null)
1378                     {
1379                         for (int j = 0; j < ui.groupInfos[i].contents.Length; ++j)
1380                         {
1381                             if (usedNodeIds.Contains(ui.groupInfos[i].contents[j]))
1382                             {
1383                                 Debug.Log("Element present in multiple groupnodes");
1384                                 --j;
1385                                 ui.groupInfos[i].contents = ui.groupInfos[i].contents.Where((t, k) => k != j).ToArray();
1386                             }
1387                             else
1388                             {
1389                                 usedNodeIds.Add(ui.groupInfos[i].contents[j]);
1390                             }
1391                         }
1392                     }
1393                 }
1394
1395                 for (int i = m_GroupNodeControllers.Count; i < ui.groupInfos.Length; ++i)
1396                 {
1397                     VFXGroupNodeController groupNodeController = new VFXGroupNodeController(this, ui, i);
1398                     m_GroupNodeControllers.Add(groupNodeController);
1399                     changed = true;
1400                     groupNodeChanged = true;
1401                 }
1402
1403                 while (ui.groupInfos.Length < m_GroupNodeControllers.Count)
1404                 {
1405                     m_GroupNodeControllers.Last().OnDisable();
1406                     m_GroupNodeControllers.RemoveAt(m_GroupNodeControllers.Count - 1);
1407                     changed = true;
1408                     groupNodeChanged = true;
1409                 }
1410             }
1411             if (ui.stickyNoteInfos != null)
1412             {
1413                 for (int i = m_StickyNoteControllers.Count; i < ui.stickyNoteInfos.Length; ++i)
1414                 {
1415                     VFXStickyNoteController stickyNoteController = new VFXStickyNoteController(this, ui, i);
1416                     m_StickyNoteControllers.Add(stickyNoteController);
1417                     stickyNoteController.ApplyChanges();
1418                     changed = true;
1419                 }
1420
1421                 while (ui.stickyNoteInfos.Length < m_StickyNoteControllers.Count)
1422                 {
1423                     m_StickyNoteControllers.Last().OnDisable();
1424                     m_StickyNoteControllers.RemoveAt(m_StickyNoteControllers.Count - 1);
1425                     changed = true;
1426                 }
1427             }
1428
1429             return changed;
1430         }
1431
1432         public void ValidateCategoryList()
1433         {
1434             if (!m_Syncing)
1435             {
1436                 var ui = graph.UIInfos;
1437                 // Validate category list
1438                 var categories = ui.categories != null ? ui.categories : new List<VFXUI.CategoryInfo>();
1439
1440                 string[] missingCategories = m_ParameterControllers.Select(t => t.Key.category).Where(t => !string.IsNullOrEmpty(t)).Except(categories.Select(t => t.name)).ToArray();
1441
1442                 HashSet<string> foundCategories = new HashSet<string>();
1443
1444                 for (int i = 0; i < categories.Count; ++i)
1445                 {
1446                     string category = categories[i].name;
1447                     if (string.IsNullOrEmpty(category) || foundCategories.Contains(category))
1448                     {
1449                         categories.RemoveAt(i);
1450                         --i;
1451                     }
1452                     foundCategories.Add(category);
1453                 }
1454
1455                 if (missingCategories.Length > 0)
1456                 {
1457                     categories.AddRange(missingCategories.Select(t => new VFXUI.CategoryInfo { name = t}));
1458                     ui.categories = categories;
1459                     ui.Modified();
1460                 }
1461             }
1462         }
1463
1464         public void ForceReload()
1465         {
1466             Clear();
1467             ModelChanged(model);
1468             GraphChanged();
1469         }
1470
1471         bool m_Syncing;
1472
1473         public bool SyncControllerFromModel(ref bool groupNodeChanged)
1474         {
1475             m_Syncing = true;
1476             bool changed = false;
1477             var toRemove = m_SyncedModels.Keys.Except(graph.children).ToList();
1478             foreach (var m in toRemove)
1479             {
1480                 RemoveControllersFromModel(m);
1481                 changed = true;
1482             }
1483
1484             var toAdd = graph.children.Except(m_SyncedModels.Keys).ToList();
1485             foreach (var m in toAdd)
1486             {
1487                 AddControllersFromModel(m);
1488                 changed = true;
1489             }
1490
1491
1492             // make sure every parameter instance is created before we look for edges
1493             foreach (var parameter in m_ParameterControllers.Values)
1494             {
1495                 parameter.UpdateControllers();
1496             }
1497
1498             changed |= RecreateNodeEdges();
1499             changed |= RecreateFlowEdges();
1500
1501             changed |= RecreateUI(ref groupNodeChanged);
1502
1503             m_Syncing = false;
1504             ValidateCategoryList();
1505             UpdateSystems();
1506             return changed;
1507         }
1508
1509         Dictionary<VFXParameter, VFXParameterController> m_ParameterControllers = new Dictionary<VFXParameter, VFXParameterController>();
1510
1511         public IEnumerable<VFXParameterController> parameterControllers
1512         {
1513             get { return m_ParameterControllers.Values; }
1514         }
1515
1516
1517         public void MoveCategory(string category, int index)
1518         {
1519             if (graph.UIInfos.categories == null)
1520                 return;
1521             int oldIndex = graph.UIInfos.categories.FindIndex(t => t.name == category);
1522
1523             if (oldIndex == -1 || oldIndex == index)
1524                 return;
1525             graph.UIInfos.categories.RemoveAt(oldIndex);
1526             if (index < graph.UIInfos.categories.Count)
1527                 graph.UIInfos.categories.Insert(index, new VFXUI.CategoryInfo { name = category });
1528             else
1529                 graph.UIInfos.categories.Add(new VFXUI.CategoryInfo { name = category });
1530
1531             graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1532         }
1533
1534         public bool SetCategoryName(int category, string newName)
1535         {
1536             if (category >= 0 && graph.UIInfos.categories != null && category < graph.UIInfos.categories.Count)
1537             {
1538                 if (graph.UIInfos.categories[category].name == newName)
1539                 {
1540                     return false;
1541                 }
1542                 if (!graph.UIInfos.categories.Any(t => t.name == newName))
1543                 {
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;
1548
1549                     foreach (var parameter in m_ParameterControllers)
1550                     {
1551                         if (parameter.Key.category == oldName)
1552                         {
1553                             parameter.Key.category = newName;
1554                         }
1555                     }
1556
1557
1558                     graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1559                     return true;
1560                 }
1561                 else
1562                 {
1563                     Debug.LogError("Can't change name, category with the same name already exists");
1564                 }
1565             }
1566             else
1567             {
1568                 Debug.LogError("Can't change name, category not found");
1569             }
1570
1571             return false;
1572         }
1573
1574         public void RemoveCategory(string name)
1575         {
1576             int index = graph.UIInfos.categories.FindIndex(t => t.name == name);
1577
1578             if (index > -1)
1579             {
1580                 var parametersToRemove = RemoveCategory(index);
1581
1582                 Remove(parametersToRemove.Cast<Controller>());
1583             }
1584         }
1585
1586         public IEnumerable<VFXParameterController> RemoveCategory(int category)
1587         {
1588             if (category >= 0 && graph.UIInfos.categories != null && category < graph.UIInfos.categories.Count)
1589             {
1590                 string name = graph.UIInfos.categories[category].name;
1591
1592                 graph.UIInfos.categories.RemoveAt(category);
1593                 graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1594
1595                 return m_ParameterControllers.Values.Where(t => t.model.category == name);
1596             }
1597             return Enumerable.Empty<VFXParameterController>();
1598         }
1599
1600         // The default version
1601         public void SetParametersOrder(VFXParameterController controller, int index, bool input)
1602         {
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();
1605
1606             int oldIndex = orderedParameters.IndexOf(controller);
1607
1608             if (oldIndex != -1)
1609             {
1610                 orderedParameters.RemoveAt(oldIndex);
1611
1612                 if (oldIndex < index)
1613                     --index;
1614             }
1615
1616             controller.isOutput = !input;
1617
1618             if (index < orderedParameters.Count)
1619                 orderedParameters.Insert(index, controller);
1620             else
1621                 orderedParameters.Add(controller);
1622
1623             for (int i = 0; i < orderedParameters.Count; ++i)
1624             {
1625                 orderedParameters[i].order = i;
1626             }
1627             NotifyChange(AnyThing);
1628         }
1629
1630         //The category version
1631         public void SetParametersOrder(VFXParameterController controller, int index, string category)
1632         {
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();
1635
1636             int oldIndex = orderedParameters.IndexOf(controller);
1637
1638
1639             if (oldIndex != -1)
1640             {
1641                 orderedParameters.RemoveAt(oldIndex);
1642
1643                 if (oldIndex < index)
1644                 {
1645                     --index;
1646                 }
1647             }
1648
1649             controller.model.category = category;
1650
1651             if (index < orderedParameters.Count)
1652             {
1653                 orderedParameters.Insert(index, controller);
1654             }
1655             else
1656             {
1657                 orderedParameters.Add(controller);
1658             }
1659
1660             for (int i = 0; i < orderedParameters.Count; ++i)
1661             {
1662                 orderedParameters[i].order = i;
1663             }
1664             NotifyChange(AnyThing);
1665         }
1666
1667         public void SetCategoryExpanded(string category, bool expanded)
1668         {
1669             if (graph.UIInfos.categories != null)
1670             {
1671                 for (int i = 0; i < graph.UIInfos.categories.Count; ++i)
1672                 {
1673                     if (graph.UIInfos.categories[i].name == category)
1674                     {
1675                         graph.UIInfos.categories[i] = new VFXUI.CategoryInfo { name = category, collapsed = !expanded };
1676                     }
1677                 }
1678             }
1679             NotifyChange(AnyThing);
1680         }
1681
1682         private void AddControllersFromModel(VFXModel model)
1683         {
1684             List<VFXNodeController> newControllers = new List<VFXNodeController>();
1685             if (model is VFXOperator)
1686             {
1687                 if (model is VFXOperatorNumericCascadedUnified)
1688                     newControllers.Add(new VFXCascadedOperatorController(model as VFXOperator, this));
1689                 else if (model is VFXOperatorNumericUniform)
1690                 {
1691                     newControllers.Add(new VFXNumericUniformOperatorController(model as VFXOperator, this));
1692                 }
1693                 else if (model is VFXOperatorNumericUnified)
1694                 {
1695                     if (model is IVFXOperatorNumericUnifiedConstrained)
1696                         newControllers.Add(new VFXUnifiedConstraintOperatorController(model as VFXOperator, this));
1697                     else
1698                         newControllers.Add(new VFXUnifiedOperatorController(model as VFXOperator, this));
1699                 }
1700                 else if (model is Branch)
1701                 {
1702                     newControllers.Add(new VFXBranchOperatorController(model as VFXOperator, this));
1703                 }
1704                 else
1705                     newControllers.Add(new VFXOperatorController(model as VFXOperator, this));
1706             }
1707             else if (model is VFXContext)
1708             {
1709                 newControllers.Add(new VFXContextController(model as VFXContext, this));
1710             }
1711             else if (model is VFXParameter)
1712             {
1713                 VFXParameter parameter = model as VFXParameter;
1714
1715                 if ( parameter.isOutput)
1716                 {
1717                     if(parameter.GetNbInputSlots() < 1)
1718                     {
1719                         parameter.AddSlot(VFXSlot.Create(new VFXProperty(typeof(float),"i"),VFXSlot.Direction.kInput));
1720                     }
1721                     while (parameter.GetNbInputSlots() > 1)
1722                     {
1723                         parameter.RemoveSlot(parameter.inputSlots[1]);
1724                     }
1725                     while (parameter.GetNbOutputSlots() > 0)
1726                     {
1727                         parameter.RemoveSlot(parameter.outputSlots[0]);
1728                     }
1729                 }
1730                 else
1731                 {
1732                     if (parameter.GetNbOutputSlots() < 1)
1733                     {
1734                         parameter.AddSlot(VFXSlot.Create(new VFXProperty(typeof(float), "o"), VFXSlot.Direction.kOutput));
1735                     }
1736                     while (parameter.GetNbOutputSlots() > 1)
1737                     {
1738                         parameter.RemoveSlot(parameter.outputSlots[1]);
1739                     }
1740                     while (parameter.GetNbInputSlots() > 0)
1741                     {
1742                         parameter.RemoveSlot(parameter.inputSlots[0]);
1743                     }
1744                 }
1745
1746                 parameter.ValidateNodes();
1747
1748                 m_ParameterControllers[parameter] = new VFXParameterController(parameter, this);
1749
1750                 m_SyncedModels[model] = new List<VFXNodeController>();
1751             }
1752
1753             if (newControllers.Count > 0)
1754             {
1755                 List<VFXNodeController> existingControllers;
1756                 if (m_SyncedModels.TryGetValue(model, out existingControllers))
1757                 {
1758                     Debug.LogError("adding a model to controllers twice");
1759                 }
1760                 m_SyncedModels[model] = newControllers;
1761                 foreach (var controller in newControllers)
1762                 {
1763                     controller.ForceUpdate();
1764                 }
1765             }
1766         }
1767
1768         public void AddControllerToModel(VFXModel model, VFXNodeController controller)
1769         {
1770             m_SyncedModels[model].Add(controller);
1771         }
1772
1773         public void RemoveControllerFromModel(VFXModel model, VFXNodeController controller)
1774         {
1775             m_SyncedModels[model].Remove(controller);
1776         }
1777
1778         private void RemoveControllersFromModel(VFXModel model)
1779         {
1780             List<VFXNodeController> controllers = null;
1781             if (m_SyncedModels.TryGetValue(model, out controllers))
1782             {
1783                 foreach (var controller in controllers)
1784                 {
1785                     controller.OnDisable();
1786                 }
1787                 m_SyncedModels.Remove(model);
1788             }
1789             if (model is VFXParameter)
1790             {
1791                 m_ParameterControllers[model as VFXParameter].OnDisable();
1792                 m_ParameterControllers.Remove(model as VFXParameter);
1793             }
1794         }
1795
1796         public VFXNodeController GetNodeController(VFXModel model, int id)
1797         {
1798             if (model is VFXBlock)
1799             {
1800                 VFXContextController controller = GetRootNodeController(model.GetParent(), 0) as VFXContextController;
1801                 if (controller == null)
1802                     return null;
1803                 return controller.blockControllers.FirstOrDefault(t => t.model == model);
1804             }
1805             else
1806             {
1807                 return GetRootNodeController(model, id);
1808             }
1809         }
1810
1811         public void ChangeEventName(string oldName, string newName)
1812         {
1813             foreach (var context in m_SyncedModels.Keys.OfType<VFXBasicEvent>())
1814             {
1815                 if (context.eventName == oldName)
1816                     context.SetSettingValue("eventName", newName);
1817             }
1818         }
1819
1820         public VFXNodeController GetRootNodeController(VFXModel model, int id)
1821         {
1822             List<VFXNodeController> controller = null;
1823             m_SyncedModels.TryGetValue(model, out controller);
1824             if (controller == null) return null;
1825
1826             return controller.FirstOrDefault(t => t.id == id);
1827         }
1828
1829         public VFXStickyNoteController GetStickyNoteController(int index)
1830         {
1831             return m_StickyNoteControllers[index];
1832         }
1833
1834         public VFXParameterController GetParameterController(VFXParameter parameter)
1835         {
1836             VFXParameterController controller = null;
1837             m_ParameterControllers.TryGetValue(parameter, out controller);
1838             return controller;
1839         }
1840
1841         VFXUI.GroupInfo PrivateAddGroupNode(Vector2 position)
1842         {
1843             var ui = graph.UIInfos;
1844
1845             var newGroupInfo = new VFXUI.GroupInfo { title = "New Group Node", position = new Rect(position, Vector2.one * 100) };
1846
1847             if (ui.groupInfos != null)
1848                 ui.groupInfos = ui.groupInfos.Concat(Enumerable.Repeat(newGroupInfo, 1)).ToArray();
1849             else
1850                 ui.groupInfos = new VFXUI.GroupInfo[] { newGroupInfo };
1851
1852             return ui.groupInfos.Last();
1853         }
1854
1855         public void GroupNodes(IEnumerable<VFXNodeController> nodes)
1856         {
1857
1858             foreach( var g in groupNodes) // remove nodes from other exisitings groups
1859             {
1860                 g.RemoveNodes(nodes);
1861             }
1862             VFXUI.GroupInfo info = PrivateAddGroupNode(Vector2.zero);
1863
1864             info.contents = nodes.Select(t => new VFXNodeID(t.model, t.id)).ToArray();
1865
1866             m_Graph.Invalidate(VFXModel.InvalidationCause.kUIChanged);
1867         }
1868
1869         public void PutInSameGroupNodeAs(VFXNodeController target, VFXNodeController example)
1870         {
1871             var ui = graph.UIInfos;
1872             if (ui.groupInfos == null) return;
1873
1874             foreach (var groupNode in m_GroupNodeControllers)
1875             {
1876                 if (groupNode.nodes.Contains(example))
1877                 {
1878                     groupNode.AddNode(target);
1879                     break;
1880                 }
1881             }
1882         }
1883
1884
1885         List<VFXSystemController> m_Systems = new List<VFXSystemController>();
1886
1887         public ReadOnlyCollection<VFXSystemController> systems
1888         {
1889             get { return m_Systems.AsReadOnly(); }
1890         }
1891
1892         
1893
1894         public void UpdateSystems()
1895         {
1896             try
1897             {
1898             VFXContext[] directContexts = graph.children.OfType<VFXContext>().ToArray();
1899
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());
1902
1903             List<Dictionary<VFXContext, int>> systems = new List<Dictionary<VFXContext, int>>();
1904
1905
1906             while (initializes.Count > 0 || updates.Count > 0)
1907             {
1908                 int generation = 0;
1909
1910                 VFXContext currentContext;
1911                 if (initializes.Count > 0)
1912                 {
1913                     currentContext = initializes.First();
1914                     initializes.Remove(currentContext);
1915                 }
1916                 else
1917                 {
1918                     currentContext = updates.First();
1919                     updates.Remove(currentContext);
1920                 }
1921
1922                 Dictionary<VFXContext, int> system = new Dictionary<VFXContext, int>();
1923
1924                 system.Add(currentContext, generation);
1925
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)
1928                 {
1929                     ++generation;
1930
1931                     foreach (var child in allChildren)
1932                     {
1933                         initializes.Remove(child);
1934                         updates.Remove(child);
1935                         system.Add(child, generation);
1936                     }
1937
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)));
1940
1941                     allChildren = allSubChildren.Concat(allPreChildren).Except(system.Keys).ToList();
1942                 }
1943
1944                 if (system.Count > 1)
1945                     systems.Add(system);
1946             }
1947
1948             while (m_Systems.Count() < systems.Count())
1949             {
1950                 VFXSystemController systemController = new VFXSystemController(this,graph.UIInfos);
1951                 m_Systems.Add(systemController);
1952             }
1953
1954             while (m_Systems.Count() > systems.Count())
1955             {
1956                 VFXSystemController systemController = m_Systems.Last();
1957                 m_Systems.RemoveAt(m_Systems.Count - 1);
1958                 systemController.OnDisable();
1959             }
1960
1961             for (int i = 0; i < systems.Count(); ++i)
1962             {
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);
1966
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();
1970
1971                 char letter = 'A';
1972                 foreach (var context in orderedContexts)
1973                 {
1974                     if (context.contextType == type)
1975                     {
1976                         if (prevContext != null)
1977                         {
1978                             letter = 'A';
1979                             prevContext.letter = letter;
1980                             prevContext = null;
1981                         }
1982
1983                         if (letter == 'Z') // loop back to A in the unlikely event that there are more than 26 contexts
1984                             letter = 'a';
1985                         else if( letter == 'z')
1986                             letter = 'α';
1987                         else if( letter == 'ω')
1988                             letter = 'A';
1989                         context.letter = ++letter;
1990                     }
1991                     else
1992                     {
1993                         context.letter = '\0';
1994                         prevContext = context;
1995                     }
1996                     type = context.contextType;
1997                 }
1998
1999             }
2000             }
2001             catch(Exception e)
2002             {
2003                 Debug.LogException(e);
2004             }
2005         }
2006         private VFXGraph m_Graph;
2007
2008         private VFXUI m_UI;
2009
2010         private VFXView m_View; // Don't call directly as it is lazy initialized
2011     }
2012 }