121 lines
5.3 KiB
C#
121 lines
5.3 KiB
C#
using System;
|
|
using System.Drawing;
|
|
using System.Numerics;
|
|
using SlatedGameToolkit.Framework.Graphics.Meshes;
|
|
using SlatedGameToolkit.Framework.Graphics;
|
|
using SlatedGameToolkit.Framework.Graphics.Textures;
|
|
using SlatedGameToolkit.Framework.Graphics.Shaders;
|
|
using SlatedGameToolkit.Framework.Graphics.Programs;
|
|
using SlatedGameToolkit.Framework.Exceptions;
|
|
|
|
namespace SlatedGameToolkit.Framework.Graphics.Render
|
|
{
|
|
public class Batch : IDisposable {
|
|
private int projLoc, viewLoc, modelLoc;
|
|
private Camera camera;
|
|
private GLShaderProgram shaderProgram;
|
|
private Texture texture;
|
|
private bool disposed;
|
|
private VertexArray vertexArray;
|
|
private const int VERTEX_LENGTH = 9;
|
|
private GLMultiDrawElements multiDrawElements;
|
|
public bool Batching { get; private set; }
|
|
|
|
private Matrix4x4 modelsMatrix;
|
|
private float[] data;
|
|
private uint[] indices;
|
|
private uint[] lengths;
|
|
private uint[] offsets;
|
|
private uint dataIndex, indicesIndex, lengthsIndex;
|
|
|
|
public Batch(Camera camera, GLShaderProgram shaderProgram, uint BatchVertexSize = 4096) {
|
|
multiDrawElements = OpenGL.RetrieveGLDelegate<GLMultiDrawElements>("glMultiDrawElements");
|
|
this.camera = camera;
|
|
this.shaderProgram = shaderProgram;
|
|
indices = new uint[BatchVertexSize];
|
|
lengths = new uint[BatchVertexSize];
|
|
offsets = new uint[BatchVertexSize];
|
|
data = new float[BatchVertexSize * VERTEX_LENGTH];
|
|
vertexArray = new VertexArray();
|
|
GLGetAttribLocation attribLocation = OpenGL.RetrieveGLDelegate<GLGetAttribLocation>("glGetAttribLocation");
|
|
VertexAttributeDefinition[] definitions = new VertexAttributeDefinition[3];
|
|
definitions[0] = new VertexAttributeDefinition((uint)shaderProgram.GetAttributeLocation("aPosition"), 3, 3 * sizeof(float), 0);
|
|
definitions[1] = new VertexAttributeDefinition((uint)shaderProgram.GetAttributeLocation("aColor"), 4, 4 * sizeof(float), 3 * sizeof(float));
|
|
definitions[2] = new VertexAttributeDefinition((uint)shaderProgram.GetAttributeLocation("aTexCoord"), 2, 2 * sizeof(float), (4 + 3) * sizeof(float));
|
|
modelLoc = shaderProgram.GetUniformLocation("models");
|
|
viewLoc = shaderProgram.GetUniformLocation("view");
|
|
projLoc = shaderProgram.GetUniformLocation("projection");
|
|
vertexArray.defineVertexAttributes(definitions: definitions);
|
|
}
|
|
|
|
public virtual void Begin(Texture texture, Matrix4x4 modelsMatrix) {
|
|
if (Batching) throw new InvalidOperationException("This batch is already started.");
|
|
this.texture = texture ?? throw new ArgumentNullException("texture");
|
|
this.Batching = true;
|
|
this.modelsMatrix = modelsMatrix;
|
|
}
|
|
|
|
public virtual void Dispose()
|
|
{
|
|
if (disposed) return;
|
|
if (Batching) End();
|
|
disposed = true;
|
|
vertexArray.Dispose();
|
|
}
|
|
|
|
public virtual void Add(IMeshable meshable, Color color) {
|
|
ValueTuple<Vector3, Vector2>[] vertices = meshable.Vertices;
|
|
uint[] indices = meshable.Elements;
|
|
if (vertices.Length * VERTEX_LENGTH + dataIndex >= data.Length || indices.Length + indicesIndex >= indicesIndex) Flush();
|
|
for (int i = 0; i < vertices.Length; i++) {
|
|
data[dataIndex] = vertices[i].Item1.X;
|
|
dataIndex++;
|
|
data[dataIndex] = vertices[i].Item1.Y;
|
|
dataIndex++;
|
|
data[dataIndex] = vertices[i].Item1.Z;
|
|
dataIndex++;
|
|
|
|
data[dataIndex] = (float) color.A / byte.MaxValue;
|
|
dataIndex++;
|
|
data[dataIndex] = (float) color.R / byte.MaxValue;
|
|
dataIndex++;
|
|
data[dataIndex] = (float) color.G / byte.MaxValue;
|
|
dataIndex++;
|
|
data[dataIndex] = (float) color.B / byte.MaxValue;
|
|
dataIndex++;
|
|
|
|
data[dataIndex] = vertices[i].Item2.X;
|
|
dataIndex++;
|
|
data[dataIndex] = vertices[i].Item2.Y;
|
|
dataIndex++;
|
|
|
|
uint elementsCount = (uint)indices.Length;
|
|
Array.Copy(indices, indices, elementsCount);
|
|
indicesIndex += elementsCount;
|
|
|
|
lengths[lengthsIndex] = elementsCount;
|
|
lengthsIndex ++;
|
|
}
|
|
}
|
|
|
|
public virtual void End() {
|
|
if (!Batching) throw new InvalidOperationException("This batch was never started.");
|
|
this.Batching = false;
|
|
Flush();
|
|
}
|
|
|
|
protected virtual void Flush() {
|
|
texture.Use();
|
|
vertexArray.Use();
|
|
vertexArray.BufferVertices(data);
|
|
vertexArray.BufferIndices(indices);
|
|
dataIndex = 0;
|
|
indicesIndex = 0;
|
|
lengthsIndex = 0;
|
|
shaderProgram.SetUniformMatrix4x4(modelLoc, modelsMatrix);
|
|
shaderProgram.SetUniformMatrix4x4(viewLoc, camera.ViewMatrix);
|
|
shaderProgram.SetUniformMatrix4x4(projLoc, camera.ProjectionMatrix);
|
|
multiDrawElements(GLEnum.GL_TRIANGLE_STRIP, lengths, GLEnum.GL_UNSIGNED_INT, offsets, lengths.Length);
|
|
}
|
|
}
|
|
} |