using System; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; namespace Michsky.UI.MTP { [AddComponentMenu("Modern UI Pack/Effects/UI Gradient")] public class UIGradient : BaseMeshEffect { public enum Type { Horizontal = 0, Vertical = 1, Diamond = 2 } public enum Blend { Override = 0, Add = 1, Multiply = 2 } [SerializeField] private Type _gradientType; [SerializeField] private Blend _blendMode = Blend.Multiply; [SerializeField] private bool _modifyVertices = true; [SerializeField] [Range(-1f, 1f)] private float _offset; [SerializeField] [Range(0.1f, 10f)] private float _zoom = 1f; [SerializeField] private Gradient _effectGradient = new Gradient { colorKeys = new GradientColorKey[2] { new GradientColorKey(Color.black, 0f), new GradientColorKey(Color.white, 1f) } }; public Blend BlendMode { get { return _blendMode; } set { _blendMode = value; base.graphic.SetVerticesDirty(); } } public Gradient EffectGradient { get { return _effectGradient; } set { _effectGradient = value; base.graphic.SetVerticesDirty(); } } public Type GradientType { get { return _gradientType; } set { _gradientType = value; base.graphic.SetVerticesDirty(); } } public bool ModifyVertices { get { return _modifyVertices; } set { _modifyVertices = value; base.graphic.SetVerticesDirty(); } } public float Offset { get { return _offset; } set { _offset = Mathf.Clamp(value, -1f, 1f); base.graphic.SetVerticesDirty(); } } public float Zoom { get { return _zoom; } set { _zoom = Mathf.Clamp(value, 0.1f, 10f); base.graphic.SetVerticesDirty(); } } public override void ModifyMesh(VertexHelper helper) { if (!IsActive() || helper.currentVertCount == 0) { return; } List list = new List(); helper.GetUIVertexStream(list); int count = list.Count; switch (GradientType) { case Type.Horizontal: case Type.Vertical: { Rect bounds2 = GetBounds(list); float num3 = bounds2.xMin; float num4 = bounds2.width; Func func = (UIVertex v) => v.position.x; if (GradientType == Type.Vertical) { num3 = bounds2.yMin; num4 = bounds2.height; func = (UIVertex v) => v.position.y; } float num5 = ((num4 == 0f) ? 0f : (1f / num4 / Zoom)); float num6 = (1f - 1f / Zoom) * 0.5f; float num7 = Offset * (1f - num6) - num6; if (ModifyVertices) { SplitTrianglesAtGradientStops(list, bounds2, num6, helper); } UIVertex vertex2 = default(UIVertex); for (int num8 = 0; num8 < helper.currentVertCount; num8++) { helper.PopulateUIVertex(ref vertex2, num8); vertex2.color = BlendColor(vertex2.color, EffectGradient.Evaluate((func(vertex2) - num3) * num5 - num7)); helper.SetUIVertex(vertex2, num8); } break; } case Type.Diamond: { Rect bounds = GetBounds(list); float num = ((bounds.height == 0f) ? 0f : (1f / bounds.height / Zoom)); float num2 = bounds.center.y / 2f; Vector3 vector = (Vector3.right + Vector3.up) * num2 + Vector3.forward * list[0].position.z; if (ModifyVertices) { helper.Clear(); for (int i = 0; i < count; i++) { helper.AddVert(list[i]); } helper.AddVert(new UIVertex { position = vector, normal = list[0].normal, uv0 = new Vector2(0.5f, 0.5f), color = Color.white }); for (int j = 1; j < count; j++) { helper.AddTriangle(j - 1, j, count); } helper.AddTriangle(0, count - 1, count); } UIVertex vertex = default(UIVertex); for (int k = 0; k < helper.currentVertCount; k++) { helper.PopulateUIVertex(ref vertex, k); vertex.color = BlendColor(vertex.color, EffectGradient.Evaluate(Vector3.Distance(vertex.position, vector) * num - Offset)); helper.SetUIVertex(vertex, k); } break; } } } private Rect GetBounds(List vertices) { float num = vertices[0].position.x; float num2 = num; float num3 = vertices[0].position.y; float num4 = num3; for (int num5 = vertices.Count - 1; num5 >= 1; num5--) { float x = vertices[num5].position.x; float y = vertices[num5].position.y; if (x > num2) { num2 = x; } else if (x < num) { num = x; } if (y > num4) { num4 = y; } else if (y < num3) { num3 = y; } } return new Rect(num, num3, num2 - num, num4 - num3); } private void SplitTrianglesAtGradientStops(List _vertexList, Rect bounds, float zoomOffset, VertexHelper helper) { List list = FindStops(zoomOffset, bounds); if (list.Count <= 0) { return; } helper.Clear(); int count = _vertexList.Count; for (int i = 0; i < count; i += 3) { float[] positions = GetPositions(_vertexList, i); List list2 = new List(3); List list3 = new List(3); List list4 = new List(2); for (int j = 0; j < list.Count; j++) { int currentVertCount = helper.currentVertCount; bool flag = list4.Count > 0; bool flag2 = false; for (int k = 0; k < 3; k++) { if (!list2.Contains(k) && positions[k] < list[j]) { int num = (k + 1) % 3; UIVertex item = _vertexList[k + i]; if (positions[num] > list[j]) { list2.Insert(0, k); list3.Insert(0, item); flag2 = true; } else { list2.Add(k); list3.Add(item); } } } if (list2.Count == 0) { continue; } if (list2.Count == 3) { break; } foreach (UIVertex item3 in list3) { helper.AddVert(item3); } list4.Clear(); foreach (int item4 in list2) { int num2 = (item4 + 1) % 3; if (positions[num2] < list[j]) { num2 = (num2 + 1) % 3; } list4.Add(CreateSplitVertex(_vertexList[item4 + i], _vertexList[num2 + i], list[j])); } if (list4.Count == 1) { int num3 = (list2[0] + 2) % 3; list4.Add(CreateSplitVertex(_vertexList[list2[0] + i], _vertexList[num3 + i], list[j])); } foreach (UIVertex item5 in list4) { helper.AddVert(item5); } if (flag) { helper.AddTriangle(currentVertCount - 2, currentVertCount, currentVertCount + 1); helper.AddTriangle(currentVertCount - 2, currentVertCount + 1, currentVertCount - 1); if (list3.Count > 0) { if (flag2) { helper.AddTriangle(currentVertCount - 2, currentVertCount + 3, currentVertCount); } else { helper.AddTriangle(currentVertCount + 1, currentVertCount + 3, currentVertCount - 1); } } } else { int currentVertCount2 = helper.currentVertCount; helper.AddTriangle(currentVertCount, currentVertCount2 - 2, currentVertCount2 - 1); if (list3.Count > 1) { helper.AddTriangle(currentVertCount, currentVertCount2 - 1, currentVertCount + 1); } } list3.Clear(); } if (list4.Count > 0) { if (list3.Count == 0) { for (int l = 0; l < 3; l++) { if (!list2.Contains(l) && positions[l] > list[list.Count - 1]) { int num4 = (l + 1) % 3; UIVertex item2 = _vertexList[l + i]; if (positions[num4] > list[list.Count - 1]) { list3.Insert(0, item2); } else { list3.Add(item2); } } } } foreach (UIVertex item6 in list3) { helper.AddVert(item6); } int currentVertCount3 = helper.currentVertCount; if (list3.Count > 1) { helper.AddTriangle(currentVertCount3 - 4, currentVertCount3 - 2, currentVertCount3 - 1); helper.AddTriangle(currentVertCount3 - 4, currentVertCount3 - 1, currentVertCount3 - 3); } else if (list3.Count > 0) { helper.AddTriangle(currentVertCount3 - 3, currentVertCount3 - 1, currentVertCount3 - 2); } } else { helper.AddVert(_vertexList[i]); helper.AddVert(_vertexList[i + 1]); helper.AddVert(_vertexList[i + 2]); int currentVertCount4 = helper.currentVertCount; helper.AddTriangle(currentVertCount4 - 3, currentVertCount4 - 2, currentVertCount4 - 1); } } } private float[] GetPositions(List _vertexList, int index) { float[] array = new float[3]; if (GradientType == Type.Horizontal) { array[0] = _vertexList[index].position.x; array[1] = _vertexList[index + 1].position.x; array[2] = _vertexList[index + 2].position.x; } else { array[0] = _vertexList[index].position.y; array[1] = _vertexList[index + 1].position.y; array[2] = _vertexList[index + 2].position.y; } return array; } private List FindStops(float zoomOffset, Rect bounds) { List list = new List(); float num = Offset * (1f - zoomOffset); float num2 = zoomOffset - num; float num3 = 1f - zoomOffset - num; GradientColorKey[] colorKeys = EffectGradient.colorKeys; for (int i = 0; i < colorKeys.Length; i++) { GradientColorKey gradientColorKey = colorKeys[i]; if (gradientColorKey.time >= num3) { break; } if (gradientColorKey.time > num2) { list.Add((gradientColorKey.time - num2) * Zoom); } } GradientAlphaKey[] alphaKeys = EffectGradient.alphaKeys; for (int i = 0; i < alphaKeys.Length; i++) { GradientAlphaKey gradientAlphaKey = alphaKeys[i]; if (gradientAlphaKey.time >= num3) { break; } if (gradientAlphaKey.time > num2) { list.Add((gradientAlphaKey.time - num2) * Zoom); } } float num4 = bounds.xMin; float num5 = bounds.width; if (GradientType == Type.Vertical) { num4 = bounds.yMin; num5 = bounds.height; } list.Sort(); for (int j = 0; j < list.Count; j++) { list[j] = list[j] * num5 + num4; if (j > 0 && Math.Abs(list[j] - list[j - 1]) < 2f) { list.RemoveAt(j); j--; } } return list; } private UIVertex CreateSplitVertex(UIVertex vertex1, UIVertex vertex2, float stop) { if (GradientType == Type.Horizontal) { float num = vertex1.position.x - stop; float num2 = vertex1.position.x - vertex2.position.x; float num3 = vertex1.position.y - vertex2.position.y; float num4 = vertex1.uv0.x - vertex2.uv0.x; float num5 = vertex1.uv0.y - vertex2.uv0.y; float num6 = num / num2; float y = vertex1.position.y - num3 * num6; return new UIVertex { position = new Vector3(stop, y, vertex1.position.z), normal = vertex1.normal, uv0 = new Vector2(vertex1.uv0.x - num4 * num6, vertex1.uv0.y - num5 * num6), color = Color.white }; } float num7 = vertex1.position.y - stop; float num8 = vertex1.position.y - vertex2.position.y; float num9 = vertex1.position.x - vertex2.position.x; float num10 = vertex1.uv0.x - vertex2.uv0.x; float num11 = vertex1.uv0.y - vertex2.uv0.y; float num12 = num7 / num8; float x = vertex1.position.x - num9 * num12; return new UIVertex { position = new Vector3(x, stop, vertex1.position.z), normal = vertex1.normal, uv0 = new Vector2(vertex1.uv0.x - num10 * num12, vertex1.uv0.y - num11 * num12), color = Color.white }; } private Color BlendColor(Color colorA, Color colorB) { return BlendMode switch { Blend.Add => colorA + colorB, Blend.Multiply => colorA * colorB, _ => colorB, }; } } }