summaryrefslogtreecommitdiff
path: root/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs')
-rw-r--r--Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs235
1 files changed, 235 insertions, 0 deletions
diff --git a/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs
new file mode 100644
index 0000000..0d0f327
--- /dev/null
+++ b/Assets/uGUI-2017.1/UnityEngine.UI/UI/Core/Graphics/MaskableGraphic.cs
@@ -0,0 +1,235 @@
+using System;
+using UnityEngine.Events;
+using UnityEngine.Rendering;
+
+namespace UnityEngine.UI
+{
+ public abstract class MaskableGraphic : Graphic, IClippable, IMaskable, IMaterialModifier
+ {
+ [NonSerialized]
+ protected bool m_ShouldRecalculateStencil = true;
+
+ [NonSerialized]
+ protected Material m_MaskMaterial;
+
+ [NonSerialized]
+ private RectMask2D m_ParentMask;
+
+ // m_Maskable is whether this graphic is allowed to be masked or not. It has the matching public property maskable.
+ // The default for m_Maskable is true, so graphics under a mask are masked out of the box.
+ // The maskable property can be turned off from script by the user if masking is not desired.
+ // m_IncludeForMasking is whether we actually consider this graphic for masking or not - this is an implementation detail.
+ // m_IncludeForMasking should only be true if m_Maskable is true AND a parent of the graphic has an IMask component.
+ // Things would still work correctly if m_IncludeForMasking was always true when m_Maskable is, but performance would suffer.
+ [NonSerialized]
+ private bool m_Maskable = true;
+
+ [NonSerialized]
+ [Obsolete("Not used anymore.", true)]
+ protected bool m_IncludeForMasking = false;
+
+ [Serializable]
+ public class CullStateChangedEvent : UnityEvent<bool> {}
+
+ // Event delegates triggered on click.
+ [SerializeField]
+ private CullStateChangedEvent m_OnCullStateChanged = new CullStateChangedEvent();
+
+ public CullStateChangedEvent onCullStateChanged
+ {
+ get { return m_OnCullStateChanged; }
+ set { m_OnCullStateChanged = value; }
+ }
+
+ public bool maskable
+ {
+ get { return m_Maskable; }
+ set
+ {
+ if (value == m_Maskable)
+ return;
+ m_Maskable = value;
+ m_ShouldRecalculateStencil = true;
+ SetMaterialDirty();
+ }
+ }
+
+ [NonSerialized]
+ [Obsolete("Not used anymore", true)]
+ protected bool m_ShouldRecalculate = true;
+
+ [NonSerialized]
+ protected int m_StencilValue;
+
+ public virtual Material GetModifiedMaterial(Material baseMaterial)
+ {
+ var toUse = baseMaterial;
+
+ if (m_ShouldRecalculateStencil)
+ {
+ var rootCanvas = MaskUtilities.FindRootSortOverrideCanvas(transform);
+ // Graphic在masks下的深度,如果不是0且没有mask组件意味着是普通的非mask用graphic(如果是0一定是mask用的graphic)
+ m_StencilValue = maskable ? MaskUtilities.GetStencilDepth(transform, rootCanvas) : 0;
+ m_ShouldRecalculateStencil = false;
+ }
+
+ // if we have a enabled Mask component then it will
+ // generate the mask material. This is an optimisation
+ // it adds some coupling between components though :(
+ Mask maskComponent = GetComponent<Mask>();
+ if (m_StencilValue > 0 && (maskComponent == null || !maskComponent.IsActive()))
+ {
+ // Ref = (1 << stencilValue) - 1
+ // Op = Keep
+ // Func = Equal
+ // ReadMask = (1 << stencilValue) - 1
+ // WriteMask = 0
+ var maskMat = StencilMaterial.Add(toUse, (1 << m_StencilValue) - 1, StencilOp.Keep, CompareFunction.Equal, ColorWriteMask.All, (1 << m_StencilValue) - 1, 0);
+ StencilMaterial.Remove(m_MaskMaterial);
+ m_MaskMaterial = maskMat;
+ toUse = m_MaskMaterial;
+ }
+ return toUse;
+ }
+
+ public virtual void Cull(Rect clipRect, bool validRect)
+ {
+ var cull = !validRect || !clipRect.Overlaps(rootCanvasRect, true);
+ UpdateCull(cull);
+ }
+
+ private void UpdateCull(bool cull)
+ {
+ var cullingChanged = canvasRenderer.cull != cull;
+ canvasRenderer.cull = cull;
+
+ if (cullingChanged)
+ {
+ UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this);
+ m_OnCullStateChanged.Invoke(cull);
+ SetVerticesDirty(); // 这里需要更新一下canvasRenderer的网格数据
+ }
+ }
+
+ public virtual void SetClipRect(Rect clipRect, bool validRect)
+ {
+ if (validRect)
+ canvasRenderer.EnableRectClipping(clipRect);
+ else
+ canvasRenderer.DisableRectClipping();
+ }
+
+ protected override void OnEnable()
+ {
+ base.OnEnable();
+ m_ShouldRecalculateStencil = true;
+ UpdateClipParent();
+ SetMaterialDirty();
+
+ if (GetComponent<Mask>() != null)
+ {
+ MaskUtilities.NotifyStencilStateChanged(this);
+ }
+ }
+
+ protected override void OnDisable()
+ {
+ base.OnDisable();
+ m_ShouldRecalculateStencil = true;
+ SetMaterialDirty();
+ UpdateClipParent();
+ StencilMaterial.Remove(m_MaskMaterial);
+ m_MaskMaterial = null;
+
+ if (GetComponent<Mask>() != null)
+ {
+ MaskUtilities.NotifyStencilStateChanged(this);
+ }
+ }
+
+#if UNITY_EDITOR
+ protected override void OnValidate()
+ {
+ base.OnValidate();
+ m_ShouldRecalculateStencil = true;
+ UpdateClipParent();
+ SetMaterialDirty();
+ }
+
+#endif
+
+ protected override void OnTransformParentChanged()
+ {
+ base.OnTransformParentChanged();
+
+ if (!isActiveAndEnabled)
+ return;
+
+ m_ShouldRecalculateStencil = true;
+ UpdateClipParent();
+ SetMaterialDirty();
+ }
+
+ [Obsolete("Not used anymore.", true)]
+ public virtual void ParentMaskStateChanged() {}
+
+ protected override void OnCanvasHierarchyChanged()
+ {
+ base.OnCanvasHierarchyChanged();
+
+ if (!isActiveAndEnabled)
+ return;
+
+ m_ShouldRecalculateStencil = true;
+ UpdateClipParent();
+ SetMaterialDirty();
+ }
+
+ readonly Vector3[] m_Corners = new Vector3[4];
+ private Rect rootCanvasRect
+ {
+ get
+ {
+ rectTransform.GetWorldCorners(m_Corners);
+
+ if (canvas)
+ {
+ Canvas rootCanvas = canvas.rootCanvas;
+ for (int i = 0; i < 4; ++i)
+ m_Corners[i] = rootCanvas.transform.InverseTransformPoint(m_Corners[i]);
+ }
+
+ return new Rect(m_Corners[0].x, m_Corners[0].y, m_Corners[2].x - m_Corners[0].x, m_Corners[2].y - m_Corners[0].y);
+ }
+ }
+
+ private void UpdateClipParent()
+ {
+ var newParent = (maskable && IsActive()) ? MaskUtilities.GetRectMaskForClippable(this) : null;
+
+ // if the new parent is different OR is now inactive
+ if (m_ParentMask != null && (newParent != m_ParentMask || !newParent.IsActive()))
+ {
+ m_ParentMask.RemoveClippable(this);
+ UpdateCull(false);
+ }
+
+ // don't re-add it if the newparent is inactive
+ if (newParent != null && newParent.IsActive())
+ newParent.AddClippable(this);
+
+ m_ParentMask = newParent;
+ }
+
+ public virtual void RecalculateClipping()
+ {
+ UpdateClipParent();
+ }
+
+ public virtual void RecalculateMasking()
+ {
+ m_ShouldRecalculateStencil = true;
+ SetMaterialDirty();
+ }
+ }
+}