#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