doc/preprocess.hpp
e38947dc
 class GLTraits
 {
 
   public:
     template <typename> struct Value;
a6304722
 
     template <GLenum id> struct ValueID;
799e1ae5
 
     template <GLenum object_type> struct Object;
3378873e
 
     template <std::size_t N> struct Texture;
 
   private:
     template <std::size_t... Is> struct Indices
     {
     };
 
     template <std::size_t N, std::size_t... Is>
     struct MakeIndices_ : MakeIndices_<N - 1, N - 1, Is...>
     {
     };
 
     template <std::size_t... Is> struct MakeIndices_<0, Is...>
     {
         using Indices_ = Indices<Is...>;
     };
 
     template <std::size_t N>
     using MakeIndices = typename MakeIndices_<N>::Indices_;
 
     template <
         std::size_t N,
         typename Indices,
         typename CopySizeIndices,
         typename CopyOffsetIndices>
     struct Texture_;
e38947dc
 };
 
 template <> struct GLTraits::Value<GLfloat>
 {
     auto static constexpr name                 = "GLfloat";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_FLOAT};
     auto static constexpr format               = GLenum{GL_RED};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_R32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLfloat) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLfloat const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform1f(location, (value));
     }
     void static vertex_attrib(GLint location, GLfloat const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib1f((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLfloat))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLfloat) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLfloat>::id>
 {
     using Value = GLfloat;
 };
 
e38947dc
 template <> struct GLTraits::Value<bool>
 {
     auto static constexpr name                 = "bool";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_BOOL};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_BYTE};
     auto static constexpr internal_format      = GLenum{GL_R8I};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(bool) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, bool const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform1i(location, (value));
     }
     void static vertex_attrib(GLint location, bool const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1i((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(bool))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(bool) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<bool>::id>
 {
     using Value = bool;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLbyte>
 {
     auto static constexpr name                 = "GLbyte";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_BYTE};
     auto static constexpr internal_format      = GLenum{GL_R8I};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLbyte) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLbyte const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform1i(location, (value));
     }
     void static vertex_attrib(GLint location, GLbyte const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1i((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLbyte))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLbyte) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLbyte>::id>
 {
     using Value = GLbyte;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLshort>
 {
     auto static constexpr name                 = "GLshort";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_SHORT};
     auto static constexpr internal_format      = GLenum{GL_R16I};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLshort) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLshort const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform1i(location, (value));
     }
     void static vertex_attrib(GLint location, GLshort const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1i((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLshort))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLshort) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLshort>::id>
 {
     using Value = GLshort;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLint>
 {
     auto static constexpr name                 = "GLint";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_INT};
     auto static constexpr internal_format      = GLenum{GL_R32I};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLint) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLint const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform1i(location, (value));
     }
     void static vertex_attrib(GLint location, GLint const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1i((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLint))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLint) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLint>::id>
 {
     using Value = GLint;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLubyte>
 {
     auto static constexpr name                 = "GLubyte";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_BYTE};
     auto static constexpr internal_format      = GLenum{GL_R8UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLubyte) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLubyte const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform1ui(location, (value));
     }
     void static vertex_attrib(GLint location, GLubyte const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1ui((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLubyte))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLubyte) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLubyte>::id>
 {
     using Value = GLubyte;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLushort>
 {
     auto static constexpr name                 = "GLushort";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_SHORT};
     auto static constexpr internal_format      = GLenum{GL_R16UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLushort) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLushort const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform1ui(location, (value));
     }
     void static vertex_attrib(GLint location, GLushort const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1ui((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLushort))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLushort) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLushort>::id>
 {
     using Value = GLushort;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLuint>
 {
     auto static constexpr name                 = "GLuint";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr format               = GLenum{GL_RED_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr internal_format      = GLenum{GL_R32UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLuint) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLuint const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform1ui(location, (value));
     }
     void static vertex_attrib(GLint location, GLuint const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI1ui((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLuint))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLuint) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLuint>::id>
 {
     using Value = GLuint;
 };
 
e38947dc
 template <> struct GLTraits::Value<GLdouble>
 {
     auto static constexpr name                 = "GLdouble";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{1};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE};
     auto static constexpr format               = GLenum{GL_RED};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RED};
     auto static constexpr internal_format_srgb = GLenum{GL_SR8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RED};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(GLdouble) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, GLdouble const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniform1d(location, (value));
     }
     void static vertex_attrib(GLint location, GLdouble const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL1d((GLuint)location + column, (value));
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(GLdouble))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(GLdouble) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<GLdouble>::id>
 {
     using Value = GLdouble;
 };
 
