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; } }
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); }