123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417 |
- using System;
- using System.Linq;
- using System.Collections.Generic;
- using UnityEngine;
- using UnityEditor.VFX;
- using UnityEngine.UIElements;
- using System.Reflection;
- using NodeID = System.UInt32;
- namespace UnityEditor.VFX.UI
- {
- class VFXCopy : VFXCopyPasteCommon
- {
- VFXContextController[] contexts;
- int[] contextsIndices;
- VFXOperatorController[] operators;
- int[] operatorIndices;
- VFXParameterNodeController[] parameters;
- int[] parameterIndices;
- VFXData[] datas;
- Dictionary<VFXNodeController, uint> modelIndices = new Dictionary<VFXNodeController, NodeID>();
- static VFXCopy s_Instance;
- public static object Copy(IEnumerable<Controller> elements, Rect bounds)
- {
- if (s_Instance == null)
- s_Instance = new VFXCopy();
- return s_Instance.CreateCopy(elements, bounds);
- }
- public static string SerializeElements(IEnumerable<Controller> elements, Rect bounds)
- {
- if (s_Instance == null)
- s_Instance = new VFXCopy();
- var serializableGraph = s_Instance.CreateCopy(elements, bounds) as SerializableGraph;
- return JsonUtility.ToJson(serializableGraph);
- }
- public static object CopyBlocks(IEnumerable<VFXBlockController> blocks)
- {
- if (s_Instance == null)
- s_Instance = new VFXCopy();
- return s_Instance.DoCopyBlocks(blocks);
- }
- object CreateCopy(IEnumerable<Controller> elements, Rect bounds)
- {
- IEnumerable<VFXContextController> contexts = elements.OfType<VFXContextController>();
- IEnumerable<VFXNodeController> nodes = elements.Where(t => t is VFXOperatorController || t is VFXParameterNodeController).Cast<VFXNodeController>();
- IEnumerable<VFXBlockController> blocks = elements.OfType<VFXBlockController>();
- SerializableGraph serializableGraph = new SerializableGraph();
- serializableGraph.controllerCount = elements.Count();
- if (contexts.Count() == 0 && nodes.Count() == 0 && blocks.Count() > 0)
- {
- var copiedBlocks = new List<VFXBlockController>(blocks);
- modelIndices.Clear();
- serializableGraph.operators = CopyBlocks(copiedBlocks, 0);
- serializableGraph.blocksOnly = true;
- }
- else
- {
- //Don't copy VFXBlockSubgraphContext because they can't be pasted anywhere.
- CopyNodes(serializableGraph, elements, contexts.Where(t => !(t.model is VFXBlockSubgraphContext)), nodes, bounds);
- }
- return serializableGraph;
- }
- void CopyNodes(SerializableGraph serializableGraph, IEnumerable<Controller> elements, IEnumerable<VFXContextController> copiedContexts, IEnumerable<VFXNodeController> nodes, Rect bounds)
- {
- Controller[] copiedElements = elements.ToArray();
- serializableGraph.bounds = bounds;
- IEnumerable<VFXNodeController> dataEdgeTargets = nodes.Concat(copiedContexts.Cast<VFXNodeController>()).Concat(copiedContexts.SelectMany(t => t.blockControllers).Cast<VFXNodeController>()).ToArray();
- // consider only edges contained in the selection
- IEnumerable<VFXDataEdgeController> dataEdges = elements.OfType<VFXDataEdgeController>().Where(t =>
- dataEdgeTargets.Contains((t.input as VFXDataAnchorController).sourceNode as VFXNodeController) &&
- dataEdgeTargets.Contains((t.output as VFXDataAnchorController).sourceNode as VFXNodeController)).ToArray();
- IEnumerable<VFXFlowEdgeController> flowEdges = elements.OfType<VFXFlowEdgeController>().Where(t =>
- copiedContexts.Contains((t.input as VFXFlowAnchorController).context) &&
- copiedContexts.Contains((t.output as VFXFlowAnchorController).context)
- ).ToArray();
- modelIndices.Clear();
- contexts = copiedContexts.ToArray();
- operators = nodes.OfType<VFXOperatorController>().ToArray();
- parameters = nodes.OfType<VFXParameterNodeController>().ToArray();
- contextsIndices = contexts.Select(t => Array.IndexOf(copiedElements, t)).ToArray();
- operatorIndices = operators.Select(t => Array.IndexOf(copiedElements, t)).ToArray();
- parameterIndices = parameters.Select(t => Array.IndexOf(copiedElements, t)).ToArray();
- datas = contexts.Select(t => t.model.GetData()).Where(t => t != null).ToArray();
- CopyOperatorsAndContexts(ref serializableGraph);
- CopyParameters(ref serializableGraph);
- CopyGroupNodesAndStickyNotes(ref serializableGraph, elements);
- CopyDatas(ref serializableGraph);
- CopyDataEdge(ref serializableGraph, dataEdges);
- CopyFlowEdges(ref serializableGraph, flowEdges);
- }
- void CopyGroupNodesAndStickyNotes(ref SerializableGraph serializableGraph, IEnumerable<Controller> elements)
- {
- VFXGroupNodeController[] groupNodes = elements.OfType<VFXGroupNodeController>().ToArray();
- VFXStickyNoteController[] stickyNotes = elements.OfType<VFXStickyNoteController>().ToArray();
- if (groupNodes.Length > 0 || stickyNotes.Length > 0)
- {
- var stickyNodeIndexToCopiedIndex = new Dictionary<int, int>();
- if (stickyNotes.Length > 0)
- {
- serializableGraph.stickyNotes = new VFXUI.StickyNoteInfo[stickyNotes.Length];
- for (int i = 0; i < stickyNotes.Length; ++i)
- {
- VFXStickyNoteController stickyNote = stickyNotes[i];
- stickyNodeIndexToCopiedIndex[stickyNote.index] = i;
- VFXUI.StickyNoteInfo info = stickyNote.model.stickyNoteInfos[stickyNote.index];
- serializableGraph.stickyNotes[i] = new VFXUI.StickyNoteInfo(info);
- }
- }
- if (groupNodes.Length > 0)
- {
- serializableGraph.groupNodes = new GroupNode[groupNodes.Length];
- for (int i = 0; i < groupNodes.Length; ++i)
- {
- VFXGroupNodeController groupNode = groupNodes[i];
- VFXUI.GroupInfo info = groupNode.model.groupInfos[groupNode.index];
- serializableGraph.groupNodes[i] = new GroupNode { infos = new VFXUI.UIInfo(info) };
- // only keep nodes and sticky notes that are copied because a element can not be in two groups at the same time.
- if (info.contents != null)
- {
- var nodeIndices = groupNode.nodes.OfType<VFXNodeController>().Where(t => contexts.Contains(t) || operators.Contains(t) || parameters.Contains(t)).Select(t => modelIndices[t]);
- var stickNoteIndices = info.contents.Where(t => t.isStickyNote && stickyNodeIndexToCopiedIndex.ContainsKey(t.id)).Select(t => (uint)stickyNodeIndexToCopiedIndex[t.id]);
- serializableGraph.groupNodes[i].contents = nodeIndices.Concat(stickNoteIndices).ToArray();
- serializableGraph.groupNodes[i].stickNodeCount = stickNoteIndices.Count();
- }
- }
- }
- }
- }
- void CopyDataEdge(ref SerializableGraph serializableGraph, IEnumerable<VFXDataEdgeController> dataEdges)
- {
- serializableGraph.dataEdges = new DataEdge[dataEdges.Count()];
- int cpt = 0;
- foreach (var edge in dataEdges)
- {
- DataEdge copyPasteEdge = new DataEdge();
- var inputController = edge.input as VFXDataAnchorController;
- var outputController = edge.output as VFXDataAnchorController;
- copyPasteEdge.input.slotPath = MakeSlotPath(inputController.model, true);
- copyPasteEdge.input.targetIndex = modelIndices[inputController.sourceNode];
- copyPasteEdge.output.slotPath = MakeSlotPath(outputController.model, false);
- copyPasteEdge.output.targetIndex = modelIndices[outputController.sourceNode];
- serializableGraph.dataEdges[cpt++] = copyPasteEdge;
- }
- }
- void CopyFlowEdges(ref SerializableGraph serializableGraph, IEnumerable<VFXFlowEdgeController> flowEdges)
- {
- serializableGraph.flowEdges = new FlowEdge[flowEdges.Count()];
- int cpt = 0;
- foreach (var edge in flowEdges)
- {
- FlowEdge copyPasteEdge = new FlowEdge();
- var inputController = edge.input as VFXFlowAnchorController;
- var outputController = edge.output as VFXFlowAnchorController;
- copyPasteEdge.input.contextIndex = modelIndices[inputController.context];
- copyPasteEdge.input.flowIndex = inputController.slotIndex;
- copyPasteEdge.output.contextIndex = modelIndices[outputController.context];
- copyPasteEdge.output.flowIndex = outputController.slotIndex;
- serializableGraph.flowEdges[cpt++] = copyPasteEdge;
- }
- }
- void CopyDatas(ref SerializableGraph serializableGraph)
- {
- serializableGraph.datas = new Data[datas.Length];
- for (int i = 0; i < datas.Length; ++i)
- {
- CopyModelSettings(ref serializableGraph.datas[i].settings, datas[i]);
- }
- }
- void CopyModelSettings(ref Property[] properties, VFXModel model)
- {
- // Copy all fields that are either VFXSettings or serialized by unity
- Type type = model.GetType();
- var fields = GetFields(type);
- properties = new Property[fields.Count()];
- for (int i = 0; i < properties.Length; ++i)
- {
- properties[i].name = fields[i].Name;
- properties[i].value = new VFXSerializableObject(fields[i].FieldType, fields[i].GetValue(model));
- }
- }
- ParameterNode CopyParameterNode(int parameterIndex, int nodeIndex, VFXParameterNodeController controller, int indexInClipboard)
- {
- ParameterNode n = new ParameterNode();
- n.position = controller.position;
- n.collapsed = controller.superCollapsed;
- n.expandedOutput = controller.infos.expandedSlots.Select(t => t.path).ToArray();
- n.indexInClipboard = indexInClipboard;
- if (parameterIndex < (1 << 18) && nodeIndex < (1 << 11))
- modelIndices[controller] = GetParameterNodeID((uint)parameterIndex, (uint)nodeIndex);
- else
- modelIndices[controller] = InvalidID;
- return n;
- }
- void CopyParameters(ref SerializableGraph serializableGraph)
- {
- int cpt = 0;
- serializableGraph.parameters = parameters.GroupBy(t => t.parentController, t => t, (p, c) =>
- {
- ++cpt;
- return new Parameter()
- {
- originalInstanceID = p.model.GetInstanceID(),
- name = p.model.exposedName,
- value = new VFXSerializableObject(p.model.type, p.model.value),
- exposed = p.model.exposed,
- isOutput = p.model.isOutput,
- valueFilter = p.valueFilter,
- min = p.valueFilter == VFXValueFilter.Range ? new VFXSerializableObject(p.model.type, p.model.min) : null,
- max = p.valueFilter == VFXValueFilter.Range ? new VFXSerializableObject(p.model.type, p.model.max) : null,
- enumValue = p.valueFilter == VFXValueFilter.Enum ? p.model.enumValues.ToArray() : null,
- tooltip = p.model.tooltip,
- nodes = c.Select((u, i) => CopyParameterNode(cpt - 1, i, u, parameterIndices[Array.IndexOf(parameters, u)])).ToArray()
- };
- }
- ).ToArray();
- }
- void CopyOperatorsAndContexts(ref SerializableGraph serializableGraph)
- {
- serializableGraph.contexts = new Context[contexts.Length];
- for (int i = 0; i < contexts.Length; ++i)
- {
- NodeID id = CopyContext(ref serializableGraph.contexts[i], contexts[i], i);
- modelIndices[contexts[i]] = id;
- }
- serializableGraph.operators = new Node[operators.Length];
- for (int i = 0; i < operators.Length; ++i)
- {
- uint id = CopyNode(ref serializableGraph.operators[i], operators[i].model, (NodeID)i);
- serializableGraph.operators[i].indexInClipboard = operatorIndices[i];
- modelIndices[operators[i]] = id;
- }
- }
- NodeID CopyNode(ref Node node, VFXModel model, uint index)
- {
- // Copy node infos
- node.position = model.position;
- node.type = model.GetType();
- node.flags = (model as VFXBlock)?.enabled != false ? Node.Flags.Enabled : 0;
- if (model.collapsed)
- node.flags |= Node.Flags.Collapsed;
- if (model.superCollapsed)
- node.flags |= Node.Flags.SuperCollapsed;
- uint id = 0;
- if (model is VFXOperator)
- {
- id = OperatorFlag;
- }
- else if (model is VFXContext)
- {
- id = ContextFlag;
- }
- id |= (uint)index;
- //Copy settings value
- CopyModelSettings(ref node.settings, model);
- var inputSlots = (model as IVFXSlotContainer).inputSlots;
- node.inputSlots = new Property[inputSlots.Count];
- for (int i = 0; i < inputSlots.Count; i++)
- {
- node.inputSlots[i].name = inputSlots[i].name;
- if (inputSlots[i].spaceable)
- node.inputSlots[i].space = inputSlots[i].space;
- node.inputSlots[i].value = new VFXSerializableObject(inputSlots[i].property.type, inputSlots[i].value);
- }
- node.expandedInputs = AllSlots(inputSlots).Where(t => !t.collapsed).Select(t => t.path).ToArray();
- node.expandedOutputs = AllSlots((model as IVFXSlotContainer).outputSlots).Where(t => !t.collapsed).Select(t => t.path).ToArray();
- return id;
- }
- SerializableGraph DoCopyBlocks(IEnumerable<VFXBlockController> blocks)
- {
- var newBlocks = new Node[blocks.Count()];
- uint cpt = 0;
- foreach (var block in blocks)
- {
- CopyNode(ref newBlocks[(int)cpt], block.model, cpt);
- ++cpt;
- }
- var graph = new SerializableGraph();
- graph.blocksOnly = true;
- graph.operators = newBlocks;
- return graph;
- }
- Node[] CopyBlocks(IList<VFXBlockController> blocks, int contextIndex)
- {
- var newBlocks = new Node[blocks.Count];
- for (uint i = 0; i < newBlocks.Length; ++i)
- {
- CopyNode(ref newBlocks[(int)i], blocks[(int)i].model, i);
- if (blocks[(int)i].model.enabled)
- {
- newBlocks[i].flags |= Node.Flags.Enabled;
- }
- if (contextIndex < (1 << 18) && i < (1 << 11))
- modelIndices[blocks[(int)i]] = BlockFlag | (i << 18) | (uint)contextIndex;
- else
- modelIndices[blocks[(int)i]] = InvalidID;
- }
- return newBlocks;
- }
- NodeID CopyContext(ref Context context, VFXContextController controller, int index)
- {
- NodeID id = CopyNode(ref context.node, controller.model, (NodeID)index);
- var blocks = controller.blockControllers;
- context.label = controller.model.label;
- context.systemName = VFXSystemNames.GetSystemName(controller.model);
- if (controller.model.GetData() != null)
- context.dataIndex = Array.IndexOf(datas, controller.model.GetData());
- else
- context.dataIndex = -1;
- context.blocks = CopyBlocks(controller.blockControllers, index);
- context.node.indexInClipboard = contextsIndices[index];
- if (controller.model is VFXAbstractRenderedOutput)
- context.subOutputs = CopySubOutputs(((VFXAbstractRenderedOutput)controller.model).GetSubOutputs());
- else
- context.subOutputs = null;
- return id;
- }
- SubOutput[] CopySubOutputs(List<VFXSRPSubOutput> subOutputs)
- {
- var newSubOutputs = new SubOutput[subOutputs.Count];
- for (int i = 0; i < newSubOutputs.Length; ++i)
- {
- if (subOutputs[i] != null) // Can be null if associated SRP is unknown
- {
- newSubOutputs[i].type = subOutputs[i].GetType();
- CopyModelSettings(ref newSubOutputs[i].settings, subOutputs[i]);
- }
- }
- return newSubOutputs;
- }
- static int[] MakeSlotPath(VFXSlot slot, bool input)
- {
- List<int> slotPath = new List<int>(slot.depth + 1);
- while (slot.GetParent() != null)
- {
- slotPath.Add(slot.GetParent().GetIndex(slot));
- slot = slot.GetParent();
- }
- slotPath.Add((input ? (slot.owner as IVFXSlotContainer).inputSlots : (slot.owner as IVFXSlotContainer).outputSlots).IndexOf(slot));
- return slotPath.ToArray();
- }
- }
- }
|