e38947dc
 
 template <> struct GLTraits::Value<glm::vec2>
 {
     auto static constexpr name                 = "glm::vec2";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RG32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::vec2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::vec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform2fv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::vec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib2fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::vec2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::vec2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::vec2>::id>
 {
     using Value = glm::vec2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::vec3>
 {
     auto static constexpr name                 = "glm::vec3";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGB32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::vec3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::vec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform3fv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::vec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib3fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::vec3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::vec3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::vec3>::id>
 {
     using Value = glm::vec3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::vec4>
 {
     auto static constexpr name                 = "glm::vec4";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_VEC4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::vec4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::vec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform4fv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::vec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib4fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::vec4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::vec4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::vec4>::id>
 {
     using Value = glm::vec4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat2>
 {
     auto static constexpr name                 = "glm::mat2";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RG32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniformMatrix2fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib2fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat2>::id>
 {
     using Value = glm::mat2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat2x3>
 {
     auto static constexpr name                 = "glm::mat2x3";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2x3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGB32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat2x3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat2x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix2x3fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat2x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib3fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat2x3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat2x3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat2x3>::id>
 {
     using Value = glm::mat2x3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat2x4>
 {
     auto static constexpr name                 = "glm::mat2x4";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT2x4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat2x4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat2x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix2x4fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat2x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib4fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat2x4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat2x4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat2x4>::id>
 {
     using Value = glm::mat2x4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat3x2>
 {
     auto static constexpr name                 = "glm::mat3x2";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3x2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RG32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat3x2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat3x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix3x2fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat3x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib2fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat3x2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat3x2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat3x2>::id>
 {
     using Value = glm::mat3x2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat3>
 {
     auto static constexpr name                 = "glm::mat3";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGB32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniformMatrix3fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib3fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat3>::id>
 {
     using Value = glm::mat3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat3x4>
 {
     auto static constexpr name                 = "glm::mat3x4";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT3x4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat3x4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat3x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix3x4fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat3x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib4fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat3x4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat3x4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat3x4>::id>
 {
     using Value = glm::mat3x4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat4x2>
 {
     auto static constexpr name                 = "glm::mat4x2";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4x2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RG32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat4x2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat4x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix4x2fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat4x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib2fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat4x2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat4x2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat4x2>::id>
 {
     using Value = glm::mat4x2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat4x3>
 {
     auto static constexpr name                 = "glm::mat4x3";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4x3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGB32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat4x3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat4x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 1}, {});
         glUniformMatrix4x3fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat4x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib3fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat4x3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat4x3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat4x3>::id>
 {
     using Value = glm::mat4x3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::mat4>
 {
     auto static constexpr name                 = "glm::mat4";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_FLOAT_MAT4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_FLOAT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32F};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::mat4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::mat4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniformMatrix4fv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::mat4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttrib4fv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::mat4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::mat4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 GL_FALSE,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::mat4>::id>
 {
     using Value = glm::mat4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::ivec2>
 {
     auto static constexpr name                 = "glm::ivec2";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_INT_VEC2};
     auto static constexpr format               = GLenum{GL_RG_INTEGER};
     auto static constexpr type                 = GLenum{GL_INT};
     auto static constexpr internal_format      = GLenum{GL_RG32I};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::ivec2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::ivec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform2iv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::ivec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI2iv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::ivec2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::ivec2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::ivec2>::id>
 {
     using Value = glm::ivec2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::ivec3>
 {
     auto static constexpr name                 = "glm::ivec3";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_INT_VEC3};
     auto static constexpr format               = GLenum{GL_RGB_INTEGER};
     auto static constexpr type                 = GLenum{GL_INT};
     auto static constexpr internal_format      = GLenum{GL_RGB32I};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::ivec3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::ivec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform3iv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::ivec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI3iv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::ivec3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::ivec3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::ivec3>::id>
 {
     using Value = glm::ivec3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::ivec4>
 {
     auto static constexpr name                 = "glm::ivec4";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_INT_VEC4};
     auto static constexpr format               = GLenum{GL_RGBA_INTEGER};
     auto static constexpr type                 = GLenum{GL_INT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32I};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::ivec4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::ivec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         glUniform4iv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::ivec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI4iv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::ivec4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::ivec4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::ivec4>::id>
 {
     using Value = glm::ivec4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::uvec2>
 {
     auto static constexpr name                 = "glm::uvec2";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC2};
     auto static constexpr format               = GLenum{GL_RG_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr internal_format      = GLenum{GL_RG32UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::uvec2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::uvec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform2uiv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::uvec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI2uiv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::uvec2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::uvec2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::uvec2>::id>
 {
     using Value = glm::uvec2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::uvec3>
 {
     auto static constexpr name                 = "glm::uvec3";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC3};
     auto static constexpr format               = GLenum{GL_RGB_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr internal_format      = GLenum{GL_RGB32UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::uvec3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::uvec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform3uiv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::uvec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI3uiv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::uvec3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::uvec3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::uvec3>::id>
 {
     using Value = glm::uvec3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::uvec4>
 {
     auto static constexpr name                 = "glm::uvec4";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_UNSIGNED_INT_VEC4};
     auto static constexpr format               = GLenum{GL_RGBA_INTEGER};
     auto static constexpr type                 = GLenum{GL_UNSIGNED_INT};
     auto static constexpr internal_format      = GLenum{GL_RGBA32UI};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"_INTEGER");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::uvec4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::uvec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         glUniform4uiv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::uvec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribI4uiv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::uvec4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, {});
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::uvec4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribIPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::uvec4>::id>
 {
     using Value = glm::uvec4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dvec2>
 {
     auto static constexpr name                 = "glm::dvec2";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RG};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dvec2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dvec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniform2dv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dvec2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL2dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dvec2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dvec2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dvec2>::id>
 {
     using Value = glm::dvec2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dvec3>
 {
     auto static constexpr name                 = "glm::dvec3";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGB};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dvec3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dvec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniform3dv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dvec3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL3dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dvec3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dvec3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dvec3>::id>
 {
     using Value = glm::dvec3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dvec4>
 {
     auto static constexpr name                 = "glm::dvec4";
     auto static constexpr columns              = GLint{1};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_VEC4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGBA};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dvec4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dvec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniform4dv(location, 1, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dvec4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL4dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dvec4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dvec4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dvec4>::id>
 {
     using Value = glm::dvec4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat2>
 {
     auto static constexpr name                 = "glm::dmat2";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RG};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix2dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL2dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat2>::id>
 {
     using Value = glm::dmat2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat2x3>
 {
     auto static constexpr name                 = "glm::dmat2x3";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2x3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGB};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat2x3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat2x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix2x3dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat2x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL3dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat2x3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat2x3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat2x3>::id>
 {
     using Value = glm::dmat2x3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat2x4>
 {
     auto static constexpr name                 = "glm::dmat2x4";
     auto static constexpr columns              = GLint{2};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT2x4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGBA};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat2x4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat2x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix2x4dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat2x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL4dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat2x4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat2x4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat2x4>::id>
 {
     using Value = glm::dmat2x4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat3x2>
 {
     auto static constexpr name                 = "glm::dmat3x2";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3x2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RG};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat3x2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat3x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix3x2dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat3x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL2dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat3x2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat3x2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat3x2>::id>
 {
     using Value = glm::dmat3x2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat3>
 {
     auto static constexpr name                 = "glm::dmat3";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGB};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix3dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL3dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat3>::id>
 {
     using Value = glm::dmat3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat3x4>
 {
     auto static constexpr name                 = "glm::dmat3x4";
     auto static constexpr columns              = GLint{3};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT3x4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGBA};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat3x4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat3x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix3x4dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat3x4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL4dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat3x4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat3x4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat3x4>::id>
 {
     using Value = glm::dmat3x4;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat4x2>
 {
     auto static constexpr name                 = "glm::dmat4x2";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{2};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4x2};
     auto static constexpr format               = GLenum{GL_RG};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RG};
     auto static constexpr internal_format_srgb = GLenum{GL_SRG8_EXT};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RG};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat4x2) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat4x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix4x2dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat4x2 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL2dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat4x2))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat4x2) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat4x2>::id>
 {
     using Value = glm::dmat4x2;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat4x3>
 {
     auto static constexpr name                 = "glm::dmat4x3";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{3};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4x3};
     auto static constexpr format               = GLenum{GL_RGB};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGB};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGB};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat4x3) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat4x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix4x3dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat4x3 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL3dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat4x3))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat4x3) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat4x3>::id>
 {
     using Value = glm::dmat4x3;
 };
 
e38947dc
 template <> struct GLTraits::Value<glm::dmat4>
 {
     auto static constexpr name                 = "glm::dmat4";
     auto static constexpr columns              = GLint{4};
     auto static constexpr rows                 = GLint{4};
     auto static constexpr glsl                 = GLenum{GL_DOUBLE_MAT4};
     auto static constexpr format               = GLenum{GL_RGBA};
     auto static constexpr type                 = GLenum{GL_DOUBLE};
     auto static constexpr internal_format      = GLenum{GL_RGBA};
     auto static constexpr internal_format_srgb = GLenum{GL_SRGB8_ALPHA8};
     auto static constexpr internal_format_compressed =
         GLenum{GL_COMPRESSED_RGBA};
     auto static constexpr internal_format_compressed_srgb =
         GLenum{GL_COMPRESSED_SRGB_ALPHA};
     auto static constexpr integer = bool(*"");
a6304722
     auto static constexpr id = (glsl == GL_INT || glsl == GL_UNSIGNED_INT) &&
                                        sizeof(glm::dmat4) < sizeof(GLint)
                                    ? type
                                    : glsl;
e38947dc
     void static uniform(GLint location, glm::dmat4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_gpu_shader_fp64");
         glUniformMatrix4dv(location, 1, GL_FALSE, glm::value_ptr(value));
     }
     void static vertex_attrib(GLint location, glm::dmat4 const & value)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribL4dv(
                 (GLuint)location + column,
                 glm::value_ptr(value) + rows * column);
     }
     void static vertex_attrib_pointer(
         GLint       location,
         std::size_t offset = 0,
         std::size_t stride = sizeof(glm::dmat4))
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_vertex_attrib_64bit");
         if (location == -1)
             return;
         auto constexpr sizeof_column = sizeof(glm::dmat4) / columns;
         for (auto column = GLuint{0}; column < columns; ++column)
             glVertexAttribLPointer(
                 (GLuint)location + column,
                 rows,
                 type,
                 (GLsizei)stride,
                 (void const *)(offset + sizeof_column * column));
     }
 };
 
a6304722
 template <> struct GLTraits::ValueID<GLTraits::Value<glm::dmat4>::id>
 {
     using Value = glm::dmat4;
 };
 
799e1ae5
 template <> struct GLTraits::Object<GL_TEXTURE>
 {
     auto static constexpr name = "GL_"
                                  "TEXTURE";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         glGenTextures(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         glDeleteTextures(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_BUFFER>
 {
     auto static constexpr name = "GL_"
                                  "BUFFER";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 5}, {});
         glGenBuffers(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 5}, {});
         glDeleteBuffers(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_QUERY>
 {
     auto static constexpr name = "GL_"
                                  "QUERY";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 5}, {});
         glGenQueries(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 5}, {});
         glDeleteQueries(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_PROGRAM>
 {
     auto static constexpr name = "GL_"
                                  "PROGRAM";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         while (n--)
             objects[n] = glCreateProgram(args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         while (n--)
             glDeleteProgram(objects[n]);
     }
     std::string static info_log(GLuint object)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         auto length = GLint{};
         glGetProgramiv(object, GL_INFO_LOG_LENGTH, &length);
         if (length != 0)
             --length;
         auto info_log = std::string((std::size_t)length, char{});
         glGetProgramInfoLog(object, length + 1, nullptr, &info_log[0]);
         return info_log;
     }
 };
 
 template <> struct GLTraits::Object<GL_SHADER>
 {
     auto static constexpr name = "GL_"
                                  "SHADER";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         while (n--)
             objects[n] = glCreateShader(args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         while (n--)
             glDeleteShader(objects[n]);
     }
     std::string static info_log(GLuint object)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({2, 0}, {});
         auto length = GLint{};
         glGetShaderiv(object, GL_INFO_LOG_LENGTH, &length);
         if (length != 0)
             --length;
         auto info_log = std::string((std::size_t)length, char{});
         glGetShaderInfoLog(object, length + 1, nullptr, &info_log[0]);
         return info_log;
     }
 };
 
 template <> struct GLTraits::Object<GL_VERTEX_ARRAY>
 {
     auto static constexpr name = "GL_"
                                  "VERTEX_ARRAY";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_vertex_array_object");
         glGenVertexArrays(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_vertex_array_object");
         glDeleteVertexArrays(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_FRAMEBUFFER>
 {
     auto static constexpr name = "GL_"
                                  "FRAMEBUFFER";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_framebuffer_object");
         glGenFramebuffers(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_framebuffer_object");
         glDeleteFramebuffers(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_RENDERBUFFER>
 {
     auto static constexpr name = "GL_"
                                  "RENDERBUFFER";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_framebuffer_object");
         glGenRenderbuffers(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 0}, "GL_ARB_framebuffer_object");
         glDeleteRenderbuffers(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_SAMPLER>
 {
     auto static constexpr name = "GL_"
                                  "SAMPLER";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 3}, "GL_ARB_sampler_objects");
         glGenSamplers(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({3, 3}, "GL_ARB_sampler_objects");
         glDeleteSamplers(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_TRANSFORM_FEEDBACK>
 {
     auto static constexpr name = "GL_"
                                  "TRANSFORM_FEEDBACK";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_transform_feedback2");
         glGenTransformFeedbacks(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 0}, "GL_ARB_transform_feedback2");
         glDeleteTransformFeedbacks(n, objects);
     }
 };
 
 template <> struct GLTraits::Object<GL_PROGRAM_PIPELINE>
 {
     auto static constexpr name = "GL_"
                                  "PROGRAM_PIPELINE";
     template <typename... Args>
     void static gen_objects(GLsizei n, GLuint * objects, Args... args)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_separate_shader_objects");
         glGenProgramPipelines(n, objects, args...);
     }
     void static delete_objects(GLsizei n, GLuint const * objects)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_separate_shader_objects");
         glDeleteProgramPipelines(n, objects);
     }
     std::string static info_log(GLuint object)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 1}, "GL_ARB_separate_shader_objects");
         auto length = GLint{};
         glGetProgramPipelineiv(object, GL_INFO_LOG_LENGTH, &length);
         if (length != 0)
             --length;
         auto info_log = std::string((std::size_t)length, char{});
         glGetProgramPipelineInfoLog(object, length + 1, nullptr, &info_log[0]);
         return info_log;
     }
 };
 
3378873e
 
 template <> struct GLTraits::Texture<0>
 {
   protected:
     void static defaults_(
         GLenum & internal_format,
         GLenum & format,
         GLenum & type,
         GLenum   default_internal_format,
         GLenum   default_format,
         GLenum   default_type)
     {
         if (!internal_format)
             internal_format = default_internal_format;
         switch (internal_format)
         {
         case GL_DEPTH_STENCIL:
         case GL_DEPTH24_STENCIL8:
         case GL_DEPTH32F_STENCIL8:
             if (!format)
                 format = GL_DEPTH_STENCIL;
             if (!type)
                 type = GL_UNSIGNED_INT_24_8;
             break;
         case GL_DEPTH_COMPONENT:
         case GL_DEPTH_COMPONENT16:
         case GL_DEPTH_COMPONENT24:
         case GL_DEPTH_COMPONENT32:
         case GL_DEPTH_COMPONENT32F:
             if (!format)
                 format = GL_DEPTH_COMPONENT;
             if (!type)
                 type = GL_UNSIGNED_INT;
             break;
         case GL_STENCIL_INDEX:
         case GL_STENCIL_INDEX1:
         case GL_STENCIL_INDEX4:
         case GL_STENCIL_INDEX8:
         case GL_STENCIL_INDEX16:
             if (!format)
                 format = GL_STENCIL_INDEX;
             if (!type)
                 type = GL_UNSIGNED_BYTE;
             break;
         default:
             if (!format)
                 format = default_format;
             if (!type)
                 type = default_type;
         }
     }
 };
 
 template <
     std::size_t... Is,
     std::size_t... CopySizeIs,
     std::size_t... CopyOffsetIs>
 struct GLTraits::Texture_<
     1,
     GLTraits::Indices<Is...>,
     GLTraits::Indices<CopySizeIs...>,
     GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
 {
     using Size       = std::array<GLsizei, sizeof...(Is)>;
     using Offset     = std::array<GLsizei, sizeof...(Is)>;
     using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
     using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
     auto static constexpr default_target  = GL_TEXTURE_1D;
     auto static constexpr default_binding = GL_TEXTURE_BINDING_1D;
     template <typename Value = GLubyte>
     void static tex_image(
         GLenum        target,
         Size          size,
         GLenum        internal_format = 0,
         Value const * data            = nullptr,
         GLenum        format          = 0,
         GLenum        type            = 0,
         GLint         level           = 0,
         GLint         border          = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 0}, {});
         defaults_(
             internal_format,
             format,
             type,
             GLTraits::Value<Value>::internal_format,
             GLTraits::Value<Value>::format,
             GLTraits::Value<Value>::type);
         glTexImage1D(
             target,
             level,
             (GLint)internal_format,
             std::get<Is>(size)...,
             border,
             format,
             type,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_sub_image(
         GLenum        target,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTexSubImage1D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_tex_sub_image(
         GLenum     target,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         glCopyTexSubImage1D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_tex_image(
         GLenum       target,
         Size         size,
         GLenum       internal_format,
         GLsizei      data_size = 0,
         void const * data      = nullptr,
         GLint        level     = 0,
         GLint        border    = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexImage1D(
             target,
             level,
             internal_format,
             std::get<Is>(size)...,
             border,
             data_size,
             data);
     }
     void static compressed_tex_sub_image(
         GLenum       target,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexSubImage1D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_storage(
         GLenum  target,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTexStorage1D(target, levels, internal_format, std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_storage(
         GLuint  texture,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTextureStorage1D(
             texture,
             levels,
             internal_format,
             std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_sub_image(
         GLuint        texture,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTextureSubImage1D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_texture_sub_image(
         GLuint     texture,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCopyTextureSubImage1D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_texture_sub_image(
         GLuint       texture,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCompressedTextureSubImage1D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
 };
 
 template <>
 struct GLTraits::Texture<1>
     : Texture_<1, MakeIndices<1>, MakeIndices<1 < 2 ? 1 : 2>, MakeIndices<2>>
 {
 };
 
 template <
     std::size_t... Is,
     std::size_t... CopySizeIs,
     std::size_t... CopyOffsetIs>
 struct GLTraits::Texture_<
     2,
     GLTraits::Indices<Is...>,
     GLTraits::Indices<CopySizeIs...>,
     GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
 {
     using Size       = std::array<GLsizei, sizeof...(Is)>;
     using Offset     = std::array<GLsizei, sizeof...(Is)>;
     using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
     using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
     auto static constexpr default_target  = GL_TEXTURE_2D;
     auto static constexpr default_binding = GL_TEXTURE_BINDING_2D;
     template <typename Value = GLubyte>
     void static tex_image(
         GLenum        target,
         Size          size,
         GLenum        internal_format = 0,
         Value const * data            = nullptr,
         GLenum        format          = 0,
         GLenum        type            = 0,
         GLint         level           = 0,
         GLint         border          = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 0}, {});
         defaults_(
             internal_format,
             format,
             type,
             GLTraits::Value<Value>::internal_format,
             GLTraits::Value<Value>::format,
             GLTraits::Value<Value>::type);
         glTexImage2D(
             target,
             level,
             (GLint)internal_format,
             std::get<Is>(size)...,
             border,
             format,
             type,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_sub_image(
         GLenum        target,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTexSubImage2D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_tex_sub_image(
         GLenum     target,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 1}, {});
         glCopyTexSubImage2D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_tex_image(
         GLenum       target,
         Size         size,
         GLenum       internal_format,
         GLsizei      data_size = 0,
         void const * data      = nullptr,
         GLint        level     = 0,
         GLint        border    = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexImage2D(
             target,
             level,
             internal_format,
             std::get<Is>(size)...,
             border,
             data_size,
             data);
     }
     void static compressed_tex_sub_image(
         GLenum       target,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexSubImage2D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_storage(
         GLenum  target,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTexStorage2D(target, levels, internal_format, std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_storage(
         GLuint  texture,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTextureStorage2D(
             texture,
             levels,
             internal_format,
             std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_sub_image(
         GLuint        texture,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTextureSubImage2D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_texture_sub_image(
         GLuint     texture,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCopyTextureSubImage2D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_texture_sub_image(
         GLuint       texture,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCompressedTextureSubImage2D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
 };
 
 template <>
 struct GLTraits::Texture<2>
     : Texture_<2, MakeIndices<2>, MakeIndices<2 < 2 ? 2 : 2>, MakeIndices<2>>
 {
 };
 
 template <
     std::size_t... Is,
     std::size_t... CopySizeIs,
     std::size_t... CopyOffsetIs>
 struct GLTraits::Texture_<
     3,
     GLTraits::Indices<Is...>,
     GLTraits::Indices<CopySizeIs...>,
     GLTraits::Indices<CopyOffsetIs...>> : GLTraits::Texture<0>
 {
     using Size       = std::array<GLsizei, sizeof...(Is)>;
     using Offset     = std::array<GLsizei, sizeof...(Is)>;
     using CopySize   = std::array<GLsizei, sizeof...(CopySizeIs)>;
     using CopyOffset = std::array<GLsizei, sizeof...(CopyOffsetIs)>;
     auto static constexpr default_target  = GL_TEXTURE_3D;
     auto static constexpr default_binding = GL_TEXTURE_BINDING_3D;
     template <typename Value = GLubyte>
     void static tex_image(
         GLenum        target,
         Size          size,
         GLenum        internal_format = 0,
         Value const * data            = nullptr,
         GLenum        format          = 0,
         GLenum        type            = 0,
         GLint         level           = 0,
         GLint         border          = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 2}, {});
         defaults_(
             internal_format,
             format,
             type,
             GLTraits::Value<Value>::internal_format,
             GLTraits::Value<Value>::format,
             GLTraits::Value<Value>::type);
         glTexImage3D(
             target,
             level,
             (GLint)internal_format,
             std::get<Is>(size)...,
             border,
             format,
             type,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_sub_image(
         GLenum        target,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 2}, {});
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTexSubImage3D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_tex_sub_image(
         GLenum     target,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 2}, {});
         glCopyTexSubImage3D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_tex_image(
         GLenum       target,
         Size         size,
         GLenum       internal_format,
         GLsizei      data_size = 0,
         void const * data      = nullptr,
         GLint        level     = 0,
         GLint        border    = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexImage3D(
             target,
             level,
             internal_format,
             std::get<Is>(size)...,
             border,
             data_size,
             data);
     }
     void static compressed_tex_sub_image(
         GLenum       target,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({1, 3}, {});
         glCompressedTexSubImage3D(
             target,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
     template <typename Value = GLubyte>
     void static tex_storage(
         GLenum  target,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 2}, "GL_ARB_texture_storage");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTexStorage3D(target, levels, internal_format, std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_storage(
         GLuint  texture,
         Size    size,
         GLenum  internal_format = 0,
         GLsizei levels          = 1)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!internal_format)
             internal_format = GLTraits::Value<Value>::internal_format;
         glTextureStorage3D(
             texture,
             levels,
             internal_format,
             std::get<Is>(size)...);
     }
     template <typename Value = GLubyte>
     void static texture_sub_image(
         GLuint        texture,
         Size          size,
         Value const * data,
         GLenum        format = 0,
         GLenum        type   = 0,
         Offset        offset = {},
         GLint         level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         if (!format)
             format = GLTraits::Value<Value>::format;
         if (!type)
             type = GLTraits::Value<Value>::type;
         glTextureSubImage3D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             format,
             type,
             data);
     }
     void static copy_texture_sub_image(
         GLuint     texture,
         CopySize   copy_size,
         CopyOffset copy_offset = {},
         Offset     offset      = {},
         GLint      level       = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCopyTextureSubImage3D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<CopyOffsetIs>(copy_offset)...,
             std::get<CopySizeIs>(copy_size)...);
     }
     void static compressed_texture_sub_image(
         GLuint       texture,
         Size         size,
         GLsizei      data_size,
         void const * data,
         GLenum       internal_format,
         Offset       offset = {},
         GLint        level  = 0)
     {
         if (GLBase::debug() >= 1)
             GLBase::check_supported({4, 5}, "GL_ARB_direct_state_access");
         glCompressedTextureSubImage3D(
             texture,
             level,
             std::get<Is>(offset)...,
             std::get<Is>(size)...,
             internal_format,
             data_size,
             data);
     }
 };
 
 template <>
 struct GLTraits::Texture<3>
     : Texture_<3, MakeIndices<3>, MakeIndices<3 < 2 ? 3 : 2>, MakeIndices<2>>
 {
 };