661 lines
23 KiB
C#
661 lines
23 KiB
C#
|
// Copyright (C) 2015-2021 gamevanilla - All rights reserved.
|
|||
|
// This code can only be used under the standard Unity Asset Store End User License Agreement.
|
|||
|
// A Copy of the Asset Store EULA is available at http://unity3d.com/company/legal/as_terms.
|
|||
|
|
|||
|
// Credit goes to https://gist.github.com/yasirkula/391fa12bc173acdf5ac48c466f180708. Thank you!
|
|||
|
|
|||
|
using System;
|
|||
|
using System.Collections.Generic;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.UI;
|
|||
|
|
|||
|
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
|||
|
using UnityEngine.U2D;
|
|||
|
#endif
|
|||
|
|
|||
|
using Sprites = UnityEngine.Sprites;
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
using UnityEditor;
|
|||
|
|
|||
|
namespace UltimateClean
|
|||
|
{
|
|||
|
// Custom Editor to order the variables in the Inspector similar to Image component
|
|||
|
[CustomEditor(typeof(SlicedFilledImage)), CanEditMultipleObjects]
|
|||
|
public class SlicedFilledImageEditor : Editor
|
|||
|
{
|
|||
|
private SerializedProperty spriteProp, colorProp;
|
|||
|
private GUIContent spriteLabel;
|
|||
|
|
|||
|
private void OnEnable()
|
|||
|
{
|
|||
|
spriteProp = serializedObject.FindProperty("m_Sprite");
|
|||
|
colorProp = serializedObject.FindProperty("m_Color");
|
|||
|
spriteLabel = new GUIContent("Source Image");
|
|||
|
}
|
|||
|
|
|||
|
public override void OnInspectorGUI()
|
|||
|
{
|
|||
|
serializedObject.Update();
|
|||
|
|
|||
|
EditorGUILayout.PropertyField(spriteProp, spriteLabel);
|
|||
|
EditorGUILayout.PropertyField(colorProp);
|
|||
|
DrawPropertiesExcluding(serializedObject, "m_Script", "m_Sprite", "m_Color", "m_OnCullStateChanged");
|
|||
|
|
|||
|
serializedObject.ApplyModifiedProperties();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
namespace UltimateClean
|
|||
|
{
|
|||
|
// Credit: https://bitbucket.org/Unity-Technologies/ui/src/2018.4/UnityEngine.UI/UI/Core/Image.cs
|
|||
|
[RequireComponent(typeof(CanvasRenderer))]
|
|||
|
[AddComponentMenu("UI/Sliced Filled Image", 11)]
|
|||
|
public class SlicedFilledImage : MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastFilter
|
|||
|
{
|
|||
|
private static class SetPropertyUtility
|
|||
|
{
|
|||
|
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
|||
|
{
|
|||
|
if (EqualityComparer<T>.Default.Equals(currentValue, newValue))
|
|||
|
return false;
|
|||
|
|
|||
|
currentValue = newValue;
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
|||
|
{
|
|||
|
if ((currentValue == null && newValue == null ) || (currentValue != null && currentValue.Equals(newValue)))
|
|||
|
return false;
|
|||
|
|
|||
|
currentValue = newValue;
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public enum FillDirection { Right = 0, Left = 1, Up = 2, Down = 3 }
|
|||
|
|
|||
|
private static readonly Vector3[] s_Vertices = new Vector3[4];
|
|||
|
private static readonly Vector2[] s_UVs = new Vector2[4];
|
|||
|
private static readonly Vector2[] s_SlicedVertices = new Vector2[4];
|
|||
|
private static readonly Vector2[] s_SlicedUVs = new Vector2[4];
|
|||
|
|
|||
|
#pragma warning disable 1692
|
|||
|
#pragma warning disable IDE1006 // Suppress 'Naming rule violation' warnings
|
|||
|
#pragma warning disable 0649
|
|||
|
[SerializeField]
|
|||
|
private Sprite m_Sprite;
|
|||
|
public Sprite sprite
|
|||
|
{
|
|||
|
get { return m_Sprite; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (SetPropertyUtility.SetClass(ref m_Sprite, value))
|
|||
|
{
|
|||
|
SetAllDirty();
|
|||
|
TrackImage();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
private FillDirection m_FillDirection;
|
|||
|
public FillDirection fillDirection
|
|||
|
{
|
|||
|
get { return m_FillDirection; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (SetPropertyUtility.SetStruct(ref m_FillDirection, value))
|
|||
|
SetVerticesDirty();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[Range( 0, 1 )]
|
|||
|
[SerializeField]
|
|||
|
private float m_FillAmount = 1f;
|
|||
|
public float fillAmount
|
|||
|
{
|
|||
|
get { return m_FillAmount; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (SetPropertyUtility.SetStruct(ref m_FillAmount, Mathf.Clamp01(value)))
|
|||
|
SetVerticesDirty();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
private bool m_FillCenter = true;
|
|||
|
public bool fillCenter
|
|||
|
{
|
|||
|
get { return m_FillCenter; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (SetPropertyUtility.SetStruct(ref m_FillCenter, value))
|
|||
|
SetVerticesDirty();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
[SerializeField]
|
|||
|
private float m_PixelsPerUnitMultiplier = 1f;
|
|||
|
public float pixelsPerUnitMultiplier
|
|||
|
{
|
|||
|
get { return m_PixelsPerUnitMultiplier; }
|
|||
|
set { m_PixelsPerUnitMultiplier = Mathf.Max( 0.01f, value ); }
|
|||
|
}
|
|||
|
|
|||
|
public float pixelsPerUnit
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
float spritePixelsPerUnit = 100;
|
|||
|
if (activeSprite)
|
|||
|
spritePixelsPerUnit = activeSprite.pixelsPerUnit;
|
|||
|
|
|||
|
float referencePixelsPerUnit = 100;
|
|||
|
if (canvas)
|
|||
|
referencePixelsPerUnit = canvas.referencePixelsPerUnit;
|
|||
|
|
|||
|
return m_PixelsPerUnitMultiplier * spritePixelsPerUnit / referencePixelsPerUnit;
|
|||
|
}
|
|||
|
}
|
|||
|
#pragma warning restore 0649
|
|||
|
|
|||
|
[NonSerialized]
|
|||
|
private Sprite m_OverrideSprite;
|
|||
|
public Sprite overrideSprite
|
|||
|
{
|
|||
|
get { return activeSprite; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (SetPropertyUtility.SetClass(ref m_OverrideSprite, value))
|
|||
|
{
|
|||
|
SetAllDirty();
|
|||
|
TrackImage();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private Sprite activeSprite { get { return m_OverrideSprite != null ? m_OverrideSprite : m_Sprite; } }
|
|||
|
|
|||
|
public override Texture mainTexture
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (activeSprite != null)
|
|||
|
return activeSprite.texture;
|
|||
|
|
|||
|
return material != null && material.mainTexture != null ? material.mainTexture : s_WhiteTexture;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool hasBorder
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (activeSprite != null)
|
|||
|
{
|
|||
|
Vector4 v = activeSprite.border;
|
|||
|
return v.sqrMagnitude > 0f;
|
|||
|
}
|
|||
|
|
|||
|
return false;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public override Material material
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (m_Material != null)
|
|||
|
return m_Material;
|
|||
|
|
|||
|
if (activeSprite && activeSprite.associatedAlphaSplitTexture != null)
|
|||
|
{
|
|||
|
#if UNITY_EDITOR
|
|||
|
if (Application.isPlaying)
|
|||
|
#endif
|
|||
|
return Image.defaultETC1GraphicMaterial;
|
|||
|
}
|
|||
|
|
|||
|
return defaultMaterial;
|
|||
|
}
|
|||
|
set { base.material = value; }
|
|||
|
}
|
|||
|
|
|||
|
public float alphaHitTestMinimumThreshold { get; set; }
|
|||
|
#pragma warning restore IDE1006
|
|||
|
#pragma warning restore 1692
|
|||
|
|
|||
|
protected SlicedFilledImage()
|
|||
|
{
|
|||
|
useLegacyMeshGeneration = false;
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnEnable()
|
|||
|
{
|
|||
|
base.OnEnable();
|
|||
|
TrackImage();
|
|||
|
}
|
|||
|
|
|||
|
protected override void OnDisable()
|
|||
|
{
|
|||
|
base.OnDisable();
|
|||
|
|
|||
|
if (m_Tracked)
|
|||
|
UnTrackImage();
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_EDITOR
|
|||
|
protected override void OnValidate()
|
|||
|
{
|
|||
|
base.OnValidate();
|
|||
|
m_PixelsPerUnitMultiplier = Mathf.Max(0.01f, m_PixelsPerUnitMultiplier);
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
protected override void OnPopulateMesh(VertexHelper vh)
|
|||
|
{
|
|||
|
if (activeSprite == null)
|
|||
|
{
|
|||
|
base.OnPopulateMesh(vh);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
GenerateSlicedFilledSprite(vh);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// Update the renderer's material.
|
|||
|
/// </summary>
|
|||
|
protected override void UpdateMaterial()
|
|||
|
{
|
|||
|
base.UpdateMaterial();
|
|||
|
|
|||
|
// Check if this sprite has an associated alpha texture (generated when splitting RGBA = RGB + A as two textures without alpha)
|
|||
|
if (activeSprite == null)
|
|||
|
{
|
|||
|
canvasRenderer.SetAlphaTexture(null);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Texture2D alphaTex = activeSprite.associatedAlphaSplitTexture;
|
|||
|
if (alphaTex != null)
|
|||
|
canvasRenderer.SetAlphaTexture(alphaTex);
|
|||
|
}
|
|||
|
|
|||
|
private void GenerateSlicedFilledSprite(VertexHelper vh)
|
|||
|
{
|
|||
|
vh.Clear();
|
|||
|
|
|||
|
if (m_FillAmount < 0.001f)
|
|||
|
return;
|
|||
|
|
|||
|
Rect rect = GetPixelAdjustedRect();
|
|||
|
Vector4 outer = Sprites.DataUtility.GetOuterUV(activeSprite);
|
|||
|
Vector4 padding = Sprites.DataUtility.GetPadding(activeSprite);
|
|||
|
|
|||
|
if (!hasBorder)
|
|||
|
{
|
|||
|
Vector2 size = activeSprite.rect.size;
|
|||
|
|
|||
|
int spriteW = Mathf.RoundToInt(size.x);
|
|||
|
int spriteH = Mathf.RoundToInt(size.y);
|
|||
|
|
|||
|
// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
|
|||
|
Vector4 vertices = new Vector4(
|
|||
|
rect.x + rect.width * (padding.x / spriteW),
|
|||
|
rect.y + rect.height * (padding.y / spriteH),
|
|||
|
rect.x + rect.width * ((spriteW - padding.z) / spriteW),
|
|||
|
rect.y + rect.height * ((spriteH - padding.w) / spriteH));
|
|||
|
|
|||
|
GenerateFilledSprite(vh, vertices, outer, m_FillAmount);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
Vector4 inner = Sprites.DataUtility.GetInnerUV(activeSprite);
|
|||
|
Vector4 border = GetAdjustedBorders(activeSprite.border / pixelsPerUnit, rect);
|
|||
|
|
|||
|
padding = padding / pixelsPerUnit;
|
|||
|
|
|||
|
s_SlicedVertices[0] = new Vector2(padding.x, padding.y);
|
|||
|
s_SlicedVertices[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);
|
|||
|
|
|||
|
s_SlicedVertices[1].x = border.x;
|
|||
|
s_SlicedVertices[1].y = border.y;
|
|||
|
|
|||
|
s_SlicedVertices[2].x = rect.width - border.z;
|
|||
|
s_SlicedVertices[2].y = rect.height - border.w;
|
|||
|
|
|||
|
for (int i = 0; i < 4; ++i)
|
|||
|
{
|
|||
|
s_SlicedVertices[i].x += rect.x;
|
|||
|
s_SlicedVertices[i].y += rect.y;
|
|||
|
}
|
|||
|
|
|||
|
s_SlicedUVs[0] = new Vector2(outer.x, outer.y);
|
|||
|
s_SlicedUVs[1] = new Vector2(inner.x, inner.y);
|
|||
|
s_SlicedUVs[2] = new Vector2(inner.z, inner.w);
|
|||
|
s_SlicedUVs[3] = new Vector2(outer.z, outer.w);
|
|||
|
|
|||
|
float rectStartPos;
|
|||
|
float _1OverTotalSize;
|
|||
|
if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right)
|
|||
|
{
|
|||
|
rectStartPos = s_SlicedVertices[0].x;
|
|||
|
|
|||
|
float totalSize = (s_SlicedVertices[3].x - s_SlicedVertices[0].x);
|
|||
|
_1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
rectStartPos = s_SlicedVertices[0].y;
|
|||
|
|
|||
|
float totalSize = (s_SlicedVertices[3].y - s_SlicedVertices[0].y);
|
|||
|
_1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f;
|
|||
|
}
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
float sliceStart, sliceEnd;
|
|||
|
switch (m_FillDirection)
|
|||
|
{
|
|||
|
case FillDirection.Right:
|
|||
|
sliceStart = (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize;
|
|||
|
sliceEnd = (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize;
|
|||
|
break;
|
|||
|
case FillDirection.Up:
|
|||
|
sliceStart = (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize;
|
|||
|
sliceEnd = (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize;
|
|||
|
break;
|
|||
|
case FillDirection.Left:
|
|||
|
sliceStart = 1f - (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize;
|
|||
|
sliceEnd = 1f - (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize;
|
|||
|
break;
|
|||
|
case FillDirection.Down:
|
|||
|
sliceStart = 1f - (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize;
|
|||
|
sliceEnd = 1f - (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize;
|
|||
|
break;
|
|||
|
default: // Just there to get rid of the "Use of unassigned local variable" compiler error
|
|||
|
sliceStart = sliceEnd = 0f;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (sliceStart >= m_FillAmount)
|
|||
|
continue;
|
|||
|
|
|||
|
Vector4 vertices = new Vector4(s_SlicedVertices[x].x, s_SlicedVertices[y].y, s_SlicedVertices[x2].x, s_SlicedVertices[y2].y);
|
|||
|
Vector4 uvs = new Vector4(s_SlicedUVs[x].x, s_SlicedUVs[y].y, s_SlicedUVs[x2].x, s_SlicedUVs[y2].y);
|
|||
|
float fillAmount = (m_FillAmount - sliceStart) / (sliceEnd - sliceStart);
|
|||
|
|
|||
|
GenerateFilledSprite(vh, vertices, uvs, fillAmount);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect)
|
|||
|
{
|
|||
|
Rect originalRect = rectTransform.rect;
|
|||
|
|
|||
|
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;
|
|||
|
}
|
|||
|
|
|||
|
private void GenerateFilledSprite(VertexHelper vh, Vector4 vertices, Vector4 uvs, float fillAmount)
|
|||
|
{
|
|||
|
if (m_FillAmount < 0.001f)
|
|||
|
return;
|
|||
|
|
|||
|
float uvLeft = uvs.x;
|
|||
|
float uvBottom = uvs.y;
|
|||
|
float uvRight = uvs.z;
|
|||
|
float uvTop = uvs.w;
|
|||
|
|
|||
|
if (fillAmount < 1f)
|
|||
|
{
|
|||
|
if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right)
|
|||
|
{
|
|||
|
if (m_FillDirection == FillDirection.Left)
|
|||
|
{
|
|||
|
vertices.x = vertices.z - (vertices.z - vertices.x) * fillAmount;
|
|||
|
uvLeft = uvRight - (uvRight - uvLeft) * fillAmount;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vertices.z = vertices.x + (vertices.z - vertices.x) * fillAmount;
|
|||
|
uvRight = uvLeft + (uvRight - uvLeft) * fillAmount;
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
if (m_FillDirection == FillDirection.Down)
|
|||
|
{
|
|||
|
vertices.y = vertices.w - (vertices.w - vertices.y) * fillAmount;
|
|||
|
uvBottom = uvTop - (uvTop - uvBottom) * fillAmount;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
vertices.w = vertices.y + (vertices.w - vertices.y) * fillAmount;
|
|||
|
uvTop = uvBottom + (uvTop - uvBottom) * fillAmount;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
s_Vertices[0] = new Vector3(vertices.x, vertices.y);
|
|||
|
s_Vertices[1] = new Vector3(vertices.x, vertices.w);
|
|||
|
s_Vertices[2] = new Vector3(vertices.z, vertices.w);
|
|||
|
s_Vertices[3] = new Vector3(vertices.z, vertices.y);
|
|||
|
|
|||
|
s_UVs[0] = new Vector2(uvLeft, uvBottom);
|
|||
|
s_UVs[1] = new Vector2(uvLeft, uvTop);
|
|||
|
s_UVs[2] = new Vector2(uvRight, uvTop);
|
|||
|
s_UVs[3] = new Vector2(uvRight, uvBottom);
|
|||
|
|
|||
|
int startIndex = vh.currentVertCount;
|
|||
|
|
|||
|
for (int i = 0; i < 4; i++)
|
|||
|
vh.AddVert(s_Vertices[i], color, s_UVs[i]);
|
|||
|
|
|||
|
vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
|
|||
|
vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
|
|||
|
}
|
|||
|
|
|||
|
int ILayoutElement.layoutPriority { get { return 0; } }
|
|||
|
float ILayoutElement.minWidth { get { return 0; } }
|
|||
|
float ILayoutElement.minHeight { get { return 0; } }
|
|||
|
float ILayoutElement.flexibleWidth { get { return -1; } }
|
|||
|
float ILayoutElement.flexibleHeight { get { return -1; } }
|
|||
|
|
|||
|
float ILayoutElement.preferredWidth
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (activeSprite == null)
|
|||
|
return 0;
|
|||
|
|
|||
|
return Sprites.DataUtility.GetMinSize(activeSprite).x / pixelsPerUnit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
float ILayoutElement.preferredHeight
|
|||
|
{
|
|||
|
get
|
|||
|
{
|
|||
|
if (activeSprite == null)
|
|||
|
return 0;
|
|||
|
|
|||
|
return Sprites.DataUtility.GetMinSize(activeSprite).y / pixelsPerUnit;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void ILayoutElement.CalculateLayoutInputHorizontal() { }
|
|||
|
void ILayoutElement.CalculateLayoutInputVertical() { }
|
|||
|
|
|||
|
bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
|
|||
|
{
|
|||
|
if (alphaHitTestMinimumThreshold <= 0)
|
|||
|
return true;
|
|||
|
|
|||
|
if (alphaHitTestMinimumThreshold > 1)
|
|||
|
return false;
|
|||
|
|
|||
|
if (activeSprite == null)
|
|||
|
return true;
|
|||
|
|
|||
|
Vector2 local;
|
|||
|
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local))
|
|||
|
return false;
|
|||
|
|
|||
|
Rect rect = GetPixelAdjustedRect();
|
|||
|
|
|||
|
// Convert to have lower left corner as reference point.
|
|||
|
local.x += rectTransform.pivot.x * rect.width;
|
|||
|
local.y += rectTransform.pivot.y * rect.height;
|
|||
|
|
|||
|
Rect spriteRect = activeSprite.rect;
|
|||
|
Vector4 border = activeSprite.border;
|
|||
|
Vector4 adjustedBorder = GetAdjustedBorders(border / pixelsPerUnit, rect);
|
|||
|
|
|||
|
for (int i = 0; i < 2; i++)
|
|||
|
{
|
|||
|
if (local[i] <= adjustedBorder[i])
|
|||
|
continue;
|
|||
|
|
|||
|
if (rect.size[i] - local[i] <= adjustedBorder[i + 2])
|
|||
|
{
|
|||
|
local[i] -= (rect.size[i] - spriteRect.size[i]);
|
|||
|
continue;
|
|||
|
}
|
|||
|
|
|||
|
float lerp = Mathf.InverseLerp(adjustedBorder[i], rect.size[i] - adjustedBorder[i + 2], local[i]);
|
|||
|
local[i] = Mathf.Lerp( border[i], spriteRect.size[i] - border[i + 2], lerp );
|
|||
|
}
|
|||
|
|
|||
|
// Normalize local coordinates.
|
|||
|
Rect textureRect = activeSprite.textureRect;
|
|||
|
Vector2 normalized = new Vector2(local.x / textureRect.width, local.y / textureRect.height);
|
|||
|
|
|||
|
// Convert to texture space.
|
|||
|
float x = Mathf.Lerp(textureRect.x, textureRect.xMax, normalized.x) / activeSprite.texture.width;
|
|||
|
float y = Mathf.Lerp(textureRect.y, textureRect.yMax, normalized.y) / activeSprite.texture.height;
|
|||
|
|
|||
|
switch (m_FillDirection)
|
|||
|
{
|
|||
|
case FillDirection.Right:
|
|||
|
if (x > m_FillAmount)
|
|||
|
return false;
|
|||
|
break;
|
|||
|
case FillDirection.Left:
|
|||
|
if (1f - x > m_FillAmount)
|
|||
|
return false;
|
|||
|
break;
|
|||
|
case FillDirection.Up:
|
|||
|
if (y > m_FillAmount)
|
|||
|
return false;
|
|||
|
break;
|
|||
|
case FillDirection.Down:
|
|||
|
if (1f - y > m_FillAmount)
|
|||
|
return false;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
try
|
|||
|
{
|
|||
|
return activeSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold;
|
|||
|
}
|
|||
|
catch (UnityException e)
|
|||
|
{
|
|||
|
Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
|
|||
|
return true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void ISerializationCallbackReceiver.OnBeforeSerialize() { }
|
|||
|
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
|||
|
{
|
|||
|
m_FillAmount = Mathf.Clamp01(m_FillAmount);
|
|||
|
}
|
|||
|
|
|||
|
// Whether this is being tracked for Atlas Binding
|
|||
|
private bool m_Tracked = false;
|
|||
|
|
|||
|
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
|||
|
private static List<SlicedFilledImage> m_TrackedTexturelessImages = new List<SlicedFilledImage>();
|
|||
|
private static bool s_Initialized;
|
|||
|
#endif
|
|||
|
|
|||
|
private void TrackImage()
|
|||
|
{
|
|||
|
if (activeSprite != null && activeSprite.texture == null)
|
|||
|
{
|
|||
|
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
|||
|
if (!s_Initialized)
|
|||
|
{
|
|||
|
SpriteAtlasManager.atlasRegistered += RebuildImage;
|
|||
|
s_Initialized = true;
|
|||
|
}
|
|||
|
|
|||
|
m_TrackedTexturelessImages.Add(this);
|
|||
|
#endif
|
|||
|
m_Tracked = true;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void UnTrackImage()
|
|||
|
{
|
|||
|
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
|||
|
m_TrackedTexturelessImages.Remove(this);
|
|||
|
#endif
|
|||
|
m_Tracked = false;
|
|||
|
}
|
|||
|
|
|||
|
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
|||
|
private static void RebuildImage(SpriteAtlas spriteAtlas)
|
|||
|
{
|
|||
|
for (int i = m_TrackedTexturelessImages.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
SlicedFilledImage image = m_TrackedTexturelessImages[i];
|
|||
|
if (spriteAtlas.CanBindTo(image.activeSprite))
|
|||
|
{
|
|||
|
image.SetAllDirty();
|
|||
|
m_TrackedTexturelessImages.RemoveAt(i);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
#endif
|
|||
|
}
|
|||
|
}
|