using UnityEngine;
using System.Collections.Generic;
using System.Linq;
using UnityEngine.ProBuilder;
namespace UnityEngine.ProBuilder.MeshOperations
{
///
/// Methods for merging multiple faces of a to a single face.
///
public static class MergeElements
{
///
/// Merge each pair of faces to a single face. Indexes are combined, but otherwise the properties of the first face in the pair take precedence. Returns a list of the new faces created.
///
///
///
///
///
public static List MergePairs(ProBuilderMesh target, IEnumerable> pairs, bool collapseCoincidentVertices = true)
{
HashSet remove = new HashSet();
List add = new List();
foreach (SimpleTuple pair in pairs)
{
Face left = pair.item1;
Face right = pair.item2;
int leftLength = left.indexesInternal.Length;
int rightLength = right.indexesInternal.Length;
int[] indexes = new int[leftLength + rightLength];
System.Array.Copy(left.indexesInternal, 0, indexes, 0, leftLength);
System.Array.Copy(right.indexesInternal, 0, indexes, leftLength, rightLength);
add.Add(new Face(indexes,
left.submeshIndex,
left.uv,
left.smoothingGroup,
left.textureGroup,
left.elementGroup,
left.manualUV));
remove.Add(left);
remove.Add(right);
}
List faces = target.facesInternal.Where(x => !remove.Contains(x)).ToList();
faces.AddRange(add);
target.faces = faces;
if (collapseCoincidentVertices)
CollapseCoincidentVertices(target, add);
return add;
}
///
/// Merge a collection of faces to a single face. This function does not
/// perform any sanity checks, it just merges faces. It's the caller's
/// responsibility to make sure that the input is valid.
/// In addition to merging faces this method also removes duplicate vertices
/// created as a result of merging previously common vertices.
///
///
///
///
public static Face Merge(ProBuilderMesh target, IEnumerable faces)
{
int mergedCount = faces != null ? faces.Count() : 0;
if (mergedCount < 1)
return null;
Face first = faces.First();
Face mergedFace = new Face(faces.SelectMany(x => x.indexesInternal).ToArray(),
first.submeshIndex,
first.uv,
first.smoothingGroup,
first.textureGroup,
first.elementGroup,
first.manualUV);
Face[] rebuiltFaces = new Face[target.facesInternal.Length - mergedCount + 1];
int n = 0;
HashSet skip = new HashSet(faces);
foreach (Face f in target.facesInternal)
{
if (!skip.Contains(f))
rebuiltFaces[n++] = f;
}
rebuiltFaces[n] = mergedFace;
target.faces = rebuiltFaces;
CollapseCoincidentVertices(target, new Face[] { mergedFace });
return mergedFace;
}
///
/// Condense co-incident vertex positions per-face. vertices must already be marked as shared in the sharedIndexes
/// array to be considered. This method is really only useful after merging faces.
///
///
///
internal static void CollapseCoincidentVertices(ProBuilderMesh mesh, IEnumerable faces)
{
Dictionary lookup = mesh.sharedVertexLookup;
Dictionary matches = new Dictionary();
foreach (Face face in faces)
{
matches.Clear();
for (int i = 0; i < face.indexesInternal.Length; i++)
{
int common = lookup[face.indexesInternal[i]];
if (matches.ContainsKey(common))
face.indexesInternal[i] = matches[common];
else
matches.Add(common, face.indexesInternal[i]);
}
face.InvalidateCache();
}
MeshValidation.RemoveUnusedVertices(mesh);
}
}
}