using UnityEngine;
using System.Collections.Generic;
using System;
using System.ComponentModel;
using System.Linq;
namespace UnityEngine.ProBuilder.MeshOperations
{
///
/// Provides functions for removing vertices and triangles from a mesh.
///
public static class DeleteElements
{
///
/// Deletes the vertices from the specified index array and rebuilds the array.
///
/// This function does not retriangulate the mesh. This means that you are responsible for ensuring that the indexes
/// deleted by this function are not referenced by any triangles.
/// The source mesh.
/// A list of vertices to delete. Note that this must not contain duplicates.
public static void DeleteVertices(this ProBuilderMesh mesh, IEnumerable distinctIndexes)
{
if (mesh == null)
throw new ArgumentNullException("mesh");
if (distinctIndexes == null || !distinctIndexes.Any())
return;
Vertex[] vertices = mesh.GetVertices();
int originalVertexCount = vertices.Length;
int[] offset = new int[originalVertexCount];
List sorted = new List(distinctIndexes);
sorted.Sort();
vertices = vertices.SortedRemoveAt(sorted);
// Add 1 because NearestIndexPriorToValue is 0 indexed.
for (int i = 0; i < originalVertexCount; i++)
offset[i] = ArrayUtility.NearestIndexPriorToValue(sorted, i) + 1;
foreach (Face face in mesh.facesInternal)
{
int[] indexes = face.indexesInternal;
for (int i = 0; i < indexes.Length; i++)
indexes[i] -= offset[indexes[i]];
face.InvalidateCache();
}
// remove from sharedIndexes & shift to account for deletions
var common = mesh.sharedVertexLookup.Where(x => sorted.BinarySearch(x.Key) < 0).Select(y => new KeyValuePair(y.Key - offset[y.Key], y.Value));
var commonUV = mesh.sharedTextureLookup.Where(x => sorted.BinarySearch(x.Key) < 0).Select(y => new KeyValuePair(y.Key - offset[y.Key], y.Value));
mesh.SetVertices(vertices);
mesh.SetSharedVertices(common);
mesh.SetSharedTextures(commonUV);
}
///
/// Removes a face from a mesh.
///
/// This is the equivalent of the [Delete Faces](../manual/Face_Delete.html) action.
///
/// The source mesh.
/// The face to remove.
/// An array of vertex indices that ProBuilder deleted when it removed the specified face.
public static int[] DeleteFace(this ProBuilderMesh mesh, Face face)
{
return DeleteFaces(mesh, new Face[] { face });
}
///
/// Deletes a collection of faces from a mesh.
///
/// This is the equivalent of the [Delete Faces](../manual/Face_Delete.html) action.
///
/// The source mesh.
/// The faces to remove.
/// An array of vertex indices that ProBuilder deleted when it removed the specified faces.
public static int[] DeleteFaces(this ProBuilderMesh mesh, IEnumerable faces)
{
return DeleteFaces(mesh, faces.Select(x => System.Array.IndexOf(mesh.facesInternal, x)).ToList());
}
///
/// Deletes a list of faces from a mesh.
///
/// This is the equivalent of the [Delete Faces](../manual/Face_Delete.html) action.
///
/// The source mesh.
/// The indices of faces to remove (corresponding to the collection.
/// An array of vertex indices that ProBuilder deleted when it removed the specified faces.
public static int[] DeleteFaces(this ProBuilderMesh mesh, IList faceIndexes)
{
if (mesh == null)
throw new ArgumentNullException("mesh");
if (faceIndexes == null)
throw new ArgumentNullException("faceIndexes");
Face[] faces = new Face[faceIndexes.Count];
for (int i = 0; i < faces.Length; i++)
faces[i] = mesh.facesInternal[faceIndexes[i]];
List indexesToRemove = faces.SelectMany(x => x.distinctIndexesInternal).Distinct().ToList();
indexesToRemove.Sort();
int vertexCount = mesh.positionsInternal.Length;
Face[] nFaces = mesh.facesInternal.RemoveAt(faceIndexes);
var vertices = mesh.GetVertices().SortedRemoveAt(indexesToRemove);
Dictionary shiftmap = new Dictionary();
for (var i = 0; i < vertexCount; i++)
shiftmap.Add(i, ArrayUtility.NearestIndexPriorToValue(indexesToRemove, i) + 1);
// shift all other face indexes down to account for moved vertex positions
for (var i = 0; i < nFaces.Length; i++)
{
int[] tris = nFaces[i].indexesInternal;
for (var n = 0; n < tris.Length; n++)
tris[n] -= shiftmap[tris[n]];
nFaces[i].indexesInternal = tris;
}
mesh.SetVertices(vertices);
mesh.sharedVerticesInternal = SharedVertex.SortedRemoveAndShift(mesh.sharedVertexLookup, indexesToRemove);
mesh.sharedTextures = SharedVertex.SortedRemoveAndShift(mesh.sharedTextureLookup, indexesToRemove);
mesh.facesInternal = nFaces;
int[] array = indexesToRemove.ToArray();
return array;
}
/// Obsolete. Use `MeshValidation.RemoveDegenerateTriangles` instead.
/// The source mesh.
/// The list of removed triangles
[Obsolete("Use MeshValidation.RemoveDegenerateTriangles")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static int[] RemoveDegenerateTriangles(this ProBuilderMesh mesh)
{
List removed = new List();
MeshValidation.RemoveDegenerateTriangles(mesh, removed);
return removed.ToArray();
}
/// Obsolete. Use `MeshValidation.RemoveUnusedVertices` instead.
/// The source mesh.
/// The list of removed vertices
[Obsolete("Use MeshValidation.RemoveUnusedVertices")]
[EditorBrowsable(EditorBrowsableState.Never)]
public static int[] RemoveUnusedVertices(this ProBuilderMesh mesh)
{
List removed = new List();
MeshValidation.RemoveUnusedVertices(mesh, removed);
return removed.ToArray();
}
}
}