using System.Collections.Generic;
using UnityEngine;
namespace FairyGUI
{
///
///
/// Inspired by kim ki won (http://mypi.ruliweb.daum.net/mypi.htm?id=newtypekorea)
///
public class LineMesh : IMeshFactory
{
///
///
///
public GPath path;
///
///
///
public float lineWidth;
///
///
///
public AnimationCurve lineWidthCurve;
///
///
///
public Gradient gradient;
///
///
///
public bool roundEdge;
///
///
///
public float fillStart;
///
///
///
public float fillEnd;
///
///
///
public float pointDensity;
///
///
///
public bool repeatFill;
static List points = new List();
static List ts = new List();
public LineMesh()
{
path = new GPath();
lineWidth = 2;
fillStart = 0;
fillEnd = 1;
pointDensity = 0.1f;
}
public void OnPopulateMesh(VertexBuffer vb)
{
Vector2 uvMin = vb.uvRect.position;
Vector2 uvMax = new Vector2(vb.uvRect.xMax, vb.uvRect.yMax);
float uvRatio = path.length / vb.textureSize.x;
int segCount = path.segmentCount;
float t = 0;
float lw = lineWidth;
float u;
for (int si = 0; si < segCount; si++)
{
float ratio = path.GetSegmentLength(si) / path.length;
float t0 = Mathf.Clamp(fillStart - t, 0, ratio) / ratio;
float t1 = Mathf.Clamp(fillEnd - t, 0, ratio) / ratio;
if (t0 >= t1)
{
t += ratio;
continue;
}
points.Clear();
ts.Clear();
path.GetPointsInSegment(si, t0, t1, points, ts, pointDensity);
int cnt = points.Count;
Color c0 = vb.vertexColor;
Color c1 = vb.vertexColor;
if (gradient != null)
c0 = gradient.Evaluate(t);
if (lineWidthCurve != null)
lw = lineWidthCurve.Evaluate(t);
if (roundEdge && si == 0 && t0 == 0)
DrawRoundEdge(vb, points[0], points[1], lw, c0, uvMin);
int vertCount = vb.currentVertCount;
for (int i = 1; i < cnt; i++)
{
Vector3 p0 = points[i - 1];
Vector3 p1 = points[i];
int k = vertCount + (i - 1) * 2;
float tc = t + ratio * ts[i];
Vector3 lineVector = p1 - p0;
Vector3 widthVector = Vector3.Cross(lineVector, new Vector3(0, 0, 1));
widthVector.Normalize();
if (i == 1)
{
if (repeatFill)
u = tc * uvRatio * uvMax.x;
else
u = Mathf.Lerp(uvMin.x, uvMax.x, t + ratio * ts[i - 1]);
vb.AddVert(p0 - widthVector * lw * 0.5f, c0, new Vector2(u, uvMax.y));
vb.AddVert(p0 + widthVector * lw * 0.5f, c0, new Vector2(u, uvMin.y));
if (si != 0) //joint
{
vb.AddTriangle(k - 2, k - 1, k + 1);
vb.AddTriangle(k - 2, k + 1, k);
}
}
if (gradient != null)
c1 = gradient.Evaluate(tc);
if (lineWidthCurve != null)
lw = lineWidthCurve.Evaluate(tc);
if (repeatFill)
u = tc * uvRatio * uvMax.x;
else
u = Mathf.Lerp(uvMin.x, uvMax.x, tc);
vb.AddVert(p1 - widthVector * lw * 0.5f, c1, new Vector2(u, uvMax.y));
vb.AddVert(p1 + widthVector * lw * 0.5f, c1, new Vector2(u, uvMin.y));
vb.AddTriangle(k, k + 1, k + 3);
vb.AddTriangle(k, k + 3, k + 2);
}
if (roundEdge && si == segCount - 1 && t1 == 1)
DrawRoundEdge(vb, points[cnt - 1], points[cnt - 2], lw, c1, uvMax);
t += ratio;
}
}
void DrawRoundEdge(VertexBuffer vb, Vector2 p0, Vector2 p1, float lw, Color32 color, Vector2 uv)
{
Vector2 widthVector = Vector3.Cross(p0 - p1, new Vector3(0, 0, 1));
widthVector.Normalize();
widthVector = widthVector * lw / 2f;
Vector2 lineVector = (p0 - p1).normalized * lw / 2f;
int sides = Mathf.CeilToInt(Mathf.PI * lw / 2);
if (sides < 6)
sides = 6;
int current = vb.currentVertCount;
float angleUnit = Mathf.PI / (sides - 1);
vb.AddVert(p0, color, uv);
vb.AddVert(p0 + widthVector, color, uv);
for (int n = 0; n < sides; n++)
{
vb.AddVert(p0 + Mathf.Cos(angleUnit * n) * widthVector + Mathf.Sin(angleUnit * n) * lineVector, color, uv);
vb.AddTriangle(current, current + 1 + n, current + 2 + n);
}
}
}
}