using System; using System.Collections.Generic; using UnityEngine; namespace MPUIKIT { /// /// Gradient overlay of the image. /// [Serializable] public struct GradientEffect : IMPUIComponent { [SerializeField] private bool m_Enabled; [SerializeField] private GradientType m_GradientType; [SerializeField] private Gradient m_Gradient; [SerializeField] private Color[] m_CornerGradientColors; [SerializeField] private float m_Rotation; /// /// Enable/Disable Gradient overlay /// public bool Enabled { get => m_Enabled; set { m_Enabled = value; if (ShouldModifySharedMat) { SharedMat.SetInt(SpEnableGradient, m_Enabled?1:0); } OnComponentSettingsChanged?.Invoke(this, EventArgs.Empty); } } /// /// Type of the Gradient. There are three types: Linear, Radial, Corner /// public GradientType GradientType { get => m_GradientType; set { m_GradientType = value; if (ShouldModifySharedMat) { SharedMat.SetInt(SpGradientType, (int)m_GradientType); } OnComponentSettingsChanged?.Invoke(this, EventArgs.Empty); } } /// /// Rotation of the gradient. Only applies for Linear Gradient. /// public float Rotation { get => m_Rotation; set { m_Rotation = value; if (ShouldModifySharedMat) { SharedMat.SetFloat(SpGradientRotation, m_Rotation); } OnComponentSettingsChanged?.Invoke(this, EventArgs.Empty); } } /// /// Gradient that will be overlaid onto the image. /// public Gradient Gradient { get => m_Gradient; set { m_Gradient = value; if (ShouldModifySharedMat) { List Colors = new List(8); List Alphas = new List(8); for (int i = 0; i < 8; i++) { if (i < m_Gradient.colorKeys.Length) { Color col = m_Gradient.colorKeys[i].color; Vector4 data = new Vector4(col.r, col.g, col.b, m_Gradient.colorKeys[i].time); Colors.Add(data); SharedMat.SetVector("_GradientColor"+i, data); } else { SharedMat.SetVector("_GradientColor"+i, Vector4.zero); } if (i < m_Gradient.alphaKeys.Length) { Vector4 data = new Vector4(m_Gradient.alphaKeys[i].alpha, m_Gradient.alphaKeys[i].time); Alphas.Add(data); SharedMat.SetVector("_GradientAlpha"+i, data); } else { SharedMat.SetVector("_GradientAlpha"+i, Vector4.zero); } } SharedMat.SetInt(SpGradientColorsLength, m_Gradient.colorKeys.Length); SharedMat.SetInt(SpGradientAlphasLength, m_Gradient.alphaKeys.Length); for (int i = Colors.Count; i < 8; i++) { Colors.Add(Vector4.zero); } for (int i = Alphas.Count; i < 8; i++) { Alphas.Add(Vector4.zero); } SharedMat.SetVectorArray(SpGradientColors, Colors); SharedMat.SetVectorArray(SpGradientAlphas, Alphas); SharedMat.SetInt(SpGradientInterpolationType, (int) m_Gradient.mode); } OnComponentSettingsChanged?.Invoke(this, EventArgs.Empty); } } /// /// 4 Colors for Corner Gradient overlay. /// [0] => top-left, [1] => top-right /// [2] => bottom-left, [3] => bottom-right /// public Color[] CornerGradientColors { get => m_CornerGradientColors; set { if (m_CornerGradientColors.Length != 4) { m_CornerGradientColors = new Color[4]; } for (int i = 0; i < value.Length && i < 4; i++) { m_CornerGradientColors[i] = value[i]; } if (ShouldModifySharedMat) { for (int i = 0; i < m_CornerGradientColors.Length; i++) { SharedMat.SetColor("_CornerGradientColor"+i, m_CornerGradientColors[i]); } } OnComponentSettingsChanged?.Invoke(this, EventArgs.Empty); } } private static readonly int SpGradientType = Shader.PropertyToID("_GradientType"); private static readonly int SpGradientColors = Shader.PropertyToID("colors"); private static readonly int SpGradientAlphas = Shader.PropertyToID("alphas"); private static readonly int SpGradientColorsLength = Shader.PropertyToID("_GradientColorLength"); private static readonly int SpGradientAlphasLength = Shader.PropertyToID("_GradientAlphaLength"); private static readonly int SpGradientInterpolationType = Shader.PropertyToID("_GradientInterpolationType"); private static readonly int SpEnableGradient = Shader.PropertyToID("_EnableGradient"); private static readonly int SpGradientRotation = Shader.PropertyToID("_GradientRotation"); public Material SharedMat { get; set; } public bool ShouldModifySharedMat { get; set; } public RectTransform RectTransform { get; set; } public void Init(Material SharedMat, Material renderMat, RectTransform rectTransform) { this.SharedMat = SharedMat; this.ShouldModifySharedMat = SharedMat == renderMat; this.RectTransform = rectTransform; if (m_CornerGradientColors == null || m_CornerGradientColors.Length != 4) { m_CornerGradientColors = new Color[4]; } } public event EventHandler OnComponentSettingsChanged; public void OnValidate() { Enabled = m_Enabled; GradientType = m_GradientType; Gradient = m_Gradient; CornerGradientColors = m_CornerGradientColors; Rotation = m_Rotation; } public void InitValuesFromMaterial(ref Material material) { m_Enabled = material.GetInt(SpEnableGradient) == 1; m_GradientType = (GradientType) material.GetInt(SpGradientType); m_Rotation = material.GetFloat(SpGradientRotation); int colorLength = material.GetInt(SpGradientColorsLength); int alphaLength = material.GetInt(SpGradientAlphasLength); Gradient gradient = new Gradient(); GradientColorKey[] colorKeys = new GradientColorKey[colorLength]; GradientAlphaKey[] alphaKeys = new GradientAlphaKey[alphaLength]; for (int i = 0; i < colorLength; i++) { Vector4 colorValue = material.GetVector("_GradientColor" + i); colorKeys[i].color = new Color(colorValue.x, colorValue.y, colorValue.z); colorKeys[i].time = colorValue.w; } gradient.colorKeys = colorKeys; for (int i = 0; i < alphaLength; i++) { Vector4 alphaValue = material.GetVector("_GradientAlpha" + i); alphaKeys[i].alpha = alphaValue.x; alphaKeys[i].time = alphaValue.y; } gradient.alphaKeys = alphaKeys; gradient.mode = (GradientMode) material.GetInt(SpGradientInterpolationType); m_Gradient = gradient; m_CornerGradientColors = new Color[4]; for (int i = 0; i < CornerGradientColors.Length; i++) { CornerGradientColors[i] = material.GetColor("_CornerGradientColor" + i); } } public void ModifyMaterial(ref Material material, params object[] otherProperties) { material.DisableKeyword("GRADIENT_LINEAR"); material.DisableKeyword("GRADIENT_RADIAL"); material.DisableKeyword("GRADIENT_CORNER"); if (!m_Enabled) return; material.SetInt(SpEnableGradient, m_Enabled?1:0); material.SetInt(SpGradientType, (int)m_GradientType); switch (m_GradientType) { case GradientType.Linear: material.EnableKeyword("GRADIENT_LINEAR"); break; case GradientType.Radial: material.EnableKeyword("GRADIENT_RADIAL"); break; case GradientType.Corner: material.EnableKeyword("GRADIENT_CORNER"); break; default: throw new ArgumentOutOfRangeException(); } if (m_GradientType == GradientType.Corner) { for (int i = 0; i < m_CornerGradientColors.Length; i++) { material.SetColor("_CornerGradientColor"+i, m_CornerGradientColors[i]); } } else { Vector4[] colors = new Vector4[8]; Vector4[] alphas = new Vector4[8]; for (int i = 0; i < m_Gradient.colorKeys.Length; i++) { Color col = m_Gradient.colorKeys[i].color; colors[i] = new Vector4(col.r, col.g, col.b, m_Gradient.colorKeys[i].time); } for (int i = 0; i < m_Gradient.alphaKeys.Length; i++) { alphas[i] = new Vector4(m_Gradient.alphaKeys[i].alpha, m_Gradient.alphaKeys[i].time); } material.SetFloat(SpGradientColorsLength, m_Gradient.colorKeys.Length); material.SetFloat(SpGradientAlphasLength, m_Gradient.alphaKeys.Length); material.SetFloat(SpGradientInterpolationType, (int)m_Gradient.mode); material.SetFloat(SpGradientRotation, m_Rotation); for (int i = 0; i < colors.Length; i++) { material.SetVector("_GradientColor"+i, colors[i]); } for (int i = 0; i < alphas.Length; i++) { material.SetVector("_GradientAlpha"+i, alphas[i]); } } } } }