///<summary> /// Find the Rect to use for clipping. /// Given the input RectMask2ds find a rectangle that is the overlap of all the inputs. ///</summary> ///<param name="rectMaskParents">RectMasks to build the overlap rect from.</param> ///<param name="validRect">Was there a valid Rect found.</param> ///<returns>The final compounded overlapping rect</returns> publicstatic Rect FindCullAndClipWorldRect(List<RectMask2D> rectMaskParents, outbool validRect) { if (rectMaskParents.Count == 0) { validRect = false; returnnew Rect(); }
Rect current = rectMaskParents[0].canvasRect; float xMin = current.xMin; float xMax = current.xMax; float yMin = current.yMin; float yMax = current.yMax; for (var i = 1; i < rectMaskParents.Count; ++i) { current = rectMaskParents[i].canvasRect; if (xMin < current.xMin) xMin = current.xMin; if (yMin < current.yMin) yMin = current.yMin; if (xMax > current.xMax) xMax = current.xMax; if (yMax > current.yMax) yMax = current.yMax; }
///<summary> /// Handles canvas scaling that scales with the screen size. ///</summary> protectedvirtualvoidHandleScaleWithScreenSize() { Vector2 screenSize = new Vector2(Screen.width, Screen.height);
// Multiple display support only when not the main display. For display 0 the reported // resolution is always the desktops resolution since its part of the display API, // so we use the standard none multiple display method. (case 741751) int displayIndex = m_Canvas.targetDisplay; if (displayIndex > 0 && displayIndex < Display.displays.Length) { Display disp = Display.displays[displayIndex]; screenSize = new Vector2(disp.renderingWidth, disp.renderingHeight); }
float scaleFactor = 0; switch (m_ScreenMatchMode) { case ScreenMatchMode.MatchWidthOrHeight: { // We take the log of the relative width and height before taking the average. // Then we transform it back in the original space. // the reason to transform in and out of logarithmic space is to have better behavior. // If one axis has twice resolution and the other has half, it should even out if widthOrHeight value is at 0.5. // In normal space the average would be (0.5 + 2) / 2 = 1.25 // In logarithmic space the average is (-1 + 1) / 2 = 0 // 在取平均值之前,我们先取相对宽度和高度的对数 // 然后将其转换到原始空间 // 进出对数空间的原因是具有更好的表现 // 如果一个轴的分辨率为两倍,而另一个轴的分辨率为一半 // 则widthOrHeight值为0.5时,它应该平整 // 在正常空间中,平均值为 (0.5 + 2) / 2 = 1.25 // 在对数空间中,平均值为 (-1 + 1) / 2 = 0 float logWidth = Mathf.Log(screenSize.x / m_ReferenceResolution.x, kLogBase); float logHeight = Mathf.Log(screenSize.y / m_ReferenceResolution.y, kLogBase); float logWeightedAverage = Mathf.Lerp(logWidth, logHeight, m_MatchWidthOrHeight); scaleFactor = Mathf.Pow(kLogBase, logWeightedAverage); break; } case ScreenMatchMode.Expand: { scaleFactor = Mathf.Min(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y); break; } case ScreenMatchMode.Shrink: { scaleFactor = Mathf.Max(screenSize.x / m_ReferenceResolution.x, screenSize.y / m_ReferenceResolution.y); break; } }
///<summary> /// Set all properties of the Graphic dirty and needing rebuilt. /// Dirties Layout, Vertices, and Materials. ///</summary> publicvirtualvoidSetAllDirty() { // Optimization: Graphic layout doesn't need recalculation if // the underlying Sprite is the same size with the same texture. // (e.g. Sprite sheet texture animation)
///<summary> /// Mark the layout as dirty and needing rebuilt. ///</summary> ///<remarks> /// Send a OnDirtyLayoutCallback notification if any elements are registered. See RegisterDirtyLayoutCallback ///</remarks> publicvirtualvoidSetLayoutDirty() { // 是否激活 if (!IsActive()) return; // 标记重构节点 LayoutRebuilder.MarkLayoutForRebuild(rectTransform); // 重构标记回调通知 if (m_OnDirtyLayoutCallback != null) m_OnDirtyLayoutCallback(); }
///<summary> /// Mark the vertices as dirty and needing rebuilt. ///</summary> ///<remarks> /// Send a OnDirtyVertsCallback notification if any elements are registered. See RegisterDirtyVerticesCallback ///</remarks> publicvirtualvoidSetVerticesDirty() { // 是否激活 if (!IsActive()) return; // 设置重构标记 m_VertsDirty = true; // 将自己注册到重构队列中 CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); // 回调通知 if (m_OnDirtyVertsCallback != null) m_OnDirtyVertsCallback(); }
///<summary> /// Mark the material as dirty and needing rebuilt. ///</summary> ///<remarks> /// Send a OnDirtyMaterialCallback notification if any elements are registered. See RegisterDirtyMaterialCallback ///</remarks> publicvirtualvoidSetMaterialDirty() { // 是否激活 if (!IsActive()) return; // 设置重构标记 m_MaterialDirty = true; // 将自己注册到重构队列中 CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); // 回调通知 if (m_OnDirtyMaterialCallback != null) m_OnDirtyMaterialCallback(); }
///<summary> /// Try and add the given element to the rebuild list. /// Will not return if successfully added. ///</summary> ///<param name="element">The element that is needing rebuilt.</param> publicstaticvoidRegisterCanvasElementForGraphicRebuild(ICanvasElement element) { instance.InternalRegisterCanvasElementForGraphicRebuild(element); }
///<summary> /// Try and add the given element to the rebuild list. ///</summary> ///<param name="element">The element that is needing rebuilt.</param> ///<returns> /// True if the element was successfully added to the rebuilt list. /// False if either already inside a Graphic Update loop OR has already been added to the list. ///</returns> publicstaticboolTryRegisterCanvasElementForGraphicRebuild(ICanvasElement element) { return instance.InternalRegisterCanvasElementForGraphicRebuild(element); }
privateboolInternalRegisterCanvasElementForGraphicRebuild(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)); returnfalse; }
// 裁剪 // now layout is complete do culling... ClipperRegistry.instance.Cull(); // 元素重构 m_PerformingGraphicUpdate = true; 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); } } }
for (int i = 0; i < m_GraphicRebuildQueue.Count; ++i) m_GraphicRebuildQueue[i].GraphicUpdateComplete();
publicvirtualvoidPerformClipping() { if (ReferenceEquals(Canvas, null)) { return; }
//TODO See if an IsActive() test would work well here or whether it might cause unexpected side effects (re case 776771)
// if the parents are changed // or something similar we // do a recalculate here // 如果父节点改变或发生类似的事情,我们在这里重新计算 if (m_ShouldRecalculateClipRects) { MaskUtilities.GetRectMasksForClip(this, m_Clippers); m_ShouldRecalculateClipRects = false; }
// get the compound rects from // the clippers that are valid // 从切割片中获得合法的Rect bool validRect = true; Rect clipRect = Clipping.FindCullAndClipWorldRect(m_Clippers, out validRect);
// If the mask is in ScreenSpaceOverlay/Camera render mode, its content is only rendered when its rect // overlaps that of the root canvas. RenderMode renderMode = Canvas.rootCanvas.renderMode; bool maskIsCulled = (renderMode == RenderMode.ScreenSpaceCamera || renderMode == RenderMode.ScreenSpaceOverlay) && !clipRect.Overlaps(rootCanvasRect, true);
if (maskIsCulled) { // Children are only displayed when inside the mask. If the mask is culled, then the children // inside the mask are also culled. In that situation, we pass an invalid rect to allow callees // to avoid some processing. clipRect = Rect.zero; validRect = false; }
if (clipRect != m_LastClipRectCanvasSpace) { foreach (IClippable clipTarget in m_ClipTargets) { clipTarget.SetClipRect(clipRect, validRect); }