#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 using System; using System.Collections.Generic; using Microsoft.Xna.Framework.Graphics; namespace Nuclex.Graphics.Batching { /// Collects vertices into batches to improve rendering performance /// Type of vertices to be batched /// /// This class is very similar to the SpriteBatch class, but instead of being /// specialized for sprite rendering, it handles all kinds of primitives. /// It is ideal for dynamic, CPU-calculated geometry such as particle systems, /// fluid visualization or marching cube/tetrahedron-based geometry. /// public class PrimitiveBatch : IDisposable where VertexType : struct, IVertexType { /// Maximum number of vertices or indices in a single batch public const int BatchSize = 8192; /// Initializes a new primitive batcher /// /// Graphics device the primitive batcher will use /// public PrimitiveBatch(GraphicsDevice graphicsDevice) : this(GetDefaultBatchDrawer(graphicsDevice)) { } /// Initializes a new primitive batcher /// /// Vertex batch drawer that will be used by the primitive batcher /// internal PrimitiveBatch(IBatchDrawer batchDrawer) { this.batchDrawer = batchDrawer; this.queueingStrategy = QueueingStrategy.Immediate; this.primitiveQueuer = new ImmediateQueuer(this.batchDrawer); } /// /// Immediately releases all resources owned by the primitive batch /// public void Dispose() { if(this.primitiveQueuer != null) { this.primitiveQueuer.Dispose(); this.primitiveQueuer = null; } if(this.batchDrawer != null) { IDisposable disposable = this.batchDrawer as IDisposable; if(disposable != null) { disposable.Dispose(); } this.batchDrawer = null; } } /// Begins the drawing process /// /// By what criteria to queue primitives and when to draw them /// public void Begin(QueueingStrategy queueingStrategy) { // If the queueing strategy hast changed from the last frame, we need to // build a new queuer for the selected strategy if(queueingStrategy != this.queueingStrategy) { this.primitiveQueuer.Dispose(); switch(queueingStrategy) { case QueueingStrategy.Immediate: { this.primitiveQueuer = new ImmediateQueuer(this.batchDrawer); break; } case QueueingStrategy.Deferred: { this.primitiveQueuer = new DeferredQueuer(this.batchDrawer); break; } case QueueingStrategy.Context: { this.primitiveQueuer = new DrawContextQueuer(this.batchDrawer); break; } default: { throw new ArgumentException( "Invalid queueing strategy specified", "queueingStrategy" ); } } this.queueingStrategy = queueingStrategy; } // Tell the queuer that a new drawing cycle has started this.primitiveQueuer.Begin(); } /// Ends the drawing process public void End() { // Tell the queuer that the current drawing cycle has ended this.primitiveQueuer.End(); } /// Draws a series of triangles /// Triangle vertices /// Desired graphics device settings for the primitives public void Draw(VertexType[] vertices, DrawContext context) { this.primitiveQueuer.Queue( vertices, 0, vertices.Length, PrimitiveType.TriangleList, context ); } /// Draws a series of primitives /// Primitive vertices /// Type of primitives to draw /// Desired graphics device settings for the primitives public void Draw(VertexType[] vertices, PrimitiveType type, DrawContext context) { this.primitiveQueuer.Queue(vertices, 0, vertices.Length, type, context); } /// Draws a series of primitives /// Primitive vertices /// Index of vertex to begin drawing with /// Number of vertices to draw /// Type of primitives to draw /// Desired graphics device settings for the primitives public void Draw( VertexType[] vertices, int startVertex, int vertexCount, PrimitiveType type, DrawContext context ) { this.primitiveQueuer.Queue(vertices, 0, vertices.Length, type, context); } /// Draws a series of indexed triangles /// Triangle vertices /// Indices of the vertices to draw /// Desired graphics device settings for the primitives public void Draw(VertexType[] vertices, short[] indices, DrawContext context) { this.primitiveQueuer.Queue( vertices, 0, vertices.Length, indices, 0, indices.Length, PrimitiveType.TriangleList, context ); } /// Draws a series of indexed primitives /// Primitive vertices /// Indices of the vertices to draw /// Type of primitives to draw /// Desired graphics device settings for the primitives public void Draw( VertexType[] vertices, short[] indices, PrimitiveType type, DrawContext context ) { this.primitiveQueuer.Queue( vertices, 0, vertices.Length, indices, 0, indices.Length, type, context ); } /// Draws 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 /// Desired graphics device settings for the primitives public void Draw( VertexType[] vertices, int startVertex, int vertexCount, short[] indices, int startIndex, int indexCount, PrimitiveType type, DrawContext context ) { this.primitiveQueuer.Queue( vertices, startVertex, vertexCount, indices, startIndex, indexCount, type, context ); } /// Returns the default batch drawer for the target platform /// Graphics device that batch drawer will use /// /// A new instance of the default batch drawer for the target platform /// internal static IBatchDrawer GetDefaultBatchDrawer( GraphicsDevice graphicsDevice ) { return new DynamicBufferBatchDrawer(graphicsDevice); } /// Sends batches of vertices to the GPU for drawing private IBatchDrawer batchDrawer; /// Controls how primitives are queued (selects queuer) private QueueingStrategy queueingStrategy; /// Queues vertices and initiates rendering when needed private Queuer primitiveQueuer; } } // namespace Nuclex.Graphics.Batching