#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