using System.Reflection; using System.Runtime.InteropServices; using Engine.Renderer.Buffer.Vertex; using OpenTK.Graphics.OpenGL; using Serilog; namespace Engine.Renderer.Buffer; public class VertexArray : OpenGlObject { // private IndexBuffer? _boundIndexBuffer; // private readonly Dictionary> _boundVertexBuffers = new(); public VertexArray() { GL.CreateVertexArrays(1, out int handle); Handle = handle; } public void BindIndexBuffer(IndexBuffer buffer) { GL.VertexArrayElementBuffer(Handle, buffer.Handle); Log.Debug("Vertex array {Handle} bound to index buffer {Buffer}", Handle, buffer.Handle); } public void BindVertexBuffer(VertexBuffer buffer, int bindingIndex = 0, int divisor = 0) where T : struct, IVertex { if (bindingIndex < 0) throw new ArgumentException("Binding index must be greater than 0"); if (divisor < 0) throw new ArgumentException("Divisor must be greater than 0"); var stride = Marshal.SizeOf(); var fields = IVertex.GetFields(); GL.VertexArrayVertexBuffer(Handle, bindingIndex, buffer.Handle, 0, stride); var location = 0; foreach (var field in fields) { var attribute = field.GetCustomAttribute()!; var offset = Marshal.OffsetOf(field.Name).ToInt32(); SetupAttribute(attribute, location, offset, bindingIndex); location += attribute.RepeatCount; } GL.VertexArrayBindingDivisor(Handle, bindingIndex, divisor); Log.Debug( "Vertex array {Handle} bound to vertex buffer {Buffer} at {BindingIndex} binding with {Divisor} divisor", Handle, buffer.Handle, bindingIndex, divisor); } private void SetupAttribute(VertexAttribute attribute, int baseLocation, int baseOffset, int bindingIndex) { var size = attribute.ComponentCount * IVertex.AttributeSize(attribute.Type); for (var i = 0; i < attribute.RepeatCount; i++) { var location = baseLocation + i; var offset = baseOffset + i * size; GL.EnableVertexArrayAttrib(Handle, location); GL.VertexArrayAttribFormat(Handle, location, attribute.ComponentCount, attribute.Type, attribute.Normalized, offset); GL.VertexArrayAttribBinding(Handle, location, bindingIndex); } } internal override void Bind() { GL.BindVertexArray(Handle); } internal override void Unbind() { GL.BindVertexArray(0); } protected override void Destroy() { GL.DeleteVertexArray(Handle); } }