Browse code

Add Value

Robert Cranston authored on 15/10/2022 19:02:09
Showing 6 changed files

... ...
@@ -9,3 +9,19 @@ project(gltraits
9 9
     VERSION 1.0.0
10 10
     LANGUAGES CXX
11 11
 )
12
+
13
+## Main target
14
+add_library(${PROJECT_NAME} INTERFACE)
15
+
16
+## Common
17
+include(common.cmake)
18
+common(
19
+    CXX_STANDARD 11
20
+    PACKAGES
21
+        glm
22
+    FETCHCONTENT
23
+        https://git.rcrnstn.net/rcrnstn/glbase
24
+    DEPENDENCIES_TESTS
25
+        glm::glm
26
+        glbase
27
+)
... ...
@@ -13,6 +13,22 @@ brought to light. Therefore, it may be useful for learning and understanding
13 13
 the OpenGL API (although this use case may be limited due to the (ab)use of C++
14 14
 language features).
15 15
 
16
+This header-only library makes heavy use of macros. For easy inspection of the
17
+results, a script that runs the preprocessor is available in
18
+[`doc/preprocess`][] and its output in [`doc/preprocess.hpp`][].
19
+
20
+A typical use case is demonstrated by this quote from [OGLDEV on YouTube][]:
21
+
22
+> Notice, in order to make this an unsigned integer texture we use `GL_RGB32UI`
23
+> as the `internal_format`, `GL_RGB_INTEGER` as the `format`, and
24
+> `GL_UNSIGNED_INT` as the data `type`. Combining all these formats and types
25
+> correctly in OpenGL can often be a pain, and I literally pulled the last few
26
+> pieces of hair from my head trying to get this to work.
27
+
28
+These constants are provided in `GLTraits::Value<glm::uvec3>`. Of course, this
29
+becomes even more valuable when `glm::uvec3` is replaced by some unknown
30
+template parameter.
31
+
16 32
 [`gltraits`]: https://git.rcrnstn.net/rcrnstn/gltraits
17 33
 [C++11]: https://en.wikipedia.org/wiki/C++11
18 34
 [OpenGL]: https://en.wikipedia.org/wiki/OpenGL
... ...
@@ -26,6 +42,99 @@ language features).
26 42
 [version]: https://en.wikipedia.org/wiki/OpenGL#Version_history
27 43
 [extension]: https://www.khronos.org/opengl/wiki/OpenGL_Extension
28 44
 [GLSL]: https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language
