#pragma once #include "collections.h" #include "glArrays.h" #include "glBuffer.h" #include "gl_traits.h" namespace Impl { class VertexArrayConfigurator { public: template struct MP { constexpr MP(M T::* ptr) : ptr {ptr} { } operator GLuint() const { return static_cast(reinterpret_cast(&(static_cast(nullptr)->*ptr)) - static_cast(nullptr)); } M T::* ptr; using ValueType = M; }; template MP(M T::*) -> MP; explicit VertexArrayConfigurator(GLuint name) : name {name} { } VertexArrayConfigurator & addIndices(const glBuffer & buffer) { glVertexArrayElementBuffer(name, buffer); return *this; } VertexArrayConfigurator & addIndices(glBuffer & buffer, const SequentialCollection auto & indices) { buffer.storage(indices, 0); return addIndices(buffer); } // Customisation point template VertexArrayConfigurator & addAttribsFor(GLuint divisor, const glBuffer & buffer); template VertexArrayConfigurator & addAttribs(const GLuint divisor) { configureAttribs(divisor); return *this; } template VertexArrayConfigurator & addAttribs(const GLuint divisor, const glBuffer & buffer) { glVertexArrayVertexBuffer(name, binding, buffer, 0, sizeof(VertexT)); return addAttribs(divisor); } template VertexArrayConfigurator & addAttribs(const GLuint divisor, glBuffer & buffer, const SequentialCollection auto & data) { buffer.storage(data, 0); return addAttribs(divisor, buffer); } private: void setPointerMeta(const GLuint usedAttribs) { while (attrib < usedAttribs) { glEnableVertexArrayAttrib(name, attrib); glVertexArrayAttribBinding(name, attrib++, binding); } } template void setPointer(const GLuint offset) { setPointerMeta(attrib + gl_traits::vertexArrayAttribFormat(name, attrib, offset)); } template void setPointer() { setPointer(Attrib); } template void configureAttribs(const GLuint divisor) { if constexpr (sizeof...(Attribs) == 0) { setPointer(0); } else { ((setPointer()), ...); } glVertexArrayBindingDivisor(name, binding++, divisor); } GLuint name; GLuint binding = 0; GLuint attrib = 0; }; // NOLINTNEXTLINE(readability-identifier-naming) struct glVertexArray : Detail::glNamed { VertexArrayConfigurator configure() { return VertexArrayConfigurator {name}; } template void useBuffer(GLuint binding, const GlAllocated & buffer) const requires requires { { buffer.bufferName() } -> std::same_as; } { using T = typename GlAllocated::value_type; glVertexArrayVertexBuffer(name, binding, buffer.bufferName(), 0, sizeof(T)); } }; } // NOLINTBEGIN(readability-identifier-naming) template using glVertexArrays = glManagedArray; using glVertexArray = glManagedSingle; // NOLINTEND(readability-identifier-naming)