5using System.Collections.Generic;
9 [AddComponentMenu(
"UI/Extensions/Primitives/UILineRendererList")]
10 [RequireComponent(typeof(RectTransform))]
13 private enum SegmentType
36 private const float MIN_MITER_JOIN = 15 * Mathf.Deg2Rad;
41 private const float MIN_BEVEL_NICE_JOIN = 30 * Mathf.Deg2Rad;
43 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;
44 private static Vector2[] startUvs, middleUvs, endUvs, fullUvs;
46 [SerializeField, Tooltip(
"Points to draw lines between\n Can be improved using the Resolution Option")]
47 internal List<Vector2> m_points;
51 [SerializeField, Tooltip(
"Thickness of the line")]
52 internal float lineThickness = 2;
53 [SerializeField, Tooltip(
"Use the relative bounds of the Rect Transform (0,0 -> 0,1) or screen space coordinates")]
54 internal bool relativeSize;
55 [SerializeField, Tooltip(
"Do the points identify a single line or split pairs of lines")]
56 internal bool lineList;
57 [SerializeField, Tooltip(
"Add end caps to each line\nMultiple caps when used with Line List")]
58 internal bool lineCaps;
59 [SerializeField, Tooltip(
"Resolution of the Bezier curve, different to line Resolution")]
60 internal int bezierSegmentsPerCurve = 10;
64 get {
return lineThickness; }
65 set { lineThickness = value; SetAllDirty(); }
70 get {
return relativeSize; }
71 set { relativeSize = value; SetAllDirty(); }
76 get {
return lineList; }
77 set { lineList = value; SetAllDirty(); }
82 get {
return lineCaps; }
83 set { lineCaps = value; SetAllDirty(); }
86 [Tooltip(
"The type of Join used between lines, Square/Mitre or Curved/Bevel")]
89 [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")]
94 get {
return bezierSegmentsPerCurve; }
95 set { bezierSegmentsPerCurve = value; }
114 if (m_points == value)
141 m_points.Add(pointToAdd);
147 m_points.Remove(pointToRemove);
157 private void PopulateMesh(VertexHelper vh, List<Vector2> pointsToDraw)
165 List<Vector2> drawingPoints;
178 pointsToDraw = drawingPoints;
181 CableCurve cable =
new CableCurve (pointsToDraw);
184 pointsToDraw.Clear();
185 pointsToDraw.AddRange(cable.Points());
193 var sizeX = !relativeSize ? 1 : rectTransform.rect.width;
194 var sizeY = !relativeSize ? 1 : rectTransform.rect.height;
195 var offsetX = -rectTransform.pivot.x * sizeX;
196 var offsetY = -rectTransform.pivot.y * sizeY;
199 var segments =
new List<UIVertex[]> ();
201 for (var i = 1; i < pointsToDraw.Count; i += 2) {
202 var start = pointsToDraw [i - 1];
203 var end = pointsToDraw [i];
204 start =
new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
205 end =
new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
208 segments.Add (CreateLineCap (start, end, SegmentType.Start));
212 segments.Add (CreateLineSegment (start, end, SegmentType.Middle));
215 segments.Add (CreateLineCap (start, end, SegmentType.End));
219 for (var i = 1; i < pointsToDraw.Count; i++) {
220 var start = pointsToDraw [i - 1];
221 var end = pointsToDraw [i];
222 start =
new Vector2 (start.x * sizeX + offsetX, start.y * sizeY + offsetY);
223 end =
new Vector2 (end.x * sizeX + offsetX, end.y * sizeY + offsetY);
225 if (lineCaps && i == 1) {
226 segments.Add (CreateLineCap (start, end, SegmentType.Start));
229 segments.Add (CreateLineSegment (start, end, SegmentType.Middle));
232 if (lineCaps && i == pointsToDraw.Count - 1) {
233 segments.Add (CreateLineCap (start, end, SegmentType.End));
239 for (var i = 0; i < segments.Count; i++) {
240 if (!lineList && i < segments.Count - 1) {
241 var vec1 = segments [i] [1].position - segments [i] [2].position;
242 var vec2 = segments [i + 1] [2].position - segments [i + 1] [1].position;
243 var angle =
Vector2.Angle (vec1, vec2) * Mathf.Deg2Rad;
246 var sign = Mathf.Sign (
Vector3.Cross (vec1.normalized, vec2.normalized).z);
249 var miterDistance = lineThickness / (2 * Mathf.Tan (angle / 2));
250 var miterPointA = segments [i] [2].position - vec1.normalized * miterDistance * sign;
251 var miterPointB = segments [i] [3].position + vec1.normalized * miterDistance * sign;
256 if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_MITER_JOIN) {
257 segments [i] [2].position = miterPointA;
258 segments [i] [3].position = miterPointB;
259 segments [i + 1] [0].position = miterPointB;
260 segments [i + 1] [1].position = miterPointA;
267 if (miterDistance < vec1.magnitude / 2 && miterDistance < vec2.magnitude / 2 && angle > MIN_BEVEL_NICE_JOIN) {
269 segments [i] [2].position = miterPointA;
270 segments [i + 1] [1].position = miterPointA;
272 segments [i] [3].position = miterPointB;
273 segments [i + 1] [0].position = miterPointB;
277 var join =
new UIVertex[] { segments [i] [2], segments [i] [3], segments [i + 1] [0], segments [i + 1] [1] };
278 vh.AddUIVertexQuad (join);
282 vh.AddUIVertexQuad (segments [i]);
284 if (vh.currentVertCount > 64000) {
285 Debug.LogError (
"Max Verticies size is 64000, current mesh verticies count is [" + vh.currentVertCount +
"] - Cannot Draw");
294 if (m_points !=
null && m_points.Count > 0) {
298 PopulateMesh (vh, m_points);
312 private UIVertex[] CreateLineCap(Vector2 start, Vector2 end, SegmentType type)
314 if (type == SegmentType.Start)
316 var capStart = start - ((end - start).normalized * lineThickness / 2);
317 return CreateLineSegment(capStart, start, SegmentType.Start);
319 else if (type == SegmentType.End)
321 var capEnd = end + ((end - start).normalized * lineThickness / 2);
322 return CreateLineSegment(end, capEnd, SegmentType.End);
325 Debug.LogError(
"Bad SegmentType passed in to CreateLineCap. Must be SegmentType.Start or SegmentType.End");
329 private UIVertex[] CreateLineSegment(Vector2 start, Vector2 end, SegmentType type)
331 Vector2 offset =
new Vector2((start.y - end.y), end.x - start.x).normalized * lineThickness / 2;
333 var v1 = start - offset;
334 var v2 = start + offset;
335 var v3 = end + offset;
336 var v4 = end - offset;
340 case SegmentType.Start:
341 return SetVbo(
new[] { v1, v2, v3, v4 }, startUvs);
342 case SegmentType.End:
343 return SetVbo(
new[] { v1, v2, v3, v4 }, endUvs);
344 case SegmentType.Full:
345 return SetVbo(
new[] { v1, v2, v3, v4 }, fullUvs);
347 return SetVbo(
new[] { v1, v2, v3, v4 }, middleUvs);
355 var outer = Sprites.DataUtility.GetOuterUV(
activeSprite);
356 var inner = Sprites.DataUtility.GetInnerUV(
activeSprite);
357 UV_TOP_LEFT =
new Vector2(outer.x, outer.y);
358 UV_BOTTOM_LEFT =
new Vector2(outer.x, outer.w);
359 UV_TOP_CENTER_LEFT =
new Vector2(inner.x, inner.y);
360 UV_TOP_CENTER_RIGHT =
new Vector2(inner.z, inner.y);
361 UV_BOTTOM_CENTER_LEFT =
new Vector2(inner.x, inner.w);
362 UV_BOTTOM_CENTER_RIGHT =
new Vector2(inner.z, inner.w);
363 UV_TOP_RIGHT =
new Vector2(outer.z, outer.y);
364 UV_BOTTOM_RIGHT =
new Vector2(outer.z, outer.w);
368 UV_TOP_LEFT = Vector2.zero;
369 UV_BOTTOM_LEFT =
new Vector2(0, 1);
370 UV_TOP_CENTER_LEFT =
new Vector2(0.5f, 0);
371 UV_TOP_CENTER_RIGHT =
new Vector2(0.5f, 0);
372 UV_BOTTOM_CENTER_LEFT =
new Vector2(0.5f, 1);
373 UV_BOTTOM_CENTER_RIGHT =
new Vector2(0.5f, 1);
374 UV_TOP_RIGHT =
new Vector2(1, 0);
375 UV_BOTTOM_RIGHT = Vector2.one;
379 startUvs =
new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_CENTER_LEFT, UV_TOP_CENTER_LEFT };
380 middleUvs =
new[] { UV_TOP_CENTER_LEFT, UV_BOTTOM_CENTER_LEFT, UV_BOTTOM_CENTER_RIGHT, UV_TOP_CENTER_RIGHT };
381 endUvs =
new[] { UV_TOP_CENTER_RIGHT, UV_BOTTOM_CENTER_RIGHT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
382 fullUvs =
new[] { UV_TOP_LEFT, UV_BOTTOM_LEFT, UV_BOTTOM_RIGHT, UV_TOP_RIGHT };
List< Vector2 > GetDrawingPoints0()
void SetControlPoints(List< Vector2 > newControlPoints)
List< Vector2 > GetDrawingPoints2()
List< Vector2 > GetDrawingPoints1()
override void OnPopulateMesh(VertexHelper vh)
int BezierSegmentsPerCurve
void AddPoint(Vector2 pointToAdd)
override void ResolutionToNativeSize(float distance)
void RemovePoint(Vector2 pointToRemove)
override void GeneratedUVs()
List< Vector2 > Points
Points to be drawn in the line.
Vector2[] IncreaseResolution(Vector2[] input)
ResolutionMode ImproveResolution
UIVertex[] SetVbo(Vector2[] vertices, Vector2[] uvs)
Credit Erdener Gonenc - @PixelEnvision.