TMP_UpdateManager.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  1. using UnityEngine;
  2. using UnityEngine.UI;
  3. using System.Collections.Generic;
  4. #if UNITY_2019_1_OR_NEWER
  5. using UnityEngine.Rendering;
  6. #elif UNITY_2018_1_OR_NEWER
  7. using UnityEngine.Experimental.Rendering;
  8. #endif
  9. namespace TMPro
  10. {
  11. public class TMP_UpdateManager
  12. {
  13. private static TMP_UpdateManager s_Instance;
  14. private readonly List<TMP_Text> m_LayoutRebuildQueue = new List<TMP_Text>();
  15. private Dictionary<int, int> m_LayoutQueueLookup = new Dictionary<int, int>();
  16. private readonly List<TMP_Text> m_GraphicRebuildQueue = new List<TMP_Text>();
  17. private Dictionary<int, int> m_GraphicQueueLookup = new Dictionary<int, int>();
  18. private readonly List<TMP_Text> m_InternalUpdateQueue = new List<TMP_Text>();
  19. private Dictionary<int, int> m_InternalUpdateLookup = new Dictionary<int, int>();
  20. //private bool m_PerformingGraphicRebuild;
  21. //private bool m_PerformingLayoutRebuild;
  22. /// <summary>
  23. /// Get a singleton instance of the registry
  24. /// </summary>
  25. public static TMP_UpdateManager instance
  26. {
  27. get
  28. {
  29. if (TMP_UpdateManager.s_Instance == null)
  30. TMP_UpdateManager.s_Instance = new TMP_UpdateManager();
  31. return TMP_UpdateManager.s_Instance;
  32. }
  33. }
  34. /// <summary>
  35. /// Register to receive rendering callbacks.
  36. /// </summary>
  37. protected TMP_UpdateManager()
  38. {
  39. Camera.onPreCull += OnCameraPreCull;
  40. #if UNITY_2019_1_OR_NEWER
  41. RenderPipelineManager.beginFrameRendering += OnBeginFrameRendering;
  42. #elif UNITY_2018_1_OR_NEWER
  43. RenderPipeline.beginFrameRendering += OnBeginFrameRendering;
  44. #endif
  45. }
  46. /// <summary>
  47. /// Function used as a replacement for LateUpdate() to handle SDF Scale updates and Legacy Animation updates.
  48. /// </summary>
  49. /// <param name="textObject"></param>
  50. internal static void RegisterTextObjectForUpdate(TMP_Text textObject)
  51. {
  52. TMP_UpdateManager.instance.InternalRegisterTextObjectForUpdate(textObject);
  53. }
  54. private void InternalRegisterTextObjectForUpdate(TMP_Text textObject)
  55. {
  56. int id = textObject.GetInstanceID();
  57. if (this.m_InternalUpdateLookup.ContainsKey(id))
  58. return;
  59. m_InternalUpdateLookup[id] = id;
  60. this.m_InternalUpdateQueue.Add(textObject);
  61. return;
  62. }
  63. /// <summary>
  64. /// Function to register elements which require a layout rebuild.
  65. /// </summary>
  66. /// <param name="element"></param>
  67. public static void RegisterTextElementForLayoutRebuild(TMP_Text element)
  68. {
  69. TMP_UpdateManager.instance.InternalRegisterTextElementForLayoutRebuild(element);
  70. }
  71. private bool InternalRegisterTextElementForLayoutRebuild(TMP_Text element)
  72. {
  73. int id = element.GetInstanceID();
  74. if (this.m_LayoutQueueLookup.ContainsKey(id))
  75. return false;
  76. m_LayoutQueueLookup[id] = id;
  77. this.m_LayoutRebuildQueue.Add(element);
  78. return true;
  79. }
  80. /// <summary>
  81. /// Function to register elements which require a layout rebuild.
  82. /// </summary>
  83. /// <param name="element"></param>
  84. public static void RegisterTextElementForGraphicRebuild(TMP_Text element)
  85. {
  86. TMP_UpdateManager.instance.InternalRegisterTextElementForGraphicRebuild(element);
  87. }
  88. private bool InternalRegisterTextElementForGraphicRebuild(TMP_Text element)
  89. {
  90. int id = element.GetInstanceID();
  91. if (this.m_GraphicQueueLookup.ContainsKey(id))
  92. return false;
  93. m_GraphicQueueLookup[id] = id;
  94. this.m_GraphicRebuildQueue.Add(element);
  95. return true;
  96. }
  97. /// <summary>
  98. /// Callback which occurs just before the Scriptable Render Pipeline (SRP) begins rendering.
  99. /// </summary>
  100. /// <param name="cameras"></param>
  101. #if UNITY_2019_1_OR_NEWER
  102. void OnBeginFrameRendering(ScriptableRenderContext renderContext, Camera[] cameras)
  103. #elif UNITY_2018_1_OR_NEWER
  104. void OnBeginFrameRendering(Camera[] cameras)
  105. #endif
  106. {
  107. // Exclude the PreRenderCamera
  108. #if UNITY_EDITOR
  109. if (cameras.Length == 1 && cameras[0].cameraType == CameraType.Preview)
  110. return;
  111. #endif
  112. DoRebuilds();
  113. }
  114. /// <summary>
  115. /// Callback which occurs just before the cam is rendered.
  116. /// </summary>
  117. /// <param name="cam"></param>
  118. void OnCameraPreCull(Camera cam)
  119. {
  120. // Exclude the PreRenderCamera
  121. #if UNITY_EDITOR
  122. if (cam.cameraType == CameraType.Preview)
  123. return;
  124. #endif
  125. DoRebuilds();
  126. }
  127. /// <summary>
  128. /// Process the rebuild requests in the rebuild queues.
  129. /// </summary>
  130. void DoRebuilds()
  131. {
  132. // Handle text objects the require an update either as a result of scale changes or legacy animation.
  133. for (int i = 0; i < m_InternalUpdateQueue.Count; i++)
  134. {
  135. m_InternalUpdateQueue[i].InternalUpdate();
  136. }
  137. // Handle Layout Rebuild Phase
  138. for (int i = 0; i < m_LayoutRebuildQueue.Count; i++)
  139. {
  140. m_LayoutRebuildQueue[i].Rebuild(CanvasUpdate.Prelayout);
  141. }
  142. if (m_LayoutRebuildQueue.Count > 0)
  143. {
  144. m_LayoutRebuildQueue.Clear();
  145. m_LayoutQueueLookup.Clear();
  146. }
  147. // Handle Graphic Rebuild Phase
  148. for (int i = 0; i < m_GraphicRebuildQueue.Count; i++)
  149. {
  150. m_GraphicRebuildQueue[i].Rebuild(CanvasUpdate.PreRender);
  151. }
  152. // If there are no objects in the queue, we don't need to clear the lists again.
  153. if (m_GraphicRebuildQueue.Count > 0)
  154. {
  155. m_GraphicRebuildQueue.Clear();
  156. m_GraphicQueueLookup.Clear();
  157. }
  158. }
  159. internal static void UnRegisterTextObjectForUpdate(TMP_Text textObject)
  160. {
  161. TMP_UpdateManager.instance.InternalUnRegisterTextObjectForUpdate(textObject);
  162. }
  163. /// <summary>
  164. /// Function to unregister elements which no longer require a rebuild.
  165. /// </summary>
  166. /// <param name="element"></param>
  167. public static void UnRegisterTextElementForRebuild(TMP_Text element)
  168. {
  169. TMP_UpdateManager.instance.InternalUnRegisterTextElementForGraphicRebuild(element);
  170. TMP_UpdateManager.instance.InternalUnRegisterTextElementForLayoutRebuild(element);
  171. TMP_UpdateManager.instance.InternalUnRegisterTextObjectForUpdate(element);
  172. }
  173. private void InternalUnRegisterTextElementForGraphicRebuild(TMP_Text element)
  174. {
  175. int id = element.GetInstanceID();
  176. TMP_UpdateManager.instance.m_GraphicRebuildQueue.Remove(element);
  177. m_GraphicQueueLookup.Remove(id);
  178. }
  179. private void InternalUnRegisterTextElementForLayoutRebuild(TMP_Text element)
  180. {
  181. int id = element.GetInstanceID();
  182. TMP_UpdateManager.instance.m_LayoutRebuildQueue.Remove(element);
  183. m_LayoutQueueLookup.Remove(id);
  184. }
  185. private void InternalUnRegisterTextObjectForUpdate(TMP_Text textObject)
  186. {
  187. int id = textObject.GetInstanceID();
  188. TMP_UpdateManager.instance.m_InternalUpdateQueue.Remove(textObject);
  189. m_InternalUpdateLookup.Remove(id);
  190. }
  191. }
  192. }