using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; public class GuiBatcher { private List _vertices = new List(); private int _vbo; private int _vao; public GuiBatcher() { _vao = GL.GenVertexArray(); _vbo = GL.GenBuffer(); GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); // Position (2 floats) GL.EnableVertexAttribArray(0); GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), 0); // TexCoord (2 floats) GL.EnableVertexAttribArray(1); GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, 8 * sizeof(float), 2 * sizeof(float)); // Color (4 floats) GL.EnableVertexAttribArray(2); GL.VertexAttribPointer(2, 4, VertexAttribPointerType.Float, false, 8 * sizeof(float), 4 * sizeof(float)); } public void DrawQuad(float x, float y, float w, float h, Vector4 uv, Vector4 color) { // Two triangles (Standard Minecraft Blit) _vertices.Add(new UiVertex(x, y, uv.X, uv.Y, color)); // TL _vertices.Add(new UiVertex(x + w, y, uv.Z, uv.Y, color)); // TR _vertices.Add(new UiVertex(x, y + h, uv.X, uv.W, color)); // BL _vertices.Add(new UiVertex(x + w, y, uv.Z, uv.Y, color)); // TR _vertices.Add(new UiVertex(x + w, y + h, uv.Z, uv.W, color)); // BR _vertices.Add(new UiVertex(x, y + h, uv.X, uv.W, color)); // BL } public void Render() { if (_vertices.Count == 0) return; GL.BindVertexArray(_vao); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); var data = _vertices.ToArray(); GL.BufferData(BufferTarget.ArrayBuffer, data.Length * 8 * sizeof(float), data, BufferUsageHint.StreamDraw); GL.DrawArrays(PrimitiveType.Triangles, 0, _vertices.Count); _vertices.Clear(); // Reset for next frame } public void DrawString(string text, float x, float y, float size, Vector4 color) { float charStep = 1.0f / 16.0f; float currentX = x; foreach (char c in text) { int ascii = (int)c; int row = ascii / 16; int col = ascii % 16; float uStart = col * charStep; float uEnd = uStart + charStep; float vStart = 1.0f - (row * charStep); float vEnd = vStart - charStep; Vector4 uv = new Vector4( uStart, // U start vStart, // V start uEnd, // U end vEnd // V end ); DrawQuad(currentX, y, size, size, uv, color); float charWidthPixels = (CharWidth.GetWidth(c) + 1) / 8; float charWidthWorldUnits = size * charWidthPixels; currentX += charWidthWorldUnits; } } }