using System.Collections.Generic; using System; using System.Linq; namespace UnityEngine.UI { public class UXImage : Image { public enum ColorType { Solid_Color, Gradient_Color } [SerializeField] public ColorType m_ColorType = ColorType.Solid_Color; [SerializeField] private Gradient m_GradientColor = new Gradient() { colorKeys = new GradientColorKey[2] { // Add your colour and specify the stop point new GradientColorKey(new Color(0, 0, 0), 0), new GradientColorKey(new Color(1, 1, 1), 1) }, // This sets the alpha to 1 at both ends of the gradient alphaKeys = new GradientAlphaKey[2] { new GradientAlphaKey(1, 0), new GradientAlphaKey(1, 1) } }; public Gradient gradient { get { return m_GradientColor; } set { m_GradientColor = value; SetVerticesDirty(); } } public enum GradientDirection { Vertical, Horizontal } [SerializeField] private GradientDirection m_Direction = GradientDirection.Vertical; public GradientDirection Direction { get { return m_Direction; } set { m_Direction = Direction; } } //这个用于标记属于哪个镜像区域 public enum FlipPart { Part1 = 0, Part2 = 1, Part3 = 2, Part4 = 3, } public enum FlipDirection { None = 0, Horziontal = 1, Vertical = 2, FourCorner = 3, HorizontalNotCopy = 4, VerticalNotCopy = 5, DiagonalNotCopy = 6, } public enum FlipMode { None = 0, Horziontal = 1, Vertical = 2, FourCorner = 3, } public enum FlipEdge { None = -1, Left = 0, HorzMiddle = 1, Right = 2, Up = 3, VertMiddle = 4, Down = 5 } public enum FlipEdgeHorizontal { Left = 0, Middle = 1, Right = 2, } public enum FlipEdgeVertical { Up = 3, Middle = 4, Down = 5 } public enum FlipFillCenter { LeftTop, RightTop, RightBottom, LeftBottom } public FlipMode m_OriginFlipMode = FlipMode.None; public FlipMode m_FlipMode = FlipMode.None; public FlipMode flipMode { get { return m_FlipMode; } set { SetVerticesDirty(); } } public bool m_FlipWithCopy = true; public bool flipWithCopy { get { return m_FlipWithCopy; } set { SetVerticesDirty(); } } public FlipEdge flipEdge { get { if (m_FlipMode == FlipMode.Horziontal) { return (FlipEdge)(int)m_FlipEdgeHorizontal; } if (m_FlipMode == FlipMode.Vertical) { return (FlipEdge)(int)m_FlipEdgeVertical; } return FlipEdge.None; } set { SetVerticesDirty(); } } public FlipEdgeHorizontal m_FlipEdgeHorizontal = FlipEdgeHorizontal.Right; public FlipEdgeHorizontal flipEdgeHorizontal { get { return m_FlipEdgeHorizontal; } set { SetVerticesDirty(); } } public FlipEdgeVertical m_FlipEdgeVertical = FlipEdgeVertical.Down; public FlipEdgeVertical flipEdgeVertical { get { return m_FlipEdgeVertical; } set { SetVerticesDirty(); } } public FlipFillCenter m_FlipFillCenter = FlipFillCenter.LeftBottom; public FlipFillCenter flipFillCenter { get { return m_FlipFillCenter; } set { SetVerticesDirty(); } } [SerializeField] public FlipDirection m_FlipDirection = FlipDirection.FourCorner; public FlipDirection flipDirection { get { return m_FlipDirection; } set { SetVerticesDirty(); } } static Rect rect = new Rect(); static UIVertex vert = new UIVertex(); private static readonly Vector4 s_DefaultTangent = new Vector4(1.0f, 0.0f, 0.0f, -1.0f); private static readonly Vector3 s_DefaultNormal = Vector3.back; /// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top. private Vector4 GetDrawingDimensions(bool shouldPreserveAspect) { var padding = overrideSprite == null ? Vector4.zero : Sprites.DataUtility.GetPadding(overrideSprite); var size = overrideSprite == null ? new Vector2(rectTransform.rect.width, rectTransform.rect.height) : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); Rect r = GetPixelRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); int spriteW = Mathf.RoundToInt(size.x); int spriteH = Mathf.RoundToInt(size.y); var v = new Vector4( padding.x / spriteW, padding.y / spriteH, (spriteW - padding.z) / spriteW, (spriteH - padding.w) / spriteH); if (shouldPreserveAspect && size.sqrMagnitude > 0.0f) { PreserveSpriteAspectRatio(ref r, size); } v = new Vector4( r.x + r.width * v.x, r.y + r.height * v.y, r.x + r.width * v.z, r.y + r.height * v.w ); return v; } private void ResizeByFlip() { if (flipMode == FlipMode.Horziontal && flipWithCopy) { RectTransform trans = transform as RectTransform; trans.sizeDelta = new Vector2(trans.sizeDelta.x * 2, trans.sizeDelta.y); } if (flipMode == FlipMode.Vertical && flipWithCopy) { RectTransform trans = transform as RectTransform; trans.sizeDelta = new Vector2(trans.sizeDelta.x, trans.sizeDelta.y * 2); } if (flipMode == FlipMode.FourCorner) { RectTransform trans = transform as RectTransform; trans.sizeDelta = new Vector2(trans.sizeDelta.x * 2, trans.sizeDelta.y * 2); } } protected void OnPopulateMesh1(VertexHelper toFill) { //ResizeByFlip(); //if (overrideSprite == null) //{ // //support pure color fill // switch (m_ColorFillType) // { // case ColorFillType.None: // GenerateEmpytSprite(toFill); // break; // case ColorFillType.Filled: // GenerateFilledSprite(toFill, preserveAspect); // break; // } //} //else { UnityEngine.Profiling.Profiler.BeginSample(GetType().Name + ".OnPopulateMesh:" + type); switch (type) { case Type.Simple: if (!useSpriteMesh) { UnityEngine.Profiling.Profiler.BeginSample(GetType().Name + ".OnPopulateMesh:" + type + ", GenerateSimpleSprite"); GenerateSimpleSprite(toFill, preserveAspect); UnityEngine.Profiling.Profiler.EndSample(); } else { UnityEngine.Profiling.Profiler.BeginSample(GetType().Name + ".OnPopulateMesh:" + type + ", GenerateSprite"); GenerateSprite(toFill, preserveAspect); UnityEngine.Profiling.Profiler.EndSample(); } break; case Type.Sliced: GenerateSlicedSprite(toFill); break; case Type.Tiled: GenerateTiledSprite(toFill); break; case Type.Filled: GenerateFilledSprite(toFill, preserveAspect); break; } UnityEngine.Profiling.Profiler.EndSample(); } rect = GetDrawPixelAdjustedRect(); if (flipMode == FlipMode.Horziontal) { if (flipWithCopy) { CopyImage(toFill); Rect src = GetPixelRectByFlipDirection(FlipMode.Horziontal, flipWithCopy, flipEdge, flipFillCenter); Rect target = GetCopyRectByFlipDirection(src, FlipMode.Horziontal, flipEdge); //Rect target = new Rect(src.position - new Vector2(src.width, 0), src.size); RemapImage(toFill, FlipMode.Horziontal, toFill.currentVertCount / 2, toFill.currentVertCount, src.xMin, src.xMax, target.xMax, target.xMin); } else { RemapImage(toFill, FlipMode.Horziontal, 0, toFill.currentVertCount, rect.xMin, rect.xMax, rect.xMax, rect.xMin); } } if (flipMode == FlipMode.Vertical) { if (flipWithCopy) { CopyImage(toFill); Rect src = GetPixelRectByFlipDirection(FlipMode.Vertical, flipWithCopy, flipEdge, flipFillCenter); Rect target = GetCopyRectByFlipDirection(src, FlipMode.Vertical, flipEdge); RemapImage(toFill, FlipMode.Vertical, toFill.currentVertCount / 2, toFill.currentVertCount, src.yMin, src.yMax, target.yMax, target.yMin); } else { RemapImage(toFill, FlipMode.Vertical, 0, toFill.currentVertCount, rect.xMin, rect.xMax, rect.xMax, rect.xMin); } } if (flipMode == FlipMode.FourCorner) { //先水平拷贝 CopyImage(toFill); Rect src = GetPixelRectByFlipDirection(FlipMode.FourCorner, true, flipEdge, flipFillCenter); Rect target = GetCopyRectByFlipCenter(src, FlipMode.Horziontal, flipFillCenter); //Rect target = new Rect(src.position + new Vector2(src.width, 0), src.size); RemapImage(toFill, FlipMode.Horziontal, toFill.currentVertCount / 2, toFill.currentVertCount, src.xMin, src.xMax, target.xMax, target.xMin); //再垂直拷贝 CopyImage(toFill); Rect src1 = GetPixelRectByFlipDirection(FlipMode.FourCorner, true, flipEdge, flipFillCenter); Rect target1 = GetCopyRectByFlipCenter(src1, FlipMode.Vertical, flipFillCenter); RemapImage(toFill, FlipMode.Vertical, toFill.currentVertCount / 2, toFill.currentVertCount, src1.yMin, src1.yMax, target1.yMax, target1.yMin); } m_OriginFlipMode = m_FlipMode; /* if (flipDirection == FlipDirection.HorizontalNotCopy || flipDirection == FlipDirection.DiagonalNotCopy) { RemapImage(toFill, FlipDirection.Horziontal, 0, toFill.currentVertCount, rect.xMin, rect.xMax, rect.xMax, rect.xMin); } if (flipDirection == FlipDirection.VerticalNotCopy || flipDirection == FlipDirection.DiagonalNotCopy) { RemapImage(toFill, FlipDirection.Vertical, 0, toFill.currentVertCount, rect.yMin, rect.yMax, rect.yMax, rect.yMin); } if (flipDirection == FlipDirection.Horziontal || flipDirection == FlipDirection.FourCorner) { CopyImage(toFill); Rect src = GetPixelRectByFlipDirection(FlipDirection.Horziontal); Rect target = new Rect(src.position + new Vector2(src.width, 0), src.size); RemapImage(toFill, FlipDirection.Horziontal, toFill.currentVertCount / 2, toFill.currentVertCount, src.xMin, src.xMax, target.xMax, target.xMin); } if (flipDirection == FlipDirection.Vertical || flipDirection == FlipDirection.FourCorner) { CopyImage(toFill); Rect src = GetPixelRectByFlipDirection(FlipDirection.Vertical); Rect target = new Rect(src.position - new Vector2(0, src.height), src.size); RemapImage(toFill, FlipDirection.Vertical, toFill.currentVertCount / 2, toFill.currentVertCount, src.yMin, src.yMax, target.yMax, target.yMin); } */ } #region Flip private FlipPart GetFlipPart(int index, int vertCount) { switch (flipDirection) { case FlipDirection.None: return FlipPart.Part1; case FlipDirection.Horziontal: case FlipDirection.Vertical: return index < vertCount / 2 ? FlipPart.Part1 : FlipPart.Part2; case FlipDirection.FourCorner: if (index < vertCount / 4) { return FlipPart.Part1; } else if (index < vertCount / 2) { return FlipPart.Part2; } else if (index < vertCount * 3 / 4) { return FlipPart.Part3; } else { return FlipPart.Part4; } } return FlipPart.Part1; } //TODO: 改变加点规则 private void CopyImage(VertexHelper toFill) { int count = toFill.currentVertCount; for (int i = 0; i < count; ++i) { toFill.PopulateUIVertex(ref vert, i % count); toFill.AddVert(vert); } for (int i = count; i < 2 * count - 2; i += 4) { toFill.AddTriangle(i, i + 1, i + 2); toFill.AddTriangle(i + 2, i + 3, i); } } private void RemapImage(VertexHelper toFill, FlipMode flipMode, int indexMin, int indexMax, float Min1, float Max1, float Min2, float Max2) { for (int i = indexMin; i < indexMax; i++) { toFill.PopulateUIVertex(ref vert, i); RemapVertex(ref vert, flipMode, Min1, Max1, Min2, Max2); toFill.SetUIVertex(vert, i); } } public void RemapVertex(ref UIVertex vertex, FlipMode flipMode, float Min1, float Max1, float Min2, float Max2) { Vector2 position = vertex.position; float k = (Min2 - Max2) / (Min1 - Max1); float b = Min2 - Min1 * k; //水平方向,左侧图像方向不变,右侧图像翻转 if (flipMode == FlipMode.Horziontal) { vertex.position = new Vector2(position.x * k + b, position.y); } //垂直方向,上方图像方向不变,下方图像翻转 if (flipMode == FlipMode.Vertical) { vertex.position = new Vector2(position.x, position.y * k + b); } } Rect GetDrawPixelAdjustedRect() { Rect rect = GetPixelAdjustedRect(); return rect; } private Rect GetPixelRectByFlipDirection(FlipMode flipMode, bool copy, FlipEdge flipEdge, FlipFillCenter fillCenter) { Rect rect = GetDrawPixelAdjustedRect(); return ModifyRectByFlipDirection(rect, flipMode, copy, flipEdge, fillCenter); } private Rect GetRectByFlipDirection(FlipMode flipMode, bool copy, FlipEdge flipEdge, FlipFillCenter fillCenter) { Rect rect = rectTransform.rect; return ModifyRectByFlipDirection(rect, flipMode, copy, flipEdge, fillCenter); } /// /// 修改原来的Rect /// 如果 flipMode == Horziontal 或 Vertical, 根据copy, flipEdge来修改原本的Rect /// 如果 flipMode == FourCorner, 根据flipFillCenter 来修改 /// /// Image原始Rect private Rect ModifyRectByFlipDirection(Rect rect, FlipMode flipMode, bool copy, FlipEdge flipEdge, FlipFillCenter fillCenter) { if (flipMode == FlipMode.Horziontal) { if (copy) { if (flipEdge == FlipEdge.Left) { rect = new Rect(rect.center.x, rect.yMin, rect.width / 2, rect.height); } if (flipEdge == FlipEdge.Right) { rect = new Rect(rect.xMin, rect.yMin, rect.width / 2, rect.height); } } } if (flipMode == FlipMode.Vertical) { if (copy) { if (flipEdge == FlipEdge.Up) { rect = new Rect(rect.xMin, rect.yMin, rect.width, rect.height / 2); } if (flipEdge == FlipEdge.Down) { rect = new Rect(rect.xMin, rect.center.y, rect.width, rect.height / 2); } } } if (flipMode == FlipMode.FourCorner) { if (fillCenter == FlipFillCenter.LeftBottom) { rect = new Rect(rect.center.x, rect.center.y, rect.width / 2, rect.height / 2); } if (fillCenter == FlipFillCenter.LeftTop) { rect = new Rect(rect.center.x, rect.yMin, rect.width / 2, rect.height / 2); } if (fillCenter == FlipFillCenter.RightTop) { rect = new Rect(rect.xMin, rect.yMin, rect.width / 2, rect.height / 2); } if (fillCenter == FlipFillCenter.RightBottom) { rect = new Rect(rect.xMin, rect.center.y, rect.width / 2, rect.height / 2); } } return rect; } /// /// 获取Copy出来的Rect /// 这里Src应该是Modify过的原Rect /// 只处理flipMode == Horziontal 或 Vertical的情况 /// /// /// /// /// private Rect GetCopyRectByFlipDirection(Rect src, FlipMode flipMode, FlipEdge flipEdge) { Rect target = new Rect(); if (flipMode == FlipMode.None) { target = src; } if (flipMode == FlipMode.Horziontal) { if (flipEdge == FlipEdge.Left) { target = new Rect(src.position - new Vector2(src.width, 0), src.size); } if (flipEdge == FlipEdge.HorzMiddle) { target = src; } if (flipEdge == FlipEdge.Right) { target = new Rect(src.position + new Vector2(src.width, 0), src.size); } } if (flipMode == FlipMode.Vertical) { if (flipEdge == FlipEdge.Up) { target = new Rect(src.position + new Vector2(0, src.height), src.size); } if (flipEdge == FlipEdge.VertMiddle) { target = src; } if (flipEdge == FlipEdge.Down) { target = new Rect(src.position - new Vector2(0, src.height), src.size); } } return target; } /// /// 获取Copy出来的Rect, flipMode == FourCorner时专用 /// flipMode == FourCorner时会转换成两次Copy /// 分别调用GetCopyRectByFlipDirection /// 这里Src应该是Modify过的原Rect /// /// /// /// /// private Rect GetCopyRectByFlipCenter(Rect src, FlipMode flipMode, FlipFillCenter fillCenter) { Rect target = new Rect(); if (flipMode == FlipMode.Horziontal) { if (fillCenter == FlipFillCenter.LeftBottom || fillCenter == FlipFillCenter.LeftTop) { target = GetCopyRectByFlipDirection(src, FlipMode.Horziontal, FlipEdge.Left); } else { target = GetCopyRectByFlipDirection(src, FlipMode.Horziontal, FlipEdge.Right); } } if (flipMode == FlipMode.Vertical) { if (fillCenter == FlipFillCenter.LeftTop || fillCenter == FlipFillCenter.RightTop) { target = GetCopyRectByFlipDirection(src, FlipMode.Vertical, FlipEdge.Up); } else { target = GetCopyRectByFlipDirection(src, FlipMode.Vertical, FlipEdge.Down); } } return target; } private void PreserveSpriteAspectRatio(ref Rect r, Vector2 size) { var spriteRatio = size.x / size.y; var rectRatio = r.width / r.height; if (spriteRatio > rectRatio) { var oldHeight = r.height; r.height = r.width * (1.0f / spriteRatio); r.y += (oldHeight - r.height) * rectTransform.pivot.y; } else { var oldWidth = r.width; r.width = r.height * spriteRatio; r.x += (oldWidth - r.width) * rectTransform.pivot.x; } } private void GenerateSimpleSprite(VertexHelper vh, bool lPreserveAspect) { Vector4 v = GetDrawingDimensions(lPreserveAspect); var uv = (overrideSprite != null) ? Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; vh.Clear(); AddQuad(vh, new Vector2(v.x, v.y), new Vector2(v.z, v.w), color, new Vector2(uv.x, uv.y), new Vector2(uv.z, uv.w), Vector2.zero, Vector2.one); } #endregion #region gradient public class Vert2D //描述alphakey和colorkey的类 { public Vector3 position = default; public Color color = Color.white; public Vector2 uv0 = default; public int type;//1=alphakey,2=colorkey, 0=两端 public Vert2D(int type) { this.type = type; } public Vert2D(UIVertex vertex) { type = 0; } public int CompareToVertically(Vert2D vert) { if (this.uv0.y > vert.uv0.y) return 1; else if (this.uv0.y == vert.uv0.y) { if (this.uv0.x <= vert.uv0.x) { return -1; } else return 1; } else return -1; } public int CompareToHorizontally(Vert2D vert) { if (this.uv0.x > vert.uv0.x) return 1; else if (this.uv0.x == vert.uv0.x) { if (this.uv0.y <= vert.uv0.y) { return -1; } else return 1; } else return -1; } // public void SetColor(byte r, byte g, byte b){ // this.color.r = r; // this.color.g = g; // this.color.b = b; // } public void SetColor(Color col) { this.color.r = col.r; this.color.g = col.g; this.color.b = col.b; } public void SetAlpha(float a) { this.color.a = a; } public void SetUV(float u, float v) { this.uv0.x = u; this.uv0.y = v; } public void SetPosition(Vector3 pos) { this.position.x = pos.x; this.position.y = pos.y; this.position.z = pos.z; } } public class Comparer : IEqualityComparer { public bool Equals(Vert2D x, Vert2D y) { //这里定义比较的逻辑 return x.uv0 == y.uv0; } public int GetHashCode(Vert2D obj) { //返回字段的HashCode,只有HashCode相同才会去比较 return obj.uv0.GetHashCode(); } } void PositionLerp(List vlist, Vector2 minpos, Vector2 maxpos) { if (m_Direction == GradientDirection.Horizontal) { for (int i = 0; i < vlist.Count; i++) { Vector3 temppos = Vector3.Lerp(minpos, maxpos, vlist[i].uv0.x); if (vlist[i].uv0.y == 1) { temppos.y = maxpos.y; } else { temppos.y = minpos.y; } vlist[i].SetPosition(temppos); } } else if (m_Direction == GradientDirection.Vertical) { for (int i = 0; i < vlist.Count; i++) { Vector3 temppos = Vector3.Lerp(minpos, maxpos, vlist[i].uv0.y); if (vlist[i].uv0.x == 1) { temppos.x = maxpos.x; } else { temppos.x = minpos.x; } vlist[i].SetPosition(temppos); } } } void UVShrink(List vlist, Vector2 uvmin, Vector2 uvmax) { foreach (Vert2D v in vlist) { v.uv0.x = (uvmax.x - uvmin.x) * v.uv0.x + uvmin.x; v.uv0.y = (uvmax.y - uvmin.y) * v.uv0.y + uvmin.y; } } protected override void OnPopulateMesh(VertexHelper toFill) { if (m_ColorType == ColorType.Solid_Color) { OnPopulateMesh1(toFill); } else if (m_ColorType == ColorType.Gradient_Color) { //根据Gradient,新建mesh GradientAlphaKey[] alpha = m_GradientColor.alphaKeys; GradientColorKey[] colorkey = m_GradientColor.colorKeys; List vertList = new List(); if (m_Direction == GradientDirection.Vertical) { //垂直分割 Rect rect = GetPixelAdjustedRect(); Vert2D v0 = new Vert2D(0); v0.SetColor(colorkey[colorkey.Length - 1].color); v0.SetAlpha(alpha[alpha.Length - 1].alpha); v0.SetUV(0, 0); Vector3 vec = new Vector3(rect.x, rect.y, 0); v0.SetPosition(vec); vertList.Add(v0); Vert2D v1 = new Vert2D(0); v1.SetColor(colorkey[colorkey.Length - 1].color); v1.SetAlpha(alpha[alpha.Length - 1].alpha); v1.SetUV(1, 0); vec = new Vector3(rect.x + rect.width, rect.y, 0); v1.SetPosition(vec); vertList.Add(v1); Vert2D v2 = new Vert2D(0); v2.SetColor(colorkey[0].color); v2.SetAlpha(alpha[0].alpha); v2.SetUV(1, 1); vec = new Vector3(rect.x + rect.width, rect.y + rect.height, 0); v2.SetPosition(vec); vertList.Add(v2); Vert2D v3 = new Vert2D(0); v3.SetColor(colorkey[0].color); v3.SetAlpha(alpha[0].alpha); v3.SetUV(0, 1); vec = new Vector3(rect.x, rect.y + rect.height, 0); v3.SetPosition(vec); vertList.Add(v3); for (int i = 0; i < alpha.Length; i++) { if (alpha[i].time == 0 || alpha[i].time == 1) { continue; } Vert2D v = new Vert2D(1); v.SetAlpha(alpha[i].alpha); v.SetUV(0, 1 - alpha[i].time); vertList.Add(v); Vert2D v_ = new Vert2D(1); v_.SetAlpha(alpha[i].alpha); v_.SetUV(1, 1 - alpha[i].time); vertList.Add(v_); } for (int i = 0; i < colorkey.Length; i++) { if (colorkey[i].time == 0 || colorkey[i].time == 1) { continue; } Vert2D v = new Vert2D(2); v.SetColor(colorkey[i].color); v.SetUV(1, 1 - colorkey[i].time); vertList.Add(v); Vert2D v_ = new Vert2D(2); v_.SetColor(colorkey[i].color); v_.SetUV(0, 1 - colorkey[i].time); vertList.Add(v_); } //排序,addvert vertList.Sort((x, y) => { return x.CompareToVertically(y); }); //给未填充数据的点填充数据 int nowtype = vertList[1].type; int lasttypepos = 0; int nexttypepos = 1; for (int i = 1; i < vertList.Count - 1; i++) { nowtype = vertList[i].type; if (i >= nexttypepos) { //去找下一个type lasttypepos = i - 1; for (int j = i + 1; j < vertList.Count; j++) { if (vertList[j].type != nowtype) { nexttypepos = j; break; } } } //插值更新color和alpha if (nowtype == 1) { //是alpha点,要更新color Color col; #if UNITY_2022_2_OR_NEWER if (m_GradientColor.mode == GradientMode.Blend || m_GradientColor.mode == GradientMode.PerceptualBlend) #else if (m_GradientColor.mode == GradientMode.Blend) #endif { if ((vertList[nexttypepos].uv0.y - vertList[lasttypepos].uv0.y) == 0) { col = new Color(vertList[lasttypepos].color.r, vertList[lasttypepos].color.g, vertList[lasttypepos].color.b, vertList[lasttypepos].color.a); } else { col = Color.Lerp(vertList[lasttypepos].color, vertList[nexttypepos].color, (vertList[i].uv0.y - vertList[lasttypepos].uv0.y) / (vertList[nexttypepos].uv0.y - vertList[lasttypepos].uv0.y)); } } else { col = vertList[nexttypepos].color; } vertList[i].SetColor(col); } else if (nowtype == 2) { Color col; #if UNITY_2022_2_OR_NEWER if (m_GradientColor.mode == GradientMode.Blend || m_GradientColor.mode == GradientMode.PerceptualBlend) #else if (m_GradientColor.mode == GradientMode.Blend) #endif { if ((vertList[nexttypepos].uv0.y - vertList[lasttypepos].uv0.y) == 0) { col = new Color(vertList[lasttypepos].color.r, vertList[lasttypepos].color.g, vertList[lasttypepos].color.b, vertList[lasttypepos].color.a); } else { col = Color.Lerp(vertList[lasttypepos].color, vertList[nexttypepos].color, (vertList[i].uv0.y - vertList[lasttypepos].uv0.y) / (vertList[nexttypepos].uv0.y - vertList[lasttypepos].uv0.y)); } } else { col = vertList[nexttypepos].color; } vertList[i].SetAlpha(col.a); } } //去重 vertList = vertList.Distinct(new Comparer()).ToList(); PositionLerp(vertList, new Vector2(rect.x, rect.y), new Vector2(rect.x + rect.width, rect.y + rect.height)); } else if (m_Direction == GradientDirection.Horizontal) { //水平分割 Rect rect = GetPixelAdjustedRect(); Vert2D v0 = new Vert2D(0); v0.SetColor(colorkey[0].color); v0.SetAlpha(alpha[0].alpha); v0.SetUV(0, 0); Vector3 vec = new Vector3(rect.x, rect.y, 0); v0.SetPosition(vec); vertList.Add(v0); Vert2D v3 = new Vert2D(0); v3.SetColor(colorkey[0].color); v3.SetAlpha(alpha[0].alpha); v3.SetUV(0, 1); vec = new Vector3(rect.x, rect.y + rect.height, 0); v3.SetPosition(vec); vertList.Add(v3); Vert2D v2 = new Vert2D(0); v2.SetColor(colorkey[colorkey.Length - 1].color); v2.SetAlpha(alpha[alpha.Length - 1].alpha); v2.SetUV(1, 1); vec = new Vector3(rect.x + rect.width, rect.y + rect.height, 0); v2.SetPosition(vec); vertList.Add(v2); Vert2D v1 = new Vert2D(0); v1.SetColor(colorkey[colorkey.Length - 1].color); v1.SetAlpha(alpha[alpha.Length - 1].alpha); v1.SetUV(1, 0); vec = new Vector3(rect.x + rect.width, rect.y, 0); v1.SetPosition(vec); vertList.Add(v1); for (int i = 0; i < alpha.Length; i++) { if (alpha[i].time == 0 || alpha[i].time == 1) { continue; } Vert2D v = new Vert2D(1); v.SetAlpha(alpha[i].alpha); v.SetUV(alpha[i].time, 0); vertList.Add(v); Vert2D v_ = new Vert2D(1); v_.SetAlpha(alpha[i].alpha); v_.SetUV(alpha[i].time, 1); vertList.Add(v_); } for (int i = 0; i < colorkey.Length; i++) { if (colorkey[i].time == 0 || colorkey[i].time == 1) { continue; } Vert2D v = new Vert2D(2); v.SetColor(colorkey[i].color); v.SetUV(colorkey[i].time, 1); vertList.Add(v); Vert2D v_ = new Vert2D(2); v_.SetColor(colorkey[i].color); v_.SetUV(colorkey[i].time, 0); vertList.Add(v_); } //排序,addvert vertList.Sort((x, y) => { return x.CompareToHorizontally(y); }); int nowtype = vertList[1].type; int lasttypepos = 0; int nexttypepos = 1; for (int i = 1; i < vertList.Count - 1; i++) { nowtype = vertList[i].type; if (i >= nexttypepos) { //去找下一个type lasttypepos = i - 1; for (int j = i + 1; j < vertList.Count; j++) { if (vertList[j].type != nowtype) { nexttypepos = j; break; } } } //插值 if (nowtype == 1) { //是alpha点,要更新color Color col; #if UNITY_2022_2_OR_NEWER if (m_GradientColor.mode == GradientMode.Blend || m_GradientColor.mode == GradientMode.PerceptualBlend) #else if (m_GradientColor.mode == GradientMode.Blend) #endif { if ((vertList[nexttypepos].uv0.x - vertList[lasttypepos].uv0.x) == 0) { col = new Color(vertList[lasttypepos].color.r, vertList[lasttypepos].color.g, vertList[lasttypepos].color.b, vertList[lasttypepos].color.a); } else { col = Color.Lerp(vertList[lasttypepos].color, vertList[nexttypepos].color, (vertList[i].uv0.x - vertList[lasttypepos].uv0.x) / (vertList[nexttypepos].uv0.x - vertList[lasttypepos].uv0.x)); } } else { col = vertList[nexttypepos].color; } vertList[i].SetColor(col); } else if (nowtype == 2) { Color col; #if UNITY_2022_2_OR_NEWER if (m_GradientColor.mode == GradientMode.Blend || m_GradientColor.mode == GradientMode.PerceptualBlend) #else if (m_GradientColor.mode == GradientMode.Blend) #endif { if ((vertList[nexttypepos].uv0.x - vertList[lasttypepos].uv0.x) == 0) { col = new Color(vertList[lasttypepos].color.r, vertList[lasttypepos].color.g, vertList[lasttypepos].color.b, vertList[lasttypepos].color.a); } else { col = Color.Lerp(vertList[lasttypepos].color, vertList[nexttypepos].color, (vertList[i].uv0.x - vertList[lasttypepos].uv0.x) / (vertList[nexttypepos].uv0.x - vertList[lasttypepos].uv0.x)); } } else { col = vertList[nexttypepos].color; } vertList[i].SetAlpha(col.a); } } vertList = vertList.Distinct(new Comparer()).ToList(); PositionLerp(vertList, new Vector2(rect.x, rect.y), new Vector2(rect.x + rect.width, rect.y + rect.height)); } //重写四个函数 switch (type) { case Type.Simple: //因为UseSpriteMesh和渐变色加点冲突,因此放弃使用 if (!useSpriteMesh) { GenerateSimpleSprite(toFill, vertList, preserveAspect); } else GenerateSprite(toFill, preserveAspect); break; case Type.Sliced: GenerateSlicedSprite(toFill, vertList); break; // case Type.Tiled: // GenerateTiledSprite(toFill); // break; // case Type.Filled: // GenerateFilledSprite(toFill, preserveAspect); // break; } // rect = GetDrawPixelAdjustedRect(); // if (flipMode == FlipMode.Horziontal) // { // if (flipWithCopy) // { // CopyImage(toFill); // Rect src = GetPixelRectByFlipDirection(FlipMode.Horziontal, flipWithCopy, flipEdge, flipFillCenter); // Rect target = GetCopyRectByFlipDirection(src, FlipMode.Horziontal, flipEdge); // //Rect target = new Rect(src.position - new Vector2(src.width, 0), src.size); // RemapImage(toFill, FlipMode.Horziontal, toFill.currentVertCount / 2, toFill.currentVertCount, src.xMin, src.xMax, target.xMax, target.xMin); // } // else // { // RemapImage(toFill, FlipMode.Horziontal, 0, toFill.currentVertCount, rect.xMin, rect.xMax, rect.xMax, rect.xMin); // } // } // if (flipMode == FlipMode.Vertical) // { // if (flipWithCopy) // { // CopyImage(toFill); // Rect src = GetPixelRectByFlipDirection(FlipMode.Vertical, flipWithCopy, flipEdge, flipFillCenter); // Rect target = GetCopyRectByFlipDirection(src, FlipMode.Vertical, flipEdge); // RemapImage(toFill, FlipMode.Vertical, toFill.currentVertCount / 2, toFill.currentVertCount, src.yMin, src.yMax, target.yMax, target.yMin); // } // else // { // RemapImage(toFill, FlipMode.Vertical, 0, toFill.currentVertCount, rect.xMin, rect.xMax, rect.xMax, rect.xMin); // } // } // if (flipMode == FlipMode.FourCorner) // { // //先水平拷贝 // CopyImage(toFill); // Rect src = GetPixelRectByFlipDirection(FlipMode.FourCorner, true, flipEdge, flipFillCenter); // Rect target = GetCopyRectByFlipCenter(src, FlipMode.Horziontal, flipFillCenter); // //Rect target = new Rect(src.position + new Vector2(src.width, 0), src.size); // RemapImage(toFill, FlipMode.Horziontal, toFill.currentVertCount / 2, toFill.currentVertCount, src.xMin, src.xMax, target.xMax, target.xMin); // //再垂直拷贝 // CopyImage(toFill); // Rect src1 = GetPixelRectByFlipDirection(FlipMode.FourCorner, true, flipEdge, flipFillCenter); // Rect target1 = GetCopyRectByFlipCenter(src1, FlipMode.Vertical, flipFillCenter); // RemapImage(toFill, FlipMode.Vertical, toFill.currentVertCount / 2, toFill.currentVertCount, src1.yMin, src1.yMax, target1.yMax, target1.yMin); // } // m_OriginFlipMode = m_FlipMode; //将color设置为white,函数结束将原color设置回去 // rect = GetPixelAdjustedRect(); // for (int i = 0; i < toFill.currentVertCount; ++i) // { // toFill.PopulateUIVertex(ref vert, i); // //SetGradientColor(ref vert, rect, flipDirection, GetFlipPart(i, toFill.currentVertCount)); // toFill.SetUIVertex(vert, i); // } //根据gradient的值,赋color } } void GenerateSimpleSprite(VertexHelper vh, List vertlist, bool lPreserveAspect) { if (overrideSprite == null) { vh.Clear(); AddQuads(vh, vertlist); return; } Vector4 v = GetDrawingDimensions(lPreserveAspect); var uv = (overrideSprite != null) ? Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; PositionLerp(vertlist, new Vector2(v.x, v.y), new Vector2(v.z, v.w)); UVShrink(vertlist, new Vector2(uv.x, uv.y), new Vector2(uv.z, uv.w)); vh.Clear(); AddQuads(vh, vertlist); } private void GenerateSprite(VertexHelper vh, bool lPreserveAspect) { var spriteSize = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); // Covert sprite pivot into normalized space. var spritePivot = overrideSprite.pivot / spriteSize; var rectPivot = rectTransform.pivot; Rect r = GetPixelAdjustedRect(); if (lPreserveAspect & spriteSize.sqrMagnitude > 0.0f) { PreserveSpriteAspectRatio(ref r, spriteSize); } var drawingSize = new Vector2(r.width, r.height); var spriteBoundSize = overrideSprite.bounds.size; // Calculate the drawing offset based on the difference between the two pivots. var drawOffset = (rectPivot - spritePivot) * drawingSize; var color32 = color; vh.Clear(); Vector2[] vertices = overrideSprite.vertices; Vector2[] uvs = overrideSprite.uv; for (int i = 0; i < vertices.Length; ++i) { vh.AddVert(new Vector3((vertices[i].x / spriteBoundSize.x) * drawingSize.x - drawOffset.x, (vertices[i].y / spriteBoundSize.y) * drawingSize.y - drawOffset.y), color32, new Vector2(uvs[i].x, uvs[i].y)); } UInt16[] triangles = overrideSprite.triangles; for (int i = 0; i < triangles.Length; i += 3) { vh.AddTriangle(triangles[i + 0], triangles[i + 1], triangles[i + 2]); } } private void GenerateSprite(VertexHelper vh, List vertlist, bool lPreserveAspect) { var spriteSize = new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); // Covert sprite pivot into normalized space. var spritePivot = overrideSprite.pivot / spriteSize; var rectPivot = rectTransform.pivot; Rect r = GetPixelAdjustedRect(); if (lPreserveAspect & spriteSize.sqrMagnitude > 0.0f) { PreserveSpriteAspectRatio(ref r, spriteSize); } var drawingSize = new Vector2(r.width, r.height); var spriteBoundSize = overrideSprite.bounds.size; // Calculate the drawing offset based on the difference between the two pivots. var drawOffset = (rectPivot - spritePivot) * drawingSize; var color32 = color; vh.Clear(); Vector2[] vertices = overrideSprite.vertices; Vector2[] uvs = overrideSprite.uv; List colors = new List(); for (int i = 0; i < uvs.Length; ++i) { //Debug.Log(uvs[i]); if (m_Direction == GradientDirection.Vertical) { float tolerp = uvs[i].y; //基于uv y值做插值,通过二分查找插值位置 int le = 0; int ri = vertlist.Count; int mid; while (le < ri - 1) { mid = (le + ri) / 2; float midY = vertlist[mid].uv0.y; if (midY == tolerp) { break; } else if (midY < tolerp) { le = mid; } else { ri = mid; } } if ((vertlist[(le + ri) / 2 + 1].uv0.y - vertlist[(le + ri) / 2].uv0.y) != 0 && (le + ri) / 2 != vertlist.Count) { Color lerpColor = Color.Lerp(vertlist[(le + ri) / 2].color, vertlist[(le + ri) / 2 + 1].color, (tolerp - vertlist[(le + ri) / 2].uv0.y) / (vertlist[(le + ri) / 2 + 1].uv0.y - vertlist[(le + ri) / 2].uv0.y)); colors.Add(lerpColor); } else { Color lerpColor = vertlist[(le + ri) / 2].color; colors.Add(lerpColor); } } else { //基于x做插值 float tolerp = uvs[i].x; int le = 0; int ri = vertlist.Count; int mid; while (le < ri - 1) { mid = (le + ri) / 2; float midY = vertlist[mid].uv0.x; if (midY == tolerp) { break; } else if (midY < tolerp) { le = mid; } else { ri = mid; } } if ((vertlist[(le + ri) / 2 + 1].uv0.x - vertlist[(le + ri) / 2].uv0.x) != 0 && (le + ri) / 2 != vertlist.Count) { Color lerpColor = Color.Lerp(vertlist[(le + ri) / 2].color, vertlist[(le + ri) / 2 + 1].color, (tolerp - vertlist[(le + ri) / 2].uv0.x) / (vertlist[(le + ri) / 2 + 1].uv0.x - vertlist[(le + ri) / 2].uv0.x)); colors.Add(lerpColor); } else { Color lerpColor = vertlist[(le + ri) / 2].color; colors.Add(lerpColor); } } } // //Debug.Log(vertices.Length); for (int i = 0; i < vertices.Length; ++i) { //Debug.Log(vertices[i]); // vh.AddVert(new Vector3((vertices[i].x / spriteBoundSize.x) * drawingSize.x - drawOffset.x, (vertices[i].y / spriteBoundSize.y) * drawingSize.y - drawOffset.y), colors[i], new Vector2(uvs[i].x, uvs[i].y)); } UInt16[] triangles = overrideSprite.triangles; //Debug.Log(triangles.Length); for (int i = 0; i < triangles.Length; i += 3) { //Debug.Log(triangles[i] + " " + triangles[i + 1] + " " + triangles[i + 2]); vh.AddTriangle(triangles[i + 0], triangles[i + 1], triangles[i + 2]); } } static readonly Vector2[] s_VertScratch = new Vector2[4]; static readonly Vector2[] s_UVScratch = new Vector2[4]; private void GenerateSlicedSprite(VertexHelper toFill/*, List vlist*/) { if (!hasBorder) { //GenerateSimpleSprite(toFill, vlist, false); GenerateSimpleSprite(toFill, false); return; } Vector4 outer, inner, padding, border; if (overrideSprite != null) { outer = Sprites.DataUtility.GetOuterUV(overrideSprite); inner = Sprites.DataUtility.GetInnerUV(overrideSprite); padding = Sprites.DataUtility.GetPadding(overrideSprite); border = overrideSprite.border; } else { outer = Vector4.zero; inner = Vector4.zero; padding = Vector4.zero; border = Vector4.zero; } Rect rect = GetPixelRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); border = GetAdjustedBorders(border / pixelsPerUnit, rect); padding = padding / pixelsPerUnit; s_VertScratch[0] = new Vector2(padding.x, padding.y); s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); s_VertScratch[1].x = border.x; s_VertScratch[1].y = border.y; s_VertScratch[2].x = rect.width - border.z; s_VertScratch[2].y = rect.height - border.w; float vertWidth = s_VertScratch[3].x - s_VertScratch[0].x; float vertHeight = s_VertScratch[3].y - s_VertScratch[0].y; for (int i = 0; i < 4; ++i) { s_VertScratch[i].x += rect.x; s_VertScratch[i].y += rect.y; } s_UVScratch[0] = new Vector2(outer.x, outer.y); s_UVScratch[1] = new Vector2(inner.x, inner.y); s_UVScratch[2] = new Vector2(inner.z, inner.w); s_UVScratch[3] = new Vector2(outer.z, outer.w); toFill.Clear(); for (int x = 0; x < 3; ++x) { int x2 = x + 1; for (int y = 0; y < 3; ++y) { if (!fillCenter && x == 1 && y == 1) continue; int y2 = y + 1; Vector2 uv1Min = new Vector2((s_VertScratch[x].x - rect.x) / vertWidth, (s_VertScratch[y].y - rect.y) / vertHeight); Vector2 uv1Max = new Vector2((s_VertScratch[x2].x - rect.x) / vertWidth, (s_VertScratch[y2].y - rect.y) / vertHeight); AddQuad(toFill, new Vector2(s_VertScratch[x].x, s_VertScratch[y].y), new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y), color, new Vector2(s_UVScratch[x].x, s_UVScratch[y].y), new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y), uv1Min, uv1Max); } } } private void GenerateSlicedSprite(VertexHelper toFill, List vlist) { if (!hasBorder) { GenerateSimpleSprite(toFill, vlist, false); //GenerateSimpleSprite(toFill, false); return; } Vector4 outer, inner, padding, border; if (overrideSprite != null) { outer = Sprites.DataUtility.GetOuterUV(overrideSprite); inner = Sprites.DataUtility.GetInnerUV(overrideSprite); padding = Sprites.DataUtility.GetPadding(overrideSprite); border = overrideSprite.border; } else { outer = Vector4.zero; inner = Vector4.zero; padding = Vector4.zero; border = Vector4.zero; } Rect rect = GetPixelRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); border = GetAdjustedBorders(border / pixelsPerUnit, rect); padding = padding / pixelsPerUnit; //Debug.Log(padding); //Debug.Log(border); //Debug.Log(inner); //Debug.Log(outer); //Debug.Log(rect.width); s_VertScratch[0] = new Vector2(padding.x, padding.y); s_VertScratch[3] = new Vector2(rect.width - padding.z, rect.height - padding.w); s_VertScratch[1].x = border.x; s_VertScratch[1].y = border.y; s_VertScratch[2].x = rect.width - border.z; s_VertScratch[2].y = rect.height - border.w; float vertWidth = s_VertScratch[3].x - s_VertScratch[0].x; float vertHeight = s_VertScratch[3].y - s_VertScratch[0].y; // for (int i = 0; i < 4; i++) // { // Debug.Log(s_VertScratch[i]); // } for (int i = 0; i < 4; ++i) { s_VertScratch[i].x += rect.x; s_VertScratch[i].y += rect.y; } s_UVScratch[0] = new Vector2(outer.x, outer.y); s_UVScratch[1] = new Vector2(inner.x, inner.y); s_UVScratch[2] = new Vector2(inner.z, inner.w); s_UVScratch[3] = new Vector2(outer.z, outer.w); // for (int i = 0; i < 4; ++i) // { // Debug.Log(s_UVScratch[i]); // } toFill.Clear(); for (int x = 0; x < 3; ++x) { int x2 = x + 1; for (int y = 0; y < 3; ++y) { if (!fillCenter && x == 1 && y == 1) continue; int y2 = y + 1; Vector2 uv1Min = new Vector2((s_VertScratch[x].x - rect.x) / vertWidth, (s_VertScratch[y].y - rect.y) / vertHeight); Vector2 uv1Max = new Vector2((s_VertScratch[x2].x - rect.x) / vertWidth, (s_VertScratch[y2].y - rect.y) / vertHeight); AddQuad(toFill, new Vector2(s_VertScratch[x].x, s_VertScratch[y].y), new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y), color, new Vector2(s_UVScratch[x].x, s_UVScratch[y].y), new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y), uv1Min, uv1Max); } } } private void GenerateTiledSprite(VertexHelper toFill) { Vector4 outer, inner, border; Vector2 spriteSize; if (overrideSprite != null) { outer = Sprites.DataUtility.GetOuterUV(overrideSprite); inner = Sprites.DataUtility.GetInnerUV(overrideSprite); border = overrideSprite.border; spriteSize = overrideSprite.rect.size; } else { outer = Vector4.zero; inner = Vector4.zero; border = Vector4.zero; spriteSize = Vector2.one * 100; } Rect rect = GetPixelRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); float tileWidth = (spriteSize.x - border.x - border.z) / pixelsPerUnit; float tileHeight = (spriteSize.y - border.y - border.w) / pixelsPerUnit; border = GetAdjustedBorders(border / pixelsPerUnit, rect); var uvMin = new Vector2(inner.x, inner.y); var uvMax = new Vector2(inner.z, inner.w); // Min to max max range for tiled region in coordinates relative to lower left corner. float xMin = border.x; float xMax = rect.width - border.z; float yMin = border.y; float yMax = rect.height - border.w; toFill.Clear(); var clipped = uvMax; // if either width is zero we cant tile so just assume it was the full width. if (tileWidth <= 0) tileWidth = xMax - xMin; if (tileHeight <= 0) tileHeight = yMax - yMin; if (overrideSprite != null && (hasBorder || overrideSprite.packed || overrideSprite.texture.wrapMode != TextureWrapMode.Repeat)) { // Sprite has border, or is not in repeat mode, or cannot be repeated because of packing. // We cannot use texture tiling so we will generate a mesh of quads to tile the texture. // Evaluate how many vertices we will generate. Limit this number to something sane, // especially since meshes can not have more than 65000 vertices. int nTilesW = 0; int nTilesH = 0; if (fillCenter) { nTilesW = (int)Math.Ceiling((xMax - xMin) / tileWidth); nTilesH = (int)Math.Ceiling((yMax - yMin) / tileHeight); int nVertices = 0; if (hasBorder) { nVertices = (nTilesW + 2) * (nTilesH + 2) * 4; // 4 vertices per tile } else { nVertices = nTilesW * nTilesH * 4; // 4 vertices per tile } if (nVertices > 65000) { double maxTiles = 65000.0 / 4.0; // Max number of vertices is 65000; 4 vertices per tile. double imageRatio; if (hasBorder) { imageRatio = (nTilesW + 2.0) / (nTilesH + 2.0); } else { imageRatio = (double)nTilesW / nTilesH; } double targetTilesW = Math.Sqrt(maxTiles / imageRatio); double targetTilesH = targetTilesW * imageRatio; if (hasBorder) { targetTilesW -= 2; targetTilesH -= 2; } nTilesW = (int)Math.Floor(targetTilesW); nTilesH = (int)Math.Floor(targetTilesH); tileWidth = (xMax - xMin) / nTilesW; tileHeight = (yMax - yMin) / nTilesH; } } else { if (hasBorder) { // Texture on the border is repeated only in one direction. nTilesW = (int)Math.Ceiling((xMax - xMin) / tileWidth); nTilesH = (int)Math.Ceiling((yMax - yMin) / tileHeight); int nVertices = (nTilesH + nTilesW + 2 /*corners*/) * 2 /*sides*/ * 4 /*vertices per tile*/; if (nVertices > 65000) { double maxTiles = 65000.0 / 4.0; // Max number of vertices is 65000; 4 vertices per tile. double imageRatio = (double)nTilesW / nTilesH; double targetTilesW = (maxTiles - 4 /*corners*/) / (2 * (1.0 + imageRatio)); double targetTilesH = targetTilesW * imageRatio; nTilesW = (int)Math.Floor(targetTilesW); nTilesH = (int)Math.Floor(targetTilesH); tileWidth = (xMax - xMin) / nTilesW; tileHeight = (yMax - yMin) / nTilesH; } } else { nTilesH = nTilesW = 0; } } if (fillCenter) { // TODO: we could share vertices between quads. If vertex sharing is implemented. update the computation for the number of vertices accordingly. float width = nTilesW * tileWidth; float height = nTilesH * tileHeight; for (int j = 0; j < nTilesH; j++) { float y1 = yMin + j * tileHeight; float y2 = yMin + (j + 1) * tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } clipped.x = uvMax.x; for (int i = 0; i < nTilesW; i++) { float x1 = xMin + i * tileWidth; float x2 = xMin + (i + 1) * tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } Vector2 posMin = new Vector2(x1, y1) + rect.position; Vector2 posMax = new Vector2(x2, y2) + rect.position; Vector2 localPosMin = new Vector2(x1, y1); Vector2 localPosMax = new Vector2(x2, y2); AddQuad(toFill, posMin, posMax, color, uvMin, clipped, new Vector2(localPosMin.x / width, localPosMin.y / height), new Vector2(localPosMax.x / width, localPosMax.y / height)); } } } if (hasBorder) { clipped = uvMax; float width = nTilesW * tileWidth; float height = nTilesH * tileHeight; for (int j = 0; j < nTilesH; j++) { float y1 = yMin + j * tileHeight; float y2 = yMin + (j + 1) * tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } AddQuad(toFill, new Vector2(0, y1) + rect.position, new Vector2(xMin, y2) + rect.position, color, new Vector2(outer.x, uvMin.y), new Vector2(uvMin.x, clipped.y), new Vector2(0, y1 / height), new Vector2(xMin / width, y2 / height)); AddQuad(toFill, new Vector2(xMax, y1) + rect.position, new Vector2(rect.width, y2) + rect.position, color, new Vector2(uvMax.x, uvMin.y), new Vector2(outer.z, clipped.y), new Vector2(xMax / width, y1 / height), new Vector2(rect.width / width, y2 / height)); } // Bottom and top tiled border clipped = uvMax; for (int i = 0; i < nTilesW; i++) { float x1 = xMin + i * tileWidth; float x2 = xMin + (i + 1) * tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } AddQuad(toFill, new Vector2(x1, 0) + rect.position, new Vector2(x2, yMin) + rect.position, color, new Vector2(uvMin.x, outer.y), new Vector2(clipped.x, uvMin.y), new Vector2(x1 / width, 0), new Vector2(x2 / width, yMin / height)); AddQuad(toFill, new Vector2(x1, yMax) + rect.position, new Vector2(x2, rect.height) + rect.position, color, new Vector2(uvMin.x, uvMax.y), new Vector2(clipped.x, outer.w), new Vector2(x1 / width, yMax / height), new Vector2(x2 / width, rect.height / height)); } // Corners AddQuad(toFill, new Vector2(0, 0) + rect.position, new Vector2(xMin, yMin) + rect.position, color, new Vector2(outer.x, outer.y), new Vector2(uvMin.x, uvMin.y), new Vector2(0, 0), new Vector2(xMin / width, yMin / height)); AddQuad(toFill, new Vector2(xMax, 0) + rect.position, new Vector2(rect.width, yMin) + rect.position, color, new Vector2(uvMax.x, outer.y), new Vector2(outer.z, uvMin.y), new Vector2(xMax / width, 0), new Vector2(rect.width / width, yMin / height)); AddQuad(toFill, new Vector2(0, yMax) + rect.position, new Vector2(xMin, rect.height) + rect.position, color, new Vector2(outer.x, uvMax.y), new Vector2(uvMin.x, outer.w), new Vector2(0, yMax / height), new Vector2(xMin / width, rect.height / height)); AddQuad(toFill, new Vector2(xMax, yMax) + rect.position, new Vector2(rect.width, rect.height) + rect.position, color, new Vector2(uvMax.x, uvMax.y), new Vector2(outer.z, outer.w), new Vector2(xMax / width, yMax / height), new Vector2(rect.width / width, rect.height / height)); } } else { // Texture has no border, is in repeat mode and not packed. Use texture tiling. Vector2 uvScale = new Vector2((xMax - xMin) / tileWidth, (yMax - yMin) / tileHeight); if (fillCenter) { AddQuad(toFill, new Vector2(xMin, yMin) + rect.position, new Vector2(xMax, yMax) + rect.position, color, Vector2.Scale(uvMin, uvScale), Vector2.Scale(uvMax, uvScale), Vector2.zero, Vector2.one); } } } private void GenerateTiledSprite(VertexHelper toFill, List vertlist) { Vector4 outer, inner, border; Vector2 spriteSize; if (overrideSprite != null) { outer = Sprites.DataUtility.GetOuterUV(overrideSprite); inner = Sprites.DataUtility.GetInnerUV(overrideSprite); border = overrideSprite.border; spriteSize = overrideSprite.rect.size; } else { outer = Vector4.zero; inner = Vector4.zero; border = Vector4.zero; spriteSize = Vector2.one * 100; } Rect rect = GetPixelRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); float tileWidth = (spriteSize.x - border.x - border.z) / pixelsPerUnit; float tileHeight = (spriteSize.y - border.y - border.w) / pixelsPerUnit; border = GetAdjustedBorders(border / pixelsPerUnit, rect); var uvMin = new Vector2(inner.x, inner.y); var uvMax = new Vector2(inner.z, inner.w); // Min to max max range for tiled region in coordinates relative to lower left corner. float xMin = border.x; float xMax = rect.width - border.z; float yMin = border.y; float yMax = rect.height - border.w; toFill.Clear(); var clipped = uvMax; // if either width is zero we cant tile so just assume it was the full width. if (tileWidth <= 0) tileWidth = xMax - xMin; if (tileHeight <= 0) tileHeight = yMax - yMin; if (overrideSprite != null && (hasBorder || overrideSprite.packed || overrideSprite.texture.wrapMode != TextureWrapMode.Repeat)) { // Sprite has border, or is not in repeat mode, or cannot be repeated because of packing. // We cannot use texture tiling so we will generate a mesh of quads to tile the texture. // Evaluate how many vertices we will generate. Limit this number to something sane, // especially since meshes can not have more than 65000 vertices. int nTilesW = 0; int nTilesH = 0; if (fillCenter) { nTilesW = (int)Math.Ceiling((xMax - xMin) / tileWidth); nTilesH = (int)Math.Ceiling((yMax - yMin) / tileHeight); int nVertices = 0; if (hasBorder) { nVertices = (nTilesW + 2) * (nTilesH + 2) * 4; // 4 vertices per tile } else { nVertices = nTilesW * nTilesH * 4; // 4 vertices per tile } if (nVertices > 65000) { double maxTiles = 65000.0 / 4.0; // Max number of vertices is 65000; 4 vertices per tile. double imageRatio; if (hasBorder) { imageRatio = (nTilesW + 2.0) / (nTilesH + 2.0); } else { imageRatio = (double)nTilesW / nTilesH; } double targetTilesW = Math.Sqrt(maxTiles / imageRatio); double targetTilesH = targetTilesW * imageRatio; if (hasBorder) { targetTilesW -= 2; targetTilesH -= 2; } nTilesW = (int)Math.Floor(targetTilesW); nTilesH = (int)Math.Floor(targetTilesH); tileWidth = (xMax - xMin) / nTilesW; tileHeight = (yMax - yMin) / nTilesH; } } else { if (hasBorder) { // Texture on the border is repeated only in one direction. nTilesW = (int)Math.Ceiling((xMax - xMin) / tileWidth); nTilesH = (int)Math.Ceiling((yMax - yMin) / tileHeight); int nVertices = (nTilesH + nTilesW + 2 /*corners*/) * 2 /*sides*/ * 4 /*vertices per tile*/; if (nVertices > 65000) { double maxTiles = 65000.0 / 4.0; // Max number of vertices is 65000; 4 vertices per tile. double imageRatio = (double)nTilesW / nTilesH; double targetTilesW = (maxTiles - 4 /*corners*/) / (2 * (1.0 + imageRatio)); double targetTilesH = targetTilesW * imageRatio; nTilesW = (int)Math.Floor(targetTilesW); nTilesH = (int)Math.Floor(targetTilesH); tileWidth = (xMax - xMin) / nTilesW; tileHeight = (yMax - yMin) / nTilesH; } } else { nTilesH = nTilesW = 0; } } if (fillCenter) { // TODO: we could share vertices between quads. If vertex sharing is implemented. update the computation for the number of vertices accordingly. float width = nTilesW * tileWidth; float height = nTilesH * tileHeight; for (int j = 0; j < nTilesH; j++) { float y1 = yMin + j * tileHeight; float y2 = yMin + (j + 1) * tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } clipped.x = uvMax.x; for (int i = 0; i < nTilesW; i++) { float x1 = xMin + i * tileWidth; float x2 = xMin + (i + 1) * tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } Vector2 posMin = new Vector2(x1, y1) + rect.position; Vector2 posMax = new Vector2(x2, y2) + rect.position; Vector2 localPosMin = new Vector2(x1, y1); Vector2 localPosMax = new Vector2(x2, y2); AddQuad(toFill, posMin, posMax, color, uvMin, clipped, new Vector2(localPosMin.x / width, localPosMin.y / height), new Vector2(localPosMax.x / width, localPosMax.y / height)); } } } if (hasBorder) { clipped = uvMax; float width = nTilesW * tileWidth; float height = nTilesH * tileHeight; for (int j = 0; j < nTilesH; j++) { float y1 = yMin + j * tileHeight; float y2 = yMin + (j + 1) * tileHeight; if (y2 > yMax) { clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); y2 = yMax; } AddQuad(toFill, new Vector2(0, y1) + rect.position, new Vector2(xMin, y2) + rect.position, color, new Vector2(outer.x, uvMin.y), new Vector2(uvMin.x, clipped.y), new Vector2(0, y1 / height), new Vector2(xMin / width, y2 / height)); AddQuad(toFill, new Vector2(xMax, y1) + rect.position, new Vector2(rect.width, y2) + rect.position, color, new Vector2(uvMax.x, uvMin.y), new Vector2(outer.z, clipped.y), new Vector2(xMax / width, y1 / height), new Vector2(rect.width / width, y2 / height)); } // Bottom and top tiled border clipped = uvMax; for (int i = 0; i < nTilesW; i++) { float x1 = xMin + i * tileWidth; float x2 = xMin + (i + 1) * tileWidth; if (x2 > xMax) { clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); x2 = xMax; } AddQuad(toFill, new Vector2(x1, 0) + rect.position, new Vector2(x2, yMin) + rect.position, color, new Vector2(uvMin.x, outer.y), new Vector2(clipped.x, uvMin.y), new Vector2(x1 / width, 0), new Vector2(x2 / width, yMin / height)); AddQuad(toFill, new Vector2(x1, yMax) + rect.position, new Vector2(x2, rect.height) + rect.position, color, new Vector2(uvMin.x, uvMax.y), new Vector2(clipped.x, outer.w), new Vector2(x1 / width, yMax / height), new Vector2(x2 / width, rect.height / height)); } // Corners AddQuad(toFill, new Vector2(0, 0) + rect.position, new Vector2(xMin, yMin) + rect.position, color, new Vector2(outer.x, outer.y), new Vector2(uvMin.x, uvMin.y), new Vector2(0, 0), new Vector2(xMin / width, yMin / height)); AddQuad(toFill, new Vector2(xMax, 0) + rect.position, new Vector2(rect.width, yMin) + rect.position, color, new Vector2(uvMax.x, outer.y), new Vector2(outer.z, uvMin.y), new Vector2(xMax / width, 0), new Vector2(rect.width / width, yMin / height)); AddQuad(toFill, new Vector2(0, yMax) + rect.position, new Vector2(xMin, rect.height) + rect.position, color, new Vector2(outer.x, uvMax.y), new Vector2(uvMin.x, outer.w), new Vector2(0, yMax / height), new Vector2(xMin / width, rect.height / height)); AddQuad(toFill, new Vector2(xMax, yMax) + rect.position, new Vector2(rect.width, rect.height) + rect.position, color, new Vector2(uvMax.x, uvMax.y), new Vector2(outer.z, outer.w), new Vector2(xMax / width, yMax / height), new Vector2(rect.width / width, rect.height / height)); } } else { // Texture has no border, is in repeat mode and not packed. Use texture tiling. Vector2 uvScale = new Vector2((xMax - xMin) / tileWidth, (yMax - yMin) / tileHeight); if (fillCenter) { AddQuad(toFill, new Vector2(xMin, yMin) + rect.position, new Vector2(xMax, yMax) + rect.position, color, Vector2.Scale(uvMin, uvScale), Vector2.Scale(uvMax, uvScale), Vector2.zero, Vector2.one); } } } static void AddQuad(VertexHelper vertexHelper, Vector3[] quadPositions, Color32 color, Vector3[] quadUVs, Vector3[] quadUV1s) { int startIndex = vertexHelper.currentVertCount; for (int i = 0; i < 4; ++i) vertexHelper.AddVert(quadPositions[i], color, quadUVs[i], quadUV1s[i], s_DefaultNormal, s_DefaultTangent); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax, Vector2 uv1Min, Vector2 uv1Max) { int startIndex = vertexHelper.currentVertCount; vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y), new Vector2(uv1Min.x, uv1Min.y), s_DefaultNormal, s_DefaultTangent); vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y), new Vector2(uv1Min.x, uv1Max.y), s_DefaultNormal, s_DefaultTangent); vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y), new Vector2(uv1Max.x, uv1Max.y), s_DefaultNormal, s_DefaultTangent); vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y), new Vector2(uv1Max.x, uv1Min.y), s_DefaultNormal, s_DefaultTangent); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect) { Rect originalRect = GetRectByFlipDirection(flipMode, flipWithCopy, flipEdge, flipFillCenter); for (int axis = 0; axis <= 1; axis++) { float borderScaleRatio; // The adjusted rect (adjusted for pixel correctness) // may be slightly larger than the original rect. // Adjust the border to match the adjustedRect to avoid // small gaps between borders (case 833201). if (originalRect.size[axis] != 0) { borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis]; border[axis] *= borderScaleRatio; border[axis + 2] *= borderScaleRatio; } // If the rect is smaller than the combined borders, then there's not room for the borders at their normal size. // In order to avoid artefacts with overlapping borders, we scale the borders down to fit. float combinedBorders = border[axis] + border[axis + 2]; if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0) { borderScaleRatio = adjustedRect.size[axis] / combinedBorders; border[axis] *= borderScaleRatio; border[axis + 2] *= borderScaleRatio; } } return border; } static readonly Vector3[] s_Xy = new Vector3[4]; static readonly Vector3[] s_Uv = new Vector3[4]; static readonly Vector3[] s_Uv1 = new Vector3[4]; void GenerateFilledSprite(VertexHelper toFill, bool preserveAspect) { toFill.Clear(); if (fillAmount < 0.001f) return; Vector4 v = GetDrawingDimensions(preserveAspect); Vector4 outer = overrideSprite != null ? Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; UIVertex uiv = UIVertex.simpleVert; uiv.color = color; float tx0 = outer.x; float ty0 = outer.y; float tx1 = outer.z; float ty1 = outer.w; // Horizontal and vertical filled sprites are simple -- just end the Image prematurely if (fillMethod == FillMethod.Horizontal || fillMethod == FillMethod.Vertical) { if (fillMethod == FillMethod.Horizontal) { float fill = (tx1 - tx0) * fillAmount; if (fillOrigin == 1) { v.x = v.z - (v.z - v.x) * fillAmount; tx0 = tx1 - fill; } else { v.z = v.x + (v.z - v.x) * fillAmount; tx1 = tx0 + fill; } } else if (fillMethod == FillMethod.Vertical) { float fill = (ty1 - ty0) * fillAmount; if (fillOrigin == 1) { v.y = v.w - (v.w - v.y) * fillAmount; ty0 = ty1 - fill; } else { v.w = v.y + (v.w - v.y) * fillAmount; ty1 = ty0 + fill; } } } s_Xy[0] = new Vector2(v.x, v.y); s_Xy[1] = new Vector2(v.x, v.w); s_Xy[2] = new Vector2(v.z, v.w); s_Xy[3] = new Vector2(v.z, v.y); s_Uv[0] = new Vector2(tx0, ty0); s_Uv[1] = new Vector2(tx0, ty1); s_Uv[2] = new Vector2(tx1, ty1); s_Uv[3] = new Vector2(tx1, ty0); s_Uv1[0] = new Vector2(0, 0); s_Uv1[1] = new Vector2(0, 1); s_Uv1[2] = new Vector2(1, 1); s_Uv1[3] = new Vector2(1, 0); { if (fillAmount < 1f && fillMethod != FillMethod.Horizontal && fillMethod != FillMethod.Vertical) { if (fillMethod == FillMethod.Radial90) { if (RadialCut(s_Xy, s_Uv, fillAmount, fillClockwise, fillOrigin)) AddQuad(toFill, s_Xy, color, s_Uv, s_Uv1); } else if (fillMethod == FillMethod.Radial180) { for (int side = 0; side < 2; ++side) { float fx0, fx1, fy0, fy1; int even = fillOrigin > 1 ? 1 : 0; if (fillOrigin == 0 || fillOrigin == 2) { fy0 = 0f; fy1 = 1f; if (side == even) { fx0 = 0f; fx1 = 0.5f; } else { fx0 = 0.5f; fx1 = 1f; } } else { fx0 = 0f; fx1 = 1f; if (side == even) { fy0 = 0.5f; fy1 = 1f; } else { fy0 = 0f; fy1 = 0.5f; } } s_Xy[0].x = Mathf.Lerp(v.x, v.z, fx0); s_Xy[1].x = s_Xy[0].x; s_Xy[2].x = Mathf.Lerp(v.x, v.z, fx1); s_Xy[3].x = s_Xy[2].x; s_Xy[0].y = Mathf.Lerp(v.y, v.w, fy0); s_Xy[1].y = Mathf.Lerp(v.y, v.w, fy1); s_Xy[2].y = s_Xy[1].y; s_Xy[3].y = s_Xy[0].y; s_Uv[0].x = Mathf.Lerp(tx0, tx1, fx0); s_Uv[1].x = s_Uv[0].x; s_Uv[2].x = Mathf.Lerp(tx0, tx1, fx1); s_Uv[3].x = s_Uv[2].x; s_Uv[0].y = Mathf.Lerp(ty0, ty1, fy0); s_Uv[1].y = Mathf.Lerp(ty0, ty1, fy1); s_Uv[2].y = s_Uv[1].y; s_Uv[3].y = s_Uv[0].y; float val = fillClockwise ? fillAmount * 2f - side : fillAmount * 2f - (1 - side); if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), fillClockwise, ((side + fillOrigin + 3) % 4))) { AddQuad(toFill, s_Xy, color, s_Uv, s_Uv1); } } } else if (fillMethod == FillMethod.Radial360) { for (int corner = 0; corner < 4; ++corner) { float fx0, fx1, fy0, fy1; if (corner < 2) { fx0 = 0f; fx1 = 0.5f; } else { fx0 = 0.5f; fx1 = 1f; } if (corner == 0 || corner == 3) { fy0 = 0f; fy1 = 0.5f; } else { fy0 = 0.5f; fy1 = 1f; } s_Xy[0].x = Mathf.Lerp(v.x, v.z, fx0); s_Xy[1].x = s_Xy[0].x; s_Xy[2].x = Mathf.Lerp(v.x, v.z, fx1); s_Xy[3].x = s_Xy[2].x; s_Xy[0].y = Mathf.Lerp(v.y, v.w, fy0); s_Xy[1].y = Mathf.Lerp(v.y, v.w, fy1); s_Xy[2].y = s_Xy[1].y; s_Xy[3].y = s_Xy[0].y; s_Uv[0].x = Mathf.Lerp(tx0, tx1, fx0); s_Uv[1].x = s_Uv[0].x; s_Uv[2].x = Mathf.Lerp(tx0, tx1, fx1); s_Uv[3].x = s_Uv[2].x; s_Uv[0].y = Mathf.Lerp(ty0, ty1, fy0); s_Uv[1].y = Mathf.Lerp(ty0, ty1, fy1); s_Uv[2].y = s_Uv[1].y; s_Uv[3].y = s_Uv[0].y; float val = fillClockwise ? fillAmount * 4f - ((corner + fillOrigin) % 4) : fillAmount * 4f - (3 - ((corner + fillOrigin) % 4)); if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), fillClockwise, ((corner + 2) % 4))) AddQuad(toFill, s_Xy, color, s_Uv, s_Uv1); } } } else { AddQuad(toFill, s_Xy, color, s_Uv, s_Uv1); } } } /// /// Adjust the specified quad, making it be radially filled instead. /// static bool RadialCut(Vector3[] xy, Vector3[] uv, float fill, bool invert, int corner) { // Nothing to fill if (fill < 0.001f) return false; // Even corners invert the fill direction if ((corner & 1) == 1) invert = !invert; // Nothing to adjust if (!invert && fill > 0.999f) return true; // Convert 0-1 value into 0 to 90 degrees angle in radians float angle = Mathf.Clamp01(fill); if (invert) angle = 1f - angle; angle *= 90f * Mathf.Deg2Rad; // Calculate the effective X and Y factors float cos = Mathf.Cos(angle); float sin = Mathf.Sin(angle); RadialCut(xy, cos, sin, invert, corner); RadialCut(uv, cos, sin, invert, corner); return true; } /// /// Adjust the specified quad, making it be radially filled instead. /// static void RadialCut(Vector3[] xy, float cos, float sin, bool invert, int corner) { int i0 = corner; int i1 = ((corner + 1) % 4); int i2 = ((corner + 2) % 4); int i3 = ((corner + 3) % 4); if ((corner & 1) == 1) { if (sin > cos) { cos /= sin; sin = 1f; if (invert) { xy[i1].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); xy[i2].x = xy[i1].x; } } else if (cos > sin) { sin /= cos; cos = 1f; if (!invert) { xy[i2].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); xy[i3].y = xy[i2].y; } } else { cos = 1f; sin = 1f; } if (!invert) xy[i3].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); else xy[i1].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); } else { if (cos > sin) { sin /= cos; cos = 1f; if (!invert) { xy[i1].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); xy[i2].y = xy[i1].y; } } else if (sin > cos) { cos /= sin; sin = 1f; if (invert) { xy[i2].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); xy[i3].x = xy[i2].x; } } else { cos = 1f; sin = 1f; } if (invert) xy[i3].y = Mathf.Lerp(xy[i0].y, xy[i2].y, sin); else xy[i1].x = Mathf.Lerp(xy[i0].x, xy[i2].x, cos); } } static void AddQuad(VertexHelper vertexHelper, Vector3[] quadPositions, Color32 color, Vector3[] quadUVs) { int startIndex = vertexHelper.currentVertCount; for (int i = 0; i < 4; ++i) vertexHelper.AddVert(quadPositions[i], color, quadUVs[i]); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } static void AddQuad(VertexHelper vertexHelper, Vector2 posMin, Vector2 posMax, Color32 color, Vector2 uvMin, Vector2 uvMax) { int startIndex = vertexHelper.currentVertCount; vertexHelper.AddVert(new Vector3(posMin.x, posMin.y, 0), color, new Vector2(uvMin.x, uvMin.y)); vertexHelper.AddVert(new Vector3(posMin.x, posMax.y, 0), color, new Vector2(uvMin.x, uvMax.y)); vertexHelper.AddVert(new Vector3(posMax.x, posMax.y, 0), color, new Vector2(uvMax.x, uvMax.y)); vertexHelper.AddVert(new Vector3(posMax.x, posMin.y, 0), color, new Vector2(uvMax.x, uvMin.y)); vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); vertexHelper.AddTriangle(startIndex + 2, startIndex + 3, startIndex); } void AddQuads(VertexHelper vertexHelper, List vlist) { #if UNITY_2022_2_OR_NEWER if (m_GradientColor.mode == GradientMode.Blend || m_GradientColor.mode == GradientMode.PerceptualBlend) #else if (m_GradientColor.mode == GradientMode.Blend) #endif { int startIndex = vertexHelper.currentVertCount; foreach (Vert2D v in vlist) { vertexHelper.AddVert(v.position, v.color, v.uv0); } for (; startIndex < vertexHelper.currentVertCount - 2; startIndex++) { vertexHelper.AddTriangle(startIndex, startIndex + 1, startIndex + 2); } } else { List newvlist = new List(); if (m_Direction == GradientDirection.Horizontal) { for (int i = 0; i < vlist.Count; i++) { if (i == 0 || i == 1) { Vert2D newvert = new Vert2D(vlist[i].type); newvert.SetAlpha(vlist[i + 2].color.a); newvert.SetColor(vlist[i + 2].color); newvert.SetUV(vlist[i].uv0.x, vlist[i].uv0.y); newvert.SetPosition(vlist[i].position); newvlist.Add(newvert); } else if (i == vlist.Count - 2 || i == vlist.Count - 1) { newvlist.Add(vlist[i]); } else { newvlist.Add(vlist[i]); Vert2D newvert = new Vert2D(vlist[i].type); newvert.SetAlpha(vlist[i + 2].color.a); newvert.SetColor(vlist[i + 2].color); newvert.SetUV(vlist[i].uv0.x, vlist[i].uv0.y); newvert.SetPosition(vlist[i].position); newvlist.Add(newvert); } } } else { for (int i = 0; i < vlist.Count; i++) { if (i == 0 || i == 1) { newvlist.Add(vlist[i]); } else if (i == vlist.Count - 2 || i == vlist.Count - 1) { Vert2D newvert = new Vert2D(vlist[i].type); newvert.SetAlpha(vlist[i - 2].color.a); newvert.SetColor(vlist[i - 2].color); newvert.SetUV(vlist[i].uv0.x, vlist[i].uv0.y); newvert.SetPosition(vlist[i].position); newvlist.Add(newvert); } else { Vert2D newvert = new Vert2D(vlist[i].type); newvert.SetAlpha(vlist[i - 2].color.a); newvert.SetColor(vlist[i - 2].color); newvert.SetUV(vlist[i].uv0.x, vlist[i].uv0.y); newvert.SetPosition(vlist[i].position); newvlist.Add(newvert); newvlist.Add(vlist[i]); } } } foreach (Vert2D v in newvlist) { vertexHelper.AddVert(v.position, v.color, v.uv0); } int s = -1; for (; s < newvlist.Count - 1; s += 4) { if (s == -1) { vertexHelper.AddTriangle(s + 1, s + 2, s + 3); } else { vertexHelper.AddTriangle(s, s + 2, s + 3); } if (s == newvlist.Count - 5) { vertexHelper.AddTriangle(s + 2, s + 3, s + 4); } else { vertexHelper.AddTriangle(s + 2, s + 3, s + 5); } } } } #endregion } }