private static void TessellateFilledFan(TessellationType tessellationType, Vector2 center, Vector2 radius, Color color, float posZ, MeshWriteData mesh, ref UInt16 indexOffset, ref UInt16 vertexCount, ref UInt16 indexCount, bool countOnly)
        {
            if (countOnly)
            {
                vertexCount += (UInt16)(kSubdivisions + 1);
                indexCount  += (UInt16)((kSubdivisions - 1) * 3);
                return;
            }

            float innerVertexFlags, outerVertexFlags;

            if (tessellationType == TessellationType.EdgeCorner)
            {
                innerVertexFlags = (float)VertexFlags.IsEdge;
                outerVertexFlags = (float)VertexFlags.IsSolid;
            }
            else
            {
                outerVertexFlags = innerVertexFlags = (float)mesh.m_Flags;
            }

            var p = new Vector2(center.x - radius.x, center.y);

            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(center.x, center.y, posZ), uv = p, tint = color, flags = innerVertexFlags
            });
            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(p.x, p.y, posZ), uv = center, tint = color, flags = outerVertexFlags
            });
            vertexCount += 2;

            for (int k = 1; k < kSubdivisions; ++k)
            {
                float angle = (Mathf.PI * 0.5f) * ((float)k) / (kSubdivisions - 1);
                p = center + new Vector2(-Mathf.Cos(angle), -Mathf.Sin(angle)) * radius;
                mesh.SetNextVertex(new Vertex()
                {
                    position = new Vector3(p.x, p.y, posZ), uv = center, tint = color, flags = outerVertexFlags
                });
                vertexCount++;

                mesh.SetNextIndex((UInt16)(indexOffset + 0));
                mesh.SetNextIndex((UInt16)(indexOffset + k + 1));
                mesh.SetNextIndex((UInt16)(indexOffset + k));
                indexCount += 3;
            }

            indexOffset += (UInt16)(kSubdivisions + 1);
        }
        private static void TessellateBorderedFan(TessellationType tessellationType, Vector2 center, Vector2 radius, float leftWidth, float topWidth, Color color, float posZ, MeshWriteData mesh, ref UInt16 indexOffset, ref UInt16 vertexCount, ref UInt16 indexCount, bool countOnly)
        {
            if (countOnly)
            {
                vertexCount += (UInt16)(kSubdivisions * 2);
                indexCount  += (UInt16)((kSubdivisions - 1) * 6);
                return;
            }

            float innerVertexFlags, outerVertexFlags;

            if (tessellationType == TessellationType.EdgeCorner)
            {
                innerVertexFlags = (float)VertexFlags.IsEdge;
                outerVertexFlags = (float)VertexFlags.IsSolid;
            }
            else
            {
                innerVertexFlags = outerVertexFlags = (float)mesh.m_Flags;
            }

            var a = radius.x - leftWidth;
            var b = radius.y - topWidth;
            var p = new Vector2(center.x - radius.x, center.y);
            var q = new Vector2(center.x - a, center.y);

            mesh.SetNextVertex(new Vertex {
                position = new Vector3(q.x, q.y, posZ), uv = q - p, tint = color, flags = innerVertexFlags
            });
            mesh.SetNextVertex(new Vertex {
                position = new Vector3(p.x, p.y, posZ), uv = p - q, tint = color, flags = outerVertexFlags
            });
            vertexCount += 2;

            for (int k = 1; k < kSubdivisions; ++k)
            {
                float percent = ((float)k) / (kSubdivisions - 1);
                float angle   = (Mathf.PI * 0.5f) * percent;
                p = center + new Vector2(-Mathf.Cos(angle), -Mathf.Sin(angle)) * radius;
                q = center + new Vector2(-a * Mathf.Cos(angle), -b * Mathf.Sin(angle));
                mesh.SetNextVertex(new Vertex {
                    position = new Vector3(q.x, q.y, posZ), uv = q - p, tint = color, flags = innerVertexFlags
                });
                mesh.SetNextVertex(new Vertex {
                    position = new Vector3(p.x, p.y, posZ), uv = p - q, tint = color, flags = outerVertexFlags
                });
                vertexCount += 2;

                int i = k * 2;
                mesh.SetNextIndex((UInt16)(indexOffset + (i - 2)));
                mesh.SetNextIndex((UInt16)(indexOffset + (i)));
                mesh.SetNextIndex((UInt16)(indexOffset + (i - 1)));
                mesh.SetNextIndex((UInt16)(indexOffset + (i - 1)));
                mesh.SetNextIndex((UInt16)(indexOffset + (i)));
                mesh.SetNextIndex((UInt16)(indexOffset + (i + 1)));
                indexCount += 6;
            }

            indexOffset += (UInt16)(kSubdivisions * 2);
        }
        internal static void MakeText(MeshInfo meshInfo, Vector2 offset, MeshBuilder.AllocMeshData meshAlloc)
        {
            int           num           = MeshBuilder.LimitTextVertices(meshInfo.vertexCount, true);
            int           num2          = num / 4;
            MeshWriteData meshWriteData = meshAlloc.Allocate((uint)(num2 * 4), (uint)(num2 * 6));
            int           i             = 0;
            int           num3          = 0;
            int           num4          = 0;

            while (i < num2)
            {
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(meshInfo, num3, offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(meshInfo, num3 + 1, offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(meshInfo, num3 + 2, offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(meshInfo, num3 + 3, offset));
                meshWriteData.SetNextIndex((ushort)num3);
                meshWriteData.SetNextIndex((ushort)(num3 + 1));
                meshWriteData.SetNextIndex((ushort)(num3 + 2));
                meshWriteData.SetNextIndex((ushort)(num3 + 2));
                meshWriteData.SetNextIndex((ushort)(num3 + 3));
                meshWriteData.SetNextIndex((ushort)num3);
                i++;
                num3 += 4;
                num4 += 6;
            }
        }
Example #4
0
 private void ValidateMeshWriteData()
 {
     for (int i = 0; i < this.m_NextMeshWriteDataPoolItem; i++)
     {
         MeshWriteData meshWriteData = this.m_MeshWriteDataPool[i];
         bool          flag          = meshWriteData.vertexCount > 0 && meshWriteData.currentVertex < meshWriteData.vertexCount;
         if (flag)
         {
             Debug.LogError(string.Concat(new string[]
             {
                 "Not enough vertices written in generateVisualContent callback (asked for ",
                 meshWriteData.vertexCount.ToString(),
                 " but only wrote ",
                 meshWriteData.currentVertex.ToString(),
                 ")"
             }));
             Vertex nextVertex = meshWriteData.m_Vertices[0];
             while (meshWriteData.currentVertex < meshWriteData.vertexCount)
             {
                 meshWriteData.SetNextVertex(nextVertex);
             }
         }
         bool flag2 = meshWriteData.indexCount > 0 && meshWriteData.currentIndex < meshWriteData.indexCount;
         if (flag2)
         {
             Debug.LogError(string.Concat(new string[]
             {
                 "Not enough indices written in generateVisualContent callback (asked for ",
                 meshWriteData.indexCount.ToString(),
                 " but only wrote ",
                 meshWriteData.currentIndex.ToString(),
                 ")"
             }));
             while (meshWriteData.currentIndex < meshWriteData.indexCount)
             {
                 meshWriteData.SetNextIndex(0);
             }
         }
     }
 }
        void QuadA(Vector2 pos, Vector2 size, Vector2 uvSize, Vector2 uvOffset, Color color, MeshWriteData mesh, ushort vertextOffset)
        {
            var x0 = pos.x;
            var y0 = pos.y;

            var x1 = pos.x + size.x;
            var y1 = pos.y + size.y;

            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(x0, y0, Vertex.nearZ),
                tint     = color,
                uv       = new Vector2(0, 1) * uvSize * mesh.uvRegion.size + mesh.uvRegion.position
            });
            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(x1, y0, Vertex.nearZ),
                tint     = color,
                uv       = new Vector2(1, 1) * uvSize * mesh.uvRegion.size + mesh.uvRegion.position
            });
            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(x0, y1, Vertex.nearZ),
                tint     = color,
                uv       = new Vector2(0, uvOffset.y) * uvSize * mesh.uvRegion.size + mesh.uvRegion.position
            });
            mesh.SetNextVertex(new Vertex()
            {
                position = new Vector3(x1, y1, Vertex.nearZ),
                tint     = color,
                uv       = new Vector2(1, uvOffset.y) * uvSize * mesh.uvRegion.size + mesh.uvRegion.position
            });
            for (int i = 0; i < k_Indices.Length; i++)
            {
                mesh.SetNextIndex((ushort)(k_Indices[i] + vertextOffset));
            }
        }
        private static void MakeQuad(Rect rcPosition, Rect rcTexCoord, Color color, float posZ, MeshBuilder.AllocMeshData meshAlloc)
        {
            MeshWriteData meshWriteData = meshAlloc.Allocate(4u, 6u);
            float         x             = rcPosition.x;
            float         xMax          = rcPosition.xMax;
            float         yMax          = rcPosition.yMax;
            float         y             = rcPosition.y;
            Rect          uvRegion      = meshWriteData.uvRegion;
            float         x2            = rcTexCoord.x * uvRegion.width + uvRegion.xMin;
            float         x3            = rcTexCoord.xMax * uvRegion.width + uvRegion.xMin;
            float         y2            = rcTexCoord.y * uvRegion.height + uvRegion.yMin;
            float         y3            = rcTexCoord.yMax * uvRegion.height + uvRegion.yMin;

            meshWriteData.SetNextVertex(new Vertex
            {
                position = new Vector3(x, yMax, posZ),
                tint     = color,
                uv       = new Vector2(x2, y2)
            });
            meshWriteData.SetNextVertex(new Vertex
            {
                position = new Vector3(xMax, yMax, posZ),
                tint     = color,
                uv       = new Vector2(x3, y2)
            });
            meshWriteData.SetNextVertex(new Vertex
            {
                position = new Vector3(x, y, posZ),
                tint     = color,
                uv       = new Vector2(x2, y3)
            });
            meshWriteData.SetNextVertex(new Vertex
            {
                position = new Vector3(xMax, y, posZ),
                tint     = color,
                uv       = new Vector2(x3, y3)
            });
            meshWriteData.SetNextIndex(0);
            meshWriteData.SetNextIndex(2);
            meshWriteData.SetNextIndex(1);
            meshWriteData.SetNextIndex(1);
            meshWriteData.SetNextIndex(2);
            meshWriteData.SetNextIndex(3);
        }
        internal static void MakeText(NativeArray <UnityEngine.UIElements.TextVertex> uiVertices, Vector2 offset, MeshBuilder.AllocMeshData meshAlloc)
        {
            int           num           = MeshBuilder.LimitTextVertices(uiVertices.Length, true);
            int           num2          = num / 4;
            MeshWriteData meshWriteData = meshAlloc.Allocate((uint)(num2 * 4), (uint)(num2 * 6));
            int           i             = 0;
            int           num3          = 0;

            while (i < num2)
            {
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(uiVertices[num3], offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(uiVertices[num3 + 1], offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(uiVertices[num3 + 2], offset));
                meshWriteData.SetNextVertex(MeshBuilder.ConvertTextVertexToUIRVertex(uiVertices[num3 + 3], offset));
                meshWriteData.SetNextIndex((ushort)num3);
                meshWriteData.SetNextIndex((ushort)(num3 + 1));
                meshWriteData.SetNextIndex((ushort)(num3 + 2));
                meshWriteData.SetNextIndex((ushort)(num3 + 2));
                meshWriteData.SetNextIndex((ushort)(num3 + 3));
                meshWriteData.SetNextIndex((ushort)num3);
                i++;
                num3 += 4;
            }
        }
        private static void TessellateQuad(Rect rect, TessellationType tessellationType, Color color, float posZ, MeshWriteData mesh, ref UInt16 indexOffset, ref UInt16 vertexCount, ref UInt16 indexCount, bool countOnly)
        {
            if (rect.width < kEpsilon || rect.height < kEpsilon)
            {
                return;
            }

            if (countOnly)
            {
                vertexCount += 4;
                indexCount  += 6;
                return;
            }

            float x0 = rect.x;
            float x3 = rect.xMax;
            float y0 = rect.y;
            float y3 = rect.yMax;

            Vector2 uv0, uv1, uv2, uv3;
            float   flags0, flags1, flags2, flags3;

            switch (tessellationType)
            {
            case TessellationType.EdgeHorizontal:
                // The uvs contain the displacement from the vertically opposed corner.
                uv0    = new Vector2(0, y0 - y3);
                uv1    = new Vector2(0, y0 - y3);
                uv2    = new Vector2(0, y3 - y0);
                uv3    = new Vector2(0, y3 - y0);
                flags0 = flags1 = (float)VertexFlags.IsSolid;
                flags2 = flags3 = (float)VertexFlags.IsEdge;
                break;

            case TessellationType.EdgeVertical:
                // The uvs contain the displacement from the horizontally opposed corner.
                uv0    = new Vector2(x0 - x3, 0);
                uv1    = new Vector2(x3 - x0, 0);
                uv2    = new Vector2(x0 - x3, 0);
                uv3    = new Vector2(x3 - x0, 0);
                flags0 = flags2 = (float)VertexFlags.IsSolid;
                flags1 = flags3 = (float)VertexFlags.IsEdge;
                break;

            case TessellationType.EdgeCorner:
                uv0    = uv1 = uv2 = uv3 = Vector2.zero;
                flags0 = flags1 = flags2 = flags3 = (float)VertexFlags.IsSolid;
                break;

            case TessellationType.Content:
                uv0    = uv1 = uv2 = uv3 = Vector2.zero;  // UVs are computed later for content
                flags0 = flags1 = flags2 = flags3 = (float)mesh.m_Flags;
                break;

            default:
                throw new NotImplementedException();
            }

            mesh.SetNextVertex(new Vertex {
                position = new Vector3(x0, y0, posZ), uv = uv0, tint = color, flags = flags0
            });
            mesh.SetNextVertex(new Vertex {
                position = new Vector3(x3, y0, posZ), uv = uv1, tint = color, flags = flags1
            });
            mesh.SetNextVertex(new Vertex {
                position = new Vector3(x0, y3, posZ), uv = uv2, tint = color, flags = flags2
            });
            mesh.SetNextVertex(new Vertex {
                position = new Vector3(x3, y3, posZ), uv = uv3, tint = color, flags = flags3
            });

            mesh.SetNextIndex((UInt16)(indexOffset + 0));
            mesh.SetNextIndex((UInt16)(indexOffset + 2));
            mesh.SetNextIndex((UInt16)(indexOffset + 1));
            mesh.SetNextIndex((UInt16)(indexOffset + 3));
            mesh.SetNextIndex((UInt16)(indexOffset + 1));
            mesh.SetNextIndex((UInt16)(indexOffset + 2));

            vertexCount += 4;
            indexCount  += 6;
            indexOffset += 4;
        }
        unsafe static void RectClipTriangle(Vertex *vt, UInt16 *it, Vector4 clipRectMinMax, MeshWriteData mwd, ref UInt16 nextNewVertex)
        {
            Vertex *newVerts      = stackalloc Vertex[4 + 3 + 6];
            int     newVertsCount = 0;

            // First check, add original triangle vertices if they all fall within the clip rect, and early out if they are 3.
            // This hopefully will trap the majority of triangles.
            for (int i = 0; i < 3; i++)
            {
                if ((vt[i].position.x >= clipRectMinMax.x) &&
                    (vt[i].position.y >= clipRectMinMax.y) &&
                    (vt[i].position.x <= clipRectMinMax.z) &&
                    (vt[i].position.y <= clipRectMinMax.w))
                {
                    newVerts[newVertsCount++] = vt[i];
                }
            }

            if (newVertsCount == 3)
            {
                // Entire triangle is contained within the clip rect, just reference the original triangle verts and sayonara
                mwd.SetNextIndex(it[0]);
                mwd.SetNextIndex(it[1]);
                mwd.SetNextIndex(it[2]);
                return;
            }

            // Next, check if any clip rect vertices are within the triangle, and register those
            Vector3     uvwTL    = GetVertexBaryCentricCoordinates(vt, clipRectMinMax.x, clipRectMinMax.y);
            Vector3     uvwTR    = GetVertexBaryCentricCoordinates(vt, clipRectMinMax.z, clipRectMinMax.y);
            Vector3     uvwBL    = GetVertexBaryCentricCoordinates(vt, clipRectMinMax.x, clipRectMinMax.w);
            Vector3     uvwBR    = GetVertexBaryCentricCoordinates(vt, clipRectMinMax.z, clipRectMinMax.w);
            const float kEpsilon = 0.0000001f; // Better be safe and have more verts than miss some
            const float kMin     = -kEpsilon;
            const float kMax     = 1 + kEpsilon;

            if ((uvwTL.x >= kMin && uvwTL.x <= kMax) && (uvwTL.y >= kMin && uvwTL.y <= kMax) && (uvwTL.z >= kMin && uvwTL.z <= kMax))
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangle(vt, clipRectMinMax.x, clipRectMinMax.y, uvwTL);
            }
            if ((uvwTR.x >= kMin && uvwTR.x <= kMax) && (uvwTR.y >= kMin && uvwTR.y <= kMax) && (uvwTR.z >= kMin && uvwTR.z <= kMax))
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangle(vt, clipRectMinMax.z, clipRectMinMax.y, uvwTR);
            }
            if ((uvwBL.x >= kMin && uvwBL.x <= kMax) && (uvwBL.y >= kMin && uvwBL.y <= kMax) && (uvwBL.z >= kMin && uvwBL.z <= kMax))
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangle(vt, clipRectMinMax.x, clipRectMinMax.w, uvwBL);
            }
            if ((uvwBR.x >= kMin && uvwBR.x <= kMax) && (uvwBR.y >= kMin && uvwBR.y <= kMax) && (uvwBR.z >= kMin && uvwBR.z <= kMax))
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangle(vt, clipRectMinMax.z, clipRectMinMax.w, uvwBR);
            }

            // Next, test triangle edges against rect sides (12 tests)
            float t;

            t = IntersectSegments(vt[0].position.x, vt[0].position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y); // Edge 1 against top side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 0, 1, t);
            }

            t = IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y); // Edge 2 against top side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 1, 2, t);
            }

            t = IntersectSegments(vt[2].position.x, vt[2].position.y, vt[0].position.x, vt[0].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y); // Edge 3 against top side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 2, 0, t);
            }


            t = IntersectSegments(vt[0].position.x, vt[0].position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w); // Edge 1 against right side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 0, 1, t);
            }

            t = IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w); // Edge 2 against right side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 1, 2, t);
            }

            t = IntersectSegments(vt[2].position.x, vt[2].position.y, vt[0].position.x, vt[0].position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w); // Edge 3 against right side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 2, 0, t);
            }

            t = IntersectSegments(vt[0].position.x, vt[0].position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w); // Edge 1 against bottom side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 0, 1, t);
            }

            t = IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w); // Edge 2 against bottom side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 1, 2, t);
            }

            t = IntersectSegments(vt[2].position.x, vt[2].position.y, vt[0].position.x, vt[0].position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w); // Edge 3 against bottom side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 2, 0, t);
            }

            t = IntersectSegments(vt[0].position.x, vt[0].position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w); // Edge 1 against left side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 0, 1, t);
            }

            t = IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w); // Edge 2 against left side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 1, 2, t);
            }

            t = IntersectSegments(vt[2].position.x, vt[2].position.y, vt[0].position.x, vt[0].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w); // Edge 3 against left side
            if (t != float.MaxValue)
            {
                newVerts[newVertsCount++] = InterpolateVertexInTriangleEdge(vt, 2, 0, t);
            }

            if (newVertsCount == 0)
            {
                return; // This should be rare. It means the bounding box test intersected but the accurate test found no intersection. It's ok.
            }
            // The first added vertex will be our anchor for the fan

            // All vertices involved in the result are accumulated in newVerts. Calculate angles of vertices with regards to the first vertex to sort against.
            float *vertAngles = stackalloc float[newVertsCount];

            vertAngles[0] = 0; // Doesn't matter, unused
            const float k2PI = Mathf.PI * 2.0f;

            for (int i = 1; i < newVertsCount; i++)
            {
                vertAngles[i] = Mathf.Atan2(newVerts[i].position.y - newVerts[0].position.y, newVerts[i].position.x - newVerts[0].position.x);
                if (vertAngles[i] < 0.0f)
                {
                    vertAngles[i] += k2PI;
                }
            }

            // Sort vertices in angle order
            int *sortedVerts = stackalloc int[newVertsCount];

            sortedVerts[0] = 0;
            uint addedFlag = 0; // Bit field for each vertex, max 32.. definitely enough

            for (int i = 1; i < newVertsCount; i++)
            {
                int   minIndex = -1;
                float minAngle = float.MaxValue;
                for (int j = 1; j < newVertsCount; j++)
                {
                    if (((addedFlag & (1 << j)) == 0) && (vertAngles[j] < minAngle))
                    {
                        minAngle = vertAngles[j];
                        minIndex = j;
                    }
                }
                sortedVerts[i] = minIndex;
                addedFlag      = addedFlag | (1U << minIndex);
            }

            // Register new vertices
            UInt16 newVerticesIndex = nextNewVertex;

            for (int i = 0; i < newVertsCount; i++)
            {
                mwd.m_Vertices[newVerticesIndex + i] = newVerts[sortedVerts[i]];
            }
            nextNewVertex += (UInt16)newVertsCount;

            // Build a fan, our selection of first edge might be crossing the middle of the tessellated polygon
            // so the fan is not starting from side to side, but from middle to middle. This is why wrapAroundHandled is there.
            int     newTriCount       = newVertsCount - 2;
            bool    wrapAroundHandled = false;
            Vector3 p0 = mwd.m_Vertices[newVerticesIndex].position;

            for (int i = 0; i < newTriCount; i++)
            {
                int index1 = newVerticesIndex + i + 1;
                int index2 = newVerticesIndex + i + 2;
                if (!wrapAroundHandled)
                {
                    float angle1 = vertAngles[sortedVerts[i + 1]];
                    float angle2 = vertAngles[sortedVerts[i + 2]];
                    if (angle2 - angle1 >= Mathf.PI)
                    {
                        index1            = newVerticesIndex + 1;
                        index2            = newVerticesIndex + newVertsCount - 1;
                        wrapAroundHandled = true;
                    }
                }

                Vector3 p1 = mwd.m_Vertices[index1].position;
                Vector3 p2 = mwd.m_Vertices[index2].position;
                Vector3 c  = Vector3.Cross(p1 - p0, p2 - p0);

                // Add the indices in the right winding order
                mwd.SetNextIndex((UInt16)(newVerticesIndex));
                if (c.z < 0)
                {
                    mwd.SetNextIndex((UInt16)index1);
                    mwd.SetNextIndex((UInt16)index2);
                }
                else
                {
                    mwd.SetNextIndex((UInt16)index2);
                    mwd.SetNextIndex((UInt16)index1);
                }
            } // For each new triangle
        }
        unsafe static void RectClip(Vertex[] vertices, UInt16[] indices, Vector4 clipRectMinMax, MeshWriteData mwd, ClipCounts cc, ref int newVertexCount)
        {
            int lastEffectiveClippedIndex = cc.lastClippedIndex;

            if (cc.firstDegenerateIndex != -1 && cc.firstDegenerateIndex < lastEffectiveClippedIndex)
            {
                lastEffectiveClippedIndex = cc.firstDegenerateIndex;
            }
            UInt16 nextNewVertex = (UInt16)vertices.Length;

            // Copy all non-clipped indices
            for (int i = 0; i < cc.firstClippedIndex; i++)
            {
                mwd.SetNextIndex(indices[i]);
            }

            // Clipped triangles
            UInt16 *it = stackalloc UInt16[3]; // Indices of the triangle
            Vertex *vt = stackalloc Vertex[3]; // Vertices of the triangle

            for (int i = cc.firstClippedIndex; i < lastEffectiveClippedIndex; i += 3)
            {
                it[0] = indices[i];
                it[1] = indices[i + 1];
                it[2] = indices[i + 2];
                vt[0] = vertices[it[0]];
                vt[1] = vertices[it[1]];
                vt[2] = vertices[it[2]];

                Vector4 triRectMinMax;
                triRectMinMax.x = vt[0].position.x < vt[1].position.x ? vt[0].position.x : vt[1].position.x;
                triRectMinMax.x = triRectMinMax.x < vt[2].position.x ? triRectMinMax.x : vt[2].position.x;
                triRectMinMax.y = vt[0].position.y < vt[1].position.y ? vt[0].position.y : vt[1].position.y;
                triRectMinMax.y = triRectMinMax.y < vt[2].position.y ? triRectMinMax.y : vt[2].position.y;
                triRectMinMax.z = vt[0].position.x > vt[1].position.x ? vt[0].position.x : vt[1].position.x;
                triRectMinMax.z = triRectMinMax.z > vt[2].position.x ? triRectMinMax.z : vt[2].position.x;
                triRectMinMax.w = vt[0].position.y > vt[1].position.y ? vt[0].position.y : vt[1].position.y;
                triRectMinMax.w = triRectMinMax.w > vt[2].position.y ? triRectMinMax.w : vt[2].position.y;

                // Test if the rect is outside (degenerate triangle), or totally inside (not clipped),
                // else it is _probably_ clipped, but can still be either degenerate or unclipped
                if ((triRectMinMax.x >= clipRectMinMax.x) &&
                    (triRectMinMax.z <= clipRectMinMax.z) &&
                    (triRectMinMax.y >= clipRectMinMax.y) &&
                    (triRectMinMax.w <= clipRectMinMax.w))
                {
                    // Clean triangle
                    mwd.SetNextIndex(it[0]);
                    mwd.SetNextIndex(it[1]);
                    mwd.SetNextIndex(it[2]);
                    continue;
                }
                if ((triRectMinMax.x >= clipRectMinMax.z) ||
                    (triRectMinMax.z <= clipRectMinMax.x) ||
                    (triRectMinMax.y >= clipRectMinMax.w) ||
                    (triRectMinMax.w <= clipRectMinMax.y))
                {
                    continue;  // Skip this triangle. It is fully clipped.
                }

                // The full shabang
                RectClipTriangle(vt, it, clipRectMinMax, mwd, ref nextNewVertex);
            }

            // Copy remaining non-clipped indices
            int indexCount = indices.Length;

            for (int i = cc.lastClippedIndex + 1; i < indexCount; i++)
            {
                mwd.SetNextIndex(indices[i]);
            }

            newVertexCount = nextNewVertex;
            mwd.m_Vertices = mwd.m_Vertices.Slice(0, newVertexCount);
            mwd.m_Indices  = mwd.m_Indices.Slice(0, mwd.currentIndex);
        }
        private unsafe static void RectClipTriangle(Vertex *vt, ushort *it, Vector4 clipRectMinMax, MeshWriteData mwd, ref ushort nextNewVertex)
        {
            Vertex *ptr = stackalloc Vertex[13];
            int     num = 0;

            for (int i = 0; i < 3; i++)
            {
                bool flag = vt[i].position.x >= clipRectMinMax.x && vt[i].position.y >= clipRectMinMax.y && vt[i].position.x <= clipRectMinMax.z && vt[i].position.y <= clipRectMinMax.w;
                if (flag)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = vt[i];
                }
            }
            bool flag2 = num == 3;

            if (flag2)
            {
                mwd.SetNextIndex(*it);
                mwd.SetNextIndex(it[1]);
                mwd.SetNextIndex(it[2]);
            }
            else
            {
                Vector3 vertexBaryCentricCoordinates  = MeshBuilder.GetVertexBaryCentricCoordinates(vt, clipRectMinMax.x, clipRectMinMax.y);
                Vector3 vertexBaryCentricCoordinates2 = MeshBuilder.GetVertexBaryCentricCoordinates(vt, clipRectMinMax.z, clipRectMinMax.y);
                Vector3 vertexBaryCentricCoordinates3 = MeshBuilder.GetVertexBaryCentricCoordinates(vt, clipRectMinMax.x, clipRectMinMax.w);
                Vector3 vertexBaryCentricCoordinates4 = MeshBuilder.GetVertexBaryCentricCoordinates(vt, clipRectMinMax.z, clipRectMinMax.w);
                bool    flag3 = vertexBaryCentricCoordinates.x >= -1E-07f && vertexBaryCentricCoordinates.x <= 1.00000012f && vertexBaryCentricCoordinates.y >= -1E-07f && vertexBaryCentricCoordinates.y <= 1.00000012f && vertexBaryCentricCoordinates.z >= -1E-07f && vertexBaryCentricCoordinates.z <= 1.00000012f;
                if (flag3)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangle(vt, clipRectMinMax.x, clipRectMinMax.y, vertexBaryCentricCoordinates);
                }
                bool flag4 = vertexBaryCentricCoordinates2.x >= -1E-07f && vertexBaryCentricCoordinates2.x <= 1.00000012f && vertexBaryCentricCoordinates2.y >= -1E-07f && vertexBaryCentricCoordinates2.y <= 1.00000012f && vertexBaryCentricCoordinates2.z >= -1E-07f && vertexBaryCentricCoordinates2.z <= 1.00000012f;
                if (flag4)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangle(vt, clipRectMinMax.z, clipRectMinMax.y, vertexBaryCentricCoordinates2);
                }
                bool flag5 = vertexBaryCentricCoordinates3.x >= -1E-07f && vertexBaryCentricCoordinates3.x <= 1.00000012f && vertexBaryCentricCoordinates3.y >= -1E-07f && vertexBaryCentricCoordinates3.y <= 1.00000012f && vertexBaryCentricCoordinates3.z >= -1E-07f && vertexBaryCentricCoordinates3.z <= 1.00000012f;
                if (flag5)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangle(vt, clipRectMinMax.x, clipRectMinMax.w, vertexBaryCentricCoordinates3);
                }
                bool flag6 = vertexBaryCentricCoordinates4.x >= -1E-07f && vertexBaryCentricCoordinates4.x <= 1.00000012f && vertexBaryCentricCoordinates4.y >= -1E-07f && vertexBaryCentricCoordinates4.y <= 1.00000012f && vertexBaryCentricCoordinates4.z >= -1E-07f && vertexBaryCentricCoordinates4.z <= 1.00000012f;
                if (flag6)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangle(vt, clipRectMinMax.z, clipRectMinMax.w, vertexBaryCentricCoordinates4);
                }
                float num2  = MeshBuilder.IntersectSegments(vt->position.x, vt->position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y);
                bool  flag7 = num2 != 3.40282347E+38f;
                if (flag7)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 0, 1, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y);
                bool flag8 = num2 != 3.40282347E+38f;
                if (flag8)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 1, 2, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[2].position.x, vt[2].position.y, vt->position.x, vt->position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.y);
                bool flag9 = num2 != 3.40282347E+38f;
                if (flag9)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 2, 0, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt->position.x, vt->position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w);
                bool flag10 = num2 != 3.40282347E+38f;
                if (flag10)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 0, 1, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w);
                bool flag11 = num2 != 3.40282347E+38f;
                if (flag11)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 1, 2, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[2].position.x, vt[2].position.y, vt->position.x, vt->position.y, clipRectMinMax.z, clipRectMinMax.y, clipRectMinMax.z, clipRectMinMax.w);
                bool flag12 = num2 != 3.40282347E+38f;
                if (flag12)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 2, 0, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt->position.x, vt->position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w);
                bool flag13 = num2 != 3.40282347E+38f;
                if (flag13)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 0, 1, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w);
                bool flag14 = num2 != 3.40282347E+38f;
                if (flag14)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 1, 2, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[2].position.x, vt[2].position.y, vt->position.x, vt->position.y, clipRectMinMax.x, clipRectMinMax.w, clipRectMinMax.z, clipRectMinMax.w);
                bool flag15 = num2 != 3.40282347E+38f;
                if (flag15)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 2, 0, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt->position.x, vt->position.y, vt[1].position.x, vt[1].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w);
                bool flag16 = num2 != 3.40282347E+38f;
                if (flag16)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 0, 1, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[1].position.x, vt[1].position.y, vt[2].position.x, vt[2].position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w);
                bool flag17 = num2 != 3.40282347E+38f;
                if (flag17)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 1, 2, num2);
                }
                num2 = MeshBuilder.IntersectSegments(vt[2].position.x, vt[2].position.y, vt->position.x, vt->position.y, clipRectMinMax.x, clipRectMinMax.y, clipRectMinMax.x, clipRectMinMax.w);
                bool flag18 = num2 != 3.40282347E+38f;
                if (flag18)
                {
                    ptr[(IntPtr)(num++) * (IntPtr)sizeof(Vertex)] = MeshBuilder.InterpolateVertexInTriangleEdge(vt, 2, 0, num2);
                }
                bool flag19 = num == 0;
                if (!flag19)
                {
                    float *ptr2 = stackalloc float[num];
                    *      ptr2 = 0f;
                    for (int j = 1; j < num; j++)
                    {
                        ptr2[j] = Mathf.Atan2(ptr[j].position.y - ptr->position.y, ptr[j].position.x - ptr->position.x);
                        bool flag20 = ptr2[j] < 0f;
                        if (flag20)
                        {
                            ptr2[j] += 6.28318548f;
                        }
                    }
                    int *ptr3 = stackalloc int[num];
                    *    ptr3 = 0;
                    uint num3 = 0u;
                    for (int k = 1; k < num; k++)
                    {
                        int   num4 = -1;
                        float num5 = 3.40282347E+38f;
                        for (int l = 1; l < num; l++)
                        {
                            bool flag21 = ((ulong)num3 & (ulong)(1L << (l & 31))) == 0uL && ptr2[l] < num5;
                            if (flag21)
                            {
                                num5 = ptr2[l];
                                num4 = l;
                            }
                        }
                        ptr3[k] = num4;
                        num3   |= 1u << num4;
                    }
                    ushort num6 = nextNewVertex;
                    for (int m = 0; m < num; m++)
                    {
                        mwd.m_Vertices[(int)num6 + m] = ptr[ptr3[m]];
                    }
                    nextNewVertex += (ushort)num;
                    int     num7     = num - 2;
                    bool    flag22   = false;
                    Vector3 position = mwd.m_Vertices[(int)num6].position;
                    for (int n = 0; n < num7; n++)
                    {
                        int  num8   = (int)num6 + n + 1;
                        int  num9   = (int)num6 + n + 2;
                        bool flag23 = !flag22;
                        if (flag23)
                        {
                            float num10  = ptr2[ptr3[n + 1]];
                            float num11  = ptr2[ptr3[n + 2]];
                            bool  flag24 = num11 - num10 >= 3.14159274f;
                            if (flag24)
                            {
                                num8   = (int)(num6 + 1);
                                num9   = (int)num6 + num - 1;
                                flag22 = true;
                            }
                        }
                        Vector3 position2 = mwd.m_Vertices[num8].position;
                        Vector3 position3 = mwd.m_Vertices[num9].position;
                        Vector3 vector    = Vector3.Cross(position2 - position, position3 - position);
                        mwd.SetNextIndex(num6);
                        bool flag25 = vector.z < 0f;
                        if (flag25)
                        {
                            mwd.SetNextIndex((ushort)num9);
                            mwd.SetNextIndex((ushort)num8);
                        }
                        else
                        {
                            mwd.SetNextIndex((ushort)num8);
                            mwd.SetNextIndex((ushort)num9);
                        }
                    }
                }
            }
        }
        private unsafe static void RectClip(Vertex[] vertices, ushort[] indices, Vector4 clipRectMinMax, MeshWriteData mwd, MeshBuilder.ClipCounts cc, ref int newVertexCount)
        {
            int  num  = cc.lastClippedIndex;
            bool flag = cc.firstDegenerateIndex != -1 && cc.firstDegenerateIndex < num;

            if (flag)
            {
                num = cc.firstDegenerateIndex;
            }
            ushort num2 = (ushort)vertices.Length;

            for (int i = 0; i < cc.firstClippedIndex; i++)
            {
                mwd.SetNextIndex(indices[i]);
            }
            ushort *ptr  = stackalloc ushort[3];
            Vertex *ptr2 = stackalloc Vertex[3];

            for (int j = cc.firstClippedIndex; j < num; j += 3)
            {
                *ptr = indices[j];
                ptr[1] = indices[j + 1];
                ptr[2] = indices[j + 2];
                *ptr2 = vertices[(int)(*ptr)];
                ptr2[1] = vertices[(int)ptr[1]];
                ptr2[2] = vertices[(int)ptr[2]];
                Vector4 vector;
                vector.x = ((ptr2->position.x < ptr2[1].position.x) ? ptr2->position.x : ptr2[1].position.x);
                vector.x = ((vector.x < ptr2[2].position.x) ? vector.x : ptr2[2].position.x);
                vector.y = ((ptr2->position.y < ptr2[1].position.y) ? ptr2->position.y : ptr2[1].position.y);
                vector.y = ((vector.y < ptr2[2].position.y) ? vector.y : ptr2[2].position.y);
                vector.z = ((ptr2->position.x > ptr2[1].position.x) ? ptr2->position.x : ptr2[1].position.x);
                vector.z = ((vector.z > ptr2[2].position.x) ? vector.z : ptr2[2].position.x);
                vector.w = ((ptr2->position.y > ptr2[1].position.y) ? ptr2->position.y : ptr2[1].position.y);
                vector.w = ((vector.w > ptr2[2].position.y) ? vector.w : ptr2[2].position.y);
                bool flag2 = vector.x >= clipRectMinMax.x && vector.z <= clipRectMinMax.z && vector.y >= clipRectMinMax.y && vector.w <= clipRectMinMax.w;
                if (flag2)
                {
                    mwd.SetNextIndex(*ptr);
                    mwd.SetNextIndex(ptr[1]);
                    mwd.SetNextIndex(ptr[2]);
                }
                else
                {
                    bool flag3 = vector.x >= clipRectMinMax.z || vector.z <= clipRectMinMax.x || vector.y >= clipRectMinMax.w || vector.w <= clipRectMinMax.y;
                    if (!flag3)
                    {
                        MeshBuilder.RectClipTriangle(ptr2, ptr, clipRectMinMax, mwd, ref num2);
                    }
                }
            }
            int num3 = indices.Length;

            for (int k = cc.lastClippedIndex + 1; k < num3; k++)
            {
                mwd.SetNextIndex(indices[k]);
            }
            newVertexCount = (int)num2;
            mwd.m_Vertices = mwd.m_Vertices.Slice(0, newVertexCount);
            mwd.m_Indices  = mwd.m_Indices.Slice(0, mwd.currentIndex);
        }