/// <summary> /// Creates a deep copy of the specified mesh. /// </summary> /// <typeparam name="TVertex">The type of the vertex.</typeparam> /// <param name="mesh">The mesh to copy.</param> /// <returns>A deep copy of the mesh.</returns> public static IDivisibleMesh <TVertex> Copy <TVertex>(this IDivisibleMesh <TVertex> mesh) where TVertex : struct { Contracts.Requires.That(mesh != null); return(new DivisibleMesh <TVertex>(mesh.Groups.ToArray(), mesh.Offsets.ToArray(), mesh.Vertices.ToArray())); }
public static bool IsEmpty <TVertex>(this IDivisibleMesh <TVertex> mesh) where TVertex : struct { Contracts.Requires.That(mesh != null); return(mesh.Groups.Count == 0); }
public static IEnumerable <IDivisibleMesh <TVertex> > Split <TVertex>( int maxVerticesPerMesh, IDivisibleMesh <TVertex> mesh) where TVertex : struct { Contracts.Requires.That(maxVerticesPerMesh >= MeshConstants.VerticesPerTriangle); Contracts.Requires.That(mesh != null); Contracts.Requires.That(mesh.Groups.All(group => group.Vertices <= maxVerticesPerMesh)); if (mesh.Vertices.Count <= maxVerticesPerMesh) { yield return(mesh); yield break; } var combiner = new MeshCombiner <TVertex>(maxVerticesPerMesh); foreach (var submesh in Split(mesh, combiner)) { yield return(submesh); } if (combiner.VertexCount > 0) { yield return(combiner.CreateMesh()); } }
public static void VerifyContracts <TVertex>(IDivisibleMesh <TVertex> mesh) where TVertex : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(mesh.Groups != null); Contracts.Requires.That(mesh.Offsets != null); Contracts.Requires.That(mesh.Vertices != null); Contracts.Requires.That(!mesh.Groups.Contains(TriangleGroup.Empty)); Contracts.Requires.That(mesh.Offsets.Count.IsDivisibleBy(MeshConstants.VerticesPerTriangle)); Contracts.Requires.That(mesh.Offsets.Count == mesh.Groups.Select(group => group.Offsets).Sum()); Contracts.Requires.That(mesh.Vertices.Count == mesh.Groups.Select(group => (int)group.Vertices).Sum()); // index offsets for each cluster of polys must not index out of bounds of the vertices // defined for that cluster var offsets = mesh.Offsets.GetEnumerator(); foreach (var group in mesh.Groups) { for (int count = 0; count < group.Offsets; count++) { var success = offsets.MoveNext(); Contracts.Requires.That(success); Contracts.Requires.That(offsets.Current.IsIn(Range.FromLength(group.Vertices))); } } }
public MeshSplitter(IDivisibleMesh <TVertex> mesh, int remainingVertices) { Contracts.Requires.That(mesh != null); Contracts.Requires.That(remainingVertices >= 0); this.mesh = mesh; this.remainingVertices = remainingVertices; }
public static IReadOnlyCollection <int> GetTriangles <TVertex>( this IDivisibleMesh <TVertex> mesh, VertexWindingOrder winding) where TVertex : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(winding.IsValidEnumValue()); return(new ReadOnlyCollection <int>(mesh.EnumerateTriangles(winding), mesh.Offsets.Count)); }
/// <inheritdoc /> protected override void DecomposeValue( IDivisibleMesh <TVertex> value, out IReadOnlyCollection <TriangleGroup> groups, out IReadOnlyCollection <byte> offsets, out IReadOnlyCollection <TVertex> vertices) { groups = value.Groups; offsets = value.Offsets; vertices = value.Vertices; }
public static void CopyIn <TVertex>( IMeshDataTransfer <TVertex> instance, IDivisibleMesh <TVertex> mesh, VertexWindingOrder winding) where TVertex : struct { Contracts.Requires.That(instance != null); Contracts.Requires.That(mesh != null); Contracts.Requires.That( mesh.Vertices.Count <= instance.MaxVertices || instance.MaxVertices == Capacity.Unbounded); Contracts.Requires.That(winding.IsValidEnumValue()); DivisibleMesh.VerifyContracts(mesh); }
public static IDivisibleMesh <TResult> CopyConverted <TSource, TResult>( this IDivisibleMesh <TSource> mesh, Converter <TSource, TResult> vertexConverter) where TSource : struct where TResult : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(vertexConverter != null); return(new DivisibleMesh <TResult>( mesh.Groups.ToArray(), mesh.Offsets.ToArray(), mesh.Vertices.Convert(vertexConverter).ToCounted(mesh.Vertices.Count).ToArray())); }
public static IDivisibleMesh <TResult> Convert <TSource, TResult>( this IDivisibleMesh <TSource> mesh, Converter <TSource, TResult> vertexConverter) where TSource : struct where TResult : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(vertexConverter != null); return(new DivisibleMesh <TResult>( mesh.Groups, mesh.Offsets, new ReadOnlyCollection <TResult>(mesh.Vertices.Convert(vertexConverter), mesh.Vertices.Count))); }
/// <inheritdoc /> public void CopyIn(IDivisibleMesh <TVertex> mesh, VertexWindingOrder winding) { IMeshDataTransferContracts.CopyIn(this, mesh, winding); var triangles = mesh.GetTriangles(winding); this.IndicesCount = triangles.Count; this.indices.CopyIn( CountedEnumerable.New(triangles.Select(index => (ushort)index), triangles.Count)); this.VerticesCount = mesh.Vertices.Count; this.vertices.CopyIn(mesh.Vertices.AsCounted(), this.MaxVertices); }
public bool TryAdd(IDivisibleMesh <TVertex> mesh) { Contracts.Requires.That(mesh != null); int newVertexCount = this.VertexCount + mesh.Vertices.Count; if (newVertexCount <= this.MaxVerticesPerMesh) { this.VertexCount = newVertexCount; this.groups.Add(mesh.Groups); this.offsets.Add(mesh.Offsets); this.vertices.Add(mesh.Vertices); return(true); } return(false); }
private static IEnumerable <IDivisibleMesh <TVertex> > Split <TVertex>( IDivisibleMesh <TVertex> mesh, MeshCombiner <TVertex> combiner) where TVertex : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(combiner != null); var splitter = new MeshSplitter <TVertex>(mesh, combiner.MaxVerticesPerMesh - combiner.VertexCount); foreach (var group in mesh.Groups) { // empty groups aren't allowed in the mesh so no need to check for them here // so instead assert that there aren't empty groups Contracts.Assert.That(group.Triangles >= 1); Contracts.Assert.That(group.Vertices >= MeshConstants.VerticesPerTriangle); if (!splitter.TryAdd(group)) { if (splitter.HasMesh) { // the splitter is full so add it to the combiner to finish off the current mesh var success = combiner.TryAdd(splitter.CreateMesh()); Contracts.Assert.That(success); yield return(combiner.CreateMesh()); splitter.Reset(group, combiner.MaxVerticesPerMesh); } } } if (splitter.HasMesh) { // if there is any remaining mesh in the splitter add that to the combiner var success = combiner.TryAdd(splitter.CreateMesh()); Contracts.Assert.That(success); } }
public static IEnumerable <int> EnumerateTriangles <TVertex>( this IDivisibleMesh <TVertex> mesh, VertexWindingOrder winding) where TVertex : struct { Contracts.Requires.That(mesh != null); Contracts.Requires.That(winding.IsValidEnumValue()); var offsets = mesh.Offsets.GetEnumerator(); int globalOffset = 0; switch (winding) { case VertexWindingOrder.Clockwise: foreach (var group in mesh.Groups) { for (int count = 0; count < group.Offsets; count++) { var success = offsets.MoveNext(); Contracts.Assert.That(success); yield return(globalOffset + offsets.Current); } globalOffset += group.Vertices; } yield break; case VertexWindingOrder.Counterclockwise: foreach (var group in mesh.Groups) { // IDivisibleMesh<TVertex> is always stored in clockwise winding order // so the last 2 offsets of each triangle need to be swapped to become counterclockwise for (int count = 0; count < group.Triangles; count++) { // return the first offset as normal var success = offsets.MoveNext(); Contracts.Assert.That(success); yield return(globalOffset + offsets.Current); // temporarily store the second offset success = offsets.MoveNext(); Contracts.Assert.That(success); var tempOffset = offsets.Current; // return the third offset as though it were the second offset success = offsets.MoveNext(); Contracts.Assert.That(success); yield return(globalOffset + offsets.Current); // return the second offset (stored) as though it were the third offset yield return(globalOffset + tempOffset); } globalOffset += group.Vertices; } yield break; default: throw InvalidEnumArgument.CreateException(nameof(winding), winding); } }