recrownedgtk/RecrownedGTK/Graphics/Render/Batch.cs

130 lines
4.6 KiB
C#

using RecrownedGTK.Graphics.Render.Shaders;
using System;
using OpenTK;
using OpenTK.Graphics.OpenGL;
namespace RecrownedGTK.Graphics.Render {
public class Batch : IDisposable {
private bool disposed;
private bool begun;
private readonly float[] vertices;
private TextureData textureData;
private VertexAttributesArrayHandle vertexAttributes;
private Shader shader;
private VertexBufferArrayHandle bufferArrayHandle;
private uint[] indices;
private ElementBufferArrayHandle elementBufferArray;
private Matrix4 transformMatrix;
private uint vertPosition;
private int indicePosition;
public Batch(int verticesLimit = 300, int elementLimit = 450) {
elementBufferArray = new ElementBufferArrayHandle();
bufferArrayHandle = new VertexBufferArrayHandle();
vertices = new float[verticesLimit*9];
indices = new uint[elementLimit];
}
public void Begin(VertexAttributesArrayHandle vertexAttributesArray = null, Shader shader = null) {
if (begun) throw new InvalidOperationException("This TextureBatch has already been started.");
this.shader = shader ?? this.shader ?? Shader.CreateBasicShader();
this.vertexAttributes = vertexAttributes ?? this.vertexAttributes ?? VertexAttributesArrayHandle.CreateBasicVA(ref transformMatrix, this.shader);
begun = true;
}
public void Draw(IDrawable drawable) {
TextureData textureData = null;
VertexInformation[] vertices = null;
uint[] indices = null;
drawable.Draw(out vertices, out indices, out textureData);
// If the new set of vertices are greater than the max length, we flush.
if (vertices.Length * 9 + vertPosition > this.vertices.Length) {
Flush();
}
// Flush if the texture is changed.
if (!this.textureData.Equals(textureData)) {
Flush();
this.textureData = textureData;
}
if (indices.Length + indicePosition > this.indices.Length) {
Flush();
}
// Indices.
for (int indIndex = 0; indIndex < indices.Length; indIndex++) {
this.indices[indicePosition] = indices[indIndex] + vertPosition;
indicePosition++;
}
for (int vertIndex = 0; vertIndex < vertices.Length; vertIndex++) {
VertexInformation curr = vertices[vertIndex];
this.vertices[vertPosition] = curr.coords.X;
vertPosition++;
this.vertices[vertPosition] = curr.coords.Y;
vertPosition++;
this.vertices[vertPosition] = curr.coords.Z;
vertPosition++;
this.vertices[vertPosition] = curr.textureCoords.X;
vertPosition++;
this.vertices[vertPosition] = curr.textureCoords.Y;
vertPosition++;
this.vertices[vertPosition] = curr.color.R;
vertPosition++;
this.vertices[vertPosition] = curr.color.G;
vertPosition++;
this.vertices[vertPosition] = curr.color.B;
vertPosition++;
this.vertices[vertPosition] = curr.color.A;
vertPosition++;
}
}
private void Flush() {
if (vertPosition == 0) return;
indicePosition = 0;
vertPosition = 0;
vertexAttributes.Bind();
shader.Use();
bufferArrayHandle.Buffer(vertices);
elementBufferArray.Buffer(indices);
GL.DrawElements(PrimitiveType.Triangles, indicePosition, DrawElementsType.UnsignedInt, 0);
}
public void End() {
if (!begun) throw new InvalidOperationException("The TextureBatch has not begun.");
Flush();
begun = false;
}
protected virtual void Dispose(bool disposing) {
if (disposed) return;
if (disposing) {
elementBufferArray.Dispose();
vertexAttributes.Dispose();
bufferArrayHandle.Dispose();
shader.Dispose();
}
disposed = true;
}
/// <summary>
/// Disposes all the handles and shaders.
/// </summary>
public void Dispose() {
Dispose(true);
GC.SuppressFinalize(this);
}
~Batch() {
Dispose(false);
}
}
}