summaryrefslogtreecommitdiff
path: root/gfx/gl/vertexArrayObject.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/gl/vertexArrayObject.h')
-rw-r--r--gfx/gl/vertexArrayObject.h109
1 files changed, 109 insertions, 0 deletions
diff --git a/gfx/gl/vertexArrayObject.h b/gfx/gl/vertexArrayObject.h
new file mode 100644
index 0000000..085cba6
--- /dev/null
+++ b/gfx/gl/vertexArrayObject.h
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "collections.h"
+#include "gl_traits.h"
+#include "special_members.h"
+#include <GL/glew.h>
+
+class VertexArrayObject {
+public:
+ template<typename T> [[nodiscard]] VertexArrayObject(const T & arrayObject)
+ {
+ glBindVertexArray(arrayObject);
+ }
+ ~VertexArrayObject()
+ {
+ glBindVertexArray(0);
+ }
+ NO_MOVE(VertexArrayObject);
+ NO_COPY(VertexArrayObject);
+
+ template<typename m, typename T> struct MP {
+ constexpr MP(m T::*p) : P {p} { }
+ operator void *() const
+ {
+ return &(static_cast<T *>(nullptr)->*P);
+ }
+ m T::*P;
+ using value_type = m;
+ };
+ template<typename m, typename T> MP(m T::*) -> MP<m, T>;
+
+ template<typename VertexT, MP... attribs>
+ VertexArrayObject &
+ addAttribs(const GLuint arrayBuffer, const SequentialCollection<VertexT> auto & vertices, const GLuint divisor = 0)
+ {
+ addAttribs<VertexT, attribs...>(arrayBuffer, divisor);
+ data(vertices, arrayBuffer, GL_ARRAY_BUFFER);
+ return *this;
+ }
+
+ template<typename VertexT, MP... attribs>
+ VertexArrayObject &
+ addAttribs(const GLuint arrayBuffer, const GLuint divisor = 0)
+ {
+ configure_attribs<VertexT, attribs...>(arrayBuffer, divisor);
+ return *this;
+ }
+
+ template<typename Indices>
+ 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<typename Data>
+ static void
+ data(const Data & data, const GLuint arrayBuffer, GLenum target)
+ {
+ using Value = typename Data::value_type;
+ glBindBuffer(target, arrayBuffer);
+ glBufferData(target, static_cast<GLsizeiptr>(sizeof(Value) * data.size()), data.data(), GL_STATIC_DRAW);
+ }
+
+private:
+ template<typename VertexT, typename T>
+ static auto
+ set_pointer(const GLuint vertexArrayId, const void * ptr, const GLuint divisor)
+ {
+ using traits = gl_traits<T>;
+ const auto usedAttribs
+ = traits::vertexAttribFunc(vertexArrayId, traits::size, traits::type, sizeof(VertexT), ptr);
+ for (GLuint i {}; i < usedAttribs; i++) {
+ glEnableVertexAttribArray(vertexArrayId + i);
+ glVertexAttribDivisor(vertexArrayId + i, divisor);
+ }
+ return usedAttribs;
+ }
+
+ template<typename VertexT, MP attrib>
+ static auto
+ set_pointer(const GLuint vertexArrayId, const GLuint divisor)
+ {
+ return set_pointer<VertexT, typename decltype(attrib)::value_type>(vertexArrayId, attrib, divisor);
+ }
+
+ template<typename VertexT, MP... attribs>
+ void
+ configure_attribs(const GLuint arrayBuffer, const GLuint divisor)
+ {
+ glBindBuffer(GL_ARRAY_BUFFER, arrayBuffer);
+ if constexpr (sizeof...(attribs) == 0) {
+ vertexArrayId += set_pointer<VertexT, VertexT>(vertexArrayId, nullptr, divisor);
+ }
+ else {
+ ((vertexArrayId += set_pointer<VertexT, attribs>(vertexArrayId, divisor)), ...);
+ }
+ }
+
+ GLuint vertexArrayId {};
+};