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);
}
}
}
}