暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

UsageDial.cs 9.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284
  1. using System;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using Unity.Collections;
  5. using Unity.Collections.LowLevel.Unsafe;
  6. using UnityEngine;
  7. using UnityEngine.UIElements;
  8. namespace UnityEditor.AdaptivePerformance.UI.Editor
  9. {
  10. /// <summary>
  11. /// Usage Dial is a VisualElement to display a values with a color dial.
  12. /// </summary>
  13. public class UsageDial : VisualElement
  14. {
  15. Texture2D m_BaseTexture;
  16. Texture2D m_Texture;
  17. /// <summary>
  18. /// A value the usage dial should represent.
  19. /// </summary>
  20. public int Value
  21. {
  22. get { return m_Value; }
  23. set
  24. {
  25. SetValue(value);
  26. }
  27. }
  28. /// <summary>
  29. /// If the usage dial should show the percentage label.
  30. /// </summary>
  31. public bool ShowLabel
  32. {
  33. get { return m_showLabel; }
  34. set { m_showLabel = value; }
  35. }
  36. int m_Value = 55;
  37. byte m_ValueCutoff = 0;
  38. int m_ThresholdYellowPercentage = 50;
  39. int m_ThresholdRedPercentage = 75;
  40. byte m_ThresholdYellow = 0;
  41. byte m_ThresholdRed = 0;
  42. static readonly Color32 k_Green = new Color32(136, 176, 49, byte.MaxValue);
  43. static readonly Color32 k_Yellow = new Color32(221, 124, 69, byte.MaxValue);
  44. static readonly Color32 k_Red = new Color32(219, 89, 81, byte.MaxValue);
  45. VisualElement m_Indicator;
  46. VisualElement m_IndicatorRoot;
  47. Label m_Label;
  48. bool m_showLabel;
  49. static readonly ushort[] k_Indices = new ushort[]
  50. {
  51. 0, 1, 2,
  52. 1, 3, 2,
  53. };
  54. /// <summary>
  55. /// Constructor, setups the usage dial with its correct percentages.
  56. /// </summary>
  57. public UsageDial() : base()
  58. {
  59. SetThresholds(m_ThresholdYellowPercentage, m_ThresholdRedPercentage, force: true);
  60. RegenerateTexture();
  61. RegisterCallback<CustomStyleResolvedEvent>(OnCustomStyleResolved);
  62. generateVisualContent = GenerateVisualContent;
  63. }
  64. /// <summary>
  65. /// Finalizer destorys the dial texture if still allocated.
  66. /// </summary>
  67. ~UsageDial()
  68. {
  69. if (m_Texture)
  70. UnityEngine.Object.DestroyImmediate(m_Texture);
  71. m_Texture = null;
  72. }
  73. /// <summary>
  74. /// Change the percentage levels of the dial.
  75. /// </summary>
  76. /// <param name="yellowPercentage"></param>
  77. /// <param name="redPercentage"></param>
  78. /// <param name="force">Force and intemediate update.</param>
  79. public void SetThresholds(int yellowPercentage, int redPercentage, bool force = false)
  80. {
  81. if (!force && yellowPercentage == m_ThresholdYellowPercentage && redPercentage == m_ThresholdRedPercentage)
  82. return;
  83. m_ThresholdYellowPercentage = yellowPercentage;
  84. m_ThresholdRedPercentage = redPercentage;
  85. m_ThresholdYellow = (byte)(byte.MaxValue * (yellowPercentage / 100f));
  86. m_ThresholdRed = (byte)(byte.MaxValue * (redPercentage / 100f));
  87. RegenerateTexture();
  88. }
  89. void SetValue(int percentage, bool force = false)
  90. {
  91. if (!force && m_Value == percentage)
  92. return;
  93. if (m_IndicatorRoot == null)
  94. {
  95. InitVisualChildElements();
  96. }
  97. var f = percentage / 100f;
  98. if (m_IndicatorRoot != null)
  99. m_IndicatorRoot.transform.rotation = Quaternion.Euler(0, 0, 180 * f);
  100. if (m_Label != null)
  101. {
  102. if (m_showLabel)
  103. m_Label.text = string.Format("{0:0}%", percentage);
  104. else
  105. m_Label.text = "";
  106. }
  107. m_Value = percentage;
  108. m_ValueCutoff = (byte)((percentage / 100f) * byte.MaxValue);
  109. RegenerateTexture();
  110. MarkDirtyRepaint();
  111. }
  112. void Init(int value, int yellow, int red, bool showLabel)
  113. {
  114. m_showLabel = showLabel;
  115. InitVisualChildElements();
  116. SetThresholds(yellow, red, force: true);
  117. SetValue(value, force: true);
  118. }
  119. void InitVisualChildElements()
  120. {
  121. m_IndicatorRoot = this.Q("usage-dial__root");
  122. m_Indicator = this.Q("usage-dial__indicator");
  123. m_Label = this.Q<Label>("usage-dial__label");
  124. }
  125. void GenerateVisualContent(MeshGenerationContext obj)
  126. {
  127. if (m_Texture == null)
  128. RegenerateTexture();
  129. Quad(contentRect.position, contentRect.size, Color.white, m_Texture, obj);
  130. }
  131. void Quad(Vector2 pos, Vector2 size, Color color, Texture2D texture2D, MeshGenerationContext context)
  132. {
  133. var mesh = context.Allocate(4, 6, texture2D);
  134. var x0 = pos.x;
  135. var y0 = pos.y;
  136. var x1 = pos.x + size.x;
  137. var y1 = pos.y + size.y;
  138. mesh.SetNextVertex(new Vertex()
  139. {
  140. position = new Vector3(x0, y0, Vertex.nearZ),
  141. tint = color,
  142. uv = new Vector2(0, 1) * mesh.uvRegion.size + mesh.uvRegion.position
  143. });
  144. mesh.SetNextVertex(new Vertex()
  145. {
  146. position = new Vector3(x1, y0, Vertex.nearZ),
  147. tint = color,
  148. uv = new Vector2(1, 1) * mesh.uvRegion.size + mesh.uvRegion.position
  149. });
  150. mesh.SetNextVertex(new Vertex()
  151. {
  152. position = new Vector3(x0, y1, Vertex.nearZ),
  153. tint = color,
  154. uv = new Vector2(0, 0) * mesh.uvRegion.size + mesh.uvRegion.position
  155. });
  156. mesh.SetNextVertex(new Vertex()
  157. {
  158. position = new Vector3(x1, y1, Vertex.nearZ),
  159. tint = color,
  160. uv = new Vector2(1, 0) * mesh.uvRegion.size + mesh.uvRegion.position
  161. });
  162. mesh.SetAllIndices(k_Indices);
  163. }
  164. void OnCustomStyleResolved(CustomStyleResolvedEvent e)
  165. {
  166. RegenerateTexture();
  167. }
  168. void RegenerateTexture()
  169. {
  170. if (m_BaseTexture == null)
  171. m_BaseTexture = resolvedStyle.backgroundImage.texture;
  172. if (m_BaseTexture == null)
  173. return;
  174. if (m_Texture != null)
  175. {
  176. if (m_Texture.width != m_BaseTexture.width || m_Texture.height != m_BaseTexture.height)
  177. UnityEngine.Object.DestroyImmediate(m_Texture);
  178. }
  179. m_Texture = new Texture2D((int)m_BaseTexture.width, m_BaseTexture.height, TextureFormat.RGBA32, false, true);
  180. m_Texture.name = "UsageDial Generated";
  181. m_Texture.wrapMode = TextureWrapMode.Clamp;
  182. m_Texture.filterMode = FilterMode.Point;
  183. m_Texture.hideFlags = HideFlags.HideAndDontSave;
  184. var rawTexture = m_Texture.GetRawTextureData<Color32>();
  185. var rawBaseTexture = m_BaseTexture.GetRawTextureData<Color32>();
  186. unsafe
  187. {
  188. var ptr = rawTexture.GetUnsafePtr();
  189. var ptr2 = rawBaseTexture.GetUnsafePtr();
  190. UnsafeUtility.MemCpy(ptr, ptr2, rawTexture.Length * UnsafeUtility.SizeOf<Color32>());
  191. Color32* c = (Color32*)ptr;
  192. for (int i = 0; i < rawTexture.Length; ++i, ++c)
  193. {
  194. var a = c->a;
  195. if (a <= 0)
  196. continue;
  197. if (c->r > m_ValueCutoff)
  198. a = (byte)(a / 2);
  199. if (c->r > m_ThresholdRed)
  200. *c = k_Red;
  201. else if (c->r > m_ThresholdYellow)
  202. *c = k_Yellow;
  203. else
  204. *c = k_Green;
  205. c->a = a;
  206. }
  207. }
  208. m_Texture.Apply(false, true);
  209. }
  210. /// <summary>
  211. /// Instantiates a <see cref="UsageDial"/> using the data read from a UXML file.
  212. /// </summary>
  213. public new class UxmlFactory : UxmlFactory<UsageDial, UxmlTraits> {}
  214. /// <summary>
  215. /// Defines <see cref="UxmlTraits"/> for the <see cref="UsageDial"/>.
  216. /// </summary>
  217. public new class UxmlTraits : VisualElement.UxmlTraits
  218. {
  219. UxmlIntAttributeDescription m_Value = new UxmlIntAttributeDescription { name = "percentage-value", defaultValue = 55 };
  220. UxmlIntAttributeDescription m_YellowThreshold = new UxmlIntAttributeDescription { name = "yellow-threshold", defaultValue = 50 };
  221. UxmlIntAttributeDescription m_RedThreshold = new UxmlIntAttributeDescription { name = "red-threshold", defaultValue = 75 };
  222. UxmlBoolAttributeDescription m_ShowLabel = new UxmlBoolAttributeDescription { name = "show-label", defaultValue = true };
  223. /// <summary>
  224. ///
  225. /// </summary>
  226. public override IEnumerable<UxmlChildElementDescription> uxmlChildElementsDescription
  227. {
  228. get { yield break; }
  229. }
  230. /// <summary>
  231. /// Initializes the <see cref="UsageDial"/> with supplied <see cref="UxmlTraits"/>.
  232. /// </summary>
  233. /// <param name="ve"></param>
  234. /// <param name="bag"></param>
  235. /// <param name="cc"></param>
  236. public override void Init(VisualElement ve, IUxmlAttributes bag, CreationContext cc)
  237. {
  238. base.Init(ve, bag, cc);
  239. var value = m_Value.GetValueFromBag(bag, cc);
  240. var yellow = m_YellowThreshold.GetValueFromBag(bag, cc);
  241. var red = m_RedThreshold.GetValueFromBag(bag, cc);
  242. var showLabel = m_ShowLabel.GetValueFromBag(bag, cc);
  243. ((UsageDial)ve).Init(value, yellow, red, showLabel);
  244. }
  245. }
  246. }
  247. }