#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 Nuclex.Testing.Xna;
using TestVertex = Microsoft.Xna.Framework.Graphics.VertexPositionColor;
using System.Threading;
namespace Nuclex.Graphics.Batching {
/// Unit tests for the primitive batcher
[TestFixture]
internal class PrimitiveBatchTest {
#region class DummyDrawContext
/// Drawing context used for the unit test
private class DummyDrawContext : DrawContext {
/// Number of passes this draw context requires for rendering
public override int Passes {
get { return 0; }
}
/// Prepares the graphics device for drawing
/// Index of the pass to begin rendering
///
/// Should only be called between the normal Begin() and End() methods.
///
public override void Apply(int pass) { }
/// Tests whether another draw context is identical to this one
/// Other context to check for equality
/// True if the other context is identical to this one
public override bool Equals(DrawContext otherContext) {
return ReferenceEquals(this, otherContext);
}
}
#endregion // class TestDrawContext
#region class PrimitiveBatchCreator
/// Helper class that automates primitive batcher creation
private class PrimitiveBatchCreator : IDisposable {
/// Initializes a new primitive batch creator
public PrimitiveBatchCreator() {
this.mockedGraphicsDeviceService = new MockedGraphicsDeviceService();
this.graphicsDeviceKeeper = this.mockedGraphicsDeviceService.CreateDevice();
this.vertexDeclaration = TestVertex.VertexDeclaration;
this.primitiveBatch = new PrimitiveBatch(
this.mockedGraphicsDeviceService.GraphicsDevice
);
}
/// Immediately releases all resources owned by the instance
public void Dispose() {
if(this.primitiveBatch != null) {
this.primitiveBatch.Dispose();
this.primitiveBatch = null;
}
if(this.graphicsDeviceKeeper != null) {
this.graphicsDeviceKeeper.Dispose();
this.graphicsDeviceKeeper = null;
}
this.mockedGraphicsDeviceService = null;
}
/// Mocked graphics device service used for rendering
public MockedGraphicsDeviceService MockedGraphicsDeviceService {
get { return this.mockedGraphicsDeviceService; }
}
/// Primitive batch the primitive batch creator has created
public PrimitiveBatch PrimitiveBatch {
get { return this.primitiveBatch; }
}
///
/// The mocked graphics device sevice providing the graphics device for testing
///
private MockedGraphicsDeviceService mockedGraphicsDeviceService;
/// Keeps the graphics device alive until disposed
private IDisposable graphicsDeviceKeeper;
/// Declaration for the vertex structure we're using in the tests
private VertexDeclaration vertexDeclaration;
/// Primitive batcher being tested
private PrimitiveBatch primitiveBatch;
}
#endregion // class PrimitiveBatchCreator
///
/// Tests whether the constructor of the primitve batcher is working
///
[Test]
public void TestConstructor() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
Assert.IsNotNull(creator.PrimitiveBatch);
}
}
///
/// Tests whether the different queueing strategies can be selected
///
[Test]
public void TestStrategySwitching() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
creator.PrimitiveBatch.End();
creator.PrimitiveBatch.Begin(QueueingStrategy.Deferred);
creator.PrimitiveBatch.End();
creator.PrimitiveBatch.Begin(QueueingStrategy.Context);
creator.PrimitiveBatch.End();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
creator.PrimitiveBatch.End();
}
}
///
/// Verifies that an exception is thrown if an invalid queueing strategy
/// is chosen
///
[Test]
public void TestInvalidStrategy() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
Assert.Throws(
delegate() {
creator.PrimitiveBatch.Begin((QueueingStrategy)(-1));
creator.PrimitiveBatch.End();
}
);
}
}
///
/// Verifies that the primitive batcher can draw all kinds of primitives
///
[Test]
public void TestDrawPrimitives() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
DummyDrawContext dummy = new DummyDrawContext();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
try {
creator.PrimitiveBatch.Draw(
new TestVertex[10], PrimitiveType.LineList, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[10], PrimitiveType.LineStrip, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[9], PrimitiveType.TriangleList, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[10], PrimitiveType.TriangleStrip, dummy
);
}
finally {
creator.PrimitiveBatch.End();
}
}
}
///
/// Verifies that the primitive batcher can draw all kinds of primitives
/// using an index array
///
[Test]
public void TestDrawIndexedPrimitives() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
DummyDrawContext dummy = new DummyDrawContext();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
try {
creator.PrimitiveBatch.Draw(
new TestVertex[10], createIndices(10), PrimitiveType.LineList, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[10], createIndices(10), PrimitiveType.LineStrip, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[9], createIndices(9), PrimitiveType.TriangleList, dummy
);
creator.PrimitiveBatch.Draw(
new TestVertex[10], createIndices(10), PrimitiveType.TriangleStrip, dummy
);
}
finally {
creator.PrimitiveBatch.End();
}
}
}
///
/// Tests whether the primitive batch is able to draw a list of triangles
///
[Test]
public void TestDrawTriangles() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
DummyDrawContext dummy = new DummyDrawContext();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
creator.PrimitiveBatch.Draw(new VertexPositionColor[9], dummy);
creator.PrimitiveBatch.End();
}
}
///
/// Tests whether the primitive batch is able to draw a list of triangles
/// indexed by an index array
///
[Test]
public void TestDrawIndexedTriangles() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
DummyDrawContext dummy = new DummyDrawContext();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
creator.PrimitiveBatch.Draw(
new VertexPositionColor[9], createIndices(9), dummy
);
creator.PrimitiveBatch.End();
}
}
///
/// Verifies that the primitive batcher can survive a graphics device reset
///
[Test]
public void TestGraphicsDeviceReset() {
using(PrimitiveBatchCreator creator = new PrimitiveBatchCreator()) {
DummyDrawContext dummy = new DummyDrawContext();
// Simulate a graphics device reset
creator.MockedGraphicsDeviceService.ResetDevice();
creator.PrimitiveBatch.Begin(QueueingStrategy.Immediate);
creator.PrimitiveBatch.Draw(new VertexPositionColor[9], dummy);
creator.PrimitiveBatch.End();
}
}
/// Creates a list of sequential indices
/// Number of indices to generate
/// An array containing the generated indices
private static short[] createIndices(int count) {
short[] indices = new short[9];
for(short index = 0; index < 9; ++index) {
indices[index] = index;
}
return indices;
}
}
} // namespace Nuclex.Graphics
#endif // UNITTEST