#pragma once #include "collections.hpp" #include "gl_traits.hpp" #include "special_members.hpp" #include class VertexArrayObject { public: template [[nodiscard]] VertexArrayObject(const T & arrayObject) { glBindVertexArray(arrayObject); } ~VertexArrayObject() { glBindVertexArray(0); } NO_MOVE(VertexArrayObject); NO_COPY(VertexArrayObject); template struct MP { constexpr MP(m T::*p) : P {p} { } operator void *() const { return &(static_cast(nullptr)->*P); } m T::*P; using value_type = m; }; template MP(m T::*) -> MP; template VertexArrayObject & addAttribs(const GLuint arrayBuffer, const SequentialCollection auto & vertices) { addAttribs(arrayBuffer); data(vertices, arrayBuffer, GL_ARRAY_BUFFER); return *this; } template VertexArrayObject & addAttribs(const GLuint arrayBuffer) { configure_attribs(arrayBuffer); return *this; } template VertexArrayObject & addIndices(const GLuint arrayBuffer, const Indices & indices) { data(indices, arrayBuffer, GL_ELEMENT_ARRAY_BUFFER); return *this; } VertexArrayObject & addIndices(const GLuint arrayBuffer) { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, arrayBuffer); return *this; } 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); } private: template static void set_pointer(const GLuint vertexArrayId, const void * ptr) { glEnableVertexAttribArray(vertexArrayId); using traits = gl_traits; traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(VertexT), ptr); } template static void set_pointer(const GLuint vertexArrayId) { set_pointer(vertexArrayId, 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++), ...); } } };