static StackObject *GetDistanceToPoint_11(ILIntepreter __intp, StackObject *__esp, IList <object> __mStack, CLRMethod __method, bool isNewObj)
        {
            CSHotFix.Runtime.Enviorment.AppDomain __domain = __intp.AppDomain;
            StackObject *ptr_of_this_method;
            StackObject *__ret = ILIntepreter.Minus(__esp, 2);

            ptr_of_this_method = ILIntepreter.Minus(__esp, 1);
            UnityEngine.Vector3 @point = (UnityEngine.Vector3) typeof(UnityEngine.Vector3).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));
            __intp.Free(ptr_of_this_method);

            ptr_of_this_method = ILIntepreter.Minus(__esp, 2);
            ptr_of_this_method = ILIntepreter.GetObjectAndResolveReference(ptr_of_this_method);
            UnityEngine.Plane instance_of_this_method = (UnityEngine.Plane) typeof(UnityEngine.Plane).CheckCLRTypes(StackObject.ToObject(ptr_of_this_method, __domain, __mStack));

            var result_of_this_method = instance_of_this_method.GetDistanceToPoint(@point);

            ptr_of_this_method = ILIntepreter.Minus(__esp, 2);
            WriteBackInstance(__domain, ptr_of_this_method, __mStack, ref instance_of_this_method);

            __intp.Free(ptr_of_this_method);
            __ret->ObjectType       = ObjectTypes.Float;
            *(float *)&__ret->Value = result_of_this_method;
            return(__ret + 1);
        }
