com.alicizax.unity.ui.exten.../Runtime/UXComponent/UX/UXImage.cs
2025-07-29 14:22:35 +08:00

2549 lines
105 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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);
}
/// <summary>
/// 修改原来的Rect
/// 如果 flipMode == Horziontal 或 Vertical, 根据copy, flipEdge来修改原本的Rect
/// 如果 flipMode == FourCorner, 根据flipFillCenter 来修改
/// </summary>
/// <param name="rect">Image原始Rect</param>
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;
}
/// <summary>
/// 获取Copy出来的Rect
/// 这里Src应该是Modify过的原Rect
/// 只处理flipMode == Horziontal 或 Vertical的情况
/// </summary>
/// <param name="src"></param>
/// <param name="flipMode"></param>
/// <param name="flipEdge"></param>
/// <returns></returns>
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;
}
/// <summary>
/// 获取Copy出来的Rect flipMode == FourCorner时专用
/// flipMode == FourCorner时会转换成两次Copy
/// 分别调用GetCopyRectByFlipDirection
/// 这里Src应该是Modify过的原Rect
/// </summary>
/// <param name="src"></param>
/// <param name="flipMode"></param>
/// <param name="fillCenter"></param>
/// <returns></returns>
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<Vert2D>
{
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<Vert2D> 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<Vert2D> 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<Vert2D> vertList = new List<Vert2D>();
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<Vert2D> 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<Vert2D> 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<Color> colors = new List<Color>();
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<Vert2D> 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<Vert2D> 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<Vert2D> 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);
}
}
}
/// <summary>
/// Adjust the specified quad, making it be radially filled instead.
/// </summary>
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;
}
/// <summary>
/// Adjust the specified quad, making it be radially filled instead.
/// </summary>
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<Vert2D> 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<Vert2D> newvlist = new List<Vert2D>();
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
}
}