GraphData.cs 47 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Linq;
  4. using System.Text.RegularExpressions;
  5. using UnityEngine;
  6. using UnityEditor.Graphing;
  7. using UnityEditor.Graphing.Util;
  8. using UnityEditor.Rendering;
  9. using UnityEditor.ShaderGraph.Internal;
  10. using Edge = UnityEditor.Graphing.Edge;
  11. namespace UnityEditor.ShaderGraph
  12. {
  13. [Serializable]
  14. [FormerName("UnityEditor.ShaderGraph.MaterialGraph")]
  15. [FormerName("UnityEditor.ShaderGraph.SubGraph")]
  16. [FormerName("UnityEditor.ShaderGraph.AbstractMaterialGraph")]
  17. sealed class GraphData : ISerializationCallbackReceiver
  18. {
  19. public GraphObject owner { get; set; }
  20. #region Input data
  21. [NonSerialized]
  22. List<AbstractShaderProperty> m_Properties = new List<AbstractShaderProperty>();
  23. public IEnumerable<AbstractShaderProperty> properties
  24. {
  25. get { return m_Properties; }
  26. }
  27. [SerializeField]
  28. List<SerializationHelper.JSONSerializedElement> m_SerializedProperties = new List<SerializationHelper.JSONSerializedElement>();
  29. [NonSerialized]
  30. List<ShaderKeyword> m_Keywords = new List<ShaderKeyword>();
  31. public IEnumerable<ShaderKeyword> keywords
  32. {
  33. get { return m_Keywords; }
  34. }
  35. [SerializeField]
  36. List<SerializationHelper.JSONSerializedElement> m_SerializedKeywords = new List<SerializationHelper.JSONSerializedElement>();
  37. [NonSerialized]
  38. List<ShaderInput> m_AddedInputs = new List<ShaderInput>();
  39. public IEnumerable<ShaderInput> addedInputs
  40. {
  41. get { return m_AddedInputs; }
  42. }
  43. [NonSerialized]
  44. List<Guid> m_RemovedInputs = new List<Guid>();
  45. public IEnumerable<Guid> removedInputs
  46. {
  47. get { return m_RemovedInputs; }
  48. }
  49. [NonSerialized]
  50. List<ShaderInput> m_MovedInputs = new List<ShaderInput>();
  51. public IEnumerable<ShaderInput> movedInputs
  52. {
  53. get { return m_MovedInputs; }
  54. }
  55. public string assetGuid { get; set; }
  56. #endregion
  57. #region Node data
  58. [NonSerialized]
  59. Stack<Identifier> m_FreeNodeTempIds = new Stack<Identifier>();
  60. [NonSerialized]
  61. List<AbstractMaterialNode> m_Nodes = new List<AbstractMaterialNode>();
  62. [NonSerialized]
  63. Dictionary<Guid, AbstractMaterialNode> m_NodeDictionary = new Dictionary<Guid, AbstractMaterialNode>();
  64. public IEnumerable<T> GetNodes<T>()
  65. {
  66. return m_Nodes.Where(x => x != null).OfType<T>();
  67. }
  68. [SerializeField]
  69. List<SerializationHelper.JSONSerializedElement> m_SerializableNodes = new List<SerializationHelper.JSONSerializedElement>();
  70. [NonSerialized]
  71. List<AbstractMaterialNode> m_AddedNodes = new List<AbstractMaterialNode>();
  72. public IEnumerable<AbstractMaterialNode> addedNodes
  73. {
  74. get { return m_AddedNodes; }
  75. }
  76. [NonSerialized]
  77. List<AbstractMaterialNode> m_RemovedNodes = new List<AbstractMaterialNode>();
  78. public IEnumerable<AbstractMaterialNode> removedNodes
  79. {
  80. get { return m_RemovedNodes; }
  81. }
  82. [NonSerialized]
  83. List<AbstractMaterialNode> m_PastedNodes = new List<AbstractMaterialNode>();
  84. public IEnumerable<AbstractMaterialNode> pastedNodes
  85. {
  86. get { return m_PastedNodes; }
  87. }
  88. #endregion
  89. #region Group Data
  90. [SerializeField]
  91. List<GroupData> m_Groups = new List<GroupData>();
  92. public IEnumerable<GroupData> groups
  93. {
  94. get { return m_Groups; }
  95. }
  96. [NonSerialized]
  97. List<GroupData> m_AddedGroups = new List<GroupData>();
  98. public IEnumerable<GroupData> addedGroups
  99. {
  100. get { return m_AddedGroups; }
  101. }
  102. [NonSerialized]
  103. List<GroupData> m_RemovedGroups = new List<GroupData>();
  104. public IEnumerable<GroupData> removedGroups
  105. {
  106. get { return m_RemovedGroups; }
  107. }
  108. [NonSerialized]
  109. List<GroupData> m_PastedGroups = new List<GroupData>();
  110. public IEnumerable<GroupData> pastedGroups
  111. {
  112. get { return m_PastedGroups; }
  113. }
  114. [NonSerialized]
  115. List<ParentGroupChange> m_ParentGroupChanges = new List<ParentGroupChange>();
  116. public IEnumerable<ParentGroupChange> parentGroupChanges
  117. {
  118. get { return m_ParentGroupChanges; }
  119. }
  120. [NonSerialized]
  121. GroupData m_MostRecentlyCreatedGroup;
  122. public GroupData mostRecentlyCreatedGroup => m_MostRecentlyCreatedGroup;
  123. [NonSerialized]
  124. Dictionary<Guid, List<IGroupItem>> m_GroupItems = new Dictionary<Guid, List<IGroupItem>>();
  125. public IEnumerable<IGroupItem> GetItemsInGroup(GroupData groupData)
  126. {
  127. if (m_GroupItems.TryGetValue(groupData.guid, out var nodes))
  128. {
  129. return nodes;
  130. }
  131. return Enumerable.Empty<IGroupItem>();
  132. }
  133. #endregion
  134. #region StickyNote Data
  135. [SerializeField]
  136. List<StickyNoteData> m_StickyNotes = new List<StickyNoteData>();
  137. public IEnumerable<StickyNoteData> stickyNotes => m_StickyNotes;
  138. [NonSerialized]
  139. List<StickyNoteData> m_AddedStickyNotes = new List<StickyNoteData>();
  140. public List<StickyNoteData> addedStickyNotes => m_AddedStickyNotes;
  141. [NonSerialized]
  142. List<StickyNoteData> m_RemovedNotes = new List<StickyNoteData>();
  143. public IEnumerable<StickyNoteData> removedNotes => m_RemovedNotes;
  144. [NonSerialized]
  145. List<StickyNoteData> m_PastedStickyNotes = new List<StickyNoteData>();
  146. public IEnumerable<StickyNoteData> pastedStickyNotes => m_PastedStickyNotes;
  147. #endregion
  148. #region Edge data
  149. [NonSerialized]
  150. List<IEdge> m_Edges = new List<IEdge>();
  151. public IEnumerable<IEdge> edges
  152. {
  153. get { return m_Edges; }
  154. }
  155. [SerializeField]
  156. List<SerializationHelper.JSONSerializedElement> m_SerializableEdges = new List<SerializationHelper.JSONSerializedElement>();
  157. [NonSerialized]
  158. Dictionary<Guid, List<IEdge>> m_NodeEdges = new Dictionary<Guid, List<IEdge>>();
  159. [NonSerialized]
  160. List<IEdge> m_AddedEdges = new List<IEdge>();
  161. public IEnumerable<IEdge> addedEdges
  162. {
  163. get { return m_AddedEdges; }
  164. }
  165. [NonSerialized]
  166. List<IEdge> m_RemovedEdges = new List<IEdge>();
  167. public IEnumerable<IEdge> removedEdges
  168. {
  169. get { return m_RemovedEdges; }
  170. }
  171. #endregion
  172. [SerializeField]
  173. InspectorPreviewData m_PreviewData = new InspectorPreviewData();
  174. public InspectorPreviewData previewData
  175. {
  176. get { return m_PreviewData; }
  177. set { m_PreviewData = value; }
  178. }
  179. [SerializeField]
  180. string m_Path;
  181. public string path
  182. {
  183. get { return m_Path; }
  184. set
  185. {
  186. if (m_Path == value)
  187. return;
  188. m_Path = value;
  189. if(owner != null)
  190. owner.RegisterCompleteObjectUndo("Change Path");
  191. }
  192. }
  193. public MessageManager messageManager { get; set; }
  194. public bool isSubGraph { get; set; }
  195. [SerializeField]
  196. private ConcretePrecision m_ConcretePrecision = ConcretePrecision.Float;
  197. public ConcretePrecision concretePrecision
  198. {
  199. get => m_ConcretePrecision;
  200. set => m_ConcretePrecision = value;
  201. }
  202. [NonSerialized]
  203. Guid m_ActiveOutputNodeGuid;
  204. public Guid activeOutputNodeGuid
  205. {
  206. get { return m_ActiveOutputNodeGuid; }
  207. set
  208. {
  209. if (value != m_ActiveOutputNodeGuid)
  210. {
  211. m_ActiveOutputNodeGuid = value;
  212. m_OutputNode = null;
  213. didActiveOutputNodeChange = true;
  214. }
  215. }
  216. }
  217. [SerializeField]
  218. string m_ActiveOutputNodeGuidSerialized;
  219. [NonSerialized]
  220. private AbstractMaterialNode m_OutputNode;
  221. public AbstractMaterialNode outputNode
  222. {
  223. get
  224. {
  225. // find existing node
  226. if (m_OutputNode == null)
  227. {
  228. if (isSubGraph)
  229. {
  230. m_OutputNode = GetNodes<SubGraphOutputNode>().FirstOrDefault();
  231. }
  232. else
  233. {
  234. m_OutputNode = GetNodeFromGuid(m_ActiveOutputNodeGuid);
  235. }
  236. }
  237. return m_OutputNode;
  238. }
  239. }
  240. public bool didActiveOutputNodeChange { get; set; }
  241. internal delegate void SaveGraphDelegate(Shader shader, object context);
  242. internal static SaveGraphDelegate onSaveGraph;
  243. public GraphData()
  244. {
  245. m_GroupItems[Guid.Empty] = new List<IGroupItem>();
  246. }
  247. public void ClearChanges()
  248. {
  249. m_AddedNodes.Clear();
  250. m_RemovedNodes.Clear();
  251. m_PastedNodes.Clear();
  252. m_ParentGroupChanges.Clear();
  253. m_AddedGroups.Clear();
  254. m_RemovedGroups.Clear();
  255. m_PastedGroups.Clear();
  256. m_AddedEdges.Clear();
  257. m_RemovedEdges.Clear();
  258. m_AddedInputs.Clear();
  259. m_RemovedInputs.Clear();
  260. m_MovedInputs.Clear();
  261. m_AddedStickyNotes.Clear();
  262. m_RemovedNotes.Clear();
  263. m_PastedStickyNotes.Clear();
  264. m_MostRecentlyCreatedGroup = null;
  265. didActiveOutputNodeChange = false;
  266. }
  267. public void AddNode(AbstractMaterialNode node)
  268. {
  269. if (node is AbstractMaterialNode materialNode)
  270. {
  271. if (isSubGraph && !materialNode.allowedInSubGraph)
  272. {
  273. Debug.LogWarningFormat("Attempting to add {0} to Sub Graph. This is not allowed.", materialNode.GetType());
  274. return;
  275. }
  276. AddNodeNoValidate(materialNode);
  277. // If adding a Sub Graph node whose asset contains Keywords
  278. // Need to restest Keywords against the variant limit
  279. if(node is SubGraphNode subGraphNode &&
  280. subGraphNode.asset != null &&
  281. subGraphNode.asset.keywords.Count > 0)
  282. {
  283. OnKeywordChangedNoValidate();
  284. }
  285. ValidateGraph();
  286. }
  287. else
  288. {
  289. Debug.LogWarningFormat("Trying to add node {0} to Material graph, but it is not a {1}", node, typeof(AbstractMaterialNode));
  290. }
  291. }
  292. public void CreateGroup(GroupData groupData)
  293. {
  294. if (AddGroup(groupData))
  295. {
  296. m_MostRecentlyCreatedGroup = groupData;
  297. }
  298. }
  299. bool AddGroup(GroupData groupData)
  300. {
  301. if (m_Groups.Contains(groupData))
  302. return false;
  303. m_Groups.Add(groupData);
  304. m_AddedGroups.Add(groupData);
  305. m_GroupItems.Add(groupData.guid, new List<IGroupItem>());
  306. return true;
  307. }
  308. public void RemoveGroup(GroupData groupData)
  309. {
  310. RemoveGroupNoValidate(groupData);
  311. ValidateGraph();
  312. }
  313. void RemoveGroupNoValidate(GroupData group)
  314. {
  315. if (!m_Groups.Contains(group))
  316. throw new InvalidOperationException("Cannot remove a group that doesn't exist.");
  317. m_Groups.Remove(group);
  318. m_RemovedGroups.Add(group);
  319. if (m_GroupItems.TryGetValue(group.guid, out var items))
  320. {
  321. foreach (IGroupItem groupItem in items.ToList())
  322. {
  323. SetGroup(groupItem, null);
  324. }
  325. m_GroupItems.Remove(group.guid);
  326. }
  327. }
  328. public void AddStickyNote(StickyNoteData stickyNote)
  329. {
  330. if (m_StickyNotes.Contains(stickyNote))
  331. {
  332. throw new InvalidOperationException("Sticky note has already been added to the graph.");
  333. }
  334. if (!m_GroupItems.ContainsKey(stickyNote.groupGuid))
  335. {
  336. throw new InvalidOperationException("Trying to add sticky note with group that doesn't exist.");
  337. }
  338. m_StickyNotes.Add(stickyNote);
  339. m_AddedStickyNotes.Add(stickyNote);
  340. m_GroupItems[stickyNote.groupGuid].Add(stickyNote);
  341. }
  342. void RemoveNoteNoValidate(StickyNoteData stickyNote)
  343. {
  344. if (!m_StickyNotes.Contains(stickyNote))
  345. {
  346. throw new InvalidOperationException("Cannot remove a note that doesn't exist.");
  347. }
  348. m_StickyNotes.Remove(stickyNote);
  349. m_RemovedNotes.Add(stickyNote);
  350. if (m_GroupItems.TryGetValue(stickyNote.groupGuid, out var groupItems))
  351. {
  352. groupItems.Remove(stickyNote);
  353. }
  354. }
  355. public void RemoveStickyNote(StickyNoteData stickyNote)
  356. {
  357. RemoveNoteNoValidate(stickyNote);
  358. ValidateGraph();
  359. }
  360. public void SetGroup(IGroupItem node, GroupData group)
  361. {
  362. var groupChange = new ParentGroupChange()
  363. {
  364. groupItem = node,
  365. oldGroupGuid = node.groupGuid,
  366. // Checking if the groupdata is null. If it is, then it means node has been removed out of a group.
  367. // If the group data is null, then maybe the old group id should be removed
  368. newGroupGuid = group?.guid ?? Guid.Empty
  369. };
  370. node.groupGuid = groupChange.newGroupGuid;
  371. var oldGroupNodes = m_GroupItems[groupChange.oldGroupGuid];
  372. oldGroupNodes.Remove(node);
  373. m_GroupItems[groupChange.newGroupGuid].Add(node);
  374. m_ParentGroupChanges.Add(groupChange);
  375. }
  376. void AddNodeNoValidate(AbstractMaterialNode node)
  377. {
  378. if (node.groupGuid != Guid.Empty && !m_GroupItems.ContainsKey(node.groupGuid))
  379. {
  380. throw new InvalidOperationException("Cannot add a node whose group doesn't exist.");
  381. }
  382. node.owner = this;
  383. if (m_FreeNodeTempIds.Any())
  384. {
  385. var id = m_FreeNodeTempIds.Pop();
  386. id.IncrementVersion();
  387. node.tempId = id;
  388. m_Nodes[id.index] = node;
  389. }
  390. else
  391. {
  392. var id = new Identifier(m_Nodes.Count);
  393. node.tempId = id;
  394. m_Nodes.Add(node);
  395. }
  396. m_NodeDictionary.Add(node.guid, node);
  397. m_AddedNodes.Add(node);
  398. m_GroupItems[node.groupGuid].Add(node);
  399. }
  400. public void RemoveNode(AbstractMaterialNode node)
  401. {
  402. if (!node.canDeleteNode)
  403. {
  404. throw new InvalidOperationException($"Node {node.name} ({node.guid}) cannot be deleted.");
  405. }
  406. RemoveNodeNoValidate(node);
  407. ValidateGraph();
  408. }
  409. void RemoveNodeNoValidate(AbstractMaterialNode node)
  410. {
  411. if (!m_NodeDictionary.ContainsKey(node.guid))
  412. {
  413. throw new InvalidOperationException("Cannot remove a node that doesn't exist.");
  414. }
  415. m_Nodes[node.tempId.index] = null;
  416. m_FreeNodeTempIds.Push(node.tempId);
  417. m_NodeDictionary.Remove(node.guid);
  418. messageManager?.RemoveNode(node.tempId);
  419. m_RemovedNodes.Add(node);
  420. if (m_GroupItems.TryGetValue(node.groupGuid, out var groupItems))
  421. {
  422. groupItems.Remove(node);
  423. }
  424. }
  425. void AddEdgeToNodeEdges(IEdge edge)
  426. {
  427. List<IEdge> inputEdges;
  428. if (!m_NodeEdges.TryGetValue(edge.inputSlot.nodeGuid, out inputEdges))
  429. m_NodeEdges[edge.inputSlot.nodeGuid] = inputEdges = new List<IEdge>();
  430. inputEdges.Add(edge);
  431. List<IEdge> outputEdges;
  432. if (!m_NodeEdges.TryGetValue(edge.outputSlot.nodeGuid, out outputEdges))
  433. m_NodeEdges[edge.outputSlot.nodeGuid] = outputEdges = new List<IEdge>();
  434. outputEdges.Add(edge);
  435. }
  436. IEdge ConnectNoValidate(SlotReference fromSlotRef, SlotReference toSlotRef)
  437. {
  438. var fromNode = GetNodeFromGuid(fromSlotRef.nodeGuid);
  439. var toNode = GetNodeFromGuid(toSlotRef.nodeGuid);
  440. if (fromNode == null || toNode == null)
  441. return null;
  442. // if fromNode is already connected to toNode
  443. // do now allow a connection as toNode will then
  444. // have an edge to fromNode creating a cycle.
  445. // if this is parsed it will lead to an infinite loop.
  446. var dependentNodes = new List<AbstractMaterialNode>();
  447. NodeUtils.CollectNodesNodeFeedsInto(dependentNodes, toNode);
  448. if (dependentNodes.Contains(fromNode))
  449. return null;
  450. var fromSlot = fromNode.FindSlot<ISlot>(fromSlotRef.slotId);
  451. var toSlot = toNode.FindSlot<ISlot>(toSlotRef.slotId);
  452. if (fromSlot == null || toSlot == null)
  453. return null;
  454. if (fromSlot.isOutputSlot == toSlot.isOutputSlot)
  455. return null;
  456. var outputSlot = fromSlot.isOutputSlot ? fromSlotRef : toSlotRef;
  457. var inputSlot = fromSlot.isInputSlot ? fromSlotRef : toSlotRef;
  458. s_TempEdges.Clear();
  459. GetEdges(inputSlot, s_TempEdges);
  460. // remove any inputs that exits before adding
  461. foreach (var edge in s_TempEdges)
  462. {
  463. RemoveEdgeNoValidate(edge);
  464. }
  465. var newEdge = new Edge(outputSlot, inputSlot);
  466. m_Edges.Add(newEdge);
  467. m_AddedEdges.Add(newEdge);
  468. AddEdgeToNodeEdges(newEdge);
  469. //Debug.LogFormat("Connected edge: {0} -> {1} ({2} -> {3})\n{4}", newEdge.outputSlot.nodeGuid, newEdge.inputSlot.nodeGuid, fromNode.name, toNode.name, Environment.StackTrace);
  470. return newEdge;
  471. }
  472. public IEdge Connect(SlotReference fromSlotRef, SlotReference toSlotRef)
  473. {
  474. var newEdge = ConnectNoValidate(fromSlotRef, toSlotRef);
  475. ValidateGraph();
  476. return newEdge;
  477. }
  478. public void RemoveEdge(IEdge e)
  479. {
  480. RemoveEdgeNoValidate(e);
  481. ValidateGraph();
  482. }
  483. public void RemoveElements(AbstractMaterialNode[] nodes, IEdge[] edges, GroupData[] groups, StickyNoteData[] notes)
  484. {
  485. foreach (var node in nodes)
  486. {
  487. if (!node.canDeleteNode)
  488. {
  489. throw new InvalidOperationException($"Node {node.name} ({node.guid}) cannot be deleted.");
  490. }
  491. }
  492. foreach (var edge in edges.ToArray())
  493. {
  494. RemoveEdgeNoValidate(edge);
  495. }
  496. foreach (var serializableNode in nodes)
  497. {
  498. RemoveNodeNoValidate(serializableNode);
  499. }
  500. foreach (var noteData in notes)
  501. {
  502. RemoveNoteNoValidate(noteData);
  503. }
  504. foreach (var groupData in groups)
  505. {
  506. RemoveGroupNoValidate(groupData);
  507. }
  508. ValidateGraph();
  509. }
  510. void RemoveEdgeNoValidate(IEdge e)
  511. {
  512. e = m_Edges.FirstOrDefault(x => x.Equals(e));
  513. if (e == null)
  514. throw new ArgumentException("Trying to remove an edge that does not exist.", "e");
  515. m_Edges.Remove(e);
  516. List<IEdge> inputNodeEdges;
  517. if (m_NodeEdges.TryGetValue(e.inputSlot.nodeGuid, out inputNodeEdges))
  518. inputNodeEdges.Remove(e);
  519. List<IEdge> outputNodeEdges;
  520. if (m_NodeEdges.TryGetValue(e.outputSlot.nodeGuid, out outputNodeEdges))
  521. outputNodeEdges.Remove(e);
  522. m_RemovedEdges.Add(e);
  523. }
  524. public AbstractMaterialNode GetNodeFromGuid(Guid guid)
  525. {
  526. AbstractMaterialNode node;
  527. m_NodeDictionary.TryGetValue(guid, out node);
  528. return node;
  529. }
  530. public AbstractMaterialNode GetNodeFromTempId(Identifier tempId)
  531. {
  532. if (tempId.index > m_Nodes.Count)
  533. throw new ArgumentException("Trying to retrieve a node using an identifier that does not exist.");
  534. var node = m_Nodes[tempId.index];
  535. if (node == null)
  536. throw new Exception("Trying to retrieve a node using an identifier that does not exist.");
  537. if (node.tempId.version != tempId.version)
  538. throw new Exception("Trying to retrieve a node that was removed from the graph.");
  539. return node;
  540. }
  541. public bool ContainsNodeGuid(Guid guid)
  542. {
  543. return m_NodeDictionary.ContainsKey(guid);
  544. }
  545. public T GetNodeFromGuid<T>(Guid guid) where T : AbstractMaterialNode
  546. {
  547. var node = GetNodeFromGuid(guid);
  548. if (node is T)
  549. return (T)node;
  550. return default(T);
  551. }
  552. public void GetEdges(SlotReference s, List<IEdge> foundEdges)
  553. {
  554. var node = GetNodeFromGuid(s.nodeGuid);
  555. if (node == null)
  556. {
  557. return;
  558. }
  559. ISlot slot = node.FindSlot<ISlot>(s.slotId);
  560. List<IEdge> candidateEdges;
  561. if (!m_NodeEdges.TryGetValue(s.nodeGuid, out candidateEdges))
  562. return;
  563. foreach (var edge in candidateEdges)
  564. {
  565. var cs = slot.isInputSlot ? edge.inputSlot : edge.outputSlot;
  566. if (cs.nodeGuid == s.nodeGuid && cs.slotId == s.slotId)
  567. foundEdges.Add(edge);
  568. }
  569. }
  570. public IEnumerable<IEdge> GetEdges(SlotReference s)
  571. {
  572. var edges = new List<IEdge>();
  573. GetEdges(s, edges);
  574. return edges;
  575. }
  576. public void CollectShaderProperties(PropertyCollector collector, GenerationMode generationMode)
  577. {
  578. foreach (var prop in properties)
  579. {
  580. if(prop is GradientShaderProperty gradientProp && generationMode == GenerationMode.Preview)
  581. {
  582. GradientUtil.GetGradientPropertiesForPreview(collector, gradientProp.referenceName, gradientProp.value);
  583. continue;
  584. }
  585. collector.AddShaderProperty(prop);
  586. }
  587. }
  588. public void CollectShaderKeywords(KeywordCollector collector, GenerationMode generationMode)
  589. {
  590. foreach (var keyword in keywords)
  591. {
  592. collector.AddShaderKeyword(keyword);
  593. }
  594. // Alwways calculate permutations when collecting
  595. collector.CalculateKeywordPermutations();
  596. }
  597. public void AddGraphInput(ShaderInput input)
  598. {
  599. if (input == null)
  600. return;
  601. switch(input)
  602. {
  603. case AbstractShaderProperty property:
  604. if (m_Properties.Contains(property))
  605. return;
  606. m_Properties.Add(property);
  607. break;
  608. case ShaderKeyword keyword:
  609. if (m_Keywords.Contains(keyword))
  610. return;
  611. m_Keywords.Add(keyword);
  612. break;
  613. default:
  614. throw new ArgumentOutOfRangeException();
  615. }
  616. m_AddedInputs.Add(input);
  617. }
  618. public void SanitizeGraphInputName(ShaderInput input)
  619. {
  620. input.displayName = input.displayName.Trim();
  621. switch(input)
  622. {
  623. case AbstractShaderProperty property:
  624. input.displayName = GraphUtil.SanitizeName(properties.Where(p => p.guid != input.guid).Select(p => p.displayName), "{0} ({1})", input.displayName);
  625. break;
  626. case ShaderKeyword keyword:
  627. input.displayName = GraphUtil.SanitizeName(keywords.Where(p => p.guid != input.guid).Select(p => p.displayName), "{0} ({1})", input.displayName);
  628. break;
  629. default:
  630. throw new ArgumentOutOfRangeException();
  631. }
  632. }
  633. public void SanitizeGraphInputReferenceName(ShaderInput input, string newName)
  634. {
  635. if (string.IsNullOrEmpty(newName))
  636. return;
  637. string name = newName.Trim();
  638. if (string.IsNullOrEmpty(name))
  639. return;
  640. name = Regex.Replace(name, @"(?:[^A-Za-z_0-9])|(?:\s)", "_");
  641. switch(input)
  642. {
  643. case AbstractShaderProperty property:
  644. property.overrideReferenceName = GraphUtil.SanitizeName(properties.Where(p => p.guid != property.guid).Select(p => p.referenceName), "{0}_{1}", name);
  645. break;
  646. case ShaderKeyword keyword:
  647. keyword.overrideReferenceName = GraphUtil.SanitizeName(keywords.Where(p => p.guid != input.guid).Select(p => p.referenceName), "{0}_{1}", name).ToUpper();
  648. break;
  649. default:
  650. throw new ArgumentOutOfRangeException();
  651. }
  652. }
  653. public void RemoveGraphInput(ShaderInput input)
  654. {
  655. switch(input)
  656. {
  657. case AbstractShaderProperty property:
  658. var propetyNodes = GetNodes<PropertyNode>().Where(x => x.propertyGuid == input.guid).ToList();
  659. foreach (var propNode in propetyNodes)
  660. ReplacePropertyNodeWithConcreteNodeNoValidate(propNode);
  661. break;
  662. }
  663. RemoveGraphInputNoValidate(input.guid);
  664. ValidateGraph();
  665. }
  666. public void MoveProperty(AbstractShaderProperty property, int newIndex)
  667. {
  668. if (newIndex > m_Properties.Count || newIndex < 0)
  669. throw new ArgumentException("New index is not within properties list.");
  670. var currentIndex = m_Properties.IndexOf(property);
  671. if (currentIndex == -1)
  672. throw new ArgumentException("Property is not in graph.");
  673. if (newIndex == currentIndex)
  674. return;
  675. m_Properties.RemoveAt(currentIndex);
  676. if (newIndex > currentIndex)
  677. newIndex--;
  678. var isLast = newIndex == m_Properties.Count;
  679. if (isLast)
  680. m_Properties.Add(property);
  681. else
  682. m_Properties.Insert(newIndex, property);
  683. if (!m_MovedInputs.Contains(property))
  684. m_MovedInputs.Add(property);
  685. }
  686. public void MoveKeyword(ShaderKeyword keyword, int newIndex)
  687. {
  688. if (newIndex > m_Keywords.Count || newIndex < 0)
  689. throw new ArgumentException("New index is not within keywords list.");
  690. var currentIndex = m_Keywords.IndexOf(keyword);
  691. if (currentIndex == -1)
  692. throw new ArgumentException("Keyword is not in graph.");
  693. if (newIndex == currentIndex)
  694. return;
  695. m_Keywords.RemoveAt(currentIndex);
  696. if (newIndex > currentIndex)
  697. newIndex--;
  698. var isLast = newIndex == m_Keywords.Count;
  699. if (isLast)
  700. m_Keywords.Add(keyword);
  701. else
  702. m_Keywords.Insert(newIndex, keyword);
  703. if (!m_MovedInputs.Contains(keyword))
  704. m_MovedInputs.Add(keyword);
  705. }
  706. public int GetGraphInputIndex(ShaderInput input)
  707. {
  708. switch(input)
  709. {
  710. case AbstractShaderProperty property:
  711. return m_Properties.IndexOf(property);
  712. case ShaderKeyword keyword:
  713. return m_Keywords.IndexOf(keyword);
  714. default:
  715. throw new ArgumentOutOfRangeException();
  716. }
  717. }
  718. void RemoveGraphInputNoValidate(Guid guid)
  719. {
  720. if (m_Properties.RemoveAll(x => x.guid == guid) > 0 ||
  721. m_Keywords.RemoveAll(x => x.guid == guid) > 0)
  722. {
  723. m_RemovedInputs.Add(guid);
  724. m_AddedInputs.RemoveAll(x => x.guid == guid);
  725. m_MovedInputs.RemoveAll(x => x.guid == guid);
  726. }
  727. }
  728. static List<IEdge> s_TempEdges = new List<IEdge>();
  729. public void ReplacePropertyNodeWithConcreteNode(PropertyNode propertyNode)
  730. {
  731. ReplacePropertyNodeWithConcreteNodeNoValidate(propertyNode);
  732. ValidateGraph();
  733. }
  734. void ReplacePropertyNodeWithConcreteNodeNoValidate(PropertyNode propertyNode)
  735. {
  736. var property = properties.FirstOrDefault(x => x.guid == propertyNode.propertyGuid);
  737. if (property == null)
  738. return;
  739. var node = property.ToConcreteNode() as AbstractMaterialNode;
  740. if (node == null)
  741. return;
  742. var slot = propertyNode.FindOutputSlot<MaterialSlot>(PropertyNode.OutputSlotId);
  743. var newSlot = node.GetOutputSlots<MaterialSlot>().FirstOrDefault(s => s.valueType == slot.valueType);
  744. if (newSlot == null)
  745. return;
  746. node.drawState = propertyNode.drawState;
  747. node.groupGuid = propertyNode.groupGuid;
  748. AddNodeNoValidate(node);
  749. foreach (var edge in this.GetEdges(slot.slotReference))
  750. ConnectNoValidate(newSlot.slotReference, edge.inputSlot);
  751. RemoveNodeNoValidate(propertyNode);
  752. }
  753. public void OnKeywordChanged()
  754. {
  755. OnKeywordChangedNoValidate();
  756. ValidateGraph();
  757. }
  758. public void OnKeywordChangedNoValidate()
  759. {
  760. var allNodes = GetNodes<AbstractMaterialNode>();
  761. foreach(AbstractMaterialNode node in allNodes)
  762. {
  763. node.Dirty(ModificationScope.Topological);
  764. node.ValidateNode();
  765. }
  766. }
  767. public void ValidateGraph()
  768. {
  769. var propertyNodes = GetNodes<PropertyNode>().Where(n => !m_Properties.Any(p => p.guid == n.propertyGuid)).ToArray();
  770. foreach (var pNode in propertyNodes)
  771. ReplacePropertyNodeWithConcreteNodeNoValidate(pNode);
  772. messageManager?.ClearAllFromProvider(this);
  773. //First validate edges, remove any
  774. //orphans. This can happen if a user
  775. //manually modifies serialized data
  776. //of if they delete a node in the inspector
  777. //debug view.
  778. foreach (var edge in edges.ToArray())
  779. {
  780. var outputNode = GetNodeFromGuid(edge.outputSlot.nodeGuid);
  781. var inputNode = GetNodeFromGuid(edge.inputSlot.nodeGuid);
  782. MaterialSlot outputSlot = null;
  783. MaterialSlot inputSlot = null;
  784. if (outputNode != null && inputNode != null)
  785. {
  786. outputSlot = outputNode.FindOutputSlot<MaterialSlot>(edge.outputSlot.slotId);
  787. inputSlot = inputNode.FindInputSlot<MaterialSlot>(edge.inputSlot.slotId);
  788. }
  789. if (outputNode == null
  790. || inputNode == null
  791. || outputSlot == null
  792. || inputSlot == null)
  793. {
  794. //orphaned edge
  795. RemoveEdgeNoValidate(edge);
  796. }
  797. }
  798. var temporaryMarks = IndexSetPool.Get();
  799. var permanentMarks = IndexSetPool.Get();
  800. var slots = ListPool<MaterialSlot>.Get();
  801. // Make sure we process a node's children before the node itself.
  802. var stack = StackPool<AbstractMaterialNode>.Get();
  803. foreach (var node in GetNodes<AbstractMaterialNode>())
  804. {
  805. stack.Push(node);
  806. }
  807. while (stack.Count > 0)
  808. {
  809. var node = stack.Pop();
  810. if (permanentMarks.Contains(node.tempId.index))
  811. {
  812. continue;
  813. }
  814. if (temporaryMarks.Contains(node.tempId.index))
  815. {
  816. node.ValidateNode();
  817. permanentMarks.Add(node.tempId.index);
  818. }
  819. else
  820. {
  821. temporaryMarks.Add(node.tempId.index);
  822. stack.Push(node);
  823. node.GetInputSlots(slots);
  824. foreach (var inputSlot in slots)
  825. {
  826. var nodeEdges = GetEdges(inputSlot.slotReference);
  827. foreach (var edge in nodeEdges)
  828. {
  829. var fromSocketRef = edge.outputSlot;
  830. var childNode = GetNodeFromGuid(fromSocketRef.nodeGuid);
  831. if (childNode != null)
  832. {
  833. stack.Push(childNode);
  834. }
  835. }
  836. }
  837. slots.Clear();
  838. }
  839. }
  840. StackPool<AbstractMaterialNode>.Release(stack);
  841. ListPool<MaterialSlot>.Release(slots);
  842. IndexSetPool.Release(temporaryMarks);
  843. IndexSetPool.Release(permanentMarks);
  844. foreach (var edge in m_AddedEdges.ToList())
  845. {
  846. if (!ContainsNodeGuid(edge.outputSlot.nodeGuid) || !ContainsNodeGuid(edge.inputSlot.nodeGuid))
  847. {
  848. Debug.LogWarningFormat("Added edge is invalid: {0} -> {1}\n{2}", edge.outputSlot.nodeGuid, edge.inputSlot.nodeGuid, Environment.StackTrace);
  849. m_AddedEdges.Remove(edge);
  850. }
  851. }
  852. foreach (var groupChange in m_ParentGroupChanges.ToList())
  853. {
  854. if (groupChange.groupItem is AbstractMaterialNode node && !ContainsNodeGuid(node.guid))
  855. {
  856. m_ParentGroupChanges.Remove(groupChange);
  857. }
  858. if (groupChange.groupItem is StickyNoteData stickyNote && !m_StickyNotes.Contains(stickyNote))
  859. {
  860. m_ParentGroupChanges.Remove(groupChange);
  861. }
  862. }
  863. }
  864. public void AddValidationError(Identifier id, string errorMessage,
  865. ShaderCompilerMessageSeverity severity = ShaderCompilerMessageSeverity.Error)
  866. {
  867. messageManager?.AddOrAppendError(this, id, new ShaderMessage(errorMessage, severity));
  868. }
  869. public void ClearErrorsForNode(AbstractMaterialNode node)
  870. {
  871. messageManager?.ClearNodesFromProvider(this, node.ToEnumerable());
  872. }
  873. public void ReplaceWith(GraphData other)
  874. {
  875. if (other == null)
  876. throw new ArgumentException("Can only replace with another AbstractMaterialGraph", "other");
  877. using (var removedInputsPooledObject = ListPool<Guid>.GetDisposable())
  878. {
  879. var removedInputGuids = removedInputsPooledObject.value;
  880. foreach (var property in m_Properties)
  881. removedInputGuids.Add(property.guid);
  882. foreach (var keyword in m_Keywords)
  883. removedInputGuids.Add(keyword.guid);
  884. foreach (var inputGuid in removedInputGuids)
  885. RemoveGraphInputNoValidate(inputGuid);
  886. }
  887. foreach (var otherProperty in other.properties)
  888. {
  889. if (!properties.Any(p => p.guid == otherProperty.guid))
  890. AddGraphInput(otherProperty);
  891. }
  892. foreach (var otherKeyword in other.keywords)
  893. {
  894. if (!keywords.Any(p => p.guid == otherKeyword.guid))
  895. AddGraphInput(otherKeyword);
  896. }
  897. other.ValidateGraph();
  898. ValidateGraph();
  899. // Current tactic is to remove all nodes and edges and then re-add them, such that depending systems
  900. // will re-initialize with new references.
  901. using (var removedGroupsPooledObject = ListPool<GroupData>.GetDisposable())
  902. {
  903. var removedGroupDatas = removedGroupsPooledObject.value;
  904. removedGroupDatas.AddRange(m_Groups);
  905. foreach (var groupData in removedGroupDatas)
  906. {
  907. RemoveGroupNoValidate(groupData);
  908. }
  909. }
  910. using (var removedNotesPooledObject = ListPool<StickyNoteData>.GetDisposable())
  911. {
  912. var removedNoteDatas = removedNotesPooledObject.value;
  913. removedNoteDatas.AddRange(m_StickyNotes);
  914. foreach (var groupData in removedNoteDatas)
  915. {
  916. RemoveNoteNoValidate(groupData);
  917. }
  918. }
  919. using (var pooledList = ListPool<IEdge>.GetDisposable())
  920. {
  921. var removedNodeEdges = pooledList.value;
  922. removedNodeEdges.AddRange(m_Edges);
  923. foreach (var edge in removedNodeEdges)
  924. RemoveEdgeNoValidate(edge);
  925. }
  926. using (var removedNodesPooledObject = ListPool<Guid>.GetDisposable())
  927. {
  928. var removedNodeGuids = removedNodesPooledObject.value;
  929. removedNodeGuids.AddRange(m_Nodes.Where(n => n != null).Select(n => n.guid));
  930. foreach (var nodeGuid in removedNodeGuids)
  931. RemoveNodeNoValidate(m_NodeDictionary[nodeGuid]);
  932. }
  933. ValidateGraph();
  934. foreach (GroupData groupData in other.groups)
  935. AddGroup(groupData);
  936. foreach (var stickyNote in other.stickyNotes)
  937. {
  938. AddStickyNote(stickyNote);
  939. }
  940. foreach (var node in other.GetNodes<AbstractMaterialNode>())
  941. AddNodeNoValidate(node);
  942. foreach (var edge in other.edges)
  943. ConnectNoValidate(edge.outputSlot, edge.inputSlot);
  944. ValidateGraph();
  945. }
  946. internal void PasteGraph(CopyPasteGraph graphToPaste, List<AbstractMaterialNode> remappedNodes, List<IEdge> remappedEdges)
  947. {
  948. var groupGuidMap = new Dictionary<Guid, Guid>();
  949. foreach (var group in graphToPaste.groups)
  950. {
  951. var position = group.position;
  952. position.x += 30;
  953. position.y += 30;
  954. GroupData newGroup = new GroupData(group.title, position);
  955. var oldGuid = group.guid;
  956. var newGuid = newGroup.guid;
  957. groupGuidMap[oldGuid] = newGuid;
  958. AddGroup(newGroup);
  959. m_PastedGroups.Add(newGroup);
  960. }
  961. foreach (var stickyNote in graphToPaste.stickyNotes)
  962. {
  963. var position = stickyNote.position;
  964. position.x += 30;
  965. position.y += 30;
  966. StickyNoteData pastedStickyNote = new StickyNoteData(stickyNote.title, stickyNote.content, position);
  967. if (groupGuidMap.ContainsKey(stickyNote.groupGuid))
  968. {
  969. pastedStickyNote.groupGuid = groupGuidMap[stickyNote.groupGuid];
  970. }
  971. AddStickyNote(pastedStickyNote);
  972. m_PastedStickyNotes.Add(pastedStickyNote);
  973. }
  974. var nodeGuidMap = new Dictionary<Guid, Guid>();
  975. foreach (var node in graphToPaste.GetNodes<AbstractMaterialNode>())
  976. {
  977. AbstractMaterialNode pastedNode = node;
  978. var oldGuid = node.guid;
  979. var newGuid = node.RewriteGuid();
  980. nodeGuidMap[oldGuid] = newGuid;
  981. // Check if the property nodes need to be made into a concrete node.
  982. if (node is PropertyNode propertyNode)
  983. {
  984. // If the property is not in the current graph, do check if the
  985. // property can be made into a concrete node.
  986. if (!m_Properties.Select(x => x.guid).Contains(propertyNode.propertyGuid))
  987. {
  988. // If the property is in the serialized paste graph, make the property node into a property node.
  989. var pastedGraphMetaProperties = graphToPaste.metaProperties.Where(x => x.guid == propertyNode.propertyGuid);
  990. if (pastedGraphMetaProperties.Any())
  991. {
  992. pastedNode = pastedGraphMetaProperties.FirstOrDefault().ToConcreteNode();
  993. pastedNode.drawState = node.drawState;
  994. nodeGuidMap[oldGuid] = pastedNode.guid;
  995. }
  996. }
  997. }
  998. AbstractMaterialNode abstractMaterialNode = (AbstractMaterialNode)node;
  999. // Check if the node is inside a group
  1000. if (groupGuidMap.ContainsKey(abstractMaterialNode.groupGuid))
  1001. {
  1002. var absNode = pastedNode as AbstractMaterialNode;
  1003. absNode.groupGuid = groupGuidMap[abstractMaterialNode.groupGuid];
  1004. pastedNode = absNode;
  1005. }
  1006. var drawState = node.drawState;
  1007. var position = drawState.position;
  1008. position.x += 30;
  1009. position.y += 30;
  1010. drawState.position = position;
  1011. node.drawState = drawState;
  1012. remappedNodes.Add(pastedNode);
  1013. AddNode(pastedNode);
  1014. // add the node to the pasted node list
  1015. m_PastedNodes.Add(pastedNode);
  1016. // Check if the keyword nodes need to have their keywords copied.
  1017. if (node is KeywordNode keywordNode)
  1018. {
  1019. // If the keyword is not in the current graph and is in the serialized paste graph copy it.
  1020. if (!keywords.Select(x => x.guid).Contains(keywordNode.keywordGuid))
  1021. {
  1022. var pastedGraphMetaKeywords = graphToPaste.metaKeywords.Where(x => x.guid == keywordNode.keywordGuid);
  1023. if (pastedGraphMetaKeywords.Any())
  1024. {
  1025. var keyword = pastedGraphMetaKeywords.FirstOrDefault(x => x.guid == keywordNode.keywordGuid);
  1026. SanitizeGraphInputName(keyword);
  1027. SanitizeGraphInputReferenceName(keyword, keyword.overrideReferenceName);
  1028. AddGraphInput(keyword);
  1029. }
  1030. }
  1031. // Always update Keyword nodes to handle any collisions resolved on the Keyword
  1032. keywordNode.UpdateNode();
  1033. }
  1034. }
  1035. // only connect edges within pasted elements, discard
  1036. // external edges.
  1037. foreach (var edge in graphToPaste.edges)
  1038. {
  1039. var outputSlot = edge.outputSlot;
  1040. var inputSlot = edge.inputSlot;
  1041. Guid remappedOutputNodeGuid;
  1042. Guid remappedInputNodeGuid;
  1043. if (nodeGuidMap.TryGetValue(outputSlot.nodeGuid, out remappedOutputNodeGuid)
  1044. && nodeGuidMap.TryGetValue(inputSlot.nodeGuid, out remappedInputNodeGuid))
  1045. {
  1046. var outputSlotRef = new SlotReference(remappedOutputNodeGuid, outputSlot.slotId);
  1047. var inputSlotRef = new SlotReference(remappedInputNodeGuid, inputSlot.slotId);
  1048. remappedEdges.Add(Connect(outputSlotRef, inputSlotRef));
  1049. }
  1050. }
  1051. ValidateGraph();
  1052. }
  1053. public void OnBeforeSerialize()
  1054. {
  1055. m_SerializableNodes = SerializationHelper.Serialize(GetNodes<AbstractMaterialNode>());
  1056. m_SerializableEdges = SerializationHelper.Serialize<IEdge>(m_Edges);
  1057. m_SerializedProperties = SerializationHelper.Serialize<AbstractShaderProperty>(m_Properties);
  1058. m_SerializedKeywords = SerializationHelper.Serialize<ShaderKeyword>(m_Keywords);
  1059. m_ActiveOutputNodeGuidSerialized = m_ActiveOutputNodeGuid == Guid.Empty ? null : m_ActiveOutputNodeGuid.ToString();
  1060. }
  1061. public void OnAfterDeserialize()
  1062. {
  1063. // have to deserialize 'globals' before nodes
  1064. m_Properties = SerializationHelper.Deserialize<AbstractShaderProperty>(m_SerializedProperties, GraphUtil.GetLegacyTypeRemapping());
  1065. m_Keywords = SerializationHelper.Deserialize<ShaderKeyword>(m_SerializedKeywords, GraphUtil.GetLegacyTypeRemapping());
  1066. var nodes = SerializationHelper.Deserialize<AbstractMaterialNode>(m_SerializableNodes, GraphUtil.GetLegacyTypeRemapping());
  1067. m_Nodes = new List<AbstractMaterialNode>(nodes.Count);
  1068. m_NodeDictionary = new Dictionary<Guid, AbstractMaterialNode>(nodes.Count);
  1069. foreach (var group in m_Groups)
  1070. {
  1071. m_GroupItems.Add(group.guid, new List<IGroupItem>());
  1072. }
  1073. foreach (var node in nodes)
  1074. {
  1075. node.owner = this;
  1076. node.UpdateNodeAfterDeserialization();
  1077. node.tempId = new Identifier(m_Nodes.Count);
  1078. m_Nodes.Add(node);
  1079. m_NodeDictionary.Add(node.guid, node);
  1080. m_GroupItems[node.groupGuid].Add(node);
  1081. }
  1082. foreach (var stickyNote in m_StickyNotes)
  1083. {
  1084. m_GroupItems[stickyNote.groupGuid].Add(stickyNote);
  1085. }
  1086. m_SerializableNodes = null;
  1087. m_Edges = SerializationHelper.Deserialize<IEdge>(m_SerializableEdges, GraphUtil.GetLegacyTypeRemapping());
  1088. m_SerializableEdges = null;
  1089. foreach (var edge in m_Edges)
  1090. AddEdgeToNodeEdges(edge);
  1091. m_OutputNode = null;
  1092. if (!isSubGraph)
  1093. {
  1094. if (string.IsNullOrEmpty(m_ActiveOutputNodeGuidSerialized))
  1095. {
  1096. var node = (AbstractMaterialNode)GetNodes<IMasterNode>().FirstOrDefault();
  1097. if (node != null)
  1098. {
  1099. m_ActiveOutputNodeGuid = node.guid;
  1100. }
  1101. }
  1102. else
  1103. {
  1104. m_ActiveOutputNodeGuid = new Guid(m_ActiveOutputNodeGuidSerialized);
  1105. }
  1106. }
  1107. }
  1108. public void OnEnable()
  1109. {
  1110. foreach (var node in GetNodes<AbstractMaterialNode>().OfType<IOnAssetEnabled>())
  1111. {
  1112. node.OnEnable();
  1113. }
  1114. ShaderGraphPreferences.onVariantLimitChanged += OnKeywordChanged;
  1115. }
  1116. public void OnDisable()
  1117. {
  1118. ShaderGraphPreferences.onVariantLimitChanged -= OnKeywordChanged;
  1119. }
  1120. }
  1121. [Serializable]
  1122. class InspectorPreviewData
  1123. {
  1124. public SerializableMesh serializedMesh = new SerializableMesh();
  1125. [NonSerialized]
  1126. public Quaternion rotation = Quaternion.identity;
  1127. [NonSerialized]
  1128. public float scale = 1f;
  1129. }
  1130. }