VFXViewWindow.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #define USE_EXIT_WORKAROUND_FOGBUGZ_1062258
  2. using System;
  3. using System.Linq;
  4. using UnityEditor.UIElements;
  5. using UnityEditor.Experimental.GraphView;
  6. using UnityEngine;
  7. using UnityEngine.VFX;
  8. using UnityEditor.VFX;
  9. using UnityEngine.UIElements;
  10. using System.Collections.Generic;
  11. using UnityEditor;
  12. using UnityObject = UnityEngine.Object;
  13. using System.IO;
  14. using UnityEditor.VersionControl;
  15. namespace UnityEditor.VFX.UI
  16. {
  17. [Serializable]
  18. class VFXViewWindow : EditorWindow
  19. {
  20. ShortcutHandler m_ShortcutHandler;
  21. protected void SetupFramingShortcutHandler(VFXView view)
  22. {
  23. m_ShortcutHandler = new ShortcutHandler(
  24. new Dictionary<Event, ShortcutDelegate>
  25. {
  26. {Event.KeyboardEvent("a"), view.FrameAll },
  27. {Event.KeyboardEvent("f"), view.FrameSelection },
  28. {Event.KeyboardEvent("o"), view.FrameOrigin },
  29. {Event.KeyboardEvent("^#>"), view.FramePrev },
  30. {Event.KeyboardEvent("^>"), view.FrameNext },
  31. {Event.KeyboardEvent("F7"), view.Compile},
  32. {Event.KeyboardEvent("#d"), view.OutputToDot},
  33. {Event.KeyboardEvent("^&d"), view.DuplicateSelectionWithEdges},
  34. {Event.KeyboardEvent("^#d"), view.OutputToDotReduced},
  35. {Event.KeyboardEvent("#c"), view.OutputToDotConstantFolding},
  36. {Event.KeyboardEvent("^r"), view.ReinitComponents},
  37. {Event.KeyboardEvent("F5"), view.ReinitComponents},
  38. {Event.KeyboardEvent("#^r"), view.ReinitAndPlayComponents},
  39. {Event.KeyboardEvent("#F5"), view.ReinitAndPlayComponents},
  40. });
  41. }
  42. public static VFXViewWindow currentWindow;
  43. [MenuItem("Window/Visual Effects/Visual Effect Graph", false, 3011)]
  44. public static void ShowWindow()
  45. {
  46. VFXLibrary.LogUnsupportedSRP();
  47. GetWindow<VFXViewWindow>();
  48. }
  49. public VFXView graphView
  50. {
  51. get; private set;
  52. }
  53. public void LoadAsset(VisualEffectAsset asset, VisualEffect effectToAttach)
  54. {
  55. VFXLibrary.LogUnsupportedSRP();
  56. string assetPath = AssetDatabase.GetAssetPath(asset);
  57. VisualEffectResource resource = VisualEffectResource.GetResourceAtPath(assetPath);
  58. //Transitionning code
  59. if (resource == null)
  60. {
  61. resource = new VisualEffectResource();
  62. resource.SetAssetPath(AssetDatabase.GetAssetPath(asset));
  63. }
  64. LoadResource(resource, effectToAttach);
  65. }
  66. public void LoadResource(VisualEffectResource resource, VisualEffect effectToAttach = null)
  67. {
  68. m_ResourceHistory.Clear();
  69. if (graphView.controller == null || graphView.controller.model != resource)
  70. {
  71. InternalLoadResource(resource);
  72. }
  73. if (effectToAttach != null && graphView.controller != null && graphView.controller.model != null && effectToAttach.visualEffectAsset == graphView.controller.model.asset)
  74. graphView.attachedComponent = effectToAttach;
  75. }
  76. List<VisualEffectResource> m_ResourceHistory = new List<VisualEffectResource>();
  77. public IEnumerable<VisualEffectResource> resourceHistory
  78. {
  79. get { return m_ResourceHistory; }
  80. }
  81. public void PushResource(VisualEffectResource resource)
  82. {
  83. if (graphView.controller == null || graphView.controller.model != resource)
  84. {
  85. m_ResourceHistory.Add(m_DisplayedResource);
  86. InternalLoadResource(resource);
  87. }
  88. }
  89. void InternalLoadResource(VisualEffectResource resource)
  90. {
  91. m_DisplayedResource = resource;
  92. graphView.controller = VFXViewController.GetController(resource, true);
  93. graphView.UpdateGlobalSelection();
  94. graphView.FrameNewController();
  95. }
  96. public void PopResource()
  97. {
  98. InternalLoadResource(m_ResourceHistory.Last());
  99. m_ResourceHistory.RemoveAt(m_ResourceHistory.Count - 1);
  100. }
  101. protected VisualEffectResource GetCurrentResource()
  102. {
  103. var objs = Selection.objects;
  104. VisualEffectResource selectedResource = null;
  105. if (objs != null && objs.Length == 1)
  106. {
  107. if (objs[0] is VisualEffectAsset)
  108. {
  109. VisualEffectAsset asset = objs[0] as VisualEffectAsset;
  110. selectedResource = asset.GetResource();
  111. }
  112. else if (objs[0] is VisualEffectResource)
  113. {
  114. selectedResource = objs[0] as VisualEffectResource;
  115. }
  116. }
  117. if (selectedResource == null)
  118. {
  119. int instanceID = Selection.activeInstanceID;
  120. if (instanceID != 0)
  121. {
  122. string path = AssetDatabase.GetAssetPath(instanceID);
  123. if (path.EndsWith(VisualEffectResource.Extension))
  124. {
  125. selectedResource = VisualEffectResource.GetResourceAtPath(path);
  126. }
  127. }
  128. }
  129. if (selectedResource == null && m_DisplayedResource != null)
  130. {
  131. selectedResource = m_DisplayedResource;
  132. }
  133. return selectedResource;
  134. }
  135. Action m_OnUpdateAction;
  136. protected void CreateGUI()
  137. {
  138. VFXManagerEditor.CheckVFXManager();
  139. if (m_ResourceHistory == null)
  140. m_ResourceHistory = new List<VisualEffectResource>();
  141. graphView = new VFXView();
  142. graphView.StretchToParentSize();
  143. SetupFramingShortcutHandler(graphView);
  144. rootVisualElement.Add(graphView);
  145. // make sure we don't do something that might touch the model on the view OnEnable because
  146. // the models OnEnable might be called after in the case of a domain reload.
  147. m_OnUpdateAction = () =>
  148. {
  149. var currentAsset = GetCurrentResource();
  150. if (currentAsset != null)
  151. {
  152. LoadResource(currentAsset);
  153. }
  154. };
  155. autoCompile = true;
  156. graphView.RegisterCallback<AttachToPanelEvent>(OnEnterPanel);
  157. graphView.RegisterCallback<DetachFromPanelEvent>(OnLeavePanel);
  158. if (rootVisualElement.panel != null)
  159. {
  160. rootVisualElement.AddManipulator(m_ShortcutHandler);
  161. }
  162. currentWindow = this;
  163. #if USE_EXIT_WORKAROUND_FOGBUGZ_1062258
  164. EditorApplication.wantsToQuit += Quitting_Workaround;
  165. #endif
  166. var icon = AssetDatabase.LoadAssetAtPath<Texture2D>(VisualEffectAssetEditorUtility.editorResourcesPath + "/VFX/" + (EditorGUIUtility.isProSkin ? "vfx_graph_icon_gray_dark.png" : "vfx_graph_icon_gray_light.png"));
  167. titleContent.image = icon;
  168. }
  169. #if USE_EXIT_WORKAROUND_FOGBUGZ_1062258
  170. private bool Quitting_Workaround()
  171. {
  172. if (graphView != null)
  173. graphView.controller = null;
  174. return true;
  175. }
  176. #endif
  177. protected void OnDestroy()
  178. {
  179. #if USE_EXIT_WORKAROUND_FOGBUGZ_1062258
  180. EditorApplication.wantsToQuit -= Quitting_Workaround;
  181. #endif
  182. if (graphView != null)
  183. {
  184. graphView.UnregisterCallback<AttachToPanelEvent>(OnEnterPanel);
  185. graphView.UnregisterCallback<DetachFromPanelEvent>(OnLeavePanel);
  186. graphView.controller = null;
  187. graphView.Dispose();
  188. graphView = null;
  189. }
  190. currentWindow = null;
  191. }
  192. void OnEnterPanel(AttachToPanelEvent e)
  193. {
  194. rootVisualElement.AddManipulator(m_ShortcutHandler);
  195. }
  196. void OnLeavePanel(DetachFromPanelEvent e)
  197. {
  198. rootVisualElement.RemoveManipulator(m_ShortcutHandler);
  199. }
  200. void OnFocus()
  201. {
  202. if (graphView != null) // OnFocus can be somehow called before OnEnable
  203. graphView.OnFocus();
  204. }
  205. public void OnVisualEffectComponentChanged(IEnumerable<VisualEffect> componentChanged)
  206. {
  207. if (graphView != null)
  208. graphView.OnVisualEffectComponentChanged(componentChanged);
  209. }
  210. public bool autoCompile { get; set; }
  211. void Update()
  212. {
  213. if (graphView == null)
  214. return;
  215. if (m_OnUpdateAction != null)
  216. {
  217. m_OnUpdateAction();
  218. m_OnUpdateAction = null;
  219. }
  220. VFXViewController controller = graphView.controller;
  221. var filename = "No Asset";
  222. if (controller != null)
  223. {
  224. controller.NotifyUpdate();
  225. if (controller.model != null)
  226. {
  227. var graph = controller.graph;
  228. if (graph != null)
  229. {
  230. filename = controller.name;
  231. if (EditorUtility.IsDirty(graph))
  232. {
  233. filename += "*";
  234. }
  235. if (autoCompile && graph.IsExpressionGraphDirty() && !graph.GetResource().isSubgraph)
  236. {
  237. VFXGraph.explicitCompile = true;
  238. graph.errorManager.ClearAllErrors(null, VFXErrorOrigin.Compilation);
  239. using (var reporter = new VFXCompileErrorReporter(controller.graph.errorManager))
  240. {
  241. VFXGraph.compileReporter = reporter;
  242. AssetDatabase.ImportAsset(AssetDatabase.GetAssetPath(graphView.controller.model));
  243. graph.SetExpressionGraphDirty(false); // As are implemented subgraph now, compiling dependents chain can reset dirty flag on used subgraphs, which will make an infinite loop, this is bad!
  244. VFXGraph.compileReporter = null;
  245. }
  246. VFXGraph.explicitCompile = false;
  247. }
  248. else
  249. graph.RecompileIfNeeded(true, true);
  250. bool wasDirty = graph.IsExpressionGraphDirty();
  251. controller.RecompileExpressionGraphIfNeeded();
  252. // Hack to avoid infinite recompilation due to UI triggering a recompile TODO: Fix problematic cases that trigger that error
  253. if (!wasDirty && graph.IsExpressionGraphDirty())
  254. {
  255. Debug.LogError("Expression graph was marked as dirty after compiling context for UI. Discard to avoid infinite compilation loop.");
  256. graph.SetExpressionGraphDirty(false);
  257. }
  258. }
  259. }
  260. }
  261. if (VFXViewModificationProcessor.assetMoved)
  262. {
  263. graphView.AssetMoved();
  264. VFXViewModificationProcessor.assetMoved = false;
  265. }
  266. titleContent.text = filename;
  267. if (graphView?.controller?.model?.visualEffectObject != null)
  268. {
  269. graphView.checkoutButton.visible = true;
  270. if (!graphView.IsAssetEditable() && Provider.isActive && Provider.enabled)
  271. {
  272. graphView.checkoutButton.SetEnabled(true);
  273. }
  274. else
  275. {
  276. graphView.checkoutButton.SetEnabled(false);
  277. }
  278. }
  279. }
  280. [SerializeField]
  281. private VisualEffectResource m_DisplayedResource;
  282. }
  283. }