#pragma once #include "collections.hpp" #include "gl_traits.hpp" #include #include template class VertexArrayObject { public: template static void configure(const GLuint arrayObject, const GLuint arrayBuffer, const GLuint indexBuffer, const SequentialCollection auto & vertices, const SequentialCollection auto & indices) { glBindVertexArray(arrayObject); configure_attribs(arrayBuffer); data(vertices, arrayBuffer, GL_ARRAY_BUFFER); data(indices, indexBuffer, GL_ELEMENT_ARRAY_BUFFER); glBindVertexArray(0); } template static void configure(const GLuint arrayObject, const GLuint arrayBuffer, const SequentialCollection auto & vertices) { glBindVertexArray(arrayObject); configure_attribs(arrayBuffer); data(vertices, arrayBuffer, GL_ARRAY_BUFFER); glBindVertexArray(0); } template static void configure(const GLuint arrayObject, const GLuint arrayBuffer) { glBindVertexArray(arrayObject); configure_attribs(arrayBuffer); glBufferData(GL_ARRAY_BUFFER, static_cast(sizeof(Vertex)), nullptr, GL_DYNAMIC_DRAW); glBindVertexArray(0); } private: template static void data(const Data & data, const GLuint arrayBuffer, GLenum target) { using Value = typename Data::value_type; glBindBuffer(target, arrayBuffer); glBufferData(target, static_cast(sizeof(Value) * data.size()), data.data(), GL_STATIC_DRAW); } template static void set_pointer(const GLuint vertexArrayId, const void * ptr) { glEnableVertexAttribArray(vertexArrayId); using traits = gl_traits; glVertexAttribPointer(vertexArrayId, traits::size, traits::type, GL_FALSE, sizeof(Vertex), ptr); } template static void set_pointer(const GLuint vertexArrayId) { set_pointer().*attrib)>>( vertexArrayId, &(static_cast(nullptr)->*attrib)); } template static void configure_attribs(const GLuint arrayBuffer) { glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer); if constexpr (sizeof...(attribs) == 0) { set_pointer(0, nullptr); } else { GLuint vertexArrayId {}; (set_pointer(vertexArrayId++), ...); } } };