Пример #1
0
    /// <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()));
    }
Пример #2
0
    public static bool IsEmpty <TVertex>(this IDivisibleMesh <TVertex> mesh)
        where TVertex : struct
    {
        Contracts.Requires.That(mesh != null);

        return(mesh.Groups.Count == 0);
    }
Пример #3
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());
            }
        }
Пример #4
0
        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)));
                }
            }
        }
Пример #5
0
            public MeshSplitter(IDivisibleMesh <TVertex> mesh, int remainingVertices)
            {
                Contracts.Requires.That(mesh != null);
                Contracts.Requires.That(remainingVertices >= 0);

                this.mesh = mesh;
                this.remainingVertices = remainingVertices;
            }
Пример #6
0
    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));
    }
Пример #7
0
 /// <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;
 }
Пример #8
0
        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);
        }
Пример #9
0
    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()));
    }
Пример #10
0
    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)));
    }
Пример #11
0
        /// <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);
        }
Пример #12
0
            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);
            }
Пример #13
0
        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);
            }
        }
Пример #14
0
    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);
        }
    }