namespace TheLabs; using LearnOpenTK.Common; using OpenTK.Graphics.OpenGL4; using OpenTK.Mathematics; using OpenTK.Windowing.Desktop; using StbImageSharp; public class Mesh : IDisposable { private readonly int _vao; private readonly int _vbo; private readonly int _ebo; private readonly int _vertexCount; private readonly bool _useIndices; // A flexible way to define vertex layout // (Could be an enum or a struct) public enum VertexLayout { PosColor, PosTex } public Mesh(float[] vertices, uint[] indices, VertexLayout layout) { _vertexCount = indices.Length; _useIndices = true; _vao = GL.GenVertexArray(); GL.BindVertexArray(_vao); _vbo = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw); _ebo = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ElementArrayBuffer, _ebo); GL.BufferData(BufferTarget.ElementArrayBuffer, indices.Length * sizeof(uint), indices, BufferUsageHint.StaticDraw); // --- Set up Vertex Attributes based on layout --- if (layout == VertexLayout.PosColor) { // layout(location = 0) in shader: vec3 position var stride = 7 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); // layout(location = 1) in shader: vec4 color GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float)); GL.EnableVertexAttribArray(1); } else if (layout == VertexLayout.PosTex) { // layout(location = 0) in shader: vec3 position var stride = 5 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); // layout(location = 1) in shader: vec2 texCoord GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float)); GL.EnableVertexAttribArray(1); } // ... (you could add more layouts) GL.BindVertexArray(0); } // Constructor for non-indexed drawing (like your Circle) public Mesh(float[] vertices, VertexLayout layout) { // Calculate vertex count based on stride if (layout == VertexLayout.PosColor) _vertexCount = vertices.Length / 7; else // PosTex _vertexCount = vertices.Length / 5; _useIndices = false; _ebo = 0; // No EBO _vao = GL.GenVertexArray(); GL.BindVertexArray(_vao); _vbo = GL.GenBuffer(); GL.BindBuffer(BufferTarget.ArrayBuffer, _vbo); GL.BufferData(BufferTarget.ArrayBuffer, vertices.Length * sizeof(float), vertices, BufferUsageHint.StaticDraw); // --- Set up Vertex Attributes based on layout --- if (layout == VertexLayout.PosColor) { // layout(location = 0) in shader: vec3 position var stride = 7 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); // layout(location = 1) in shader: vec4 color GL.VertexAttribPointer(1, 4, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float)); GL.EnableVertexAttribArray(1); } else if (layout == VertexLayout.PosTex) { // layout(location = 0) in shader: vec3 position var stride = 5 * sizeof(float); GL.VertexAttribPointer(0, 3, VertexAttribPointerType.Float, false, stride, 0); GL.EnableVertexAttribArray(0); // layout(location = 1) in shader: vec2 texCoord GL.VertexAttribPointer(1, 2, VertexAttribPointerType.Float, false, stride, 3 * sizeof(float)); GL.EnableVertexAttribArray(1); } GL.BindVertexArray(0); } // Draw the mesh. Notice it doesn't know about shaders or matrices! public void Draw() { GL.BindVertexArray(_vao); if (_useIndices) { GL.DrawElements(PrimitiveType.Triangles, _vertexCount, DrawElementsType.UnsignedInt, 0); } else { // For your Circle (which used TriangleFan) GL.DrawArrays(PrimitiveType.TriangleFan, 0, _vertexCount); } } public void Dispose() { GL.DeleteBuffer(_vbo); GL.DeleteBuffer(_ebo); GL.DeleteVertexArray(_vao); } }