From a1aa3594e75e611a69fbce1c6f9beef65d284533 Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Fri, 6 Mar 2026 14:16:17 +0000 Subject: Extend glVertexArray with VertexArrayConfigurator DSA version of VertexArrayObject. --- gfx/gl/glVertexArray.h | 114 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 112 insertions(+), 2 deletions(-) (limited to 'gfx') diff --git a/gfx/gl/glVertexArray.h b/gfx/gl/glVertexArray.h index 891f21d..3594cbf 100644 --- a/gfx/gl/glVertexArray.h +++ b/gfx/gl/glVertexArray.h @@ -1,11 +1,121 @@ #pragma once -#include "config/types.h" +#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 { }; + struct glVertexArray : Detail::glNamed { + VertexArrayConfigurator + configure() + { + return VertexArrayConfigurator {name}; + } + }; } // NOLINTBEGIN(readability-identifier-naming) -- cgit v1.3