Пример #2
0
        static void CreateExtrudedSubMesh(CSGBrushSubMesh subMesh, Vector3[] sideVertices, Vector3 extrusion, int[] segmentDescriptionIndices, int[] segmentAssetIndices, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions)
        {
            const float distanceEpsilon = 0.0000001f;

            for (int i = sideVertices.Length - 1; i >= 0; i--)
            {
                var j         = (i - 1 + sideVertices.Length) % sideVertices.Length;
                var magnitude = (sideVertices[j] - sideVertices[i]).sqrMagnitude;
                if (magnitude < distanceEpsilon)
                {
                    // TODO: improve on this
                    var tmp = sideVertices.ToList();
                    tmp.RemoveAt(i);
                    sideVertices = tmp.ToArray();
                }
            }

            var segments        = sideVertices.Length;
            var isSegmentConvex = new sbyte[segments];
            var edgeIndices     = new int[segments * 2];
            var vertices        = new Vector3[segments * 2];

            var polygonCount = 2;
            var edgeOffset   = segments + segments;

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                //			      t0
                //	 ------>   ------->   ----->
                //        v0 *          * v1
                //	 <-----    <-------   <-----
                //			^ |   e2   ^ |
                //          | |        | |
                //	   q1 p0| |e3 q2 e5| |n0 q3
                //          | |        | |
                //			| v   e4   | v
                //	 ------>   ------->   ----->
                //        v3 *          * v2
                //	 <-----    <-------   <-----
                //			      b0
                //

                var v0 = sideVertices[p];
                var v1 = sideVertices[e];
                var v2 = sideVertices[e] + extrusion;
                var v3 = sideVertices[p] + extrusion;

                vertices[p]            = v0;
                vertices[e]            = v1;
                vertices[e + segments] = v2;
                vertices[p + segments] = v3;

                var plane = new Plane(v0, v1, v3);
                var dist  = plane.GetDistanceToPoint(v2);

                if (UnityEngine.Mathf.Abs(dist) < 0.001f)
                {
                    isSegmentConvex[n] = 0;
                }
                else
                {
                    isSegmentConvex[n] = (sbyte)UnityEngine.Mathf.Sign(dist);
                }

                edgeIndices[(n * 2) + 0] = edgeOffset + 1;

                if (isSegmentConvex[n] == 0)
                {
                    polygonCount++;
                    edgeOffset += 4;
                }
                else
                {
                    polygonCount += 2;
                    edgeOffset   += 6;
                }
                edgeIndices[(n * 2) + 1] = edgeOffset - 1;
            }

            var polygons = new CSGBrushSubMesh.Polygon[polygonCount];

            var descriptionIndex0   = (segmentDescriptionIndices == null) ? 0 : (segmentDescriptionIndices[0]);
            var descriptionIndex1   = (segmentDescriptionIndices == null) ? 1 : (segmentDescriptionIndices[1]);
            var assetIndex0         = (segmentAssetIndices == null) ? 0 : (segmentAssetIndices[0]);
            var assetIndex1         = (segmentAssetIndices == null) ? 1 : (segmentAssetIndices[1]);
            var surfaceDescription0 = surfaceDescriptions[descriptionIndex0];
            var surfaceDescription1 = surfaceDescriptions[descriptionIndex1];
            var surfaceAsset0       = surfaceAssets[assetIndex0];
            var surfaceAsset1       = surfaceAssets[assetIndex1];

            polygons[0] = new CSGBrushSubMesh.Polygon {
                surfaceID = 0, firstEdge = 0, edgeCount = segments, description = surfaceDescription0, surfaceAsset = surfaceAsset0
            };
            polygons[1] = new CSGBrushSubMesh.Polygon {
                surfaceID = 1, firstEdge = segments, edgeCount = segments, description = surfaceDescription1, surfaceAsset = surfaceAsset1
            };

            for (int s = 0, surfaceID = 2; s < segments; s++)
            {
                var descriptionIndex = (segmentDescriptionIndices == null) ? s + 2 : (segmentDescriptionIndices[s + 2]);
                var assetIndex       = (segmentAssetIndices == null) ? 2     : (segmentAssetIndices[s + 2]);
                var firstEdge        = edgeIndices[(s * 2) + 0] - 1;
                if (isSegmentConvex[s] == 0)
                {
                    polygons[surfaceID] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID, firstEdge = firstEdge, edgeCount = 4, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID].description.smoothingGroup = (uint)0;
                    surfaceID++;
                }
                else
                {
                    var smoothingGroup = surfaceID + 1; // TODO: create an unique smoothing group for faceted surfaces that are split in two,
                                                        //			unless there's already a smoothing group for this edge; then use that

                    polygons[surfaceID + 0] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID + 0, firstEdge = firstEdge, edgeCount = 3, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID + 0].description.smoothingGroup = (uint)smoothingGroup;
                    polygons[surfaceID + 1] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID + 1, firstEdge = firstEdge + 3, edgeCount = 3, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID + 1].description.smoothingGroup = (uint)smoothingGroup;
                    surfaceID += 2;
                }
            }

            var halfEdges = new BrushMesh.HalfEdge[edgeOffset];

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                var vi1 = e;
                var vi3 = p + segments;

                var t0 = e;
                var b0 = ((segments - 1) - e) + segments;

                halfEdges[t0] = new BrushMesh.HalfEdge {
                    vertexIndex = vi1, twinIndex = -1
                };
                halfEdges[b0] = new BrushMesh.HalfEdge {
                    vertexIndex = vi3, twinIndex = -1
                };
            }

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                var vi0 = p;
                var vi1 = e;
                var vi2 = e + segments;
                var vi3 = p + segments;

                var t0 = e;
                var b0 = ((segments - 1) - e) + segments;

                var p0 = edgeIndices[(p * 2) + 1];
                var n0 = edgeIndices[(n * 2) + 0];

                if (isSegmentConvex[e] == 0)
                {
                    //			      t0
                    //	 ------>   ------->   ----->
                    //        v0 *          * v1
                    //	 <-----    <-------   <-----
                    //			^ |   e2   ^ |
                    //          | |        | |
                    //	   q1 p0| |e3 q2 e5| |n0 q3
                    //          | |        | |
                    //			| v   e4   | v
                    //	 ------>   ------->   ----->
                    //        v3 *          * v2
                    //	 <-----    <-------   <-----
                    //			      b0
                    //

                    var q2 = edgeIndices[(e * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e4;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };

                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                }
                else
                if (isSegmentConvex[e] == -1)
                {
                    //			        t0
                    //	 ------>   ----------->   ----->
                    //        v0 *              * v1
                    //	 <-----    <-----------   <-----
                    //			^ |     e2   ^ ^ |
                    //          | |        / / | |
                    //          | |    e4/ /   | |
                    //	   q1 p0| |e3   / /  e7| |n0 q3
                    //          | |   / /e5    | |
                    //          | | / /        | |
                    //			| v/v   e6     | v
                    //	 ------>   ----------->   ----->
                    //        v3 *              * v2
                    //	 <-----    <-----------   <-----
                    //			        b0
                    //

                    var q2 = edgeIndices[(e * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;
                    var e6 = q2 + 3;
                    var e7 = q2 + 4;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e6;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = e5
                    };

                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = e4
                    };
                    halfEdges[e6] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[e7] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                }
                else
                if (isSegmentConvex[e] == 1)
                {
                    //			        t0
                    //	 ------>   ----------->   ----->
                    //        v0 *              * v1
                    //	 <-----    <-----------   <-----
                    //			^ |^\   e5     ^ |
                    //          | | \ \        | |
                    //          | |   \ \ e6   | |
                    //	   q1 p0| |e3 e2\ \  e7| |n0 q3
                    //          | |       \ \  | |
                    //          | |        \ \ | |
                    //			| v   e4    \ v| v
                    //	 ------>   ----------->   ----->
                    //        v3 *              * v2
                    //	 <-----    <-----------   <-----
                    //			        b0
                    //

                    var q2 = edgeIndices[(e * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;
                    var e6 = q2 + 3;
                    var e7 = q2 + 4;

                    halfEdges[t0].twinIndex = e5;
                    halfEdges[b0].twinIndex = e4;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = e6
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };

                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e6] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = e2
                    };
                    halfEdges[e7] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                }
            }

            subMesh.Polygons  = polygons;
            subMesh.HalfEdges = halfEdges;
            subMesh.Vertices  = vertices;
            subMesh.CreateOrUpdateBrushMesh();
        }
