using UnityEngine; using UnityEngine.UI; namespace Coffee.UIEffects { /// /// UIGradient. /// [DisallowMultipleComponent] [AddComponentMenu("UI/UIEffects/UIGradient", 101)] public class UIGradient : BaseMeshEffect { static readonly Vector2[] s_SplitedCharacterPosition = {Vector2.up, Vector2.one, Vector2.right, Vector2.zero}; /// /// Gradient direction. /// public enum Direction { Horizontal, Vertical, Angle, Diagonal, } /// /// Gradient space for Text. /// public enum GradientStyle { Rect, Fit, Split, } [Tooltip("Gradient Direction.")] [SerializeField] Direction m_Direction; [Tooltip("Color1: Top or Left.")] [SerializeField] Color m_Color1 = Color.white; [Tooltip("Color2: Bottom or Right.")] [SerializeField] Color m_Color2 = Color.white; [Tooltip("Color3: For diagonal.")] [SerializeField] Color m_Color3 = Color.white; [Tooltip("Color4: For diagonal.")] [SerializeField] Color m_Color4 = Color.white; [Tooltip("Gradient rotation.")] [SerializeField] [Range(-180, 180)] float m_Rotation; [Tooltip("Gradient offset for Horizontal, Vertical or Angle.")] [SerializeField] [Range(-1, 1)] float m_Offset1; [Tooltip("Gradient offset for Diagonal.")] [SerializeField] [Range(-1, 1)] float m_Offset2; [Tooltip("Gradient style for Text.")] [SerializeField] GradientStyle m_GradientStyle; [Tooltip("Color space to correct color.")] [SerializeField] ColorSpace m_ColorSpace = ColorSpace.Uninitialized; [Tooltip("Ignore aspect ratio.")] [SerializeField] bool m_IgnoreAspectRatio = true; /// /// Gradient Direction. /// public Direction direction { get { return m_Direction; } set { if (m_Direction == value) return; m_Direction = value; SetVerticesDirty(); } } /// /// Color1: Top or Left. /// public Color color1 { get { return m_Color1; } set { if (m_Color1 == value) return; m_Color1 = value; SetVerticesDirty(); } } /// /// Color2: Bottom or Right. /// public Color color2 { get { return m_Color2; } set { if (m_Color2 == value) return; m_Color2 = value; SetVerticesDirty(); } } /// /// Color3: For diagonal. /// public Color color3 { get { return m_Color3; } set { if (m_Color3 == value) return; m_Color3 = value; SetVerticesDirty(); } } /// /// Color4: For diagonal. /// public Color color4 { get { return m_Color4; } set { if (m_Color4 == value) return; m_Color4 = value; SetVerticesDirty(); } } /// /// Gradient rotation. /// public float rotation { get { return m_Direction == Direction.Horizontal ? -90 : m_Direction == Direction.Vertical ? 0 : m_Rotation; } set { if (Mathf.Approximately(m_Rotation, value)) return; m_Rotation = value; SetVerticesDirty(); } } /// /// Gradient offset for Horizontal, Vertical or Angle. /// public float offset { get { return m_Offset1; } set { if (Mathf.Approximately(m_Offset1, value)) return; m_Offset1 = value; SetVerticesDirty(); } } /// /// Gradient offset for Diagonal. /// public Vector2 offset2 { get { return new Vector2(m_Offset2, m_Offset1); } set { if (Mathf.Approximately(m_Offset1, value.y) && Mathf.Approximately(m_Offset2, value.x)) return; m_Offset1 = value.y; m_Offset2 = value.x; SetVerticesDirty(); } } /// /// Gradient style for Text. /// public GradientStyle gradientStyle { get { return m_GradientStyle; } set { if (m_GradientStyle == value) return; m_GradientStyle = value; SetVerticesDirty(); } } /// /// Color space to correct color. /// public ColorSpace colorSpace { get { return m_ColorSpace; } set { if (m_ColorSpace == value) return; m_ColorSpace = value; SetVerticesDirty(); } } /// /// Ignore aspect ratio. /// public bool ignoreAspectRatio { get { return m_IgnoreAspectRatio; } set { if (m_IgnoreAspectRatio == value) return; m_IgnoreAspectRatio = value; SetVerticesDirty(); } } /// /// Call used to modify mesh. /// public override void ModifyMesh(VertexHelper vh, Graphic graphic) { if (!isActiveAndEnabled) return; // Gradient space. var rect = default(Rect); var vertex = default(UIVertex); switch (m_GradientStyle) { case GradientStyle.Rect: // RectTransform. rect = graphic.rectTransform.rect; break; case GradientStyle.Split: // Each characters. rect.Set(0, 0, 1, 1); break; case GradientStyle.Fit: { // Fit to contents. rect.xMin = rect.yMin = float.MaxValue; rect.xMax = rect.yMax = float.MinValue; for (var i = 0; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); rect.xMin = Mathf.Min(rect.xMin, vertex.position.x); rect.yMin = Mathf.Min(rect.yMin, vertex.position.y); rect.xMax = Mathf.Max(rect.xMax, vertex.position.x); rect.yMax = Mathf.Max(rect.yMax, vertex.position.y); } break; } } // Gradient rotation. var rad = rotation * Mathf.Deg2Rad; var dir = new Vector2(Mathf.Cos(rad), Mathf.Sin(rad)); if (!m_IgnoreAspectRatio && Direction.Angle <= m_Direction) { dir.x *= rect.height / rect.width; dir = dir.normalized; } // Calculate vertex color. var localMatrix = new Matrix2x3(rect, dir.x, dir.y); // Get local matrix. for (var i = 0; i < vh.currentVertCount; i++) { vh.PopulateUIVertex(ref vertex, i); // Normalize vertex position by local matrix. Vector2 normalizedPos; if (m_GradientStyle == GradientStyle.Split) { // Each characters. normalizedPos = localMatrix * s_SplitedCharacterPosition[i % 4] + offset2; } else { normalizedPos = localMatrix * vertex.position + offset2; } // Interpolate vertex color. Color color; if (direction == Direction.Diagonal) { color = Color.LerpUnclamped( Color.LerpUnclamped(m_Color1, m_Color2, normalizedPos.x), Color.LerpUnclamped(m_Color3, m_Color4, normalizedPos.x), normalizedPos.y); } else { color = Color.LerpUnclamped(m_Color2, m_Color1, normalizedPos.y); } // Correct color. vertex.color *= (m_ColorSpace == ColorSpace.Gamma) ? color.gamma : (m_ColorSpace == ColorSpace.Linear) ? color.linear : color; vh.SetUIVertex(vertex, i); } } } }