GraphEditorView.cs 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using UnityEngine;
  5. using UnityEditor.Graphing;
  6. using UnityEditor.Graphing.Util;
  7. using UnityEditor.ShaderGraph.Drawing.Inspector;
  8. using Object = UnityEngine.Object;
  9. using UnityEditor.Experimental.GraphView;
  10. using UnityEditor.ShaderGraph.Drawing.Colors;
  11. using UnityEditor.ShaderGraph.Internal;
  12. using UnityEngine.UIElements;
  13. using Edge = UnityEditor.Experimental.GraphView.Edge;
  14. using UnityEditor.VersionControl;
  15. namespace UnityEditor.ShaderGraph.Drawing
  16. {
  17. [Serializable]
  18. class FloatingWindowsLayout
  19. {
  20. public WindowDockingLayout previewLayout = new WindowDockingLayout();
  21. public WindowDockingLayout blackboardLayout = new WindowDockingLayout();
  22. public Vector2 masterPreviewSize = new Vector2(400, 400);
  23. }
  24. [Serializable]
  25. class UserViewSettings
  26. {
  27. public bool isBlackboardVisible = true;
  28. public bool isPreviewVisible = true;
  29. public string colorProvider = NoColors.Title;
  30. }
  31. class GraphEditorView : VisualElement, IDisposable
  32. {
  33. MaterialGraphView m_GraphView;
  34. MasterPreviewView m_MasterPreviewView;
  35. GraphData m_Graph;
  36. PreviewManager m_PreviewManager;
  37. MessageManager m_MessageManager;
  38. SearchWindowProvider m_SearchWindowProvider;
  39. EdgeConnectorListener m_EdgeConnectorListener;
  40. BlackboardProvider m_BlackboardProvider;
  41. ColorManager m_ColorManager;
  42. public BlackboardProvider blackboardProvider
  43. {
  44. get { return m_BlackboardProvider; }
  45. }
  46. const string k_UserViewSettings = "UnityEditor.ShaderGraph.ToggleSettings";
  47. UserViewSettings m_UserViewSettings;
  48. const string k_FloatingWindowsLayoutKey = "UnityEditor.ShaderGraph.FloatingWindowsLayout2";
  49. FloatingWindowsLayout m_FloatingWindowsLayout;
  50. public Action saveRequested { get; set; }
  51. public Func<bool> isCheckedOut { get; set; }
  52. public Action checkOut { get; set; }
  53. public Action convertToSubgraphRequested
  54. {
  55. get { return m_GraphView.onConvertToSubgraphClick; }
  56. set { m_GraphView.onConvertToSubgraphClick = value; }
  57. }
  58. public Action showInProjectRequested { get; set; }
  59. public MaterialGraphView graphView
  60. {
  61. get { return m_GraphView; }
  62. }
  63. PreviewManager previewManager
  64. {
  65. get { return m_PreviewManager; }
  66. set { m_PreviewManager = value; }
  67. }
  68. public string assetName
  69. {
  70. get { return m_BlackboardProvider.assetName; }
  71. set
  72. {
  73. m_BlackboardProvider.assetName = value;
  74. }
  75. }
  76. public ColorManager colorManager
  77. {
  78. get => m_ColorManager;
  79. }
  80. public GraphEditorView(EditorWindow editorWindow, GraphData graph, MessageManager messageManager)
  81. {
  82. m_GraphViewGroupTitleChanged = OnGroupTitleChanged;
  83. m_GraphViewElementsAddedToGroup = OnElementsAddedToGroup;
  84. m_GraphViewElementsRemovedFromGroup = OnElementsRemovedFromGroup;
  85. m_Graph = graph;
  86. m_MessageManager = messageManager;
  87. styleSheets.Add(Resources.Load<StyleSheet>("Styles/GraphEditorView"));
  88. previewManager = new PreviewManager(graph, messageManager);
  89. previewManager.onPrimaryMasterChanged = OnPrimaryMasterChanged;
  90. var serializedSettings = EditorUserSettings.GetConfigValue(k_UserViewSettings);
  91. m_UserViewSettings = JsonUtility.FromJson<UserViewSettings>(serializedSettings) ?? new UserViewSettings();
  92. m_ColorManager = new ColorManager(m_UserViewSettings.colorProvider);
  93. string serializedWindowLayout = EditorUserSettings.GetConfigValue(k_FloatingWindowsLayoutKey);
  94. if (!string.IsNullOrEmpty(serializedWindowLayout))
  95. {
  96. m_FloatingWindowsLayout = JsonUtility.FromJson<FloatingWindowsLayout>(serializedWindowLayout);
  97. }
  98. else
  99. {
  100. m_FloatingWindowsLayout = new FloatingWindowsLayout
  101. {
  102. blackboardLayout =
  103. {
  104. dockingTop = true,
  105. dockingLeft = true,
  106. verticalOffset = 16,
  107. horizontalOffset = 16,
  108. size = new Vector2(200, 400)
  109. }
  110. };
  111. }
  112. if (m_FloatingWindowsLayout.masterPreviewSize.x > 0f && m_FloatingWindowsLayout.masterPreviewSize.y > 0f)
  113. {
  114. previewManager.ResizeMasterPreview(m_FloatingWindowsLayout.masterPreviewSize);
  115. }
  116. previewManager.RenderPreviews();
  117. var colorProviders = m_ColorManager.providerNames.ToArray();
  118. var toolbar = new IMGUIContainer(() =>
  119. {
  120. GUILayout.BeginHorizontal(EditorStyles.toolbar);
  121. if (GUILayout.Button("Save Asset", EditorStyles.toolbarButton))
  122. {
  123. if (saveRequested != null)
  124. saveRequested();
  125. }
  126. GUILayout.Space(6);
  127. if (GUILayout.Button("Show In Project", EditorStyles.toolbarButton))
  128. {
  129. if (showInProjectRequested != null)
  130. showInProjectRequested();
  131. }
  132. EditorGUI.BeginChangeCheck();
  133. GUILayout.Label("Precision");
  134. graph.concretePrecision = (ConcretePrecision)EditorGUILayout.EnumPopup(graph.concretePrecision, GUILayout.Width(100f));
  135. GUILayout.Space(4);
  136. if (EditorGUI.EndChangeCheck())
  137. {
  138. var nodeList = m_GraphView.Query<MaterialNodeView>().ToList();
  139. m_ColorManager.SetNodesDirty(nodeList);
  140. graph.ValidateGraph();
  141. m_ColorManager.UpdateNodeViews(nodeList);
  142. foreach (var node in graph.GetNodes<AbstractMaterialNode>())
  143. {
  144. node.Dirty(ModificationScope.Graph);
  145. }
  146. }
  147. if (isCheckedOut != null)
  148. {
  149. if (!isCheckedOut() && Provider.enabled && Provider.isActive)
  150. {
  151. if (GUILayout.Button("Check Out", EditorStyles.toolbarButton))
  152. {
  153. if (checkOut != null)
  154. checkOut();
  155. }
  156. }
  157. else
  158. {
  159. EditorGUI.BeginDisabledGroup(true);
  160. GUILayout.Button("Check Out", EditorStyles.toolbarButton);
  161. EditorGUI.EndDisabledGroup();
  162. }
  163. }
  164. GUILayout.FlexibleSpace();
  165. EditorGUI.BeginChangeCheck();
  166. GUILayout.Label("Color Mode");
  167. var newColorIdx = EditorGUILayout.Popup(m_ColorManager.activeIndex, colorProviders, GUILayout.Width(100f));
  168. GUILayout.Space(4);
  169. m_UserViewSettings.isBlackboardVisible = GUILayout.Toggle(m_UserViewSettings.isBlackboardVisible, "Blackboard", EditorStyles.toolbarButton);
  170. GUILayout.Space(6);
  171. m_UserViewSettings.isPreviewVisible = GUILayout.Toggle(m_UserViewSettings.isPreviewVisible, "Main Preview", EditorStyles.toolbarButton);
  172. if (EditorGUI.EndChangeCheck())
  173. {
  174. if(newColorIdx != m_ColorManager.activeIndex)
  175. {
  176. m_ColorManager.SetActiveProvider(newColorIdx, m_GraphView.Query<MaterialNodeView>().ToList());
  177. m_UserViewSettings.colorProvider = m_ColorManager.activeProviderName;
  178. }
  179. UpdateSubWindowsVisibility();
  180. var serializedViewSettings = JsonUtility.ToJson(m_UserViewSettings);
  181. EditorUserSettings.SetConfigValue(k_UserViewSettings, serializedViewSettings);
  182. }
  183. GUILayout.EndHorizontal();
  184. });
  185. Add(toolbar);
  186. var content = new VisualElement { name = "content" };
  187. {
  188. m_GraphView = new MaterialGraphView(graph) { name = "GraphView", viewDataKey = "MaterialGraphView" };
  189. m_GraphView.SetupZoom(0.05f, ContentZoomer.DefaultMaxScale);
  190. m_GraphView.AddManipulator(new ContentDragger());
  191. m_GraphView.AddManipulator(new SelectionDragger());
  192. m_GraphView.AddManipulator(new RectangleSelector());
  193. m_GraphView.AddManipulator(new ClickSelector());
  194. m_GraphView.RegisterCallback<KeyDownEvent>(OnKeyDown);
  195. RegisterGraphViewCallbacks();
  196. content.Add(m_GraphView);
  197. m_BlackboardProvider = new BlackboardProvider(graph);
  198. m_GraphView.Add(m_BlackboardProvider.blackboard);
  199. CreateMasterPreview();
  200. UpdateSubWindowsVisibility();
  201. m_GraphView.graphViewChanged = GraphViewChanged;
  202. RegisterCallback<GeometryChangedEvent>(ApplySerializewindowLayouts);
  203. if (m_Graph.isSubGraph)
  204. {
  205. m_GraphView.AddToClassList("subgraph");
  206. }
  207. }
  208. m_SearchWindowProvider = ScriptableObject.CreateInstance<SearchWindowProvider>();
  209. m_SearchWindowProvider.Initialize(editorWindow, m_Graph, m_GraphView);
  210. m_GraphView.nodeCreationRequest = (c) =>
  211. {
  212. m_SearchWindowProvider.connectedPort = null;
  213. SearchWindow.Open(new SearchWindowContext(c.screenMousePosition), m_SearchWindowProvider);
  214. };
  215. m_EdgeConnectorListener = new EdgeConnectorListener(m_Graph, m_SearchWindowProvider);
  216. foreach (var graphGroup in graph.groups)
  217. {
  218. AddGroup(graphGroup);
  219. }
  220. foreach (var stickyNote in graph.stickyNotes)
  221. {
  222. AddStickyNote(stickyNote);
  223. }
  224. foreach (var node in graph.GetNodes<AbstractMaterialNode>())
  225. AddNode(node);
  226. foreach (var edge in graph.edges)
  227. AddEdge(edge);
  228. Add(content);
  229. }
  230. void UpdateSubWindowsVisibility()
  231. {
  232. m_MasterPreviewView.visible = m_UserViewSettings.isPreviewVisible;
  233. if (m_UserViewSettings.isBlackboardVisible)
  234. m_BlackboardProvider.blackboard.style.display = DisplayStyle.Flex;
  235. else
  236. m_BlackboardProvider.blackboard.style.display = DisplayStyle.None;
  237. }
  238. Action<Group, string> m_GraphViewGroupTitleChanged;
  239. Action<Group, IEnumerable<GraphElement>> m_GraphViewElementsAddedToGroup;
  240. Action<Group, IEnumerable<GraphElement>> m_GraphViewElementsRemovedFromGroup;
  241. void RegisterGraphViewCallbacks()
  242. {
  243. m_GraphView.groupTitleChanged = m_GraphViewGroupTitleChanged;
  244. m_GraphView.elementsAddedToGroup = m_GraphViewElementsAddedToGroup;
  245. m_GraphView.elementsRemovedFromGroup = m_GraphViewElementsRemovedFromGroup;
  246. }
  247. void UnregisterGraphViewCallbacks()
  248. {
  249. m_GraphView.groupTitleChanged = null;
  250. m_GraphView.elementsAddedToGroup = null;
  251. m_GraphView.elementsRemovedFromGroup = null;
  252. }
  253. void CreateMasterPreview()
  254. {
  255. m_MasterPreviewView = new MasterPreviewView(previewManager, m_Graph) {name = "masterPreview"};
  256. var masterPreviewViewDraggable = new WindowDraggable(null, this);
  257. m_MasterPreviewView.AddManipulator(masterPreviewViewDraggable);
  258. m_GraphView.Add(m_MasterPreviewView);
  259. masterPreviewViewDraggable.OnDragFinished += UpdateSerializedWindowLayout;
  260. m_MasterPreviewView.previewResizeBorderFrame.OnResizeFinished += UpdateSerializedWindowLayout;
  261. }
  262. void OnKeyDown(KeyDownEvent evt)
  263. {
  264. if (evt.keyCode == KeyCode.F1)
  265. {
  266. var selection = m_GraphView.selection.OfType<IShaderNodeView>();
  267. if (selection.Count() == 1)
  268. {
  269. var nodeView = selection.First();
  270. if (nodeView.node.documentationURL != null)
  271. {
  272. System.Diagnostics.Process.Start(nodeView.node.documentationURL);
  273. }
  274. }
  275. }
  276. if (evt.ctrlKey && evt.keyCode == KeyCode.G)
  277. {
  278. if (m_GraphView.selection.OfType<MaterialNodeView>().Any())
  279. {
  280. m_GraphView.GroupSelection();
  281. }
  282. }
  283. }
  284. GraphViewChange GraphViewChanged(GraphViewChange graphViewChange)
  285. {
  286. if (graphViewChange.edgesToCreate != null)
  287. {
  288. foreach (var edge in graphViewChange.edgesToCreate)
  289. {
  290. var leftSlot = edge.output.GetSlot();
  291. var rightSlot = edge.input.GetSlot();
  292. if (leftSlot != null && rightSlot != null)
  293. {
  294. m_Graph.owner.RegisterCompleteObjectUndo("Connect Edge");
  295. m_Graph.Connect(leftSlot.slotReference, rightSlot.slotReference);
  296. }
  297. }
  298. graphViewChange.edgesToCreate.Clear();
  299. }
  300. if (graphViewChange.movedElements != null)
  301. {
  302. m_Graph.owner.RegisterCompleteObjectUndo("Move Elements");
  303. List<GraphElement> nodesInsideGroup = new List<GraphElement>();
  304. foreach (var element in graphViewChange.movedElements)
  305. {
  306. var groupNode = element as ShaderGroup;
  307. if (groupNode == null)
  308. continue;
  309. foreach (GraphElement graphElement in groupNode.containedElements)
  310. {
  311. nodesInsideGroup.Add(graphElement);
  312. }
  313. SetGroupPosition(groupNode);
  314. }
  315. if(nodesInsideGroup.Any())
  316. graphViewChange.movedElements.AddRange(nodesInsideGroup);
  317. foreach (var element in graphViewChange.movedElements)
  318. {
  319. if (element.userData is AbstractMaterialNode node)
  320. {
  321. var drawState = node.drawState;
  322. drawState.position = element.parent.ChangeCoordinatesTo(m_GraphView.contentViewContainer, element.GetPosition());
  323. node.drawState = drawState;
  324. }
  325. if (element is StickyNote stickyNote)
  326. {
  327. SetStickyNotePosition(stickyNote);
  328. }
  329. }
  330. }
  331. var nodesToUpdate = m_NodeViewHashSet;
  332. nodesToUpdate.Clear();
  333. if (graphViewChange.elementsToRemove != null)
  334. {
  335. m_Graph.owner.RegisterCompleteObjectUndo("Remove Elements");
  336. m_Graph.RemoveElements(graphViewChange.elementsToRemove.OfType<IShaderNodeView>().Select(v => v.node).ToArray(),
  337. graphViewChange.elementsToRemove.OfType<Edge>().Select(e => (IEdge)e.userData).ToArray(),
  338. graphViewChange.elementsToRemove.OfType<ShaderGroup>().Select(g => g.userData).ToArray(),
  339. graphViewChange.elementsToRemove.OfType<StickyNote>().Select(n => n.userData).ToArray());
  340. foreach (var edge in graphViewChange.elementsToRemove.OfType<Edge>())
  341. {
  342. if (edge.input != null)
  343. {
  344. if (edge.input.node is IShaderNodeView materialNodeView)
  345. nodesToUpdate.Add(materialNodeView);
  346. }
  347. if (edge.output != null)
  348. {
  349. if (edge.output.node is IShaderNodeView materialNodeView)
  350. nodesToUpdate.Add(materialNodeView);
  351. }
  352. }
  353. }
  354. foreach (var node in nodesToUpdate)
  355. {
  356. if (node is MaterialNodeView materialNodeView)
  357. {
  358. materialNodeView.OnModified(ModificationScope.Topological);
  359. }
  360. }
  361. UpdateEdgeColors(nodesToUpdate);
  362. return graphViewChange;
  363. }
  364. void SetGroupPosition(ShaderGroup groupNode)
  365. {
  366. var pos = groupNode.GetPosition();
  367. groupNode.userData.position = new Vector2(pos.x, pos.y);
  368. }
  369. void SetStickyNotePosition(StickyNote stickyNote)
  370. {
  371. var pos = stickyNote.GetPosition();
  372. stickyNote.userData.position = new Rect(pos);
  373. }
  374. void OnGroupTitleChanged(Group graphGroup, string title)
  375. {
  376. var groupData = graphGroup.userData as GroupData;
  377. if (groupData != null)
  378. {
  379. groupData.title = graphGroup.title;
  380. }
  381. }
  382. void OnElementsAddedToGroup(Group graphGroup, IEnumerable<GraphElement> elements)
  383. {
  384. if (graphGroup.userData is GroupData groupData)
  385. {
  386. var anyChanged = false;
  387. foreach (var element in elements)
  388. {
  389. if (element.userData is IGroupItem groupItem && groupItem.groupGuid != groupData.guid)
  390. {
  391. anyChanged = true;
  392. break;
  393. }
  394. }
  395. if (!anyChanged)
  396. return;
  397. m_Graph.owner.RegisterCompleteObjectUndo(groupData.title);
  398. foreach (var element in elements)
  399. {
  400. if (element.userData is IGroupItem groupItem)
  401. {
  402. m_Graph.SetGroup(groupItem, groupData);
  403. }
  404. }
  405. }
  406. }
  407. void OnElementsRemovedFromGroup(Group graphGroup, IEnumerable<GraphElement> elements)
  408. {
  409. if (graphGroup.userData is GroupData groupData)
  410. {
  411. var anyChanged = false;
  412. foreach (var element in elements)
  413. {
  414. if (element.userData is IGroupItem groupItem && groupItem.groupGuid == groupData.guid)
  415. {
  416. anyChanged = true;
  417. break;
  418. }
  419. }
  420. if (!anyChanged)
  421. return;
  422. m_Graph.owner.RegisterCompleteObjectUndo("Ungroup Node(s)");
  423. foreach (var element in elements)
  424. {
  425. if (element.userData is IGroupItem groupItem)
  426. {
  427. m_Graph.SetGroup(groupItem, null);
  428. SetGroupPosition((ShaderGroup)graphGroup); //, (GraphElement)nodeView);
  429. }
  430. }
  431. }
  432. }
  433. void OnNodeChanged(AbstractMaterialNode inNode, ModificationScope scope)
  434. {
  435. if (m_GraphView == null)
  436. return;
  437. var dependentNodes = new List<AbstractMaterialNode>();
  438. NodeUtils.CollectNodesNodeFeedsInto(dependentNodes, inNode);
  439. foreach (var node in dependentNodes)
  440. {
  441. var theViews = m_GraphView.nodes.ToList().OfType<IShaderNodeView>();
  442. var viewsFound = theViews.Where(x => x.node.guid == node.guid).ToList();
  443. foreach (var drawableNodeData in viewsFound)
  444. drawableNodeData.OnModified(scope);
  445. }
  446. }
  447. HashSet<IShaderNodeView> m_NodeViewHashSet = new HashSet<IShaderNodeView>();
  448. HashSet<ShaderGroup> m_GroupHashSet = new HashSet<ShaderGroup>();
  449. public void HandleGraphChanges()
  450. {
  451. UnregisterGraphViewCallbacks();
  452. if(previewManager.HandleGraphChanges())
  453. {
  454. var nodeList = m_GraphView.Query<MaterialNodeView>().ToList();
  455. m_ColorManager.SetNodesDirty(nodeList);
  456. m_ColorManager.UpdateNodeViews(nodeList);
  457. }
  458. previewManager.RenderPreviews();
  459. m_BlackboardProvider.HandleGraphChanges();
  460. m_GroupHashSet.Clear();
  461. foreach (var node in m_Graph.removedNodes)
  462. {
  463. node.UnregisterCallback(OnNodeChanged);
  464. var nodeView = m_GraphView.nodes.ToList().OfType<IShaderNodeView>()
  465. .FirstOrDefault(p => p.node != null && p.node.guid == node.guid);
  466. if (nodeView != null)
  467. {
  468. nodeView.Dispose();
  469. m_GraphView.RemoveElement((Node)nodeView);
  470. if (node.groupGuid != Guid.Empty)
  471. {
  472. var shaderGroup = m_GraphView.graphElements.ToList().OfType<ShaderGroup>().First(g => g.userData.guid == node.groupGuid);
  473. m_GroupHashSet.Add(shaderGroup);
  474. }
  475. }
  476. }
  477. foreach (var noteData in m_Graph.removedNotes)
  478. {
  479. var note = m_GraphView.graphElements.ToList().OfType<StickyNote>().First(n => n.userData == noteData);
  480. m_GraphView.RemoveElement(note);
  481. }
  482. foreach (GroupData groupData in m_Graph.removedGroups)
  483. {
  484. var group = m_GraphView.graphElements.ToList().OfType<ShaderGroup>().First(g => g.userData == groupData);
  485. m_GraphView.RemoveElement(group);
  486. }
  487. foreach (var groupData in m_Graph.addedGroups)
  488. {
  489. AddGroup(groupData);
  490. }
  491. foreach (var stickyNote in m_Graph.addedStickyNotes)
  492. {
  493. AddStickyNote(stickyNote);
  494. }
  495. foreach (var node in m_Graph.addedNodes)
  496. {
  497. AddNode(node);
  498. }
  499. foreach (var groupChange in m_Graph.parentGroupChanges)
  500. {
  501. GraphElement graphElement = null;
  502. if (groupChange.groupItem is AbstractMaterialNode node)
  503. {
  504. graphElement = m_GraphView.GetNodeByGuid(node.guid.ToString());
  505. }
  506. else if (groupChange.groupItem is StickyNoteData stickyNote)
  507. {
  508. graphElement = m_GraphView.GetElementByGuid(stickyNote.guid.ToString());
  509. }
  510. else
  511. {
  512. throw new InvalidOperationException("Unknown group item type.");
  513. }
  514. if (graphElement != null)
  515. {
  516. var groupView = graphElement.GetContainingScope() as ShaderGroup;
  517. if (groupView?.userData.guid != groupChange.newGroupGuid)
  518. {
  519. groupView?.RemoveElement(graphElement);
  520. if (groupChange.newGroupGuid != Guid.Empty)
  521. {
  522. var newGroupView = m_GraphView.graphElements.ToList()
  523. .OfType<ShaderGroup>()
  524. .First(x => x.userData.guid == groupChange.newGroupGuid);
  525. newGroupView.AddElement(graphElement);
  526. }
  527. }
  528. }
  529. }
  530. foreach (var groupData in m_Graph.pastedGroups)
  531. {
  532. var group = m_GraphView.graphElements.ToList().OfType<ShaderGroup>().ToList().First(g => g.userData == groupData);
  533. m_GraphView.AddToSelection(group);
  534. }
  535. foreach (var stickyNoteData in m_Graph.pastedStickyNotes)
  536. {
  537. var stickyNote = m_GraphView.graphElements.ToList().OfType<StickyNote>().First(s => s.userData == stickyNoteData);
  538. m_GraphView.AddToSelection(stickyNote);
  539. }
  540. foreach (var node in m_Graph.pastedNodes)
  541. {
  542. var nodeView = m_GraphView.nodes.ToList().OfType<IShaderNodeView>()
  543. .FirstOrDefault(p => p.node != null && p.node.guid == node.guid);
  544. m_GraphView.AddToSelection((Node)nodeView);
  545. }
  546. foreach (var shaderGroup in m_GroupHashSet)
  547. {
  548. SetGroupPosition(shaderGroup);
  549. }
  550. var nodesToUpdate = m_NodeViewHashSet;
  551. nodesToUpdate.Clear();
  552. foreach (var edge in m_Graph.removedEdges)
  553. {
  554. var edgeView = m_GraphView.graphElements.ToList().OfType<Edge>()
  555. .FirstOrDefault(p => p.userData is IEdge && Equals((IEdge) p.userData, edge));
  556. if (edgeView != null)
  557. {
  558. var nodeView = (IShaderNodeView)edgeView.input.node;
  559. if (nodeView?.node != null)
  560. {
  561. nodesToUpdate.Add(nodeView);
  562. }
  563. edgeView.output.Disconnect(edgeView);
  564. edgeView.input.Disconnect(edgeView);
  565. edgeView.output = null;
  566. edgeView.input = null;
  567. m_GraphView.RemoveElement(edgeView);
  568. }
  569. }
  570. foreach (var edge in m_Graph.addedEdges)
  571. {
  572. var edgeView = AddEdge(edge);
  573. if (edgeView != null)
  574. nodesToUpdate.Add((IShaderNodeView)edgeView.input.node);
  575. }
  576. foreach (var node in nodesToUpdate)
  577. {
  578. if (node is MaterialNodeView materialNodeView)
  579. {
  580. materialNodeView.OnModified(ModificationScope.Topological);
  581. }
  582. }
  583. UpdateEdgeColors(nodesToUpdate);
  584. // Checking if any new Group Nodes just got added
  585. if (m_Graph.mostRecentlyCreatedGroup != null)
  586. {
  587. var groups = m_GraphView.graphElements.ToList().OfType<ShaderGroup>();
  588. foreach (ShaderGroup shaderGroup in groups)
  589. {
  590. if (shaderGroup.userData == m_Graph.mostRecentlyCreatedGroup)
  591. {
  592. shaderGroup.FocusTitleTextField();
  593. break;
  594. }
  595. }
  596. }
  597. UpdateBadges();
  598. RegisterGraphViewCallbacks();
  599. }
  600. void UpdateBadges()
  601. {
  602. if (!m_MessageManager.nodeMessagesChanged)
  603. return;
  604. foreach (var messageData in m_MessageManager.GetNodeMessages())
  605. {
  606. var node = m_Graph.GetNodeFromTempId(messageData.Key);
  607. if (!(m_GraphView.GetNodeByGuid(node.guid.ToString()) is MaterialNodeView nodeView))
  608. continue;
  609. if (messageData.Value.Count == 0)
  610. {
  611. var badge = nodeView.Q<IconBadge>();
  612. badge?.Detach();
  613. badge?.RemoveFromHierarchy();
  614. }
  615. else
  616. {
  617. var foundMessage = messageData.Value.First();
  618. nodeView.AttachMessage(foundMessage.message, foundMessage.severity);
  619. }
  620. }
  621. }
  622. List<GraphElement> m_GraphElementsTemp = new List<GraphElement>();
  623. void AddNode(AbstractMaterialNode node)
  624. {
  625. var materialNode = (AbstractMaterialNode)node;
  626. Node nodeView;
  627. if (node is PropertyNode propertyNode)
  628. {
  629. var tokenNode = new PropertyNodeView(propertyNode, m_EdgeConnectorListener);
  630. m_GraphView.AddElement(tokenNode);
  631. nodeView = tokenNode;
  632. }
  633. else
  634. {
  635. var materialNodeView = new MaterialNodeView {userData = materialNode};
  636. m_GraphView.AddElement(materialNodeView);
  637. materialNodeView.Initialize(materialNode, m_PreviewManager, m_EdgeConnectorListener, graphView);
  638. m_ColorManager.UpdateNodeView(materialNodeView);
  639. nodeView = materialNodeView;
  640. }
  641. node.RegisterCallback(OnNodeChanged);
  642. nodeView.MarkDirtyRepaint();
  643. if (m_SearchWindowProvider.nodeNeedsRepositioning && m_SearchWindowProvider.targetSlotReference.nodeGuid.Equals(node.guid))
  644. {
  645. m_SearchWindowProvider.nodeNeedsRepositioning = false;
  646. foreach (var element in nodeView.inputContainer.Children().Union(nodeView.outputContainer.Children()))
  647. {
  648. var port = (ShaderPort)element;
  649. if (port.slot.slotReference.Equals(m_SearchWindowProvider.targetSlotReference))
  650. {
  651. port.RegisterCallback<GeometryChangedEvent>(RepositionNode);
  652. return;
  653. }
  654. }
  655. }
  656. // This should also work for sticky notes
  657. m_GraphElementsTemp.Clear();
  658. m_GraphView.graphElements.ToList(m_GraphElementsTemp);
  659. if (materialNode.groupGuid != Guid.Empty)
  660. {
  661. foreach (var element in m_GraphElementsTemp)
  662. {
  663. if (element is ShaderGroup groupView && groupView.userData.guid == materialNode.groupGuid)
  664. {
  665. groupView.AddElement(nodeView);
  666. }
  667. }
  668. }
  669. }
  670. void AddGroup(GroupData groupData)
  671. {
  672. ShaderGroup graphGroup = new ShaderGroup(m_Graph);
  673. graphGroup.userData = groupData;
  674. graphGroup.title = groupData.title;
  675. graphGroup.SetPosition(new Rect(graphGroup.userData.position, Vector2.zero));
  676. m_GraphView.AddElement(graphGroup);
  677. }
  678. void AddStickyNote(StickyNoteData stickyNoteData)
  679. {
  680. var stickyNote = new StickyNote(stickyNoteData.position, m_Graph);
  681. stickyNote.userData = stickyNoteData;
  682. stickyNote.viewDataKey = stickyNoteData.guid.ToString();
  683. stickyNote.title = stickyNoteData.title;
  684. stickyNote.contents = stickyNoteData.content;
  685. stickyNote.textSize = (StickyNote.TextSize)stickyNoteData.textSize;
  686. stickyNote.theme = (StickyNote.Theme)stickyNoteData.theme;
  687. stickyNote.userData.groupGuid = stickyNoteData.groupGuid;
  688. stickyNote.SetPosition(new Rect(stickyNote.userData.position));
  689. m_GraphView.AddElement(stickyNote);
  690. // Add Sticky Note to group
  691. m_GraphElementsTemp.Clear();
  692. m_GraphView.graphElements.ToList(m_GraphElementsTemp);
  693. if (stickyNoteData.groupGuid != Guid.Empty)
  694. {
  695. foreach (var element in m_GraphElementsTemp)
  696. {
  697. if (element is ShaderGroup groupView && groupView.userData.guid == stickyNoteData.groupGuid)
  698. {
  699. groupView.AddElement(stickyNote);
  700. }
  701. }
  702. }
  703. }
  704. static void RepositionNode(GeometryChangedEvent evt)
  705. {
  706. var port = evt.target as ShaderPort;
  707. if (port == null)
  708. return;
  709. port.UnregisterCallback<GeometryChangedEvent>(RepositionNode);
  710. var nodeView = port.node as IShaderNodeView;
  711. if (nodeView == null)
  712. return;
  713. var offset = nodeView.gvNode.mainContainer.WorldToLocal(port.GetGlobalCenter() + new Vector3(3f, 3f, 0f));
  714. var position = nodeView.gvNode.GetPosition();
  715. position.position -= offset;
  716. nodeView.gvNode.SetPosition(position);
  717. var drawState = nodeView.node.drawState;
  718. drawState.position = position;
  719. nodeView.node.drawState = drawState;
  720. nodeView.gvNode.MarkDirtyRepaint();
  721. port.MarkDirtyRepaint();
  722. }
  723. Edge AddEdge(IEdge edge)
  724. {
  725. var sourceNode = m_Graph.GetNodeFromGuid(edge.outputSlot.nodeGuid);
  726. if (sourceNode == null)
  727. {
  728. Debug.LogWarning("Source node is null");
  729. return null;
  730. }
  731. var sourceSlot = sourceNode.FindOutputSlot<MaterialSlot>(edge.outputSlot.slotId);
  732. var targetNode = m_Graph.GetNodeFromGuid(edge.inputSlot.nodeGuid);
  733. if (targetNode == null)
  734. {
  735. Debug.LogWarning("Target node is null");
  736. return null;
  737. }
  738. var targetSlot = targetNode.FindInputSlot<MaterialSlot>(edge.inputSlot.slotId);
  739. var sourceNodeView = m_GraphView.nodes.ToList().OfType<IShaderNodeView>().FirstOrDefault(x => x.node == sourceNode);
  740. if (sourceNodeView != null)
  741. {
  742. var sourceAnchor = sourceNodeView.gvNode.outputContainer.Children().OfType<ShaderPort>().First(x => x.slot.Equals(sourceSlot));
  743. var targetNodeView = m_GraphView.nodes.ToList().OfType<IShaderNodeView>().First(x => x.node == targetNode);
  744. var targetAnchor = targetNodeView.gvNode.inputContainer.Children().OfType<ShaderPort>().First(x => x.slot.Equals(targetSlot));
  745. var edgeView = new Edge
  746. {
  747. userData = edge,
  748. output = sourceAnchor,
  749. input = targetAnchor
  750. };
  751. edgeView.output.Connect(edgeView);
  752. edgeView.input.Connect(edgeView);
  753. m_GraphView.AddElement(edgeView);
  754. sourceNodeView.gvNode.RefreshPorts();
  755. targetNodeView.gvNode.RefreshPorts();
  756. sourceNodeView.UpdatePortInputTypes();
  757. targetNodeView.UpdatePortInputTypes();
  758. return edgeView;
  759. }
  760. return null;
  761. }
  762. Stack<Node> m_NodeStack = new Stack<Node>();
  763. void UpdateEdgeColors(HashSet<IShaderNodeView> nodeViews)
  764. {
  765. var nodeStack = m_NodeStack;
  766. nodeStack.Clear();
  767. foreach (var nodeView in nodeViews)
  768. nodeStack.Push((Node)nodeView);
  769. while (nodeStack.Any())
  770. {
  771. var nodeView = nodeStack.Pop();
  772. if (nodeView is MaterialNodeView materialNodeView)
  773. {
  774. materialNodeView.UpdatePortInputTypes();
  775. }
  776. foreach (var anchorView in nodeView.outputContainer.Children().OfType<Port>())
  777. {
  778. foreach (var edgeView in anchorView.connections)
  779. {
  780. var targetSlot = edgeView.input.GetSlot();
  781. if (targetSlot.valueType == SlotValueType.DynamicVector || targetSlot.valueType == SlotValueType.DynamicMatrix || targetSlot.valueType == SlotValueType.Dynamic)
  782. {
  783. var connectedNodeView = edgeView.input.node;
  784. if (connectedNodeView != null && !nodeViews.Contains((IShaderNodeView)connectedNodeView))
  785. {
  786. nodeStack.Push(connectedNodeView);
  787. nodeViews.Add((IShaderNodeView)connectedNodeView);
  788. }
  789. }
  790. }
  791. }
  792. foreach (var anchorView in nodeView.inputContainer.Children().OfType<Port>())
  793. {
  794. var targetSlot = anchorView.GetSlot();
  795. if (targetSlot.valueType != SlotValueType.DynamicVector)
  796. continue;
  797. foreach (var edgeView in anchorView.connections)
  798. {
  799. var connectedNodeView = edgeView.output.node;
  800. if (connectedNodeView != null && !nodeViews.Contains((IShaderNodeView)connectedNodeView))
  801. {
  802. nodeStack.Push(connectedNodeView);
  803. nodeViews.Add((IShaderNodeView)connectedNodeView);
  804. }
  805. }
  806. }
  807. }
  808. }
  809. void OnPrimaryMasterChanged()
  810. {
  811. m_MasterPreviewView?.RemoveFromHierarchy();
  812. CreateMasterPreview();
  813. ApplyMasterPreviewLayout();
  814. UpdateSubWindowsVisibility();
  815. }
  816. void HandleEditorViewChanged(GeometryChangedEvent evt)
  817. {
  818. m_BlackboardProvider.blackboard.SetPosition(m_FloatingWindowsLayout.blackboardLayout.GetLayout(m_GraphView.layout));
  819. }
  820. void StoreBlackboardLayoutOnGeometryChanged(GeometryChangedEvent evt)
  821. {
  822. UpdateSerializedWindowLayout();
  823. }
  824. void ApplySerializewindowLayouts(GeometryChangedEvent evt)
  825. {
  826. UnregisterCallback<GeometryChangedEvent>(ApplySerializewindowLayouts);
  827. ApplyMasterPreviewLayout();
  828. // Restore blackboard layout, and make sure that it remains in the view.
  829. Rect blackboardRect = m_FloatingWindowsLayout.blackboardLayout.GetLayout(this.layout);
  830. // Make sure the dimensions are sufficiently large.
  831. blackboardRect.width = Mathf.Clamp(blackboardRect.width, 160f, m_GraphView.contentContainer.layout.width);
  832. blackboardRect.height = Mathf.Clamp(blackboardRect.height, 160f, m_GraphView.contentContainer.layout.height);
  833. // Make sure that the positionining is on screen.
  834. blackboardRect.x = Mathf.Clamp(blackboardRect.x, 0f, Mathf.Max(1f, m_GraphView.contentContainer.layout.width - blackboardRect.width - blackboardRect.width));
  835. blackboardRect.y = Mathf.Clamp(blackboardRect.y, 0f, Mathf.Max(1f, m_GraphView.contentContainer.layout.height - blackboardRect.height - blackboardRect.height));
  836. // Set the processed blackboard layout.
  837. m_BlackboardProvider.blackboard.SetPosition(blackboardRect);
  838. previewManager.ResizeMasterPreview(m_FloatingWindowsLayout.masterPreviewSize);
  839. // After the layout is restored from the previous session, start tracking layout changes in the blackboard.
  840. m_BlackboardProvider.blackboard.RegisterCallback<GeometryChangedEvent>(StoreBlackboardLayoutOnGeometryChanged);
  841. // After the layout is restored, track changes in layout and make the blackboard have the same behavior as the preview w.r.t. docking.
  842. RegisterCallback<GeometryChangedEvent>(HandleEditorViewChanged);
  843. }
  844. void ApplyMasterPreviewLayout()
  845. {
  846. m_FloatingWindowsLayout.previewLayout.ApplyPosition(m_MasterPreviewView);
  847. m_MasterPreviewView.previewTextureView.style.width = m_FloatingWindowsLayout.masterPreviewSize.x;
  848. m_MasterPreviewView.previewTextureView.style.height = m_FloatingWindowsLayout.masterPreviewSize.y;
  849. }
  850. void UpdateSerializedWindowLayout()
  851. {
  852. m_FloatingWindowsLayout.previewLayout.CalculateDockingCornerAndOffset(m_MasterPreviewView.layout, m_GraphView.layout);
  853. m_FloatingWindowsLayout.previewLayout.ClampToParentWindow();
  854. m_FloatingWindowsLayout.blackboardLayout.CalculateDockingCornerAndOffset(m_BlackboardProvider.blackboard.layout, m_GraphView.layout);
  855. m_FloatingWindowsLayout.blackboardLayout.ClampToParentWindow();
  856. if (m_MasterPreviewView.expanded)
  857. {
  858. m_FloatingWindowsLayout.masterPreviewSize = m_MasterPreviewView.previewTextureView.layout.size;
  859. }
  860. string serializedWindowLayout = JsonUtility.ToJson(m_FloatingWindowsLayout);
  861. EditorUserSettings.SetConfigValue(k_FloatingWindowsLayoutKey, serializedWindowLayout);
  862. }
  863. public void Dispose()
  864. {
  865. if (m_GraphView != null)
  866. {
  867. saveRequested = null;
  868. convertToSubgraphRequested = null;
  869. showInProjectRequested = null;
  870. isCheckedOut = null;
  871. checkOut = null;
  872. foreach (var node in m_GraphView.Children().OfType<IShaderNodeView>())
  873. node.Dispose();
  874. m_GraphView.nodeCreationRequest = null;
  875. m_GraphView = null;
  876. }
  877. if (previewManager != null)
  878. {
  879. previewManager.Dispose();
  880. previewManager = null;
  881. }
  882. if (m_SearchWindowProvider != null)
  883. {
  884. Object.DestroyImmediate(m_SearchWindowProvider);
  885. m_SearchWindowProvider = null;
  886. }
  887. }
  888. }
  889. }