static bool generatingClockwisePolygon; // assigned in GenPolygonMesh, used by EarClipPoint public static void GenPolygonMesh(Mesh mesh, List <Vector2> path, PolygonTriangulation triangulation) { // kinda have to do this, the algorithm relies on knowing this generatingClockwisePolygon = ShapesMath.PolygonSignedArea(path) > 0; mesh.Clear(); // todo maybe not always do this you know? int pointCount = path.Count; if (pointCount < 2) { return; } int triangleCount = pointCount - 2; int triangleIndexCount = triangleCount * 3; int[] meshTriangles = new int[triangleIndexCount]; if (triangulation == PolygonTriangulation.FastConvexOnly) { int tri = 0; for (int i = 0; i < triangleCount; i++) { meshTriangles[tri++] = i + 2; meshTriangles[tri++] = i + 1; meshTriangles[tri++] = 0; } } else { List <EarClipPoint> pointsLeft = new List <EarClipPoint>(pointCount); for (int i = 0; i < pointCount; i++) { pointsLeft.Add(new EarClipPoint(i, new Vector2(path[i].x, path[i].y))); } for (int i = 0; i < pointCount; i++) // update prev/next connections { EarClipPoint p = pointsLeft[i]; p.prev = pointsLeft[(i + pointCount - 1) % pointCount]; p.next = pointsLeft[(i + 1) % pointCount]; } int tri = 0; int countLeft; int safeguard = 1000000; while ((countLeft = pointsLeft.Count) >= 3 && (safeguard-- > 0)) { //for( int k = 0; k < pointsLeft.Count * 2; k++ ) { if (countLeft == 3) { // final triangle meshTriangles[tri++] = pointsLeft[2].vertIndex; meshTriangles[tri++] = pointsLeft[1].vertIndex; meshTriangles[tri++] = pointsLeft[0].vertIndex; break; } // iterate until we find a convex vertex bool foundConvex = false; for (int i = 0; i < countLeft; i++) { EarClipPoint p = pointsLeft[i]; if (p.ReflexState == ReflexState.Convex) { // it's convex! now make sure there are no reflex points inside bool canClipEar = true; int idPrev = (i + countLeft - 1) % countLeft; int idNext = (i + 1) % countLeft; for (int j = 0; j < countLeft; j++) { if (j == i) { continue; // skip self } if (j == idPrev) { continue; // skip next } if (j == idNext) { continue; // skip prev } if (pointsLeft[j].ReflexState == ReflexState.Reflex) { // found a reflex point, make sure it's outside the triangle if (ShapesMath.PointInsideTriangle(p.next.pt, p.pt, p.prev.pt, pointsLeft[j].pt, 0f, -0.0001f, 0f)) { canClipEar = false; // it's inside, rip break; } } } if (canClipEar) { meshTriangles[tri++] = p.next.vertIndex; meshTriangles[tri++] = p.vertIndex; meshTriangles[tri++] = p.prev.vertIndex; p.next.MarkReflexUnknown(); p.prev.MarkReflexUnknown(); (p.next.prev, p.prev.next) = (p.prev, p.next); // update prev/next pointsLeft.RemoveAt(i); foundConvex = true; break; // stop search for more convex edges, restart loop } } } // no convex found?? if (foundConvex == false) { Debug.LogError("Invalid polygon triangulation - no convex edges found. Your polygon is likely self-intersecting"); goto breakBoth; } } breakBoth: if (safeguard < 1) { Debug.LogError("Polygon triangulation failed, please report a bug (Shapes/Report Bug) with this exact case included"); } } // assign to segments mesh List <Vector3> verts3D = new List <Vector3>(pointCount); for (int i = 0; i < pointCount; i++) { verts3D.Add(path[i]); } mesh.SetVertices(verts3D); mesh.subMeshCount = 1; mesh.SetTriangles(meshTriangles, 0); }