A game about forced loneliness, made by TACStudios
1using System; 2using System.Collections.Generic; 3using System.Linq; 4using UnityEngine; 5using UnityEngine.UIElements; 6using UnityEditor.Experimental.GraphView; 7using UnityEditor.ShaderGraph.Drawing; 8using UnityEditor.ShaderGraph.Serialization; 9 10namespace UnityEditor.ShaderGraph 11{ 12 sealed class ContextView : StackNode, IDisposable 13 { 14 ContextData m_ContextData; 15 16 // Currently we only need one Port per context 17 // As the Contexts are hardcoded we know their directions 18 Port m_Port; 19 20 //need this from graph view specifically for nodecreation 21 EditorWindow m_EditorWindow; 22 23 // When dealing with more Contexts, `name` should be serialized in the ContextData 24 // Right now we dont do this so we dont overcommit to serializing unknowns 25 public ContextView(string name, ContextData contextData, EditorWindow editorWindow) 26 { 27 // Set data 28 m_ContextData = contextData; 29 m_EditorWindow = editorWindow; 30 31 // Header 32 var headerLabel = new Label() { name = "headerLabel" }; 33 headerLabel.text = name; 34 headerContainer.Add(headerLabel); 35 } 36 37 public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) 38 { 39 // Disable the context menu for block nodes. This prevents a duplicate "disconnect all" 40 // option from getting registered which grays out stack block node's option. 41 if (evt.target is MaterialNodeView) return; 42 43 // If the user didn't click on a block node (i.e. the stack frame), include the "Add Block Node" item. 44 InsertCreateNodeAction(evt, childCount, 0); 45 evt.menu.InsertSeparator(null, 1); 46 } 47 48 public ContextData contextData => m_ContextData; 49 public Port port => m_Port; 50 51 // We need to use graphViewChange.movedElements to check whether a BlockNode has moved onto the GraphView 52 // but Nodes return in movedElements when they are mid-drag because they are removed from the stack (placeholder) 53 // StackNode has `dragEntered` but its protected so we need `isDragging` 54 public bool isDragging => dragEntered; 55 56 public void AddPort(Direction direction) 57 { 58 var capacity = direction == Direction.Input ? Port.Capacity.Single : Port.Capacity.Multi; 59 var container = direction == Direction.Input ? inputContainer : outputContainer; 60 m_Port = Port.Create<Edge>(Orientation.Vertical, direction, capacity, null); 61 m_Port.portName = ""; 62 63 // Vertical ports have no representation in Model 64 // Therefore we need to disable interaction 65 m_Port.pickingMode = PickingMode.Ignore; 66 67 container.Add(m_Port); 68 } 69 70 public void InsertBlock(MaterialNodeView nodeView) 71 { 72 if (!(nodeView.userData is BlockNode blockNode)) 73 return; 74 75 // If index is -1 the node is being added to the end of the Stack 76 if (blockNode.index == -1) 77 { 78 AddElement(nodeView); 79 return; 80 } 81 82 // Add or Insert based on index 83 if (blockNode.index >= contentContainer.childCount) 84 { 85 AddElement(nodeView); 86 } 87 else 88 { 89 InsertElement(blockNode.index, nodeView); 90 } 91 } 92 93 public void InsertElements(int insertIndex, IEnumerable<GraphElement> elements) 94 { 95 var blockDatas = elements.Select(x => x.userData as BlockNode).ToArray(); 96 for (int i = 0; i < blockDatas.Length; i++) 97 { 98 contextData.blocks.Remove(blockDatas[i]); 99 } 100 101 int count = elements.Count(); 102 var refs = new JsonRef<BlockNode>[count]; 103 for (int i = 0; i < count; i++) 104 { 105 refs[i] = blockDatas[i]; 106 } 107 108 contextData.blocks.InsertRange(insertIndex, refs); 109 110 var window = m_EditorWindow as MaterialGraphEditWindow; 111 window?.graphEditorView?.graphView?.graph?.ValidateCustomBlockLimit(); 112 } 113 114 protected override bool AcceptsElement(GraphElement element, ref int proposedIndex, int maxIndex) 115 { 116 return element.userData is BlockNode blockNode && blockNode.descriptor != null && 117 blockNode.descriptor.shaderStage == contextData.shaderStage; 118 } 119 120 protected override void OnSeparatorContextualMenuEvent(ContextualMenuPopulateEvent evt, int separatorIndex) 121 { 122 base.OnSeparatorContextualMenuEvent(evt, separatorIndex); 123 InsertCreateNodeAction(evt, separatorIndex, 0); 124 } 125 126 void InsertCreateNodeAction(ContextualMenuPopulateEvent evt, int separatorIndex, int itemIndex) 127 { 128 //we need to arbitrarily add the editor position values because node creation context 129 //exptects a non local coordinate 130 var mousePosition = evt.mousePosition + m_EditorWindow.position.position; 131 var graphView = GetFirstAncestorOfType<MaterialGraphView>(); 132 133 evt.menu.InsertAction(itemIndex, "Add Block Node", (e) => 134 { 135 var context = new NodeCreationContext 136 { 137 screenMousePosition = mousePosition, 138 target = this, 139 index = separatorIndex, 140 }; 141 graphView.nodeCreationRequest(context); 142 }); 143 } 144 145 public void Dispose() 146 { 147 m_Port = null; 148 m_ContextData = null; 149 m_EditorWindow = null; 150 inputContainer.Clear(); 151 outputContainer.Clear(); 152 } 153 } 154}