using UnityEngine; using UnityEngine.Profiling; using UnityEngine.UI; using System.Collections.Generic; namespace TMPro { public class TMP_UpdateManager { private static TMP_UpdateManager s_Instance; private readonly HashSet m_LayoutQueueLookup = new HashSet(); private readonly List m_LayoutRebuildQueue = new List(); private readonly HashSet m_GraphicQueueLookup = new HashSet(); private readonly List m_GraphicRebuildQueue = new List(); private readonly HashSet m_InternalUpdateLookup = new HashSet(); private readonly List m_InternalUpdateQueue = new List(); private readonly HashSet m_CullingUpdateLookup = new HashSet(); private readonly List m_CullingUpdateQueue = new List(); /// /// Get a singleton instance of the registry /// static TMP_UpdateManager instance { get { if (s_Instance == null) s_Instance = new TMP_UpdateManager(); return s_Instance; } } /// /// Register to receive rendering callbacks. /// TMP_UpdateManager() { Canvas.willRenderCanvases += DoRebuilds; } /// /// Function used as a replacement for LateUpdate() to handle SDF Scale updates and Legacy Animation updates. /// /// internal static void RegisterTextObjectForUpdate(TMP_Text textObject) { Profiler.BeginSample("TMP.RegisterTextObjectForUpdate"); instance.InternalRegisterTextObjectForUpdate(textObject); Profiler.EndSample(); } private void InternalRegisterTextObjectForUpdate(TMP_Text textObject) { int id = textObject.GetInstanceID(); if (m_InternalUpdateLookup.Contains(id)) return; m_InternalUpdateLookup.Add(id); m_InternalUpdateQueue.Add(textObject); } /// /// Function to register elements which require a layout rebuild. /// /// public static void RegisterTextElementForLayoutRebuild(TMP_Text element) { instance.InternalRegisterTextElementForLayoutRebuild(element); } private void InternalRegisterTextElementForLayoutRebuild(TMP_Text element) { int id = element.GetInstanceID(); if (m_LayoutQueueLookup.Contains(id)) return; m_LayoutQueueLookup.Add(id); m_LayoutRebuildQueue.Add(element); } /// /// Function to register elements which require a layout rebuild. /// /// public static void RegisterTextElementForGraphicRebuild(TMP_Text element) { Profiler.BeginSample("TMP.RegisterTextElementForGraphicRebuild"); instance.InternalRegisterTextElementForGraphicRebuild(element); Profiler.EndSample(); } private void InternalRegisterTextElementForGraphicRebuild(TMP_Text element) { int id = element.GetInstanceID(); if (m_GraphicQueueLookup.Contains(id)) return; m_GraphicQueueLookup.Add(id); m_GraphicRebuildQueue.Add(element); } public static void RegisterTextElementForCullingUpdate(TMP_Text element) { Profiler.BeginSample("TMP.RegisterTextElementForCullingUpdate"); instance.InternalRegisterTextElementForCullingUpdate(element); Profiler.EndSample(); } private void InternalRegisterTextElementForCullingUpdate(TMP_Text element) { int id = element.GetInstanceID(); if (m_CullingUpdateLookup.Contains(id)) return; m_CullingUpdateLookup.Add(id); m_CullingUpdateQueue.Add(element); } /// /// Callback which occurs just before the cam is rendered. /// void OnCameraPreCull() { DoRebuilds(); } /// /// Process the rebuild requests in the rebuild queues. /// void DoRebuilds() { // Handle text objects the require an update either as a result of scale changes or legacy animation. for (int i = 0; i < m_InternalUpdateQueue.Count; i++) { m_InternalUpdateQueue[i].InternalUpdate(); } // Handle Layout Rebuild Phase for (int i = 0; i < m_LayoutRebuildQueue.Count; i++) { m_LayoutRebuildQueue[i].Rebuild(CanvasUpdate.Prelayout); } if (m_LayoutRebuildQueue.Count > 0) { m_LayoutRebuildQueue.Clear(); m_LayoutQueueLookup.Clear(); } // Handle Graphic Rebuild Phase for (int i = 0; i < m_GraphicRebuildQueue.Count; i++) { m_GraphicRebuildQueue[i].Rebuild(CanvasUpdate.PreRender); } // If there are no objects in the queue, we don't need to clear the lists again. if (m_GraphicRebuildQueue.Count > 0) { m_GraphicRebuildQueue.Clear(); m_GraphicQueueLookup.Clear(); } // Handle Culling Update for (int i = 0; i < m_CullingUpdateQueue.Count; i++) { m_CullingUpdateQueue[i].UpdateCulling(); } // If there are no objects in the queue, we don't need to clear the lists again. if (m_CullingUpdateQueue.Count > 0) { m_CullingUpdateQueue.Clear(); m_CullingUpdateLookup.Clear(); } } internal static void UnRegisterTextObjectForUpdate(TMP_Text textObject) { Profiler.BeginSample("TMP.UnRegisterTextObjectForUpdate"); instance.InternalUnRegisterTextObjectForUpdate(textObject); Profiler.EndSample(); } /// /// Function to unregister elements which no longer require a rebuild. /// /// public static void UnRegisterTextElementForRebuild(TMP_Text element) { instance.InternalUnRegisterTextElementForGraphicRebuild(element); instance.InternalUnRegisterTextElementForLayoutRebuild(element); instance.InternalUnRegisterTextObjectForUpdate(element); } private void InternalUnRegisterTextElementForGraphicRebuild(TMP_Text element) { Profiler.BeginSample("TMP.InternalUnRegisterTextElementForGraphicRebuild"); int id = element.GetInstanceID(); m_GraphicRebuildQueue.Remove(element); m_GraphicQueueLookup.Remove(id); Profiler.EndSample(); } private void InternalUnRegisterTextElementForLayoutRebuild(TMP_Text element) { int id = element.GetInstanceID(); m_LayoutRebuildQueue.Remove(element); m_LayoutQueueLookup.Remove(id); } private void InternalUnRegisterTextObjectForUpdate(TMP_Text textObject) { int id = textObject.GetInstanceID(); m_InternalUpdateQueue.Remove(textObject); m_InternalUpdateLookup.Remove(id); } } }