#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion #if UNITTEST using System; using System.Collections.Generic; using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Graphics; using NUnit.Framework; using TestVertex = Microsoft.Xna.Framework.Graphics.VertexPositionColor; namespace Nuclex.Graphics.Batching { /// Unit tests for the deferred queuer [TestFixture] internal class DeferredQueuerTest : QueuerTest { #region class Creator /// Sets up a test environment for the deferred queuer private class Creator : IDisposable { /// Initializes a new test environment public Creator() { this.drawContext = new DummyDrawContext(); this.batchDrawer = new DummyBatchDrawer(); this.queuer = new DeferredQueuer(this.batchDrawer); } /// Immediately releases all resources owned by the instance public void Dispose() { if(this.queuer != null) { this.queuer.Dispose(); this.queuer = null; } this.batchDrawer = null; this.drawContext = null; } /// Queues a series of primitives /// Primitive vertices /// Index of vertex to begin drawing with /// Number of vertices to draw /// Type of primitives to draw public void Queue( TestVertex[] vertices, int startVertex, int vertexCount, PrimitiveType type ) { this.queuer.Queue(vertices, startVertex, vertexCount, type, this.drawContext); } /// Queues a series of indexed primitives /// Primitive vertices /// /// Index in the vertex array of the first vertex. This vertex will become /// the new index 0 for the index buffer. /// /// Number of vertices to draw /// Indices of the vertices to draw /// Index of the vertex index to begin drawing with /// Number of vertex indices to draw /// Type of primitives to draw public void Queue( TestVertex[] vertices, int startVertex, int vertexCount, short[] indices, int startIndex, int indexCount, PrimitiveType type ) { this.queuer.Queue( vertices, startVertex, vertexCount, indices, startIndex, indexCount, type, this.drawContext ); } /// Informs the queuer that a new drawing cycle is about to start public void Begin() { this.queuer.Begin(); } /// Informs the queuer that the current drawing cycle has ended public void End() { this.queuer.End(); } /// Batches that have been drawn so far public List> DrawnBatches { get { return this.batchDrawer.DrawnBatches; } } /// Deferred queuer being tested private DeferredQueuer queuer; /// Dummy batch drawer that records drawn vertices private DummyBatchDrawer batchDrawer; /// Dummy draw context that doesn't do a thing private DummyDrawContext drawContext; } #endregion // class Creator /// /// Verifies that new instances of the deferred queuer can be created /// [Test] public void TestConstructor() { using(Creator creator = new Creator()) { Assert.IsNotNull(creator); } } /// /// Tests a line strip drawing call which overflows the vertex batch size /// [Test] public void TestLineStripBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 39); creator.Queue(TestVertices, 0, 9, PrimitiveType.LineStrip); creator.Queue(test, 9, 30, PrimitiveType.LineStrip); } finally { creator.End(); } // First line strip with 9 supporting points Assert.AreEqual(subArray(TestVertices, 0, 9), creator.DrawnBatches[0]); // Second line strip, first batch Assert.AreEqual(subArray(TestVertices, 9, 7), creator.DrawnBatches[1]); // Second line strip, second batch, repeating cutoff vertex Assert.AreEqual(subArray(TestVertices, 15, 16), creator.DrawnBatches[2]); // Second line strip, third batch, repeating cutoff vertex Assert.AreEqual(subArray(TestVertices, 30, 9), creator.DrawnBatches[3]); } } /// /// Tests a line strip drawing call which overflows the vertex batch size /// and where no vertices can be placed in the first batch. /// [Test] public void TestLineStripBatchOverflowSkip() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 31); creator.Queue(TestVertices, 0, 15, PrimitiveType.LineStrip); creator.Queue(test, 15, 16, PrimitiveType.LineStrip); } finally { creator.End(); } // First line strip with 15 supporting points Assert.AreEqual(subArray(TestVertices, 0, 15), creator.DrawnBatches[0]); // Second line strip, should be unsplit in the second batch Assert.AreEqual(subArray(TestVertices, 15, 16), creator.DrawnBatches[1]); } } /// /// Tests a line list drawing call which overflows the vertex batch size /// [Test] public void TestLineListBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 40); creator.Queue(TestVertices, 0, 10, PrimitiveType.LineList); creator.Queue(test, 10, 30, PrimitiveType.LineList); } finally { creator.End(); } Assert.AreEqual(subArray(TestVertices, 0, 16), creator.DrawnBatches[0]); Assert.AreEqual(subArray(TestVertices, 16, 16), creator.DrawnBatches[1]); Assert.AreEqual(subArray(TestVertices, 32, 8), creator.DrawnBatches[2]); } } /// /// Tests a triangle strip drawing call which overflows the vertex batch size /// [Test] public void TestTriangleStripBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 39); creator.Queue(TestVertices, 0, 9, PrimitiveType.TriangleStrip); creator.Queue(test, 9, 30, PrimitiveType.TriangleStrip); } finally { creator.End(); } // First triangle strip with 9 supporting points Assert.AreEqual(subArray(TestVertices, 0, 9), creator.DrawnBatches[0]); // Second triangle strip, first batch Assert.AreEqual(subArray(TestVertices, 9, 7), creator.DrawnBatches[1]); // Second triangle strip, second batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 14, 15), creator.DrawnBatches[2]); // Second triangle strip, third batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 27, 12), creator.DrawnBatches[3]); } } /// /// Tests a triangle strip drawing call which overflows the vertex batch size /// with the first batch too full to hold the beginning of the strip /// [Test] public void TestTriangleStripBatchOverflowSkip() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 39); creator.Queue(TestVertices, 0, 13, PrimitiveType.TriangleStrip); creator.Queue(test, 13, 26, PrimitiveType.TriangleStrip); } finally { creator.End(); } // First triangle strip with 13 supporting points Assert.AreEqual(subArray(TestVertices, 0, 13), creator.DrawnBatches[0]); // Second triangle strip, first batch Assert.AreEqual(subArray(TestVertices, 13, 15), creator.DrawnBatches[1]); // Second triangle strip, second batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 26, 13), creator.DrawnBatches[2]); } } /// /// Tests a triangle list drawing call which overflows the vertex batch size /// [Test] public void TestTriangleListBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { TestVertex[] test = subArray(TestVertices, 0, 39); creator.Queue(TestVertices, 0, 15, PrimitiveType.TriangleList); creator.Queue(test, 15, 24, PrimitiveType.TriangleList); } finally { creator.End(); } Assert.AreEqual(subArray(TestVertices, 0, 15), creator.DrawnBatches[0]); Assert.AreEqual(subArray(TestVertices, 15, 15), creator.DrawnBatches[1]); Assert.AreEqual(subArray(TestVertices, 30, 9), creator.DrawnBatches[2]); } } /// /// Tests an indexed line strip drawing call which overflows the vertex batch size /// [Test] public void TestIndexedLineStripBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 10, 2 + 0 + 9, TestIndices, 0, 9, PrimitiveType.LineStrip ); // - Indices start at 2 ("index[0] == 2") // - First index used is index 9 (so vertices 11 - 41 will be drawn) // - Base vertex (offset that becomes vertex index 0) is 10 // -- Resulting in vertices 21 - 51 to be drawn creator.Queue( TestVertices, 10, 2 + 9 + 30, TestIndices, 9, 30, PrimitiveType.LineStrip ); } finally { creator.End(); } // First line strip with 9 supporting points Assert.AreEqual(subArray(TestVertices, 12, 9), creator.DrawnBatches[0]); // Second line strip, first batch Assert.AreEqual(subArray(TestVertices, 21, 5), creator.DrawnBatches[1]); // Second line strip, second batch, repeating cutoff vertex Assert.AreEqual(subArray(TestVertices, 25, 16), creator.DrawnBatches[2]); // Second line strip, third batch, repeating cutoff vertex Assert.AreEqual(subArray(TestVertices, 40, 11), creator.DrawnBatches[3]); } } /// /// Tests an indexed line strip drawing call which overflows the vertex batch size /// and where no vertices can be placed in the first batch. /// [Test] public void TestIndexedLineStripBatchOverflowSkip() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 0, 2 + 0 + 13, TestIndices, 0, 13, PrimitiveType.LineStrip ); // - Indices start at 2 ("index[0] == 2") // - First index used is index 13 (so vertices 15 - 31 will be drawn) // - Base vertex (offset that becomes vertex index 0) is 10 // -- Resulting in vertices 25 - 41 to be drawn creator.Queue( TestVertices, 10, 2 + 13 + 16, TestIndices, 13, 16, PrimitiveType.LineStrip ); } finally { creator.End(); } // First line strip with 15 supporting points Assert.AreEqual(subArray(TestVertices, 2, 13), creator.DrawnBatches[0]); // Second line strip, should be unsplit in the second batch Assert.AreEqual(subArray(TestVertices, 25, 16), creator.DrawnBatches[1]); } } /// /// Tests a indexed line list drawing call which overflows the vertex batch size /// [Test] public void TestIndexedLineListBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 0, 2 + 0 +10, TestIndices, 0, 10, PrimitiveType.LineList ); creator.Queue( TestVertices, 10, 2 + 10 + 30, TestIndices, 10, 30, PrimitiveType.LineList ); } finally { creator.End(); } TestVertex[] firstBatch = creator.DrawnBatches[0].ToArray(); Assert.AreEqual(subArray(TestVertices, 2, 10), subArray(firstBatch, 0, 10)); Assert.AreEqual(subArray(TestVertices, 22, 4), subArray(firstBatch, 10)); Assert.AreEqual(subArray(TestVertices, 26, 16), creator.DrawnBatches[1]); Assert.AreEqual(subArray(TestVertices, 42, 10), creator.DrawnBatches[2]); } } /// /// Tests an indexed triangle strip drawing call which overflows /// the vertex batch size /// [Test] public void TestIndexedTriangleStripBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 0, 7 + 2, TestIndices, 0, 7, PrimitiveType.TriangleStrip ); creator.Queue( TestVertices, 10, 30 + 2, TestIndices, 7, 30, PrimitiveType.TriangleStrip ); } finally { creator.End(); } // First triangle strip with 7 supporting points Assert.AreEqual(subArray(TestVertices, 0 + 2, 7), creator.DrawnBatches[0]); // Second triangle strip, first batch Assert.AreEqual(subArray(TestVertices, 17 + 2, 7), creator.DrawnBatches[1]); // Second triangle strip, second batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 22 + 2, 15), creator.DrawnBatches[2]); // Second triangle strip, third batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 35 + 2, 12), creator.DrawnBatches[3]); } } /// /// Tests an indexed triangle strip drawing call which overflows the vertex batch /// size with the first batch too full to hold the beginning of the strip /// [Test] public void TestIndexedTriangleStripBatchOverflowSkip() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 0, 11 + 2, TestIndices, 0, 11, PrimitiveType.TriangleStrip ); creator.Queue( TestVertices, 10, 26 + 2, TestIndices, 13, 26, PrimitiveType.TriangleStrip ); } finally { creator.End(); } // First triangle strip with 11 supporting points Assert.AreEqual(subArray(TestVertices, 0 + 2, 11), creator.DrawnBatches[0]); // Second triangle strip, first batch Assert.AreEqual(subArray(TestVertices, 23 + 2, 15), creator.DrawnBatches[1]); // Second triangle strip, second batch, repeating two vertices before cutoff Assert.AreEqual(subArray(TestVertices, 36 + 2, 13), creator.DrawnBatches[2]); } } /// /// Tests an indexed triangle list drawing call which overflows /// the vertex batch size /// [Test] public void TestIndexedTriangleListBatchOverflow() { using(Creator creator = new Creator()) { creator.Begin(); try { creator.Queue( TestVertices, 0, 13 + 2, TestIndices, 0, 13, PrimitiveType.TriangleList ); creator.Queue( TestVertices, 10, 24 + 2, TestIndices, 15, 24, PrimitiveType.TriangleList ); } finally { creator.End(); } Assert.AreEqual(subArray(TestVertices, 0 + 2, 13), creator.DrawnBatches[0]); Assert.AreEqual(subArray(TestVertices, 25 + 2, 15), creator.DrawnBatches[1]); Assert.AreEqual(subArray(TestVertices, 40 + 2, 9), creator.DrawnBatches[2]); } } /// Returns a subsection of an array as a new array /// /// Type of the elements being stored in the array /// /// Array from which a subsection will be extracted /// Start index in the array at which extration will begin /// /// An array containing only the elements within the specified range of /// the original array /// private static ElementType[] subArray(ElementType[] array, int start) { return subArray(array, start, array.Length - start); } /// Returns a subsection of an array as a new array /// /// Type of the elements being stored in the array /// /// Array from which a subsection will be extracted /// Start index in the array at which extration will begin /// Number of elements that will be extracted /// /// An array containing only the elements within the specified range of /// the original array /// private static ElementType[] subArray( ElementType[] array, int start, int count ) { ElementType[] subArray = new ElementType[count]; Array.Copy(array, start, subArray, 0, count); return subArray; } } } // namespace Nuclex.Graphics #endif // UNITTEST