Name Mode Size
..
gltraits.cpp 100644 7 kb
vertex_setup.cpp 100644 1 kb
README.md
# [`gltraits`][] A [C++11][](/[C++14][])/[OpenGL][]>=[1.0][](/[GLM][]) [trait][]s library. This library seeks to unify some parts of the OpenGL [API][] to ease [generic programming][]. It also provides sensible default arguments, [optional][debug] [check][]s for [version][]/[extension][] support, and optional support for [OpenGL Mathematics (GLM)][GLM] (which provides [GLSL][]-like types). A more philosophical description: it aims to make the implicit symmetries of the OpenGL API explicit. In the process, some wrinkles in the symmetry are also brought to light. Therefore, it may be useful for learning and understanding the OpenGL API (although this use case may be limited due to the (ab)use of C++ language features). This header-only library makes heavy use of macros. For easy inspection of the results, a script that runs the preprocessor is available in [`doc/preprocess`][] and its output in [`doc/preprocess.hpp`][]. A typical use case is demonstrated by this quote from [OGLDEV on YouTube][]: > Notice, in order to make this an unsigned integer texture we use `GL_RGB32UI` > as the `internal_format`, `GL_RGB_INTEGER` as the `format`, and > `GL_UNSIGNED_INT` as the data `type`. Combining all these formats and types > correctly in OpenGL can often be a pain, and I literally pulled the last few > pieces of hair from my head trying to get this to work. These constants are provided in `GLTraits::Value<glm::uvec3>`. Of course, this becomes even more valuable when `glm::uvec3` is replaced by some unknown template parameter. The function call seen in the video ```cpp glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32UI, WindowWidth, WindowHeight, 0, GL_RGB_INTEGER, GL_UNSIGNED_INT, NULL); ``` can be replaced with ```cpp GLTraits::Texture<2>::tex_image<glm::uvec3>(GL_TEXTURE_2D, {WindowWidth, WindowHeight}); ``` It is recommended to use a library based on `gltraits` that abstracts this further. [`gltraits`]: https://git.rcrnstn.net/rcrnstn/gltraits [C++11]: https://en.wikipedia.org/wiki/C++11 [C++14]: https://en.wikipedia.org/wiki/C++14 [OpenGL]: https://en.wikipedia.org/wiki/OpenGL [1.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history [GLM]: https://glm.g-truc.net [trait]: https://en.wikipedia.org/wiki/Trait_(computer_programming) [API]: https://en.wikipedia.org/wiki/API [generic programming]: https://en.wikipedia.org/wiki/Generic_programming [debug]: https://git.rcrnstn.net/rcrnstn/glbase#debug [check]: https://git.rcrnstn.net/rcrnstn/glbase#check [version]: https://en.wikipedia.org/wiki/OpenGL#Version_history [extension]: https://www.khronos.org/opengl/wiki/OpenGL_Extension [GLSL]: https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language [`doc/preprocess`]: doc/preprocess [`doc/preprocess.hpp`]: doc/preprocess.hpp [OGLDEV on YouTube]: https://www.youtube.com/watch?v=71G-PVpaVk8&t=5m17s ## Usage ### Value The [empty][] `struct GLTraits::Value<typename Value>` is template specialized on the following types. - `GLfloat` - `bool` - `GL{,u}byte` - `GL{,u}short` - `GL{,u}int` - `GLdouble` [GLM][] support is enabled if `glm/glm.hpp` is included (specifically, if `GLM_VERSION` is defined) before inclusion of `gltraits.hpp`. In that case `GLTraits::Value` is additionally template specialized on the following types. - `glm::{,i,u,d}vec{2,3,4}` - `glm::{,d}mat{2{,x3,x4},3{x2,,x4},4{x2,x3,}}` `GLTraits::Value` contains the following `static constexpr` member variables. - `char const name[]` - `GLint columns` - `GLint rows` - `GLenum glsl` - `GLenum format` - `GLenum type` - `GLenum internal_format` - `GLenum internal_format_srgb` - `GLenum internal_format_compressed` - `GLenum internal_format_compressed_srgb` - `bool integer` - `GLenum id` `id` is guaranteed to be unique to this `Value` and is equal to `glsl` for all `Value`s except `GL{,u}{byte,short}`, for which it is equal to `type`. `GLTraits::Value` contains the following `static` member functions. - ```cpp void uniform(GLint location, Value const & value) ``` Generalization of `glUniform*`. Uploads `value` to the [uniform][] indicated by `location` of the current [shader][] program. - ```cpp void vertex_attrib(GLint location, Value const & value) ``` Generalization of `glVertexAttrib*`. Uploads `value` to the [non-array attribute][] indicated by `location`. Note that [`glDisableVertexAttribArray`][] is not called (for performance). - ```cpp void vertex_attrib_pointer( GLint location, std::size_t offset = 0, std::size_t stride = sizeof(Value) ) ``` Generalization of `glVertexAttrib*Pointer`. Sets the [format][] as well as the [offset and stride][] of the [array attribute][] indicated by `location`. Note that [`glEnableVertexAttribArray`][] is not called (for performance). If `location` is `-1`, the above calls will do nothing. No error will be generated in this case. Note that matrix types (e.g. from [GLM][], if enabled), occupy several consecutive attribute locations (one per column), which are all handled automatically by `vertex_attrib{,_pointer}(...)` above. `GLTRAITS_VALUE*` macros are defined to ease the definition of new template specializations of `GLTraits::Value`. Consult the source for the definitions and usage examples. The [empty][] `struct GLTraits::ValueID<GLenum id>` is template specialized on the different values of `GLTraits::Value<Value>::id`. `GLTraits::ValueID` contains the following type definitions. - `Value`. An alias for the template type parameter for which `GLTraits::Value<Value>::id == id` holds. `GLTraits::ValueID` provides a compile time mapping from `GLenum id` back to the type `Value`. E.g. `GLTraits::ValueID<GL_FLOAT>::Value` is an alias for `GLfloat`. This works for all supported types, including those provided by [GLM][] if enabled, e.g. `GLTraits::ValueID<GL_FLOAT_VEC3>::Value` would be an alias for `glm::vec3`. [empty]: https://en.cppreference.com/w/cpp/types/is_empty [uniform]: https://www.khronos.org/opengl/wiki/Uniform_(GLSL) [shader]: https://www.khronos.org/opengl/wiki/Shader [non-array attribute]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Non-array_attribute_values [format]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_format [offset and stride]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_buffer_offset_and_stride [array attribute]: https://www.khronos.org/opengl/wiki/Vertex_Specification#Vertex_Buffer_Object [`glDisableVertexAttribArray`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glEnableVertexAttribArray.xhtml [`glEnableVertexAttribArray`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glEnableVertexAttribArray.xhtml ### Object The [empty][] `struct GLTraits::Object<GLenum object_type>` is template specialized on the following values. - `GL_TEXTURE` - `GL_BUFFER` - `GL_QUERY` - `GL_PROGRAM` - `GL_SHADER` - `GL_VERTEX_ARRAY` - `GL_FRAMEBUFFER` - `GL_RENDERBUFFER` - `GL_SAMPLER` - `GL_TRANSFORM_FEEDBACK` - `GL_PROGRAM_PIPELINE` `GLTraits::Object` contains the following `static constexpr` member variables. - `char const name[]` `GLTraits::Object` contains the following `static` member functions. - ```cpp template<typename... Args> void gen_objects(GLsizei n, GLuint * objects, Args... args) ``` Generalization of `glGen*s` and `glCreate`. - ```cpp void delete_objects(GLsizei n, GLuint * objects) ``` Generalization of `glDelete*s` and `glDelete*`. For `object_types` equal to `GL_SHADER`, `GL_PROGRAM`, and `GL_PROGRAM_PIPELINE`, `GLTraits::Object` additionally contains the following `static` member functions. - ```cpp std::string info_log(GLuint object) ``` Generalization of `glGet*InfoLog`. `GLTRAITS_OBJECT*` macros are defined to ease the definition of new template specializations of `GLTraits::Object`. Consult the source for the definitions and usage examples. ### Texture The [empty][] `struct GLTraits::Texture<std::size_t N>` is template specialized on the following values. - `1`. 1D textures. - `2`. 2D textures. - `3`. 3D textures. `GLTraits::Texture` contains the following type definitions. - `Size`. An alias for `std::array<GLsizei, N>`. - `Offset`. An alias for `std::array<GLsizei, N>`. - `CopySize`. An alias for `std::array<GLsizei, min(N, 2)>`. - `CopyOffset`. An alias for `std::array<GLsizei, 2>`. `GLTraits::Texture` contains the following `static constexpr` member variables. - `default_target`. This is the default target, but many other targets can be used with the member functions described below. E.g. for `N = 2` `default_target` is `GL_TEXTURE_2D`, but valid `target` function arguments are `GL_{,PROXY}_TEXTURE_{2D,RECTANGLE,1D_ARRAY}`, `GL_TEXTURE_CUBE_MAP_{POSITIVE,NEGATIVE}_{X,Y,Z}`, and `GL_PROXY_TEXTURE_CUBE_MAP`. - `default_binding`. Likewise, this is the default binding. `GLTraits::Texture` contains the following `static` member functions. - ```cpp template<typename Value = GLubyte> void 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 ) ``` Generalization of `glTexImage{1,2,3}D`. OpenGL requires that `format` matches the kind of [image format][] specified by `internal_format` (even if `data` is `nullptr`!). Moreover, if `internal_format` specifies an unsized image format, `type` may be used by the implementation when choosing a size (perhaps even if that size is slow!). Therefore, if `format` and/or `type` is `0` (the default) sensible values will be chosen based on the given (or automatically chosen, see below) `internal_format` (note that there is no requirement that the number of color components of `internal_format` and `format` match): - [Color formats][]: `GLTraits::Value<Value>` member variables. - [Depth/stencil formats][]: `GL_DEPTH_STENCIL`, `GL_UNSIGNED_INT_24_8`. - [Depth formats][]: `GL_DEPTH_COMPONENT`, `GL_UNSIGNED_INT`. - [Stencil formats][]: `GL_STENCIL_INDEX`, `GL_UNSIGNED_BYTE`. - ```cpp template<typename Value = GLubyte> void {tex,texture}_storage( {GLenum,GLuint} {target,texture}, Size size, GLenum internal_format = 0, GLsizei levels = 1 ) ``` Generalizations of `gl{Tex,Texture}Storage{1,2,3}D`, which both use [immutable storage][], where the latter uses [Direct State Access][]. - ```cpp template<typename Value = GLubyte> void {tex,texture}_sub_image( {GLenum,GLuint} {target,texture}, Size size, Value const * data, GLenum format = 0, GLenum type = 0, Offset offset = {}, GLint level = 0 ) ``` Generalizations of `gl{Tex,Texture}SubImage{1,2,3}D`, where the latter uses [Direct State Access][]. - ```cpp void copy_{tex,texture}_sub_image( {GLenum,GLuint} {target,texture}, CopySize copy_size, CopyOffset copy_offset = {}, Offset offset = {}, GLint level = 0 ) ``` Generalizations of `glCopy{Tex,Texture}SubImage{1,2,3}D`, where the latter uses [Direct State Access][]. - ```cpp void compressed_tex_image( GLenum target, Size size, GLenum internal_format, GLsizei data_size = 0, void const * data = nullptr, GLint level = 0, GLint border = 0 ) ``` Generalization of `glCompressedTexImage{1,2,3}D`. - ```cpp void compressed_{tex,texture}_sub_image( {GLenum,GLuint} {target,texture}, Size size, GLsizei data_size, void const * data, GLenum internal_format, Offset offset = {}, GLint level = 0 ) ``` Generalizations of `glCompressed{Tex,Texture}SubImage{1,2,3}D`, where the latter uses [Direct State Access][]. For the member functions that are template parameterized on `Value`, when `internal_format`, `format` and/or `type` is `0` (the default), the value used will be taken from the corresponding `GLTraits::Value<Value>` member variable. Note that when the `Value` template type parameter is deduced from `data` the automatically chosen `format` may not be correct. E.g. it is reasonable for `data` to be a `GLubyte` pointer to RGBA values in which case `format` must be manually specified as `GL_RGBA` since the automatically chosen `format` would be `GL_RED`. Note that the [pixel transfer parameters][] are not modified, this must be handled manually if required. (There is no `copy_tex_image(...)` because OpenGL does not provide `glCopyTexImage3D`, only `glCopyTexImage{1,2}D`.) (There is no `{tex_image,tex_storage,texture_storage}_multisample(...)` because OpenGL does not provide `gl{TexImage,TexStorage,TextureStorage}1DMultisample`, only `gl{TexImage,TexStorage,TextureStorage}{2,3}DMultisample`.) (There is no `compressed_texture_image(...)` because OpenGL does not provide `glCompressedTextureImage{1,2,3}D`, only the `Sub` variants.) (There is no `framebuffer_texture(...)` because OpenGL provides incompatible signatures for `glFramebufferTexture1D` and `glFramebufferTexture{2,3}D`.) [image format]: https://www.khronos.org/opengl/wiki/Image_Format [color formats]: https://www.khronos.org/opengl/wiki/Image_Format#Color_formats [depth/stencil formats]: https://www.khronos.org/opengl/wiki/Image_Format#Depth_stencil_formats [depth formats]: https://www.khronos.org/opengl/wiki/Image_Format#Depth_formats [stencil formats]: https://www.khronos.org/opengl/wiki/Image_Format#Stencil_only [Direct State Access]: https://www.khronos.org/opengl/wiki/Direct_State_Access [immutable storage]: https://www.khronos.org/opengl/wiki/Texture_Storage#Immutable_storage [pixel transfer parameters]: https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_transfer_parameters ### Member `GLTraits::members()` provides compile time reflection for types consisting (only) of types supported by `GLTraits::Value`. This feature is only available if [C++14][] or above is supported. If `T` is a non-[empty][] [trivially copyable][] [standard-layout][] type and there exists template specializations of `GLTraits::Value` for the types of either - public member variables of `T`, if `T` is a [class][], or - elements of `T`, if `T` is an [array][], or - `T` itself, if `T` is a [scalar][] then `constexpr auto GLTraits::members<T>()` returns an instance of the [empty][] `struct GLTraits::Members<typename T, typename... Members>` where each of `Members...` is `GLTraits::Member<typename Value, std::size_t offset>` that describe the ("member") types above, in the order they occur in `T`. `Value` is the type of the member and `offset` is the offset of the member in `T`. Note that `offset` is only correct if the padding in `T` is minimal while still satisfying the [`alignof`][] of the member types. The author knows of no compiler that breaks this assumption unless explicitly instructed (e.g. with [`alignas`][], which are not taken into account), however the standard allows it. An example use case would be along the lines of: ```cpp template< typename T, typename Value, std::size_t offset, typename... Members > void vertex_setup( GLTraits::Members<T, GLTraits::Member<Value, offset>, Members...>, GLint location = 0 ) { GLTraits::Value<Value>::vertex_attrib_pointer(location, offset, sizeof(T)); vertex_setup( GLTraits::Members<T, Members...>{}, location + GLTraits::Value<Value>::columns ); } template<typename T> void vertex_setup(GLTraits::Members<T>, GLint) {} struct Vertex { glm::vec3 position; glm::vec2 tex_coord; glm::mat3 tbn; glm::ivec4 bone_indices; glm::vec4 bone_weights; GLubyte flags; GLdouble unaligned; }; vertex_setup(GLTraits::members<Vertex>()); ``` This use case is tested in [`tests/vertex_setup.cpp`][]. To verify that the compiler sees through all the templates, a script that builds it and disassembles it available in [`doc/vertex_setup`][] and its output in [`doc/vertex_setup.i`][]. It is recommended to use a library based on `gltraits` that abstracts this further. Many thanks to Antony Polukhin (the author of [Boost.PFR][] and its standalone version [`magic_get`][]) on whose talks this implementation is based: - [CppCon 2016: C++14 Reflections Without Macros, Markup nor External Tooling][] - [Meeting C++ 2018: Better C++14 reflections][] [trivially copyable]: https://en.cppreference.com/w/cpp/types/is_trivially_copyable [standard-layout]: https://en.cppreference.com/w/cpp/types/is_standard_layout [class]: https://en.cppreference.com/w/cpp/types/is_class [array]: https://en.cppreference.com/w/cpp/types/is_array [scalar]: https://en.cppreference.com/w/cpp/types/is_scalar [`alignof`]: https://en.cppreference.com/w/cpp/language/alignof [`alignas`]: https://en.cppreference.com/w/cpp/language/alignas [`tests/vertex_setup.cpp`]: tests/vertex_setup.cpp [`doc/vertex_setup`]: doc/vertex_setup [`doc/vertex_setup.i`]: doc/vertex_setup.i [Boost.PFR]: https://www.boost.org/libs/pfr [`magic_get`]: https://github.com/apolukhin/magic_get [CppCon 2016: C++14 Reflections Without Macros, Markup nor External Tooling]: https://www.youtube.com/watch?v=abdeAew3gmQ [Meeting C++ 2018: Better C++14 reflections]: https://www.youtube.com/watch?v=UlNUNxLtBI0 ## Building See [`BUILDING.md`][]. [`BUILDING.md`]: BUILDING.md ## License Licensed under the [ISC License][] unless otherwise noted, see the [`LICENSE`][] file. [ISC License]: https://choosealicense.com/licenses/isc [`LICENSE`]: LICENSE