summaryrefslogtreecommitdiff
path: root/gfx/gl/glVertexArray.h
diff options
context:
space:
mode:
authorDan Goodliffe <dan@randomdan.homeip.net>2026-03-07 11:50:47 +0000
committerDan Goodliffe <dan@randomdan.homeip.net>2026-03-07 11:50:47 +0000
commitadb0096046d357a6463ae2ce66c182546c8de9c2 (patch)
tree0e06a281efc2da637ebc19dca38f160e86516d9f /gfx/gl/glVertexArray.h
parentUpdate stencils and billboards less often (diff)
parentReplace glContainer with glAllocator (diff)
downloadilt-adb0096046d357a6463ae2ce66c182546c8de9c2.tar.bz2
ilt-adb0096046d357a6463ae2ce66c182546c8de9c2.tar.xz
ilt-adb0096046d357a6463ae2ce66c182546c8de9c2.zip
Merge branch 'glalloc'
Diffstat (limited to 'gfx/gl/glVertexArray.h')
-rw-r--r--gfx/gl/glVertexArray.h125
1 files changed, 125 insertions, 0 deletions
diff --git a/gfx/gl/glVertexArray.h b/gfx/gl/glVertexArray.h
new file mode 100644
index 0000000..3594cbf
--- /dev/null
+++ b/gfx/gl/glVertexArray.h
@@ -0,0 +1,125 @@
+#pragma once
+
+#include "collections.h"
+#include "glArrays.h"
+#include "glBuffer.h"
+#include "gl_traits.h"
+
+namespace Impl {
+ class VertexArrayConfigurator {
+ public:
+ template<typename M, typename T> struct MP {
+ constexpr MP(M T::* ptr) : ptr {ptr} { }
+
+ operator GLuint() const
+ {
+ return static_cast<GLuint>(reinterpret_cast<const char *>(&(static_cast<T *>(nullptr)->*ptr))
+ - static_cast<const char *>(nullptr));
+ }
+
+ M T::* ptr;
+ using ValueType = M;
+ };
+
+ template<typename M, typename T> MP(M T::*) -> MP<M, T>;
+
+ explicit VertexArrayConfigurator(GLuint name) : name {name} { }
+
+ VertexArrayConfigurator &
+ addIndices(const glBuffer & buffer)
+ {
+ glVertexArrayElementBuffer(name, buffer);
+ return *this;
+ }
+
+ VertexArrayConfigurator &
+ addIndices(glBuffer & buffer, const SequentialCollection<GLuint> auto & indices)
+ {
+ buffer.storage(indices, 0);
+ return addIndices(buffer);
+ }
+
+ // Customisation point
+ template<typename VertexT> VertexArrayConfigurator & addAttribsFor(GLuint divisor, const glBuffer & buffer);
+
+ template<typename VertexT, MP... Attribs>
+ VertexArrayConfigurator &
+ addAttribs(const GLuint divisor)
+ {
+ configureAttribs<VertexT, Attribs...>(divisor);
+ return *this;
+ }
+
+ template<typename VertexT, MP... Attribs>
+ VertexArrayConfigurator &
+ addAttribs(const GLuint divisor, const glBuffer & buffer)
+ {
+ glVertexArrayVertexBuffer(name, binding, buffer, 0, sizeof(VertexT));
+ return addAttribs<VertexT, Attribs...>(divisor);
+ }
+
+ template<typename VertexT, MP... Attribs>
+ VertexArrayConfigurator &
+ addAttribs(const GLuint divisor, glBuffer & buffer, const SequentialCollection<VertexT> auto & data)
+ {
+ buffer.storage(data, 0);
+ return addAttribs<VertexT, Attribs...>(divisor, buffer);
+ }
+
+ private:
+ void
+ setPointerMeta(const GLuint usedAttribs)
+ {
+ while (attrib < usedAttribs) {
+ glEnableVertexArrayAttrib(name, attrib);
+ glVertexArrayAttribBinding(name, attrib++, binding);
+ }
+ }
+
+ template<typename T>
+ void
+ setPointer(const GLuint offset)
+ {
+ setPointerMeta(attrib + gl_traits<T>::vertexArrayAttribFormat(name, attrib, offset));
+ }
+
+ template<MP Attrib>
+ void
+ setPointer()
+ {
+ setPointer<typename decltype(Attrib)::ValueType>(Attrib);
+ }
+
+ template<typename VertexT, MP... Attribs>
+ void
+ configureAttribs(const GLuint divisor)
+ {
+ if constexpr (sizeof...(Attribs) == 0) {
+ setPointer<VertexT>(0);
+ }
+ else {
+ ((setPointer<Attribs>()), ...);
+ }
+ 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};
+ }
+ };
+}
+
+// NOLINTBEGIN(readability-identifier-naming)
+template<size_t N>
+using glVertexArrays = glManagedArray<Impl::glVertexArray, N, &glCreateVertexArrays, &glDeleteVertexArrays>;
+using glVertexArray = glManagedSingle<Impl::glVertexArray, &glCreateVertexArrays, &glDeleteVertexArrays>;
+// NOLINTEND(readability-identifier-naming)