recrownedgtk/RecrownedAthenaeum/Render/PrimitiveBatch.cs

146 lines
6.0 KiB
C#
Raw Normal View History

2019-01-12 04:09:42 +00:00
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
using System.Collections.Generic;
namespace RecrownedAthenaeum.Render
{
2019-01-14 07:26:46 +00:00
/// <summary>
/// A batch used to draw primitive shapes by batching together vertices.
/// </summary>
2019-01-12 04:09:42 +00:00
public class PrimitiveBatch : IDisposable
{
2019-01-12 05:11:45 +00:00
List<VertexPositionColor> vertices;
2019-01-14 07:26:46 +00:00
/// <summary>
/// The maximum vertices expected. The further off this expectancy is from the true value, the less efficient.
/// </summary>
public int MaxVertices { get { return vertices.Capacity; } set { vertices.Capacity = value; } }
2019-01-12 04:09:42 +00:00
int bufferPosition;
BasicEffect basicEffect;
PrimitiveType primitiveType;
int verticesPerPrimitive;
GraphicsDevice graphicsDevice;
2019-01-12 04:09:42 +00:00
bool began;
bool disposed;
2019-01-12 04:09:42 +00:00
/// <summary>
/// Creates a batch used to draw primitives.
/// </summary>
/// <param name="camera">The current camera being used. Will use default set in <see cref="Configuration"/> if left null.</param>
2019-01-22 04:18:22 +00:00
/// <param name="graphicsDevice">The graphics device used to draw the primitives. Will be using <see cref="Configuration"/>'s graphics device from graphics device manager if null. Default is null.</param>
/// <param name="verticesPerBatch">The amount of vertices every batch can hold before flushing. Default is 450. Should be changed to be the most optimal number if possible to prevent unnecessary resizing. Especially if using strip primitive types.</param>
public PrimitiveBatch(Camera2D camera = null, GraphicsDevice graphicsDevice = null, int verticesPerBatch = 500)
2019-01-12 04:09:42 +00:00
{
this.graphicsDevice = graphicsDevice ?? (Configuration.GraphicsDeviceManager.GraphicsDevice);
camera = camera ?? (Configuration.Camera2D);
basicEffect = new BasicEffect(this.graphicsDevice);
2019-01-12 04:09:42 +00:00
basicEffect.VertexColorEnabled = true;
basicEffect.View = camera.Matrix;
2019-01-12 05:11:45 +00:00
vertices = new List<VertexPositionColor>(verticesPerBatch);
2019-01-12 04:09:42 +00:00
}
/// <summary>
/// Starts the batch. Batch cannot be started twice.
/// </summary>
/// <param name="primitiveType">The type of primitive this batch would be drawing.</param>
public void Begin(PrimitiveType primitiveType)
{
if (began) throw new InvalidOperationException("Begin is being called twice before being ended.");
if (disposed) throw new ObjectDisposedException(this.GetType().Name);
2019-01-12 04:09:42 +00:00
this.primitiveType = primitiveType;
2019-01-12 05:11:45 +00:00
verticesPerPrimitive = 0;
2019-01-12 04:09:42 +00:00
switch (primitiveType)
{
case PrimitiveType.LineList: verticesPerPrimitive = 2; break;
case PrimitiveType.TriangleList: verticesPerPrimitive = 3; break;
2019-01-12 05:11:45 +00:00
default: verticesPerPrimitive = 1; break;
2019-01-12 04:09:42 +00:00
}
basicEffect.CurrentTechnique.Passes[0].Apply();
began = true;
}
/// <summary>
/// Ends the batch. Begin needs to be called before end.
/// </summary>
public void End()
{
if (disposed) throw new ObjectDisposedException(this.GetType().Name);
2019-01-12 04:09:42 +00:00
if (!began) throw new InvalidOperationException("Begin must be called before ending.");
Flush();
}
/// <summary>
/// Adds a vertex position for the primitive being drawn. The batch needs to have beens started before this.
/// </summary>
/// <param name="vertex">The vector that represents the vertex.</param>
/// <param name="color">The color of that vertex.</param>
public void AddVertex(Vector2 vertex, Color color)
{
if (!began) throw new InvalidOperationException("Begin needs to be called before adding vertex.");
if (disposed) throw new ObjectDisposedException(this.GetType().Name);
if (bufferPosition + verticesPerPrimitive >= MaxVertices && (bufferPosition % MaxVertices == 0))
2019-01-12 04:09:42 +00:00
{
if (primitiveType != PrimitiveType.LineStrip && primitiveType != PrimitiveType.TriangleStrip)
{
Flush();
2019-01-14 07:26:46 +00:00
}
else
{
throw new InvalidOperationException("Buffer size isn't large enough.");
}
2019-01-12 04:09:42 +00:00
}
vertices.Add(new VertexPositionColor(new Vector3(vertex, 0), color));
bufferPosition = vertices.Count;
2019-01-12 04:09:42 +00:00
}
/// <summary>
2019-01-12 05:11:45 +00:00
/// Flushes the batch. Automatically called if required if using <see cref="PrimitiveType.LineList"/> or <see cref="PrimitiveType.TriangleList"/>. Otherwise, manual flushing is required.
2019-01-12 04:09:42 +00:00
/// </summary>
public void Flush()
{
if (!began) throw new InvalidOperationException("Begin needs to be called before flushing.");
if (disposed) throw new ObjectDisposedException(this.GetType().Name);
2019-01-12 04:09:42 +00:00
if (bufferPosition == 0) return;
2019-01-12 05:11:45 +00:00
graphicsDevice.DrawUserPrimitives(primitiveType, vertices.ToArray(), 0, bufferPosition / verticesPerPrimitive);
2019-01-12 04:09:42 +00:00
bufferPosition = 0;
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// Disposes this.
/// </summary>
2019-01-12 04:09:42 +00:00
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// Overridable dispose.
/// </summary>
/// <param name="disposing">True for when user called for this to be disposed. False otherwise.</param>
public virtual void Dispose(bool disposing)
2019-01-12 04:09:42 +00:00
{
2019-01-14 07:26:46 +00:00
if (disposed) throw new ObjectDisposedException(this.GetType().Name);
disposed = true;
if (disposing && !disposed)
2019-01-12 04:09:42 +00:00
{
basicEffect.Dispose();
}
}
2019-01-14 07:26:46 +00:00
/// <summary>
/// Destructor.
/// </summary>
~PrimitiveBatch()
{
Dispose(false);
}
2019-01-12 04:09:42 +00:00
}
}