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
118
119
120
121
122
123
124
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)
|