using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace Coffee.UIExtensions { /// /// Unmask Raycast Filter. /// The ray passes through the unmasked rectangle. /// [AddComponentMenu("UI/Unmask/UnmaskRaycastFilter", 2)] public class UnmaskRaycastFilter : MonoBehaviour, ICanvasRaycastFilter { //################################ // Constant or Static Members. //################################ Vector3[] s_WorldCorners = new Vector3[4]; //################################ // Serialize Members. //################################ [Tooltip("Target unmask component. The ray passes through the unmasked rectangle.")] [SerializeField] Unmask m_TargetUnmask; //################################ // Public Members. //################################ /// /// Target unmask component. Ray through the unmasked rectangle. /// public Unmask targetUnmask{ get { return m_TargetUnmask; } set { m_TargetUnmask = value; } } /// /// Given a point and a camera is the raycast valid. /// /// Valid. /// Screen position. /// Raycast camera. public bool IsRaycastLocationValid(Vector2 sp, Camera eventCamera) { // Skip if deactived. if (!isActiveAndEnabled || !m_TargetUnmask || !m_TargetUnmask.isActiveAndEnabled) { return true; } // Get world corners for the target. (m_TargetUnmask.transform as RectTransform).GetWorldCorners(s_WorldCorners); // Convert to screen positions. var cam = eventCamera ?? Camera.main; var p = cam.WorldToScreenPoint(sp); var a = cam.WorldToScreenPoint(s_WorldCorners[0]); var b = cam.WorldToScreenPoint(s_WorldCorners[1]); var c = cam.WorldToScreenPoint(s_WorldCorners[2]); var d = cam.WorldToScreenPoint(s_WorldCorners[3]); // check left/right side var ab = Cross(p - a, b - a) < 0.0; var bc = Cross(p - b, c - b) < 0.0; var cd = Cross(p - c, d - c) < 0.0; var da = Cross(p - d, a - d) < 0.0; // check inside return ab ^ bc ||bc ^ cd ||cd ^ da; } //################################ // Private Members. //################################ /// /// This function is called when the object becomes enabled and active. /// void OnEnable() { } /// /// Cross for Vector2. /// float Cross(Vector2 a, Vector2 b) { return a.x * b.y - a.y * b.x; } } }