Пример #3
0
        static bool CreateExtrudedSubMesh(CSGBrushSubMesh subMesh, int segments, int[] segmentDescriptionIndices, int[] segmentAssetIndices, int segmentTopIndex, int segmentBottomIndex, Vector3[] vertices, CSGSurfaceAsset[] surfaceAssets, SurfaceDescription[] surfaceDescriptions)
        {
            if (vertices.Length < 3)
            {
                return(false);
            }

            // TODO: vertex reverse winding when it's not clockwise
            // TODO: handle duplicate vertices, remove them or avoid them being created in the first place (maybe use indices?)

            var segmentTopology = new SegmentTopology[segments];
            var edgeIndices     = new int[segments * 2];

            var polygonCount = 2;
            var edgeOffset   = segments + segments;

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                //			      t0
                //	 ------>   ------->   ----->
                //        v0 *          * v1
                //	 <-----    <-------   <-----
                //			^ |   e2   ^ |
                //          | |        | |
                //	   q1 p0| |e3 q2 e5| |n0 q3
                //          | |        | |
                //			| v   e4   | v
                //	 ------>   ------->   ----->
                //        v3 *          * v2
                //	 <-----    <-------   <-----
                //			      b0
                //
                var v0 = vertices[p];
                var v1 = vertices[e];
                var v2 = vertices[e + segments];
                var v3 = vertices[p + segments];

                var equals03 = (v0 - v3).sqrMagnitude < 0.0001f;
                var equals12 = (v1 - v2).sqrMagnitude < 0.0001f;
                if (equals03)
                {
                    if (equals12)
                    {
                        segmentTopology[n] = SegmentTopology.None;
                    }
                    else
                    {
                        segmentTopology[n] = SegmentTopology.TriangleNegative;
                    }
                }
                else
                if (equals12)
                {
                    segmentTopology[n] = SegmentTopology.TrianglePositive;
                }
                else
                {
                    var plane = new Plane(v0, v1, v3);
                    var dist  = plane.GetDistanceToPoint(v2);
                    if (UnityEngine.Mathf.Abs(dist) < 0.001f)
                    {
                        segmentTopology[n] = SegmentTopology.Quad;
                    }
                    else
                    {
                        segmentTopology[n] = (SegmentTopology)UnityEngine.Mathf.Sign(dist);
                    }
                }

                switch (segmentTopology[n])
                {
                case SegmentTopology.Quad:
                {
                    edgeIndices[(n * 2) + 0] = edgeOffset + 1;
                    polygonCount++;
                    edgeOffset += 4;
                    edgeIndices[(n * 2) + 1] = edgeOffset - 1;
                    break;
                }

                case SegmentTopology.TrianglesNegative:
                case SegmentTopology.TrianglesPositive:
                {
                    edgeIndices[(n * 2) + 0] = edgeOffset + 1;
                    polygonCount            += 2;
                    edgeOffset += 6;
                    edgeIndices[(n * 2) + 1] = edgeOffset - 1;
                    break;
                }

                case SegmentTopology.TriangleNegative:
                case SegmentTopology.TrianglePositive:
                {
                    edgeIndices[(n * 2) + 0] = edgeOffset + 1;
                    polygonCount++;
                    edgeOffset += 3;
                    edgeIndices[(n * 2) + 1] = edgeOffset - 1;
                    break;
                }

                case SegmentTopology.None:
                    edgeIndices[(n * 2) + 0] = 0;
                    edgeIndices[(n * 2) + 1] = 0;
                    break;
                }
            }

            var polygons = new CSGBrushSubMesh.Polygon[polygonCount];

            var surfaceDescription0 = surfaceDescriptions[segmentTopIndex];
            var surfaceDescription1 = surfaceDescriptions[segmentBottomIndex];
            var surfaceAsset0       = surfaceAssets[segmentTopIndex];
            var surfaceAsset1       = surfaceAssets[segmentBottomIndex];

            polygons[0] = new CSGBrushSubMesh.Polygon {
                surfaceID = 0, firstEdge = 0, edgeCount = segments, description = surfaceDescription0, surfaceAsset = surfaceAsset0
            };
            polygons[1] = new CSGBrushSubMesh.Polygon {
                surfaceID = 1, firstEdge = segments, edgeCount = segments, description = surfaceDescription1, surfaceAsset = surfaceAsset1
            };

            for (int s = 0, surfaceID = 2; s < segments; s++)
            {
                var descriptionIndex = (segmentDescriptionIndices == null) ? s + 2 : (segmentDescriptionIndices[s]);
                var assetIndex       = (segmentAssetIndices == null) ? 2 : (segmentAssetIndices[s]);
                var firstEdge        = edgeIndices[(s * 2) + 0] - 1;
                switch (segmentTopology[s])
                {
                case SegmentTopology.Quad:
                {
                    polygons[surfaceID] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID, firstEdge = firstEdge, edgeCount = 4, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID].description.smoothingGroup = (uint)0;
                    surfaceID++;
                    break;
                }

                case SegmentTopology.TrianglesNegative:
                case SegmentTopology.TrianglesPositive:
                {
                    var smoothingGroup = surfaceID + 1;     // TODO: create an unique smoothing group for faceted surfaces that are split in two,
                                                            //			unless there's already a smoothing group for this edge; then use that

                    polygons[surfaceID + 0] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID + 0, firstEdge = firstEdge, edgeCount = 3, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID + 0].description.smoothingGroup = (uint)smoothingGroup;
                    polygons[surfaceID + 1] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID + 1, firstEdge = firstEdge + 3, edgeCount = 3, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID + 1].description.smoothingGroup = (uint)smoothingGroup;
                    surfaceID += 2;
                    break;
                }

                case SegmentTopology.TriangleNegative:
                case SegmentTopology.TrianglePositive:
                {
                    polygons[surfaceID] = new CSGBrushSubMesh.Polygon {
                        surfaceID = surfaceID, firstEdge = firstEdge, edgeCount = 3, description = surfaceDescriptions[descriptionIndex], surfaceAsset = surfaceAssets[assetIndex]
                    };
                    polygons[surfaceID].description.smoothingGroup = (uint)0;
                    surfaceID++;
                    break;
                }

                case SegmentTopology.None:
                {
                    break;
                }
                }
            }

            var halfEdges = new BrushMesh.HalfEdge[edgeOffset];

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                //var vi0 = p;
                var vi1 = e;
                var vi2 = e + segments;
                var vi3 = p + segments;

                var t0 = e;
                var b0 = ((segments - 1) - e) + segments;

                switch (segmentTopology[n])
                {
                case SegmentTopology.None:
                {
                    halfEdges[t0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[b0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = t0
                    };
                    break;
                }

                case SegmentTopology.TrianglePositive:
                {
                    halfEdges[t0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = -1
                    };
                    halfEdges[b0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = -1
                    };
                    break;
                }

                case SegmentTopology.TriangleNegative:
                default:
                {
                    halfEdges[t0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = -1
                    };
                    halfEdges[b0] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = -1
                    };
                    break;
                }
                }
            }

            for (int p = segments - 2, e = segments - 1, n = 0; n < segments; p = e, e = n, n++)
            {
                var vi0 = p;
                var vi1 = e;
                var vi2 = e + segments;
                var vi3 = p + segments;

                var t0 = e;
                var b0 = ((segments - 1) - e) + segments;

                var nn = (n + 1) % segments;

                var p0 = edgeIndices[(e * 2) + 1];
                var n0 = edgeIndices[(nn * 2) + 0];

                switch (segmentTopology[n])
                {
                case SegmentTopology.None:
                {
                    continue;
                }

                case SegmentTopology.Quad:
                {
                    //			      t0
                    //	 ------>   ------->   ----->
                    //        v0 *          * v1
                    //	 <-----    <-------   <-----
                    //			^ |   e2   ^ |
                    //          | |        | |
                    //	   q1 p0| |e3 q2 e5| |n0 q3
                    //          | |        | |
                    //			| v   e4   | v
                    //	 ------>   ------->   ----->
                    //        v3 *          * v2
                    //	 <-----    <-------   <-----
                    //			      b0
                    //

                    var q2 = edgeIndices[(n * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e4;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };

                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                    break;
                }

                case SegmentTopology.TrianglesNegative:
                {
                    //			        t0
                    //	 ------>   ----------->   ----->
                    //        v0 *              * v1
                    //	 <-----    <-----------   <-----
                    //			^ |     e2   ^ ^ |
                    //          | |        / / | |
                    //          | |    e4/ /   | |
                    //	   q1 p0| |e3   / /  e7| |n0 q3
                    //          | |   / /e5    | |
                    //          | | / /        | |
                    //			| v/v   e6     | v
                    //	 ------>   ----------->   ----->
                    //        v3 *              * v2
                    //	 <-----    <-----------   <-----
                    //			        b0
                    //

                    var q2 = edgeIndices[(n * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;
                    var e6 = q2 + 3;
                    var e7 = q2 + 4;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e6;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = e5
                    };

                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = e4
                    };
                    halfEdges[e6] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[e7] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                    break;
                }

                case SegmentTopology.TrianglesPositive:
                {
                    //			        t0
                    //	 ------>   ----------->   ----->
                    //        v0 *              * v1
                    //	 <-----    <-----------   <-----
                    //			^ |^\   e5     ^ |
                    //          | | \ \        | |
                    //          | |   \ \ e6   | |
                    //	   q1 p0| |e3 e2\ \  e7| |n0 q3
                    //          | |       \ \  | |
                    //          | |        \ \ | |
                    //			| v   e4    \ v| v
                    //	 ------>   ----------->   ----->
                    //        v3 *              * v2
                    //	 <-----    <-----------   <-----
                    //			        b0
                    //

                    var q2 = edgeIndices[(n * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;
                    var e5 = q2 + 2;
                    var e6 = q2 + 3;
                    var e7 = q2 + 4;

                    halfEdges[t0].twinIndex = e5;
                    halfEdges[b0].twinIndex = e4;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = e6
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };

                    halfEdges[e5] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e6] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = e2
                    };
                    halfEdges[e7] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                    break;
                }

                case SegmentTopology.TriangleNegative:
                {
                    //			      t0
                    //	 --->                      ------->
                    //       \                  ^ * v1
                    //	 <--- \                /  ^   <-----
                    //	     \ \              / / | |
                    //	      \ \            / /  | |
                    //	       \ \      t0  / /   | |
                    //	        \ \        / /e2  | | n0
                    //           \ \      / /     | |
                    //	          \ \    / / q2 e4| |   q3
                    //             \ \  / /       | |
                    //	            v \/ v   e3   | v
                    //	 ------------>   ------->   ----->
                    //              v3 *          * v2
                    //	 <-----------    <-------   <-----
                    //			            b0
                    //

                    var q2 = edgeIndices[(n * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e3;

                    // vi0 / vi3
                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = t0
                    };

                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi1, twinIndex = n0
                    };
                    break;
                }

                case SegmentTopology.TrianglePositive:
                {
                    //
                    //	 ------->                            ---->
                    //        v0 * \                       ^
                    //	 <-----     \                     /  <---
                    //			^ |^ \                   / /
                    //          | | \ \                 / /
                    //          | |  \ \               / /
                    //          | |   \ \ t0          / /
                    //   q1     | | e2 \ \           / /
                    //          | |     \ \         / /
                    //	      p0| |e3    \ \       / /
                    //          | |   q2  \ \     / /
                    //          | |        \ \   / /
                    //			| v   e4    \ v / v
                    //	 ------>   ----------->    ----->
                    //        v3 *              * v2
                    //	 <-----    <-----------    <-----
                    //			        b0
                    //

                    var q2 = edgeIndices[(n * 2) + 0];
                    var e2 = q2 - 1;
                    var e3 = q2 + 0;
                    var e4 = q2 + 1;

                    halfEdges[t0].twinIndex = e2;
                    halfEdges[b0].twinIndex = e4;

                    halfEdges[e2] = new BrushMesh.HalfEdge {
                        vertexIndex = vi0, twinIndex = t0
                    };
                    halfEdges[e3] = new BrushMesh.HalfEdge {
                        vertexIndex = vi3, twinIndex = p0
                    };

                    // vi1 / vi2
                    halfEdges[e4] = new BrushMesh.HalfEdge {
                        vertexIndex = vi2, twinIndex = b0
                    };
                    break;
                }
                }
            }

            subMesh.Polygons  = polygons;
            subMesh.HalfEdges = halfEdges;
            subMesh.Vertices  = vertices;
            subMesh.CreateOrUpdateBrushMesh();
            return(true);
        }