diff options
author | chai <chaifix@163.com> | 2021-05-08 23:15:13 +0800 |
---|---|---|
committer | chai <chaifix@163.com> | 2021-05-08 23:15:13 +0800 |
commit | d07e14add74e017b52ab2371efeea1aa4ea10ced (patch) | |
tree | efd07869326e4c428f5bfe43fad0c2583d32a401 /Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs |
+init
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs')
-rw-r--r-- | Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs | 307 |
1 files changed, 307 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs new file mode 100644 index 0000000..200b4e5 --- /dev/null +++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/CanvasUpdateRegistry.cs @@ -0,0 +1,307 @@ +using System; +using System.Collections.Generic; +using UnityEngine.UI.Collections; + +namespace UnityEngine.UI +{ + // canvas的不同阶段,用来设置layout、graphic做不同的事情,具体看CanvasUpdateRegistry + // prelayout -> layout -> postlayout -> prerender -> laterender =>=>=> render + public enum CanvasUpdate + { + Prelayout = 0, + Layout = 1, + PostLayout = 2, + PreRender = 3, + LatePreRender = 4, + + MaxUpdateValue = 5 + } + + public interface ICanvasElement + { + Transform transform { get; } + void Rebuild(CanvasUpdate executing); + void LayoutComplete(); + void GraphicUpdateComplete(); + // due to unity overriding null check + // we need this as something may not be null + // but may be destroyed + bool IsDestroyed(); + } + + // 需要注意整个游戏只有一个单例 + public class CanvasUpdateRegistry + { + private static CanvasUpdateRegistry s_Instance; + + private bool m_PerformingLayoutUpdate; + private bool m_PerformingGraphicUpdate; + + private readonly IndexedSet<ICanvasElement> m_LayoutRebuildQueue = new IndexedSet<ICanvasElement>(); + private readonly IndexedSet<ICanvasElement> m_GraphicRebuildQueue = new IndexedSet<ICanvasElement>(); + + protected CanvasUpdateRegistry() + { + // willRenderCanvases在渲染canvas之前调用,执行PerformUpdate来Rebuild处理m_LayoutRebuildQueue和m_GraphicRebuildQueue + Canvas.willRenderCanvases += PerformUpdate; + } + + // 简单单例 + public static CanvasUpdateRegistry instance + { + get + { + if (s_Instance == null) + s_Instance = new CanvasUpdateRegistry(); + return s_Instance; + } + } + + // 检查一下实现了ICanvasElement的对象合法性,实现了ICanvasElement接口的对象必须是Unity Object, + private bool ObjectValidForUpdate(ICanvasElement element) + { + var valid = element != null; + + var isUnityObject = element is Object; + if (isUnityObject) + valid = (element as Object) != null; //Here we make use of the overloaded UnityEngine.Object == null, that checks if the native object is alive. + + return valid; + } + + private void CleanInvalidItems() + { + // So MB's override the == operator for null equality, which checks + // if they are destroyed. This is fine if you are looking at a concrete + // mb, but in this case we are looking at a list of ICanvasElement + // this won't forward the == operator to the MB, but just check if the + // interface is null. IsDestroyed will return if the backend is destroyed. + + for (int i = m_LayoutRebuildQueue.Count - 1; i >= 0; --i) + { + var item = m_LayoutRebuildQueue[i]; + if (item == null) + { + m_LayoutRebuildQueue.RemoveAt(i); + continue; + } + + if (item.IsDestroyed()) + { + m_LayoutRebuildQueue.RemoveAt(i); + item.LayoutComplete(); + } + } + + for (int i = m_GraphicRebuildQueue.Count - 1; i >= 0; --i) + { + var item = m_GraphicRebuildQueue[i]; + if (item == null) + { + m_GraphicRebuildQueue.RemoveAt(i); + continue; + } + + if (item.IsDestroyed()) + { + m_GraphicRebuildQueue.RemoveAt(i); + item.GraphicUpdateComplete(); + } + } + } + + private static readonly Comparison<ICanvasElement> s_SortLayoutFunction = SortLayoutList; + // 在渲染canvas之前对canvas下的元素进行rebuild + // 进行 prelayout -> layout -> postlayout -> prerender -> LatePreRender 流程 + private void PerformUpdate() + { + UISystemProfilerApi.BeginSample(UISystemProfilerApi.SampleType.Layout); + CleanInvalidItems(); + + m_PerformingLayoutUpdate = true; + + // 重建layout + + // 根据父节点从少到多排序,先布局父节点少的,由少到多,由内到外 + m_LayoutRebuildQueue.Sort(s_SortLayoutFunction); + // prelayout -> layout -> postlayout + for (int i = 0; i <= (int)CanvasUpdate.PostLayout; i++) // 不同的阶段 + { + for (int j = 0; j < m_LayoutRebuildQueue.Count; j++) + { + var rebuild = instance.m_LayoutRebuildQueue[j]; + try + { + if (ObjectValidForUpdate(rebuild)) + rebuild.Rebuild((CanvasUpdate)i); + } + catch (Exception e) + { + Debug.LogException(e, rebuild.transform); + } + } + } + + // 布局完成 + for (int i = 0; i < m_LayoutRebuildQueue.Count; ++i) + m_LayoutRebuildQueue[i].LayoutComplete(); + + // 清空队列,重置状态 + instance.m_LayoutRebuildQueue.Clear(); + m_PerformingLayoutUpdate = false; + + // 做剔除+裁剪 + // now layout is complete do culling... + ClipperRegistry.instance.Cull(); + + // 重建graphic + + m_PerformingGraphicUpdate = true; + // prerender -> lateprerender + for (var i = (int)CanvasUpdate.PreRender; i < (int)CanvasUpdate.MaxUpdateValue; i++) + { + for (var k = 0; k < instance.m_GraphicRebuildQueue.Count; k++) + { + try + { + var element = instance.m_GraphicRebuildQueue[k]; + if (ObjectValidForUpdate(element)) + element.Rebuild((CanvasUpdate)i); + } + catch (Exception e) + { + Debug.LogException(e, instance.m_GraphicRebuildQueue[k].transform); + } + } + } + + // graphic设置mesh和材质完成 + for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i) + m_GraphicRebuildQueue[i].GraphicUpdateComplete(); + + // 清空队列,重置状态 + instance.m_GraphicRebuildQueue.Clear(); + m_PerformingGraphicUpdate = false; + + // 到了这里布局和网格、材质都设置完毕,后面canvas会渲染 + + // profiler不用管 + UISystemProfilerApi.EndSample(UISystemProfilerApi.SampleType.Layout); + } + + // 统计父节点个数 + private static int ParentCount(Transform child) + { + if (child == null) + return 0; + + var parent = child.parent; + int count = 0; + while (parent != null) + { + count++; + parent = parent.parent; + } + return count; + } + + // 根据父节点由少到多排序 + private static int SortLayoutList(ICanvasElement x, ICanvasElement y) + { + Transform t1 = x.transform; + Transform t2 = y.transform; + + return ParentCount(t1) - ParentCount(t2); + }
+
+ public static bool IsRebuildingLayout() + { + return instance.m_PerformingLayoutUpdate; + } + + public static bool IsRebuildingGraphics() + { + return instance.m_PerformingGraphicUpdate; + }
+
+#region 将canvas elements注册到队列里的方法 +
+ public static void RegisterCanvasElementForLayoutRebuild(ICanvasElement element) + { + instance.InternalRegisterCanvasElementForLayoutRebuild(element); + } + + public static bool TryRegisterCanvasElementForLayoutRebuild(ICanvasElement element) + { + return instance.InternalRegisterCanvasElementForLayoutRebuild(element); + } + + private bool InternalRegisterCanvasElementForLayoutRebuild(ICanvasElement element) + { + if (m_LayoutRebuildQueue.Contains(element)) + return false; + + /* TODO: this likely should be here but causes the error to show just resizing the game view (case 739376) + if (m_PerformingLayoutUpdate) + { + Debug.LogError(string.Format("Trying to add {0} for layout rebuild while we are already inside a layout rebuild loop. This is not supported.", element)); + return false; + }*/ + + return m_LayoutRebuildQueue.AddUnique(element); + } + + public static void RegisterCanvasElementForGraphicRebuild(ICanvasElement element) + { + instance.InternalRegisterCanvasElementForGraphicRebuild(element); + } + + public static bool TryRegisterCanvasElementForGraphicRebuild(ICanvasElement element) + { + return instance.InternalRegisterCanvasElementForGraphicRebuild(element); + } + + private bool InternalRegisterCanvasElementForGraphicRebuild(ICanvasElement element) + { + if (m_PerformingGraphicUpdate) + { + Debug.LogError(string.Format("Trying to add {0} for graphic rebuild while we are already inside a graphic rebuild loop. This is not supported.", element)); + return false; + } + + return m_GraphicRebuildQueue.AddUnique(element); + } + + public static void UnRegisterCanvasElementForRebuild(ICanvasElement element) + { + instance.InternalUnRegisterCanvasElementForLayoutRebuild(element); + instance.InternalUnRegisterCanvasElementForGraphicRebuild(element); + } + + private void InternalUnRegisterCanvasElementForLayoutRebuild(ICanvasElement element) + { + if (m_PerformingLayoutUpdate) + { + Debug.LogError(string.Format("Trying to remove {0} from rebuild list while we are already inside a rebuild loop. This is not supported.", element)); + return; + } + + element.LayoutComplete(); + instance.m_LayoutRebuildQueue.Remove(element); + } + + private void InternalUnRegisterCanvasElementForGraphicRebuild(ICanvasElement element) + { + if (m_PerformingGraphicUpdate) + { + Debug.LogError(string.Format("Trying to remove {0} from rebuild list while we are already inside a rebuild loop. This is not supported.", element)); + return; + } + element.GraphicUpdateComplete(); + instance.m_GraphicRebuildQueue.Remove(element); + }
+
+#endregion + + } +} |