using System; using System.Collections.Generic; using UnityEngine; namespace PathBerserker2d { class MiterLineMeshCreator { private List verts = new List(); private List colors = new List(); private List tris = new List(); public void CreateLine(Mesh mesh, IList linePoints, float thickness, Color line, Color32 corner, Color endpoint) { verts.Clear(); colors.Clear(); tris.Clear(); verts.Capacity = Math.Max(verts.Capacity, linePoints.Count * 2); colors.Capacity = Math.Max(colors.Capacity, verts.Count); tris.Capacity = Math.Max(tris.Capacity, linePoints.Count * 4); Vector2 curTangent = (linePoints[0] - linePoints[1]).normalized; Vector2 curNormal = new Vector2(-curTangent.y, curTangent.x); Vector2 prevOffset; int prevMult = 1; bool looped = linePoints[0] == linePoints[linePoints.Count - 1]; if (looped) { // its a loop Vector2 nextTangent = (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized; Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x); var tangent2 = (nextTangent + curTangent).normalized; var miter2 = new Vector2(-tangent2.y, tangent2.x); float length2 = thickness / Vector2.Dot(nextNormal, miter2); prevOffset = length2 * miter2; prevMult = Math.Sign(Vector2.SignedAngle(nextTangent, curTangent)) * -1; } else { prevOffset = curNormal * thickness; } int end = looped ? linePoints.Count - 1 : linePoints.Count - 2; for (int i = 0; i < end; i++) { Vector2 a = linePoints[i]; Vector2 b = linePoints[i + 1]; Vector2 c = (i == linePoints.Count - 2) ? linePoints[1] : linePoints[i + 2]; Vector2 nextTangent = (b - c).normalized; Vector2 nextNormal = new Vector2(-nextTangent.y, nextTangent.x); var tangent2 = (nextTangent + curTangent).normalized; var miter2 = new Vector2(-tangent2.y, tangent2.x); float length2 = thickness / Vector2.Dot(curNormal, miter2); Vector2 offset2 = length2 * miter2; verts.Add(a + prevOffset * prevMult); verts.Add((a + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult); int nextMult; if (Vector2.SignedAngle(curTangent, nextTangent) > 0) { if (prevMult == -1) { verts.Add(b - offset2); verts.Add((b - offset2) + curNormal * thickness * 2); } else { verts.Add((b - offset2) + curNormal * thickness * 2); verts.Add(b - offset2); } nextMult = -1; } else { if (prevMult == -1) { verts.Add((b + offset2) - curNormal * thickness * 2); verts.Add(b + offset2); } else { verts.Add(b + offset2); verts.Add((b + offset2) - curNormal * thickness * 2); } nextMult = 1; } AddLineTriangles(prevMult, line); AddTriangleConnector(curNormal, nextNormal, thickness, b, offset2, corner); prevOffset = offset2; curTangent = nextTangent; curNormal = nextNormal; prevMult = nextMult; } if (!looped) { verts.Add(linePoints[linePoints.Count - 2] + prevOffset * prevMult); verts.Add((linePoints[linePoints.Count - 2] + prevOffset * prevMult) - curNormal * thickness * 2 * prevMult); if (prevMult == -1) { verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness); verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness); } else { verts.Add(linePoints[linePoints.Count - 1] + curNormal * thickness); verts.Add(linePoints[linePoints.Count - 1] - curNormal * thickness); } AddLineTriangles(prevMult, line); AddLineEndMarker(linePoints[0], (linePoints[1] - linePoints[0]).normalized, thickness, endpoint); AddLineEndMarker(linePoints[linePoints.Count -1], (linePoints[linePoints.Count - 2] - linePoints[linePoints.Count - 1]).normalized, thickness, endpoint); } mesh.triangles = new int[] { }; mesh.vertices = verts.ToArray(); mesh.triangles = tris.ToArray(); mesh.colors32 = colors.ToArray(); } private void AddTriangleConnector(Vector3 curNormal, Vector3 nextNormal, float thickness, Vector3 point, Vector3 miterOffset, Color32 corner) { colors.Add(corner); colors.Add(corner); colors.Add(corner); if (Vector2.SignedAngle(curNormal, nextNormal) > 0) { verts.Add((point - miterOffset) + nextNormal * thickness * 2); verts.Add(point - miterOffset); verts.Add((point - miterOffset) + curNormal * thickness * 2); tris.Add(verts.Count - 3); tris.Add(verts.Count - 1); tris.Add(verts.Count - 2); } else { verts.Add((point + miterOffset) - nextNormal * thickness * 2); verts.Add(point + miterOffset); verts.Add((point + miterOffset) - curNormal * thickness * 2); tris.Add(verts.Count - 2); tris.Add(verts.Count - 1); tris.Add(verts.Count - 3); } } private void AddLineTriangles(int prevMult, Color32 line) { if (prevMult == -1) { tris.Add(colors.Count + 3); tris.Add(colors.Count + 1); tris.Add(colors.Count + 0); tris.Add(colors.Count + 0); tris.Add(colors.Count + 2); tris.Add(colors.Count + 3); } else { tris.Add(colors.Count + 0); tris.Add(colors.Count + 1); tris.Add(colors.Count + 3); tris.Add(colors.Count + 3); tris.Add(colors.Count + 2); tris.Add(colors.Count + 0); } colors.Add(line); colors.Add(line); colors.Add(line); colors.Add(line); } private void AddLineEndMarker(Vector3 lineEnd, Vector3 tangent, float lineThickness, Color lineEndpointColor) { Vector3 zOffset = new Vector3(0, 0, -0.01f); Vector3 normal = new Vector3(-tangent.y, tangent.x); float increasedThickness = lineThickness * 1.25f * 2; int index = verts.Count; verts.Add(lineEnd + normal * increasedThickness + zOffset); verts.Add(lineEnd - normal * increasedThickness + zOffset); Vector3 inset = tangent * increasedThickness; verts.Add(lineEnd + inset + normal * increasedThickness + zOffset); verts.Add(lineEnd + inset - normal * increasedThickness + zOffset); colors.Add(lineEndpointColor); colors.Add(lineEndpointColor); colors.Add(lineEndpointColor); colors.Add(lineEndpointColor); tris.Add(index + 1); tris.Add(index); tris.Add(index + 2); tris.Add(index + 2); tris.Add(index + 3); tris.Add(index + 1); } } }