recrownedgtk/RecrownedAthenaeum/Render/PrimitiveBatch.cs

115 lines
4.4 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;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace RecrownedAthenaeum.Render
{
public class PrimitiveBatch : IDisposable
{
2019-01-12 05:11:45 +00:00
List<VertexPositionColor> vertices;
int maxVertices;
2019-01-12 04:09:42 +00:00
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>
2019-01-12 05:11:45 +00:00
/// <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. Especially if using strip primitive types.</param>
public PrimitiveBatch(GraphicsDevice graphicsDevice, Camera2D camera, int verticesPerBatch = 500)
2019-01-12 04:09:42 +00:00
{
this.graphicsDevice = graphicsDevice ?? throw new ArgumentNullException("Graphics device can't be null.");
2019-01-12 05:11:45 +00:00
maxVertices = verticesPerBatch;
2019-01-12 04:09:42 +00:00
basicEffect = new BasicEffect(graphicsDevice);
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.");
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 (!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.");
2019-01-12 05:11:45 +00:00
if (primitiveType != PrimitiveType.LineStrip && primitiveType != PrimitiveType.TriangleStrip && bufferPosition + verticesPerPrimitive >= maxVertices && (bufferPosition % maxVertices == 0))
2019-01-12 04:09:42 +00:00
{
Flush();
}
2019-01-12 05:11:45 +00:00
vertices[bufferPosition] = new VertexPositionColor(new Vector3(vertex, 0), color);
2019-01-12 04:09:42 +00:00
bufferPosition++;
}
/// <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 (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;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
if (disposing && !isDisposed)
{
basicEffect.Dispose();
isDisposed = true;
}
}
}
}