recrownedgtk/RecrownedAthenaeum/Render/PrimitiveBatch.cs

117 lines
4.1 KiB
C#

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using RecrownedAthenaeum.Camera;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RecrownedAthenaeum.Render
{
public class PrimitiveBatch : IDisposable
{
VertexPositionColor[] vertices;
int MaxVertices { get { return vertices.Length; } }
int bufferPosition;
BasicEffect basicEffect;
PrimitiveType primitiveType;
int verticesPerPrimitive;
GraphicsDevice graphicsDevice;
bool began;
bool isDisposed;
/// <summary>
/// Creates a batch used to draw primitives.
/// </summary>
/// <param name="graphicsDevice">The current graphics device being used.</param>
/// <param name="camera">The current camera being used.</param>
/// <param name="verticesPerBatch">The amount of vertices every batch can hold before flushing. Default is 450.</param>
public PrimitiveBatch(GraphicsDevice graphicsDevice, Camera2D camera, int verticesPerBatch = 450)
{
this.graphicsDevice = graphicsDevice ?? throw new ArgumentNullException("Graphics device can't be null.");
basicEffect = new BasicEffect(graphicsDevice);
basicEffect.VertexColorEnabled = true;
basicEffect.View = camera.Matrix;
vertices = new VertexPositionColor[verticesPerBatch];
}
/// <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.");
this.primitiveType = primitiveType;
this.verticesPerPrimitive = 0;
switch (primitiveType)
{
case PrimitiveType.LineList: verticesPerPrimitive = 2; break;
case PrimitiveType.TriangleList: verticesPerPrimitive = 3; break;
}
basicEffect.CurrentTechnique.Passes[0].Apply();
began = true;
}
/// <summary>
/// Ends the batch. Begin needs to be called before end.
/// </summary>
public void End()
{
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 (bufferPosition + verticesPerPrimitive >= MaxVertices && (bufferPosition % MaxVertices == 0))
{
Flush();
}
vertices[bufferPosition].Position = (new Vector3(vertex, 0));
vertices[bufferPosition].Color = color;
bufferPosition++;
}
/// <summary>
/// Flushes the batch. Automatically called if required.
/// </summary>
public void Flush()
{
if (!began) throw new InvalidOperationException("Begin needs to be called before flushing.");
if (bufferPosition == 0) return;
graphicsDevice.DrawUserPrimitives(primitiveType, vertices, 0, bufferPosition / verticesPerPrimitive);
bufferPosition = 0;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (disposing && !isDisposed)
{
basicEffect.Dispose();
isDisposed = true;
}
}
}
}