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;
///
/// Creates a batch used to draw primitives.
///
/// The current graphics device being used.
/// The current camera being used.
/// The amount of vertices every batch can hold before flushing. Default is 450.
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];
}
///
/// Starts the batch. Batch cannot be started twice.
///
/// The type of primitive this batch would be drawing.
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;
}
///
/// Ends the batch. Begin needs to be called before end.
///
public void End()
{
if (!began) throw new InvalidOperationException("Begin must be called before ending.");
Flush();
}
///
/// Adds a vertex position for the primitive being drawn. The batch needs to have beens started before this.
///
/// The vector that represents the vertex.
/// The color of that vertex.
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++;
}
///
/// Flushes the batch. Automatically called if required.
///
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;
}
}
}
}