NodeScript+ 导入了个 UI Extend
Signed-off-by: TRADER_FOER <lhf190@outlook.com>
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
/// Credit koohddang
|
||||
/// Sourced from - http://forum.unity3d.com/threads/onfillvbo-to-onpopulatemesh-help.353977/#post-2299311
|
||||
|
||||
using System;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/Diamond Graph")]
|
||||
public class DiamondGraph : UIPrimitiveBase
|
||||
{
|
||||
[SerializeField]
|
||||
private float m_a = 1;
|
||||
[SerializeField]
|
||||
private float m_b = 1;
|
||||
[SerializeField]
|
||||
private float m_c = 1;
|
||||
[SerializeField]
|
||||
private float m_d = 1;
|
||||
|
||||
|
||||
public float A
|
||||
{
|
||||
get { return m_a; }
|
||||
set { m_a = value; }
|
||||
}
|
||||
|
||||
public float B
|
||||
{
|
||||
get { return m_b; }
|
||||
set { m_b = value; }
|
||||
}
|
||||
|
||||
public float C
|
||||
{
|
||||
get { return m_c; }
|
||||
set { m_c = value; }
|
||||
}
|
||||
|
||||
public float D
|
||||
{
|
||||
get { return m_d; }
|
||||
set { m_d = value; }
|
||||
}
|
||||
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
vh.Clear();
|
||||
float wHalf = rectTransform.rect.width / 2;
|
||||
//float hHalf = rectTransform.rect.height / 2;
|
||||
m_a = Math.Min(1, Math.Max(0, m_a));
|
||||
m_b = Math.Min(1, Math.Max(0, m_b));
|
||||
m_c = Math.Min(1, Math.Max(0, m_c));
|
||||
m_d = Math.Min(1, Math.Max(0, m_d));
|
||||
|
||||
Color32 color32 = color;
|
||||
vh.AddVert(new Vector3(-wHalf * m_a, 0), color32, new Vector2(0f, 0f));
|
||||
vh.AddVert(new Vector3(0, wHalf * m_b), color32, new Vector2(0f, 1f));
|
||||
vh.AddVert(new Vector3(wHalf * m_c, 0), color32, new Vector2(1f, 1f));
|
||||
vh.AddVert(new Vector3(0, -wHalf * m_d), color32, new Vector2(1f, 0f));
|
||||
|
||||
vh.AddTriangle(0, 1, 2);
|
||||
vh.AddTriangle(2, 3, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 891530df3841c0041ab9982359e02e0f
|
||||
timeCreated: 1442708993
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,226 @@
|
||||
/// Credit zge, jeremie sellam
|
||||
/// Sourced from - http://forum.unity3d.com/threads/draw-circles-or-primitives-on-the-new-ui-canvas.272488/#post-2293224
|
||||
/// Updated from - https://bitbucket.org/SimonDarksideJ/unity-ui-extensions/issues/65/a-better-uicircle
|
||||
|
||||
/// Update 10.9.2017 (tswalker, https://bitbucket.org/tswalker/)
|
||||
///
|
||||
/// * Modified component to utilize vertex stream instead of quads
|
||||
/// * Improved accuracy of geometry fill to prevent edge "sliding" and redundant tris
|
||||
/// * Added progress capability to allow component to be used as an indicator
|
||||
/// * Added methods for use during runtime and event system(s) with other components
|
||||
/// * Change some terminology of members to reflect other component property changes
|
||||
/// * Added padding capability
|
||||
/// * Only utilizes UV0 set for sprite/texture mapping (maps UV to geometry 0,1 boundary)
|
||||
/// * Sample usage in scene "UICircleProgress"
|
||||
/// Note: moving the pivot around from center to an edge can cause strange things
|
||||
/// as well as having the RectTransform be smaller than the Thickness and/or Padding.
|
||||
/// When making an initial layout for the component, it would be best to test multiple
|
||||
/// aspect ratios and resolutions to ensure consistent behaviour.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UI Circle")]
|
||||
public class UICircle : UIPrimitiveBase
|
||||
{
|
||||
[Tooltip("The Arc Invert property will invert the construction of the Arc.")]
|
||||
public bool ArcInvert = true;
|
||||
|
||||
[Tooltip("The Arc property is a percentage of the entire circumference of the circle.")]
|
||||
[Range(0, 1)]
|
||||
public float Arc = 1;
|
||||
|
||||
[Tooltip("The Arc Steps property defines the number of segments that the Arc will be divided into.")]
|
||||
[Range(0, 1000)]
|
||||
public int ArcSteps = 100;
|
||||
|
||||
[Tooltip("The Arc Rotation property permits adjusting the geometry orientation around the Z axis.")]
|
||||
[Range(0, 360)]
|
||||
public int ArcRotation = 0;
|
||||
|
||||
[Tooltip("The Progress property allows the primitive to be used as a progression indicator.")]
|
||||
[Range(0, 1)]
|
||||
public float Progress = 0;
|
||||
private float _progress = 0;
|
||||
|
||||
public Color ProgressColor = new Color(255, 255, 255, 255);
|
||||
public bool Fill = true; //solid circle
|
||||
public float Thickness = 5;
|
||||
public int Padding = 0;
|
||||
|
||||
private List<int> indices = new List<int>(); //ordered list of vertices per tri
|
||||
private List<UIVertex> vertices = new List<UIVertex>();
|
||||
private Vector2 uvCenter = new Vector2(0.5f, 0.5f);
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
int _inversion = ArcInvert ? -1 : 1;
|
||||
float Diameter = (rectTransform.rect.width < rectTransform.rect.height ? rectTransform.rect.width : rectTransform.rect.height) - Padding; //correct for padding and always fit RectTransform
|
||||
float outerDiameter = -rectTransform.pivot.x * Diameter;
|
||||
float innerDiameter = -rectTransform.pivot.x * Diameter + Thickness;
|
||||
|
||||
vh.Clear();
|
||||
indices.Clear();
|
||||
vertices.Clear();
|
||||
|
||||
int i = 0;
|
||||
int j = 1;
|
||||
int k = 0;
|
||||
|
||||
float stepDegree = (Arc * 360f) / ArcSteps;
|
||||
_progress = ArcSteps * Progress;
|
||||
float rad = _inversion * Mathf.Deg2Rad * ArcRotation;
|
||||
float X = Mathf.Cos(rad);
|
||||
float Y = Mathf.Sin(rad);
|
||||
|
||||
var vertex = UIVertex.simpleVert;
|
||||
vertex.color = _progress > 0 ? ProgressColor : color;
|
||||
|
||||
//initial vertex
|
||||
vertex.position = new Vector2(outerDiameter * X, outerDiameter * Y);
|
||||
vertex.uv0 = new Vector2(vertex.position.x / Diameter + 0.5f, vertex.position.y / Diameter + 0.5f);
|
||||
vertices.Add(vertex);
|
||||
|
||||
var iV = new Vector2(innerDiameter * X, innerDiameter * Y);
|
||||
if (Fill) iV = Vector2.zero; //center vertex to pivot
|
||||
vertex.position = iV;
|
||||
vertex.uv0 = Fill ? uvCenter : new Vector2(vertex.position.x / Diameter + 0.5f, vertex.position.y / Diameter + 0.5f);
|
||||
vertices.Add(vertex);
|
||||
|
||||
for (int counter = 1; counter <= ArcSteps; counter++)
|
||||
{
|
||||
rad = _inversion * Mathf.Deg2Rad * (counter * stepDegree + ArcRotation);
|
||||
X = Mathf.Cos(rad);
|
||||
Y = Mathf.Sin(rad);
|
||||
|
||||
vertex.color = counter > _progress ? color : ProgressColor;
|
||||
vertex.position = new Vector2(outerDiameter * X, outerDiameter * Y);
|
||||
vertex.uv0 = new Vector2(vertex.position.x / Diameter + 0.5f, vertex.position.y / Diameter + 0.5f);
|
||||
vertices.Add(vertex);
|
||||
|
||||
//add additional vertex if required and generate indices for tris in clockwise order
|
||||
if (!Fill)
|
||||
{
|
||||
vertex.position = new Vector2(innerDiameter * X, innerDiameter * Y);
|
||||
vertex.uv0 = new Vector2(vertex.position.x / Diameter + 0.5f, vertex.position.y / Diameter + 0.5f);
|
||||
vertices.Add(vertex);
|
||||
k = j;
|
||||
indices.Add(i);
|
||||
indices.Add(j + 1);
|
||||
indices.Add(j);
|
||||
j++;
|
||||
i = j;
|
||||
j++;
|
||||
indices.Add(i);
|
||||
indices.Add(j);
|
||||
indices.Add(k);
|
||||
}
|
||||
else
|
||||
{
|
||||
indices.Add(i);
|
||||
indices.Add(j + 1);
|
||||
//Fills (solid circle) with progress require an additional vertex to
|
||||
// prevent the base circle from becoming a gradient from center to edge
|
||||
if (counter > _progress)
|
||||
{
|
||||
indices.Add(ArcSteps + 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
indices.Add(1);
|
||||
}
|
||||
|
||||
j++;
|
||||
i = j;
|
||||
}
|
||||
}
|
||||
|
||||
//this vertex is added to the end of the list to simplify index ordering on geometry fill
|
||||
if (Fill)
|
||||
{
|
||||
vertex.position = iV;
|
||||
vertex.color = color;
|
||||
vertex.uv0 = uvCenter;
|
||||
vertices.Add(vertex);
|
||||
}
|
||||
vh.AddUIVertexStream(vertices, indices);
|
||||
}
|
||||
|
||||
//the following methods may be used during run-time
|
||||
//to update the properties of the component
|
||||
public void SetProgress(float progress)
|
||||
{
|
||||
Progress = progress;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetArc(float arc)
|
||||
{
|
||||
Arc = arc;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetArcSteps(int steps)
|
||||
{
|
||||
ArcSteps = steps;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetInvertArc(bool invert)
|
||||
{
|
||||
ArcInvert = invert;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetArcRotation(int rotation)
|
||||
{
|
||||
ArcRotation = rotation;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetFill(bool fill)
|
||||
{
|
||||
Fill = fill;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetBaseColor(Color color)
|
||||
{
|
||||
this.color = color;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void UpdateBaseAlpha(float value)
|
||||
{
|
||||
var _color = this.color;
|
||||
_color.a = value;
|
||||
this.color = _color;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetProgressColor(Color color)
|
||||
{
|
||||
ProgressColor = color;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void UpdateProgressAlpha(float value)
|
||||
{
|
||||
ProgressColor.a = value;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetPadding(int padding)
|
||||
{
|
||||
Padding = padding;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
|
||||
public void SetThickness(int thickness)
|
||||
{
|
||||
Thickness = thickness;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8185cad1aa202d04ebb9e14ffa533a87
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
@@ -0,0 +1,219 @@
|
||||
/// <summary>
|
||||
/// Created by Freezy - ElicitIce.nl
|
||||
/// Posted on Unity Forums http://forum.unity3d.com/threads/cut-corners-primative.359494/
|
||||
///
|
||||
/// Free for any use and alteration, source code may not be sold without my permission.
|
||||
/// If you make improvements on this script please share them with the community.
|
||||
///
|
||||
///
|
||||
/// Here is a script that will take a rectangular TransformRect and cut off some corners based on the corner size.
|
||||
/// This is great for when you need a quick and easy non-square panel/image.
|
||||
/// Enjoy!
|
||||
/// It adds an additional square if the relevant side has a corner cut, it then offsets the ends to simulate a cut corner.
|
||||
/// UVs are being set, but might be skewed when a texture is applied.
|
||||
/// You could hide the additional colors by using the following:
|
||||
/// http://rumorgames.com/hide-in-inspector/
|
||||
///
|
||||
/// </summary>
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/Cut Corners")]
|
||||
public class UICornerCut : UIPrimitiveBase
|
||||
{
|
||||
public Vector2 cornerSize = new Vector2(16, 16);
|
||||
|
||||
[Header("Corners to cut")]
|
||||
[SerializeField]
|
||||
private bool m_cutUL = true;
|
||||
[SerializeField]
|
||||
private bool m_cutUR;
|
||||
[SerializeField]
|
||||
private bool m_cutLL;
|
||||
[SerializeField]
|
||||
private bool m_cutLR;
|
||||
|
||||
[Tooltip("Up-Down colors become Left-Right colors")]
|
||||
[SerializeField]
|
||||
private bool m_makeColumns;
|
||||
|
||||
[Header("Color the cut bars differently")]
|
||||
[SerializeField]
|
||||
private bool m_useColorUp;
|
||||
[SerializeField]
|
||||
private Color32 m_colorUp;
|
||||
[SerializeField]
|
||||
private bool m_useColorDown;
|
||||
[SerializeField]
|
||||
private Color32 m_colorDown;
|
||||
|
||||
public bool CutUL
|
||||
{
|
||||
get { return m_cutUL; }
|
||||
set { m_cutUL = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool CutUR
|
||||
{
|
||||
get { return m_cutUR; }
|
||||
set { m_cutUR = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool CutLL
|
||||
{
|
||||
get { return m_cutLL; }
|
||||
set { m_cutLL = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool CutLR
|
||||
{
|
||||
get { return m_cutLR; }
|
||||
set { m_cutLR = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool MakeColumns
|
||||
{
|
||||
get { return m_makeColumns; }
|
||||
set { m_makeColumns = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool UseColorUp
|
||||
{
|
||||
get { return m_useColorUp; }
|
||||
set { m_useColorUp = value; }
|
||||
}
|
||||
|
||||
public Color32 ColorUp
|
||||
{
|
||||
get { return m_colorUp; }
|
||||
set { m_colorUp = value; }
|
||||
}
|
||||
|
||||
public bool UseColorDown
|
||||
{
|
||||
get { return m_useColorDown; }
|
||||
set { m_useColorDown = value; }
|
||||
}
|
||||
|
||||
public Color32 ColorDown
|
||||
{
|
||||
get { return m_colorDown; }
|
||||
set { m_colorDown = value; }
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
var rect = rectTransform.rect;
|
||||
var rectNew = rect;
|
||||
|
||||
Color32 color32 = color;
|
||||
bool up = m_cutUL | m_cutUR;
|
||||
bool down = m_cutLL | m_cutLR;
|
||||
bool left = m_cutLL | m_cutUL;
|
||||
bool right = m_cutLR | m_cutUR;
|
||||
bool any = up | down;
|
||||
|
||||
if (any && cornerSize.sqrMagnitude > 0)
|
||||
{
|
||||
|
||||
//nibble off the sides
|
||||
vh.Clear();
|
||||
if (left)
|
||||
rectNew.xMin += cornerSize.x;
|
||||
if (down)
|
||||
rectNew.yMin += cornerSize.y;
|
||||
if (up)
|
||||
rectNew.yMax -= cornerSize.y;
|
||||
if (right)
|
||||
rectNew.xMax -= cornerSize.x;
|
||||
|
||||
//add two squares to the main square
|
||||
Vector2 ul, ur, ll, lr;
|
||||
|
||||
if (m_makeColumns)
|
||||
{
|
||||
ul = new Vector2(rect.xMin, m_cutUL ? rectNew.yMax : rect.yMax);
|
||||
ur = new Vector2(rect.xMax, m_cutUR ? rectNew.yMax : rect.yMax);
|
||||
ll = new Vector2(rect.xMin, m_cutLL ? rectNew.yMin : rect.yMin);
|
||||
lr = new Vector2(rect.xMax, m_cutLR ? rectNew.yMin : rect.yMin);
|
||||
|
||||
if (left)
|
||||
AddSquare(
|
||||
ll, ul,
|
||||
new Vector2(rectNew.xMin, rect.yMax),
|
||||
new Vector2(rectNew.xMin, rect.yMin),
|
||||
rect, m_useColorUp ? m_colorUp : color32, vh);
|
||||
if (right)
|
||||
AddSquare(
|
||||
ur, lr,
|
||||
new Vector2(rectNew.xMax, rect.yMin),
|
||||
new Vector2(rectNew.xMax, rect.yMax),
|
||||
rect, m_useColorDown ? m_colorDown : color32, vh);
|
||||
}
|
||||
else
|
||||
{
|
||||
ul = new Vector2(m_cutUL ? rectNew.xMin : rect.xMin, rect.yMax);
|
||||
ur = new Vector2(m_cutUR ? rectNew.xMax : rect.xMax, rect.yMax);
|
||||
ll = new Vector2(m_cutLL ? rectNew.xMin : rect.xMin, rect.yMin);
|
||||
lr = new Vector2(m_cutLR ? rectNew.xMax : rect.xMax, rect.yMin);
|
||||
if (down)
|
||||
AddSquare(
|
||||
lr, ll,
|
||||
new Vector2(rect.xMin, rectNew.yMin),
|
||||
new Vector2(rect.xMax, rectNew.yMin),
|
||||
rect, m_useColorDown ? m_colorDown : color32, vh);
|
||||
if (up)
|
||||
AddSquare(
|
||||
ul, ur,
|
||||
new Vector2(rect.xMax, rectNew.yMax),
|
||||
new Vector2(rect.xMin, rectNew.yMax),
|
||||
rect, m_useColorUp ? m_colorUp : color32, vh);
|
||||
}
|
||||
|
||||
//center
|
||||
if (m_makeColumns)
|
||||
AddSquare(new Rect(rectNew.xMin, rect.yMin, rectNew.width, rect.height), rect, color32, vh);
|
||||
else
|
||||
AddSquare(new Rect(rect.xMin, rectNew.yMin, rect.width, rectNew.height), rect, color32, vh);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void AddSquare(Rect rect, Rect rectUV, Color32 color32, VertexHelper vh) {
|
||||
int v0 = AddVert(rect.xMin, rect.yMin, rectUV, color32, vh);
|
||||
int v1 = AddVert(rect.xMin, rect.yMax, rectUV, color32, vh);
|
||||
int v2 = AddVert(rect.xMax, rect.yMax, rectUV, color32, vh);
|
||||
int v3 = AddVert(rect.xMax, rect.yMin, rectUV, color32, vh);
|
||||
|
||||
vh.AddTriangle(v0, v1, v2);
|
||||
vh.AddTriangle(v2, v3, v0);
|
||||
}
|
||||
|
||||
private static void AddSquare(Vector2 a, Vector2 b, Vector2 c, Vector2 d, Rect rectUV, Color32 color32, VertexHelper vh) {
|
||||
int v0 = AddVert(a.x, a.y, rectUV, color32, vh);
|
||||
int v1 = AddVert(b.x, b.y, rectUV, color32, vh);
|
||||
int v2 = AddVert(c.x, c.y, rectUV, color32, vh);
|
||||
int v3 = AddVert(d.x, d.y, rectUV, color32, vh);
|
||||
|
||||
vh.AddTriangle(v0, v1, v2);
|
||||
vh.AddTriangle(v2, v3, v0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Auto UV handler within the assigned area
|
||||
/// </summary>
|
||||
/// <param name="x"></param>
|
||||
/// <param name="y"></param>
|
||||
/// <param name="area"></param>
|
||||
/// <param name="color32"></param>
|
||||
/// <param name="vh"></param>
|
||||
private static int AddVert(float x, float y, Rect area, Color32 color32, VertexHelper vh) {
|
||||
var uv = new Vector2(
|
||||
Mathf.InverseLerp(area.xMin, area.xMax, x),
|
||||
Mathf.InverseLerp(area.yMin, area.yMax, y)
|
||||
);
|
||||
vh.AddVert(new Vector3(x, y), color32, uv);
|
||||
return vh.currentVertCount - 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a6e620ffa5a4e64b8875761130d0139
|
||||
timeCreated: 1444419848
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
/// Credit John Hattan (http://thecodezone.com/)
|
||||
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/117/uigridrenderer
|
||||
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UIGridRenderer")]
|
||||
public class UIGridRenderer : UILineRenderer
|
||||
{
|
||||
[SerializeField]
|
||||
private int m_GridColumns = 10;
|
||||
[SerializeField]
|
||||
private int m_GridRows = 10;
|
||||
|
||||
/// <summary>
|
||||
/// Number of columns in the Grid
|
||||
/// </summary>
|
||||
public int GridColumns
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_GridColumns;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_GridColumns == value)
|
||||
return;
|
||||
m_GridColumns = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of rows in the grid.
|
||||
/// </summary>
|
||||
public int GridRows
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_GridRows;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_GridRows == value)
|
||||
return;
|
||||
m_GridRows = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
relativeSize = true;
|
||||
|
||||
int ArraySize = (GridRows * 3) + 1;
|
||||
if(GridRows % 2 == 0)
|
||||
++ArraySize; // needs one more line
|
||||
|
||||
ArraySize += (GridColumns * 3) + 1;
|
||||
|
||||
m_points = new Vector2[ArraySize];
|
||||
|
||||
int Index = 0;
|
||||
for(int i = 0; i < GridRows; ++i)
|
||||
{
|
||||
float xFrom = 1;
|
||||
float xTo = 0;
|
||||
if(i % 2 == 0)
|
||||
{
|
||||
// reach left instead
|
||||
xFrom = 0;
|
||||
xTo = 1;
|
||||
}
|
||||
|
||||
float y = ((float)i) / GridRows;
|
||||
m_points[Index].x = xFrom;
|
||||
m_points[Index].y = y;
|
||||
++Index;
|
||||
m_points[Index].x = xTo;
|
||||
m_points[Index].y = y;
|
||||
++Index;
|
||||
m_points[Index].x = xTo;
|
||||
m_points[Index].y = (float)(i + 1) / GridRows;
|
||||
++Index;
|
||||
}
|
||||
|
||||
if(GridRows % 2 == 0)
|
||||
{
|
||||
// two lines to get to 0, 1
|
||||
m_points[Index].x = 1;
|
||||
m_points[Index].y = 1;
|
||||
++Index;
|
||||
}
|
||||
|
||||
m_points[Index].x = 0;
|
||||
m_points[Index].y = 1;
|
||||
++Index;
|
||||
|
||||
// line is now at 0,1, so we can draw the columns
|
||||
for(int i = 0; i < GridColumns; ++i)
|
||||
{
|
||||
float yFrom = 1;
|
||||
float yTo = 0;
|
||||
if(i % 2 == 0)
|
||||
{
|
||||
// reach up instead
|
||||
yFrom = 0;
|
||||
yTo = 1;
|
||||
}
|
||||
|
||||
float x = ((float)i) / GridColumns;
|
||||
m_points[Index].x = x;
|
||||
m_points[Index].y = yFrom;
|
||||
++Index;
|
||||
m_points[Index].x = x;
|
||||
m_points[Index].y = yTo;
|
||||
++Index;
|
||||
m_points[Index].x = (float)(i + 1) / GridColumns;
|
||||
m_points[Index].y = yTo;
|
||||
++Index;
|
||||
}
|
||||
|
||||
if(GridColumns % 2 == 0)
|
||||
{
|
||||
// one more line to get to 1, 1
|
||||
m_points[Index].x = 1;
|
||||
m_points[Index].y = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
// one more line to get to 1, 0
|
||||
m_points[Index].x = 1;
|
||||
m_points[Index].y = 0;
|
||||
}
|
||||
|
||||
base.OnPopulateMesh(vh);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 35ff6e8800018654d9558db07c4cd080
|
||||
timeCreated: 1487335372
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,508 @@
|
||||
/// Credit jack.sydorenko, firagon
|
||||
/// Sourced from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
|
||||
/// Updated/Refactored from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/#post-2528050
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class UILineRenderer : UIPrimitiveBase
|
||||
{
|
||||
private enum SegmentType
|
||||
{
|
||||
Start,
|
||||
Middle,
|
||||
End,
|
||||
Full,
|
||||
}
|
||||
|
||||
public enum JoinType
|
||||
{
|
||||
Bevel,
|
||||
Miter
|
||||
}
|
||||
|
||||
public enum BezierType
|
||||
{
|
||||
None,
|
||||
Quick,
|
||||
Basic,
|
||||
Improved,
|
||||
Catenary,
|
||||
}
|
||||
|
||||
private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
|
||||
|
||||
// A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
|
||||
// quad to connect the endpoints. This improves the look of textured and transparent lines, since
|
||||
// there is no overlapping.
|
||||
private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
|
||||
|
||||
private static Vector2 UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_TOP_CENTER_LEFT, UV_TOP_CENTER_RIGHT, UV_BOTTOM_CENTER_LEFT, UV_BOTTOM_CENTER_RIGHT, UV_TOP_RIGHT, UV_BOTTOM_RIGHT;
|
||||
private static Vector2[] startUvs, middleUvs, endUvs, fullUvs;
|
||||
|
||||
[SerializeField, Tooltip("Points to draw lines between\n Can be improved using the Resolution Option")]
|
||||
internal Vector2[] m_points;
|
||||
[SerializeField, Tooltip("Segments to be drawn\n This is a list of arrays of points")]
|
||||
internal List<Vector2[]> m_segments;
|
||||
|
||||
[SerializeField, Tooltip("Thickness of the line")]
|
||||
internal float lineThickness = 2;
|
||||
[SerializeField, Tooltip("Use the relative bounds of the Rect Transform (0,0 -> 0,1) or screen space coordinates")]
|
||||
internal bool relativeSize;
|
||||
[SerializeField, Tooltip("Do the points identify a single line or split pairs of lines")]
|
||||
internal bool lineList;
|
||||
[SerializeField, Tooltip("Add end caps to each line\nMultiple caps when used with Line List")]
|
||||
internal bool lineCaps;
|
||||
[SerializeField, Tooltip("Resolution of the Bezier curve, different to line Resolution")]
|
||||
internal int bezierSegmentsPerCurve = 10;
|
||||
|
||||
public float LineThickness
|
||||
{
|
||||
get { return lineThickness; }
|
||||
set { lineThickness = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool RelativeSize
|
||||
{
|
||||
get { return relativeSize; }
|
||||
set { relativeSize = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool LineList
|
||||
{
|
||||
get { return lineList; }
|
||||
set { lineList = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool LineCaps
|
||||
{
|
||||
get { return lineCaps; }
|
||||
set { lineCaps = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
[Tooltip("The type of Join used between lines, Square/Mitre or Curved/Bevel")]
|
||||
public JoinType LineJoins = JoinType.Bevel;
|
||||
|
||||
[Tooltip("Bezier method to apply to line, see docs for options\nCan't be used in conjunction with Resolution as Bezier already changes the resolution")]
|
||||
public BezierType BezierMode = BezierType.None;
|
||||
|
||||
public int BezierSegmentsPerCurve
|
||||
{
|
||||
get { return bezierSegmentsPerCurve; }
|
||||
set { bezierSegmentsPerCurve = value; }
|
||||
}
|
||||
|
||||
[HideInInspector]
|
||||
public bool drivenExternally = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Points to be drawn in the line.
|
||||
/// </summary>
|
||||
public Vector2[] Points
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_points;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_points == value) return;
|
||||
|
||||
if (value == null || value.Length == 0)
|
||||
{
|
||||
m_points = new Vector2[1];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_points = value;
|
||||
}
|
||||
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of Segments to be drawn.
|
||||
/// </summary>
|
||||
public List<Vector2[]> Segments
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_segments;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_segments = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
private void PopulateMesh(VertexHelper vh, Vector2[] pointsToDraw)
|
||||
{
|
||||
//If Bezier is desired, pick the implementation
|
||||
if (BezierMode != BezierType.None && BezierMode != BezierType.Catenary && pointsToDraw.Length > 3) {
|
||||
BezierPath bezierPath = new BezierPath ();
|
||||
|
||||
bezierPath.SetControlPoints (pointsToDraw);
|
||||
bezierPath.SegmentsPerCurve = bezierSegmentsPerCurve;
|
||||
List<Vector2> drawingPoints;
|
||||
switch (BezierMode) {
|
||||
case BezierType.Basic:
|
||||
drawingPoints = bezierPath.GetDrawingPoints0 ();
|
||||
break;
|
||||
case BezierType.Improved:
|
||||
drawingPoints = bezierPath.GetDrawingPoints1 ();
|
||||
break;
|
||||
default:
|
||||
drawingPoints = bezierPath.GetDrawingPoints2 ();
|
||||
break;
|
||||
}
|
||||
|
||||
pointsToDraw = drawingPoints.ToArray ();
|
||||
}
|
||||
if (BezierMode == BezierType.Catenary && pointsToDraw.Length == 2) {
|
||||
CableCurve cable = new CableCurve (pointsToDraw);
|
||||
cable.slack = Resolution;
|
||||
cable.steps = BezierSegmentsPerCurve;
|
||||
pointsToDraw = cable.Points ();
|
||||
}
|
||||
|
||||
if (ImproveResolution != ResolutionMode.None) {
|
||||
pointsToDraw = IncreaseResolution (pointsToDraw);
|
||||
}
|
||||
|
||||
// scale based on the size of the rect or use absolute, this is switchable
|
||||
var sizeX = !relativeSize ? 1 : rectTransform.rect.width;
|
||||
var sizeY = !relativeSize ? 1 : rectTransform.rect.height;
|
||||
var offsetX = -rectTransform.pivot.x * sizeX;
|
||||
var offsetY = -rectTransform.pivot.y * sizeY;
|
||||
|
||||
// Generate the quads that make up the wide line
|
||||
var segments = new List<UIVertex[]> ();
|
||||
if (lineList) {
|
||||
//Loop through list in line pairs, skipping drawing between lines
|
||||
for (var i = 1; i < pointsToDraw.Length; i += 2) {
|
||||
var start = pointsToDraw [i - 1];
|
||||
var end = pointsToDraw [i];
|
||||
start = new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||
end = new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||
|
||||
if (lineCaps) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.Start));
|
||||
}
|
||||
|
||||
// Originally, UV's had to be wrapped per segment to ensure textures rendered correctly, however when tested in 2019.4, this no longer seems to be an issue.
|
||||
segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
|
||||
|
||||
if (lineCaps) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.End));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Draw full lines
|
||||
for (var i = 1; i < pointsToDraw.Length; i++) {
|
||||
var start = pointsToDraw [i - 1];
|
||||
var end = pointsToDraw [i];
|
||||
start = new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||
end = new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||
|
||||
if (lineCaps && i == 1) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.Start));
|
||||
}
|
||||
|
||||
segments.Add (CreateLineSegment (start, end, SegmentType.Middle));
|
||||
|
||||
if (lineCaps && i == pointsToDraw.Length - 1) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.End));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the line segments to the vertex helper, creating any joins as needed
|
||||
for (var i = 0; i < segments.Count; i++) {
|
||||
if (!lineList && i < segments.Count - 1) {
|
||||
var vec1 = segments [i] [1].position - segments [i] [2].position;
|
||||
var vec2 = segments [i + 1] [2].position - segments [i + 1] [1].position;
|
||||
var angle = Vector2.Angle (vec1, vec2) * Mathf.Deg2Rad;
|
||||
|
||||
// Positive sign means the line is turning in a 'clockwise' direction
|
||||
var sign = Mathf.Sign (Vector3.Cross (vec1.normalized, vec2.normalized).z);
|
||||
|
||||
// Calculate the miter point
|
||||
var miterDistance = lineThickness / (2 * Mathf.Tan (angle / 2));
|
||||
var miterPointA = segments [i] [2].position - vec1.normalized * miterDistance * sign;
|
||||
var miterPointB = segments [i] [3].position + vec1.normalized * miterDistance * sign;
|
||||
|
||||
var joinType = LineJoins;
|
||||
if (joinType == JoinType.Miter) {
|
||||
// Make sure we can make a miter join without too many artifacts.
|
||||
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN) {
|
||||
segments [i] [2].position = miterPointA;
|
||||
segments [i] [3].position = miterPointB;
|
||||
segments [i + 1] [0].position = miterPointB;
|
||||
segments [i + 1] [1].position = miterPointA;
|
||||
} else {
|
||||
joinType = JoinType.Bevel;
|
||||
}
|
||||
}
|
||||
|
||||
if (joinType == JoinType.Bevel) {
|
||||
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
|
||||
if (sign < 0) {
|
||||
segments [i] [2].position = miterPointA;
|
||||
segments [i + 1] [1].position = miterPointA;
|
||||
} else {
|
||||
segments [i] [3].position = miterPointB;
|
||||
segments [i + 1] [0].position = miterPointB;
|
||||
}
|
||||
}
|
||||
|
||||
var join = new UIVertex[] { segments [i] [2], segments [i] [3], segments [i + 1] [0], segments [i + 1] [1] };
|
||||
vh.AddUIVertexQuad (join);
|
||||
}
|
||||
}
|
||||
|
||||
vh.AddUIVertexQuad (segments [i]);
|
||||
}
|
||||
if (vh.currentVertCount > 64000) {
|
||||
Debug.LogError ("Max Verticies size is 64000, current mesh verticies count is [" + vh.currentVertCount + "] - Cannot Draw");
|
||||
vh.Clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
if (m_points != null && m_points.Length > 0) {
|
||||
GeneratedUVs ();
|
||||
vh.Clear ();
|
||||
|
||||
PopulateMesh (vh, m_points);
|
||||
|
||||
}
|
||||
if (m_segments != null && m_segments.Count > 0) {
|
||||
GeneratedUVs ();
|
||||
vh.Clear ();
|
||||
|
||||
for (int s = 0; s < m_segments.Count; s++) {
|
||||
Vector2[] pointsToDraw = m_segments [s];
|
||||
PopulateMesh (vh, pointsToDraw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
|
||||
{
|
||||
if (type == SegmentType.Start)
|
||||
{
|
||||
var capStart = start - ((end - start).normalized * lineThickness / 2);
|
||||
return CreateLineSegment(capStart, start, SegmentType.Start);
|
||||
}
|
||||
else if (type == SegmentType.End)
|
||||
{
|
||||
var capEnd = end + ((end - start).normalized * lineThickness / 2);
|
||||
return CreateLineSegment(end, capEnd, SegmentType.End);
|
||||
}
|
||||
|
||||
Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
|
||||
return null;
|
||||
}
|
||||
|
||||
private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type, UIVertex[] previousVert = null)
|
||||
{
|
||||
Vector2 offset = new Vector2((start.y - end.y), end.x - start.x).normalized * lineThickness / 2;
|
||||
|
||||
Vector2 v1 = Vector2.zero;
|
||||
Vector2 v2 = Vector2.zero;
|
||||
if (previousVert != null) {
|
||||
v1 = new Vector2(previousVert[3].position.x, previousVert[3].position.y);
|
||||
v2 = new Vector2(previousVert[2].position.x, previousVert[2].position.y);
|
||||
} else {
|
||||
v1 = start - offset;
|
||||
v2 = start + offset;
|
||||
}
|
||||
|
||||
var v3 = end + offset;
|
||||
var v4 = end - offset;
|
||||
//Return the VDO with the correct uvs
|
||||
switch (type)
|
||||
{
|
||||
case SegmentType.Start:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, startUvs);
|
||||
case SegmentType.End:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, endUvs);
|
||||
case SegmentType.Full:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, fullUvs);
|
||||
default:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, middleUvs);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void GeneratedUVs()
|
||||
{
|
||||
if (activeSprite != null)
|
||||
{
|
||||
var outer = Sprites.DataUtility.GetOuterUV(activeSprite);
|
||||
var inner = Sprites.DataUtility.GetInnerUV(activeSprite);
|
||||
UV_TOP_LEFT = new Vector2(outer.x, outer.y);
|
||||
UV_BOTTOM_LEFT = new Vector2(outer.x, outer.w);
|
||||
UV_TOP_CENTER_LEFT = new Vector2(inner.x, inner.y);
|
||||
UV_TOP_CENTER_RIGHT = new Vector2(inner.z, inner.y);
|
||||
UV_BOTTOM_CENTER_LEFT = new Vector2(inner.x, inner.w);
|
||||
UV_BOTTOM_CENTER_RIGHT = new Vector2(inner.z, inner.w);
|
||||
UV_TOP_RIGHT = new Vector2(outer.z, outer.y);
|
||||
UV_BOTTOM_RIGHT = new Vector2(outer.z, outer.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
UV_TOP_LEFT = Vector2.zero;
|
||||
UV_BOTTOM_LEFT = new Vector2(0, 1);
|
||||
UV_TOP_CENTER_LEFT = new Vector2(0.5f, 0);
|
||||
UV_TOP_CENTER_RIGHT = new Vector2(0.5f, 0);
|
||||
UV_BOTTOM_CENTER_LEFT = new Vector2(0.5f, 1);
|
||||
UV_BOTTOM_CENTER_RIGHT = new Vector2(0.5f, 1);
|
||||
UV_TOP_RIGHT = new Vector2(1, 0);
|
||||
UV_BOTTOM_RIGHT = Vector2.one;
|
||||
}
|
||||
|
||||
|
||||
startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER_LEFT, UV_TOP_CENTER_LEFT };
|
||||
middleUvs = new[] { UV_TOP_CENTER_LEFT, UV_BOTTOM_CENTER_LEFT, UV_BOTTOM_CENTER_RIGHT, UV_TOP_CENTER_RIGHT };
|
||||
endUvs = new[] { UV_TOP_CENTER_RIGHT, UV_BOTTOM_CENTER_RIGHT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
|
||||
fullUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
|
||||
}
|
||||
|
||||
protected override void ResolutionToNativeSize(float distance)
|
||||
{
|
||||
if (UseNativeSize)
|
||||
{
|
||||
m_Resolution = distance / (activeSprite.rect.width / pixelsPerUnit);
|
||||
lineThickness = activeSprite.rect.height / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
private int GetSegmentPointCount()
|
||||
{
|
||||
if (Segments?.Count > 0)
|
||||
{
|
||||
int pointCount = 0;
|
||||
foreach (var segment in Segments)
|
||||
{
|
||||
pointCount += segment.Length;
|
||||
}
|
||||
return pointCount;
|
||||
}
|
||||
return Points.Length;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Vector2 position of a line index
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Positive numbers should be used to specify Index and Segment
|
||||
/// </remarks>
|
||||
/// <param name="index">Required Index of the point, starting from point 1</param>
|
||||
/// <param name="segmentIndex">(optional) Required Segment the point is held in, Starting from Segment 1</param>
|
||||
/// <returns>Vector2 position of the point within UI Space</returns>
|
||||
public Vector2 GetPosition(int index, int segmentIndex = 0)
|
||||
{
|
||||
if (segmentIndex > 0)
|
||||
{
|
||||
return Segments[segmentIndex - 1][index - 1];
|
||||
}
|
||||
else if (Segments?.Count > 0)
|
||||
{
|
||||
var segmentIndexCount = 0;
|
||||
var indexCount = index;
|
||||
foreach (var segment in Segments)
|
||||
{
|
||||
if (indexCount - segment.Length > 0)
|
||||
{
|
||||
indexCount -= segment.Length;
|
||||
segmentIndexCount += 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Segments[segmentIndexCount][indexCount - 1];
|
||||
}
|
||||
else
|
||||
{
|
||||
return Points[index - 1];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calculates the position of a point on the curve, given t (0-1), start point, control points and end point.
|
||||
/// </summary>
|
||||
/// <param name="t">Required Percentage between start and end point, in the range 0 to 1</param>
|
||||
/// <param name="p1">Required Starting point</param>
|
||||
/// <param name="p1">Required Control point 1</param>
|
||||
/// <param name="p1">Required Control point 2</param>
|
||||
/// <param name="p1">Required End point</param>
|
||||
/// <returns>Vector2 position of point on curve at t percentage between p1 and p4</returns>
|
||||
public Vector2 CalculatePointOnCurve(float t, Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4)
|
||||
{
|
||||
var t2 = t * t;
|
||||
var t3 = t2 * t;
|
||||
|
||||
var x = p1.x + (-p1.x * 3 + t * (3 * p1.x - p1.x * t)) * t + (3 * p2.x + t * (-6 * p2.x + p2.x * 3 * t)) * t +
|
||||
(p3.x * 3 - p3.x * 3 * t) * t2 + p4.x * t3;
|
||||
|
||||
var y = p1.y + (-p1.y * 3 + t * (3 * p1.y - p1.y * t)) * t + (3 * p2.y + t * (-6 * p2.y + p2.y * 3 * t)) * t +
|
||||
(p3.y * 3 - p3.y * 3 * t) * t2 + p4.y * t3;
|
||||
|
||||
return new Vector2(x, y);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the Vector2 position of a line within a specific segment
|
||||
/// </summary>
|
||||
/// <param name="index">Required Index of the point, starting from point 1</param>
|
||||
/// <param name="segmentIndex"> Required Segment the point is held in, Starting from Segment 1</param>
|
||||
/// <returns>Vector2 position of the point within UI Space</returns>
|
||||
public Vector2 GetPositionBySegment(int index, int segment)
|
||||
{
|
||||
return Segments[segment][index - 1];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the closest point between two given Vector2s from a given Vector2 point
|
||||
/// </summary>
|
||||
/// <param name="p1">Starting position</param>
|
||||
/// <param name="p2">End position</param>
|
||||
/// <param name="p3">Desired / Selected point</param>
|
||||
/// <returns>Closest Vector2 position of the target within UI Space</returns>
|
||||
public Vector2 GetClosestPoint(Vector2 p1, Vector2 p2, Vector2 p3)
|
||||
{
|
||||
Vector2 from_p1_to_p3 = p3 - p1;
|
||||
Vector2 from_p1_to_p2 = p2 - p1;
|
||||
float dot = Vector2.Dot(from_p1_to_p3, from_p1_to_p2.normalized);
|
||||
dot /= from_p1_to_p2.magnitude;
|
||||
float t = Mathf.Clamp01(dot);
|
||||
return p1 + from_p1_to_p2 * t;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
if (m_points == null || m_points?.Length == 0)
|
||||
{
|
||||
m_points = new Vector2[1];
|
||||
}
|
||||
if (transform.GetComponent<RectTransform>().position != Vector3.zero)
|
||||
{
|
||||
Debug.LogWarning("A Line Renderer component should be on a RectTransform positioned at (0,0,0), do not use in child Objects.\nFor best results, create separate RectTransforms as children of the canvas positioned at (0,0) for a UILineRenderer and do not move.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b33b2e663e78774c9f0c9af55018725
|
||||
timeCreated: 1440845580
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,146 @@
|
||||
/// Credit Steve Westhoff, jack.sydorenko, firagon
|
||||
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/324
|
||||
/// Refactored and updated for performance from UILineRenderer by Steve Westhoff
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UILineRendererFIFO")]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class UILineRendererFIFO : UIPrimitiveBase
|
||||
{
|
||||
private static readonly Vector2[] middleUvs = new[] { new Vector2(0.5f, 0), new Vector2(0.5f, 1), new Vector2(0.5f, 1), new Vector2(0.5f, 0) };
|
||||
private List<Vector2> addedPoints = new List<Vector2>();
|
||||
private bool needsResize;
|
||||
|
||||
[SerializeField, Tooltip("Thickness of the line")]
|
||||
private float lineThickness = 1;
|
||||
|
||||
[SerializeField, Tooltip("Points to draw lines between\n Can be improved using the Resolution Option")]
|
||||
private List<Vector2> points = new List<Vector2>();
|
||||
|
||||
[SerializeField, Tooltip("Segments to be drawn\n This is a list of arrays of points")]
|
||||
private List<UIVertex[]> segments = new List<UIVertex[]>();
|
||||
|
||||
/// <summary>
|
||||
/// Thickness of the line
|
||||
/// </summary>
|
||||
public float LineThickness
|
||||
{
|
||||
get { return lineThickness; }
|
||||
set { lineThickness = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Points to be drawn in the line.
|
||||
/// </summary>
|
||||
/// <remarks>Don't add points to the list directly, use the add / remove functions</remarks>
|
||||
public List<Vector2> Points
|
||||
{
|
||||
get
|
||||
{
|
||||
return points;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (points == value)
|
||||
return;
|
||||
points = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds to head
|
||||
/// </summary>
|
||||
/// <param name="point"></param>
|
||||
public void AddPoint(Vector2 point) {
|
||||
points.Add(point);
|
||||
addedPoints.Add(point);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes from tail (FIFO)
|
||||
/// </summary>
|
||||
public void RemovePoint() {
|
||||
points.RemoveAt(0);
|
||||
needsResize = true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all the points from the LineRenderer
|
||||
/// </summary>
|
||||
public void ClearPoints()
|
||||
{
|
||||
segments.Clear();
|
||||
points.Clear();
|
||||
addedPoints.Clear();
|
||||
needsResize = false;
|
||||
}
|
||||
|
||||
public void Resize() {
|
||||
needsResize = true;
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vertexHelper) {
|
||||
vertexHelper.Clear();
|
||||
if(needsResize) {
|
||||
needsResize = false;
|
||||
segments.Clear();
|
||||
addedPoints = new List<Vector2>(points);
|
||||
}
|
||||
int count = addedPoints.Count;
|
||||
if(count > 1) {
|
||||
PopulateMesh(addedPoints, vertexHelper);
|
||||
if(count % 2 == 0) {
|
||||
addedPoints.Clear();
|
||||
} else {
|
||||
Vector2 extraPoint = addedPoints[count - 1];
|
||||
addedPoints.Clear();
|
||||
addedPoints.Add(extraPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PopulateMesh(List<Vector2> pointsToDraw, VertexHelper vertexHelper) {
|
||||
if(ImproveResolution != ResolutionMode.None) {
|
||||
pointsToDraw = IncreaseResolution(pointsToDraw);
|
||||
}
|
||||
float sizeX = rectTransform.rect.width;
|
||||
float sizeY = rectTransform.rect.height;
|
||||
float offsetX = -rectTransform.pivot.x * sizeX;
|
||||
float offsetY = -rectTransform.pivot.y * sizeY;
|
||||
for(int i = 1; i < pointsToDraw.Count; i += 2) {
|
||||
Vector2 start = pointsToDraw[i - 1];
|
||||
Vector2 end = pointsToDraw[i];
|
||||
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||
UIVertex[] segment = CreateLineSegment(start, end, segments.Count > 1 ? segments[segments.Count - 2] : null);
|
||||
segments.Add(segment);
|
||||
}
|
||||
for(int i = 0; i < segments.Count; i++) {
|
||||
vertexHelper.AddUIVertexQuad(segments[i]);
|
||||
}
|
||||
if(vertexHelper.currentVertCount > 64000) {
|
||||
Debug.LogError("Max Verticies size is 64000, current mesh vertcies count is [" + vertexHelper.currentVertCount + "] - Cannot Draw");
|
||||
vertexHelper.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, UIVertex[] previousVert = null) {
|
||||
Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * lineThickness * 0.5f;
|
||||
Vector2 v1;
|
||||
Vector2 v2;
|
||||
if(previousVert != null) {
|
||||
v1 = new Vector2(previousVert[3].position.x, previousVert[3].position.y);
|
||||
v2 = new Vector2(previousVert[2].position.x, previousVert[2].position.y);
|
||||
} else {
|
||||
v1 = start - offset;
|
||||
v2 = start + offset;
|
||||
}
|
||||
return SetVbo(new[] { v1, v2, end + offset, end - offset }, middleUvs);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a3a91607af301f241b9f0a860c720b21
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,367 @@
|
||||
/// Credit jack.sydorenko, firagon
|
||||
/// Sourced from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
|
||||
/// Updated/Refactored from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/#post-2528050
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UILineRendererList")]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class UILineRendererList : UIPrimitiveBase
|
||||
{
|
||||
private enum SegmentType
|
||||
{
|
||||
Start,
|
||||
Middle,
|
||||
End,
|
||||
Full,
|
||||
}
|
||||
|
||||
public enum JoinType
|
||||
{
|
||||
Bevel,
|
||||
Miter
|
||||
}
|
||||
|
||||
public enum BezierType
|
||||
{
|
||||
None,
|
||||
Quick,
|
||||
Basic,
|
||||
Improved,
|
||||
Catenary,
|
||||
}
|
||||
|
||||
private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
|
||||
|
||||
// A bevel 'nice' join displaces the vertices of the line segment instead of simply rendering a
|
||||
// quad to connect the endpoints. This improves the look of textured and transparent lines, since
|
||||
// there is no overlapping.
|
||||
private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
|
||||
|
||||
private static Vector2 UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_TOP_CENTER_LEFT, UV_TOP_CENTER_RIGHT, UV_BOTTOM_CENTER_LEFT, UV_BOTTOM_CENTER_RIGHT, UV_TOP_RIGHT, UV_BOTTOM_RIGHT;
|
||||
private static Vector2[] startUvs, middleUvs, endUvs, fullUvs;
|
||||
|
||||
[SerializeField, Tooltip("Points to draw lines between\n Can be improved using the Resolution Option")]
|
||||
internal List<Vector2> m_points;
|
||||
// [SerializeField, Tooltip("Segments to be drawn\n This is a list of arrays of points")]
|
||||
//internal List<Vector2[]> m_segments;
|
||||
|
||||
[SerializeField, Tooltip("Thickness of the line")]
|
||||
internal float lineThickness = 2;
|
||||
[SerializeField, Tooltip("Use the relative bounds of the Rect Transform (0,0 -> 0,1) or screen space coordinates")]
|
||||
internal bool relativeSize;
|
||||
[SerializeField, Tooltip("Do the points identify a single line or split pairs of lines")]
|
||||
internal bool lineList;
|
||||
[SerializeField, Tooltip("Add end caps to each line\nMultiple caps when used with Line List")]
|
||||
internal bool lineCaps;
|
||||
[SerializeField, Tooltip("Resolution of the Bezier curve, different to line Resolution")]
|
||||
internal int bezierSegmentsPerCurve = 10;
|
||||
|
||||
public float LineThickness
|
||||
{
|
||||
get { return lineThickness; }
|
||||
set { lineThickness = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool RelativeSize
|
||||
{
|
||||
get { return relativeSize; }
|
||||
set { relativeSize = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool LineList
|
||||
{
|
||||
get { return lineList; }
|
||||
set { lineList = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
public bool LineCaps
|
||||
{
|
||||
get { return lineCaps; }
|
||||
set { lineCaps = value; SetAllDirty(); }
|
||||
}
|
||||
|
||||
[Tooltip("The type of Join used between lines, Square/Mitre or Curved/Bevel")]
|
||||
public JoinType LineJoins = JoinType.Bevel;
|
||||
|
||||
[Tooltip("Bezier method to apply to line, see docs for options\nCan't be used in conjunction with Resolution as Bezier already changes the resolution")]
|
||||
public BezierType BezierMode = BezierType.None;
|
||||
|
||||
public int BezierSegmentsPerCurve
|
||||
{
|
||||
get { return bezierSegmentsPerCurve; }
|
||||
set { bezierSegmentsPerCurve = value; }
|
||||
}
|
||||
|
||||
[HideInInspector]
|
||||
public bool drivenExternally = false;
|
||||
|
||||
/// <summary>
|
||||
/// Points to be drawn in the line.
|
||||
/// </summary>
|
||||
/// <remarks>Don't add points to the list directly, use the add / remove functions</remarks>
|
||||
public List<Vector2> Points
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_points;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_points == value)
|
||||
return;
|
||||
m_points = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public void AddPoint(Vector2 pointToAdd)
|
||||
{
|
||||
m_points.Add(pointToAdd);
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
public void RemovePoint(Vector2 pointToRemove)
|
||||
{
|
||||
m_points.Remove(pointToRemove);
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
public void ClearPoints()
|
||||
{
|
||||
m_points.Clear();
|
||||
SetAllDirty();
|
||||
}
|
||||
|
||||
private void PopulateMesh(VertexHelper vh, List<Vector2> pointsToDraw)
|
||||
{
|
||||
//If Bezier is desired, pick the implementation
|
||||
if (BezierMode != BezierType.None && BezierMode != BezierType.Catenary && pointsToDraw.Count > 3) {
|
||||
BezierPath bezierPath = new BezierPath ();
|
||||
|
||||
bezierPath.SetControlPoints (pointsToDraw);
|
||||
bezierPath.SegmentsPerCurve = bezierSegmentsPerCurve;
|
||||
List<Vector2> drawingPoints;
|
||||
switch (BezierMode) {
|
||||
case BezierType.Basic:
|
||||
drawingPoints = bezierPath.GetDrawingPoints0 ();
|
||||
break;
|
||||
case BezierType.Improved:
|
||||
drawingPoints = bezierPath.GetDrawingPoints1 ();
|
||||
break;
|
||||
default:
|
||||
drawingPoints = bezierPath.GetDrawingPoints2 ();
|
||||
break;
|
||||
}
|
||||
|
||||
pointsToDraw = drawingPoints;
|
||||
}
|
||||
if (BezierMode == BezierType.Catenary && pointsToDraw.Count == 2) {
|
||||
CableCurve cable = new CableCurve (pointsToDraw);
|
||||
cable.slack = Resolution;
|
||||
cable.steps = BezierSegmentsPerCurve;
|
||||
pointsToDraw.Clear();
|
||||
pointsToDraw.AddRange(cable.Points());
|
||||
}
|
||||
|
||||
if (ImproveResolution != ResolutionMode.None) {
|
||||
pointsToDraw = IncreaseResolution (pointsToDraw);
|
||||
}
|
||||
|
||||
// scale based on the size of the rect or use absolute, this is switchable
|
||||
var sizeX = !relativeSize ? 1 : rectTransform.rect.width;
|
||||
var sizeY = !relativeSize ? 1 : rectTransform.rect.height;
|
||||
var offsetX = -rectTransform.pivot.x * sizeX;
|
||||
var offsetY = -rectTransform.pivot.y * sizeY;
|
||||
|
||||
// Generate the quads that make up the wide line
|
||||
var segments = new List<UIVertex[]> ();
|
||||
if (lineList) {
|
||||
for (var i = 1; i < pointsToDraw.Count; i += 2) {
|
||||
var start = pointsToDraw [i - 1];
|
||||
var end = pointsToDraw [i];
|
||||
start = new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||
end = new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||
|
||||
if (lineCaps) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.Start));
|
||||
}
|
||||
|
||||
//segments.Add(CreateLineSegment(start, end, SegmentType.Full));
|
||||
segments.Add (CreateLineSegment (start, end, SegmentType.Middle));
|
||||
|
||||
if (lineCaps) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.End));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (var i = 1; i < pointsToDraw.Count; i++) {
|
||||
var start = pointsToDraw [i - 1];
|
||||
var end = pointsToDraw [i];
|
||||
start = new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
|
||||
end = new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
|
||||
|
||||
if (lineCaps && i == 1) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.Start));
|
||||
}
|
||||
|
||||
segments.Add (CreateLineSegment (start, end, SegmentType.Middle));
|
||||
//segments.Add(CreateLineSegment(start, end, SegmentType.Full));
|
||||
|
||||
if (lineCaps && i == pointsToDraw.Count - 1) {
|
||||
segments.Add (CreateLineCap (start, end, SegmentType.End));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add the line segments to the vertex helper, creating any joins as needed
|
||||
for (var i = 0; i < segments.Count; i++) {
|
||||
if (!lineList && i < segments.Count - 1) {
|
||||
var vec1 = segments [i] [1].position - segments [i] [2].position;
|
||||
var vec2 = segments [i + 1] [2].position - segments [i + 1] [1].position;
|
||||
var angle = Vector2.Angle (vec1, vec2) * Mathf.Deg2Rad;
|
||||
|
||||
// Positive sign means the line is turning in a 'clockwise' direction
|
||||
var sign = Mathf.Sign (Vector3.Cross (vec1.normalized, vec2.normalized).z);
|
||||
|
||||
// Calculate the miter point
|
||||
var miterDistance = lineThickness / (2 * Mathf.Tan (angle / 2));
|
||||
var miterPointA = segments [i] [2].position - vec1.normalized * miterDistance * sign;
|
||||
var miterPointB = segments [i] [3].position + vec1.normalized * miterDistance * sign;
|
||||
|
||||
var joinType = LineJoins;
|
||||
if (joinType == JoinType.Miter) {
|
||||
// Make sure we can make a miter join without too many artifacts.
|
||||
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN) {
|
||||
segments [i] [2].position = miterPointA;
|
||||
segments [i] [3].position = miterPointB;
|
||||
segments [i + 1] [0].position = miterPointB;
|
||||
segments [i + 1] [1].position = miterPointA;
|
||||
} else {
|
||||
joinType = JoinType.Bevel;
|
||||
}
|
||||
}
|
||||
|
||||
if (joinType == JoinType.Bevel) {
|
||||
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
|
||||
if (sign < 0) {
|
||||
segments [i] [2].position = miterPointA;
|
||||
segments [i + 1] [1].position = miterPointA;
|
||||
} else {
|
||||
segments [i] [3].position = miterPointB;
|
||||
segments [i + 1] [0].position = miterPointB;
|
||||
}
|
||||
}
|
||||
|
||||
var join = new UIVertex[] { segments [i] [2], segments [i] [3], segments [i + 1] [0], segments [i + 1] [1] };
|
||||
vh.AddUIVertexQuad (join);
|
||||
}
|
||||
}
|
||||
|
||||
vh.AddUIVertexQuad (segments [i]);
|
||||
}
|
||||
if (vh.currentVertCount > 64000) {
|
||||
Debug.LogError ("Max Verticies size is 64000, current mesh verticies count is [" + vh.currentVertCount + "] - Cannot Draw");
|
||||
vh.Clear ();
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
if (m_points != null && m_points.Count > 0) {
|
||||
GeneratedUVs ();
|
||||
vh.Clear ();
|
||||
|
||||
PopulateMesh (vh, m_points);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
|
||||
{
|
||||
if (type == SegmentType.Start)
|
||||
{
|
||||
var capStart = start - ((end - start).normalized * lineThickness / 2);
|
||||
return CreateLineSegment(capStart, start, SegmentType.Start);
|
||||
}
|
||||
else if (type == SegmentType.End)
|
||||
{
|
||||
var capEnd = end + ((end - start).normalized * lineThickness / 2);
|
||||
return CreateLineSegment(end, capEnd, SegmentType.End);
|
||||
}
|
||||
|
||||
Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
|
||||
return null;
|
||||
}
|
||||
|
||||
private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type)
|
||||
{
|
||||
Vector2 offset = new Vector2((start.y - end.y), end.x - start.x).normalized * lineThickness / 2;
|
||||
|
||||
var v1 = start - offset;
|
||||
var v2 = start + offset;
|
||||
var v3 = end + offset;
|
||||
var v4 = end - offset;
|
||||
//Return the VDO with the correct uvs
|
||||
switch (type)
|
||||
{
|
||||
case SegmentType.Start:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, startUvs);
|
||||
case SegmentType.End:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, endUvs);
|
||||
case SegmentType.Full:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, fullUvs);
|
||||
default:
|
||||
return SetVbo(new[] { v1, v2, v3, v4 }, middleUvs);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void GeneratedUVs()
|
||||
{
|
||||
if (activeSprite != null)
|
||||
{
|
||||
var outer = Sprites.DataUtility.GetOuterUV(activeSprite);
|
||||
var inner = Sprites.DataUtility.GetInnerUV(activeSprite);
|
||||
UV_TOP_LEFT = new Vector2(outer.x, outer.y);
|
||||
UV_BOTTOM_LEFT = new Vector2(outer.x, outer.w);
|
||||
UV_TOP_CENTER_LEFT = new Vector2(inner.x, inner.y);
|
||||
UV_TOP_CENTER_RIGHT = new Vector2(inner.z, inner.y);
|
||||
UV_BOTTOM_CENTER_LEFT = new Vector2(inner.x, inner.w);
|
||||
UV_BOTTOM_CENTER_RIGHT = new Vector2(inner.z, inner.w);
|
||||
UV_TOP_RIGHT = new Vector2(outer.z, outer.y);
|
||||
UV_BOTTOM_RIGHT = new Vector2(outer.z, outer.w);
|
||||
}
|
||||
else
|
||||
{
|
||||
UV_TOP_LEFT = Vector2.zero;
|
||||
UV_BOTTOM_LEFT = new Vector2(0, 1);
|
||||
UV_TOP_CENTER_LEFT = new Vector2(0.5f, 0);
|
||||
UV_TOP_CENTER_RIGHT = new Vector2(0.5f, 0);
|
||||
UV_BOTTOM_CENTER_LEFT = new Vector2(0.5f, 1);
|
||||
UV_BOTTOM_CENTER_RIGHT = new Vector2(0.5f, 1);
|
||||
UV_TOP_RIGHT = new Vector2(1, 0);
|
||||
UV_BOTTOM_RIGHT = Vector2.one;
|
||||
}
|
||||
|
||||
|
||||
startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER_LEFT, UV_TOP_CENTER_LEFT };
|
||||
middleUvs = new[] { UV_TOP_CENTER_LEFT, UV_BOTTOM_CENTER_LEFT, UV_BOTTOM_CENTER_RIGHT, UV_TOP_CENTER_RIGHT };
|
||||
endUvs = new[] { UV_TOP_CENTER_RIGHT, UV_BOTTOM_CENTER_RIGHT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
|
||||
fullUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
|
||||
}
|
||||
|
||||
protected override void ResolutionToNativeSize(float distance)
|
||||
{
|
||||
if (UseNativeSize)
|
||||
{
|
||||
m_Resolution = distance / (activeSprite.rect.width / pixelsPerUnit);
|
||||
lineThickness = activeSprite.rect.height / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34861a5dcec3dbf438f8288be97dd133
|
||||
timeCreated: 1440845580
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,159 @@
|
||||
/// Credit jonbro5556
|
||||
/// Based on original LineRender script by jack.sydorenko
|
||||
/// Sourced from - http://forum.unity3d.com/threads/new-ui-and-line-drawing.253772/
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UILineTextureRenderer")]
|
||||
public class UILineTextureRenderer : UIPrimitiveBase
|
||||
{
|
||||
[SerializeField]
|
||||
Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
|
||||
[SerializeField]
|
||||
private Vector2[] m_points;
|
||||
|
||||
public float LineThickness = 2;
|
||||
public bool UseMargins;
|
||||
public Vector2 Margin;
|
||||
public bool relativeSize;
|
||||
|
||||
/// <summary>
|
||||
/// UV rectangle used by the texture.
|
||||
/// </summary>
|
||||
public Rect uvRect
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_UVRect;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_UVRect == value)
|
||||
return;
|
||||
m_UVRect = value;
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Points to be drawn in the line.
|
||||
/// </summary>
|
||||
public Vector2[] Points
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_points;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_points == value)
|
||||
return;
|
||||
m_points = value;
|
||||
SetAllDirty();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
// requires sets of quads
|
||||
if (m_points == null || m_points.Length < 2)
|
||||
m_points = new[] { new Vector2(0, 0), new Vector2(1, 1) };
|
||||
var capSize = 24;
|
||||
var sizeX = rectTransform.rect.width;
|
||||
var sizeY = rectTransform.rect.height;
|
||||
var offsetX = -rectTransform.pivot.x * rectTransform.rect.width;
|
||||
var offsetY = -rectTransform.pivot.y * rectTransform.rect.height;
|
||||
|
||||
// don't want to scale based on the size of the rect, so this is switchable now
|
||||
if (!relativeSize)
|
||||
{
|
||||
sizeX = 1;
|
||||
sizeY = 1;
|
||||
}
|
||||
// build a new set of m_points taking into account the cap sizes.
|
||||
// would be cool to support corners too, but that might be a bit tough :)
|
||||
var pointList = new List<Vector2>();
|
||||
pointList.Add(m_points[0]);
|
||||
var capPoint = m_points[0] + (m_points[1] - m_points[0]).normalized * capSize;
|
||||
pointList.Add(capPoint);
|
||||
|
||||
// should bail before the last point to add another cap point
|
||||
for (int i = 1; i < m_points.Length - 1; i++)
|
||||
{
|
||||
pointList.Add(m_points[i]);
|
||||
}
|
||||
capPoint = m_points[m_points.Length - 1] - (m_points[m_points.Length - 1] - m_points[m_points.Length - 2]).normalized * capSize;
|
||||
pointList.Add(capPoint);
|
||||
pointList.Add(m_points[m_points.Length - 1]);
|
||||
|
||||
var Tempm_points = pointList.ToArray();
|
||||
if (UseMargins)
|
||||
{
|
||||
sizeX -= Margin.x;
|
||||
sizeY -= Margin.y;
|
||||
offsetX += Margin.x / 2f;
|
||||
offsetY += Margin.y / 2f;
|
||||
}
|
||||
|
||||
vh.Clear();
|
||||
|
||||
Vector2 prevV1 = Vector2.zero;
|
||||
Vector2 prevV2 = Vector2.zero;
|
||||
|
||||
for (int i = 1; i < Tempm_points.Length; i++)
|
||||
{
|
||||
var prev = Tempm_points[i - 1];
|
||||
var cur = Tempm_points[i];
|
||||
prev = new Vector2(prev.x * sizeX + offsetX, prev.y * sizeY + offsetY);
|
||||
cur = new Vector2(cur.x * sizeX + offsetX, cur.y * sizeY + offsetY);
|
||||
|
||||
float angle = Mathf.Atan2(cur.y - prev.y, cur.x - prev.x) * 180f / Mathf.PI;
|
||||
|
||||
var v1 = prev + new Vector2(0, -LineThickness / 2);
|
||||
var v2 = prev + new Vector2(0, +LineThickness / 2);
|
||||
var v3 = cur + new Vector2(0, +LineThickness / 2);
|
||||
var v4 = cur + new Vector2(0, -LineThickness / 2);
|
||||
|
||||
v1 = RotatePointAroundPivot(v1, prev, new Vector3(0, 0, angle));
|
||||
v2 = RotatePointAroundPivot(v2, prev, new Vector3(0, 0, angle));
|
||||
v3 = RotatePointAroundPivot(v3, cur, new Vector3(0, 0, angle));
|
||||
v4 = RotatePointAroundPivot(v4, cur, new Vector3(0, 0, angle));
|
||||
|
||||
Vector2 uvTopLeft = Vector2.zero;
|
||||
Vector2 uvBottomLeft = new Vector2(0, 1);
|
||||
|
||||
Vector2 uvTopCenter = new Vector2(0.5f, 0);
|
||||
Vector2 uvBottomCenter = new Vector2(0.5f, 1);
|
||||
|
||||
Vector2 uvTopRight = new Vector2(1, 0);
|
||||
Vector2 uvBottomRight = new Vector2(1, 1);
|
||||
|
||||
Vector2[] uvs = new[] { uvTopCenter, uvBottomCenter, uvBottomCenter, uvTopCenter };
|
||||
|
||||
if (i > 1)
|
||||
vh.AddUIVertexQuad(SetVbo(new[] { prevV1, prevV2, v1, v2 }, uvs));
|
||||
|
||||
if (i == 1)
|
||||
uvs = new[] { uvTopLeft, uvBottomLeft, uvBottomCenter, uvTopCenter };
|
||||
else if (i == Tempm_points.Length - 1)
|
||||
uvs = new[] { uvTopCenter, uvBottomCenter, uvBottomRight, uvTopRight };
|
||||
|
||||
vh.AddUIVertexQuad(SetVbo(new[] { v1, v2, v3, v4 }, uvs));
|
||||
|
||||
|
||||
prevV1 = v3;
|
||||
prevV2 = v4;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 RotatePointAroundPivot(Vector3 point, Vector3 pivot, Vector3 angles)
|
||||
{
|
||||
Vector3 dir = point - pivot; // get point direction relative to pivot
|
||||
dir = Quaternion.Euler(angles) * dir; // rotate it
|
||||
point = dir + pivot; // calculate rotated point
|
||||
return point; // return it
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b801876ddb189f94f905cd1646564fbf
|
||||
timeCreated: 1440845581
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,103 @@
|
||||
/// Credit CiaccoDavide
|
||||
/// Sourced from - http://ciaccodavi.de/unity/UIPolygon
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/UI Polygon")]
|
||||
public class UIPolygon : UIPrimitiveBase
|
||||
{
|
||||
public bool fill = true;
|
||||
public float thickness = 5;
|
||||
[Range(3, 360)]
|
||||
public int sides = 3;
|
||||
[Range(0, 360)]
|
||||
public float rotation = 0;
|
||||
[Range(0, 1)]
|
||||
public float[] VerticesDistances = new float[3];
|
||||
private float size = 0;
|
||||
|
||||
public void DrawPolygon(int _sides)
|
||||
{
|
||||
sides = _sides;
|
||||
VerticesDistances = new float[_sides + 1];
|
||||
for (int i = 0; i < _sides; i++) VerticesDistances[i] = 1; ;
|
||||
rotation = 0;
|
||||
SetAllDirty();
|
||||
}
|
||||
public void DrawPolygon(int _sides, float[] _VerticesDistances)
|
||||
{
|
||||
sides = _sides;
|
||||
VerticesDistances = _VerticesDistances;
|
||||
rotation = 0;
|
||||
SetAllDirty();
|
||||
}
|
||||
public void DrawPolygon(int _sides, float[] _VerticesDistances, float _rotation)
|
||||
{
|
||||
sides = _sides;
|
||||
VerticesDistances = _VerticesDistances;
|
||||
rotation = _rotation;
|
||||
SetAllDirty();
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
size = rectTransform.rect.width;
|
||||
if (rectTransform.rect.width > rectTransform.rect.height)
|
||||
size = rectTransform.rect.height;
|
||||
else
|
||||
size = rectTransform.rect.width;
|
||||
thickness = (float)Mathf.Clamp(thickness, 0, size / 2);
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
vh.Clear();
|
||||
|
||||
Vector2 prevX = Vector2.zero;
|
||||
Vector2 prevY = Vector2.zero;
|
||||
Vector2 uv0 = new Vector2(0, 0);
|
||||
Vector2 uv1 = new Vector2(0, 1);
|
||||
Vector2 uv2 = new Vector2(1, 1);
|
||||
Vector2 uv3 = new Vector2(1, 0);
|
||||
Vector2 pos0;
|
||||
Vector2 pos1;
|
||||
Vector2 pos2;
|
||||
Vector2 pos3;
|
||||
float degrees = 360f / sides;
|
||||
int vertices = sides + 1;
|
||||
if (VerticesDistances.Length != vertices)
|
||||
{
|
||||
VerticesDistances = new float[vertices];
|
||||
for (int i = 0; i < vertices - 1; i++) VerticesDistances[i] = 1;
|
||||
}
|
||||
// last vertex is also the first!
|
||||
VerticesDistances[vertices - 1] = VerticesDistances[0];
|
||||
for (int i = 0; i < vertices; i++)
|
||||
{
|
||||
float outer = -rectTransform.pivot.x * size * VerticesDistances[i];
|
||||
float inner = -rectTransform.pivot.x * size * VerticesDistances[i] + thickness;
|
||||
float rad = Mathf.Deg2Rad * (i * degrees + rotation);
|
||||
float c = Mathf.Cos(rad);
|
||||
float s = Mathf.Sin(rad);
|
||||
uv0 = new Vector2(0, 1);
|
||||
uv1 = new Vector2(1, 1);
|
||||
uv2 = new Vector2(1, 0);
|
||||
uv3 = new Vector2(0, 0);
|
||||
pos0 = prevX;
|
||||
pos1 = new Vector2(outer * c, outer * s);
|
||||
if (fill)
|
||||
{
|
||||
pos2 = Vector2.zero;
|
||||
pos3 = Vector2.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
pos2 = new Vector2(inner * c, inner * s);
|
||||
pos3 = prevY;
|
||||
}
|
||||
prevX = pos1;
|
||||
prevY = pos2;
|
||||
vh.AddUIVertexQuad(SetVbo(new[] { pos0, pos1, pos2, pos3 }, new[] { uv0, uv1, uv2, uv3 }));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fcd1b8078a416f844b695454a4358409
|
||||
timeCreated: 1450200166
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,362 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
public enum ResolutionMode
|
||||
{
|
||||
None,
|
||||
PerSegment,
|
||||
PerLine
|
||||
}
|
||||
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
public class UIPrimitiveBase : MaskableGraphic, ILayoutElement, ICanvasRaycastFilter
|
||||
{
|
||||
static protected Material s_ETC1DefaultUI = null;
|
||||
List<Vector2> outputList = new List<Vector2>();
|
||||
|
||||
[SerializeField] private Sprite m_Sprite;
|
||||
public Sprite sprite { get { return m_Sprite; } set { if (SetPropertyUtility.SetClass(ref m_Sprite, value)) GeneratedUVs(); SetAllDirty(); } }
|
||||
|
||||
[NonSerialized]
|
||||
private Sprite m_OverrideSprite;
|
||||
public Sprite overrideSprite { get { return activeSprite; } set { if (SetPropertyUtility.SetClass(ref m_OverrideSprite, value)) GeneratedUVs(); SetAllDirty(); } }
|
||||
|
||||
protected Sprite activeSprite { get { return m_OverrideSprite != null ? m_OverrideSprite : sprite; } }
|
||||
|
||||
// Not serialized until we support read-enabled sprites better.
|
||||
internal float m_EventAlphaThreshold = 1;
|
||||
public float eventAlphaThreshold { get { return m_EventAlphaThreshold; } set { m_EventAlphaThreshold = value; } }
|
||||
|
||||
[SerializeField]
|
||||
private ResolutionMode m_improveResolution;
|
||||
public ResolutionMode ImproveResolution { get { return m_improveResolution; } set { m_improveResolution = value; SetAllDirty(); } }
|
||||
|
||||
[SerializeField]
|
||||
protected float m_Resolution;
|
||||
public float Resolution { get { return m_Resolution; } set { m_Resolution = value; SetAllDirty(); } }
|
||||
|
||||
[SerializeField]
|
||||
private bool m_useNativeSize;
|
||||
public bool UseNativeSize { get { return m_useNativeSize; } set { m_useNativeSize = value; SetAllDirty(); } }
|
||||
|
||||
protected UIPrimitiveBase()
|
||||
{
|
||||
useLegacyMeshGeneration = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Default material used to draw everything if no explicit material was specified.
|
||||
/// </summary>
|
||||
|
||||
static public Material defaultETC1GraphicMaterial
|
||||
{
|
||||
get
|
||||
{
|
||||
if (s_ETC1DefaultUI == null)
|
||||
s_ETC1DefaultUI = Canvas.GetETC1SupportedCanvasMaterial();
|
||||
return s_ETC1DefaultUI;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Image's texture comes from the UnityEngine.Image.
|
||||
/// </summary>
|
||||
public override Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite == null)
|
||||
{
|
||||
if (material != null && material.mainTexture != null)
|
||||
{
|
||||
return material.mainTexture;
|
||||
}
|
||||
return s_WhiteTexture;
|
||||
}
|
||||
|
||||
return activeSprite.texture;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the Image has a border to work with.
|
||||
/// </summary>
|
||||
|
||||
public bool hasBorder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite != null)
|
||||
{
|
||||
Vector4 v = activeSprite.border;
|
||||
return v.sqrMagnitude > 0f;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public float pixelsPerUnit
|
||||
{
|
||||
get
|
||||
{
|
||||
float spritePixelsPerUnit = 100;
|
||||
if (activeSprite)
|
||||
spritePixelsPerUnit = activeSprite.pixelsPerUnit;
|
||||
|
||||
float referencePixelsPerUnit = 100;
|
||||
if (canvas)
|
||||
referencePixelsPerUnit = canvas.referencePixelsPerUnit;
|
||||
|
||||
return spritePixelsPerUnit / referencePixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
public override Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Material != null)
|
||||
return m_Material;
|
||||
|
||||
if (activeSprite && activeSprite.associatedAlphaSplitTexture != null)
|
||||
return defaultETC1GraphicMaterial;
|
||||
|
||||
return defaultMaterial;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
base.material = value;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
|
||||
{
|
||||
UIVertex[] vbo = new UIVertex[4];
|
||||
for (int i = 0; i < vertices.Length; i++)
|
||||
{
|
||||
var vert = UIVertex.simpleVert;
|
||||
vert.color = color;
|
||||
vert.position = vertices[i];
|
||||
vert.uv0 = uvs[i];
|
||||
vbo[i] = vert;
|
||||
}
|
||||
return vbo;
|
||||
}
|
||||
|
||||
protected Vector2[] IncreaseResolution(Vector2[] input)
|
||||
{
|
||||
return IncreaseResolution(new List<Vector2>(input)).ToArray();
|
||||
}
|
||||
|
||||
protected List<Vector2> IncreaseResolution(List<Vector2> input)
|
||||
{
|
||||
outputList.Clear();
|
||||
|
||||
switch (ImproveResolution)
|
||||
{
|
||||
case ResolutionMode.PerLine:
|
||||
float totalDistance = 0, increments = 0;
|
||||
for (int i = 0; i < input.Count - 1; i++)
|
||||
{
|
||||
totalDistance += Vector2.Distance(input[i], input[i + 1]);
|
||||
}
|
||||
ResolutionToNativeSize(totalDistance);
|
||||
increments = totalDistance / m_Resolution;
|
||||
var incrementCount = 0;
|
||||
for (int i = 0; i < input.Count - 1; i++)
|
||||
{
|
||||
var p1 = input[i];
|
||||
outputList.Add(p1);
|
||||
var p2 = input[i + 1];
|
||||
var segmentDistance = Vector2.Distance(p1, p2) / increments;
|
||||
var incrementTime = 1f / segmentDistance;
|
||||
for (int j = 0; j < segmentDistance; j++)
|
||||
{
|
||||
outputList.Add(Vector2.Lerp(p1, (Vector2)p2, j * incrementTime));
|
||||
incrementCount++;
|
||||
}
|
||||
outputList.Add(p2);
|
||||
}
|
||||
break;
|
||||
case ResolutionMode.PerSegment:
|
||||
for (int i = 0; i < input.Count - 1; i++)
|
||||
{
|
||||
var p1 = input[i];
|
||||
outputList.Add(p1);
|
||||
var p2 = input[i + 1];
|
||||
ResolutionToNativeSize(Vector2.Distance(p1, p2));
|
||||
increments = 1f / m_Resolution;
|
||||
for (Single j = 1; j < m_Resolution; j++)
|
||||
{
|
||||
outputList.Add(Vector2.Lerp(p1, (Vector2)p2, increments * j));
|
||||
}
|
||||
outputList.Add(p2);
|
||||
}
|
||||
break;
|
||||
}
|
||||
return outputList;
|
||||
}
|
||||
|
||||
protected virtual void GeneratedUVs() { }
|
||||
|
||||
protected virtual void ResolutionToNativeSize(float distance) { }
|
||||
|
||||
|
||||
#region ILayoutElement Interface
|
||||
|
||||
public virtual void CalculateLayoutInputHorizontal() { }
|
||||
public virtual void CalculateLayoutInputVertical() { }
|
||||
|
||||
public virtual float minWidth { get { return 0; } }
|
||||
|
||||
public virtual float preferredWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
if (overrideSprite == null)
|
||||
return 0;
|
||||
return overrideSprite.rect.size.x / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float flexibleWidth { get { return -1; } }
|
||||
|
||||
public virtual float minHeight { get { return 0; } }
|
||||
|
||||
public virtual float preferredHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
if (overrideSprite == null)
|
||||
return 0;
|
||||
return overrideSprite.rect.size.y / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual float flexibleHeight { get { return -1; } }
|
||||
|
||||
public virtual int layoutPriority { get { return 0; } }
|
||||
|
||||
#endregion
|
||||
|
||||
#region ICanvasRaycastFilter Interface
|
||||
public virtual bool IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
|
||||
{
|
||||
// add test for line check
|
||||
if (m_EventAlphaThreshold >= 1)
|
||||
return true;
|
||||
|
||||
Sprite sprite = overrideSprite;
|
||||
if (sprite == null)
|
||||
return true;
|
||||
|
||||
Vector2 local;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local);
|
||||
|
||||
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;
|
||||
|
||||
local = MapCoordinate(local, rect);
|
||||
|
||||
//test local coord with Mesh
|
||||
|
||||
// Normalize local coordinates.
|
||||
Rect spriteRect = sprite.textureRect;
|
||||
Vector2 normalized = new Vector2(local.x / spriteRect.width, local.y / spriteRect.height);
|
||||
|
||||
// Convert to texture space.
|
||||
float x = Mathf.Lerp(spriteRect.x, spriteRect.xMax, normalized.x) / sprite.texture.width;
|
||||
float y = Mathf.Lerp(spriteRect.y, spriteRect.yMax, normalized.y) / sprite.texture.height;
|
||||
|
||||
try
|
||||
{
|
||||
return sprite.texture.GetPixelBilinear(x, y).a >= m_EventAlphaThreshold;
|
||||
}
|
||||
catch (UnityException e)
|
||||
{
|
||||
Debug.LogError("Using clickAlphaThreshold lower than 1 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return image adjusted position
|
||||
/// **Copied from Unity's Image component for now and simplified for UI Extensions primitives
|
||||
/// </summary>
|
||||
/// <param name="local"></param>
|
||||
/// <param name="rect"></param>
|
||||
/// <returns></returns>
|
||||
private Vector2 MapCoordinate(Vector2 local, Rect rect)
|
||||
{
|
||||
Rect spriteRect = sprite.rect;
|
||||
//if (type == Type.Simple || type == Type.Filled)
|
||||
return new Vector2(local.x * rect.width, local.y * rect.height);
|
||||
|
||||
//Vector4 border = sprite.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;
|
||||
// }
|
||||
|
||||
// if (type == Type.Sliced)
|
||||
// {
|
||||
// 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);
|
||||
// continue;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// local[i] -= adjustedBorder[i];
|
||||
// local[i] = Mathf.Repeat(local[i], spriteRect.size[i] - border[i] - border[i + 2]);
|
||||
// local[i] += border[i];
|
||||
// continue;
|
||||
// }
|
||||
//}
|
||||
|
||||
//return local;
|
||||
}
|
||||
|
||||
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 artefact's 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;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region onEnable
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
SetAllDirty();
|
||||
}
|
||||
#endregion
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 65af11d29c6cb8c45b3d78d97d98440d
|
||||
timeCreated: 1464131942
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,141 @@
|
||||
/// Credit Soprachev Andrei
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[AddComponentMenu("UI/Extensions/Primitives/Squircle")]
|
||||
public class UISquircle : UIPrimitiveBase
|
||||
{
|
||||
const float C = 1.0f;
|
||||
public enum Type
|
||||
{
|
||||
Classic,
|
||||
Scaled
|
||||
}
|
||||
|
||||
[Space]
|
||||
public Type squircleType = Type.Scaled;
|
||||
[Range(1, 40)]
|
||||
public float n = 4;
|
||||
[Min(0.1f)]
|
||||
public float delta = 5f;
|
||||
public float quality = 0.1f;
|
||||
[Min(0)]
|
||||
public float radius = 1000;
|
||||
|
||||
|
||||
private float a, b;
|
||||
private List<Vector2> vert = new List<Vector2>();
|
||||
|
||||
|
||||
private float SquircleFunc(float t, bool xByY)
|
||||
{
|
||||
if (xByY)
|
||||
return (float)System.Math.Pow(C - System.Math.Pow(t / a, n), 1f / n) * b;
|
||||
|
||||
return (float)System.Math.Pow(C - System.Math.Pow(t / b, n), 1f / n) * a;
|
||||
}
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
|
||||
float dx = 0;
|
||||
float dy = 0;
|
||||
|
||||
float width = rectTransform.rect.width / 2;
|
||||
float height = rectTransform.rect.height / 2;
|
||||
|
||||
if (squircleType == Type.Classic)
|
||||
{
|
||||
a = width;
|
||||
b = height;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = Mathf.Min(width, height, radius);
|
||||
b = a;
|
||||
|
||||
dx = width - a;
|
||||
dy = height - a;
|
||||
}
|
||||
|
||||
|
||||
|
||||
float x = 0;
|
||||
float y = 1;
|
||||
vert.Clear();
|
||||
vert.Add(new Vector2(0, height));
|
||||
while (x < y)
|
||||
{
|
||||
y = SquircleFunc(x, true);
|
||||
vert.Add(new Vector2(dx + x, dy + y));
|
||||
x += delta;
|
||||
}
|
||||
|
||||
if (float.IsNaN(vert.Last().y))
|
||||
{
|
||||
vert.RemoveAt(vert.Count - 1);
|
||||
}
|
||||
|
||||
while (y > 0)
|
||||
{
|
||||
x = SquircleFunc(y, false);
|
||||
vert.Add(new Vector2(dx + x, dy + y));
|
||||
y -= delta;
|
||||
}
|
||||
|
||||
vert.Add(new Vector2(width, 0));
|
||||
|
||||
for (int i = 1; i < vert.Count - 1; i++)
|
||||
{
|
||||
if (vert[i].x < vert[i].y)
|
||||
{
|
||||
if (vert[i - 1].y - vert[i].y < quality)
|
||||
{
|
||||
vert.RemoveAt(i);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (vert[i].x - vert[i - 1].x < quality)
|
||||
{
|
||||
vert.RemoveAt(i);
|
||||
i -= 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
vert.AddRange(vert.AsEnumerable().Reverse().Select(t => new Vector2(t.x, -t.y)));
|
||||
vert.AddRange(vert.AsEnumerable().Reverse().Select(t => new Vector2(-t.x, t.y)));
|
||||
|
||||
vh.Clear();
|
||||
|
||||
for (int i = 0; i < vert.Count - 1; i++)
|
||||
{
|
||||
vh.AddVert(vert[i], color, Vector2.zero);
|
||||
vh.AddVert(vert[i + 1], color, Vector2.zero);
|
||||
vh.AddVert(Vector2.zero, color, Vector2.zero);
|
||||
|
||||
vh.AddTriangle(i * 3, i * 3 + 1, i * 3 + 2);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
[CustomEditor(typeof(UISquircle))]
|
||||
public class UISquircleEditor : Editor
|
||||
{
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
DrawDefaultInspector();
|
||||
UISquircle script = (UISquircle)target;
|
||||
GUILayout.Label("Vertex count: " + script.vert.Count().ToString());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d7948ca2f24604c4aa5340622512a976
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user