using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.ProBuilder;
using System;
namespace UnityEngine.ProBuilder.MeshOperations
{
    /// 
    /// Functions for appending elements to meshes.
    /// 
    public static class AppendElements
    {
        /// 
        /// Append a new face to the ProBuilderMesh.
        /// 
        /// The mesh target.
        /// The new vertex positions to add.
        /// The new colors to add (must match positions length).
        /// The new uvs to add (must match positions length).
        /// A face with the new triangle indexes. The indexes should be 0 indexed.
        /// 
        /// The new face as referenced on the mesh.
        internal static Face AppendFace(
			this ProBuilderMesh mesh,
			Vector3[] positions,
			Color[] colors,
			Vector2[] uv0s,
			Vector4[] uv2s,
			Vector4[] uv3s,
            Face face,
			int[] common)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (positions == null)
                throw new ArgumentNullException("positions");
            if (face == null)
                throw new ArgumentNullException("face");
            int faceVertexCount = positions.Length;
            if (common == null)
            {
                common = new int[faceVertexCount];
                for (int i = 0; i < faceVertexCount; i++)
                    common[i] = -1;
            }
            int vertexCount = mesh.vertexCount;
            var mc = mesh.HasArrays(MeshArrays.Color);
            var fc = colors != null;
            var mt0 = mesh.HasArrays(MeshArrays.Texture0);
            var ft0 = uv0s != null;
			var mt2 = mesh.HasArrays(MeshArrays.Texture2);
            var ft2 = uv2s != null;
			var mt3 = mesh.HasArrays(MeshArrays.Texture3);
            var ft3 = uv3s != null;
            Vector3[] newPositions = new Vector3[vertexCount + faceVertexCount];
            Color[] newColors = (mc || fc) ? new Color[vertexCount + faceVertexCount] : null;
            Vector2[] newTexture0s = (mt0 || ft0) ? new Vector2[vertexCount + faceVertexCount] : null;
            List newTexture2s = (mt2 || ft2) ? new List() : null;
            List newTexture3s = (mt3 || ft3) ? new List() : null;
            List faces = new List(mesh.facesInternal);
            Array.Copy(mesh.positionsInternal, 0, newPositions, 0, vertexCount);
            Array.Copy(positions, 0, newPositions, vertexCount, faceVertexCount);
            if (mc || fc)
            {
                Array.Copy(mc ? mesh.colorsInternal : ArrayUtility.Fill(Color.white, vertexCount), 0, newColors, 0,
                    vertexCount);
                Array.Copy(fc ? colors : ArrayUtility.Fill(Color.white, faceVertexCount), 0, newColors, vertexCount,
                    colors.Length);
            }
            if (mt0 || ft0)
            {
                Array.Copy(mt0 ? mesh.texturesInternal : ArrayUtility.Fill(Vector2.zero, vertexCount), 0, newTexture0s, 0,
                    vertexCount);
                Array.Copy(ft0 ? uv0s : ArrayUtility.Fill(Vector2.zero, faceVertexCount), 0, newTexture0s,
                    mesh.texturesInternal.Length, faceVertexCount);
            }
			if (mt2 || ft2)
            {
				newTexture2s.AddRange(mt2 ? mesh.textures2Internal : new Vector4[vertexCount].ToList());
				newTexture2s.AddRange(ft2 ? uv2s : new Vector4[faceVertexCount]);
            }
			if (mt3 || ft3)
            {
				newTexture3s.AddRange(mt3 ? mesh.textures3Internal : new Vector4[vertexCount].ToList());
				newTexture3s.AddRange(ft3 ? uv3s : new Vector4[faceVertexCount]);
            }
            face.ShiftIndexesToZero();
            face.ShiftIndexes(vertexCount);
            faces.Add(face);
            for (int i = 0; i < common.Length; i++)
            {
                if (common[i] < 0)
                    mesh.AddSharedVertex(new SharedVertex(new int[] {i + vertexCount}));
                else
                    mesh.AddToSharedVertex(common[i], i + vertexCount);
            }
            mesh.positions = newPositions;
            mesh.colors = newColors;
            mesh.textures = newTexture0s;
            mesh.faces = faces;
			mesh.textures2Internal = newTexture2s;
			mesh.textures3Internal = newTexture3s;
            return face;
        }
        /// 
        /// Append a group of new faces to the mesh. Significantly faster than calling AppendFace multiple times.
        /// 
        /// The source mesh to append new faces to.
        /// An array of position arrays, where indexes correspond to the appendedFaces parameter.
        /// An array of colors arrays, where indexes correspond to the appendedFaces parameter.
        /// An array of uvs arrays, where indexes correspond to the appendedFaces parameter.
        /// An array of faces arrays, which contain the triangle winding information for each new face. Face index values are 0 indexed.
        /// An optional mapping of each new vertex's common index. Common index refers to a triangle's index in the @"UnityEngine.ProBuilder.ProBuilderMesh.sharedIndexes" array. If this value is provided, it must contain entries for each vertex position. Ex, if there are 4 vertices in this face, there must be shared index entries for { 0, 1, 2, 3 }.
        /// An array of the new faces that where successfully appended to the mesh.
        public static Face[] AppendFaces(
            this ProBuilderMesh mesh,
            Vector3[][] positions,
            Color[][] colors,
            Vector2[][] uvs,
            Face[] faces,
            int[][] shared)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (positions == null)
                throw new ArgumentNullException("positions");
            if (colors == null)
                throw new ArgumentNullException("colors");
            if (uvs == null)
                throw new ArgumentNullException("uvs");
            if (faces == null)
                throw new ArgumentNullException("faces");
            var newPositions = new List(mesh.positionsInternal);
            var newColors = new List(mesh.colorsInternal);
            var newTextures = new List(mesh.texturesInternal);
            var newFaces = new List(mesh.facesInternal);
            var lookup = mesh.sharedVertexLookup;
            int vc = mesh.vertexCount;
            for (int i = 0; i < faces.Length; i++)
            {
                newPositions.AddRange(positions[i]);
                newColors.AddRange(colors[i]);
                newTextures.AddRange(uvs[i]);
                faces[i].ShiftIndexesToZero();
                faces[i].ShiftIndexes(vc);
                newFaces.Add(faces[i]);
                if (shared != null && positions[i].Length != shared[i].Length)
                {
                    Debug.LogError("Append Face failed because shared array does not match new vertex array.");
                    return null;
                }
                var hasCommon = shared != null;
                for (int j = 0; j < shared[i].Length; j++)
                    lookup.Add(j + vc, hasCommon ? shared[i][j] : -1);
                vc = newPositions.Count;
            }
            mesh.positions = newPositions;
            mesh.colors = newColors;
            mesh.textures = newTextures;
            mesh.faces = newFaces;
            mesh.SetSharedVertices(lookup);
            return faces;
        }
        /// 
        /// Create a new face connecting existing vertices.
        /// 
        /// The source mesh.
        /// The indexes of the vertices to join with the new polygon.
        /// Are the indexes in an ordered path (false), or not (true)? If indexes are not ordered this function will treat the polygon as a convex shape. Ordered paths will be triangulated allowing concave shapes.
        /// The new face created if the action was successfull, null if action failed.
        public static Face CreatePolygon(this ProBuilderMesh mesh, IList indexes, bool unordered)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal;
            Dictionary lookup = mesh.sharedVertexLookup;
            HashSet common = mesh.GetSharedVertexHandles(indexes);
            List vertices = new List(mesh.GetVertices());
            List appendVertices = new List();
            foreach (int i in common)
            {
                int index = sharedIndexes[i][0];
                appendVertices.Add(new Vertex(vertices[index]));
            }
            FaceRebuildData data = FaceWithVertices(appendVertices, unordered);
            if (data != null)
            {
                data.sharedIndexes = common.ToList();
                List faces = new List(mesh.facesInternal);
                FaceRebuildData.Apply(new FaceRebuildData[] {data}, vertices, faces, lookup, null);
                mesh.SetVertices(vertices);
                mesh.faces = faces;
                mesh.SetSharedVertices(lookup);
                return data.face;
            }
            const string insufficientPoints = "Too Few Unique Points Selected";
            const string badWinding = "Points not ordered correctly";
            Log.Info(unordered ? insufficientPoints : badWinding);
            return null;
        }
        /// 
        /// Create a new face connecting existing vertices.
        /// 
        /// The source mesh.
        /// The indexes of the vertices to join with the new polygon.
        /// A list of index lists defining holes.
        /// The new face created if the action was successful, null if action failed.
        public static Face CreatePolygonWithHole(this ProBuilderMesh mesh, IList indexes, IList> holes)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            SharedVertex[] sharedIndexes = mesh.sharedVerticesInternal;
            Dictionary lookup = mesh.sharedVertexLookup;
            List vertices = new List(mesh.GetVertices());
            HashSet commonVertices = mesh.GetSharedVertexHandles(indexes);
            List appendVertices = new List();
            foreach (int i in commonVertices)
            {
                int index = sharedIndexes[i][0];
                appendVertices.Add(new Vertex(vertices[index]));
            }
            HashSet common = commonVertices;
            List< HashSet > commonHoles = new List>();
            List< List > appendHoles = new List>();
            for (int i = 0; i < holes.Count; i++)
            {
                commonHoles.Add(mesh.GetSharedVertexHandles(holes[i]));
                List currentHole = new List();
                appendHoles.Add(currentHole);
                foreach (int j in commonHoles[i])
                {
                    common.Add(j);
                    int index = sharedIndexes[j][0];
                    currentHole.Add(new Vertex(vertices[index]));
                }
            }
            FaceRebuildData data = FaceWithVerticesAndHole(appendVertices, appendHoles);
            if (data != null)
            {
                data.sharedIndexes = common.ToList();
                List faces = new List(mesh.facesInternal);
                FaceRebuildData.Apply(new FaceRebuildData[] { data }, vertices, faces, lookup, null);
                mesh.SetVertices(vertices);
                mesh.faces = faces;
                mesh.SetSharedVertices(lookup);
                return data.face;
            }
            return null;
        }
        /// 
        /// Create a poly shape from a set of points on a plane. The points must be ordered.
        /// 
        /// The  component to rebuild.
        /// An action result indicating the status of the operation.
        public static ActionResult CreateShapeFromPolygon(this PolyShape poly)
        {
            return poly.mesh.CreateShapeFromPolygon(poly.m_Points, poly.extrude, poly.flipNormals);
        }
        /// 
        /// Clear and refresh mesh in case of failure to create a shape.
        /// 
        /// 
        internal static void ClearAndRefreshMesh(this ProBuilderMesh mesh)
        {
            mesh.Clear();
            mesh.ToMesh();
            mesh.Refresh();
        }
        /// 
        /// Rebuild a mesh from an ordered set of points.
        /// 
        /// The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.
        /// A path of points to triangulate and extrude.
        /// The distance to extrude.
        /// If true the faces will be inverted at creation.
        /// An ActionResult with the status of the operation.
        public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList points,
            float extrude, bool flipNormals)
        {
            return CreateShapeFromPolygon(mesh, points, extrude, flipNormals, null);
        }
        /// 
        /// Rebuild a mesh from an ordered set of points.
        /// 
        /// The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.
        /// A path of points to triangulate and extrude.
        /// The distance to extrude.
        /// If true the faces will be inverted at creation.
        /// This argument is now ignored.
        /// Holes in the polygon.
        /// An ActionResult with the status of the operation.
        [Obsolete("Face.CreateShapeFromPolygon is deprecated as it no longer relies on camera look at.")]
        public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList points,
            float extrude, bool flipNormals, Vector3 cameraLookAt, IList> holePoints = null)
        {
            return CreateShapeFromPolygon(mesh, points, extrude, flipNormals, null);
        }
        /// 
        /// Rebuild a mesh from an ordered set of points.
        /// 
        /// The target mesh. The mesh values will be cleared and repopulated with the shape extruded from points.
        /// A path of points to triangulate and extrude.
        /// The distance to extrude.
        /// If true the faces will be inverted at creation.
        /// Holes in the polygon. If null this will be ignored.
        /// An ActionResult with the status of the operation.
        public static ActionResult CreateShapeFromPolygon(this ProBuilderMesh mesh, IList points,
            float extrude, bool flipNormals, IList> holePoints)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (points == null || points.Count < 3)
            {
                ClearAndRefreshMesh(mesh);
                return new ActionResult(ActionResult.Status.NoChange, "Too Few Points");
            }
            Vector3[] vertices = points.ToArray();
            Vector3[][] holeVertices = null;
            if (holePoints != null && holePoints.Count > 0)
            {
                holeVertices = new Vector3[holePoints.Count][];
                for (int i = 0; i < holePoints.Count; i++)
                {
                    if (holePoints[i] == null || holePoints[i].Count < 3)
                    {
                        ClearAndRefreshMesh(mesh);
                        return new ActionResult(ActionResult.Status.NoChange, "Too Few Points in hole " + i);
                    }
                    holeVertices[i] = holePoints[i].ToArray();
                }
            }
            List triangles;
            Log.PushLogLevel(LogLevel.Error);
            if (Triangulation.TriangulateVertices(vertices, out triangles, holeVertices))
            {
                Vector3[] combinedVertices = null;
                if (holeVertices != null)
                {
                    combinedVertices = new Vector3[vertices.Length + holeVertices.Sum(arr => arr.Length)];
                    Array.Copy(vertices, combinedVertices, vertices.Length);
                    int destinationIndex = vertices.Length;
                    foreach (var hole in holeVertices)
                    {
                        Array.ConstrainedCopy(hole, 0, combinedVertices, destinationIndex, hole.Length);
                        destinationIndex += hole.Length;
                    }
                }
                else
                {
                    combinedVertices = vertices;
                }
                int[] indexes = triangles.ToArray();
                if (Math.PolygonArea(combinedVertices, indexes) < Mathf.Epsilon)
                {
                    ClearAndRefreshMesh(mesh);
                    Log.PopLogLevel();
                    return new ActionResult(ActionResult.Status.Failure, "Polygon Area < Epsilon");
                }
                mesh.Clear();
                mesh.positionsInternal = combinedVertices;
                var newFace = new Face(indexes);
                mesh.facesInternal = new[] {newFace};
                mesh.sharedVerticesInternal = SharedVertex.GetSharedVerticesWithPositions(combinedVertices);
                mesh.InvalidateCaches();
                // check that all points are represented in the triangulation
                if (newFace.distinctIndexesInternal.Length != combinedVertices.Length)
                {
                    ClearAndRefreshMesh(mesh);
                    Log.PopLogLevel();
                    return new ActionResult(ActionResult.Status.Failure, "Triangulation missing points");
                }
                Vector3 nrm = Math.Normal(mesh, mesh.facesInternal[0]);
                nrm = mesh.gameObject.transform.TransformDirection(nrm);
                if ((flipNormals
                    ? Vector3.Dot(mesh.gameObject.transform.up, nrm) > 0f
                    : Vector3.Dot(mesh.gameObject.transform.up, nrm) < 0f))
                {
                    mesh.facesInternal[0].Reverse();
                }
                if (extrude != 0.0f)
                {
                    mesh.DuplicateAndFlip(mesh.facesInternal);
                    mesh.Extrude(new Face[] {(flipNormals ? mesh.facesInternal[1] : mesh.facesInternal[0])},
                        ExtrudeMethod.IndividualFaces, extrude);
                    if ((extrude < 0f && !flipNormals) || (extrude > 0f && flipNormals))
                    {
                        foreach (var face in mesh.facesInternal)
                            face.Reverse();
                    }
                }
                mesh.ToMesh();
                mesh.Refresh();
            }
            else
            {
                // clear mesh instead of showing an invalid one
                ClearAndRefreshMesh(mesh);
                Log.PopLogLevel();
                return new ActionResult(ActionResult.Status.Failure, "Failed Triangulating Points");
            }
            Log.PopLogLevel();
            return new ActionResult(ActionResult.Status.Success, "Create Polygon Shape");
        }
        /// 
        /// Create a new face given a set of unordered vertices (or ordered, if unordered param is set to false).
        /// 
        /// 
        /// 
        /// 
        internal static FaceRebuildData FaceWithVertices(List vertices, bool unordered = true)
        {
            List triangles;
            if (Triangulation.TriangulateVertices(vertices, out triangles, unordered))
            {
                FaceRebuildData data = new FaceRebuildData();
                data.vertices = vertices;
                data.face = new Face(triangles);
                return data;
            }
            return null;
        }
        /// 
        /// Create a new face given a set of ordered vertices and vertices making holes in the face.
        /// 
        /// 
        /// 
        /// 
        internal static FaceRebuildData FaceWithVerticesAndHole(List borderVertices, List> holes)
        {
            List triangles;
            Vector3[] verticesV3 = borderVertices.Select(v => v.position).ToArray();
            Vector3[][] holesV3 = new Vector3[holes.Count][];
            for (int i = 0; i < holesV3.Length; i++)
            {
                holesV3[i] = holes[i].Select(v => v.position).ToArray();
            }
            if (Triangulation.TriangulateVertices(verticesV3, out triangles, holesV3))
            {
                List vertices = new List();
                vertices.AddRange(borderVertices);
                foreach (var hole in holes)
                {
                    vertices.AddRange(hole);
                }
                FaceRebuildData data = new FaceRebuildData();
                data.vertices = vertices;
                data.face = new Face(triangles);
                return data;
            }
            return null;
        }
        /// 
        /// Given a path of vertices, inserts a new vertex in the center inserts triangles along the path.
        /// 
        /// 
        /// 
        internal static List TentCapWithVertices(List path)
        {
            int count = path.Count;
            Vertex center = Vertex.Average(path);
            List faces = new List();
            for (int i = 0; i < count; i++)
            {
                List vertices = new List()
                {
                    path[i],
                    center,
                    path[(i + 1) % count]
                };
                FaceRebuildData data = new FaceRebuildData();
                data.vertices = vertices;
                data.face = new Face(new int[] {0, 1, 2});
                faces.Add(data);
            }
            return faces;
        }
        /// 
        /// Duplicate and reverse the winding direction for each face.
        /// 
        /// The target mesh.
        /// The faces to duplicate, reverse triangle winding order, and append to mesh.
        public static void DuplicateAndFlip(this ProBuilderMesh mesh, Face[] faces)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (faces == null)
                throw new ArgumentNullException("faces");
            List rebuild = new List();
            List vertices = new List(mesh.GetVertices());
            Dictionary lookup = mesh.sharedVertexLookup;
            foreach (Face face in faces)
            {
                FaceRebuildData data = new FaceRebuildData();
                data.vertices = new List();
                data.face = new Face(face);
                data.sharedIndexes = new List();
                Dictionary map = new Dictionary();
                int len = data.face.indexesInternal.Length;
                for (int i = 0; i < len; i++)
                {
                    if (map.ContainsKey(face.indexesInternal[i]))
                        continue;
                    map.Add(face.indexesInternal[i], map.Count);
                    data.vertices.Add(vertices[face.indexesInternal[i]]);
                    data.sharedIndexes.Add(lookup[face.indexesInternal[i]]);
                }
                int[] tris = new int[len];
                for (var i = 0; i < len; i++)
                    tris[len - (i + 1)] = map[data.face[i]];
                data.face.SetIndexes(tris);
                rebuild.Add(data);
            }
            FaceRebuildData.Apply(rebuild, mesh, vertices);
        }
        /// 
        /// Insert a face between two edges.
        /// 
        /// The source mesh.
        /// First edge.
        /// Second edge
        /// If true, this function will allow edges to be bridged that create overlapping (non-manifold) faces.
        /// The new face, or null of the action failed.
        public static Face Bridge(this ProBuilderMesh mesh, Edge a, Edge b, bool allowNonManifoldGeometry = false)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            SharedVertex[] sharedVertices = mesh.sharedVerticesInternal;
            Dictionary lookup = mesh.sharedVertexLookup;
            // Check to see if a face already exists
            if (!allowNonManifoldGeometry)
            {
                if (ElementSelection.GetNeighborFaces(mesh, a).Count > 1 ||
                    ElementSelection.GetNeighborFaces(mesh, b).Count > 1)
                {
                    return null;
                }
            }
            foreach (Face face in mesh.facesInternal)
            {
                if (mesh.IndexOf(face.edgesInternal, a) >= 0 && mesh.IndexOf(face.edgesInternal, b) >= 0)
                {
                    Log.Warning("Face already exists between these two edges!");
                    return null;
                }
            }
            Vector3[] positions = mesh.positionsInternal;
            bool hasColors = mesh.HasArrays(MeshArrays.Color);
            Color[] colors = hasColors ? mesh.colorsInternal : null;
            Vector3[] v;
            Color[] c;
            int[] s;
            AutoUnwrapSettings uvs = AutoUnwrapSettings.tile;
            int submeshIndex = 0;
            // Get material and UV stuff from the first edge face
            SimpleTuple faceAndEdge;
            if (EdgeUtility.ValidateEdge(mesh, a, out faceAndEdge) ||
                EdgeUtility.ValidateEdge(mesh, b, out faceAndEdge))
            {
                uvs = new AutoUnwrapSettings(faceAndEdge.item1.uv);
                submeshIndex = faceAndEdge.item1.submeshIndex;
            }
            // Bridge will form a triangle
            if (a.Contains(b.a, lookup) || a.Contains(b.b, lookup))
            {
                v = new Vector3[3];
                c = new Color[3];
                s = new int[3];
                bool axbx = Array.IndexOf(sharedVertices[mesh.GetSharedVertexHandle(a.a)].arrayInternal, b.a) > -1;
                bool axby = Array.IndexOf(sharedVertices[mesh.GetSharedVertexHandle(a.a)].arrayInternal, b.b) > -1;
                bool aybx = Array.IndexOf(sharedVertices[mesh.GetSharedVertexHandle(a.b)].arrayInternal, b.a) > -1;
                bool ayby = Array.IndexOf(sharedVertices[mesh.GetSharedVertexHandle(a.b)].arrayInternal, b.b) > -1;
                if (axbx)
                {
                    v[0] = positions[a.a];
                    if (hasColors) c[0] = colors[a.a];
                    s[0] = mesh.GetSharedVertexHandle(a.a);
                    v[1] = positions[a.b];
                    if (hasColors) c[1] = colors[a.b];
                    s[1] = mesh.GetSharedVertexHandle(a.b);
                    v[2] = positions[b.b];
                    if (hasColors) c[2] = colors[b.b];
                    s[2] = mesh.GetSharedVertexHandle(b.b);
                }
                else if (axby)
                {
                    v[0] = positions[a.a];
                    if (hasColors) c[0] = colors[a.a];
                    s[0] = mesh.GetSharedVertexHandle(a.a);
                    v[1] = positions[a.b];
                    if (hasColors) c[1] = colors[a.b];
                    s[1] = mesh.GetSharedVertexHandle(a.b);
                    v[2] = positions[b.a];
                    if (hasColors) c[2] = colors[b.a];
                    s[2] = mesh.GetSharedVertexHandle(b.a);
                }
                else if (aybx)
                {
                    v[0] = positions[a.b];
                    if (hasColors) c[0] = colors[a.b];
                    s[0] = mesh.GetSharedVertexHandle(a.b);
                    v[1] = positions[a.a];
                    if (hasColors) c[1] = colors[a.a];
                    s[1] = mesh.GetSharedVertexHandle(a.a);
                    v[2] = positions[b.b];
                    if (hasColors) c[2] = colors[b.b];
                    s[2] = mesh.GetSharedVertexHandle(b.b);
                }
                else if (ayby)
                {
                    v[0] = positions[a.b];
                    if (hasColors) c[0] = colors[a.b];
                    s[0] = mesh.GetSharedVertexHandle(a.b);
                    v[1] = positions[a.a];
                    if (hasColors) c[1] = colors[a.a];
                    s[1] = mesh.GetSharedVertexHandle(a.a);
                    v[2] = positions[b.a];
                    if (hasColors) c[2] = colors[b.a];
                    s[2] = mesh.GetSharedVertexHandle(b.a);
                }
                return mesh.AppendFace(
                    v,
                    hasColors ? c : null,
                    new Vector2[v.Length],
                    new Vector4[v.Length],
                    new Vector4[v.Length],
                    new Face(axbx || axby ? new int[3] {2, 1, 0} : new int[3] {0, 1, 2}, submeshIndex, uvs, 0, -1, -1,
                        false),
                    s);
            }
            // Else, bridge will form a quad
            v = new Vector3[4];
            c = new Color[4];
            s = new int[4]; // shared indexes index to add to
            v[0] = positions[a.a];
            if (hasColors)
                c[0] = mesh.colorsInternal[a.a];
            s[0] = mesh.GetSharedVertexHandle(a.a);
            v[1] = positions[a.b];
            if (hasColors)
                c[1] = mesh.colorsInternal[a.b];
            s[1] = mesh.GetSharedVertexHandle(a.b);
            Vector3 nrm = Vector3.Cross(positions[b.a] - positions[a.a], positions[a.b] - positions[a.a]).normalized;
            Vector2[] planed =
                Projection.PlanarProject(
                    new Vector3[4] {positions[a.a], positions[a.b], positions[b.a], positions[b.b]}, null, nrm);
            Vector2 ipoint = Vector2.zero;
            bool intersects = Math.GetLineSegmentIntersect(planed[0], planed[2], planed[1], planed[3], ref ipoint);
            if (!intersects)
            {
                v[2] = positions[b.a];
                if (hasColors)
                    c[2] = mesh.colorsInternal[b.a];
                s[2] = mesh.GetSharedVertexHandle(b.a);
                v[3] = positions[b.b];
                if (hasColors)
                    c[3] = mesh.colorsInternal[b.b];
                s[3] = mesh.GetSharedVertexHandle(b.b);
            }
            else
            {
                v[2] = positions[b.b];
                if (hasColors)
                    c[2] = mesh.colorsInternal[b.b];
                s[2] = mesh.GetSharedVertexHandle(b.b);
                v[3] = positions[b.a];
                if (hasColors)
                    c[3] = mesh.colorsInternal[b.a];
                s[3] = mesh.GetSharedVertexHandle(b.a);
            }
            return mesh.AppendFace(
                v,
                hasColors ? c : null,
                new Vector2[v.Length],
                new Vector4[v.Length],
                new Vector4[v.Length],
                new Face(new int[6] {2, 1, 0, 2, 3, 1}, submeshIndex, uvs, 0, -1, -1, false),
                s);
        }
        // backwards compatibility prevents us from just using insertOnEdge as an optional parameter
        public static Face AppendVerticesToFace(this ProBuilderMesh mesh, Face face, Vector3[] points)
        {
            return AppendVerticesToFace(mesh, face, points, true);
        }
        /// 
        /// Add a set of points to a face and re-triangulate. Points are added to the nearest edge.
        /// 
        /// The source mesh.
        /// The face to append points to.
        /// Points to added to the face.
        /// True to force new points to edges.
        /// The face created by appending the points.
        public static Face AppendVerticesToFace(this ProBuilderMesh mesh, Face face, Vector3[] points, bool insertOnEdge)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (face == null)
                throw new ArgumentNullException("face");
            if (points == null)
                throw new ArgumentNullException("points");
            List vertices = mesh.GetVertices().ToList();
            List faces = new List(mesh.facesInternal);
            Dictionary lookup = mesh.sharedVertexLookup;
            Dictionary lookupUV = null;
            if (mesh.sharedTextures != null)
            {
                lookupUV = new Dictionary();
                SharedVertex.GetSharedVertexLookup(mesh.sharedTextures, lookupUV);
            }
            List wound = WingedEdge.SortEdgesByAdjacency(face);
            List n_vertices = new List();
            List n_shared = new List();
            List n_sharedUV = lookupUV != null ? new List() : null;
            for (int i = 0; i < wound.Count; i++)
            {
                n_vertices.Add(vertices[wound[i].a]);
                n_shared.Add(lookup[wound[i].a]);
                if (lookupUV != null)
                {
                    int uv;
                    if (lookupUV.TryGetValue(wound[i].a, out uv))
                        n_sharedUV.Add(uv);
                    else
                        n_sharedUV.Add(-1);
                }
            }
            if (insertOnEdge)
            {
                // now insert the new points on the nearest edge
                for (int i = 0; i < points.Length; i++)
                {
                    int index = -1;
                    float best = Mathf.Infinity;
                    Vector3 p = points[i];
                    int vc = n_vertices.Count;
                    for (int n = 0; n < vc; n++)
                    {
                        Vector3 v = n_vertices[n].position;
                        Vector3 w = n_vertices[(n + 1) % vc].position;
                        float dist = Math.DistancePointLineSegment(p, v, w);
                        if (dist < best)
                        {
                            best = dist;
                            index = n;
                        }
                    }
                    Vertex left = n_vertices[index], right = n_vertices[(index + 1) % vc];
                    float x = (p - left.position).sqrMagnitude;
                    float y = (p - right.position).sqrMagnitude;
                    Vertex insert = Vertex.Mix(left, right, x / (x + y));
                    n_vertices.Insert((index + 1) % vc, insert);
                    n_shared.Insert((index + 1) % vc, -1);
                    if (n_sharedUV != null) n_sharedUV.Insert((index + 1) % vc, -1);
                }
            }
            else
            {
                for (int i = 0; i < points.Length; i++)
                {
                    int index = -1;
                    Vector3 p = points[i];
                    int vc = n_vertices.Count;
                    Vertex insert = new Vertex();//Vertex.Mix(left, right, x / (x + y));
                    insert.position = p;
                    n_vertices.Insert((index + 1) % vc, insert);
                    n_shared.Insert((index + 1) % vc, -1);
                    if (n_sharedUV != null) n_sharedUV.Insert((index + 1) % vc, -1);
                }
            }
            List triangles;
            try
            {
                Triangulation.TriangulateVertices(n_vertices, out triangles, true);
            }
            catch
            {
                Debug.Log("Failed triangulating face after appending vertices.");
                return null;
            }
            FaceRebuildData data = new FaceRebuildData();
            data.face = new Face(triangles.ToArray(), face.submeshIndex, new AutoUnwrapSettings(face.uv),
                face.smoothingGroup, face.textureGroup, -1, face.manualUV);
            data.vertices = n_vertices;
            data.sharedIndexes = n_shared;
            data.sharedIndexesUV = n_sharedUV;
            FaceRebuildData.Apply(new List() {data},
                vertices,
                faces,
                lookup,
                lookupUV);
            var newFace = data.face;
            mesh.SetVertices(vertices);
            mesh.faces = faces;
            mesh.SetSharedVertices(lookup);
            mesh.SetSharedTextures(lookupUV);
            // check old normal and make sure this new face is pointing the same direction
            Vector3 oldNrm = Math.Normal(mesh, face);
            Vector3 newNrm = Math.Normal(mesh, newFace);
            if (Vector3.Dot(oldNrm, newNrm) < 0)
                newFace.Reverse();
            mesh.DeleteFace(face);
            return newFace;
        }
        /// 
        /// Insert a number of new points to an edge. Points are evenly spaced out along the edge.
        /// 
        /// The source mesh.
        /// The edge to split with points.
        /// The number of new points to insert. Must be greater than 0.
        /// The new edges created by inserting points.
        public static List AppendVerticesToEdge(this ProBuilderMesh mesh, Edge edge, int count)
        {
            return AppendVerticesToEdge(mesh, new Edge[] {edge}, count);
        }
        /// 
        /// Insert a number of new points to each edge. Points are evenly spaced out along the edge.
        /// 
        /// The source mesh.
        /// The edges to split with points.
        /// The number of new points to insert. Must be greater than 0.
        /// The new edges created by inserting points.
        public static List AppendVerticesToEdge(this ProBuilderMesh mesh, IList edges, int count)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (edges == null)
                throw new ArgumentNullException("edges");
            if (count < 1 || count > 512)
            {
                Log.Error("New edge vertex count is less than 1 or greater than 512.");
                return null;
            }
            List vertices = new List(mesh.GetVertices());
            Dictionary lookup = mesh.sharedVertexLookup;
            Dictionary lookupUV = mesh.sharedTextureLookup;
            List indexesToDelete = new List();
            IEnumerable commonEdges = EdgeUtility.GetSharedVertexHandleEdges(mesh, edges);
            List distinctEdges = commonEdges.Distinct().ToList();
            Dictionary modifiedFaces = new Dictionary();
            int originalSharedIndexesCount = lookup.Count();
            int sharedIndexesCount = originalSharedIndexesCount;
            foreach (Edge edge in distinctEdges)
            {
                Edge localEdge = EdgeUtility.GetEdgeWithSharedVertexHandles(mesh, edge);
                // Generate the new vertices that will be inserted on this edge
                List verticesToAppend = new List(count);
                for (int i = 0; i < count; i++)
                    verticesToAppend.Add(Vertex.Mix(vertices[localEdge.a], vertices[localEdge.b],
                        (i + 1) / ((float) count + 1)));
                List> adjacentFaces = ElementSelection.GetNeighborFaces(mesh, localEdge);
                Edge edgeLookUp = new Edge(lookup[localEdge.a], lookup[localEdge.b]);
                Edge e = new Edge();
                // foreach face attached to common edge, append vertices
                foreach (SimpleTuple tup in adjacentFaces)
                {
                    Face face = tup.item1;
                    FaceRebuildData data;
                    if (!modifiedFaces.TryGetValue(face, out data))
                    {
                        data = new FaceRebuildData();
                        data.face = new Face(new int[0], face.submeshIndex, new AutoUnwrapSettings(face.uv),
                            face.smoothingGroup, face.textureGroup, -1, face.manualUV);
                        data.vertices =
                            new List(ArrayUtility.ValuesWithIndexes(vertices, face.distinctIndexesInternal));
                        data.sharedIndexes = new List();
                        data.sharedIndexesUV = new List();
                        foreach (int i in face.distinctIndexesInternal)
                        {
                            int shared;
                            if (lookup.TryGetValue(i, out shared))
                                data.sharedIndexes.Add(shared);
                            if (lookupUV.TryGetValue(i, out shared))
                                data.sharedIndexesUV.Add(shared);
                        }
                        indexesToDelete.AddRange(face.distinctIndexesInternal);
                        modifiedFaces.Add(face, data);
                        //Ordering vertices in the new face
                        List orderedVertices = new List();
                        List orderedSharedIndexes = new List();
                        List orderedSharedUVIndexes = new List();
                        List peripheralEdges = WingedEdge.SortEdgesByAdjacency(face);
                        for (int i = 0; i < peripheralEdges.Count; i++)
                        {
                            e.a = peripheralEdges[i].a;
                            e.b = peripheralEdges[i].b;
                            orderedVertices.Add(vertices[e.a]);
                            int shared;
                            if (lookup.TryGetValue(e.a, out shared))
                                orderedSharedIndexes.Add(shared);
                            if (lookupUV.TryGetValue(i, out shared))
                                data.sharedIndexesUV.Add(shared);
                            if (edgeLookUp.a == lookup[e.a] && edgeLookUp.b == lookup[e.b])
                            {
                                for (int j = 0; j < count; j++)
                                {
                                    orderedVertices.Add(verticesToAppend[j]);
                                    orderedSharedIndexes.Add(sharedIndexesCount + j);
                                    orderedSharedUVIndexes.Add(-1);
                                }
                            }
                            else if (edgeLookUp.a == lookup[e.b] && edgeLookUp.b == lookup[e.a])
                            {
                                for (int j = count - 1; j >= 0; j--)
                                {
                                    orderedVertices.Add(verticesToAppend[j]);
                                    orderedSharedIndexes.Add(sharedIndexesCount + j);
                                    orderedSharedUVIndexes.Add(-1);
                                }
                            }
                        }
                        data.vertices = orderedVertices;
                        data.sharedIndexes = orderedSharedIndexes;
                        data.sharedIndexesUV = orderedSharedUVIndexes;
                    }
                    else
                    {
                        //Get ordered vertices in the existing face and add new ones
                        List orderedVertices = data.vertices;
                        List orderedSharedIndexes = data.sharedIndexes;
                        List orderedSharedUVIndexes = data.sharedIndexesUV;
                        for (int i = 0; i < orderedVertices.Count; i++)
                        {
                            Vertex edgeStart = orderedVertices[i];
                            int edgeStartIndex = vertices.IndexOf(edgeStart);
                            Vertex edgeEnd = orderedVertices[(i + 1) % orderedVertices.Count];
                            int edgeEndIndex = vertices.IndexOf(edgeEnd);
                            if (edgeStartIndex == -1 || edgeEndIndex == -1)
                                continue;
                            if (lookup[edgeStartIndex] == lookup[localEdge.a] &&
                                lookup[edgeEndIndex] == lookup[localEdge.b])
                            {
                                orderedVertices.InsertRange(i + 1, verticesToAppend);
                                for (int j = 0; j < count; j++)
                                {
                                    orderedSharedIndexes.Insert(i + j + 1, sharedIndexesCount + j);
                                    orderedSharedUVIndexes.Add(-1);
                                }
                            }
                            else if (lookup[edgeStartIndex] == lookup[localEdge.b] &&
                                     lookup[edgeEndIndex] == lookup[localEdge.a])
                            {
                                verticesToAppend.Reverse();
                                orderedVertices.InsertRange(i + 1, verticesToAppend);
                                for (int j = count - 1; j >= 0; j--)
                                {
                                    orderedSharedIndexes.Insert(i + 1, sharedIndexesCount + j);
                                    orderedSharedUVIndexes.Add(-1);
                                }
                            }
                        }
                        data.vertices = orderedVertices;
                        data.sharedIndexes = orderedSharedIndexes;
                        data.sharedIndexesUV = orderedSharedUVIndexes;
                    }
                }
                sharedIndexesCount += count;
            }
            // now apply the changes
            List dic_face = modifiedFaces.Keys.ToList();
            List dic_data = modifiedFaces.Values.ToList();
            List appendedEdges = new List();
            for (int i = 0; i < dic_face.Count; i++)
            {
                Face face = dic_face[i];
                FaceRebuildData data = dic_data[i];
                int vertexCount = vertices.Count;
                // triangulate and set new face indexes to end of current vertex list
                List triangles;
                if (Triangulation.TriangulateVertices(data.vertices, out triangles, false))
                    data.face = new Face(triangles);
                else
                    continue;
                //Keep submesh index when rebuilding to maintain material references
                data.face.submeshIndex = face.submeshIndex;
                data.face.ShiftIndexes(vertexCount);
                face.CopyFrom(data.face);
                for (int n = 0; n < data.vertices.Count; n++)
                    lookup.Add(vertexCount + n, data.sharedIndexes[n]);
                if (data.sharedIndexesUV.Count == data.vertices.Count)
                {
                    for (int n = 0; n < data.vertices.Count; n++)
                        lookupUV.Add(vertexCount + n, data.sharedIndexesUV[n]);
                }
                vertices.AddRange(data.vertices);
                foreach (Edge e in face.edgesInternal)
                {
                    EdgeLookup el = new EdgeLookup(new Edge(lookup[e.a], lookup[e.b]), e);
                    if (el.common.a >= originalSharedIndexesCount || el.common.b >= originalSharedIndexesCount)
                        appendedEdges.Add(el);
                }
            }
            indexesToDelete = indexesToDelete.Distinct().ToList();
            int delCount = indexesToDelete.Count;
            var newEdges = appendedEdges.Distinct().Select(x => x.local - delCount).ToList();
            mesh.SetVertices(vertices);
            mesh.SetSharedVertices(lookup);
            mesh.SetSharedTextures(lookupUV);
            mesh.DeleteVertices(indexesToDelete);
            return newEdges;
        }
        /// 
        /// Add a set of points to a face and retriangulate. Points are added to the nearest edge.
        /// 
        /// The source mesh.
        /// The face to append points to.
        /// Point to added to the face.
        /// The face created by appending the points.
        public static Face[] InsertVertexInFace(this ProBuilderMesh mesh, Face face, Vector3 point)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (face == null)
                throw new ArgumentNullException("face");
            if (point == null)
                throw new ArgumentNullException("point");
            List vertices = mesh.GetVertices().ToList();
            List faces = new List(mesh.facesInternal);
            Dictionary lookup = mesh.sharedVertexLookup;
            Dictionary lookupUV = null;
            if (mesh.sharedTextures != null)
            {
                lookupUV = new Dictionary();
                SharedVertex.GetSharedVertexLookup(mesh.sharedTextures, lookupUV);
            }
            List wound = WingedEdge.SortEdgesByAdjacency(face);
            List newFacesData = new List();
            Vertex newVertex = new Vertex();
            newVertex.position = point;
            for (int i = 0; i < wound.Count; i++)
            {
                List n_vertices = new List();
                List n_shared = new List();
                List n_sharedUV = lookupUV != null ? new List() : null;
                n_vertices.Add(vertices[wound[i].a]);
                n_vertices.Add(vertices[wound[i].b]);
                n_vertices.Add(newVertex);
                n_shared.Add(lookup[wound[i].a]);
                n_shared.Add(lookup[wound[i].b]);
                n_shared.Add(vertices.Count);
                if (lookupUV != null)
                {
                    int uv;
                    lookupUV.Clear();
                    if (lookupUV.TryGetValue(wound[i].a, out uv))
                        n_sharedUV.Add(uv);
                    else
                        n_sharedUV.Add(-1);
                    if (lookupUV.TryGetValue(wound[i].b, out uv))
                        n_sharedUV.Add(uv);
                    else
                        n_sharedUV.Add(-1);
                    n_sharedUV.Add(vertices.Count);
                }
                List triangles;
                try
                {
                    Triangulation.TriangulateVertices(n_vertices, out triangles, true);
                }
                catch
                {
                    Debug.Log("Failed triangulating face after appending vertices.");
                    return null;
                }
                FaceRebuildData data = new FaceRebuildData();
                data.face = new Face(triangles.ToArray(), face.submeshIndex, new AutoUnwrapSettings(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);
                data.vertices           = n_vertices;
                data.sharedIndexes      = n_shared;
                data.sharedIndexesUV    = n_sharedUV;
                newFacesData.Add(data);
            }
            FaceRebuildData.Apply(newFacesData,
                vertices,
                faces,
                lookup,
                lookupUV);
            mesh.SetVertices(vertices);
            mesh.faces = faces;
            mesh.SetSharedVertices(lookup);
            mesh.SetSharedTextures(lookupUV);
            Face[] newFaces = newFacesData.Select(f => f.face).ToArray();
            foreach (FaceRebuildData data in newFacesData)
            {
                var newFace = data.face;
                // check old normal and make sure this new face is pointing the same direction
                Vector3 oldNrm = UnityEngine.ProBuilder.Math.Normal(mesh, face);
                Vector3 newNrm = UnityEngine.ProBuilder.Math.Normal(mesh, newFace);
                if (Vector3.Dot(oldNrm, newNrm) < 0)
                    newFace.Reverse();
            }
            mesh.DeleteFace(face);
            return newFaces;
        }
        /// 
        /// Insert a number of new points to each edge. Points are evenly spaced out along the edge.
        /// 
        /// The source mesh.
        /// The edge on which adding the point.
        /// The point to insert on the edge.
        /// The new edges created by the point insertion.//
        public static Vertex InsertVertexOnEdge(this ProBuilderMesh mesh, Edge originalEdge, Vector3 point)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (originalEdge == null)
                throw new ArgumentNullException("edge");
            List vertices = new List(mesh.GetVertices());
            Dictionary lookup = mesh.sharedVertexLookup;
            Dictionary lookupUV = mesh.sharedTextureLookup;
            List indexesToDelete = new List();
            Dictionary modifiedFaces = new Dictionary();
            int originalSharedIndexesCount = lookup.Count();
            //Ensure the new point is on the edge
            //Using Scalar projection
            Vector3 a = point -
                        vertices[originalEdge.a].position;
            Vector3 b = vertices[originalEdge.b].position -
                        vertices[originalEdge.a].position;
            float weight = Vector3.Magnitude(a) * Mathf.Cos(Vector3.Angle(b, a) * Mathf.Deg2Rad) / Vector3.Magnitude(b);
            Vertex newVertex = Vertex.Mix(vertices[originalEdge.a], vertices[originalEdge.b], weight);
            List> adjacentFaces = ElementSelection.GetNeighborFaces(mesh, originalEdge);
            Edge uni = new Edge(lookup[originalEdge.a], lookup[originalEdge.b]);
            Edge e = new Edge();
            // foreach face attached to common edge, append vertices
            foreach (SimpleTuple tup in adjacentFaces)
            {
                Face face = tup.item1;
                FaceRebuildData data;
                if (!modifiedFaces.TryGetValue(face, out data))
                {
                    data = new FaceRebuildData();
                    data.face = new Face(new int[0], face.submeshIndex, new AutoUnwrapSettings(face.uv), face.smoothingGroup, face.textureGroup, -1, face.manualUV);
                    data.vertices = new List(ArrayUtility.ValuesWithIndexes(vertices, face.distinctIndexesInternal));
                    data.sharedIndexes = new List();
                    data.sharedIndexesUV = new List();
                    foreach (int i in face.distinctIndexesInternal)
                    {
                        int shared;
                        if (lookup.TryGetValue(i, out shared))
                            data.sharedIndexes.Add(shared);
                        if (lookupUV.TryGetValue(i, out shared))
                            data.sharedIndexesUV.Add(shared);
                    }
                    indexesToDelete.AddRange(face.distinctIndexesInternal);
                    modifiedFaces.Add(face, data);
                }
                data.vertices.Add(newVertex);
                data.sharedIndexes.Add(originalSharedIndexesCount);
                data.sharedIndexesUV.Add(-1);
                List orderedVertices = new List();
                List orderedSharedIndexes = new List();
                List peripheralEdges = WingedEdge.SortEdgesByAdjacency(face);
                bool canAdd = true;
                for (int i = 0; i < peripheralEdges.Count; i++)
                {
                    e.a = peripheralEdges[i].a;
                    e.b = peripheralEdges[i].b;
                    orderedVertices.Add(vertices[e.a]);
                    int shared;
                    if (lookup.TryGetValue(e.a, out shared))
                        orderedSharedIndexes.Add(shared);
                    if (canAdd &&
                        (uni.a == lookup[e.a] && uni.b == lookup[e.b]) ||
                        (uni.a == lookup[e.b] && uni.b == lookup[e.a]))
                    {
                        canAdd = false;
                        orderedVertices.Add(data.vertices[data.vertices.Count-1]);
                        orderedSharedIndexes.Add(originalSharedIndexesCount);
                    }
                }
                data.vertices = orderedVertices;
                data.sharedIndexes = orderedSharedIndexes;
            }
            // now apply the changes
            List dic_face = modifiedFaces.Keys.ToList();
            List dic_data = modifiedFaces.Values.ToList();
            for (int i = 0; i < dic_face.Count; i++)
            {
                Face face = dic_face[i];
                FaceRebuildData data = dic_data[i];
                int vertexCount = vertices.Count;
                // triangulate and set new face indexes to end of current vertex list
                List triangles;
                if (Triangulation.TriangulateVertices(data.vertices, out triangles, false))
                    data.face = new Face(triangles);
                else
                    continue;
                //Keep submesh index when rebuilding to maintain material references
                data.face.submeshIndex = face.submeshIndex;
                data.face.ShiftIndexes(vertexCount);
                face.CopyFrom(data.face);
                for (int n = 0; n < data.vertices.Count; n++)
                    lookup.Add(vertexCount + n, data.sharedIndexes[n]);
                if (data.sharedIndexesUV.Count == data.vertices.Count)
                {
                    for (int n = 0; n < data.vertices.Count; n++)
                        lookupUV.Add(vertexCount + n, data.sharedIndexesUV[n]);
                }
                vertices.AddRange(data.vertices);
            }
            indexesToDelete = indexesToDelete.Distinct().ToList();
            mesh.SetVertices(vertices);
            mesh.SetSharedVertices(lookup);
            mesh.SetSharedTextures(lookupUV);
            mesh.DeleteVertices(indexesToDelete);
            return newVertex;
        }
        /// 
        /// Add a point to a face.
        /// 
        /// The source mesh.
        /// Point to added to the face.
        /// The inserted point normal.
        /// The face created by appending the points.
        public static Vertex InsertVertexInMesh(this ProBuilderMesh mesh, Vector3 point, Vector3 normal)
        {
            if (mesh == null)
                throw new ArgumentNullException("mesh");
            if (point == null)
                throw new ArgumentNullException("point");
            List vertices = mesh.GetVertices().ToList();
            Dictionary lookup = mesh.sharedVertexLookup;
            Dictionary lookupUV = null;
            // List indexesToDelete = new List();
            int originalSharedIndexesCount = lookup.Count();
            if (mesh.sharedTextures != null)
            {
                lookupUV = new Dictionary();
                SharedVertex.GetSharedVertexLookup(mesh.sharedTextures, lookupUV);
            }
            Vertex newVertex = new Vertex();
            newVertex.position = point;
            newVertex.normal = normal.normalized;
            vertices.Add(newVertex);
            lookup.Add(originalSharedIndexesCount,originalSharedIndexesCount);
            lookupUV.Add(originalSharedIndexesCount,-1);
            mesh.SetVertices(vertices);
            mesh.SetSharedVertices(lookup);
            mesh.SetSharedTextures(lookupUV);
            return newVertex;
        }
    }
}