Added UIGridRenderer thanks to John Hattan

Fixed "line Endings" errors
pull/413/head
Simon Jackson 2017-02-17 12:54:40 +00:00
parent bddf5ad8b0
commit 82585a7cb2
4 changed files with 388 additions and 231 deletions

View File

@ -17,5 +17,5 @@ namespace UnityEngine.UI.Extensions
base.RaycastControlsGUI(); base.RaycastControlsGUI();
base.serializedObject.ApplyModifiedProperties(); base.serializedObject.ApplyModifiedProperties();
} }
} }
} }

View File

@ -0,0 +1,142 @@
/// Credit John Hattan (http://thecodezone.com/)
/// Sourced from - https://bitbucket.org/UnityUIExtensions/unity-ui-extensions/issues/117/uigridrenderer
using System.Collections.Generic;
namespace UnityEngine.UI.Extensions
{
[AddComponentMenu("UI/Extensions/Primitives/UIGridRenderer")]
public class UIGridRenderer : UILineRenderer
{
[SerializeField]
private int m_gridWidth = 10;
[SerializeField]
private int m_gridHeight = 10;
/// <summary>
/// Width of the grid in Cells.
/// </summary>
public int GridWidth
{
get
{
return m_gridWidth;
}
set
{
if (m_gridWidth == value)
return;
m_gridWidth = value;
SetAllDirty();
}
}
/// <summary>
/// Height of the Grid in cells.
/// </summary>
public int GridHeight
{
get
{
return m_gridHeight;
}
set
{
if (m_gridHeight == value)
return;
m_gridHeight = value;
SetAllDirty();
}
}
protected override void OnPopulateMesh(VertexHelper vh)
{
relativeSize = true;
int ArraySize = (GridHeight * 3) + 1;
if(GridHeight % 2 == 0)
++ArraySize; // needs one more line
ArraySize += (GridWidth * 3) + 1;
m_points = new Vector2[ArraySize];
int Index = 0;
for(int i = 0; i < GridHeight; ++i)
{
float xFrom = 1;
float xTo = 0;
if(i % 2 == 0)
{
// reach left instead
xFrom = 0;
xTo = 1;
}
float y = ((float)i) / GridHeight;
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) / GridHeight;
++Index;
}
if(GridHeight % 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 < GridWidth; ++i)
{
float yFrom = 1;
float yTo = 0;
if(i % 2 == 0)
{
// reach up instead
yFrom = 0;
yTo = 1;
}
float x = ((float)i) / GridWidth;
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) / GridWidth;
m_points[Index].y = yTo;
++Index;
}
if(GridWidth % 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);
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 35ff6e8800018654d9558db07c4cd080
timeCreated: 1487335372
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,288 +6,291 @@ using System.Collections.Generic;
namespace UnityEngine.UI.Extensions namespace UnityEngine.UI.Extensions
{ {
[AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")] [AddComponentMenu("UI/Extensions/Primitives/UILineRenderer")]
public class UILineRenderer : UIPrimitiveBase public class UILineRenderer : UIPrimitiveBase
{ {
private enum SegmentType private enum SegmentType
{ {
Start, Start,
Middle, Middle,
End, End,
} }
public enum JoinType public enum JoinType
{ {
Bevel, Bevel,
Miter Miter
} }
public enum BezierType
{ public enum BezierType
None, {
None,
Quick, Quick,
Basic, Basic,
Improved, Improved,
} }
private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad; 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 // 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 // quad to connect the endpoints. This improves the look of textured and transparent lines, since
// there is no overlapping. // there is no overlapping.
private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad; private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
private static readonly Vector2 UV_TOP_LEFT = Vector2.zero; private static readonly Vector2 UV_TOP_LEFT = Vector2.zero;
private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1); private static readonly Vector2 UV_BOTTOM_LEFT = new Vector2(0, 1);
private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0); private static readonly Vector2 UV_TOP_CENTER = new Vector2(0.5f, 0);
private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1); private static readonly Vector2 UV_BOTTOM_CENTER = new Vector2(0.5f, 1);
private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0); private static readonly Vector2 UV_TOP_RIGHT = new Vector2(1, 0);
private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1); private static readonly Vector2 UV_BOTTOM_RIGHT = new Vector2(1, 1);
private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER }; private static readonly Vector2[] startUvs = new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER, UV_TOP_CENTER };
private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER }; private static readonly Vector2[] middleUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_CENTER, UV_TOP_CENTER };
private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT }; private static readonly Vector2[] endUvs = new[] { UV_TOP_CENTER, UV_BOTTOM_CENTER, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
[SerializeField] [SerializeField]
private Rect m_UVRect = new Rect(0f, 0f, 1f, 1f); private Rect m_UVRect = new Rect(0f, 0f, 1f, 1f);
[SerializeField] [SerializeField]
private Vector2[] m_points; protected Vector2[] m_points;
public float LineThickness = 2;
public bool UseMargins;
public Vector2 Margin;
public bool relativeSize;
public float LineThickness = 2; public bool LineList = false;
public bool UseMargins; public bool LineCaps = false;
public Vector2 Margin; public JoinType LineJoins = JoinType.Bevel;
public bool relativeSize;
public bool LineList = false; public BezierType BezierMode = BezierType.None;
public bool LineCaps = false; public int BezierSegmentsPerCurve = 10;
public JoinType LineJoins = JoinType.Bevel;
public BezierType BezierMode = BezierType.None; /// <summary>
public int BezierSegmentsPerCurve = 10; /// UV rectangle used by the texture.
/// </summary>
/// <summary>
/// UV rectangle used by the texture.
/// </summary>
public Rect uvRect public Rect uvRect
{ {
get get
{ {
return m_UVRect; return m_UVRect;
} }
set
{
if (m_UVRect == value)
return;
m_UVRect = value;
SetVerticesDirty();
}
}
/// <summary> set
/// Points to be drawn in the line. {
/// </summary> if (m_UVRect == value)
return;
m_UVRect = value;
SetVerticesDirty();
}
}
/// <summary>
/// Points to be drawn in the line.
/// </summary>
public Vector2[] Points public Vector2[] Points
{ {
get get
{ {
return m_points; return m_points;
} }
set
{
if (m_points == value)
return;
m_points = value;
SetAllDirty();
}
}
protected override void OnPopulateMesh(VertexHelper vh) set
{ {
if (m_points == null) if (m_points == value)
return; return;
Vector2[] pointsToDraw = m_points; m_points = value;
//If Bezier is desired, pick the implementation SetAllDirty();
}
}
protected override void OnPopulateMesh(VertexHelper vh)
{
if (m_points == null)
return;
Vector2[] pointsToDraw = m_points;
//If Bezier is desired, pick the implementation
if (BezierMode != BezierType.None && m_points.Length > 3) if (BezierMode != BezierType.None && m_points.Length > 3)
{ {
BezierPath bezierPath = new BezierPath(); BezierPath bezierPath = new BezierPath();
bezierPath.SetControlPoints(pointsToDraw); bezierPath.SetControlPoints(pointsToDraw);
bezierPath.SegmentsPerCurve = BezierSegmentsPerCurve; bezierPath.SegmentsPerCurve = BezierSegmentsPerCurve;
List<Vector2> drawingPoints; List<Vector2> drawingPoints;
switch (BezierMode) switch (BezierMode)
{ {
case BezierType.Basic: case BezierType.Basic:
drawingPoints = bezierPath.GetDrawingPoints0(); drawingPoints = bezierPath.GetDrawingPoints0();
break; break;
case BezierType.Improved: case BezierType.Improved:
drawingPoints = bezierPath.GetDrawingPoints1(); drawingPoints = bezierPath.GetDrawingPoints1();
break; break;
default: default:
drawingPoints = bezierPath.GetDrawingPoints2(); drawingPoints = bezierPath.GetDrawingPoints2();
break; break;
} }
pointsToDraw = drawingPoints.ToArray();
}
var sizeX = rectTransform.rect.width; pointsToDraw = drawingPoints.ToArray();
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 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) if (!relativeSize)
{ {
sizeX = 1; sizeX = 1;
sizeY = 1; sizeY = 1;
} }
if (UseMargins) if (UseMargins)
{ {
sizeX -= Margin.x; sizeX -= Margin.x;
sizeY -= Margin.y; sizeY -= Margin.y;
offsetX += Margin.x / 2f; offsetX += Margin.x / 2f;
offsetY += Margin.y / 2f; offsetY += Margin.y / 2f;
} }
vh.Clear(); vh.Clear();
// Generate the quads that make up the wide line // Generate the quads that make up the wide line
var segments = new List<UIVertex[]>(); var segments = new List<UIVertex[]>();
if (LineList) if (LineList)
{ {
for (var i = 1; i < pointsToDraw.Length; i += 2) for (var i = 1; i < pointsToDraw.Length; i += 2)
{ {
var start = pointsToDraw[i - 1]; var start = pointsToDraw[i - 1];
var end = pointsToDraw[i]; var end = pointsToDraw[i];
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY); start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY); end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
if (LineCaps) if (LineCaps)
{ {
segments.Add(CreateLineCap(start, end, SegmentType.Start)); segments.Add(CreateLineCap(start, end, SegmentType.Start));
} }
segments.Add(CreateLineSegment(start, end, SegmentType.Middle)); segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
if (LineCaps) if (LineCaps)
{ {
segments.Add(CreateLineCap(start, end, SegmentType.End)); segments.Add(CreateLineCap(start, end, SegmentType.End));
} }
} }
} }
else else
{ {
for (var i = 1; i < pointsToDraw.Length; i++) for (var i = 1; i < pointsToDraw.Length; i++)
{ {
var start = pointsToDraw[i - 1]; var start = pointsToDraw[i - 1];
var end = pointsToDraw[i]; var end = pointsToDraw[i];
start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY); start = new Vector2(start.x * sizeX + offsetX, start.y * sizeY + offsetY);
end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY); end = new Vector2(end.x * sizeX + offsetX, end.y * sizeY + offsetY);
if (LineCaps && i == 1) if (LineCaps && i == 1)
{ {
segments.Add(CreateLineCap(start, end, SegmentType.Start)); segments.Add(CreateLineCap(start, end, SegmentType.Start));
} }
segments.Add(CreateLineSegment(start, end, SegmentType.Middle)); segments.Add(CreateLineSegment(start, end, SegmentType.Middle));
if (LineCaps && i == pointsToDraw.Length - 1) if (LineCaps && i == pointsToDraw.Length - 1)
{ {
segments.Add(CreateLineCap(start, end, SegmentType.End)); segments.Add(CreateLineCap(start, end, SegmentType.End));
} }
} }
} }
// Add the line segments to the vertex helper, creating any joins as needed // Add the line segments to the vertex helper, creating any joins as needed
for (var i = 0; i < segments.Count; i++) for (var i = 0; i < segments.Count; i++)
{ {
if (!LineList && i < segments.Count - 1) if (!LineList && i < segments.Count - 1)
{ {
var vec1 = segments[i][1].position - segments[i][2].position; var vec1 = segments[i][1].position - segments[i][2].position;
var vec2 = segments[i + 1][2].position - segments[i + 1][1].position; var vec2 = segments[i + 1][2].position - segments[i + 1][1].position;
var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad; var angle = Vector2.Angle(vec1, vec2) * Mathf.Deg2Rad;
// Positive sign means the line is turning in a 'clockwise' direction // Positive sign means the line is turning in a 'clockwise' direction
var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z); var sign = Mathf.Sign(Vector3.Cross(vec1.normalized, vec2.normalized).z);
// Calculate the miter point // Calculate the miter point
var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2)); var miterDistance = LineThickness / (2 * Mathf.Tan(angle / 2));
var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign; var miterPointA = segments[i][2].position - vec1.normalized * miterDistance * sign;
var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign; var miterPointB = segments[i][3].position + vec1.normalized * miterDistance * sign;
var joinType = LineJoins; var joinType = LineJoins;
if (joinType == JoinType.Miter) if (joinType == JoinType.Miter)
{ {
// Make sure we can make a miter join without too many artifacts. // 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) if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN)
{ {
segments[i][2].position = miterPointA; segments[i][2].position = miterPointA;
segments[i][3].position = miterPointB; segments[i][3].position = miterPointB;
segments[i + 1][0].position = miterPointB; segments[i + 1][0].position = miterPointB;
segments[i + 1][1].position = miterPointA; segments[i + 1][1].position = miterPointA;
} }
else else
{ {
joinType = JoinType.Bevel; joinType = JoinType.Bevel;
} }
} }
if (joinType == JoinType.Bevel) if (joinType == JoinType.Bevel)
{ {
if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN)
{ {
if (sign < 0) if (sign < 0)
{ {
segments[i][2].position = miterPointA; segments[i][2].position = miterPointA;
segments[i + 1][1].position = miterPointA; segments[i + 1][1].position = miterPointA;
} }
else else
{ {
segments[i][3].position = miterPointB; segments[i][3].position = miterPointB;
segments[i + 1][0].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] }; var join = new UIVertex[] { segments[i][2], segments[i][3], segments[i + 1][0], segments[i + 1][1] };
vh.AddUIVertexQuad(join); vh.AddUIVertexQuad(join);
} }
} }
vh.AddUIVertexQuad(segments[i]);
}
}
private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type) vh.AddUIVertexQuad(segments[i]);
{ }
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"); private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
return null; {
} 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);
}
private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type) Debug.LogError("Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
{ return null;
var uvs = middleUvs; }
if (type == SegmentType.Start)
uvs = startUvs;
else if (type == SegmentType.End)
uvs = endUvs;
Vector2 offset = new Vector2(start.y - end.y, end.x - start.x).normalized * LineThickness / 2; private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type)
var v1 = start - offset; {
var v2 = start + offset; var uvs = middleUvs;
var v3 = end + offset; if (type == SegmentType.Start)
var v4 = end - offset; uvs = startUvs;
return SetVbo(new[] { v1, v2, v3, v4 }, uvs); else if (type == SegmentType.End)
} uvs = endUvs;
} 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 SetVbo(new[] { v1, v2, v3, v4 }, uvs);
}
}
} }