VFXConvertSubgraph.cs 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. using System;
  2. using System.IO;
  3. using System.Linq;
  4. using System.Collections.Generic;
  5. using UnityEngine;
  6. using UnityEngine.VFX;
  7. using UnityEditor.VFX;
  8. using UnityEditor.Experimental.GraphView;
  9. using NodeID = System.UInt32;
  10. namespace UnityEditor.VFX.UI
  11. {
  12. static class VFXConvertSubgraph
  13. {
  14. public static void ConvertToSubgraphContext(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect, string path = null)
  15. {
  16. var ctx = new Context();
  17. ctx.ConvertToSubgraphContext(sourceView, controllers, rect, path);
  18. }
  19. public static void ConvertToSubgraphOperator(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect, string path = null)
  20. {
  21. var ctx = new Context();
  22. ctx.ConvertToSubgraphOperator(sourceView, controllers, rect, path);
  23. }
  24. public static void ConvertToSubgraphBlock(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect)
  25. {
  26. var ctx = new Context();
  27. ctx.ConvertToSubgraphBlock(sourceView, controllers, rect);
  28. }
  29. enum Type
  30. {
  31. Context,
  32. Operator,
  33. Block
  34. }
  35. static VisualEffectObject CreateUniquePath(VFXView sourceView, Type type)
  36. {
  37. string graphPath = AssetDatabase.GetAssetPath(sourceView.controller.model.asset);
  38. string graphName = Path.GetFileNameWithoutExtension(graphPath);
  39. string graphDirPath = Path.GetDirectoryName(graphPath);
  40. switch (type)
  41. {
  42. case Type.Operator:
  43. {
  44. string targetSubgraphPath = string.Format("{0}/{1}_SubgraphOperator.vfxoperator", graphDirPath, graphName);
  45. int cpt = 1;
  46. while (File.Exists(targetSubgraphPath))
  47. {
  48. targetSubgraphPath = string.Format("{0}/{1}_SubgraphOperator_{2}.vfxoperator", graphDirPath, graphName, cpt++);
  49. }
  50. return VisualEffectAssetEditorUtility.CreateNew<VisualEffectSubgraphOperator>(targetSubgraphPath);
  51. }
  52. case Type.Context:
  53. {
  54. string targetSubgraphPath = string.Format("{0}/{1}_Subgraph.vfx", graphDirPath, graphName);
  55. int cpt = 1;
  56. while (File.Exists(targetSubgraphPath))
  57. {
  58. targetSubgraphPath = string.Format("{0}/{1}_Subgraph_{2}.vfx", graphDirPath, graphName, cpt++);
  59. }
  60. return VisualEffectAssetEditorUtility.CreateNewAsset(targetSubgraphPath);
  61. }
  62. case Type.Block:
  63. {
  64. string targetSubgraphPath = string.Format("{0}/{1}_SubgraphBlock.vfxblock", graphDirPath, graphName);
  65. int cpt = 1;
  66. while (File.Exists(targetSubgraphPath))
  67. {
  68. targetSubgraphPath = string.Format("{0}/{1}_SubgraphBlock_{2}.vfxblock", graphDirPath, graphName, cpt++);
  69. }
  70. return VisualEffectAssetEditorUtility.CreateNew<VisualEffectSubgraphBlock>(targetSubgraphPath);
  71. }
  72. }
  73. return null;
  74. }
  75. class Context
  76. {
  77. List<VFXParameterNodeController> parameterNodeControllers;
  78. VFXViewController m_SourceController;
  79. List<Controller> m_SourceControllers;
  80. VFXView m_SourceView;
  81. VFXModel m_SourceNode;
  82. IVFXSlotContainer m_SourceSlotContainer;
  83. VFXNodeController m_SourceNodeController;
  84. Dictionary<string, VFXParameterNodeController> m_SourceParameters;
  85. VFXViewController m_TargetController;
  86. List<VFXNodeController> m_TargetControllers;
  87. List<VFXParameterController> m_TargetParameters = new List<VFXParameterController>();
  88. VisualEffectObject m_TargetSubgraph;
  89. Rect m_Rect;
  90. void Init(VFXView sourceView, IEnumerable<Controller> controllers)
  91. {
  92. this.m_SourceView = sourceView;
  93. m_SourceControllers = controllers.Concat(sourceView.controller.dataEdges.Where(t => controllers.Contains(t.input.sourceNode) && controllers.Contains(t.output.sourceNode))).Distinct().ToList();
  94. parameterNodeControllers = m_SourceControllers.OfType<VFXParameterNodeController>().ToList();
  95. m_SourceController = sourceView.controller;
  96. VFXGraph sourceGraph = m_SourceController.graph;
  97. m_SourceController.useCount++;
  98. m_SourceParameters = new Dictionary<string, VFXParameterNodeController>();
  99. foreach (var parameterNode in parameterNodeControllers)
  100. {
  101. m_SourceParameters[parameterNode.exposedName] = parameterNode;
  102. }
  103. }
  104. void Uninit()
  105. {
  106. foreach (var element in m_SourceControllers.Where(t => !(t is VFXDataEdgeController) && !(t is VFXParameterNodeController)))
  107. {
  108. m_SourceController.RemoveElement(element);
  109. }
  110. foreach (var element in parameterNodeControllers)
  111. {
  112. if (element.infos.linkedSlots == null || element.infos.linkedSlots.Count() == 0)
  113. m_SourceController.RemoveElement(element);
  114. }
  115. m_TargetController.useCount--;
  116. m_SourceController.useCount--;
  117. }
  118. void UninitSmart()
  119. {
  120. var nodeNotToDelete = new HashSet<Controller>();
  121. foreach (var node in m_SourceControllers.OfType<VFXNodeController>().Where(t => t.outputPorts.Count() > 0))
  122. {
  123. if (nodeNotToDelete.Contains(node))
  124. continue;
  125. var oldBag = new HashSet<VFXNodeController>();
  126. var newBag = new HashSet<VFXNodeController>();
  127. oldBag.Add(node);
  128. while (oldBag.Count > 0)
  129. {
  130. foreach (var n in oldBag)
  131. {
  132. if (n.outputPorts.SelectMany(t => t.connections).Any(t => nodeNotToDelete.Contains(t.input.sourceNode) || !m_SourceControllersWithBlocks.Contains(t.input.sourceNode)))
  133. {
  134. nodeNotToDelete.Add(n);
  135. oldBag.Clear();
  136. break;
  137. }
  138. foreach (var o in n.inputPorts.SelectMany(t => t.connections).Select(t => t.output))
  139. {
  140. newBag.Add(o.sourceNode);
  141. }
  142. }
  143. oldBag.Clear();
  144. var tmp = oldBag;
  145. oldBag = newBag;
  146. newBag = tmp;
  147. }
  148. }
  149. foreach (var element in m_SourceControllers.Where(t => !(t is VFXDataEdgeController) && !(t is VFXParameterNodeController) && !nodeNotToDelete.Contains(t)))
  150. {
  151. m_SourceController.RemoveElement(element);
  152. }
  153. foreach (var element in parameterNodeControllers)
  154. {
  155. if (element.infos.linkedSlots == null || element.infos.linkedSlots.Count() == 0)
  156. m_SourceController.RemoveElement(element);
  157. }
  158. m_TargetController.useCount--;
  159. m_SourceController.useCount--;
  160. }
  161. void CopyPasteNodes()
  162. {
  163. object result = VFXCopy.Copy(m_SourceControllers, m_Rect);
  164. VFXPaste.Paste(m_TargetController, m_Rect.center, result, null, null, m_TargetControllers);
  165. List<VFXParameterController> targetParameters = new List<VFXParameterController>();
  166. }
  167. List<VFXNodeController> m_SourceOperatorAndParameters;
  168. List<VFXNodeController> m_TargetOperatorAndParameters;
  169. void CopyPasteOperators(Dictionary<VFXNodeController, VFXNodeController> targetNodes)
  170. {
  171. m_SourceOperatorAndParameters = m_SourceControllers.OfType<VFXNodeController>().Where(t => !(t is VFXBlockController)).ToList();
  172. object result = VFXCopy.Copy(m_SourceOperatorAndParameters, m_Rect);
  173. m_TargetOperatorAndParameters = new List<VFXNodeController>();
  174. VFXPaste.Paste(m_TargetController, m_Rect.center, result, null, null, m_TargetOperatorAndParameters);
  175. foreach (var st in m_SourceOperatorAndParameters.Zip(m_TargetOperatorAndParameters, (s, t) => new { source = s, target = t }))
  176. {
  177. targetNodes[st.source] = st.target;
  178. }
  179. }
  180. void SetupTargetParameters()
  181. {
  182. // Change each parameter created by copy paste ( and therefore a parameter copied ) to exposed
  183. foreach (var parameter in m_TargetController.parameterControllers)
  184. {
  185. m_TargetParameters.Add(parameter);
  186. parameter.exposed = true;
  187. }
  188. }
  189. public void ConvertToSubgraphContext(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect, string path)
  190. {
  191. this.m_Rect = rect;
  192. Init(sourceView, controllers);
  193. if (path == null)
  194. {
  195. if (!CreateUniqueSubgraph("Subgraph", VisualEffectResource.Extension, VisualEffectAssetEditorUtility.CreateNewAsset))
  196. return;
  197. }
  198. else
  199. {
  200. m_TargetSubgraph = VisualEffectAssetEditorUtility.CreateNewAsset(path);
  201. m_TargetController = VFXViewController.GetController(m_TargetSubgraph.GetResource());
  202. m_TargetController.useCount++;
  203. m_TargetControllers = new List<VFXNodeController>();
  204. }
  205. CopyPasteNodes();
  206. m_SourceNode = ScriptableObject.CreateInstance<VFXSubgraphContext>();
  207. PostSetupNode();
  208. m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceControllers.OfType<VFXContextController>().SelectMany(t => t.blockControllers));
  209. TransferEdges();
  210. //TransferContextsFlowEdges();
  211. UninitSmart();
  212. }
  213. public void ConvertToSubgraphOperator(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect, string path)
  214. {
  215. this.m_Rect = rect;
  216. Init(sourceView, controllers);
  217. if (path == null)
  218. {
  219. if (!CreateUniqueSubgraph("SubgraphOperator", VisualEffectSubgraphOperator.Extension, VisualEffectAssetEditorUtility.CreateNew<VisualEffectSubgraphOperator>))
  220. return;
  221. }
  222. else
  223. {
  224. m_TargetSubgraph = VisualEffectAssetEditorUtility.CreateNew<VisualEffectSubgraphOperator>(path);
  225. m_TargetController = VFXViewController.GetController(m_TargetSubgraph.GetResource());
  226. m_TargetController.useCount++;
  227. m_TargetControllers = new List<VFXNodeController>();
  228. }
  229. CopyPasteNodes();
  230. m_SourceNode = ScriptableObject.CreateInstance<VFXSubgraphOperator>();
  231. PostSetupNode();
  232. m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceControllers.OfType<VFXContextController>().SelectMany(t => t.blockControllers));
  233. TransferEdges();
  234. TransfertOperatorOutputEdges();
  235. Uninit();
  236. //The PrepareSubgraphs was initially in compilation
  237. //This change has been canceled to prevent creation of model in the wrong place
  238. //Be sure the newly created operator has expected slot
  239. var subGraphOperator = m_SourceNode as VFXSubgraphOperator;
  240. subGraphOperator.RecreateCopy();
  241. subGraphOperator.ResyncSlots(true);
  242. }
  243. List<VFXBlockController> m_SourceBlockControllers;
  244. List<VFXBlockController> m_TargetBlocks = null;
  245. public void ConvertToSubgraphBlock(VFXView sourceView, IEnumerable<Controller> controllers, Rect rect)
  246. {
  247. this.m_Rect = rect;
  248. Init(sourceView, controllers);
  249. if (!CreateUniqueSubgraph("SubgraphBlock", VisualEffectSubgraphBlock.Extension, VisualEffectAssetEditorUtility.CreateNew<VisualEffectSubgraphBlock>))
  250. return;
  251. m_SourceControllers.RemoveAll(t => t is VFXContextController); // Don't copy contexts
  252. m_SourceBlockControllers = m_SourceControllers.OfType<VFXBlockController>().OrderBy(t => t.index).ToList();
  253. VFXContextController sourceContextController = m_SourceBlockControllers.First().contextController;
  254. object copyData = VFXCopy.CopyBlocks(m_SourceBlockControllers);
  255. var targetContext = m_TargetController.graph.children.OfType<VFXBlockSubgraphContext>().FirstOrDefault();
  256. if (targetContext == null)
  257. {
  258. targetContext = ScriptableObject.CreateInstance<VFXBlockSubgraphContext>();
  259. m_TargetController.graph.AddChild(targetContext);
  260. }
  261. m_TargetController.LightApplyChanges();
  262. targetContext.position = sourceContextController.position;
  263. targetContext.SetSettingValue("m_SuitableContexts", (VFXBlockSubgraphContext.ContextType)m_SourceBlockControllers.Select(t => t.model.compatibleContexts).Aggregate((t, s) => t & s));
  264. m_TargetBlocks = new List<VFXBlockController>();
  265. VFXPaste.PasteBlocks(m_TargetController, copyData, targetContext, 0, m_TargetBlocks);
  266. Dictionary<VFXNodeController, VFXNodeController> targetControllers = new Dictionary<VFXNodeController, VFXNodeController>();
  267. CopyPasteOperators(targetControllers);
  268. m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceBlockControllers);
  269. //Create lost links between nodes and blocks
  270. foreach (var edge in m_SourceController.dataEdges.Where(t => m_SourceOperatorAndParameters.Contains(t.output.sourceNode) && m_SourceBlockControllers.Contains(t.input.sourceNode)))
  271. {
  272. var outputNode = targetControllers[edge.output.sourceNode];
  273. var output = outputNode.outputPorts.First(t => t.path == edge.output.path);
  274. var inputBlock = m_TargetBlocks[m_SourceBlockControllers.IndexOf(edge.input.sourceNode as VFXBlockController)];
  275. var input = inputBlock.inputPorts.First(t => t.path == edge.input.path);
  276. m_TargetController.CreateLink(input, output);
  277. }
  278. //Create lost links between nodes
  279. foreach (var edge in m_SourceController.dataEdges.Where(t => m_SourceOperatorAndParameters.Contains(t.output.sourceNode) && m_SourceOperatorAndParameters.Contains(t.input.sourceNode)))
  280. {
  281. var outputNode = targetControllers[edge.output.sourceNode];
  282. var output = outputNode.outputPorts.First(t => t.path == edge.output.path);
  283. var inputNode = targetControllers[edge.input.sourceNode];
  284. var input = inputNode.inputPorts.First(t => t.path == edge.input.path);
  285. m_TargetController.CreateLink(input, output);
  286. }
  287. var sourceBlock = ScriptableObject.CreateInstance<VFXSubgraphBlock>();
  288. m_SourceNode = sourceBlock;
  289. sourceContextController.model.AddChild(m_SourceNode, m_SourceBlockControllers.Select(t => t.index).Min());
  290. (m_SourceView.GetNodeByController(sourceContextController) as VFXContextUI).UpdateSelectionWithNewBlocks();
  291. sourceContextController.ApplyChanges();
  292. m_SourceNodeController = sourceContextController.blockControllers.First(t => t.model == m_SourceNode);
  293. PostSetup();
  294. m_SourceNode.SetSettingValue("m_Subgraph", m_TargetSubgraph);
  295. m_SourceNodeController.ApplyChanges();
  296. var targetContextController = m_TargetController.GetRootNodeController(targetContext, 0) as VFXContextController;
  297. m_SourceControllersWithBlocks = m_SourceControllers.Concat(m_SourceBlockControllers);
  298. m_SourceControllers = m_SourceOperatorAndParameters.Cast<Controller>().ToList();
  299. m_TargetControllers = m_TargetOperatorAndParameters;
  300. TransferEdges();
  301. m_SourceControllers = m_SourceControllersWithBlocks.ToList();
  302. UninitSmart();
  303. }
  304. bool CreateUniqueSubgraph(string typeName, string extension, Func<string, VisualEffectObject> createFunc)
  305. {
  306. string graphPath = AssetDatabase.GetAssetPath(m_SourceView.controller.model);
  307. string graphName;
  308. string graphDirPath;
  309. if (string.IsNullOrEmpty(graphPath))
  310. {
  311. graphName = m_SourceView.controller.model.name;
  312. if (string.IsNullOrEmpty(graphName))
  313. graphName = "New VFX";
  314. graphDirPath = "Assets";
  315. }
  316. else
  317. {
  318. graphName = Path.GetFileNameWithoutExtension(graphPath);
  319. graphDirPath = Path.GetDirectoryName(graphPath).Replace('\\', '/');
  320. }
  321. string fileName = $"{graphName}_{typeName}";
  322. string targetSubgraphPath = string.Format("{0}/{1}{2}", graphDirPath, fileName, extension);
  323. int cpt = 1;
  324. while (File.Exists(targetSubgraphPath))
  325. {
  326. fileName = $"{graphName}_{typeName}_{cpt++}";
  327. targetSubgraphPath = string.Format("{0}/{1}{2}", graphDirPath, fileName, extension);
  328. }
  329. targetSubgraphPath = EditorUtility.SaveFilePanelInProject("Create Subgraph", fileName, extension.Substring(1), "Select where you want to save your subgraph.");
  330. if (string.IsNullOrEmpty(targetSubgraphPath))
  331. return false;
  332. if (Path.GetExtension(targetSubgraphPath) != extension)
  333. {
  334. targetSubgraphPath += extension;
  335. }
  336. if (File.Exists(targetSubgraphPath))
  337. {
  338. Debug.LogError("Can't overwrite a subgraph");
  339. return false;
  340. }
  341. m_TargetSubgraph = createFunc(targetSubgraphPath);
  342. m_TargetController = VFXViewController.GetController(m_TargetSubgraph.GetResource());
  343. m_TargetController.useCount++;
  344. m_TargetControllers = new List<VFXNodeController>();
  345. return true;
  346. }
  347. void PostSetupNode()
  348. {
  349. PostSetup();
  350. m_SourceNode.position = m_Rect.center;
  351. m_SourceView.UpdateSelectionWithNewNode();
  352. m_SourceController.graph.AddChild(m_SourceNode);
  353. m_SourceNode.SetSettingValue("m_Subgraph", m_TargetSubgraph);
  354. m_SourceController.LightApplyChanges();
  355. m_SourceNodeController = m_SourceController.GetRootNodeController(m_SourceNode, 0);
  356. m_SourceNodeController.ApplyChanges();
  357. }
  358. void PostSetup()
  359. {
  360. SetupTargetParameters();
  361. m_SourceSlotContainer = m_SourceNode as IVFXSlotContainer;
  362. }
  363. void TransferEdges()
  364. {
  365. for (int i = 0; i < m_TargetParameters.Count; ++i)
  366. {
  367. var input = m_SourceNodeController.inputPorts.First(t => t.model == m_SourceSlotContainer.inputSlots[i]);
  368. var output = m_SourceParameters[m_TargetParameters[i].exposedName].outputPorts.First();
  369. m_TargetController.CreateLink(input, output);
  370. }
  371. TransfertDataEdges();
  372. }
  373. IEnumerable<Controller> m_SourceControllersWithBlocks;
  374. void TransfertDataEdges()
  375. {
  376. // Search for links between with inputs in the selected part and the output in other parts of the graph.
  377. Dictionary<VFXDataAnchorController, List<VFXDataAnchorController>> traversingInEdges = new Dictionary<VFXDataAnchorController, List<VFXDataAnchorController>>();
  378. foreach (var edge in m_SourceController.dataEdges.Where(
  379. t =>
  380. {
  381. if (parameterNodeControllers.Contains(t.output.sourceNode))
  382. return false;
  383. var inputInControllers = m_SourceControllersWithBlocks.Contains(t.input.sourceNode);
  384. var outputInControllers = m_SourceControllersWithBlocks.Contains(t.output.sourceNode);
  385. return inputInControllers && !outputInControllers;
  386. }
  387. ))
  388. {
  389. List<VFXDataAnchorController> outputs = null;
  390. if (!traversingInEdges.TryGetValue(edge.input, out outputs))
  391. {
  392. outputs = new List<VFXDataAnchorController>();
  393. traversingInEdges[edge.input] = outputs;
  394. }
  395. outputs.Add(edge.output);
  396. }
  397. var newSourceInputs = traversingInEdges.Keys.ToArray();
  398. for (int i = 0; i < newSourceInputs.Length; ++i)
  399. {
  400. VFXParameter newTargetParameter = m_TargetController.AddVFXParameter(Vector2.zero, VFXLibrary.GetParameters().First(t => t.model.type == newSourceInputs[i].portType));
  401. m_TargetController.LightApplyChanges();
  402. VFXParameterController newTargetParamController = m_TargetController.GetParameterController(newTargetParameter);
  403. newTargetParamController.exposed = true;
  404. var outputs = traversingInEdges[newSourceInputs[i]];
  405. var linkedParameter = outputs.FirstOrDefault(t => t.sourceNode is VFXParameterNodeController);
  406. if (linkedParameter != null)
  407. {
  408. newTargetParamController.exposedName = (linkedParameter.sourceNode as VFXParameterNodeController).parentController.exposedName;
  409. {
  410. VFXParameter originalParameter = (linkedParameter.sourceNode as VFXParameterNodeController).parentController.model;
  411. newTargetParameter.valueFilter = originalParameter.valueFilter;
  412. if (originalParameter.valueFilter == VFXValueFilter.Range)
  413. {
  414. newTargetParameter.min = originalParameter.min;
  415. newTargetParameter.max = originalParameter.max;
  416. }
  417. else if (originalParameter.valueFilter == VFXValueFilter.Enum)
  418. {
  419. newTargetParameter.enumValues = originalParameter.enumValues.ToList();
  420. }
  421. }
  422. }
  423. else
  424. newTargetParamController.exposedName = newSourceInputs[i].name;
  425. //first the equivalent of sourceInput in the target
  426. VFXNodeController targetNode = null;
  427. Vector2 position;
  428. if (newSourceInputs[i].sourceNode is VFXBlockController)
  429. {
  430. var blockController = newSourceInputs[i].sourceNode as VFXBlockController;
  431. if (m_TargetBlocks != null)
  432. {
  433. targetNode = m_TargetBlocks[m_SourceBlockControllers.IndexOf(blockController)];
  434. position = blockController.contextController.position;
  435. }
  436. else
  437. {
  438. var targetContext = m_TargetControllers[m_SourceControllers.IndexOf(blockController.contextController)] as VFXContextController;
  439. targetNode = targetContext.blockControllers[blockController.index];
  440. position = blockController.contextController.position;
  441. }
  442. }
  443. else
  444. {
  445. targetNode = m_TargetControllers[m_SourceControllers.IndexOf(newSourceInputs[i].sourceNode)];
  446. position = targetNode.position;
  447. }
  448. VFXDataAnchorController targetAnchor = targetNode.inputPorts.First(t => t.path == newSourceInputs[i].path);
  449. position.y += targetAnchor.model.owner.inputSlots.IndexOf(targetAnchor.model) * 32;
  450. VFXNodeController parameterNode = m_TargetController.AddVFXParameter(position - new Vector2(200, 0), newTargetParamController, null);
  451. // Link the parameternode and the input in the target
  452. m_TargetController.CreateLink(targetAnchor, parameterNode.outputPorts[0]);
  453. if (m_SourceSlotContainer is VFXOperator)
  454. (m_SourceSlotContainer as VFXOperator).ResyncSlots(true);
  455. else if (m_SourceSlotContainer is VFXSubgraphBlock)
  456. {
  457. VFXSubgraphBlock blk = (m_SourceSlotContainer as VFXSubgraphBlock);
  458. blk.RecreateCopy();
  459. blk.ResyncSlots(true);
  460. }
  461. else if (m_SourceSlotContainer is VFXSubgraphContext)
  462. {
  463. VFXSubgraphContext ctx = (m_SourceSlotContainer as VFXSubgraphContext);
  464. ctx.RecreateCopy();
  465. ctx.ResyncSlots(true);
  466. }
  467. m_SourceNodeController.model.Invalidate(VFXModel.InvalidationCause.kSettingChanged); // call to resync slots
  468. m_SourceNodeController.ApplyChanges();
  469. //Link all the outputs to the matching input of the subgraph
  470. foreach (var output in outputs)
  471. {
  472. m_SourceController.CreateLink(m_SourceNodeController.inputPorts.First(t => t.model == m_SourceSlotContainer.inputSlots.Last()), output);
  473. }
  474. }
  475. }
  476. void TransfertOperatorOutputEdges()
  477. {
  478. var traversingOutEdges = new Dictionary<VFXDataAnchorController, List<VFXDataAnchorController>>();
  479. foreach (var edge in m_SourceController.dataEdges.Where(
  480. t =>
  481. {
  482. if (t.output.sourceNode is VFXParameterNodeController)
  483. return false;
  484. var inputInControllers = m_SourceControllersWithBlocks.Contains(t.input.sourceNode);
  485. var outputInControllers = m_SourceControllersWithBlocks.Contains(t.output.sourceNode);
  486. return !inputInControllers && outputInControllers;
  487. }
  488. ))
  489. {
  490. List<VFXDataAnchorController> inputs = null;
  491. if (!traversingOutEdges.TryGetValue(edge.output, out inputs))
  492. {
  493. inputs = new List<VFXDataAnchorController>();
  494. traversingOutEdges[edge.output] = inputs;
  495. }
  496. inputs.Add(edge.input);
  497. }
  498. var newSourceOutputs = traversingOutEdges.Keys.ToArray();
  499. for (int i = 0; i < newSourceOutputs.Length; ++i)
  500. {
  501. VFXParameter newTargetParameter = m_TargetController.AddVFXParameter(Vector2.zero, VFXLibrary.GetParameters().First(t => t.model.type == newSourceOutputs[i].portType));
  502. m_TargetController.LightApplyChanges();
  503. VFXParameterController newTargetParamController = m_TargetController.GetParameterController(newTargetParameter);
  504. newTargetParamController.isOutput = true;
  505. var inputs = traversingOutEdges[newSourceOutputs[i]];
  506. var linkedParameter = inputs.FirstOrDefault(t => t.sourceNode is VFXParameterNodeController);
  507. if (linkedParameter != null)
  508. newTargetParamController.exposedName = (linkedParameter.sourceNode as VFXParameterNodeController).parentController.exposedName;
  509. else
  510. newTargetParamController.exposedName = newSourceOutputs[i].name;
  511. //first the equivalent of sourceInput in the target
  512. VFXNodeController targetNode = null;
  513. if (newSourceOutputs[i].sourceNode is VFXBlockController)
  514. {
  515. var blockController = newSourceOutputs[i].sourceNode as VFXBlockController;
  516. if (m_TargetBlocks != null)
  517. {
  518. targetNode = m_TargetBlocks[m_SourceBlockControllers.IndexOf(blockController)];
  519. }
  520. else
  521. {
  522. var targetContext = m_TargetControllers[m_SourceControllers.IndexOf(blockController.contextController)] as VFXContextController;
  523. targetNode = targetContext.blockControllers[blockController.index];
  524. }
  525. }
  526. else
  527. {
  528. targetNode = m_TargetControllers[m_SourceControllers.IndexOf(newSourceOutputs[i].sourceNode)];
  529. }
  530. VFXDataAnchorController targetAnchor = targetNode.outputPorts.FirstOrDefault(t => t.path == newSourceOutputs[i].path);
  531. if (targetAnchor != null)
  532. {
  533. VFXNodeController parameterNode = m_TargetController.AddVFXParameter(targetNode.position + new Vector2(400, 0), newTargetParamController, null);
  534. // Link the parameternode and the input in the target
  535. m_TargetController.CreateLink(parameterNode.inputPorts[0], targetAnchor);
  536. if (m_SourceSlotContainer is VFXOperator)
  537. (m_SourceSlotContainer as VFXOperator).ResyncSlots(true);
  538. m_SourceNodeController.ApplyChanges();
  539. }
  540. //Link all the outputs to the matching input of the subgraph
  541. foreach (var input in inputs)
  542. {
  543. var port = m_SourceNodeController.outputPorts.FirstOrDefault(t => t.model == m_SourceSlotContainer.outputSlots.Last());
  544. if (port != null)
  545. m_SourceController.CreateLink(input, port);
  546. }
  547. }
  548. }
  549. void TransferContextsFlowEdges()
  550. {
  551. var initializeContexts = m_SourceControllers.OfType<VFXContextController>().Where(t => t.model.contextType == VFXContextType.Init ||
  552. t.model.contextType == VFXContextType.Spawner ||
  553. t.model.contextType == VFXContextType.Subgraph).ToArray();
  554. var outputSpawners = new Dictionary<VFXContextController, List<VFXFlowAnchorController>>();
  555. var outputEvents = new Dictionary<string, List<VFXFlowAnchorController>>();
  556. foreach (var initializeContext in initializeContexts)
  557. {
  558. for (int i = 0; i < initializeContext.flowInputAnchors.Count; ++i)
  559. if (initializeContext.flowInputAnchors[i].connections.Count() > 0)
  560. {
  561. var outputContext = initializeContext.flowInputAnchors[i].connections.First().output.context; //output context must be linked through is it is linked with a spawner
  562. if (!m_SourceControllers.Contains(outputContext))
  563. {
  564. if (outputContext.model.contextType == VFXContextType.Spawner /*||
  565. ((outputContext.model is VFXBasicEvent) &&
  566. (new string[] { VisualEffectAsset.PlayEventName, VisualEffectAsset.StopEventName }.Contains((outputContext.model as VFXBasicEvent).eventName) ||
  567. sourceController.model.isSubgraph && (outputContext.model as VFXBasicEvent).eventName == VFXSubgraphContext.triggerEventName))*/)
  568. {
  569. List<VFXFlowAnchorController> inputs = null;
  570. if (!outputSpawners.TryGetValue(outputContext, out inputs))
  571. {
  572. inputs = new List<VFXFlowAnchorController>();
  573. outputSpawners.Add(outputContext, inputs);
  574. }
  575. inputs.Add(initializeContext.flowInputAnchors[i]);
  576. }
  577. else if (outputContext.model is VFXBasicEvent)
  578. {
  579. List<VFXFlowAnchorController> inputs = null;
  580. var eventName = (outputContext.model as VFXBasicEvent).eventName;
  581. if (!outputEvents.TryGetValue(eventName, out inputs))
  582. {
  583. inputs = new List<VFXFlowAnchorController>();
  584. outputEvents.Add(eventName, inputs);
  585. }
  586. inputs.Add(initializeContext.flowInputAnchors[i]);
  587. }
  588. }
  589. }
  590. }
  591. {
  592. if (outputSpawners.Count() > 1)
  593. {
  594. Debug.LogWarning("More than one spawner is linked to the content if the new subgraph, some links we not be kept");
  595. }
  596. }
  597. { //link named events as if
  598. foreach (var kv in outputEvents)
  599. {
  600. CreateAndLinkEvent(m_SourceControllers, m_TargetController, m_TargetControllers, kv.Value, kv.Key);
  601. }
  602. }
  603. }
  604. }
  605. private static void CreateAndLinkEvent(List<Controller> sourceControllers, VFXViewController targetController, List<VFXNodeController> targetControllers, List<VFXFlowAnchorController> inputs, string eventName)
  606. {
  607. var triggerEvent = VFXBasicEvent.CreateInstance<VFXBasicEvent>();
  608. triggerEvent.eventName = eventName;
  609. targetController.graph.AddChild(triggerEvent);
  610. float xMiddle = 0;
  611. float yMin = Mathf.Infinity;
  612. foreach (var edge in inputs)
  613. {
  614. var targetContext = targetControllers[sourceControllers.IndexOf(edge.context)] as VFXContextController;
  615. var targetInputLink = edge.slotIndex;
  616. triggerEvent.LinkTo(targetContext.model, 0, targetInputLink);
  617. xMiddle += targetContext.position.x;
  618. if (targetContext.position.y < yMin)
  619. yMin = targetContext.position.y;
  620. }
  621. triggerEvent.position = new Vector2(xMiddle / inputs.Count, yMin) - new Vector2(0, 200); // place the event above the top center of the linked contexts.
  622. }
  623. }
  624. }