VFXContextEditor.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287
  1. using System;
  2. using System.Linq;
  3. using System.Collections;
  4. using System.Collections.Generic;
  5. using UnityEditor;
  6. using UnityEditor.Experimental;
  7. using UnityEditor.VFX;
  8. using UnityEditor.SceneManagement;
  9. using UnityEngine;
  10. using UnityEngine.VFX;
  11. using UnityEditor.VFX.UI;
  12. using Object = UnityEngine.Object;
  13. using UnityEditorInternal;
  14. using System.Reflection;
  15. [CustomEditor(typeof(VFXContext), true)]
  16. [CanEditMultipleObjects]
  17. class VFXContextEditor : VFXSlotContainerEditor
  18. {
  19. SerializedProperty spaceProperty;
  20. SerializedObject dataObject;
  21. SerializedObject srpSubOutputObject;
  22. private bool subOutputObjectInitialized = false;
  23. float m_Width;
  24. protected new void OnEnable()
  25. {
  26. UnityEngine.Object[] allData = targets.Cast<VFXContext>().Select(t => t.GetData()).Distinct().Where(t => t != null).Cast<UnityEngine.Object>().ToArray();
  27. if (allData.Length > 0)
  28. {
  29. dataObject = new SerializedObject(allData);
  30. spaceProperty = dataObject.FindProperty("m_Space");
  31. }
  32. else
  33. {
  34. dataObject = null;
  35. spaceProperty = null;
  36. }
  37. subOutputObjectInitialized = false;
  38. base.OnEnable();
  39. }
  40. protected override SerializedProperty FindProperty(VFXSetting setting)
  41. {
  42. if (setting.instance is VFXContext)
  43. return serializedObject.FindProperty(setting.name);
  44. if (setting.instance is VFXSRPSubOutput)
  45. return srpSubOutputObject.FindProperty(setting.name);
  46. if (setting.instance is VFXData)
  47. return dataObject.FindProperty(setting.name);
  48. throw new ArgumentException("VFXSetting is from an unexpected instance: " + setting.instance);
  49. }
  50. protected void DisplaySpace()
  51. {
  52. if (spaceProperty != null)
  53. EditorGUILayout.PropertyField(spaceProperty);
  54. }
  55. public override SerializedProperty DoInspectorGUI()
  56. {
  57. if (!subOutputObjectInitialized)
  58. {
  59. UnityEngine.Object[] allSRPSubOutputs = targets.OfType<VFXAbstractRenderedOutput>().Select(t => t.subOutput).Where(t => t != null).ToArray();
  60. srpSubOutputObject = allSRPSubOutputs.Length > 0 ? new SerializedObject(allSRPSubOutputs) : null;
  61. subOutputObjectInitialized = true;
  62. }
  63. DisplaySpace();
  64. return base.DoInspectorGUI();
  65. }
  66. void DoAttributeLayoutGUI(string label, StructureOfArrayProvider.BucketInfo[] layout)
  67. {
  68. GUILayout.Label(label, Styles.header);
  69. // Used to distribute width evenly for each cell, induces a one-frame latency
  70. var w = GUILayoutUtility.GetLastRect().width;
  71. if (Event.current.type != EventType.Layout && w > 0)
  72. m_Width = w - 48;
  73. int maxSize = 0;
  74. foreach (StructureOfArrayProvider.BucketInfo bucket in layout)
  75. maxSize = Math.Max(maxSize, bucket.size);
  76. DrawAttributeLayoutGrid(layout, maxSize);
  77. }
  78. void DrawAttributeLayoutGrid(StructureOfArrayProvider.BucketInfo[] layout, int maxSize)
  79. {
  80. int i = 0;
  81. float height = 16.0f;
  82. Rect r = GUILayoutUtility.GetRect(m_Width, layout.Length * height);
  83. foreach (var bucket in layout)
  84. {
  85. float x = r.x;
  86. float y = r.y + i * height;
  87. float cellwidth = (m_Width - 16) / maxSize;
  88. Rect cellRect = new Rect(x, y, 16, height);
  89. GUI.Label(cellRect, i.ToString(), Styles.cell);
  90. int bucketSize = bucket.size;
  91. int usedSize = bucket.usedSize;
  92. x += 16;
  93. for (int j = 0; j < maxSize; j++)
  94. {
  95. cellRect = new Rect(x, y, cellwidth, height);
  96. if (j < usedSize)
  97. {
  98. var attrib = bucket.attributes[j];
  99. if (attrib.name != null)
  100. Styles.DataTypeLabel(cellRect, attrib.name, attrib.type, Styles.cell);
  101. else
  102. Styles.DataTypeLabel(cellRect, "", VFXValueType.None, Styles.cell);
  103. }
  104. else
  105. {
  106. if (j < bucketSize)
  107. Styles.DataTypeLabel(cellRect, "", VFXValueType.None, Styles.cell);
  108. else
  109. GUI.Label(cellRect, "");
  110. }
  111. x += cellwidth;
  112. }
  113. i++;
  114. }
  115. }
  116. protected void DisplaySummary()
  117. {
  118. if (serializedObject.isEditingMultipleObjects) return; // Summary Only visible for single selection
  119. // Context / SystemData
  120. if (dataObject == null) return;
  121. var context = (VFXContext)target;
  122. var data = (VFXData)dataObject.targetObject;
  123. // Particle context data
  124. if (data.type == VFXDataType.Particle)
  125. {
  126. VFXDataParticle particleData = data as VFXDataParticle;
  127. EditorGUILayout.Space();
  128. {
  129. Styles.Row(Styles.header, "Name", "Value");
  130. Styles.Row(Styles.cell, "Capacity", particleData.GetSettingValue("capacity").ToString());
  131. EditorGUILayout.Space();
  132. var attributes = data.GetAttributes();
  133. if (attributes.Count() > 0)
  134. {
  135. EditorGUILayout.LabelField("System Attribute Summary", Styles.header);
  136. foreach (var attr in attributes)
  137. {
  138. using (new EditorGUILayout.HorizontalScope())
  139. {
  140. GUILayout.Label(attr.attrib.name, Styles.cell);
  141. Styles.DataTypeLabel(attr.attrib.type.ToString(), attr.attrib.type, Styles.cell, GUILayout.Width(64));
  142. int size = VFXExpressionHelper.GetSizeOfType(attr.attrib.type) * 4;
  143. GUILayout.Label(size + " byte" + (size > 1 ? "s" : ""), Styles.cell, GUILayout.Width(64));
  144. var mode = attr.mode;
  145. GUILayout.Label(mode.ToString(), Styles.cell, GUILayout.Width(72));
  146. }
  147. }
  148. }
  149. StructureOfArrayProvider.BucketInfo[] current = particleData.GetCurrentAttributeLayout();
  150. StructureOfArrayProvider.BucketInfo[] source = particleData.GetSourceAttributeLayout();
  151. if (current.Length > 0)
  152. {
  153. GUILayout.Space(24);
  154. DoAttributeLayoutGUI("Current Attribute Layout", current);
  155. }
  156. if (source.Length > 0)
  157. {
  158. GUILayout.Space(12);
  159. DoAttributeLayoutGUI("Source Attribute Layout", source);
  160. }
  161. }
  162. }
  163. if (VFXViewPreference.displayExtraDebugInfo)
  164. {
  165. // Extra debug data
  166. EditorGUILayout.Space();
  167. {
  168. Styles.Row(Styles.header, "Name", "Value");
  169. Styles.Row(Styles.cell, "Context Type", context.contextType.ToString());
  170. Styles.Row(Styles.cell, "Task Type", context.taskType.ToString());
  171. Styles.Row(Styles.cell, "Input Data Type", context.inputType.ToString());
  172. Styles.Row(Styles.cell, "Context Data Type", data.type.ToString());
  173. Styles.Row(Styles.cell, "Can Be Compiled", context.CanBeCompiled().ToString());
  174. EditorGUILayout.Space();
  175. var attributeInfos = data.GetAttributesForContext(context);
  176. VFXAttributeInfo[] infos;
  177. // Early check for context consistency
  178. try
  179. {
  180. infos = attributeInfos.ToArray();
  181. }
  182. catch
  183. {
  184. return;
  185. }
  186. EditorGUILayout.LabelField("Attributes used by Context", Styles.header);
  187. foreach (var info in infos)
  188. {
  189. using (new EditorGUILayout.HorizontalScope())
  190. {
  191. GUILayout.Label(info.attrib.name, Styles.cell);
  192. Styles.DataTypeLabel(info.attrib.type.ToString(), info.attrib.type, Styles.cell, GUILayout.Width(80));
  193. Styles.AttributeModeLabel(info.mode.ToString(), info.mode, Styles.cell, GUILayout.Width(80));
  194. }
  195. }
  196. EditorGUILayout.Space();
  197. Styles.Row(Styles.header, "Blocks");
  198. foreach (var block in context.activeChildrenWithImplicit)
  199. Styles.Row(Styles.cell, block.name, !context.children.Contains(block) ? "implicit" : "");
  200. EditorGUILayout.Space();
  201. }
  202. }
  203. }
  204. protected void DisplayName()
  205. {
  206. if (!serializedObject.isEditingMultipleObjects)
  207. {
  208. VFXContext model = (VFXContext)target;
  209. if (model != null && model.letter != '\0') //TODO: Is it still relevant ?
  210. {
  211. GUILayout.Label(model.letter.ToString(), Styles.letter);
  212. }
  213. }
  214. }
  215. public virtual void DisplayWarnings()
  216. {
  217. }
  218. public override void OnInspectorGUI()
  219. {
  220. if (dataObject != null)
  221. dataObject.Update();
  222. if (srpSubOutputObject != null)
  223. srpSubOutputObject.Update();
  224. DisplayName();
  225. base.OnInspectorGUI();
  226. bool invalidateContext = (dataObject != null && dataObject.ApplyModifiedProperties()) || (srpSubOutputObject != null && srpSubOutputObject.ApplyModifiedProperties());
  227. if (invalidateContext)
  228. {
  229. foreach (VFXContext ctx in targets.OfType<VFXContext>())
  230. {
  231. // notify that something changed.
  232. ctx.GetData().Invalidate(VFXModel.InvalidationCause.kSettingChanged); // This will also invalidate contexts
  233. }
  234. }
  235. DisplayWarnings();
  236. DisplaySummary();
  237. }
  238. }