using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Rendering; using UnityEngine.UI; namespace Coffee.UIExtensions { /// /// Reverse masking for parent Mask component. /// [ExecuteInEditMode] [AddComponentMenu("UI/Unmask/Unmask", 1)] public class Unmask : MonoBehaviour, IMaterialModifier { //################################ // Constant or Static Members. //################################ static readonly Vector2 s_Center = new Vector2(0.5f, 0.5f); //################################ // Serialize Members. //################################ [Tooltip("Fit graphic's transform to target transform on LateUpdate.")] [SerializeField] RectTransform m_AutoFitTarget; [Tooltip("Show the graphic that is associated with the unmask render area.")] [SerializeField] bool m_ShowUnmaskGraphic = false; //################################ // Public Members. //################################ /// /// The graphic associated with the unmask. /// public Graphic graphic{ get { return _graphic ?? (_graphic = GetComponent()); } } /// /// Fit graphic's transform to target transform on LateUpdate. /// public RectTransform autoFitTarget{ get { return m_AutoFitTarget; } set { m_AutoFitTarget = value; } } /// /// Show the graphic that is associated with the unmask render area. /// public bool showUnmaskGraphic { get { return m_ShowUnmaskGraphic; } set { m_ShowUnmaskGraphic = value; SetDirty(); } } /// /// Perform material modification in this function. /// /// Modified material. /// Configured Material. public Material GetModifiedMaterial(Material baseMaterial) { if (!isActiveAndEnabled) { return baseMaterial; } Transform stopAfter = MaskUtilities.FindRootSortOverrideCanvas(transform); var stencilDepth = MaskUtilities.GetStencilDepth(transform, stopAfter); StencilMaterial.Remove(_unmaskMaterial); _unmaskMaterial = StencilMaterial.Add(baseMaterial, (1 << stencilDepth) - 1, StencilOp.Zero, CompareFunction.Always, m_ShowUnmaskGraphic ? ColorWriteMask.All : (ColorWriteMask)0, 0, (1 << stencilDepth) - 1); //StencilMaterial.Remove (baseMaterial); return _unmaskMaterial; } /// /// Fit to target transform. /// /// Target transform. public void FitTo(RectTransform target) { var rt = transform as RectTransform; rt.position = target.position; rt.rotation = target.rotation; var s1 = target.lossyScale; var s2 = rt.parent.lossyScale; rt.localScale = new Vector3(s1.x / s2.x, s1.y / s2.y, s1.z / s2.z); rt.sizeDelta = target.rect.size; rt.anchorMax = rt.anchorMin = s_Center; } //################################ // Private Members. //################################ Material _unmaskMaterial; Graphic _graphic; /// /// This function is called when the object becomes enabled and active. /// void OnEnable() { if (m_AutoFitTarget) { FitTo(m_AutoFitTarget); } SetDirty(); } /// /// This function is called when the behaviour becomes disabled () or inactive. /// void OnDisable() { StencilMaterial.Remove(_unmaskMaterial); _unmaskMaterial = null; SetDirty(); } /// /// LateUpdate is called every frame, if the Behaviour is enabled. /// void LateUpdate() { if (m_AutoFitTarget) { FitTo(m_AutoFitTarget); } } /// /// This function is called when the script is loaded or a value is changed in the inspector (Called in the editor only). /// void OnValidate() { SetDirty(); } /// /// Mark the graphic as dirty. /// void SetDirty() { if (graphic) { graphic.SetMaterialDirty(); } } } }