45
+[`doc/preprocess`]: doc/preprocess
46
+[`doc/preprocess.hpp`]: doc/preprocess.hpp
47
+[OGLDEV on YouTube]: https://www.youtube.com/watch?v=71G-PVpaVk8&t=5m17s
48
+
49
+## Usage
50
+
51
+### Value
52
+
53
+The [empty][] `struct GLTraits::Value<typename Value>` is template specialized
54
+on the following types.
55
+
56
+-   `GLfloat`
57
+-   `bool`
58
+-   `GL{,u}byte`
59
+-   `GL{,u}short`
60
+-   `GL{,u}int`
61
+-   `GLdouble`
62
+
63
+[GLM][] support is enabled if `glm/glm.hpp` is included (specifically, if
64
+`GLM_VERSION` is defined) before inclusion of `gltraits.hpp`. In that case
65
+`GLTraits::Value` is additionally template specialized on the following types.
66
+
67
+-   `glm::{,i,u,d}vec{2,3,4}`
68
+-   `glm::{,d}mat{2{,x3,x4},3{x2,,x4},4{x2,x3,}}`
69
+
70
+`GLTraits::Value` contains the following `static constexpr` member variables.
71
+
72
+-   `char   const name[]`
73
+-   `GLint        columns`
74
+-   `GLint        rows`
75
+-   `GLenum       glsl`
76
+-   `GLenum       format`
77
+-   `GLenum       type`
78
+-   `GLenum       internal_format`
79
+-   `GLenum       internal_format_srgb`
80
+-   `GLenum       internal_format_compressed`
81
+-   `GLenum       internal_format_compressed_srgb`
82
+-   `bool         integer`
83
+
84
+`GLTraits::Value` contains the following `static` member functions.
85
+
86
+-   ```cpp
87
+    void uniform(GLint location, Value const & value)
88
+    ```
89
+
90
+    Generalization of `glUniform*`.
91
+
92
+    Uploads `value` to the [uniform][] indicated by `location` of the current
93
+    [shader][] program.
94
+
95
+-   ```cpp
96
+    void vertex_attrib(GLint location, Value const & value)
97
+    ```
98
+
99
+    Generalization of `glVertexAttrib*`.
100
+
101
+    Uploads `value` to the [non-array attribute][] indicated by `location`.
102
+    Note that [`glDisableVertexAttribArray`][] is not called (for performance).
103
+
104
+-   ```cpp
105
+    void vertex_attrib_pointer(
106
+        GLint       location,
107
+        std::size_t offset = 0,
108
+        std::size_t stride = sizeof(Value)
109
+    )
110
+    ```
111
+
112
+    Generalization of `glVertexAttrib*Pointer`.
113
+
114
+    Sets the [format][] as well as the [offset and stride][] of the [array
115
+    attribute][] indicated by `location`. Note that
116
+    [`glEnableVertexAttribArray`][] is not called (for performance).
117
+
118
+If `location` is `-1`, the above calls will do nothing. No error will be
119
+generated in this case.
120
+
121
+Note that matrix types (e.g. from [GLM][], if enabled), occupy several
122
+consecutive attribute locations (one per column), which are all handled
123
+automatically by `vertex_attrib{,_pointer}(...)` above.
124
+
125
+`GLTRAITS_VALUE*` macros are defined to ease the definition of new template
126
+specializations of `GLTraits::Value`. Consult the source for the definitions
127
+and usage examples.
128
+
129
+[empty]: https://en.cppreference.com/w/cpp/types/is_empty
130
+[uniform]: https://www.khronos.org/opengl/wiki/Uniform_(GLSL)
131
+[shader]: https://www.khronos.org/opengl/wiki/Shader
132
+[non-array attribute]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Non-array_attribute_values
133
+[format]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_format
134
+[offset and stride]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_buffer_offset_and_stride
135
+[array attribute]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Buffer_Object
136
+[`glDisableVertexAttribArray`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glEnableVertexAttribArray.xhtml
137
+[`glEnableVertexAttribArray`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glEnableVertexAttribArray.xhtml
29 138
 
30 139
 ## Building
31 140
 
32 141
new file mode 100755
... ...
@@ -0,0 +1,33 @@
1
+#!/bin/sh
2
+set -euC
3
+
4
+cd "$(dirname "$0")/.."
5
+
6
+file="$(basename "$0")"
7
+in_file="include/gltraits.hpp"
8
+out_file="doc/$file.hpp"
9
+tmp_file="doc/$file-tmp.hpp"
10
+
11
+trap 'rm "$tmp_file"' EXIT
12
+
13
+grep -v '^\s*#include' < "$in_file" > "$tmp_file"
14
+
15
+${CPP:-cpp} -DGLM_VERSION "$tmp_file" \
16
+| grep -v '^\s*#' \
17
+| ${CLANG_FORMAT:-clang-format} --style='{
18
+    "ColumnLimit":                               79,
19
+    "IndentWidth":                               4,
20
+    "UseTab":                                    "Never",
21
+    "BreakBeforeBraces":                         "Allman",
22
+    # "AlignAfterOpenBracket":                     "BlockIndent",
23
+    "AlignAfterOpenBracket":                     "AlwaysBreak",
24
+    "PointerAlignment":                          "Middle",
25
+    "BinPackArguments":                          false,
26
+    "BinPackParameters":                         false,
27
+    "AllowAllArgumentsOnNextLine":               false,
28
+    "AllowAllParametersOfDeclarationOnNextLine": false,
29
+    "AlignConsecutiveDeclarations":              true,
30
+    "AlignConsecutiveAssignments":               true,
31
+  }' \
32
+| sed 's/^\S.*;/&\n/' \
33
+>| "$out_file"
0 34
new file mode 100644
... ...
@@ -0,0 +1,2031 @@
1
+class GLTraits
2
+{
3
+
4
+  public:
5
+    template <typename> struct Value;
6
+};
7
+
8
+template <> struct GLTraits::Value<GLfloat>
9
+{
10
+    auto static constexpr name                 = "GLfloat";
11
+    auto static constexpr columns              = GLint{1};
12
+    auto static constexpr rows                 = GLint{1};
13
+    auto static constexpr glsl                 = GLenum{GL_FLOAT};
14
+    auto static constexpr format               = GLenum{GL_RED};
15
+    auto static constexpr type                 = GLenum{GL_FLOAT};
16
+    auto static constexpr internal_format      = GLenum{GL_R32F};
17
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
18
+    auto static constexpr internal_format_compressed =
19
+        GLenum{GL_COMPRESSED_RED};
20
+    auto static constexpr internal_format_compressed_srgb =
21
+        GLenum{GL_COMPRESSED_SRGB};
22
+    auto static constexpr integer = bool(*"");
23
+    void static uniform(GLint location, GLfloat const & value)
24
+    {
25
+        if (GLBase::debug() >= 1)
26
+            GLBase::check_supported({2, 0}, {});
27
+        glUniform1f(location, (value));
28
+    }
29
+    void static vertex_attrib(GLint location, GLfloat const & value)
30
+    {
31
+        if (GLBase::debug() >= 1)
32
+            GLBase::check_supported({2, 0}, {});
33
+        if (location == -1)
34
+            return;
35
+        for (auto column = GLuint{0}; column < columns; ++column)
36
+            glVertexAttrib1f((GLuint)location + column, (value));
37
+    }
38
+    void static vertex_attrib_pointer(
39
+        GLint       location,
40
+        std::size_t offset = 0,
41
+        std::size_t stride = sizeof(GLfloat))
42
+    {
43
+        if (GLBase::debug() >= 1)
44
+            GLBase::check_supported({2, 0}, {});
45
+        if (location == -1)
46
+            return;
47
+        auto constexpr sizeof_column = sizeof(GLfloat) / columns;
48
+        for (auto column = GLuint{0}; column < columns; ++column)
49
+            glVertexAttribPointer(
50
+                (GLuint)location + column,
51
+                rows,
52
+                type,
53
+                GL_FALSE,
54
+                (GLsizei)stride,
55
+                (void const *)(offset + sizeof_column * column));
56
+    }
57
+};
58
+
59
+template <> struct GLTraits::Value<bool>
60
+{
61
+    auto static constexpr name                 = "bool";
62
+    auto static constexpr columns              = GLint{1};
63
+    auto static constexpr rows                 = GLint{1};
64
+    auto static constexpr glsl                 = GLenum{GL_BOOL};
65
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
66
+    auto static constexpr type                 = GLenum{GL_BYTE};
67
+    auto static constexpr internal_format      = GLenum{GL_R8I};
68
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
69
+    auto static constexpr internal_format_compressed =
70
+        GLenum{GL_COMPRESSED_RED};
71
+    auto static constexpr internal_format_compressed_srgb =
72
+        GLenum{GL_COMPRESSED_SRGB};
73
+    auto static constexpr integer = bool(*"_INTEGER");
74
+    void static uniform(GLint location, bool const & value)
75
+    {
76
+        if (GLBase::debug() >= 1)
77
+            GLBase::check_supported({2, 0}, {});
78
+        glUniform1i(location, (value));
79
+    }
80
+    void static vertex_attrib(GLint location, bool const & value)
81
+    {
82
+        if (GLBase::debug() >= 1)
83
+            GLBase::check_supported({3, 0}, {});
84
+        if (location == -1)
85
+            return;
86
+        for (auto column = GLuint{0}; column < columns; ++column)
87
+            glVertexAttribI1i((GLuint)location + column, (value));
88
+    }
89
+    void static vertex_attrib_pointer(
90
+        GLint       location,
91
+        std::size_t offset = 0,
92
+        std::size_t stride = sizeof(bool))
93
+    {
94
+        if (GLBase::debug() >= 1)
95
+            GLBase::check_supported({3, 0}, {});
96
+        if (location == -1)
97
+            return;
98
+        auto constexpr sizeof_column = sizeof(bool) / columns;
99
+        for (auto column = GLuint{0}; column < columns; ++column)
100
+            glVertexAttribIPointer(
101
+                (GLuint)location + column,
102
+                rows,
103
+                type,
104
+                (GLsizei)stride,
105
+                (void const *)(offset + sizeof_column * column));
106
+    }
107
+};
108
+
109
+template <> struct GLTraits::Value<GLbyte>
110
+{
111
+    auto static constexpr name                 = "GLbyte";
112
+    auto static constexpr columns              = GLint{1};
113
+    auto static constexpr rows                 = GLint{1};
114
+    auto static constexpr glsl                 = GLenum{GL_INT};
115
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
116
+    auto static constexpr type                 = GLenum{GL_BYTE};
117
+    auto static constexpr internal_format      = GLenum{GL_R8I};
118
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
119
+    auto static constexpr internal_format_compressed =
120
+        GLenum{GL_COMPRESSED_RED};
121
+    auto static constexpr internal_format_compressed_srgb =
122
+        GLenum{GL_COMPRESSED_SRGB};
123
+    auto static constexpr integer = bool(*"_INTEGER");
124
+    void static uniform(GLint location, GLbyte const & value)
125
+    {
126
+        if (GLBase::debug() >= 1)
127
+            GLBase::check_supported({2, 0}, {});
128
+        glUniform1i(location, (value));
129
+    }
130
+    void static vertex_attrib(GLint location, GLbyte const & value)
131
+    {
132
+        if (GLBase::debug() >= 1)
133
+            GLBase::check_supported({3, 0}, {});
134
+        if (location == -1)
135
+            return;
136
+        for (auto column = GLuint{0}; column < columns; ++column)
137
+            glVertexAttribI1i((GLuint)location + column, (value));
138
+    }
139
+    void static vertex_attrib_pointer(
140
+        GLint       location,
141
+        std::size_t offset = 0,
142
+        std::size_t stride = sizeof(GLbyte))
143
+    {
144
+        if (GLBase::debug() >= 1)
145
+            GLBase::check_supported({3, 0}, {});
146
+        if (location == -1)
147
+            return;
148
+        auto constexpr sizeof_column = sizeof(GLbyte) / columns;
149
+        for (auto column = GLuint{0}; column < columns; ++column)
150
+            glVertexAttribIPointer(
151
+                (GLuint)location + column,
152
+                rows,
153
+                type,
154
+                (GLsizei)stride,
155
+                (void const *)(offset + sizeof_column * column));
156
+    }
157
+};
158
+
159
+template <> struct GLTraits::Value<GLshort>
160
+{
161
+    auto static constexpr name                 = "GLshort";
162
+    auto static constexpr columns              = GLint{1};
163
+    auto static constexpr rows                 = GLint{1};
164
+    auto static constexpr glsl                 = GLenum{GL_INT};
165
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
166
+    auto static constexpr type                 = GLenum{GL_SHORT};
167
+    auto static constexpr internal_format      = GLenum{GL_R16I};
168
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
169
+    auto static constexpr internal_format_compressed =
170
+        GLenum{GL_COMPRESSED_RED};
171
+    auto static constexpr internal_format_compressed_srgb =
172
+        GLenum{GL_COMPRESSED_SRGB};
173
+    auto static constexpr integer = bool(*"_INTEGER");
174
+    void static uniform(GLint location, GLshort const & value)
175
+    {
176
+        if (GLBase::debug() >= 1)
177
+            GLBase::check_supported({2, 0}, {});
178
+        glUniform1i(location, (value));
179
+    }
180
+    void static vertex_attrib(GLint location, GLshort const & value)
181
+    {
182
+        if (GLBase::debug() >= 1)
183
+            GLBase::check_supported({3, 0}, {});
184
+        if (location == -1)
185
+            return;
186
+        for (auto column = GLuint{0}; column < columns; ++column)
187
+            glVertexAttribI1i((GLuint)location + column, (value));
188
+    }
189
+    void static vertex_attrib_pointer(
190
+        GLint       location,
191
+        std::size_t offset = 0,
192
+        std::size_t stride = sizeof(GLshort))
193
+    {
194
+        if (GLBase::debug() >= 1)
195
+            GLBase::check_supported({3, 0}, {});
196
+        if (location == -1)
197
+            return;
198
+        auto constexpr sizeof_column = sizeof(GLshort) / columns;
199
+        for (auto column = GLuint{0}; column < columns; ++column)
200
+            glVertexAttribIPointer(
201
+                (GLuint)location + column,
202
+                rows,
203
+                type,
204
+                (GLsizei)stride,
205
+                (void const *)(offset + sizeof_column * column));
206
+    }
207
+};
208
+
209
+template <> struct GLTraits::Value<GLint>
210
+{
211
+    auto static constexpr name                 = "GLint";
212
+    auto static constexpr columns              = GLint{1};
213
+    auto static constexpr rows                 = GLint{1};
214
+    auto static constexpr glsl                 = GLenum{GL_INT};
215
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
216
+    auto static constexpr type                 = GLenum{GL_INT};
217
+    auto static constexpr internal_format      = GLenum{GL_R32I};
218
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
219
+    auto static constexpr internal_format_compressed =
220
+        GLenum{GL_COMPRESSED_RED};
221
+    auto static constexpr internal_format_compressed_srgb =
222
+        GLenum{GL_COMPRESSED_SRGB};
223
+    auto static constexpr integer = bool(*"_INTEGER");
224
+    void static uniform(GLint location, GLint const & value)
225
+    {
226
+        if (GLBase::debug() >= 1)
227
+            GLBase::check_supported({2, 0}, {});
228
+        glUniform1i(location, (value));
229
+    }
230
+    void static vertex_attrib(GLint location, GLint const & value)
231
+    {
232
+        if (GLBase::debug() >= 1)
233
+            GLBase::check_supported({3, 0}, {});
234
+        if (location == -1)
235
+            return;
236
+        for (auto column = GLuint{0}; column < columns; ++column)
237
+            glVertexAttribI1i((GLuint)location + column, (value));
238
+    }
239
+    void static vertex_attrib_pointer(
240
+        GLint       location,
241
+        std::size_t offset = 0,
242
+        std::size_t stride = sizeof(GLint))
243
+    {
244
+        if (GLBase::debug() >= 1)
245
+            GLBase::check_supported({3, 0}, {});
246
+        if (location == -1)
247
+            return;
248
+        auto constexpr sizeof_column = sizeof(GLint) / columns;
249
+        for (auto column = GLuint{0}; column < columns; ++column)
250
+            glVertexAttribIPointer(
251
+                (GLuint)location + column,
252
+                rows,
253
+                type,
254
+                (GLsizei)stride,
255
+                (void const *)(offset + sizeof_column * column));
256
+    }
257
+};
258
+
259
+template <> struct GLTraits::Value<GLubyte>
260
+{
261
+    auto static constexpr name                 = "GLubyte";
262
+    auto static constexpr columns              = GLint{1};
263
+    auto static constexpr rows                 = GLint{1};
264
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
265
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
266
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_BYTE};
267
+    auto static constexpr internal_format      = GLenum{GL_R8UI};
268
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
269
+    auto static constexpr internal_format_compressed =
270
+        GLenum{GL_COMPRESSED_RED};
271
+    auto static constexpr internal_format_compressed_srgb =
272
+        GLenum{GL_COMPRESSED_SRGB};
273
+    auto static constexpr integer = bool(*"_INTEGER");
274
+    void static uniform(GLint location, GLubyte const & value)
275
+    {
276
+        if (GLBase::debug() >= 1)
277
+            GLBase::check_supported({3, 0}, {});
278
+        glUniform1ui(location, (value));
279
+    }
280
+    void static vertex_attrib(GLint location, GLubyte const & value)
281
+    {
282
+        if (GLBase::debug() >= 1)
283
+            GLBase::check_supported({3, 0}, {});
284
+        if (location == -1)
285
+            return;
286
+        for (auto column = GLuint{0}; column < columns; ++column)
287
+            glVertexAttribI1ui((GLuint)location + column, (value));
288
+    }
289
+    void static vertex_attrib_pointer(
290
+        GLint       location,
291
+        std::size_t offset = 0,
292
+        std::size_t stride = sizeof(GLubyte))
293
+    {
294
+        if (GLBase::debug() >= 1)
295
+            GLBase::check_supported({3, 0}, {});
296
+        if (location == -1)
297
+            return;
298
+        auto constexpr sizeof_column = sizeof(GLubyte) / columns;
299
+        for (auto column = GLuint{0}; column < columns; ++column)
300
+            glVertexAttribIPointer(
301
+                (GLuint)location + column,
302
+                rows,
303
+                type,
304
+                (GLsizei)stride,
305
+                (void const *)(offset + sizeof_column * column));
306
+    }
307
+};
308
+
309
+template <> struct GLTraits::Value<GLushort>
310
+{
311
+    auto static constexpr name                 = "GLushort";
312
+    auto static constexpr columns              = GLint{1};
313
+    auto static constexpr rows                 = GLint{1};
314
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
315
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
316
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_SHORT};
317
+    auto static constexpr internal_format      = GLenum{GL_R16UI};
318
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
319
+    auto static constexpr internal_format_compressed =
320
+        GLenum{GL_COMPRESSED_RED};
321
+    auto static constexpr internal_format_compressed_srgb =
322
+        GLenum{GL_COMPRESSED_SRGB};
323
+    auto static constexpr integer = bool(*"_INTEGER");
324
+    void static uniform(GLint location, GLushort const & value)
325
+    {
326
+        if (GLBase::debug() >= 1)
327
+            GLBase::check_supported({3, 0}, {});
328
+        glUniform1ui(location, (value));
329
+    }
330
+    void static vertex_attrib(GLint location, GLushort const & value)
331
+    {
332
+        if (GLBase::debug() >= 1)
333
+            GLBase::check_supported({3, 0}, {});
334
+        if (location == -1)
335
+            return;
336
+        for (auto column = GLuint{0}; column < columns; ++column)
337
+            glVertexAttribI1ui((GLuint)location + column, (value));
338
+    }
339
+    void static vertex_attrib_pointer(
340
+        GLint       location,
341
+        std::size_t offset = 0,
342
+        std::size_t stride = sizeof(GLushort))
343
+    {
344
+        if (GLBase::debug() >= 1)
345
+            GLBase::check_supported({3, 0}, {});
346
+        if (location == -1)
347
+            return;
348
+        auto constexpr sizeof_column = sizeof(GLushort) / columns;
349
+        for (auto column = GLuint{0}; column < columns; ++column)
350
+            glVertexAttribIPointer(
351
+                (GLuint)location + column,
352
+                rows,
353
+                type,
354
+                (GLsizei)stride,
355
+                (void const *)(offset + sizeof_column * column));
356
+    }
357
+};
358
+
359
+template <> struct GLTraits::Value<GLuint>
360
+{
361
+    auto static constexpr name                 = "GLuint";
362
+    auto static constexpr columns              = GLint{1};
363
+    auto static constexpr rows                 = GLint{1};
364
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
365
+    auto static constexpr format               = GLenum{GL_RED_INTEGER};
366
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
367
+    auto static constexpr internal_format      = GLenum{GL_R32UI};
368
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
369
+    auto static constexpr internal_format_compressed =
370
+        GLenum{GL_COMPRESSED_RED};
371
+    auto static constexpr internal_format_compressed_srgb =
372
+        GLenum{GL_COMPRESSED_SRGB};
373
+    auto static constexpr integer = bool(*"_INTEGER");
374
+    void static uniform(GLint location, GLuint const & value)
375
+    {
376
+        if (GLBase::debug() >= 1)
377
+            GLBase::check_supported({3, 0}, {});
378
+        glUniform1ui(location, (value));
379
+    }
380
+    void static vertex_attrib(GLint location, GLuint const & value)
381
+    {
382
+        if (GLBase::debug() >= 1)
383
+            GLBase::check_supported({3, 0}, {});
384
+        if (location == -1)
385
+            return;
386
+        for (auto column = GLuint{0}; column < columns; ++column)
387
+            glVertexAttribI1ui((GLuint)location + column, (value));
388
+    }
389
+    void static vertex_attrib_pointer(
390
+        GLint       location,
391
+        std::size_t offset = 0,
392
+        std::size_t stride = sizeof(GLuint))
393
+    {
394
+        if (GLBase::debug() >= 1)
395
+            GLBase::check_supported({3, 0}, {});
396
+        if (location == -1)
397
+            return;
398
+        auto constexpr sizeof_column = sizeof(GLuint) / columns;
399
+        for (auto column = GLuint{0}; column < columns; ++column)
400
+            glVertexAttribIPointer(
401
+                (GLuint)location + column,
402
+                rows,
403
+                type,
404
+                (GLsizei)stride,
405
+                (void const *)(offset + sizeof_column * column));
406
+    }
407
+};
408
+
409
+template <> struct GLTraits::Value<GLdouble>
410
+{
411
+    auto static constexpr name                 = "GLdouble";
412
+    auto static constexpr columns              = GLint{1};
413
+    auto static constexpr rows                 = GLint{1};
414
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE};
415
+    auto static constexpr format               = GLenum{GL_RED};
416
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
417
+    auto static constexpr internal_format      = GLenum{GL_RED};
418
+    auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
419
+    auto static constexpr internal_format_compressed =
420
+        GLenum{GL_COMPRESSED_RED};
421
+    auto static constexpr internal_format_compressed_srgb =
422
+        GLenum{GL_COMPRESSED_SRGB};
423
+    auto static constexpr integer = bool(*"");
424
+    void static uniform(GLint location, GLdouble const & value)
425
+    {
426
+        if (GLBase::debug() >= 1)
427
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
428
+        glUniform1d(location, (value));
429
+    }
430
+    void static vertex_attrib(GLint location, GLdouble const & value)
431
+    {
432
+        if (GLBase::debug() >= 1)
433
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
434
+        if (location == -1)
435
+            return;
436
+        for (auto column = GLuint{0}; column < columns; ++column)
437
+            glVertexAttribL1d((GLuint)location + column, (value));
438
+    }
439
+    void static vertex_attrib_pointer(
440
+        GLint       location,
441
+        std::size_t offset = 0,
442
+        std::size_t stride = sizeof(GLdouble))
443
+    {
444
+        if (GLBase::debug() >= 1)
445
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
446
+        if (location == -1)
447
+            return;
448
+        auto constexpr sizeof_column = sizeof(GLdouble) / columns;
449
+        for (auto column = GLuint{0}; column < columns; ++column)
450
+            glVertexAttribLPointer(
451
+                (GLuint)location + column,
452
+                rows,
453
+                type,
454
+                (GLsizei)stride,
455
+                (void const *)(offset + sizeof_column * column));
456
+    }
457
+};
458
+
459
+
460
+template <> struct GLTraits::Value<glm::vec2>
461
+{
462
+    auto static constexpr name                 = "glm::vec2";
463
+    auto static constexpr columns              = GLint{1};
464
+    auto static constexpr rows                 = GLint{2};
465
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC2};
466
+    auto static constexpr format               = GLenum{GL_RG};
467
+    auto static constexpr type                 = GLenum{GL_FLOAT};
468
+    auto static constexpr internal_format      = GLenum{GL_RG32F};
469
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
470
+    auto static constexpr internal_format_compressed =
471
+        GLenum{GL_COMPRESSED_RG};
472
+    auto static constexpr internal_format_compressed_srgb =
473
+        GLenum{GL_COMPRESSED_SRGB};
474
+    auto static constexpr integer = bool(*"");
475
+    void static uniform(GLint location, glm::vec2 const & value)
476
+    {
477
+        if (GLBase::debug() >= 1)
478
+            GLBase::check_supported({2, 0}, {});
479
+        glUniform2fv(location, 1, glm::value_ptr(value));
480
+    }
481
+    void static vertex_attrib(GLint location, glm::vec2 const & value)
482
+    {
483
+        if (GLBase::debug() >= 1)
484
+            GLBase::check_supported({2, 0}, {});
485
+        if (location == -1)
486
+            return;
487
+        for (auto column = GLuint{0}; column < columns; ++column)
488
+            glVertexAttrib2fv(
489
+                (GLuint)location + column,
490
+                glm::value_ptr(value) + rows * column);
491
+    }
492
+    void static vertex_attrib_pointer(
493
+        GLint       location,
494
+        std::size_t offset = 0,
495
+        std::size_t stride = sizeof(glm::vec2))
496
+    {
497
+        if (GLBase::debug() >= 1)
498
+            GLBase::check_supported({2, 0}, {});
499
+        if (location == -1)
500
+            return;
501
+        auto constexpr sizeof_column = sizeof(glm::vec2) / columns;
502
+        for (auto column = GLuint{0}; column < columns; ++column)
503
+            glVertexAttribPointer(
504
+                (GLuint)location + column,
505
+                rows,
506
+                type,
507
+                GL_FALSE,
508
+                (GLsizei)stride,
509
+                (void const *)(offset + sizeof_column * column));
510
+    }
511
+};
512
+
513
+template <> struct GLTraits::Value<glm::vec3>
514
+{
515
+    auto static constexpr name                 = "glm::vec3";
516
+    auto static constexpr columns              = GLint{1};
517
+    auto static constexpr rows                 = GLint{3};
518
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC3};
519
+    auto static constexpr format               = GLenum{GL_RGB};
520
+    auto static constexpr type                 = GLenum{GL_FLOAT};
521
+    auto static constexpr internal_format      = GLenum{GL_RGB32F};
522
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
523
+    auto static constexpr internal_format_compressed =
524
+        GLenum{GL_COMPRESSED_RGB};
525
+    auto static constexpr internal_format_compressed_srgb =
526
+        GLenum{GL_COMPRESSED_SRGB};
527
+    auto static constexpr integer = bool(*"");
528
+    void static uniform(GLint location, glm::vec3 const & value)
529
+    {
530
+        if (GLBase::debug() >= 1)
531
+            GLBase::check_supported({2, 0}, {});
532
+        glUniform3fv(location, 1, glm::value_ptr(value));
533
+    }
534
+    void static vertex_attrib(GLint location, glm::vec3 const & value)
535
+    {
536
+        if (GLBase::debug() >= 1)
537
+            GLBase::check_supported({2, 0}, {});
538
+        if (location == -1)
539
+            return;
540
+        for (auto column = GLuint{0}; column < columns; ++column)
541
+            glVertexAttrib3fv(
542
+                (GLuint)location + column,
543
+                glm::value_ptr(value) + rows * column);
544
+    }
545
+    void static vertex_attrib_pointer(
546
+        GLint       location,
547
+        std::size_t offset = 0,
548
+        std::size_t stride = sizeof(glm::vec3))
549
+    {
550
+        if (GLBase::debug() >= 1)
551
+            GLBase::check_supported({2, 0}, {});
552
+        if (location == -1)
553
+            return;
554
+        auto constexpr sizeof_column = sizeof(glm::vec3) / columns;
555
+        for (auto column = GLuint{0}; column < columns; ++column)
556
+            glVertexAttribPointer(
557
+                (GLuint)location + column,
558
+                rows,
559
+                type,
560
+                GL_FALSE,
561
+                (GLsizei)stride,
562
+                (void const *)(offset + sizeof_column * column));
563
+    }
564
+};
565
+
566
+template <> struct GLTraits::Value<glm::vec4>
567
+{
568
+    auto static constexpr name                 = "glm::vec4";
569
+    auto static constexpr columns              = GLint{1};
570
+    auto static constexpr rows                 = GLint{4};
571
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC4};
572
+    auto static constexpr format               = GLenum{GL_RGBA};
573
+    auto static constexpr type                 = GLenum{GL_FLOAT};
574
+    auto static constexpr internal_format      = GLenum{GL_RGBA32F};
575
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
576
+    auto static constexpr internal_format_compressed =
577
+        GLenum{GL_COMPRESSED_RGBA};
578
+    auto static constexpr internal_format_compressed_srgb =
579
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
580
+    auto static constexpr integer = bool(*"");
581
+    void static uniform(GLint location, glm::vec4 const & value)
582
+    {
583
+        if (GLBase::debug() >= 1)
584
+            GLBase::check_supported({2, 0}, {});
585
+        glUniform4fv(location, 1, glm::value_ptr(value));
586
+    }
587
+    void static vertex_attrib(GLint location, glm::vec4 const & value)
588
+    {
589
+        if (GLBase::debug() >= 1)
590
+            GLBase::check_supported({2, 0}, {});
591
+        if (location == -1)
592
+            return;
593
+        for (auto column = GLuint{0}; column < columns; ++column)
594
+            glVertexAttrib4fv(
595
+                (GLuint)location + column,
596
+                glm::value_ptr(value) + rows * column);
597
+    }
598
+    void static vertex_attrib_pointer(
599
+        GLint       location,
600
+        std::size_t offset = 0,
601
+        std::size_t stride = sizeof(glm::vec4))
602
+    {
603
+        if (GLBase::debug() >= 1)
604
+            GLBase::check_supported({2, 0}, {});
605
+        if (location == -1)
606
+            return;
607
+        auto constexpr sizeof_column = sizeof(glm::vec4) / columns;
608
+        for (auto column = GLuint{0}; column < columns; ++column)
609
+            glVertexAttribPointer(
610
+                (GLuint)location + column,
611
+                rows,
612
+                type,
613
+                GL_FALSE,
614
+                (GLsizei)stride,
615
+                (void const *)(offset + sizeof_column * column));
616
+    }
617
+};
618
+
619
+template <> struct GLTraits::Value<glm::mat2>
620
+{
621
+    auto static constexpr name                 = "glm::mat2";
622
+    auto static constexpr columns              = GLint{2};
623
+    auto static constexpr rows                 = GLint{2};
624
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2};
625
+    auto static constexpr format               = GLenum{GL_RG};
626
+    auto static constexpr type                 = GLenum{GL_FLOAT};
627
+    auto static constexpr internal_format      = GLenum{GL_RG32F};
628
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
629
+    auto static constexpr internal_format_compressed =
630
+        GLenum{GL_COMPRESSED_RG};
631
+    auto static constexpr internal_format_compressed_srgb =
632
+        GLenum{GL_COMPRESSED_SRGB};
633
+    auto static constexpr integer = bool(*"");
634
+    void static uniform(GLint location, glm::mat2 const & value)
635
+    {
636
+        if (GLBase::debug() >= 1)
637
+            GLBase::check_supported({2, 0}, {});
638
+        glUniformMatrix2fv(location, 1, GL_FALSE, glm::value_ptr(value));
639
+    }
640
+    void static vertex_attrib(GLint location, glm::mat2 const & value)
641
+    {
642
+        if (GLBase::debug() >= 1)
643
+            GLBase::check_supported({2, 0}, {});
644
+        if (location == -1)
645
+            return;
646
+        for (auto column = GLuint{0}; column < columns; ++column)
647
+            glVertexAttrib2fv(
648
+                (GLuint)location + column,
649
+                glm::value_ptr(value) + rows * column);
650
+    }
651
+    void static vertex_attrib_pointer(
652
+        GLint       location,
653
+        std::size_t offset = 0,
654
+        std::size_t stride = sizeof(glm::mat2))
655
+    {
656
+        if (GLBase::debug() >= 1)
657
+            GLBase::check_supported({2, 0}, {});
658
+        if (location == -1)
659
+            return;
660
+        auto constexpr sizeof_column = sizeof(glm::mat2) / columns;
661
+        for (auto column = GLuint{0}; column < columns; ++column)
662
+            glVertexAttribPointer(
663
+                (GLuint)location + column,
664
+                rows,
665
+                type,
666
+                GL_FALSE,
667
+                (GLsizei)stride,
668
+                (void const *)(offset + sizeof_column * column));
669
+    }
670
+};
671
+
672
+template <> struct GLTraits::Value<glm::mat2x3>
673
+{
674
+    auto static constexpr name                 = "glm::mat2x3";
675
+    auto static constexpr columns              = GLint{2};
676
+    auto static constexpr rows                 = GLint{3};
677
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2x3};
678
+    auto static constexpr format               = GLenum{GL_RGB};
679
+    auto static constexpr type                 = GLenum{GL_FLOAT};
680
+    auto static constexpr internal_format      = GLenum{GL_RGB32F};
681
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
682
+    auto static constexpr internal_format_compressed =
683
+        GLenum{GL_COMPRESSED_RGB};
684
+    auto static constexpr internal_format_compressed_srgb =
685
+        GLenum{GL_COMPRESSED_SRGB};
686
+    auto static constexpr integer = bool(*"");
687
+    void static uniform(GLint location, glm::mat2x3 const & value)
688
+    {
689
+        if (GLBase::debug() >= 1)
690
+            GLBase::check_supported({2, 1}, {});
691
+        glUniformMatrix2x3fv(location, 1, GL_FALSE, glm::value_ptr(value));
692
+    }
693
+    void static vertex_attrib(GLint location, glm::mat2x3 const & value)
694
+    {
695
+        if (GLBase::debug() >= 1)
696
+            GLBase::check_supported({2, 0}, {});
697
+        if (location == -1)
698
+            return;
699
+        for (auto column = GLuint{0}; column < columns; ++column)
700
+            glVertexAttrib3fv(
701
+                (GLuint)location + column,
702
+                glm::value_ptr(value) + rows * column);
703
+    }
704
+    void static vertex_attrib_pointer(
705
+        GLint       location,
706
+        std::size_t offset = 0,
707
+        std::size_t stride = sizeof(glm::mat2x3))
708
+    {
709
+        if (GLBase::debug() >= 1)
710
+            GLBase::check_supported({2, 0}, {});
711
+        if (location == -1)
712
+            return;
713
+        auto constexpr sizeof_column = sizeof(glm::mat2x3) / columns;
714
+        for (auto column = GLuint{0}; column < columns; ++column)
715
+            glVertexAttribPointer(
716
+                (GLuint)location + column,
717
+                rows,
718
+                type,
719
+                GL_FALSE,
720
+                (GLsizei)stride,
721
+                (void const *)(offset + sizeof_column * column));
722
+    }
723
+};
724
+
725
+template <> struct GLTraits::Value<glm::mat2x4>
726
+{
727
+    auto static constexpr name                 = "glm::mat2x4";
728
+    auto static constexpr columns              = GLint{2};
729
+    auto static constexpr rows                 = GLint{4};
730
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2x4};
731
+    auto static constexpr format               = GLenum{GL_RGBA};
732
+    auto static constexpr type                 = GLenum{GL_FLOAT};
733
+    auto static constexpr internal_format      = GLenum{GL_RGBA32F};
734
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
735
+    auto static constexpr internal_format_compressed =
736
+        GLenum{GL_COMPRESSED_RGBA};
737
+    auto static constexpr internal_format_compressed_srgb =
738
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
739
+    auto static constexpr integer = bool(*"");
740
+    void static uniform(GLint location, glm::mat2x4 const & value)
741
+    {
742
+        if (GLBase::debug() >= 1)
743
+            GLBase::check_supported({2, 1}, {});
744
+        glUniformMatrix2x4fv(location, 1, GL_FALSE, glm::value_ptr(value));
745
+    }
746
+    void static vertex_attrib(GLint location, glm::mat2x4 const & value)
747
+    {
748
+        if (GLBase::debug() >= 1)
749
+            GLBase::check_supported({2, 0}, {});
750
+        if (location == -1)
751
+            return;
752
+        for (auto column = GLuint{0}; column < columns; ++column)
753
+            glVertexAttrib4fv(
754
+                (GLuint)location + column,
755
+                glm::value_ptr(value) + rows * column);
756
+    }
757
+    void static vertex_attrib_pointer(
758
+        GLint       location,
759
+        std::size_t offset = 0,
760
+        std::size_t stride = sizeof(glm::mat2x4))
761
+    {
762
+        if (GLBase::debug() >= 1)
763
+            GLBase::check_supported({2, 0}, {});
764
+        if (location == -1)
765
+            return;
766
+        auto constexpr sizeof_column = sizeof(glm::mat2x4) / columns;
767
+        for (auto column = GLuint{0}; column < columns; ++column)
768
+            glVertexAttribPointer(
769
+                (GLuint)location + column,
770
+                rows,
771
+                type,
772
+                GL_FALSE,
773
+                (GLsizei)stride,
774
+                (void const *)(offset + sizeof_column * column));
775
+    }
776
+};
777
+
778
+template <> struct GLTraits::Value<glm::mat3x2>
779
+{
780
+    auto static constexpr name                 = "glm::mat3x2";
781
+    auto static constexpr columns              = GLint{3};
782
+    auto static constexpr rows                 = GLint{2};
783
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3x2};
784
+    auto static constexpr format               = GLenum{GL_RG};
785
+    auto static constexpr type                 = GLenum{GL_FLOAT};
786
+    auto static constexpr internal_format      = GLenum{GL_RG32F};
787
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
788
+    auto static constexpr internal_format_compressed =
789
+        GLenum{GL_COMPRESSED_RG};
790
+    auto static constexpr internal_format_compressed_srgb =
791
+        GLenum{GL_COMPRESSED_SRGB};
792
+    auto static constexpr integer = bool(*"");
793
+    void static uniform(GLint location, glm::mat3x2 const & value)
794
+    {
795
+        if (GLBase::debug() >= 1)
796
+            GLBase::check_supported({2, 1}, {});
797
+        glUniformMatrix3x2fv(location, 1, GL_FALSE, glm::value_ptr(value));
798
+    }
799
+    void static vertex_attrib(GLint location, glm::mat3x2 const & value)
800
+    {
801
+        if (GLBase::debug() >= 1)
802
+            GLBase::check_supported({2, 0}, {});
803
+        if (location == -1)
804
+            return;
805
+        for (auto column = GLuint{0}; column < columns; ++column)
806
+            glVertexAttrib2fv(
807
+                (GLuint)location + column,
808
+                glm::value_ptr(value) + rows * column);
809
+    }
810
+    void static vertex_attrib_pointer(
811
+        GLint       location,
812
+        std::size_t offset = 0,
813
+        std::size_t stride = sizeof(glm::mat3x2))
814
+    {
815
+        if (GLBase::debug() >= 1)
816
+            GLBase::check_supported({2, 0}, {});
817
+        if (location == -1)
818
+            return;
819
+        auto constexpr sizeof_column = sizeof(glm::mat3x2) / columns;
820
+        for (auto column = GLuint{0}; column < columns; ++column)
821
+            glVertexAttribPointer(
822
+                (GLuint)location + column,
823
+                rows,
824
+                type,
825
+                GL_FALSE,
826
+                (GLsizei)stride,
827
+                (void const *)(offset + sizeof_column * column));
828
+    }
829
+};
830
+
831
+template <> struct GLTraits::Value<glm::mat3>
832
+{
833
+    auto static constexpr name                 = "glm::mat3";
834
+    auto static constexpr columns              = GLint{3};
835
+    auto static constexpr rows                 = GLint{3};
836
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3};
837
+    auto static constexpr format               = GLenum{GL_RGB};
838
+    auto static constexpr type                 = GLenum{GL_FLOAT};
839
+    auto static constexpr internal_format      = GLenum{GL_RGB32F};
840
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
841
+    auto static constexpr internal_format_compressed =
842
+        GLenum{GL_COMPRESSED_RGB};
843
+    auto static constexpr internal_format_compressed_srgb =
844
+        GLenum{GL_COMPRESSED_SRGB};
845
+    auto static constexpr integer = bool(*"");
846
+    void static uniform(GLint location, glm::mat3 const & value)
847
+    {
848
+        if (GLBase::debug() >= 1)
849
+            GLBase::check_supported({2, 0}, {});
850
+        glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(value));
851
+    }
852
+    void static vertex_attrib(GLint location, glm::mat3 const & value)
853
+    {
854
+        if (GLBase::debug() >= 1)
855
+            GLBase::check_supported({2, 0}, {});
856
+        if (location == -1)
857
+            return;
858
+        for (auto column = GLuint{0}; column < columns; ++column)
859
+            glVertexAttrib3fv(
860
+                (GLuint)location + column,
861
+                glm::value_ptr(value) + rows * column);
862
+    }
863
+    void static vertex_attrib_pointer(
864
+        GLint       location,
865
+        std::size_t offset = 0,
866
+        std::size_t stride = sizeof(glm::mat3))
867
+    {
868
+        if (GLBase::debug() >= 1)
869
+            GLBase::check_supported({2, 0}, {});
870
+        if (location == -1)
871
+            return;
872
+        auto constexpr sizeof_column = sizeof(glm::mat3) / columns;
873
+        for (auto column = GLuint{0}; column < columns; ++column)
874
+            glVertexAttribPointer(
875
+                (GLuint)location + column,
876
+                rows,
877
+                type,
878
+                GL_FALSE,
879
+                (GLsizei)stride,
880
+                (void const *)(offset + sizeof_column * column));
881
+    }
882
+};
883
+
884
+template <> struct GLTraits::Value<glm::mat3x4>
885
+{
886
+    auto static constexpr name                 = "glm::mat3x4";
887
+    auto static constexpr columns              = GLint{3};
888
+    auto static constexpr rows                 = GLint{4};
889
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3x4};
890
+    auto static constexpr format               = GLenum{GL_RGBA};
891
+    auto static constexpr type                 = GLenum{GL_FLOAT};
892
+    auto static constexpr internal_format      = GLenum{GL_RGBA32F};
893
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
894
+    auto static constexpr internal_format_compressed =
895
+        GLenum{GL_COMPRESSED_RGBA};
896
+    auto static constexpr internal_format_compressed_srgb =
897
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
898
+    auto static constexpr integer = bool(*"");
899
+    void static uniform(GLint location, glm::mat3x4 const & value)
900
+    {
901
+        if (GLBase::debug() >= 1)
902
+            GLBase::check_supported({2, 1}, {});
903
+        glUniformMatrix3x4fv(location, 1, GL_FALSE, glm::value_ptr(value));
904
+    }
905
+    void static vertex_attrib(GLint location, glm::mat3x4 const & value)
906
+    {
907
+        if (GLBase::debug() >= 1)
908
+            GLBase::check_supported({2, 0}, {});
909
+        if (location == -1)
910
+            return;
911
+        for (auto column = GLuint{0}; column < columns; ++column)
912
+            glVertexAttrib4fv(
913
+                (GLuint)location + column,
914
+                glm::value_ptr(value) + rows * column);
915
+    }
916
+    void static vertex_attrib_pointer(
917
+        GLint       location,
918
+        std::size_t offset = 0,
919
+        std::size_t stride = sizeof(glm::mat3x4))
920
+    {
921
+        if (GLBase::debug() >= 1)
922
+            GLBase::check_supported({2, 0}, {});
923
+        if (location == -1)
924
+            return;
925
+        auto constexpr sizeof_column = sizeof(glm::mat3x4) / columns;
926
+        for (auto column = GLuint{0}; column < columns; ++column)
927
+            glVertexAttribPointer(
928
+                (GLuint)location + column,
929
+                rows,
930
+                type,
931
+                GL_FALSE,
932
+                (GLsizei)stride,
933
+                (void const *)(offset + sizeof_column * column));
934
+    }
935
+};
936
+
937
+template <> struct GLTraits::Value<glm::mat4x2>
938
+{
939
+    auto static constexpr name                 = "glm::mat4x2";
940
+    auto static constexpr columns              = GLint{4};
941
+    auto static constexpr rows                 = GLint{2};
942
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4x2};
943
+    auto static constexpr format               = GLenum{GL_RG};
944
+    auto static constexpr type                 = GLenum{GL_FLOAT};
945
+    auto static constexpr internal_format      = GLenum{GL_RG32F};
946
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
947
+    auto static constexpr internal_format_compressed =
948
+        GLenum{GL_COMPRESSED_RG};
949
+    auto static constexpr internal_format_compressed_srgb =
950
+        GLenum{GL_COMPRESSED_SRGB};
951
+    auto static constexpr integer = bool(*"");
952
+    void static uniform(GLint location, glm::mat4x2 const & value)
953
+    {
954
+        if (GLBase::debug() >= 1)
955
+            GLBase::check_supported({2, 1}, {});
956
+        glUniformMatrix4x2fv(location, 1, GL_FALSE, glm::value_ptr(value));
957
+    }
958
+    void static vertex_attrib(GLint location, glm::mat4x2 const & value)
959
+    {
960
+        if (GLBase::debug() >= 1)
961
+            GLBase::check_supported({2, 0}, {});
962
+        if (location == -1)
963
+            return;
964
+        for (auto column = GLuint{0}; column < columns; ++column)
965
+            glVertexAttrib2fv(
966
+                (GLuint)location + column,
967
+                glm::value_ptr(value) + rows * column);
968
+    }
969
+    void static vertex_attrib_pointer(
970
+        GLint       location,
971
+        std::size_t offset = 0,
972
+        std::size_t stride = sizeof(glm::mat4x2))
973
+    {
974
+        if (GLBase::debug() >= 1)
975
+            GLBase::check_supported({2, 0}, {});
976
+        if (location == -1)
977
+            return;
978
+        auto constexpr sizeof_column = sizeof(glm::mat4x2) / columns;
979
+        for (auto column = GLuint{0}; column < columns; ++column)
980
+            glVertexAttribPointer(
981
+                (GLuint)location + column,
982
+                rows,
983
+                type,
984
+                GL_FALSE,
985
+                (GLsizei)stride,
986
+                (void const *)(offset + sizeof_column * column));
987
+    }
988
+};
989
+
990
+template <> struct GLTraits::Value<glm::mat4x3>
991
+{
992
+    auto static constexpr name                 = "glm::mat4x3";
993
+    auto static constexpr columns              = GLint{4};
994
+    auto static constexpr rows                 = GLint{3};
995
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4x3};
996
+    auto static constexpr format               = GLenum{GL_RGB};
997
+    auto static constexpr type                 = GLenum{GL_FLOAT};
998
+    auto static constexpr internal_format      = GLenum{GL_RGB32F};
999
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1000
+    auto static constexpr internal_format_compressed =
1001
+        GLenum{GL_COMPRESSED_RGB};
1002
+    auto static constexpr internal_format_compressed_srgb =
1003
+        GLenum{GL_COMPRESSED_SRGB};
1004
+    auto static constexpr integer = bool(*"");
1005
+    void static uniform(GLint location, glm::mat4x3 const & value)
1006
+    {
1007
+        if (GLBase::debug() >= 1)
1008
+            GLBase::check_supported({2, 1}, {});
1009
+        glUniformMatrix4x3fv(location, 1, GL_FALSE, glm::value_ptr(value));
1010
+    }
1011
+    void static vertex_attrib(GLint location, glm::mat4x3 const & value)
1012
+    {
1013
+        if (GLBase::debug() >= 1)
1014
+            GLBase::check_supported({2, 0}, {});
1015
+        if (location == -1)
1016
+            return;
1017
+        for (auto column = GLuint{0}; column < columns; ++column)
1018
+            glVertexAttrib3fv(
1019
+                (GLuint)location + column,
1020
+                glm::value_ptr(value) + rows * column);
1021
+    }
1022
+    void static vertex_attrib_pointer(
1023
+        GLint       location,
1024
+        std::size_t offset = 0,
1025
+        std::size_t stride = sizeof(glm::mat4x3))
1026
+    {
1027
+        if (GLBase::debug() >= 1)
1028
+            GLBase::check_supported({2, 0}, {});
1029
+        if (location == -1)
1030
+            return;
1031
+        auto constexpr sizeof_column = sizeof(glm::mat4x3) / columns;
1032
+        for (auto column = GLuint{0}; column < columns; ++column)
1033
+            glVertexAttribPointer(
1034
+                (GLuint)location + column,
1035
+                rows,
1036
+                type,
1037
+                GL_FALSE,
1038
+                (GLsizei)stride,
1039
+                (void const *)(offset + sizeof_column * column));
1040
+    }
1041
+};
1042
+
1043
+template <> struct GLTraits::Value<glm::mat4>
1044
+{
1045
+    auto static constexpr name                 = "glm::mat4";
1046
+    auto static constexpr columns              = GLint{4};
1047
+    auto static constexpr rows                 = GLint{4};
1048
+    auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4};
1049
+    auto static constexpr format               = GLenum{GL_RGBA};
1050
+    auto static constexpr type                 = GLenum{GL_FLOAT};
1051
+    auto static constexpr internal_format      = GLenum{GL_RGBA32F};
1052
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1053
+    auto static constexpr internal_format_compressed =
1054
+        GLenum{GL_COMPRESSED_RGBA};
1055
+    auto static constexpr internal_format_compressed_srgb =
1056
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1057
+    auto static constexpr integer = bool(*"");
1058
+    void static uniform(GLint location, glm::mat4 const & value)
1059
+    {
1060
+        if (GLBase::debug() >= 1)
1061
+            GLBase::check_supported({2, 0}, {});
1062
+        glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
1063
+    }
1064
+    void static vertex_attrib(GLint location, glm::mat4 const & value)
1065
+    {
1066
+        if (GLBase::debug() >= 1)
1067
+            GLBase::check_supported({2, 0}, {});
1068
+        if (location == -1)
1069
+            return;
1070
+        for (auto column = GLuint{0}; column < columns; ++column)
1071
+            glVertexAttrib4fv(
1072
+                (GLuint)location + column,
1073
+                glm::value_ptr(value) + rows * column);
1074
+    }
1075
+    void static vertex_attrib_pointer(
1076
+        GLint       location,
1077
+        std::size_t offset = 0,
1078
+        std::size_t stride = sizeof(glm::mat4))
1079
+    {
1080
+        if (GLBase::debug() >= 1)
1081
+            GLBase::check_supported({2, 0}, {});
1082
+        if (location == -1)
1083
+            return;
1084
+        auto constexpr sizeof_column = sizeof(glm::mat4) / columns;
1085
+        for (auto column = GLuint{0}; column < columns; ++column)
1086
+            glVertexAttribPointer(
1087
+                (GLuint)location + column,
1088
+                rows,
1089
+                type,
1090
+                GL_FALSE,
1091
+                (GLsizei)stride,
1092
+                (void const *)(offset + sizeof_column * column));
1093
+    }
1094
+};
1095
+
1096
+template <> struct GLTraits::Value<glm::ivec2>
1097
+{
1098
+    auto static constexpr name                 = "glm::ivec2";
1099
+    auto static constexpr columns              = GLint{1};
1100
+    auto static constexpr rows                 = GLint{2};
1101
+    auto static constexpr glsl                 = GLenum{GL_INT_VEC2};
1102
+    auto static constexpr format               = GLenum{GL_RG_INTEGER};
1103
+    auto static constexpr type                 = GLenum{GL_INT};
1104
+    auto static constexpr internal_format      = GLenum{GL_RG32I};
1105
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1106
+    auto static constexpr internal_format_compressed =
1107
+        GLenum{GL_COMPRESSED_RG};
1108
+    auto static constexpr internal_format_compressed_srgb =
1109
+        GLenum{GL_COMPRESSED_SRGB};
1110
+    auto static constexpr integer = bool(*"_INTEGER");
1111
+    void static uniform(GLint location, glm::ivec2 const & value)
1112
+    {
1113
+        if (GLBase::debug() >= 1)
1114
+            GLBase::check_supported({2, 0}, {});
1115
+        glUniform2iv(location, 1, glm::value_ptr(value));
1116
+    }
1117
+    void static vertex_attrib(GLint location, glm::ivec2 const & value)
1118
+    {
1119
+        if (GLBase::debug() >= 1)
1120
+            GLBase::check_supported({3, 0}, {});
1121
+        if (location == -1)
1122
+            return;
1123
+        for (auto column = GLuint{0}; column < columns; ++column)
1124
+            glVertexAttribI2iv(
1125
+                (GLuint)location + column,
1126
+                glm::value_ptr(value) + rows * column);
1127
+    }
1128
+    void static vertex_attrib_pointer(
1129
+        GLint       location,
1130
+        std::size_t offset = 0,
1131
+        std::size_t stride = sizeof(glm::ivec2))
1132
+    {
1133
+        if (GLBase::debug() >= 1)
1134
+            GLBase::check_supported({3, 0}, {});
1135
+        if (location == -1)
1136
+            return;
1137
+        auto constexpr sizeof_column = sizeof(glm::ivec2) / columns;
1138
+        for (auto column = GLuint{0}; column < columns; ++column)
1139
+            glVertexAttribIPointer(
1140
+                (GLuint)location + column,
1141
+                rows,
1142
+                type,
1143
+                (GLsizei)stride,
1144
+                (void const *)(offset + sizeof_column * column));
1145
+    }
1146
+};
1147
+
1148
+template <> struct GLTraits::Value<glm::ivec3>
1149
+{
1150
+    auto static constexpr name                 = "glm::ivec3";
1151
+    auto static constexpr columns              = GLint{1};
1152
+    auto static constexpr rows                 = GLint{3};
1153
+    auto static constexpr glsl                 = GLenum{GL_INT_VEC3};
1154
+    auto static constexpr format               = GLenum{GL_RGB_INTEGER};
1155
+    auto static constexpr type                 = GLenum{GL_INT};
1156
+    auto static constexpr internal_format      = GLenum{GL_RGB32I};
1157
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1158
+    auto static constexpr internal_format_compressed =
1159
+        GLenum{GL_COMPRESSED_RGB};
1160
+    auto static constexpr internal_format_compressed_srgb =
1161
+        GLenum{GL_COMPRESSED_SRGB};
1162
+    auto static constexpr integer = bool(*"_INTEGER");
1163
+    void static uniform(GLint location, glm::ivec3 const & value)
1164
+    {
1165
+        if (GLBase::debug() >= 1)
1166
+            GLBase::check_supported({2, 0}, {});
1167
+        glUniform3iv(location, 1, glm::value_ptr(value));
1168
+    }
1169
+    void static vertex_attrib(GLint location, glm::ivec3 const & value)
1170
+    {
1171
+        if (GLBase::debug() >= 1)
1172
+            GLBase::check_supported({3, 0}, {});
1173
+        if (location == -1)
1174
+            return;
1175
+        for (auto column = GLuint{0}; column < columns; ++column)
1176
+            glVertexAttribI3iv(
1177
+                (GLuint)location + column,
1178
+                glm::value_ptr(value) + rows * column);
1179
+    }
1180
+    void static vertex_attrib_pointer(
1181
+        GLint       location,
1182
+        std::size_t offset = 0,
1183
+        std::size_t stride = sizeof(glm::ivec3))
1184
+    {
1185
+        if (GLBase::debug() >= 1)
1186
+            GLBase::check_supported({3, 0}, {});
1187
+        if (location == -1)
1188
+            return;
1189
+        auto constexpr sizeof_column = sizeof(glm::ivec3) / columns;
1190
+        for (auto column = GLuint{0}; column < columns; ++column)
1191
+            glVertexAttribIPointer(
1192
+                (GLuint)location + column,
1193
+                rows,
1194
+                type,
1195
+                (GLsizei)stride,
1196
+                (void const *)(offset + sizeof_column * column));
1197
+    }
1198
+};
1199
+
1200
+template <> struct GLTraits::Value<glm::ivec4>
1201
+{
1202
+    auto static constexpr name                 = "glm::ivec4";
1203
+    auto static constexpr columns              = GLint{1};
1204
+    auto static constexpr rows                 = GLint{4};
1205
+    auto static constexpr glsl                 = GLenum{GL_INT_VEC4};
1206
+    auto static constexpr format               = GLenum{GL_RGBA_INTEGER};
1207
+    auto static constexpr type                 = GLenum{GL_INT};
1208
+    auto static constexpr internal_format      = GLenum{GL_RGBA32I};
1209
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1210
+    auto static constexpr internal_format_compressed =
1211
+        GLenum{GL_COMPRESSED_RGBA};
1212
+    auto static constexpr internal_format_compressed_srgb =
1213
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1214
+    auto static constexpr integer = bool(*"_INTEGER");
1215
+    void static uniform(GLint location, glm::ivec4 const & value)
1216
+    {
1217
+        if (GLBase::debug() >= 1)
1218
+            GLBase::check_supported({2, 0}, {});
1219
+        glUniform4iv(location, 1, glm::value_ptr(value));
1220
+    }
1221
+    void static vertex_attrib(GLint location, glm::ivec4 const & value)
1222
+    {
1223
+        if (GLBase::debug() >= 1)
1224
+            GLBase::check_supported({3, 0}, {});
1225
+        if (location == -1)
1226
+            return;
1227
+        for (auto column = GLuint{0}; column < columns; ++column)
1228
+            glVertexAttribI4iv(
1229
+                (GLuint)location + column,
1230
+                glm::value_ptr(value) + rows * column);
1231
+    }
1232
+    void static vertex_attrib_pointer(
1233
+        GLint       location,
1234
+        std::size_t offset = 0,
1235
+        std::size_t stride = sizeof(glm::ivec4))
1236
+    {
1237
+        if (GLBase::debug() >= 1)
1238
+            GLBase::check_supported({3, 0}, {});
1239
+        if (location == -1)
1240
+            return;
1241
+        auto constexpr sizeof_column = sizeof(glm::ivec4) / columns;
1242
+        for (auto column = GLuint{0}; column < columns; ++column)
1243
+            glVertexAttribIPointer(
1244
+                (GLuint)location + column,
1245
+                rows,
1246
+                type,
1247
+                (GLsizei)stride,
1248
+                (void const *)(offset + sizeof_column * column));
1249
+    }
1250
+};
1251
+
1252
+template <> struct GLTraits::Value<glm::uvec2>
1253
+{
1254
+    auto static constexpr name                 = "glm::uvec2";
1255
+    auto static constexpr columns              = GLint{1};
1256
+    auto static constexpr rows                 = GLint{2};
1257
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC2};
1258
+    auto static constexpr format               = GLenum{GL_RG_INTEGER};
1259
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
1260
+    auto static constexpr internal_format      = GLenum{GL_RG32UI};
1261
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1262
+    auto static constexpr internal_format_compressed =
1263
+        GLenum{GL_COMPRESSED_RG};
1264
+    auto static constexpr internal_format_compressed_srgb =
1265
+        GLenum{GL_COMPRESSED_SRGB};
1266
+    auto static constexpr integer = bool(*"_INTEGER");
1267
+    void static uniform(GLint location, glm::uvec2 const & value)
1268
+    {
1269
+        if (GLBase::debug() >= 1)
1270
+            GLBase::check_supported({3, 0}, {});
1271
+        glUniform2uiv(location, 1, glm::value_ptr(value));
1272
+    }
1273
+    void static vertex_attrib(GLint location, glm::uvec2 const & value)
1274
+    {
1275
+        if (GLBase::debug() >= 1)
1276
+            GLBase::check_supported({3, 0}, {});
1277
+        if (location == -1)
1278
+            return;
1279
+        for (auto column = GLuint{0}; column < columns; ++column)
1280
+            glVertexAttribI2uiv(
1281
+                (GLuint)location + column,
1282
+                glm::value_ptr(value) + rows * column);
1283
+    }
1284
+    void static vertex_attrib_pointer(
1285
+        GLint       location,
1286
+        std::size_t offset = 0,
1287
+        std::size_t stride = sizeof(glm::uvec2))
1288
+    {
1289
+        if (GLBase::debug() >= 1)
1290
+            GLBase::check_supported({3, 0}, {});
1291
+        if (location == -1)
1292
+            return;
1293
+        auto constexpr sizeof_column = sizeof(glm::uvec2) / columns;
1294
+        for (auto column = GLuint{0}; column < columns; ++column)
1295
+            glVertexAttribIPointer(
1296
+                (GLuint)location + column,
1297
+                rows,
1298
+                type,
1299
+                (GLsizei)stride,
1300
+                (void const *)(offset + sizeof_column * column));
1301
+    }
1302
+};
1303
+
1304
+template <> struct GLTraits::Value<glm::uvec3>
1305
+{
1306
+    auto static constexpr name                 = "glm::uvec3";
1307
+    auto static constexpr columns              = GLint{1};
1308
+    auto static constexpr rows                 = GLint{3};
1309
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC3};
1310
+    auto static constexpr format               = GLenum{GL_RGB_INTEGER};
1311
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
1312
+    auto static constexpr internal_format      = GLenum{GL_RGB32UI};
1313
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1314
+    auto static constexpr internal_format_compressed =
1315
+        GLenum{GL_COMPRESSED_RGB};
1316
+    auto static constexpr internal_format_compressed_srgb =
1317
+        GLenum{GL_COMPRESSED_SRGB};
1318
+    auto static constexpr integer = bool(*"_INTEGER");
1319
+    void static uniform(GLint location, glm::uvec3 const & value)
1320
+    {
1321
+        if (GLBase::debug() >= 1)
1322
+            GLBase::check_supported({3, 0}, {});
1323
+        glUniform3uiv(location, 1, glm::value_ptr(value));
1324
+    }
1325
+    void static vertex_attrib(GLint location, glm::uvec3 const & value)
1326
+    {
1327
+        if (GLBase::debug() >= 1)
1328
+            GLBase::check_supported({3, 0}, {});
1329
+        if (location == -1)
1330
+            return;
1331
+        for (auto column = GLuint{0}; column < columns; ++column)
1332
+            glVertexAttribI3uiv(
1333
+                (GLuint)location + column,
1334
+                glm::value_ptr(value) + rows * column);
1335
+    }
1336
+    void static vertex_attrib_pointer(
1337
+        GLint       location,
1338
+        std::size_t offset = 0,
1339
+        std::size_t stride = sizeof(glm::uvec3))
1340
+    {
1341
+        if (GLBase::debug() >= 1)
1342
+            GLBase::check_supported({3, 0}, {});
1343
+        if (location == -1)
1344
+            return;
1345
+        auto constexpr sizeof_column = sizeof(glm::uvec3) / columns;
1346
+        for (auto column = GLuint{0}; column < columns; ++column)
1347
+            glVertexAttribIPointer(
1348
+                (GLuint)location + column,
1349
+                rows,
1350
+                type,
1351
+                (GLsizei)stride,
1352
+                (void const *)(offset + sizeof_column * column));
1353
+    }
1354
+};
1355
+
1356
+template <> struct GLTraits::Value<glm::uvec4>
1357
+{
1358
+    auto static constexpr name                 = "glm::uvec4";
1359
+    auto static constexpr columns              = GLint{1};
1360
+    auto static constexpr rows                 = GLint{4};
1361
+    auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC4};
1362
+    auto static constexpr format               = GLenum{GL_RGBA_INTEGER};
1363
+    auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
1364
+    auto static constexpr internal_format      = GLenum{GL_RGBA32UI};
1365
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1366
+    auto static constexpr internal_format_compressed =
1367
+        GLenum{GL_COMPRESSED_RGBA};
1368
+    auto static constexpr internal_format_compressed_srgb =
1369
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1370
+    auto static constexpr integer = bool(*"_INTEGER");
1371
+    void static uniform(GLint location, glm::uvec4 const & value)
1372
+    {
1373
+        if (GLBase::debug() >= 1)
1374
+            GLBase::check_supported({3, 0}, {});
1375
+        glUniform4uiv(location, 1, glm::value_ptr(value));
1376
+    }
1377
+    void static vertex_attrib(GLint location, glm::uvec4 const & value)
1378
+    {
1379
+        if (GLBase::debug() >= 1)
1380
+            GLBase::check_supported({3, 0}, {});
1381
+        if (location == -1)
1382
+            return;
1383
+        for (auto column = GLuint{0}; column < columns; ++column)
1384
+            glVertexAttribI4uiv(
1385
+                (GLuint)location + column,
1386
+                glm::value_ptr(value) + rows * column);
1387
+    }
1388
+    void static vertex_attrib_pointer(
1389
+        GLint       location,
1390
+        std::size_t offset = 0,
1391
+        std::size_t stride = sizeof(glm::uvec4))
1392
+    {
1393
+        if (GLBase::debug() >= 1)
1394
+            GLBase::check_supported({3, 0}, {});
1395
+        if (location == -1)
1396
+            return;
1397
+        auto constexpr sizeof_column = sizeof(glm::uvec4) / columns;
1398
+        for (auto column = GLuint{0}; column < columns; ++column)
1399
+            glVertexAttribIPointer(
1400
+                (GLuint)location + column,
1401
+                rows,
1402
+                type,
1403
+                (GLsizei)stride,
1404
+                (void const *)(offset + sizeof_column * column));
1405
+    }
1406
+};
1407
+
1408
+template <> struct GLTraits::Value<glm::dvec2>
1409
+{
1410
+    auto static constexpr name                 = "glm::dvec2";
1411
+    auto static constexpr columns              = GLint{1};
1412
+    auto static constexpr rows                 = GLint{2};
1413
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC2};
1414
+    auto static constexpr format               = GLenum{GL_RG};
1415
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1416
+    auto static constexpr internal_format      = GLenum{GL_RG};
1417
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1418
+    auto static constexpr internal_format_compressed =
1419
+        GLenum{GL_COMPRESSED_RG};
1420
+    auto static constexpr internal_format_compressed_srgb =
1421
+        GLenum{GL_COMPRESSED_SRGB};
1422
+    auto static constexpr integer = bool(*"");
1423
+    void static uniform(GLint location, glm::dvec2 const & value)
1424
+    {
1425
+        if (GLBase::debug() >= 1)
1426
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1427
+        glUniform2dv(location, 1, glm::value_ptr(value));
1428
+    }
1429
+    void static vertex_attrib(GLint location, glm::dvec2 const & value)
1430
+    {
1431
+        if (GLBase::debug() >= 1)
1432
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1433
+        if (location == -1)
1434
+            return;
1435
+        for (auto column = GLuint{0}; column < columns; ++column)
1436
+            glVertexAttribL2dv(
1437
+                (GLuint)location + column,
1438
+                glm::value_ptr(value) + rows * column);
1439
+    }
1440
+    void static vertex_attrib_pointer(
1441
+        GLint       location,
1442
+        std::size_t offset = 0,
1443
+        std::size_t stride = sizeof(glm::dvec2))
1444
+    {
1445
+        if (GLBase::debug() >= 1)
1446
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1447
+        if (location == -1)
1448
+            return;
1449
+        auto constexpr sizeof_column = sizeof(glm::dvec2) / columns;
1450
+        for (auto column = GLuint{0}; column < columns; ++column)
1451
+            glVertexAttribLPointer(
1452
+                (GLuint)location + column,
1453
+                rows,
1454
+                type,
1455
+                (GLsizei)stride,
1456
+                (void const *)(offset + sizeof_column * column));
1457
+    }
1458
+};
1459
+
1460
+template <> struct GLTraits::Value<glm::dvec3>
1461
+{
1462
+    auto static constexpr name                 = "glm::dvec3";
1463
+    auto static constexpr columns              = GLint{1};
1464
+    auto static constexpr rows                 = GLint{3};
1465
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC3};
1466
+    auto static constexpr format               = GLenum{GL_RGB};
1467
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1468
+    auto static constexpr internal_format      = GLenum{GL_RGB};
1469
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1470
+    auto static constexpr internal_format_compressed =
1471
+        GLenum{GL_COMPRESSED_RGB};
1472
+    auto static constexpr internal_format_compressed_srgb =
1473
+        GLenum{GL_COMPRESSED_SRGB};
1474
+    auto static constexpr integer = bool(*"");
1475
+    void static uniform(GLint location, glm::dvec3 const & value)
1476
+    {
1477
+        if (GLBase::debug() >= 1)
1478
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1479
+        glUniform3dv(location, 1, glm::value_ptr(value));
1480
+    }
1481
+    void static vertex_attrib(GLint location, glm::dvec3 const & value)
1482
+    {
1483
+        if (GLBase::debug() >= 1)
1484
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1485
+        if (location == -1)
1486
+            return;
1487
+        for (auto column = GLuint{0}; column < columns; ++column)
1488
+            glVertexAttribL3dv(
1489
+                (GLuint)location + column,
1490
+                glm::value_ptr(value) + rows * column);
1491
+    }
1492
+    void static vertex_attrib_pointer(
1493
+        GLint       location,
1494
+        std::size_t offset = 0,
1495
+        std::size_t stride = sizeof(glm::dvec3))
1496
+    {
1497
+        if (GLBase::debug() >= 1)
1498
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1499
+        if (location == -1)
1500
+            return;
1501
+        auto constexpr sizeof_column = sizeof(glm::dvec3) / columns;
1502
+        for (auto column = GLuint{0}; column < columns; ++column)
1503
+            glVertexAttribLPointer(
1504
+                (GLuint)location + column,
1505
+                rows,
1506
+                type,
1507
+                (GLsizei)stride,
1508
+                (void const *)(offset + sizeof_column * column));
1509
+    }
1510
+};
1511
+
1512
+template <> struct GLTraits::Value<glm::dvec4>
1513
+{
1514
+    auto static constexpr name                 = "glm::dvec4";
1515
+    auto static constexpr columns              = GLint{1};
1516
+    auto static constexpr rows                 = GLint{4};
1517
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC4};
1518
+    auto static constexpr format               = GLenum{GL_RGBA};
1519
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1520
+    auto static constexpr internal_format      = GLenum{GL_RGBA};
1521
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1522
+    auto static constexpr internal_format_compressed =
1523
+        GLenum{GL_COMPRESSED_RGBA};
1524
+    auto static constexpr internal_format_compressed_srgb =
1525
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1526
+    auto static constexpr integer = bool(*"");
1527
+    void static uniform(GLint location, glm::dvec4 const & value)
1528
+    {
1529
+        if (GLBase::debug() >= 1)
1530
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1531
+        glUniform4dv(location, 1, glm::value_ptr(value));
1532
+    }
1533
+    void static vertex_attrib(GLint location, glm::dvec4 const & value)
1534
+    {
1535
+        if (GLBase::debug() >= 1)
1536
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1537
+        if (location == -1)
1538
+            return;
1539
+        for (auto column = GLuint{0}; column < columns; ++column)
1540
+            glVertexAttribL4dv(
1541
+                (GLuint)location + column,
1542
+                glm::value_ptr(value) + rows * column);
1543
+    }
1544
+    void static vertex_attrib_pointer(
1545
+        GLint       location,
1546
+        std::size_t offset = 0,
1547
+        std::size_t stride = sizeof(glm::dvec4))
1548
+    {
1549
+        if (GLBase::debug() >= 1)
1550
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1551
+        if (location == -1)
1552
+            return;
1553
+        auto constexpr sizeof_column = sizeof(glm::dvec4) / columns;
1554
+        for (auto column = GLuint{0}; column < columns; ++column)
1555
+            glVertexAttribLPointer(
1556
+                (GLuint)location + column,
1557
+                rows,
1558
+                type,
1559
+                (GLsizei)stride,
1560
+                (void const *)(offset + sizeof_column * column));
1561
+    }
1562
+};
1563
+
1564
+template <> struct GLTraits::Value<glm::dmat2>
1565
+{
1566
+    auto static constexpr name                 = "glm::dmat2";
1567
+    auto static constexpr columns              = GLint{2};
1568
+    auto static constexpr rows                 = GLint{2};
1569
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2};
1570
+    auto static constexpr format               = GLenum{GL_RG};
1571
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1572
+    auto static constexpr internal_format      = GLenum{GL_RG};
1573
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1574
+    auto static constexpr internal_format_compressed =
1575
+        GLenum{GL_COMPRESSED_RG};
1576
+    auto static constexpr internal_format_compressed_srgb =
1577
+        GLenum{GL_COMPRESSED_SRGB};
1578
+    auto static constexpr integer = bool(*"");
1579
+    void static uniform(GLint location, glm::dmat2 const & value)
1580
+    {
1581
+        if (GLBase::debug() >= 1)
1582
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1583
+        glUniformMatrix2dv(location, 1, GL_FALSE, glm::value_ptr(value));
1584
+    }
1585
+    void static vertex_attrib(GLint location, glm::dmat2 const & value)
1586
+    {
1587
+        if (GLBase::debug() >= 1)
1588
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1589
+        if (location == -1)
1590
+            return;
1591
+        for (auto column = GLuint{0}; column < columns; ++column)
1592
+            glVertexAttribL2dv(
1593
+                (GLuint)location + column,
1594
+                glm::value_ptr(value) + rows * column);
1595
+    }
1596
+    void static vertex_attrib_pointer(
1597
+        GLint       location,
1598
+        std::size_t offset = 0,
1599
+        std::size_t stride = sizeof(glm::dmat2))
1600
+    {
1601
+        if (GLBase::debug() >= 1)
1602
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1603
+        if (location == -1)
1604
+            return;
1605
+        auto constexpr sizeof_column = sizeof(glm::dmat2) / columns;
1606
+        for (auto column = GLuint{0}; column < columns; ++column)
1607
+            glVertexAttribLPointer(
1608
+                (GLuint)location + column,
1609
+                rows,
1610
+                type,
1611
+                (GLsizei)stride,
1612
+                (void const *)(offset + sizeof_column * column));
1613
+    }
1614
+};
1615
+
1616
+template <> struct GLTraits::Value<glm::dmat2x3>
1617
+{
1618
+    auto static constexpr name                 = "glm::dmat2x3";
1619
+    auto static constexpr columns              = GLint{2};
1620
+    auto static constexpr rows                 = GLint{3};
1621
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2x3};
1622
+    auto static constexpr format               = GLenum{GL_RGB};
1623
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1624
+    auto static constexpr internal_format      = GLenum{GL_RGB};
1625
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1626
+    auto static constexpr internal_format_compressed =
1627
+        GLenum{GL_COMPRESSED_RGB};
1628
+    auto static constexpr internal_format_compressed_srgb =
1629
+        GLenum{GL_COMPRESSED_SRGB};
1630
+    auto static constexpr integer = bool(*"");
1631
+    void static uniform(GLint location, glm::dmat2x3 const & value)
1632
+    {
1633
+        if (GLBase::debug() >= 1)
1634
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1635
+        glUniformMatrix2x3dv(location, 1, GL_FALSE, glm::value_ptr(value));
1636
+    }
1637
+    void static vertex_attrib(GLint location, glm::dmat2x3 const & value)
1638
+    {
1639
+        if (GLBase::debug() >= 1)
1640
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1641
+        if (location == -1)
1642
+            return;
1643
+        for (auto column = GLuint{0}; column < columns; ++column)
1644
+            glVertexAttribL3dv(
1645
+                (GLuint)location + column,
1646
+                glm::value_ptr(value) + rows * column);
1647
+    }
1648
+    void static vertex_attrib_pointer(
1649
+        GLint       location,
1650
+        std::size_t offset = 0,
1651
+        std::size_t stride = sizeof(glm::dmat2x3))
1652
+    {
1653
+        if (GLBase::debug() >= 1)
1654
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1655
+        if (location == -1)
1656
+            return;
1657
+        auto constexpr sizeof_column = sizeof(glm::dmat2x3) / columns;
1658
+        for (auto column = GLuint{0}; column < columns; ++column)
1659
+            glVertexAttribLPointer(
1660
+                (GLuint)location + column,
1661
+                rows,
1662
+                type,
1663
+                (GLsizei)stride,
1664
+                (void const *)(offset + sizeof_column * column));
1665
+    }
1666
+};
1667
+
1668
+template <> struct GLTraits::Value<glm::dmat2x4>
1669
+{
1670
+    auto static constexpr name                 = "glm::dmat2x4";
1671
+    auto static constexpr columns              = GLint{2};
1672
+    auto static constexpr rows                 = GLint{4};
1673
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2x4};
1674
+    auto static constexpr format               = GLenum{GL_RGBA};
1675
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1676
+    auto static constexpr internal_format      = GLenum{GL_RGBA};
1677
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1678
+    auto static constexpr internal_format_compressed =
1679
+        GLenum{GL_COMPRESSED_RGBA};
1680
+    auto static constexpr internal_format_compressed_srgb =
1681
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1682
+    auto static constexpr integer = bool(*"");
1683
+    void static uniform(GLint location, glm::dmat2x4 const & value)
1684
+    {
1685
+        if (GLBase::debug() >= 1)
1686
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1687
+        glUniformMatrix2x4dv(location, 1, GL_FALSE, glm::value_ptr(value));
1688
+    }
1689
+    void static vertex_attrib(GLint location, glm::dmat2x4 const & value)
1690
+    {
1691
+        if (GLBase::debug() >= 1)
1692
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1693
+        if (location == -1)
1694
+            return;
1695
+        for (auto column = GLuint{0}; column < columns; ++column)
1696
+            glVertexAttribL4dv(
1697
+                (GLuint)location + column,
1698
+                glm::value_ptr(value) + rows * column);
1699
+    }
1700
+    void static vertex_attrib_pointer(
1701
+        GLint       location,
1702
+        std::size_t offset = 0,
1703
+        std::size_t stride = sizeof(glm::dmat2x4))
1704
+    {
1705
+        if (GLBase::debug() >= 1)
1706
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1707
+        if (location == -1)
1708
+            return;
1709
+        auto constexpr sizeof_column = sizeof(glm::dmat2x4) / columns;
1710
+        for (auto column = GLuint{0}; column < columns; ++column)
1711
+            glVertexAttribLPointer(
1712
+                (GLuint)location + column,
1713
+                rows,
1714
+                type,
1715
+                (GLsizei)stride,
1716
+                (void const *)(offset + sizeof_column * column));
1717
+    }
1718
+};
1719
+
1720
+template <> struct GLTraits::Value<glm::dmat3x2>
1721
+{
1722
+    auto static constexpr name                 = "glm::dmat3x2";
1723
+    auto static constexpr columns              = GLint{3};
1724
+    auto static constexpr rows                 = GLint{2};
1725
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3x2};
1726
+    auto static constexpr format               = GLenum{GL_RG};
1727
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1728
+    auto static constexpr internal_format      = GLenum{GL_RG};
1729
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1730
+    auto static constexpr internal_format_compressed =
1731
+        GLenum{GL_COMPRESSED_RG};
1732
+    auto static constexpr internal_format_compressed_srgb =
1733
+        GLenum{GL_COMPRESSED_SRGB};
1734
+    auto static constexpr integer = bool(*"");
1735
+    void static uniform(GLint location, glm::dmat3x2 const & value)
1736
+    {
1737
+        if (GLBase::debug() >= 1)
1738
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1739
+        glUniformMatrix3x2dv(location, 1, GL_FALSE, glm::value_ptr(value));
1740
+    }
1741
+    void static vertex_attrib(GLint location, glm::dmat3x2 const & value)
1742
+    {
1743
+        if (GLBase::debug() >= 1)
1744
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1745
+        if (location == -1)
1746
+            return;
1747
+        for (auto column = GLuint{0}; column < columns; ++column)
1748
+            glVertexAttribL2dv(
1749
+                (GLuint)location + column,
1750
+                glm::value_ptr(value) + rows * column);
1751
+    }
1752
+    void static vertex_attrib_pointer(
1753
+        GLint       location,
1754
+        std::size_t offset = 0,
1755
+        std::size_t stride = sizeof(glm::dmat3x2))
1756
+    {
1757
+        if (GLBase::debug() >= 1)
1758
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1759
+        if (location == -1)
1760
+            return;
1761
+        auto constexpr sizeof_column = sizeof(glm::dmat3x2) / columns;
1762
+        for (auto column = GLuint{0}; column < columns; ++column)
1763
+            glVertexAttribLPointer(
1764
+                (GLuint)location + column,
1765
+                rows,
1766
+                type,
1767
+                (GLsizei)stride,
1768
+                (void const *)(offset + sizeof_column * column));
1769
+    }
1770
+};
1771
+
1772
+template <> struct GLTraits::Value<glm::dmat3>
1773
+{
1774
+    auto static constexpr name                 = "glm::dmat3";
1775
+    auto static constexpr columns              = GLint{3};
1776
+    auto static constexpr rows                 = GLint{3};
1777
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3};
1778
+    auto static constexpr format               = GLenum{GL_RGB};
1779
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1780
+    auto static constexpr internal_format      = GLenum{GL_RGB};
1781
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1782
+    auto static constexpr internal_format_compressed =
1783
+        GLenum{GL_COMPRESSED_RGB};
1784
+    auto static constexpr internal_format_compressed_srgb =
1785
+        GLenum{GL_COMPRESSED_SRGB};
1786
+    auto static constexpr integer = bool(*"");
1787
+    void static uniform(GLint location, glm::dmat3 const & value)
1788
+    {
1789
+        if (GLBase::debug() >= 1)
1790
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1791
+        glUniformMatrix3dv(location, 1, GL_FALSE, glm::value_ptr(value));
1792
+    }
1793
+    void static vertex_attrib(GLint location, glm::dmat3 const & value)
1794
+    {
1795
+        if (GLBase::debug() >= 1)
1796
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1797
+        if (location == -1)
1798
+            return;
1799
+        for (auto column = GLuint{0}; column < columns; ++column)
1800
+            glVertexAttribL3dv(
1801
+                (GLuint)location + column,
1802
+                glm::value_ptr(value) + rows * column);
1803
+    }
1804
+    void static vertex_attrib_pointer(
1805
+        GLint       location,
1806
+        std::size_t offset = 0,
1807
+        std::size_t stride = sizeof(glm::dmat3))
1808
+    {
1809
+        if (GLBase::debug() >= 1)
1810
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1811
+        if (location == -1)
1812
+            return;
1813
+        auto constexpr sizeof_column = sizeof(glm::dmat3) / columns;
1814
+        for (auto column = GLuint{0}; column < columns; ++column)
1815
+            glVertexAttribLPointer(
1816
+                (GLuint)location + column,
1817
+                rows,
1818
+                type,
1819
+                (GLsizei)stride,
1820
+                (void const *)(offset + sizeof_column * column));
1821
+    }
1822
+};
1823
+
1824
+template <> struct GLTraits::Value<glm::dmat3x4>
1825
+{
1826
+    auto static constexpr name                 = "glm::dmat3x4";
1827
+    auto static constexpr columns              = GLint{3};
1828
+    auto static constexpr rows                 = GLint{4};
1829
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3x4};
1830
+    auto static constexpr format               = GLenum{GL_RGBA};
1831
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1832
+    auto static constexpr internal_format      = GLenum{GL_RGBA};
1833
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1834
+    auto static constexpr internal_format_compressed =
1835
+        GLenum{GL_COMPRESSED_RGBA};
1836
+    auto static constexpr internal_format_compressed_srgb =
1837
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1838
+    auto static constexpr integer = bool(*"");
1839
+    void static uniform(GLint location, glm::dmat3x4 const & value)
1840
+    {
1841
+        if (GLBase::debug() >= 1)
1842
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1843
+        glUniformMatrix3x4dv(location, 1, GL_FALSE, glm::value_ptr(value));
1844
+    }
1845
+    void static vertex_attrib(GLint location, glm::dmat3x4 const & value)
1846
+    {
1847
+        if (GLBase::debug() >= 1)
1848
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1849
+        if (location == -1)
1850
+            return;
1851
+        for (auto column = GLuint{0}; column < columns; ++column)
1852
+            glVertexAttribL4dv(
1853
+                (GLuint)location + column,
1854
+                glm::value_ptr(value) + rows * column);
1855
+    }
1856
+    void static vertex_attrib_pointer(
1857
+        GLint       location,
1858
+        std::size_t offset = 0,
1859
+        std::size_t stride = sizeof(glm::dmat3x4))
1860
+    {
1861
+        if (GLBase::debug() >= 1)
1862
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1863
+        if (location == -1)
1864
+            return;
1865
+        auto constexpr sizeof_column = sizeof(glm::dmat3x4) / columns;
1866
+        for (auto column = GLuint{0}; column < columns; ++column)
1867
+            glVertexAttribLPointer(
1868
+                (GLuint)location + column,
1869
+                rows,
1870
+                type,
1871
+                (GLsizei)stride,
1872
+                (void const *)(offset + sizeof_column * column));
1873
+    }
1874
+};
1875
+
1876
+template <> struct GLTraits::Value<glm::dmat4x2>
1877
+{
1878
+    auto static constexpr name                 = "glm::dmat4x2";
1879
+    auto static constexpr columns              = GLint{4};
1880
+    auto static constexpr rows                 = GLint{2};
1881
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4x2};
1882
+    auto static constexpr format               = GLenum{GL_RG};
1883
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1884
+    auto static constexpr internal_format      = GLenum{GL_RG};
1885
+    auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
1886
+    auto static constexpr internal_format_compressed =
1887
+        GLenum{GL_COMPRESSED_RG};
1888
+    auto static constexpr internal_format_compressed_srgb =
1889
+        GLenum{GL_COMPRESSED_SRGB};
1890
+    auto static constexpr integer = bool(*"");
1891
+    void static uniform(GLint location, glm::dmat4x2 const & value)
1892
+    {
1893
+        if (GLBase::debug() >= 1)
1894
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1895
+        glUniformMatrix4x2dv(location, 1, GL_FALSE, glm::value_ptr(value));
1896
+    }
1897
+    void static vertex_attrib(GLint location, glm::dmat4x2 const & value)
1898
+    {
1899
+        if (GLBase::debug() >= 1)
1900
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1901
+        if (location == -1)
1902
+            return;
1903
+        for (auto column = GLuint{0}; column < columns; ++column)
1904
+            glVertexAttribL2dv(
1905
+                (GLuint)location + column,
1906
+                glm::value_ptr(value) + rows * column);
1907
+    }
1908
+    void static vertex_attrib_pointer(
1909
+        GLint       location,
1910
+        std::size_t offset = 0,
1911
+        std::size_t stride = sizeof(glm::dmat4x2))
1912
+    {
1913
+        if (GLBase::debug() >= 1)
1914
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1915
+        if (location == -1)
1916
+            return;
1917
+        auto constexpr sizeof_column = sizeof(glm::dmat4x2) / columns;
1918
+        for (auto column = GLuint{0}; column < columns; ++column)
1919
+            glVertexAttribLPointer(
1920
+                (GLuint)location + column,
1921
+                rows,
1922
+                type,
1923
+                (GLsizei)stride,
1924
+                (void const *)(offset + sizeof_column * column));
1925
+    }
1926
+};
1927
+
1928
+template <> struct GLTraits::Value<glm::dmat4x3>
1929
+{
1930
+    auto static constexpr name                 = "glm::dmat4x3";
1931
+    auto static constexpr columns              = GLint{4};
1932
+    auto static constexpr rows                 = GLint{3};
1933
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4x3};
1934
+    auto static constexpr format               = GLenum{GL_RGB};
1935
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1936
+    auto static constexpr internal_format      = GLenum{GL_RGB};
1937
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
1938
+    auto static constexpr internal_format_compressed =
1939
+        GLenum{GL_COMPRESSED_RGB};
1940
+    auto static constexpr internal_format_compressed_srgb =
1941
+        GLenum{GL_COMPRESSED_SRGB};
1942
+    auto static constexpr integer = bool(*"");
1943
+    void static uniform(GLint location, glm::dmat4x3 const & value)
1944
+    {
1945
+        if (GLBase::debug() >= 1)
1946
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1947
+        glUniformMatrix4x3dv(location, 1, GL_FALSE, glm::value_ptr(value));
1948
+    }
1949
+    void static vertex_attrib(GLint location, glm::dmat4x3 const & value)
1950
+    {
1951
+        if (GLBase::debug() >= 1)
1952
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1953
+        if (location == -1)
1954
+            return;
1955
+        for (auto column = GLuint{0}; column < columns; ++column)
1956
+            glVertexAttribL3dv(
1957
+                (GLuint)location + column,
1958
+                glm::value_ptr(value) + rows * column);
1959
+    }
1960
+    void static vertex_attrib_pointer(
1961
+        GLint       location,
1962
+        std::size_t offset = 0,
1963
+        std::size_t stride = sizeof(glm::dmat4x3))
1964
+    {
1965
+        if (GLBase::debug() >= 1)
1966
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
1967
+        if (location == -1)
1968
+            return;
1969
+        auto constexpr sizeof_column = sizeof(glm::dmat4x3) / columns;
1970
+        for (auto column = GLuint{0}; column < columns; ++column)
1971
+            glVertexAttribLPointer(
1972
+                (GLuint)location + column,
1973
+                rows,
1974
+                type,
1975
+                (GLsizei)stride,
1976
+                (void const *)(offset + sizeof_column * column));
1977
+    }
1978
+};
1979
+
1980
+template <> struct GLTraits::Value<glm::dmat4>
1981
+{
1982
+    auto static constexpr name                 = "glm::dmat4";
1983
+    auto static constexpr columns              = GLint{4};
1984
+    auto static constexpr rows                 = GLint{4};
1985
+    auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4};
1986
+    auto static constexpr format               = GLenum{GL_RGBA};
1987
+    auto static constexpr type                 = GLenum{GL_DOUBLE};
1988
+    auto static constexpr internal_format      = GLenum{GL_RGBA};
1989
+    auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
1990
+    auto static constexpr internal_format_compressed =
1991
+        GLenum{GL_COMPRESSED_RGBA};
1992
+    auto static constexpr internal_format_compressed_srgb =
1993
+        GLenum{GL_COMPRESSED_SRGB_ALPHA};
1994
+    auto static constexpr integer = bool(*"");
1995
+    void static uniform(GLint location, glm::dmat4 const & value)
1996
+    {
1997
+        if (GLBase::debug() >= 1)
1998
+            GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
1999
+        glUniformMatrix4dv(location, 1, GL_FALSE, glm::value_ptr(value));
2000
+    }
2001
+    void static vertex_attrib(GLint location, glm::dmat4 const & value)
2002
+    {
2003
+        if (GLBase::debug() >= 1)
2004
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
2005
+        if (location == -1)
2006
+            return;
2007
+        for (auto column = GLuint{0}; column < columns; ++column)
2008
+            glVertexAttribL4dv(
2009
+                (GLuint)location + column,
2010
+                glm::value_ptr(value) + rows * column);
2011
+    }
2012
+    void static vertex_attrib_pointer(
2013
+        GLint       location,
2014
+        std::size_t offset = 0,
2015
+        std::size_t stride = sizeof(glm::dmat4))
2016
+    {
2017
+        if (GLBase::debug() >= 1)
2018
+            GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
2019
+        if (location == -1)
2020
+            return;
2021
+        auto constexpr sizeof_column = sizeof(glm::dmat4) / columns;
2022
+        for (auto column = GLuint{0}; column < columns; ++column)
2023
+            glVertexAttribLPointer(
2024
+                (GLuint)location + column,
2025
+                rows,
2026
+                type,
2027
+                (GLsizei)stride,
2028
+                (void const *)(offset + sizeof_column * column));
2029
+    }
2030
+};
2031
+
0 2032
new file mode 100644
... ...
@@ -0,0 +1,164 @@
1
+/// Guards
2
+
3
+#ifndef GLTRAITS_HPP_
4
+#define GLTRAITS_HPP_
5
+
6
+
7
+/// Includes
8
+
9
+#include <cstddef>
10
+
11
+#include <glbase.hpp>
12
+
13
+
14
+/// GLTraits
15
+
16
+class GLTraits
17
+{
18
+
19
+public:
20
+
21
+    //// Value
22
+
23
+    template<typename>
24
+    struct Value;
25
+
26
+};
27
+
28
+//// Helpers
29
+
30
+#define GLTRAITS_KEEP(...) __VA_ARGS__
31
+#define GLTRAITS_OMIT(...)
32
+
33
+//// Value
34
+
35
+#define GLTRAITS_VALUE_SRED  GL_SR8_EXT
36
+#define GLTRAITS_VALUE_SRG   GL_SRG8_EXT
37
+#define GLTRAITS_VALUE_SRGB  GL_SRGB8
38
+#define GLTRAITS_VALUE_SRGBA GL_SRGB8_ALPHA8
39
+
40
+#define GLTRAITS_VALUE_COMPRESSED_SRED  GL_COMPRESSED_SRGB
41
+#define GLTRAITS_VALUE_COMPRESSED_SRG   GL_COMPRESSED_SRGB
42
+#define GLTRAITS_VALUE_COMPRESSED_SRGB  GL_COMPRESSED_SRGB
43
+#define GLTRAITS_VALUE_COMPRESSED_SRGBA GL_COMPRESSED_SRGB_ALPHA
44
+
45
+#define GLTRAITS_VALUE( \
46
+    VALUE, \
47
+    COLUMNS, ROWS, \
48
+    GLSL, FORMAT, TYPE, INTERNAL_FORMAT, \
49
+    OFFSET_ARGS, PTR, \
50
+    V, UNIFORM, SUFFIX, ATTRIB, \
51
+    INTEGER, \
52
+    NORMALIZE_ARGS, \
53
+    V1U, V2U, \
54
+    V1A, V2A, \
55
+    EXTU, EXTA, \
56
+    ... \
57
+) \
58
+    template<> \
59
+    struct GLTraits::Value<VALUE> \
60
+    { \
61
+        auto static constexpr name                            = #VALUE; \
62
+        auto static constexpr columns                         = GLint{COLUMNS}; \
63
+        auto static constexpr rows                            = GLint{ROWS}; \
64
+        auto static constexpr glsl                            = GLenum{GL_##GLSL}; \
65
+        auto static constexpr format                          = GLenum{GL_##FORMAT##INTEGER}; \
66
+        auto static constexpr type                            = GLenum{GL_##TYPE}; \
67
+        auto static constexpr internal_format                 = GLenum{GL_##INTERNAL_FORMAT}; \
68
+        auto static constexpr internal_format_srgb            = GLenum{GLTRAITS_VALUE_S##FORMAT}; \
69
+        auto static constexpr internal_format_compressed      = GLenum{GL_COMPRESSED_##FORMAT}; \
70
+        auto static constexpr internal_format_compressed_srgb = GLenum{GLTRAITS_VALUE_COMPRESSED_S##FORMAT}; \
71
+        auto static constexpr integer                         = bool(*#INTEGER); \
72
+        void static uniform(GLint location, VALUE const & value) \
73
+        { \
74
+            if (GLBase::debug() >= 1) \
75
+                GLBase::check_supported({V1U, V2U}, EXTU); \
76
+            glUniform##UNIFORM##ROWS##SUFFIX##V( \
77
+                location, \
78
+                __VA_ARGS__ \
79
+                PTR(value) \
80
+            ); \
81
+        } \
82
+        void static vertex_attrib(GLint location, VALUE const & value) \
83
+        { \
84
+            if (GLBase::debug() >= 1) \
85
+                GLBase::check_supported({V1A, V2A}, EXTA); \
86
+            if (location == -1) \
87
+                return; \
88
+            for (auto column = GLuint{0}; column < columns; ++column) \
89
+                glVertexAttrib##ATTRIB##ROWS##SUFFIX##V( \
90
+                    (GLuint)location + column, \
91
+                    PTR(value) GLTRAITS_##OFFSET_ARGS(+ rows * column) \
92
+                ); \
93
+        } \
94
+        void static vertex_attrib_pointer( \
95
+            GLint       location, \
96
+            std::size_t offset = 0, \
97
+            std::size_t stride = sizeof(VALUE) \
98
+        ) \
99
+        { \
100
+            if (GLBase::debug() >= 1) \
101
+                GLBase::check_supported({V1A, V2A}, EXTA); \
102
+            if (location == -1) \
103
+                return; \
104
+            auto constexpr sizeof_column = sizeof(VALUE) / columns; \
105
+            for (auto column = GLuint{0}; column < columns; ++column) \
106
+                glVertexAttrib##ATTRIB##Pointer( \
107
+                    (GLuint)location + column, \
108
+                    rows, \
109
+                    type, \
110
+                    GLTRAITS_##NORMALIZE_ARGS(GL_FALSE,) \
111
+                    (GLsizei)stride, \
112
+                    (void const *)(offset + sizeof_column * column) \
113
+                ); \
114
+        } \
115
+    };
116
+
117
+#define GLTRAITS_VALUE_SCALAR(                  VALUE, TYPE, GLSL,   INTERNAL, ...) GLTRAITS_VALUE(VALUE,          1, 1, GLSL,                RED,    TYPE, R     ##INTERNAL, OMIT, ,    ,  ,             __VA_ARGS__,)
118
+#define GLTRAITS_VALUE_VECTOR_N(  N,    FORMAT, VALUE, TYPE, PTR,    INTERNAL, ...) GLTRAITS_VALUE(VALUE##N,       1, N, TYPE##_VEC##N,       FORMAT, TYPE, FORMAT##INTERNAL, KEEP, PTR, v, ,             __VA_ARGS__, 1,)
119
+#define GLTRAITS_VALUE_MATRIX_N(  N,    FORMAT, VALUE, TYPE, PTR, T, INTERNAL, ...) GLTRAITS_VALUE(VALUE##N,       N, N, TYPE##_MAT##N,       FORMAT, TYPE, FORMAT##INTERNAL, KEEP, PTR, v, Matrix,       __VA_ARGS__, 1, T,)
120
+#define GLTRAITS_VALUE_MATRIX_N_M(N, M, FORMAT, VALUE, TYPE, PTR, T, INTERNAL, ...) GLTRAITS_VALUE(VALUE##N##x##M, N, M, TYPE##_MAT##N##x##M, FORMAT, TYPE, FORMAT##INTERNAL, KEEP, PTR, v, Matrix##N##x, __VA_ARGS__, 1, T,)
121
+
122
+#define GLTRAITS_VALUE_VECTOR(...) \
123
+    GLTRAITS_VALUE_VECTOR_N(  2,    RG,   __VA_ARGS__) \
124
+    GLTRAITS_VALUE_VECTOR_N(  3,    RGB,  __VA_ARGS__) \
125
+    GLTRAITS_VALUE_VECTOR_N(  4,    RGBA, __VA_ARGS__)
126
+
127
+#define GLTRAITS_VALUE_MATRIX_(SUPPORT_ARGS, ...) \
128
+    GLTRAITS_VALUE_MATRIX_N(  2,    RG,   __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 0, 2, 0, {}, {})) \
129
+    GLTRAITS_VALUE_MATRIX_N_M(2, 3, RGB,  __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
130
+    GLTRAITS_VALUE_MATRIX_N_M(2, 4, RGBA, __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
131
+    GLTRAITS_VALUE_MATRIX_N_M(3, 2, RG,   __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
132
+    GLTRAITS_VALUE_MATRIX_N(  3,    RGB,  __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 0, 2, 0, {}, {})) \
133
+    GLTRAITS_VALUE_MATRIX_N_M(3, 4, RGBA, __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
134
+    GLTRAITS_VALUE_MATRIX_N_M(4, 2, RG,   __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
135
+    GLTRAITS_VALUE_MATRIX_N_M(4, 3, RGB,  __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 1, 2, 0, {}, {})) \
136
+    GLTRAITS_VALUE_MATRIX_N(  4,    RGBA, __VA_ARGS__ GLTRAITS_##SUPPORT_ARGS(, 2, 0, 2, 0, {}, {}))
137
+
138
+#define GLTRAITS_VALUE_MATRIXS(...) GLTRAITS_VALUE_MATRIX_(KEEP, __VA_ARGS__)
139
+#define GLTRAITS_VALUE_MATRIX(...)  GLTRAITS_VALUE_MATRIX_(OMIT, __VA_ARGS__)
140
+
141
+GLTRAITS_VALUE_SCALAR( GLfloat,   FLOAT,          FLOAT,                    32F,  f,  ,  ,         KEEP, 2, 0, 2, 0, {}, {})
142
+GLTRAITS_VALUE_SCALAR( bool,      BYTE,           BOOL,                     8I,   i,  I, _INTEGER, OMIT, 2, 0, 3, 0, {}, {})
143
+GLTRAITS_VALUE_SCALAR( GLbyte,    BYTE,           INT,                      8I,   i,  I, _INTEGER, OMIT, 2, 0, 3, 0, {}, {})
144
+GLTRAITS_VALUE_SCALAR( GLshort,   SHORT,          INT,                      16I,  i,  I, _INTEGER, OMIT, 2, 0, 3, 0, {}, {})
145
+GLTRAITS_VALUE_SCALAR( GLint,     INT,            INT,                      32I,  i,  I, _INTEGER, OMIT, 2, 0, 3, 0, {}, {})
146
+GLTRAITS_VALUE_SCALAR( GLubyte,   UNSIGNED_BYTE,  UNSIGNED_INT,             8UI,  ui, I, _INTEGER, OMIT, 3, 0, 3, 0, {}, {})
147
+GLTRAITS_VALUE_SCALAR( GLushort,  UNSIGNED_SHORT, UNSIGNED_INT,             16UI, ui, I, _INTEGER, OMIT, 3, 0, 3, 0, {}, {})
148
+GLTRAITS_VALUE_SCALAR( GLuint,    UNSIGNED_INT,   UNSIGNED_INT,             32UI, ui, I, _INTEGER, OMIT, 3, 0, 3, 0, {}, {})
149
+GLTRAITS_VALUE_SCALAR( GLdouble,  DOUBLE,         DOUBLE,                   ED,   d,  L, ,         OMIT, 4, 0, 4, 1, "GL_ARB_gpu_shader_fp64", "GL_ARB_vertex_attrib_64bit")
150
+
151
+#ifdef GLM_VERSION
152
+#include <glm/gtc/type_ptr.hpp>
153
+GLTRAITS_VALUE_VECTOR( glm::vec,  FLOAT,          glm::value_ptr,           32F,  f,  ,  ,         KEEP, 2, 0, 2, 0, {}, {})
154
+GLTRAITS_VALUE_MATRIXS(glm::mat,  FLOAT,          glm::value_ptr, GL_FALSE, 32F,  f,  ,  ,         KEEP)
155
+GLTRAITS_VALUE_VECTOR( glm::ivec, INT,            glm::value_ptr,           32I,  i,  I, _INTEGER, OMIT, 2, 0, 3, 0, {}, {})
156
+GLTRAITS_VALUE_VECTOR( glm::uvec, UNSIGNED_INT,   glm::value_ptr,           32UI, ui, I, _INTEGER, OMIT, 3, 0, 3, 0, {}, {})
157
+GLTRAITS_VALUE_VECTOR( glm::dvec, DOUBLE,         glm::value_ptr,           ,     d,  L, ,         OMIT, 4, 0, 4, 1, "GL_ARB_gpu_shader_fp64", "GL_ARB_vertex_attrib_64bit")
158
+GLTRAITS_VALUE_MATRIX( glm::dmat, DOUBLE,         glm::value_ptr, GL_FALSE, ,     d,  L, ,         OMIT, 4, 0, 4, 1, "GL_ARB_gpu_shader_fp64", "GL_ARB_vertex_attrib_64bit")
159
+#endif
160
+
161
+
162
+/// Guards
163
+
164
+#endif
0 165
new file mode 100644
... ...
@@ -0,0 +1,60 @@
1
+#include <iomanip>
2
+#include <iostream>
3
+#include <string>
4
+#include <type_traits>
5
+
6
+#include <glm/glm.hpp>
7
+
8
+#include <glbase.hpp>
9
+#include <gltraits.hpp>
10
+
11
+
12
+struct GLTraitsTest : protected GLBase
13
+{
14
+
15
+    template<typename Value>
16
+    void static test_value()
17
+    {
18
+        using Traits = GLTraits::Value<Value>;
19
+        static_assert(
20
+            std::is_empty<Traits>::value,
21
+            "GLTraits::Value must be empty"
22
+        );
23
+        #define GLTRAITS_TEST_VALUE(NAME, VALUE) \
24
+            << std::left << std::setw(35) << "  " NAME ":" << VALUE << "\n"
25
+        #define GLTRAITS_TEST_VALUE_DEC(NAME) \
26
+            GLTRAITS_TEST_VALUE(#NAME, std::dec << Traits::NAME)
27
+        #define GLTRAITS_TEST_VALUE_BOOL(NAME) \
28
+            GLTRAITS_TEST_VALUE(#NAME, std::boolalpha << Traits::NAME)
29
+        #define GLTRAITS_TEST_VALUE_ENUM(NAME, SUFFIX) \
30
+            GLTRAITS_TEST_VALUE( \
31
+                #NAME #SUFFIX, \
32
+                str_##NAME##_(Traits::NAME##SUFFIX) \
33
+            )
34
+        std::cout
35
+            << "Value<" << Traits::name << ">" << "\n"
36
+            GLTRAITS_TEST_VALUE_DEC(columns)
37
+            GLTRAITS_TEST_VALUE_DEC(rows)
38
+            GLTRAITS_TEST_VALUE_ENUM(glsl,)
39
+            GLTRAITS_TEST_VALUE_ENUM(format,)
40
+            GLTRAITS_TEST_VALUE_ENUM(type,)
41
+            GLTRAITS_TEST_VALUE_ENUM(internal_format,)
42
+            GLTRAITS_TEST_VALUE_ENUM(internal_format, _srgb)
43
+            GLTRAITS_TEST_VALUE_ENUM(internal_format, _compressed)
44
+            GLTRAITS_TEST_VALUE_ENUM(internal_format, _compressed_srgb)
45
+            GLTRAITS_TEST_VALUE_BOOL(integer);
46
+    }
47
+
48
+};
49
+
50
+
51
+int main()
52
+{
53
+    GLTraitsTest::test_value<GLfloat>();
54
+    GLTraitsTest::test_value<bool>();
55
+    GLTraitsTest::test_value<GLshort>();
56
+    GLTraitsTest::test_value<GLdouble>();
57
+    GLTraitsTest::test_value<glm::mat4x3>();
58
+    GLTraitsTest::test_value<glm::uvec2>();
59
+    GLTraitsTest::test_value<glm::dvec2>();
60
+}