A game about forced loneliness, made by TACStudios
1using System;
2using System.Collections.Generic;
3#if UNITY_2020_2_OR_NEWER
4using UnityEditor.AssetImporters;
5#else
6using UnityEditor.Experimental.AssetImporters;
7#endif
8using UnityEditor.Graphing;
9using UnityEditor.ShaderGraph.Internal;
10using UnityEditor.ShaderGraph.Serialization;
11using UnityEngine;
12
13namespace UnityEditor.ShaderGraph
14{
15 [Serializable]
16 struct FunctionPair
17 {
18 public string key; // aka function name
19 public string value; // aka function code
20 public int graphPrecisionFlags; // Flags<GraphPrecision> indicating which precision variants are requested by the subgraph
21
22 public FunctionPair(string key, string value, int graphPrecisionFlags)
23 {
24 this.key = key;
25 this.value = value;
26 this.graphPrecisionFlags = graphPrecisionFlags;
27 }
28 }
29
30 [Serializable]
31 class SlotCapability
32 {
33 public string slotName;
34 public ShaderStageCapability capabilities = ShaderStageCapability.All;
35 }
36
37 [Serializable]
38 class SlotDependencyPair
39 {
40 public string inputSlotName;
41 public string outputSlotName;
42 }
43
44 /// Cached run-time information for slot dependency tracking within a sub-graph
45 class SlotDependencyInfo
46 {
47 internal string slotName;
48 internal ShaderStageCapability capabilities = ShaderStageCapability.All;
49 internal HashSet<string> dependencies = new HashSet<string>();
50
51 internal void AddDepencencySlotName(string slotName)
52 {
53 dependencies.Add(slotName);
54 }
55
56 internal bool ContainsSlot(MaterialSlot slot)
57 {
58 return dependencies.Contains(slot.RawDisplayName());
59 }
60 }
61
62 class SubGraphData : JsonObject
63 {
64 public List<JsonData<AbstractShaderProperty>> inputs = new List<JsonData<AbstractShaderProperty>>();
65 public List<JsonData<ShaderKeyword>> keywords = new List<JsonData<ShaderKeyword>>();
66 public List<JsonData<ShaderDropdown>> dropdowns = new List<JsonData<ShaderDropdown>>();
67 public List<JsonData<AbstractShaderProperty>> nodeProperties = new List<JsonData<AbstractShaderProperty>>();
68 public List<JsonData<MaterialSlot>> outputs = new List<JsonData<MaterialSlot>>();
69 public List<JsonData<Target>> unsupportedTargets = new List<JsonData<Target>>();
70 }
71
72 class SubGraphAsset : ScriptableObject, ISerializationCallbackReceiver
73 {
74 public bool isValid;
75
76 public long processedAt;
77
78 public string functionName;
79
80 public string inputStructName;
81
82 public string hlslName;
83
84 public string assetGuid;
85
86 public ShaderGraphRequirements requirements;
87
88 public string path;
89
90 public List<FunctionPair> functions = new List<FunctionPair>();
91
92 public IncludeCollection includes;
93
94 public List<string> vtFeedbackVariables = new List<string>();
95
96 private SubGraphData m_SubGraphData;
97
98 [HideInInspector]
99 [SerializeField]
100 private SerializationHelper.JSONSerializedElement m_SerializedSubGraphData;
101
102 public DataValueEnumerable<AbstractShaderProperty> inputs => m_SubGraphData.inputs.SelectValue();
103
104 public DataValueEnumerable<ShaderKeyword> keywords => m_SubGraphData.keywords.SelectValue();
105
106 public DataValueEnumerable<ShaderDropdown> dropdowns => m_SubGraphData.dropdowns.SelectValue();
107
108 public DataValueEnumerable<AbstractShaderProperty> nodeProperties => m_SubGraphData.nodeProperties.SelectValue();
109
110 public DataValueEnumerable<MaterialSlot> outputs => m_SubGraphData.outputs.SelectValue();
111
112 public DataValueEnumerable<Target> unsupportedTargets => m_SubGraphData.unsupportedTargets.SelectValue();
113
114 public List<string> children = new List<string>(); // guids of direct USED SUBGRAPH file dependencies
115
116 public List<string> descendents = new List<string>(); // guids of ALL file dependencies at any level, SHOULD LIST EVEN MISSING DESCENDENTS
117
118 public List<SlotCapability> inputCapabilities = new List<SlotCapability>();
119 public List<SlotCapability> outputCapabilities = new List<SlotCapability>();
120 // Every unique input/output dependency pair
121 public List<SlotDependencyPair> slotDependencies = new List<SlotDependencyPair>();
122
123 Dictionary<string, SlotDependencyInfo> m_InputDependencies = new Dictionary<string, SlotDependencyInfo>();
124 Dictionary<string, SlotDependencyInfo> m_OutputDependencies = new Dictionary<string, SlotDependencyInfo>();
125
126
127 public SlotDependencyInfo GetInputDependencies(string slotName)
128 {
129 m_InputDependencies.TryGetValue(slotName, out SlotDependencyInfo result);
130 return result;
131 }
132
133 public SlotDependencyInfo GetOutputDependencies(string slotName)
134 {
135 m_OutputDependencies.TryGetValue(slotName, out SlotDependencyInfo result);
136 return result;
137 }
138
139 // this is the precision that the entire subgraph is set to (indicates whether the graph is hard-coded or switchable)
140 public GraphPrecision subGraphGraphPrecision;
141
142 // this is the precision of the subgraph outputs
143 // NOTE: this may not be the same as subGraphGraphPrecision
144 // for example, a graph could allow switching precisions for internal calculations,
145 // but the output of the graph is always full float
146 // NOTE: we don't currently have a way to select the graph precision for EACH output
147 // there's a single shared precision for all of them
148 public GraphPrecision outputGraphPrecision;
149
150 public PreviewMode previewMode;
151
152 public void WriteData(IEnumerable<AbstractShaderProperty> inputs, IEnumerable<ShaderKeyword> keywords, IEnumerable<ShaderDropdown> dropdowns, IEnumerable<AbstractShaderProperty> nodeProperties, IEnumerable<MaterialSlot> outputs, IEnumerable<Target> unsupportedTargets)
153 {
154 if (m_SubGraphData == null)
155 {
156 m_SubGraphData = new SubGraphData();
157 m_SubGraphData.OverrideObjectId(assetGuid, "_subGraphData");
158 }
159
160 m_SubGraphData.inputs.Clear();
161 m_SubGraphData.keywords.Clear();
162 m_SubGraphData.dropdowns.Clear();
163 m_SubGraphData.nodeProperties.Clear();
164 m_SubGraphData.outputs.Clear();
165 m_SubGraphData.unsupportedTargets.Clear();
166
167 foreach (var input in inputs)
168 {
169 m_SubGraphData.inputs.Add(input);
170 }
171
172 foreach (var keyword in keywords)
173 {
174 m_SubGraphData.keywords.Add(keyword);
175 }
176
177 foreach (var dropdown in dropdowns)
178 {
179 m_SubGraphData.dropdowns.Add(dropdown);
180 }
181
182 foreach (var nodeProperty in nodeProperties)
183 {
184 m_SubGraphData.nodeProperties.Add(nodeProperty);
185 }
186
187 foreach (var output in outputs)
188 {
189 m_SubGraphData.outputs.Add(output);
190 }
191
192 foreach (var unsupportedTarget in unsupportedTargets)
193 {
194 m_SubGraphData.unsupportedTargets.Add(unsupportedTarget);
195 }
196 var json = MultiJson.Serialize(m_SubGraphData);
197 m_SerializedSubGraphData = new SerializationHelper.JSONSerializedElement() { JSONnodeData = json };
198 m_SubGraphData = null;
199 }
200
201 public void OnBeforeSerialize()
202 {
203 }
204
205 public void OnAfterDeserialize()
206 {
207 }
208
209 public void LoadGraphData()
210 {
211 m_SubGraphData = new SubGraphData();
212 if (!String.IsNullOrEmpty(m_SerializedSubGraphData.JSONnodeData))
213 {
214 MultiJson.Deserialize(m_SubGraphData, m_SerializedSubGraphData.JSONnodeData);
215 }
216 }
217
218 internal void LoadDependencyData()
219 {
220 m_InputDependencies.Clear();
221 m_OutputDependencies.Clear();
222
223 foreach (var capabilityInfo in inputCapabilities)
224 {
225 var dependencyInfo = new SlotDependencyInfo();
226 dependencyInfo.slotName = capabilityInfo.slotName;
227 dependencyInfo.capabilities = capabilityInfo.capabilities;
228 if (m_InputDependencies.ContainsKey(dependencyInfo.slotName))
229 {
230 Debug.LogWarning($"SubGraph '{hlslName}' has multiple input slots named '{dependencyInfo.slotName}', which is unsupported. Please assign the input slots unique names.");
231 continue;
232 }
233 m_InputDependencies.Add(dependencyInfo.slotName, dependencyInfo);
234 }
235 foreach (var capabilityInfo in outputCapabilities)
236 {
237 var dependencyInfo = new SlotDependencyInfo();
238 dependencyInfo.slotName = capabilityInfo.slotName;
239 dependencyInfo.capabilities = capabilityInfo.capabilities;
240 if (m_OutputDependencies.ContainsKey(dependencyInfo.slotName))
241 {
242 Debug.LogWarning($"SubGraph '{hlslName}' has multiple output slots named '{dependencyInfo.slotName}', which is unsupported. Please assign the output slots unique names.");
243 continue;
244 }
245 m_OutputDependencies.Add(dependencyInfo.slotName, dependencyInfo);
246 }
247 foreach (var slotDependency in slotDependencies)
248 {
249 // This shouldn't fail since every input/output must be in the above lists...
250 if (m_InputDependencies.ContainsKey(slotDependency.inputSlotName))
251 m_InputDependencies[slotDependency.inputSlotName].AddDepencencySlotName(slotDependency.outputSlotName);
252 if (m_OutputDependencies.ContainsKey(slotDependency.outputSlotName))
253 m_OutputDependencies[slotDependency.outputSlotName].AddDepencencySlotName(slotDependency.inputSlotName);
254 }
255 }
256 }
257}