Created
August 25, 2014 23:36
-
-
Save stramit/d2e1a94cdf3dbe08caac to your computer and use it in GitHub Desktop.
Image
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
namespace UnityEngine.UI | |
{ | |
/// <summary> | |
/// Image is a textured element in the UI hierarchy. | |
/// </summary> | |
[AddComponentMenu("UI/Image", 10)] | |
public class Image : MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement | |
{ | |
public enum Type | |
{ | |
Simple, | |
Sliced, | |
Tiled, | |
Filled | |
} | |
public enum FillMethod | |
{ | |
Horizontal, | |
Vertical, | |
Radial90, | |
Radial180, | |
Radial360, | |
} | |
public enum OriginHorizontal | |
{ | |
Left, | |
Right, | |
} | |
public enum OriginVertical | |
{ | |
Bottom, | |
Top, | |
} | |
public enum Origin90 | |
{ | |
BottomLeft, | |
TopLeft, | |
TopRight, | |
BottomRight, | |
} | |
public enum Origin180 | |
{ | |
Bottom, | |
Left, | |
Top, | |
Right, | |
} | |
public enum Origin360 | |
{ | |
Bottom, | |
Right, | |
Top, | |
Left, | |
} | |
[RenamedSerializedData("m_Frame")] | |
[SerializeField] private Sprite m_Sprite; | |
public Sprite sprite { get { return m_Sprite; } set { SetPropertyUtility.SetClass (ref m_Sprite, value, m_DirtyAllCallback); } } | |
[NonSerialized] | |
private Sprite m_OverrideSprite; | |
public Sprite overrideSprite { get { return m_OverrideSprite == null ? sprite : m_OverrideSprite; } set {SetPropertyUtility.SetClass(ref m_OverrideSprite, value, m_DirtyAllCallback); } } | |
/// How the Image is drawn. | |
[SerializeField] private Type m_Type = Type.Simple; | |
public Type type { get { return m_Type; } set { SetPropertyUtility.SetStruct(ref m_Type, value, m_DirtyVertsCallback); } } | |
[SerializeField] private bool m_PreserveAspect = false; | |
public bool preserveAspect { get { return m_PreserveAspect; } set { SetPropertyUtility.SetStruct(ref m_PreserveAspect, value, m_DirtyVertsCallback); } } | |
[SerializeField] private bool m_FillCenter = true; | |
public bool fillCenter { get { return m_FillCenter; } set { SetPropertyUtility.SetStruct(ref m_FillCenter, value, m_DirtyVertsCallback); } } | |
/// Filling method for filled sprites. | |
[SerializeField] private FillMethod m_FillMethod = FillMethod.Radial360; | |
public FillMethod fillMethod { get { return m_FillMethod; } set { SetPropertyUtility.SetStruct(ref m_FillMethod, value, m_DirtyVertsCallback); m_FillOrigin = 0; } } | |
/// Amount of the Image shown. 0-1 range with 0 being nothing shown, and 1 being the full Image. | |
[Range(0, 1)] | |
[SerializeField] private float m_FillAmount = 1.0f; | |
public float fillAmount { get { return m_FillAmount; } set { SetPropertyUtility.SetStruct(ref m_FillAmount, Mathf.Clamp01(value), m_DirtyVertsCallback); } } | |
/// Whether the Image should be filled clockwise (true) or counter-clockwise (false). | |
[SerializeField] private bool m_FillClockwise = true; | |
public bool fillClockwise { get { return m_FillClockwise; } set { SetPropertyUtility.SetStruct(ref m_FillClockwise, value, m_DirtyVertsCallback); } } | |
/// Controls the origin point of the Fill process. Value means different things with each fill method. | |
[SerializeField] private int m_FillOrigin; | |
public int fillOrigin { get { return m_FillOrigin; } set { SetPropertyUtility.SetStruct(ref m_FillOrigin, value, m_DirtyVertsCallback); } } | |
protected Image() | |
{} | |
/// <summary> | |
/// Image's texture comes from the UnityEngine.Image. | |
/// </summary> | |
public override Texture mainTexture | |
{ | |
get | |
{ | |
return overrideSprite == null ? s_WhiteTexture : overrideSprite.texture; | |
} | |
} | |
/// <summary> | |
/// Whether the Image has a border to work with. | |
/// </summary> | |
public bool hasBorder | |
{ | |
get | |
{ | |
if (overrideSprite != null) | |
{ | |
Vector4 v = overrideSprite.border; | |
return v.sqrMagnitude > 0f; | |
} | |
return false; | |
} | |
} | |
public void OnBeforeSerialize() {} | |
void ISerializationCallbackReceiver.OnAfterDeserialize() | |
{ | |
if (m_FillOrigin < 0) | |
m_FillOrigin = 0; | |
else if (m_FillMethod == FillMethod.Horizontal && m_FillOrigin > 1) | |
m_FillOrigin = 0; | |
else if (m_FillMethod == FillMethod.Vertical && m_FillOrigin > 1) | |
m_FillOrigin = 0; | |
else if (m_FillOrigin > 3) | |
m_FillOrigin = 0; | |
m_FillAmount = Mathf.Clamp(m_FillAmount, 0f, 1f); | |
} | |
/// 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 ? Vector2.zero : new Vector2(overrideSprite.rect.width, overrideSprite.rect.height); | |
Rect r = GetPixelAdjustedRect(); | |
//Debug.Log(string.Format("r:{2}, size:{0}, padding:{1}", size, padding, r)); | |
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) | |
{ | |
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; | |
} | |
} | |
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; | |
} | |
public override void SetNativeSize() | |
{ | |
if (overrideSprite != null) | |
{ | |
int w = Mathf.RoundToInt (overrideSprite.rect.width); | |
int h = Mathf.RoundToInt (overrideSprite.rect.height); | |
rectTransform.anchorMax = rectTransform.anchorMin; | |
rectTransform.sizeDelta = new Vector2 (w, h); | |
SetAllDirty (); | |
} | |
} | |
/// <summary> | |
/// Update the UI renderer mesh. | |
/// </summary> | |
protected override void OnFillVBO (List<UIVertex> vbo) | |
{ | |
if (overrideSprite == null) | |
{ | |
base.OnFillVBO (vbo); | |
return; | |
} | |
switch (type) | |
{ | |
case Type.Simple: | |
GenerateSimpleSprite(vbo, m_PreserveAspect); | |
break; | |
case Type.Sliced: | |
GenerateSlicedSprite(vbo); | |
break; | |
case Type.Tiled: | |
GenerateTiledSprite(vbo); | |
break; | |
case Type.Filled: | |
GenerateFilledSprite(vbo, m_PreserveAspect); | |
break; | |
} | |
} | |
#region Various fill functions | |
/// <summary> | |
/// Generate vertices for a simple Image. | |
/// </summary> | |
void GenerateSimpleSprite (List<UIVertex> vbo, bool preserveAspect) | |
{ | |
var vert = UIVertex.simpleVert; | |
vert.color = color; | |
Vector4 v = GetDrawingDimensions(preserveAspect); | |
var uv = (overrideSprite != null) ? Sprites.DataUtility.GetOuterUV(overrideSprite) : Vector4.zero; | |
vert.position = new Vector3(v.x, v.y); | |
vert.uv0 = new Vector2(uv.x, uv.y); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.x, v.w); | |
vert.uv0 = new Vector2(uv.x, uv.w); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.z, v.w); | |
vert.uv0 = new Vector2(uv.z, uv.w); | |
vbo.Add(vert); | |
vert.position = new Vector3(v.z, v.y); | |
vert.uv0 = new Vector2(uv.z, uv.y); | |
vbo.Add(vert); | |
} | |
/// <summary> | |
/// Generate vertices for a 9-sliced Image. | |
/// </summary> | |
static readonly Vector2[] s_VertScratch = new Vector2[4]; | |
static readonly Vector2[] s_UVScratch = new Vector2[4]; | |
void GenerateSlicedSprite (List<UIVertex> vbo) | |
{ | |
if (!hasBorder) | |
{ | |
GenerateSimpleSprite(vbo, 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 = GetPixelAdjustedRect(); | |
border = GetAdjustedBorders (border / pixelsPerUnit, rect); | |
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; | |
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); | |
var uiv = UIVertex.simpleVert; | |
uiv.color = color; | |
for (int x = 0; x < 3; ++x) | |
{ | |
int x2 = x + 1; | |
for (int y = 0; y < 3; ++y) | |
{ | |
if (!m_FillCenter && x == 1 && y == 1) | |
{ | |
continue; | |
} | |
int y2 = y + 1; | |
AddQuad (vbo, uiv, | |
new Vector2(s_VertScratch[x].x, s_VertScratch[y].y), | |
new Vector2(s_VertScratch[x2].x, s_VertScratch[y2].y), | |
new Vector2(s_UVScratch[x].x, s_UVScratch[y].y), | |
new Vector2(s_UVScratch[x2].x, s_UVScratch[y2].y)); | |
} | |
} | |
} | |
/// <summary> | |
/// Generate vertices for a tiled Image. | |
/// </summary> | |
void GenerateTiledSprite (List<UIVertex> vbo) | |
{ | |
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 = GetPixelAdjustedRect(); | |
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); | |
var v = UIVertex.simpleVert; | |
v.color = color; | |
// 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; | |
// Safety check. Useful so Unity doesn't run out of memory if the sprites are too small. | |
// Max tiles are 100 x 100. | |
if ((xMax - xMin) > tileWidth * 100 || (yMax - yMin) > tileHeight * 100) | |
{ | |
tileWidth = (xMax - xMin) / 100; | |
tileHeight = (yMax - yMin) / 100; | |
} | |
var clipped = uvMax; | |
if (m_FillCenter) | |
{ | |
for (float y1 = yMin; y1 < yMax; y1 += tileHeight) | |
{ | |
float y2 = y1 + tileHeight; | |
if (y2 > yMax) | |
{ | |
clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); | |
y2 = yMax; | |
} | |
clipped.x = uvMax.x; | |
for (float x1 = xMin; x1 < xMax; x1 += tileWidth) | |
{ | |
float x2 = x1 + tileWidth; | |
if (x2 > xMax) | |
{ | |
clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); | |
x2 = xMax; | |
} | |
AddQuad (vbo, v, new Vector2 (x1, y1) + rect.position, new Vector2 (x2, y2) + rect.position, uvMin, clipped); | |
} | |
} | |
} | |
if (!hasBorder) | |
return; | |
// Left and right tiled border | |
clipped = uvMax; | |
for (float y1 = yMin; y1 < yMax; y1 += tileHeight) | |
{ | |
float y2 = y1 + tileHeight; | |
if (y2 > yMax) | |
{ | |
clipped.y = uvMin.y + (uvMax.y - uvMin.y) * (yMax - y1) / (y2 - y1); | |
y2 = yMax; | |
} | |
AddQuad (vbo, v, | |
new Vector2 (0, y1) + rect.position, | |
new Vector2 (xMin, y2) + rect.position, | |
new Vector2 (outer.x, uvMin.y), | |
new Vector2 (uvMin.x, clipped.y)); | |
AddQuad (vbo, v, | |
new Vector2 (xMax, y1) + rect.position, | |
new Vector2 (rect.width, y2) + rect.position, | |
new Vector2 (uvMax.x, uvMin.y), | |
new Vector2 (outer.z, clipped.y)); | |
} | |
// Bottom and top tiled border | |
clipped = uvMax; | |
for (float x1 = xMin; x1 < xMax; x1 += tileWidth) | |
{ | |
float x2 = x1 + tileWidth; | |
if (x2 > xMax) | |
{ | |
clipped.x = uvMin.x + (uvMax.x - uvMin.x) * (xMax - x1) / (x2 - x1); | |
x2 = xMax; | |
} | |
AddQuad (vbo, v, | |
new Vector2 (x1, 0) + rect.position, | |
new Vector2 (x2, yMin) + rect.position, | |
new Vector2 (uvMin.x, outer.y), | |
new Vector2 (clipped.x, uvMin.y)); | |
AddQuad (vbo, v, | |
new Vector2 (x1, yMax) + rect.position, | |
new Vector2 (x2, rect.height) + rect.position, | |
new Vector2 (uvMin.x, uvMax.y), | |
new Vector2 (clipped.x, outer.w)); | |
} | |
// Corners | |
AddQuad (vbo, v, | |
new Vector2 (0, 0) + rect.position, | |
new Vector2 (xMin, yMin) + rect.position, | |
new Vector2 (outer.x, outer.y), | |
new Vector2 (uvMin.x, uvMin.y)); | |
AddQuad (vbo, v, | |
new Vector2 (xMax, 0) + rect.position, | |
new Vector2 (rect.width, yMin) + rect.position, | |
new Vector2 (uvMax.x, outer.y), | |
new Vector2 (outer.z, uvMin.y)); | |
AddQuad (vbo, v, | |
new Vector2 (0, yMax) + rect.position, | |
new Vector2 (xMin, rect.height) + rect.position, | |
new Vector2 (outer.x, uvMax.y), | |
new Vector2 (uvMin.x, outer.w)); | |
AddQuad (vbo, v, | |
new Vector2 (xMax, yMax) + rect.position, | |
new Vector2 (rect.width, rect.height) + rect.position, | |
new Vector2 (uvMax.x, uvMax.y), | |
new Vector2 (outer.z, outer.w)); | |
} | |
void AddQuad (List<UIVertex> vbo, UIVertex v, Vector2 posMin, Vector2 posMax, Vector2 uvMin, Vector2 uvMax) | |
{ | |
v.position = new Vector3 (posMin.x, posMin.y, 0); | |
v.uv0 = new Vector2 (uvMin.x, uvMin.y); | |
vbo.Add (v); | |
v.position = new Vector3 (posMin.x, posMax.y, 0); | |
v.uv0 = new Vector2 (uvMin.x, uvMax.y); | |
vbo.Add (v); | |
v.position = new Vector3 (posMax.x, posMax.y, 0); | |
v.uv0 = new Vector2 (uvMax.x, uvMax.y); | |
vbo.Add (v); | |
v.position = new Vector3 (posMax.x, posMin.y, 0); | |
v.uv0 = new Vector2 (uvMax.x, uvMin.y); | |
vbo.Add (v); | |
} | |
Vector4 GetAdjustedBorders (Vector4 border, Rect rect) | |
{ | |
for (int axis = 0; axis <= 1; axis++) | |
{ | |
// 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 (rect.size[axis] < combinedBorders && combinedBorders != 0) | |
{ | |
float borderScaleRatio = rect.size[axis] / combinedBorders; | |
border[axis] *= borderScaleRatio; | |
border[axis+2] *= borderScaleRatio; | |
} | |
} | |
return border; | |
} | |
/// <summary> | |
/// Generate vertices for a filled Image. | |
/// </summary> | |
static readonly Vector2[] s_Xy = new Vector2[4]; | |
static readonly Vector2[] s_Uv = new Vector2[4]; | |
void GenerateFilledSprite (List<UIVertex> vbo, bool preserveAspect) | |
{ | |
if (m_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 (m_FillMethod == FillMethod.Horizontal || m_FillMethod == FillMethod.Vertical) | |
{ | |
if (fillMethod == FillMethod.Horizontal) | |
{ | |
float fill = (tx1 - tx0) * m_FillAmount; | |
if (m_FillOrigin == 1) | |
{ | |
v.x = v.z - (v.z - v.x) * m_FillAmount; | |
tx0 = tx1 - fill; | |
} | |
else | |
{ | |
v.z = v.x + (v.z - v.x) * m_FillAmount; | |
tx1 = tx0 + fill; | |
} | |
} | |
else if (fillMethod == FillMethod.Vertical) | |
{ | |
float fill = (ty1 - ty0) * m_FillAmount; | |
if (m_FillOrigin == 1) | |
{ | |
v.y = v.w - (v.w - v.y) * m_FillAmount; | |
ty0 = ty1 - fill; | |
} | |
else | |
{ | |
v.w = v.y + (v.w - v.y) * m_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); | |
if (m_FillAmount < 1f) | |
{ | |
if (fillMethod == FillMethod.Radial90) | |
{ | |
if (RadialCut(s_Xy, s_Uv, m_FillAmount, m_FillClockwise, m_FillOrigin)) | |
{ | |
for (int i = 0; i < 4; ++i) | |
{ | |
uiv.position = s_Xy[i]; | |
uiv.uv0 = s_Uv[i]; | |
vbo.Add(uiv); | |
} | |
} | |
return; | |
} | |
if (fillMethod == FillMethod.Radial180) | |
{ | |
for (int side = 0; side < 2; ++side) | |
{ | |
float fx0, fx1, fy0, fy1; | |
int even = m_FillOrigin > 1 ? 1 : 0; | |
if (m_FillOrigin == 0 || m_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 = m_FillClockwise ? fillAmount * 2f - side : m_FillAmount * 2f - (1 - side); | |
if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), m_FillClockwise, ((side + m_FillOrigin + 3) % 4))) | |
{ | |
for (int i = 0; i < 4; ++i) | |
{ | |
uiv.position = s_Xy[i]; | |
uiv.uv0 = s_Uv[i]; | |
vbo.Add(uiv); | |
} | |
} | |
} | |
return; | |
} | |
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 = m_FillClockwise ? | |
m_FillAmount * 4f - ((corner + m_FillOrigin) % 4) : | |
m_FillAmount * 4f - (3 - ((corner + m_FillOrigin) % 4)); | |
if (RadialCut(s_Xy, s_Uv, Mathf.Clamp01(val), m_FillClockwise, ((corner + 2) % 4))) | |
{ | |
for (int i = 0; i < 4; ++i) | |
{ | |
uiv.position = s_Xy[i]; | |
uiv.uv0 = s_Uv[i]; | |
vbo.Add(uiv); | |
} | |
} | |
} | |
return; | |
} | |
} | |
// Fill the buffer with the quad for the Image | |
for (int i = 0; i < 4; ++i) | |
{ | |
uiv.position = s_Xy[i]; | |
uiv.uv0 = s_Uv[i]; | |
vbo.Add(uiv); | |
} | |
} | |
/// <summary> | |
/// Adjust the specified quad, making it be radially filled instead. | |
/// </summary> | |
static bool RadialCut (Vector2[] xy, Vector2[] 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 (Vector2[] 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); | |
} | |
} | |
#endregion | |
public void CalculateLayoutInputHorizontal () {} | |
public void CalculateLayoutInputVertical () {} | |
public float minWidth { get { return 0; } } | |
public float preferredWidth | |
{ | |
get | |
{ | |
if (overrideSprite == null) | |
return 0; | |
if (type == Type.Sliced || type == Type.Tiled) | |
return Sprites.DataUtility.GetMinSize(overrideSprite).x; | |
return overrideSprite.rect.size.x; | |
} | |
} | |
public float flexibleWidth { get { return 1; } } | |
public float minHeight { get { return 0; } } | |
public float preferredHeight | |
{ | |
get | |
{ | |
if (overrideSprite == null) | |
return 0; | |
if (type == Type.Sliced || type == Type.Tiled) | |
return Sprites.DataUtility.GetMinSize (overrideSprite).y; | |
return overrideSprite.rect.size.y; | |
} | |
} | |
public float flexibleHeight { get { return 1; } } | |
public int layoutPriority { get { return 0; } } | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment