public static bool GenerateControlMeshFromVertices(ShapePolygon shape2DPolygon,
                                                           Matrix4x4 localToWorld,
                                                           Vector3 direction,
                                                           float height,
                                                           Material capMaterial,
                                                           TexGen capTexgen,
                                                           bool?smooth,
                                                           bool singleSurfaceEnds,                                                                                 //Plane buildPlane,
                                                           out ControlMesh controlMesh,
                                                           out Shape shape)
        {
            if (shape2DPolygon == null)
            {
                controlMesh = null;
                shape       = null;
                return(false);
            }

            var vertices = shape2DPolygon.Vertices;

            if (vertices.Length < 3)
            {
                controlMesh = null;
                shape       = null;
                return(false);
            }
            if (height == 0.0f)
            {
                controlMesh = null;
                shape       = null;
                return(false);
            }

            Vector3 from;
            Vector3 to;

            if (height > 0)
            {
                @from = direction * height;                // buildPlane.normal * height;
                to    = MathConstants.zeroVector3;
            }
            else
            {
                @from = MathConstants.zeroVector3;
                to    = direction * height;               //buildPlane.normal * height;
            }

            var count           = vertices.Length;
            var doubleCount     = (count * 2);
            var extraPoints     = 0;
            var extraEdges      = 0;
            var endsPolygons    = 2;
            var startEdgeOffset = doubleCount;

            if (!singleSurfaceEnds)
            {
                extraPoints      = 2;
                extraEdges       = (4 * count);
                endsPolygons     = doubleCount;
                startEdgeOffset += extraEdges;
            }


            var dstPoints   = new Vector3 [doubleCount + extraPoints];
            var dstEdges    = new HalfEdge[(count * 6) + extraEdges];
            var dstPolygons = new Polygon [count + endsPolygons];

            var center1 = MathConstants.zeroVector3;
            var center2 = MathConstants.zeroVector3;


            for (int i = 0; i < count; i++)
            {
                var point1 = vertices[i];
                var point2 = vertices[(count + i - 1) % count];

                point1 += @from;
                point2 += to;

                // swap y/z to solve texgen issues
                dstPoints[i].x = point1.x;
                dstPoints[i].y = point1.y;
                dstPoints[i].z = point1.z;

                center1 += dstPoints[i];

                dstEdges [i].VertexIndex = (short)i;
                dstEdges [i].HardEdge    = true;

                // swap y/z to solve texgen issues
                dstPoints[i + count].x = point2.x;
                dstPoints[i + count].y = point2.y;
                dstPoints[i + count].z = point2.z;
                center2 += dstPoints[i + count];

                dstEdges [i + count].VertexIndex = (short)(i + count);
                dstEdges [i + count].HardEdge    = true;
            }

            if (!singleSurfaceEnds)
            {
                dstPoints[doubleCount]     = center1 / count;
                dstPoints[doubleCount + 1] = center2 / count;

                int   edge_offset   = doubleCount;
                short polygon_index = (short)count;

                // 'top'
                for (int i = 0, j = count - 1; i < count; j = i, i++)
                {
                    var jm = (j) % count;
                    var im = (i) % count;

                    var edgeOut0 = edge_offset + (jm * 2) + 1;
                    var edgeIn0  = edge_offset + (im * 2) + 0;
                    var edgeOut1 = edge_offset + (im * 2) + 1;

                    dstEdges[edgeIn0].VertexIndex = (short)(doubleCount);
                    dstEdges[edgeIn0].HardEdge    = true;
                    dstEdges[edgeIn0].TwinIndex   = edgeOut1;

                    dstEdges[edgeOut1].VertexIndex = (short)im;
                    dstEdges[edgeOut1].HardEdge    = true;
                    dstEdges[edgeOut1].TwinIndex   = edgeIn0;

                    dstEdges[im].PolygonIndex       = polygon_index;
                    dstEdges[edgeIn0].PolygonIndex  = polygon_index;
                    dstEdges[edgeOut0].PolygonIndex = polygon_index;

                    dstPolygons[polygon_index] = new Polygon(new int[] { im, edgeIn0, edgeOut0 }, polygon_index);
                    polygon_index++;
                }

                edge_offset = doubleCount * 2;
                // 'bottom'
                for (int i = 0, j = count - 1; j >= 0; i = j, j--)
                {
                    var jm = (count + count - j) % count;
                    var im = (count + count - i) % count;

                    var edgeOut0 = edge_offset + (jm * 2) + 1;
                    var edgeIn0  = edge_offset + (im * 2) + 0;
                    var edgeOut1 = edge_offset + (im * 2) + 1;

                    dstEdges[edgeIn0].VertexIndex = (short)(doubleCount + 1);
                    dstEdges[edgeIn0].HardEdge    = true;
                    dstEdges[edgeIn0].TwinIndex   = edgeOut1;

                    dstEdges[edgeOut1].VertexIndex = (short)(im + count);
                    dstEdges[edgeOut1].HardEdge    = true;
                    dstEdges[edgeOut1].TwinIndex   = edgeIn0;

                    dstEdges[im + count].PolygonIndex = polygon_index;
                    dstEdges[edgeIn0].PolygonIndex    = polygon_index;
                    dstEdges[edgeOut0].PolygonIndex   = polygon_index;

                    dstPolygons[polygon_index] = new Polygon(new int[] { im + count, edgeIn0, edgeOut0 }, polygon_index);
                    polygon_index++;
                }
            }
            else
            {
                var polygon0Edges = new int[count];
                var polygon1Edges = new int[count];
                for (var i = 0; i < count; i++)
                {
                    dstEdges [i].PolygonIndex         = (short)(count + 0);
                    dstEdges [i + count].PolygonIndex = (short)(count + 1);
                    polygon0Edges[i] = i;
                    polygon1Edges[count - (i + 1)] = i + count;
                }
                dstPolygons[count + 0] = new Polygon(polygon0Edges, count + 0);
                dstPolygons[count + 1] = new Polygon(polygon1Edges, count + 1);
            }


            for (int v0 = count - 1, v1 = 0; v1 < count; v0 = v1, v1++)
            {
                var polygonIndex = (short)(v1);

                var nextOffset = startEdgeOffset + (((v1 + 1) % count) * 4);
                var currOffset = startEdgeOffset + (((v1)) * 4);
                var prevOffset = startEdgeOffset + (((v1 + count - 1) % count) * 4);

                var nextTwin = nextOffset + 1;
                var prevTwin = prevOffset + 3;

                dstEdges[v1].TwinIndex         = currOffset + 0;
                dstEdges[v1 + count].TwinIndex = currOffset + 2;

                dstEdges[currOffset + 0].PolygonIndex = polygonIndex;
                dstEdges[currOffset + 1].PolygonIndex = polygonIndex;
                dstEdges[currOffset + 2].PolygonIndex = polygonIndex;
                dstEdges[currOffset + 3].PolygonIndex = polygonIndex;

                dstEdges[currOffset + 0].TwinIndex = (v1);
                dstEdges[currOffset + 1].TwinIndex = prevTwin;
                dstEdges[currOffset + 2].TwinIndex = (v1 + count);
                dstEdges[currOffset + 3].TwinIndex = nextTwin;

                dstEdges[currOffset + 0].VertexIndex = (short)(v0);
                dstEdges[currOffset + 1].VertexIndex = (short)(v1 + count);
                dstEdges[currOffset + 2].VertexIndex = (short)(((v1 + 1) % count) + count);
                dstEdges[currOffset + 3].VertexIndex = (short)(v1);

                dstEdges[currOffset + 0].HardEdge = true;
                dstEdges[currOffset + 1].HardEdge = true;
                dstEdges[currOffset + 2].HardEdge = true;
                dstEdges[currOffset + 3].HardEdge = true;

                dstPolygons[polygonIndex] = new Polygon(new [] { currOffset + 0,
                                                                 currOffset + 1,
                                                                 currOffset + 2,
                                                                 currOffset + 3 }, polygonIndex);
            }

            for (int i = 0; i < dstPoints.Length; i++)
            {
                dstPoints[i] = localToWorld.MultiplyPoint(dstPoints[i]);
            }

            controlMesh = new ControlMesh
            {
                Vertices = dstPoints,
                Edges    = dstEdges,
                Polygons = dstPolygons
            };
            controlMesh.SetDirty();

            shape = new Shape
            {
                Materials   = new Material[dstPolygons.Length],
                Surfaces    = new Surface[dstPolygons.Length],
                TexGenFlags = new TexGenFlags[dstPolygons.Length],
                TexGens     = new TexGen[dstPolygons.Length]
            };


            var smoothinggroup = (smooth.HasValue && smooth.Value) ? SurfaceUtility.FindUnusedSmoothingGroupIndex() : 0;


            var containedMaterialCount = 0;

            if (shape2DPolygon.EdgeMaterials != null &&
                shape2DPolygon.EdgeTexgens != null /* &&
                                                    * shape2DPolygon.edgeTexgenFlags != null*/)
            {
                containedMaterialCount = Mathf.Min(shape2DPolygon.EdgeMaterials.Length,
                                                   shape2DPolygon.EdgeTexgens.Length /*,
                                                                                      *                        shape2DPolygon.edgeTexgenFlags.Length*/);
            }

            if (!capMaterial)
            {
                capMaterial = CSGSettings.DefaultMaterial;
                capTexgen   = new TexGen(-1);
            }

            for (var i = 0; i < dstPolygons.Length; i++)
            {
                if (i < containedMaterialCount)
                {
                    //shape.TexGenFlags[i] = shape2DPolygon.edgeTexgenFlags[i];
                    shape.Materials  [i]             = shape2DPolygon.EdgeMaterials[i];
                    shape.TexGens    [i]             = shape2DPolygon.EdgeTexgens[i];
                    shape.Surfaces   [i].TexGenIndex = i;
                    shape.TexGens[i].MaterialIndex   = -1;
                }
                else
                {
                    shape.Materials[i] = capMaterial;
                    shape.TexGens[i]   = capTexgen;
                    //shape.TexGenFlags[i]			= TexGenFlags.None;
                    shape.Surfaces[i].TexGenIndex  = i;
                    shape.TexGens[i].MaterialIndex = -1;
                }
                if (smooth.HasValue)
                {
                    if (i < count)
                    {
                        shape.TexGens[i].SmoothingGroup = smoothinggroup;
                    }
                    else
                    {
                        shape.TexGens[i].SmoothingGroup = 0;
                    }
                }
            }

            for (var s = 0; s < dstPolygons.Length; s++)
            {
                var normal = shape.Surfaces[s].Plane.normal;
                shape.Surfaces[s].Plane = GeometryUtility.CalcPolygonPlane(controlMesh, (short)s);
                Vector3 tangent, binormal;
                GeometryUtility.CalculateTangents(normal, out tangent, out binormal);
                //var tangent		= Vector3.Cross(GeometryUtility.CalculateTangent(normal), normal).normalized;
                //var binormal	= Vector3.Cross(normal, tangent);
                shape.Surfaces[s].Tangent     = tangent;
                shape.Surfaces[s].BiNormal    = binormal;
                shape.Surfaces[s].TexGenIndex = s;
            }

            controlMesh.IsValid = ControlMeshUtility.Validate(controlMesh, shape);
            if (controlMesh.IsValid)
            {
                return(true);
            }

            controlMesh = null;
            shape       = null;
            return(false);
        }