#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