[OvldGenCallTarget] static void Polyline_Internal(PolylinePath path, [OvldDefault("false")] bool closed, [OvldDefault(nameof(PolylineGeometry))] PolylineGeometry geometry, [OvldDefault(nameof(PolylineJoins))] PolylineJoins joins, [OvldDefault(nameof(Thickness))] float thickness, [OvldDefault(nameof(ThicknessSpace))] ThicknessSpace thicknessSpace, [OvldDefault(nameof(Color))] Color color) { if (path.EnsureMeshIsReadyToRender(closed, joins, out Mesh mesh) == false) { return; // no points defined in the mesh } switch (path.Count) { case 0: Debug.LogWarning("Tried to draw polyline with no points"); return; case 1: Debug.LogWarning("Tried to draw polyline with only one point"); return; } void ApplyToMpb(MpbPolyline2D mpb) { mpb.thickness.Add(thickness); mpb.thicknessSpace.Add((int)thicknessSpace); mpb.color.Add(color.ColorSpaceAdjusted()); mpb.alignment.Add((int)geometry); mpb.scaleMode.Add((int)ScaleMode); } if (DrawCommand.IsAddingDrawCommandsToBuffer) // mark as used by this command to prevent destroy in dispose { path.RegisterToCommandBuffer(DrawCommand.CurrentWritingCommandBuffer); } using (new IMDrawer(mpbPolyline, ShapesMaterialUtils.GetPolylineMat(joins)[Draw.BlendMode], mesh, 0)) ApplyToMpb(mpbPolyline); if (joins.HasJoinMesh()) { using (new IMDrawer(mpbPolylineJoins, ShapesMaterialUtils.GetPolylineJoinsMat(joins)[Draw.BlendMode], mesh, 1)) ApplyToMpb(mpbPolylineJoins); } }
[OvldGenCallTarget] static void Polyline([OvldDefault(nameof(BlendMode))] ShapesBlendMode blendMode, PolylinePath path, [OvldDefault("false")] bool closed, [OvldDefault(nameof(PolylineGeometry))] PolylineGeometry geometry, [OvldDefault(nameof(PolylineJoins))] PolylineJoins joins, [OvldDefault(nameof(LineThickness))] float thickness, [OvldDefault(nameof(LineThicknessSpace))] ThicknessSpace thicknessSpace, [OvldDefault(nameof(Color))] Color color) { if (path.EnsureMeshIsReadyToRender(closed, joins, out Mesh mesh) == false) { return; // no points defined in the mesh } switch (path.Count) { case 0: Debug.LogWarning("Tried to draw polyline with no points"); return; case 1: Debug.LogWarning("Tried to draw polyline with only one point"); return; } void ApplyToMpb(MpbPolyline mpb) { mpb.thickness.Add(thickness); mpb.thicknessSpace.Add((int)thicknessSpace); mpb.color.Add(color); mpb.alignment.Add((int)geometry); mpb.scaleMode.Add((int)ScaleMode); } using (new IMDrawer(mpbPolyline, ShapesMaterialUtils.GetPolylineMat(joins)[blendMode], mesh, 0)) ApplyToMpb(mpbPolyline); if (joins.HasJoinMesh()) { using (new IMDrawer(mpbPolylineJoins, ShapesMaterialUtils.GetPolylineJoinsMat(joins)[blendMode], mesh, 1)) ApplyToMpb(mpbPolylineJoins); } }
public static void GenPolylineMesh(Mesh mesh, IList <PolylinePoint> path, bool closed, PolylineJoins joins, bool useColors) { mesh.Clear(); // todo maybe not always do this you know? int pointCount = path.Count; if (pointCount < 2) { return; } if (pointCount == 2 && closed) { closed = false; } PolylinePoint firstPoint = path[0]; PolylinePoint lastPoint = path[path.Count - 1]; // if the last point is at the same place as the first and it's closed, ignore the last point if ((closed || pointCount == 2) && SamePosition(firstPoint.point, lastPoint.point)) { pointCount--; // ignore last point if (pointCount < 2) // check point count again { return; } lastPoint = path[path.Count - 2]; // second last point technically } // only mitered joints can be in the same submesh at the moment bool separateJoinMesh = joins.HasJoinMesh(); bool isSimpleJoin = joins.HasSimpleJoin(); // only used when join meshes exist int vertsPerPathPoint = separateJoinMesh ? 5 : 2; int trianglesPerSegment = separateJoinMesh ? 4 : 2; int vertexCount = pointCount * vertsPerPathPoint; int vertexCountTotal = vertexCount; int segmentCount = closed ? pointCount : pointCount - 1; int triangleCount = segmentCount * trianglesPerSegment; int triangleIndexCount = triangleCount * 3; // Joins mesh data int[] meshJoinsTriangles = default; int joinVertsPerJoin = default; if (separateJoinMesh) { joinVertsPerJoin = isSimpleJoin ? 3 : 5; int joinCount = closed ? pointCount : pointCount - 2; int joinTrianglesPerJoin = isSimpleJoin ? 1 : 3; int joinTriangleIndexCount = joinCount * joinTrianglesPerJoin * 3; int vertexCountJoins = joinCount * joinVertsPerJoin; vertexCountTotal += vertexCountJoins; meshJoinsTriangles = new int[joinTriangleIndexCount]; } Color[] meshColors = useColors ? new Color[vertexCountTotal] : null; Vector3[] meshVertices = new Vector3[vertexCountTotal]; #if UNITY_2019_3_OR_NEWER Vector4[] meshUv0 = new Vector4[vertexCountTotal]; // UVs for masking. z contains endpoint status, w is thickness Vector3[] meshUv1Prevs = new Vector3[vertexCountTotal]; Vector3[] meshUv2Nexts = new Vector3[vertexCountTotal]; #else // List<> is the only supported vec3 UV assignment method prior to Unity 2019.3 List <Vector4> meshUv0 = new List <Vector4>(new Vector4[vertexCountTotal]); List <Vector3> meshUv1Prevs = new List <Vector3>(new Vector3[vertexCountTotal]); List <Vector3> meshUv2Nexts = new List <Vector3>(new Vector3[vertexCountTotal]); #endif int[] meshTriangles = new int[triangleIndexCount]; // indices used per triangle int iv0, iv1, iv2 = 0, iv3 = 0, iv4 = 0; int ivj0 = 0, ivj1 = 0, ivj2 = 0, ivj3 = 0, ivj4 = 0; int triId = 0; int triIdJoin = 0; for (int i = 0; i < pointCount; i++) { bool isLast = i == pointCount - 1; bool isFirst = i == 0; bool makeJoin = closed || (!isLast && !isFirst); bool isEndpoint = closed == false && (isFirst || isLast); float uvEndpointValue = isEndpoint ? (isFirst ? -1 : 1) : 0; void SetUv0(int id, float x, float y) => meshUv0[id] = new Vector4(x, y, uvEndpointValue, path[i].thickness); // Indices & verts Vector3 vert = path[i].point; Color color = useColors ? path[i].color : default; iv0 = i * vertsPerPathPoint; if (separateJoinMesh) { iv1 = iv0 + 1; // "prev" outer iv2 = iv0 + 2; // "next" outer iv3 = iv0 + 3; // "prev" inner iv4 = iv0 + 4; // "next" inner meshVertices[iv0] = vert; meshVertices[iv1] = vert; meshVertices[iv2] = vert; meshVertices[iv3] = vert; meshVertices[iv4] = vert; if (useColors) { meshColors[iv0] = color; meshColors[iv1] = color; meshColors[iv2] = color; meshColors[iv3] = color; meshColors[iv4] = color; } // joins mesh if (makeJoin) { int joinIndex = (closed ? i : i - 1); // Skip first if open ivj0 = joinIndex * joinVertsPerJoin + vertexCount; ivj1 = ivj0 + 1; ivj2 = ivj0 + 2; ivj3 = ivj0 + 3; ivj4 = ivj0 + 4; meshVertices[ivj0] = vert; meshVertices[ivj1] = vert; meshVertices[ivj2] = vert; if (useColors) { meshColors[ivj0] = color; meshColors[ivj1] = color; meshColors[ivj2] = color; } if (isSimpleJoin == false) { meshVertices[ivj3] = vert; meshVertices[ivj4] = vert; if (useColors) { meshColors[ivj3] = color; meshColors[ivj4] = color; } } } } else { iv1 = iv0 + 1; // Inner vert meshVertices[iv0] = vert; meshVertices[iv1] = vert; if (useColors) { meshColors[iv0] = color; meshColors[iv1] = color; } } // Setting up next/previous positions Vector3 prevPos; Vector3 nextPos; if (i == 0) { prevPos = closed ? lastPoint.point : (firstPoint.point * 2 - path[1].point); // Mirror second point nextPos = path[i + 1].point; } else if (i == pointCount - 1) { prevPos = path[i - 1].point; nextPos = closed ? firstPoint.point : (path[pointCount - 1].point * 2 - path[pointCount - 2].point); // Mirror second last point } else { prevPos = path[i - 1].point; nextPos = path[i + 1].point; } void SetPrevNext(int atIndex) { meshUv1Prevs[atIndex] = prevPos; meshUv2Nexts[atIndex] = nextPos; } SetPrevNext(iv0); SetPrevNext(iv1); if (separateJoinMesh) { SetPrevNext(iv2); SetPrevNext(iv3); SetPrevNext(iv4); if (makeJoin) { SetPrevNext(ivj0); SetPrevNext(ivj1); SetPrevNext(ivj2); if (isSimpleJoin == false) { SetPrevNext(ivj3); SetPrevNext(ivj4); } } } if (separateJoinMesh) { SetUv0(iv0, 0, 0); SetUv0(iv1, -1, -1); SetUv0(iv2, -1, 1); SetUv0(iv3, 1, -1); SetUv0(iv4, 1, 1); if (makeJoin) { SetUv0(ivj0, 0, 0); if (isSimpleJoin) { SetUv0(ivj1, 1, -1); SetUv0(ivj2, 1, 1); } else { SetUv0(ivj1, 1, -1); SetUv0(ivj2, -1, -1); SetUv0(ivj3, -1, 1); SetUv0(ivj4, 1, 1); } } } else { SetUv0(iv0, -1, i); SetUv0(iv1, 1, i); } if (isLast == false || closed) { // clockwise order void AddQuad(int a, int b, int c, int d) { meshTriangles[triId++] = a; meshTriangles[triId++] = b; meshTriangles[triId++] = c; meshTriangles[triId++] = c; meshTriangles[triId++] = d; meshTriangles[triId++] = a; } if (separateJoinMesh) { int rootCenter = iv0; int rootOuter = iv2; int rootInner = iv4; int nextCenter = isLast ? 0 : rootCenter + vertsPerPathPoint; int nextOuter = nextCenter + 1; int nextInner = nextCenter + 3; AddQuad(rootCenter, rootOuter, nextOuter, nextCenter); AddQuad(nextCenter, nextInner, rootInner, rootCenter); if (makeJoin) { meshJoinsTriangles[triIdJoin++] = ivj0; meshJoinsTriangles[triIdJoin++] = ivj1; meshJoinsTriangles[triIdJoin++] = ivj2; if (isSimpleJoin == false) { meshJoinsTriangles[triIdJoin++] = ivj2; meshJoinsTriangles[triIdJoin++] = ivj3; meshJoinsTriangles[triIdJoin++] = ivj0; meshJoinsTriangles[triIdJoin++] = ivj0; meshJoinsTriangles[triIdJoin++] = ivj3; meshJoinsTriangles[triIdJoin++] = ivj4; } } } else { int rootOuter = iv0; int rootInner = iv1; int nextOuter = isLast ? 0 : rootOuter + vertsPerPathPoint; int nextInner = nextOuter + 1; AddQuad(rootInner, rootOuter, nextOuter, nextInner); } } } // assign to segments mesh mesh.vertices = meshVertices; mesh.subMeshCount = 2; mesh.SetTriangles(meshTriangles, 0); mesh.SetTriangles(meshJoinsTriangles, 1); mesh.SetUVs(0, meshUv0); mesh.SetUVs(1, meshUv1Prevs); mesh.SetUVs(2, meshUv2Nexts); if (useColors) { mesh.colors = meshColors; } }