1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
#pragma once
#include "collections.h"
#include "gl_traits.h"
#include "special_members.h"
#include <glad/gl.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;
}
// Customisation point
template<typename VertexT> VertexArrayObject & addAttribsFor(const GLuint arrayBuffer, const GLuint divisor = 0);
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 {};
};
|