// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
#if GT_USE_UGUI
using UnityEngine;
using UnityEngine.UI;
namespace Microsoft.MixedReality.GraphicsTools
{
///
/// A 2D rounded rectangular mask that allows for clipping / masking of areas outside the mask.
/// Constraints:
/// - Material instancing must be controlled by the user. i.e shared materials may be effected by RoundedRectMask2D.
/// - RoundedRectMask2D only work with Graphics Tools/Canvas/... shaders and the Graphics Tools/Standard Canvas shader.
/// - Nested RoundedRectMask's work but are not advised since they will not consider grandparent, great grandparent, etc. radii.
/// - Plus, same constraints as RectMask2D.
///
public class RoundedRectMask2D : RectMask2DFast
{
public static readonly string RoundedKeyword = "_UI_CLIP_RECT_ROUNDED";
public static readonly string RoundedIndependentKeyword = "_UI_CLIP_RECT_ROUNDED_INDEPENDENT";
public static readonly string RadiiPropertyName = "_ClipRectRadii";
[Tooltip("False if the rounded rect has the same radii for all four corners, true if they are all different.")]
[SerializeField]
protected bool independentRadii = false;
///
/// False if the rounded rect has the same radii for all four corners, true if they are all different.
///
public bool IndependentRadii
{
get => independentRadii;
set
{
independentRadii = value;
MaskUtilities.Notify2DMaskStateChanged(this);
ForceClip = true;
}
}
[Tooltip("The four corner radii of the rounded rect. (x: top left, y: top right, z: bottom left, w: bottom right)")]
[SerializeField]
protected Vector4 radii = Vector4.one * 10.0f;
///
/// If IndependentRadii is true, the four corner radii of the rounded rect. (x: top left, y: top right, z: bottom left, w: bottom right)
/// If IndependentRadii is false, the x value is used for all four corners of the rounded rec. (x: all, y: unused, z: unused, w: unused)
///
public Vector4 Radii
{
get => radii;
set
{
radii = value;
MaskUtilities.Notify2DMaskStateChanged(this);
ForceClip = true;
}
}
private static int clipRectRadiiID = 0;
#region RectMask2DFast Implementation
///
/// Lazy initialize shader IDs.
///
public override void PerformClipping()
{
if (clipRectRadiiID == 0)
{
clipRectRadiiID = Shader.PropertyToID(RadiiPropertyName);
}
base.PerformClipping();
}
///
/// enables shader keywords/properties based on the RoundedRectMask2D state.
///
protected override void OnSetClipRect(MaskableGraphic maskableTarget)
{
Material targetMaterial = maskableTarget.materialForRendering;
// TODO - [Cameron-Micka] for cleanliness we should reset these keywords/properties when done. But, since UnityUI controls the
// material's lifetime it is difficult to achieve. Fortunately the "UNITY_UI_CLIP_RECT" keyword does get reset by UnityUI which
// means the below keywords/properties no longer factor into shader computations but may dirty the material state.
if (targetMaterial != null)
{
if (IndependentRadii)
{
targetMaterial.EnableKeyword(RoundedIndependentKeyword);
targetMaterial.DisableKeyword(RoundedKeyword);
}
else
{
targetMaterial.DisableKeyword(RoundedIndependentKeyword);
targetMaterial.EnableKeyword(RoundedKeyword);
}
targetMaterial.SetVector(clipRectRadiiID, Radii);
}
}
#endregion RectMask2DFast Implementation
}
}
#endif // GT_USE_UGUI