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; } } } }