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; } /// /// Disposes all the handles and shaders. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~Batch() { Dispose(false); } } }