VFXEventTesterWindow.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. using UnityEngine;
  2. using UnityEditor.Overlays;
  3. using UnityEngine.VFX;
  4. using UnityEditorInternal;
  5. using System.Collections.Generic;
  6. using System.Linq;
  7. namespace UnityEditor.VFX
  8. {
  9. static class VFXEventTesterWindow
  10. {
  11. [Overlay(typeof(SceneView), k_OverlayId, k_DisplayName)]
  12. class SceneViewVFXEventTesterOverlay : IMGUIOverlay, ITransientOverlay
  13. {
  14. const string k_OverlayId = "Scene View/Visual Effect Event Tester";
  15. const string k_DisplayName = "Visual Effect Event Tester";
  16. public SceneViewVFXEventTesterOverlay()
  17. {
  18. Selection.selectionChanged += OnSelectionChanged;
  19. }
  20. public bool visible => m_Effects?.Length > 0 && VFXEventTesterWindow.visible;
  21. public override void OnGUI()
  22. {
  23. if (visible)
  24. WindowGUI();
  25. }
  26. public override void OnWillBeDestroyed()
  27. {
  28. base.OnWillBeDestroyed();
  29. Selection.selectionChanged -= OnSelectionChanged;
  30. }
  31. private void OnSelectionChanged()
  32. {
  33. m_Effects = Selection.gameObjects
  34. .Select(x => x.GetComponent<VisualEffect>())
  35. .Where(x => x != null)
  36. .ToArray();
  37. }
  38. }
  39. public static bool visible { get { return s_Visible; } set { SetVisibility(value); } }
  40. static bool s_Visible;
  41. [SerializeField]
  42. static string m_CustomEvent = "CustomEvent";
  43. [SerializeField]
  44. static List<EventAttribute> m_Attributes;
  45. static VisualEffect[] m_Effects;
  46. static ReorderableList list;
  47. static readonly string PreferenceName = "VFXEventTester.Visible";
  48. static VFXEventTesterWindow()
  49. {
  50. m_Attributes = new List<EventAttribute>();
  51. s_Visible = EditorPrefs.GetBool(PreferenceName, false);
  52. list = new ReorderableList(m_Attributes, typeof(EventAttribute), true, true, true, true);
  53. list.drawHeaderCallback = drawHeader;
  54. list.drawElementCallback = drawItem;
  55. list.onAddDropdownCallback = drawAddDropDown;
  56. }
  57. static void SetVisibility(bool visible)
  58. {
  59. if (visible != s_Visible)
  60. {
  61. s_Visible = visible;
  62. EditorPrefs.SetBool(PreferenceName, visible);
  63. }
  64. }
  65. private static void drawAddDropDown(Rect buttonRect, ReorderableList list)
  66. {
  67. GenericMenu menu = new GenericMenu();
  68. // Add Generic Attributes
  69. menu.AddItem(new GUIContent("Standard/Position"), false, AddVector3, "position");
  70. menu.AddItem(new GUIContent("Standard/Velocity"), false, AddVector3, "velocity");
  71. menu.AddItem(new GUIContent("Standard/Size"), false, AddFloat, "size");
  72. menu.AddItem(new GUIContent("Standard/Mass"), false, AddFloat, "mass");
  73. menu.AddItem(new GUIContent("Standard/Color"), false, AddColor, "color");
  74. menu.AddItem(new GUIContent("Standard/Alpha"), false, AddFloat, "alpha");
  75. menu.AddItem(new GUIContent("Standard/Age"), false, AddFloat, "age");
  76. menu.AddItem(new GUIContent("Standard/Lifetime"), false, AddFloat, "lifetime");
  77. menu.AddItem(new GUIContent("Standard/Alive"), false, AddBool, "alive");
  78. menu.AddItem(new GUIContent("Standard/Scale.X"), false, AddFloat, "scaleX");
  79. menu.AddItem(new GUIContent("Standard/Scale.Y"), false, AddFloat, "scaleY");
  80. menu.AddItem(new GUIContent("Standard/Scale.Z"), false, AddFloat, "scaleZ");
  81. menu.AddItem(new GUIContent("Standard/Angle.X"), false, AddFloat, "angleX");
  82. menu.AddItem(new GUIContent("Standard/Angle.Y"), false, AddFloat, "angleY");
  83. menu.AddItem(new GUIContent("Standard/Angle.Z"), false, AddFloat, "angleZ");
  84. // Add Advanced Attributes
  85. menu.AddItem(new GUIContent("Advanced/OldPosition"), false, AddVector3, "oldPosition");
  86. menu.AddItem(new GUIContent("Advanced/TargetPosition"), false, AddVector3, "targetPosition");
  87. menu.AddItem(new GUIContent("Advanced/Direction"), false, AddVector3, "direction");
  88. menu.AddItem(new GUIContent("Advanced/AngularVelocity.X"), false, AddFloat, "angularVelocityX");
  89. menu.AddItem(new GUIContent("Advanced/AngularVelocity.Y"), false, AddFloat, "angularVelocityY");
  90. menu.AddItem(new GUIContent("Advanced/AngularVelocity.Z"), false, AddFloat, "angularVelocityZ");
  91. // Add Generic Attributes
  92. menu.AddItem(new GUIContent("Custom/Custom bool"), false, AddBool, "customBool");
  93. menu.AddItem(new GUIContent("Custom/Custom Float"), false, AddFloat, "customFloat");
  94. menu.AddItem(new GUIContent("Custom/Custom Vector2"), false, AddVector2, "customVector2");
  95. menu.AddItem(new GUIContent("Custom/Custom Vector3"), false, AddVector3, "customVector3");
  96. menu.AddItem(new GUIContent("Custom/Custom Color"), false, AddColor, "customColor");
  97. // Add Custom Types
  98. menu.ShowAsContext();
  99. }
  100. static void AddFloat(object name)
  101. {
  102. m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Float, 0.0f));
  103. }
  104. static void AddBool(object name)
  105. {
  106. m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Bool, true));
  107. }
  108. static void AddVector2(object name)
  109. {
  110. m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Vector2, Vector2.zero));
  111. }
  112. static void AddVector3(object name)
  113. {
  114. m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Vector3, Vector3.zero));
  115. }
  116. static void AddColor(object name)
  117. {
  118. m_Attributes.Add(new EventAttribute(name as string, EventAttributeType.Color, Color.white));
  119. }
  120. [System.Serializable]
  121. enum EventAttributeType
  122. {
  123. Float = 0,
  124. Vector2 = 1,
  125. Vector3 = 2,
  126. Color = 3,
  127. Bool = 4
  128. }
  129. [System.Serializable]
  130. class EventAttribute
  131. {
  132. public string name;
  133. public EventAttributeType type;
  134. public object value;
  135. public EventAttribute()
  136. {
  137. name = "Attribute";
  138. type = EventAttributeType.Float;
  139. value = 0.0f;
  140. }
  141. public EventAttribute(string name, EventAttributeType type, object value)
  142. {
  143. this.name = name;
  144. this.type = type;
  145. this.value = value;
  146. }
  147. }
  148. private static void drawHeader(Rect rect)
  149. {
  150. GUI.Label(rect, "Event Attributes");
  151. }
  152. static void drawItem(Rect rect, int index, bool isActive, bool isFocused)
  153. {
  154. if (m_Attributes[index] == null)
  155. {
  156. var color = GUI.color;
  157. GUI.color = Color.red;
  158. EditorGUI.LabelField(rect, "NULL OR DELETED");
  159. GUI.color = color;
  160. return;
  161. }
  162. rect.yMin += 2;
  163. rect.height = 16;
  164. var namerect = rect;
  165. namerect.width = 100;
  166. m_Attributes[index].name = GUI.TextField(namerect, m_Attributes[index].name);
  167. var typerect = rect;
  168. typerect.xMin = rect.xMin + 108;
  169. typerect.width = 76;
  170. m_Attributes[index].type = (EventAttributeType)EditorGUI.EnumPopup(typerect, m_Attributes[index].type);
  171. var valueRect = rect;
  172. valueRect.xMin = rect.xMin + 192;
  173. switch (m_Attributes[index].type)
  174. {
  175. case EventAttributeType.Bool:
  176. if (m_Attributes[index].value == null || !(m_Attributes[index].value is bool))
  177. m_Attributes[index].value = true;
  178. m_Attributes[index].value = (bool)EditorGUI.Toggle(valueRect, (bool)m_Attributes[index].value);
  179. break;
  180. case EventAttributeType.Float:
  181. if (m_Attributes[index].value == null || !(m_Attributes[index].value is float))
  182. m_Attributes[index].value = 1.0f;
  183. m_Attributes[index].value = (float)EditorGUI.FloatField(valueRect, (float)m_Attributes[index].value);
  184. break;
  185. case EventAttributeType.Vector2:
  186. if (m_Attributes[index].value == null || !(m_Attributes[index].value is Vector2))
  187. m_Attributes[index].value = Vector2.zero;
  188. m_Attributes[index].value = (Vector2)EditorGUI.Vector2Field(valueRect, "", (Vector2)m_Attributes[index].value);
  189. break;
  190. case EventAttributeType.Vector3:
  191. if (m_Attributes[index].value == null || !(m_Attributes[index].value is Vector3))
  192. m_Attributes[index].value = Vector3.zero;
  193. m_Attributes[index].value = (Vector3)EditorGUI.Vector3Field(valueRect, "", (Vector3)m_Attributes[index].value);
  194. break;
  195. case EventAttributeType.Color:
  196. if (m_Attributes[index].value == null || !(m_Attributes[index].value is Color))
  197. m_Attributes[index].value = Color.white;
  198. m_Attributes[index].value = (Color)EditorGUI.ColorField(valueRect, (Color)m_Attributes[index].value);
  199. // The is a hotControl id hash collision with the selection rectangle that cause of a lost of selection on mouseup.
  200. if (Event.current.type == EventType.MouseUp && valueRect.Contains(Event.current.mousePosition))
  201. GUIUtility.hotControl = 0;
  202. break;
  203. }
  204. }
  205. static void WindowGUI()
  206. {
  207. EditorGUI.BeginDisabled((m_Effects?.Length).GetValueOrDefault(0) == 0);
  208. EditorGUILayout.Space();
  209. list.DoLayoutList();
  210. EditorGUILayout.Space();
  211. using (new GUILayout.HorizontalScope(GUILayout.Width(358)))
  212. {
  213. if (GUILayout.Button("Play", Styles.leftButton, GUILayout.Height(24)))
  214. {
  215. SendEvent("OnPlay");
  216. }
  217. if (GUILayout.Button("Stop", Styles.middleButton, GUILayout.Height(24)))
  218. {
  219. SendEvent("OnStop");
  220. }
  221. if (GUILayout.Button("Custom", Styles.rightButton, GUILayout.Height(24)))
  222. {
  223. SendEvent(m_CustomEvent);
  224. }
  225. }
  226. m_CustomEvent = EditorGUILayout.TextField("Custom Event", m_CustomEvent);
  227. EditorGUI.EndDisabled();
  228. }
  229. static void SendEvent(string name)
  230. {
  231. if ((m_Effects?.Length).GetValueOrDefault(0) == 0) return;
  232. foreach (var visualEffect in m_Effects)
  233. {
  234. var attrib = visualEffect.CreateVFXEventAttribute();
  235. if (attrib == null) return;
  236. // set all attributes
  237. foreach (var attribute in m_Attributes)
  238. {
  239. if (attribute == null) continue;
  240. switch (attribute.type)
  241. {
  242. case EventAttributeType.Bool: attrib.SetBool(attribute.name, (bool)attribute.value); break;
  243. case EventAttributeType.Float: attrib.SetFloat(attribute.name, (float)attribute.value); break;
  244. case EventAttributeType.Vector2: attrib.SetVector2(attribute.name, (Vector2)attribute.value); break;
  245. case EventAttributeType.Vector3: attrib.SetVector3(attribute.name, (Vector3)attribute.value); break;
  246. case EventAttributeType.Color: attrib.SetVector4(attribute.name, (Color)attribute.value); break;
  247. }
  248. }
  249. // then send event with attributes
  250. if (name == VisualEffectAsset.PlayEventName)
  251. visualEffect.Play(attrib);
  252. else if (name == VisualEffectAsset.StopEventName)
  253. visualEffect.Stop(attrib);
  254. else
  255. visualEffect.SendEvent(name, attrib);
  256. }
  257. }
  258. static class Contents
  259. {
  260. public static readonly GUIContent title = new GUIContent("VFX Event Tester");
  261. }
  262. static class Styles
  263. {
  264. public static GUIStyle leftButton;
  265. public static GUIStyle middleButton;
  266. public static GUIStyle rightButton;
  267. static Styles()
  268. {
  269. leftButton = new GUIStyle(EditorStyles.miniButtonLeft);
  270. middleButton = new GUIStyle(EditorStyles.miniButtonMid);
  271. rightButton = new GUIStyle(EditorStyles.miniButtonRight);
  272. leftButton.fontSize = 12;
  273. middleButton.fontSize = 12;
  274. rightButton.fontSize = 12;
  275. }
  276. }
  277. }
  278. }