using UnityEngine; using UnityEngine.UI; using System; using UnityEngine.Events; using System.Collections.Generic; namespace WXB { [RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(CanvasRenderer))] [ExecuteInEditMode] public class DrawObject : MonoBehaviour, Draw, IClippable, ICanvasElement { private RectMask2D m_ParentMask; [Serializable] public class CullStateChangedEvent : UnityEvent { } // Event delegates triggered on click. [SerializeField] private CullStateChangedEvent m_OnCullStateChanged = new CullStateChangedEvent(); /// /// Callback issued when culling changes. /// /// /// Called whene the culling state of this MaskableGraphic either becomes culled or visible. You can use this to control other elements of your UI as culling happens. /// public CullStateChangedEvent onCullStateChanged { get { return m_OnCullStateChanged; } set { m_OnCullStateChanged = value; } } private Canvas m_Canvas; /// /// A reference to the Canvas this Graphic is rendering to. /// /// /// In the situation where the Graphic is used in a hierarchy with multiple Canvases, the Canvas closest to the root will be used. /// public Canvas canvas { get { if (m_Canvas == null) CacheCanvas(); return m_Canvas; } } private void CacheCanvas() { var list = ListPool.Get(); gameObject.GetComponentsInParent(false, list); if (list.Count > 0) { // Find the first active and enabled canvas. for (int i = 0; i < list.Count; ++i) { if (list[i].isActiveAndEnabled) { m_Canvas = list[i]; break; } } } else { m_Canvas = null; } ListPool.Release(list); } readonly Vector3[] m_Corners = new Vector3[4]; private Rect rootCanvasRect { get { if (rectTransform == null) { return new Rect(Vector2.zero, Vector2.zero); } rectTransform.GetWorldCorners(m_Corners); if (canvas) { Matrix4x4 mat = canvas.rootCanvas.transform.worldToLocalMatrix; for (int i = 0; i < 4; ++i) m_Corners[i] = mat.MultiplyPoint(m_Corners[i]); } // bounding box is now based on the min and max of all corners (case 1013182) Vector2 min = m_Corners[0]; Vector2 max = m_Corners[0]; for (int i = 1; i < 4; i++) { min.x = Mathf.Min(m_Corners[i].x, min.x); min.y = Mathf.Min(m_Corners[i].y, min.y); max.x = Mathf.Max(m_Corners[i].x, max.x); max.y = Mathf.Max(m_Corners[i].y, max.y); } return new Rect(min, max - min); } } protected virtual void OnTransformParentChanged() { if (!isActiveAndEnabled) return; UpdateRect(Vector2.zero); UpdateClipParent(); } protected virtual void OnDisable() { if (canvasRenderer == null) return; canvasRenderer.Clear(); UpdateClipParent(); } protected void OnEnable() { UpdateRect(Vector2.zero); UpdateClipParent(); } public void OnInit() { enabled = true; UpdateRect(Vector2.zero); } protected void Start() { UpdateRect(Vector2.zero); } protected virtual void Init() { } protected void Awake() { canvasRenderer = GetComponent(); rectTransform = GetComponent(); Init(); } public RectTransform rectTransform { get; private set; } public virtual DrawType type { get { return DrawType.Default; } } public virtual long key { get; set; } public CanvasRenderer canvasRenderer { get; private set; } protected void UpdateRect(Vector2 offset) { Tools.UpdateRect(rectTransform, offset); } public virtual void UpdateSelf(float deltaTime) { } Material m_Material; Texture m_Texture; public Material srcMat { get { return m_Material; } set { m_Material = value; } } public Texture texture { get { return m_Texture; } set { m_Texture = value; } } public void FillMesh(Mesh workerMesh) { canvasRenderer.SetMesh(workerMesh); } public virtual void UpdateMaterial(Material mat) { canvasRenderer.materialCount = 1; canvasRenderer.SetMaterial(mat, 0); canvasRenderer.SetTexture(m_Texture); } public virtual void Release() { m_Material = null; m_Texture = null; key = 0; if (canvasRenderer != null) { canvasRenderer.Clear(); } } public void DestroySelf() { Tools.Destroy(gameObject); } private void UpdateClipParent() { var newParent = MaskUtilities.GetRectMaskForClippable(this); // 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; } /// /// See IClippable.RecalculateClipping /// public virtual void RecalculateClipping() { UpdateClipParent(); } /// /// See IClippable.Cull /// public virtual void Cull(Rect clipRect, bool validRect) { var cull = !validRect || !clipRect.Overlaps(rootCanvasRect, true); UpdateCull(cull); } private void UpdateCull(bool cull) { if (canvasRenderer == null) return; if (canvasRenderer.cull != cull) { canvasRenderer.cull = cull; UISystemProfilerApi.AddMarker("MaskableGraphic.cullingChanged", this); m_OnCullStateChanged.Invoke(cull); //OnCullingChanged(); if (!canvasRenderer.cull && !CanvasUpdateRegistry.IsRebuildingGraphics() && !CanvasUpdateRegistry.IsRebuildingLayout()) { /// When we were culled, we potentially skipped calls to Rebuild. CanvasUpdateRegistry.RegisterCanvasElementForGraphicRebuild(this); } } } /// /// See IClippable.SetClipRect /// public virtual void SetClipRect(Rect clipRect, bool validRect) { if (canvasRenderer == null) return; if (validRect) canvasRenderer.EnableRectClipping(clipRect); else canvasRenderer.DisableRectClipping(); } public virtual void Rebuild(CanvasUpdate executing) { } public virtual void LayoutComplete() { } public virtual void GraphicUpdateComplete() { } public virtual bool IsDestroyed() { return this == null; } public void SetClipSoftness(Vector2 clipSoftness) { } } }