| ... | ... | @@ -9,3 +9,30 @@ project(glbase | 
| 9 | 9 | VERSION 1.0.0 | 
| 10 | 10 | LANGUAGES CXX | 
| 11 | 11 | ) | 
| 12 | + | |
| 13 | +## Main target | |
| 14 | +add_library(${PROJECT_NAME}) | |
| 15 | + | |
| 16 | +## Variables | |
| 17 | +if(NOT GLBASE_INCLUDE) | |
| 18 | + set(GLBASE_PACKAGES GLEW OpenGL) | |
| 19 | + set(GLBASE_TARGETS GLEW::GLEW OpenGL::GL) | |
| 20 | + set(GLBASE_INCLUDE <GL/glew.h>) | |
| 21 | +endif() | |
| 22 | + | |
| 23 | +## Common | |
| 24 | +include(common.cmake) | |
| 25 | +common( | |
| 26 | + CXX_STANDARD 11 | |
| 27 | + DISABLE_CPPCHECK # function try block | |
| 28 | + PACKAGES | |
| 29 | +        ${GLBASE_PACKAGES} | |
| 30 | + FETCHCONTENT | |
| 31 | + https://git.rcrnstn.net/rcrnstn/cxx-str | |
| 32 | + DEPENDENCIES_PUBLIC | |
| 33 | +        ${GLBASE_TARGETS} | |
| 34 | + DEPENDENCIES_PRIVATE | |
| 35 | + cxx-str | |
| 36 | + DEFINITIONS | |
| 37 | +        GLBASE_INCLUDE=${GLBASE_INCLUDE} | |
| 38 | +) | 
| ... | ... | @@ -2,10 +2,518 @@ | 
| 2 | 2 |  | 
| 3 | 3 | A [C++11][]/[OpenGL][]>=[1.0][] basics library. | 
| 4 | 4 |  | 
| 5 | +This library wraps up some common basic OpenGL functionality for convenience, | |
| 6 | +including checking for supported OpenGL [version][]s and [extension][]s, basic | |
| 7 | +image loading and saving, debugging helpers, error checking, and string | |
| 8 | +helpers. | |
| 9 | + | |
| 5 | 10 | [`glbase`]: https://git.rcrnstn.net/rcrnstn/glbase | 
| 6 | 11 | [C++11]: https://en.wikipedia.org/wiki/C++11 | 
| 7 | 12 | [OpenGL]: https://en.wikipedia.org/wiki/OpenGL | 
| 8 | 13 | [1.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history | 
| 14 | +[version]: https://en.wikipedia.org/wiki/OpenGL#Version_history | |
| 15 | +[extension]: https://www.khronos.org/opengl/wiki/OpenGL_Extension | |
| 16 | + | |
| 17 | +## Usage | |
| 18 | + | |
| 19 | +### OpenGL loading library | |
| 20 | + | |
| 21 | +This library can be used with an arbitrary [OpenGL loading library][] by making | |
| 22 | +sure `GLBASE_INCLUDE` is defined to the file to `#include`, e.g. | |
| 23 | +`<glad/glad.h>` (either in the source or through a compiler switch, probably | |
| 24 | +defined in the build system). Note that double quotes or angle brackets are | |
| 25 | +required. The default if none is defined is `<GL/glew.h>`. | |
| 26 | + | |
| 27 | +If [CMake][] is used for building (see [Building][]), the `GLBASE_INCLUDE` | |
| 28 | +CMake variable can be set to tell `glbase` to not use the default [GLEW][], and | |
| 29 | +to set the corresponding define. In this case, the CMake variables | |
| 30 | +`GLBASE_PACKAGES` and `GLBASE_TARGETS` can be used to set the packages and | |
| 31 | +targets respectively to use for OpenGL and the loading library (either or both | |
| 32 | +can be empty). | |
| 33 | + | |
| 34 | +[OpenGL loading library]: https://www.khronos.org/opengl/wiki/OpenGL_Loading_Library | |
| 35 | +[CMake]: https://cmake.org | |
| 36 | +[Building]: #building | |
| 37 | +[GLEW]: https://glew.sourceforge.net | |
| 38 | + | |
| 39 | +### Thread safety | |
| 40 | + | |
| 41 | +"Global" state (usually used to mirror some OpenGL [context][] internal state | |
| 42 | +for performance) is declared [`thread_local`][] and initialized lazily. This | |
| 43 | +means that a given thread may create at most one OpenGL context, and the | |
| 44 | +`GLBase`-derived objects created while that context is current may be used only | |
| 45 | +from that thread. Driver vendors recommend to not share OpenGL contexts between | |
| 46 | +threads, for performance. | |
| 47 | + | |
| 48 | +The underlying mechanism used to retrieve system error messages may be thread | |
| 49 | +unsafe. (`GLBase`-derived classes are encouraged to use | |
| 50 | +`std::generic_category().message(errno)`, which often is, but is not required | |
| 51 | +to be, thread safe, instead of [`std::strerror`][]`(errno)`, which is thread | |
| 52 | +unsafe on most platforms). | |
| 53 | + | |
| 54 | +[context]: https://www.khronos.org/opengl/wiki/OpenGL_Context | |
| 55 | +[`thread_local`]: https://en.cppreference.com/w/cpp/keyword/thread_local | |
| 56 | +[`std::strerror`]: https://en.cppreference.com/w/cpp/string/byte/strerror | |
| 57 | + | |
| 58 | +### Conventions | |
| 59 | + | |
| 60 | +The following table summarizes the [naming convention][] used. | |
| 61 | + | |
| 62 | +| Category | Capitalization | Public | Protected | Private | | |
| 63 | +| -------- | -------------- | ------ | ---------- | ---------- | | |
| 64 | +| Type | `PascalCase` | | `_` suffix | `_` suffix | | |
| 65 | +| Function | `snake_case` | | `_` suffix | `_` suffix | | |
| 66 | +| Variable | `snake_case` | (none) | (none) | `_` suffix | | |
| 67 | +| Macro | `MACRO_CASE` | (few) | | `_` suffix | | |
| 68 | + | |
| 69 | +"Private" in this case includes things with [internal linkage][]. The [storage | |
| 70 | +duration][] or whether members are bound to class instances or not does not | |
| 71 | +affect naming. Parameters (including template parameters) are considered public | |
| 72 | +even though their use obviously is constrained to a scope inaccessible to the | |
| 73 | +outside user. | |
| 74 | + | |
| 75 | +As can be seen in the table, class member variables are always private and | |
| 76 | +(either public or protected) access is provided by [Accessors][]. | |
| 77 | +`GLBase`-derived classes should prefer to use their own protected member | |
| 78 | +functions over their private member variables. | |
| 79 | + | |
| 80 | +[naming convention]: https://en.wikipedia.org/wiki/Naming_convention_(programming) | |
| 81 | +[internal linkage]: https://en.cppreference.com/w/cpp/language/storage_duration#internal_linkage | |
| 82 | +[storage duration]: https://en.cppreference.com/w/cpp/language/storage_duration#storage_duration | |
| 83 | +[Accessors]: #accessors | |
| 84 | + | |
| 85 | +### Size | |
| 86 | + | |
| 87 | +`GLBase` is an [empty][] class and the [empty base optimization][] applies. | |
| 88 | + | |
| 89 | +[empty]: https://en.cppreference.com/w/cpp/types/is_empty | |
| 90 | +[empty base optimization]: https://en.cppreference.com/w/cpp/language/ebo | |
| 91 | + | |
| 92 | +### Special member functions | |
| 93 | + | |
| 94 | +Both the constructor and the destructor are [`protected`][]. End users should | |
| 95 | +use a `GLBase`-derived class to instantiate objects. | |
| 96 | + | |
| 97 | +Note that the destructor is not [`virtual`][]. `GLBase`-derived objects must | |
| 98 | +not be destroyed through `GLBase` pointers. | |
| 99 | + | |
| 100 | +[`protected`]: https://en.cppreference.com/w/cpp/keyword/protected | |
| 101 | +[`virtual`]: https://en.cppreference.com/w/cpp/language/virtual | |
| 102 | + | |
| 103 | +### Accessors | |
| 104 | + | |
| 105 | +Getter and setter functions share the same name and use function overloading to | |
| 106 | +disambiguate. Getters (which can be run on `const` objects) take no argument | |
| 107 | +and return the value (by `const` reference). Setters take a [forwarding | |
| 108 | +reference][] argument and return the old value (by value, after move). | |
| 109 | + | |
| 110 | +Macros that aid in the implementation of (potentially "global" static thread | |
| 111 | +local) getters and setters are defined. These should be used in the class | |
| 112 | +definition. They define functions named `NAME`, which operate on a variable | |
| 113 | +named `NAME##_`. The underlying variable is not declared automatically, this | |
| 114 | +must be done manually (probably [`private`][]). The `ACCESS` variant defines | |
| 115 | +both `GET` and `SET`. | |
| 116 | + | |
| 117 | +`GLBASE_{GET,SET,ACCESS}{,_GLOBAL}(TYPE, NAME)` | |
| 118 | + | |
| 119 | +Additionally, "global" static thread local member variables need to be defined | |
| 120 | +in exactly one [translation unit][]. A macro to help with this is defined as | |
| 121 | +well. Note that, since the definition is outside the class definition, the | |
| 122 | +`NAME` needs to be qualified with the class name. | |
| 123 | + | |
| 124 | +`GLBASE_GLOBAL(NAME, INIT)` | |
| 125 | + | |
| 126 | +[forwarding reference]: https://en.cppreference.com/w/cpp/language/reference#Forwarding_references | |
| 127 | +[`private`]: https://en.cppreference.com/w/cpp/keyword/private | |
| 128 | +[translation unit]: https://en.wikipedia.org/wiki/Translation_unit_(programming) | |
| 129 | + | |
| 130 | +### Base | |
| 131 | + | |
| 132 | +`Version` is an alias for `std::array<GLint, 2>`. | |
| 133 | + | |
| 134 | +`bool static supported(Version version_min, std::string const & extension = | |
| 135 | +{})` returns `true` if the current OpenGL [context][] implements the given, or | |
| 136 | +a later (but see `version_max(...)` below), version or the given extension. If | |
| 137 | +no version check is desired, provide `{}` (or, equivalently, `{0, 0}`). If no | |
| 138 | +extension check is desired, provide an empty extension string (the default). If | |
| 139 | +a non-empty `extension` is provided, it must start with `"GL_"`. If no check at | |
| 140 | +all is performed, `false` is returned. Being able to check for both version and | |
| 141 | +extension is convenient because extensions are often absorbed into newer | |
| 142 | +versions of the OpenGL specification itself, and some platforms stop reporting | |
| 143 | +support for the extension for those versions, so only checking if the extension | |
| 144 | +is available fails. [History of OpenGL][] has a list of which versions of | |
| 145 | +OpenGL absorbed which extensions. Since this library is agnostic to the used | |
| 146 | +[OpenGL loading library][] (which is usually used to perform these kind of | |
| 147 | +checks), the OpenGL API itself is queried. A new method of determining | |
| 148 | +supported extensions was introduced in OpenGL [3.0][] and the old method | |
| 149 | +deprecated and removed in OpenGL [3.1][]. This function uses the method | |
| 150 | +appropriate for the current OpenGL [context][]. Note that no other checks are | |
| 151 | +performed, including checks for a compatibility [profile][] [context][] or | |
| 152 | +support for the [`ARB_compatibility`][] extension. | |
| 153 | + | |
| 154 | +`Version version_max({Version version_max})` gets/sets the maximum version for | |
| 155 | +which `supported(...)` described above will return `true`. To disable this | |
| 156 | +functionality, provide `{}` (or, equivalently, `{0, 0}`), which is the default | |
| 157 | +value. Setting it to any other value also disables extension checking in | |
| 158 | +`supported(...)`. This is useful for testing fallback code paths, regardless of | |
| 159 | +the version present on a development machine (many platforms will provide a | |
| 160 | +[context][] with a version higher than the one requested). | |
| 161 | + | |
| 162 | +`char const * static string(GLenum name)` and `char const * static | |
| 163 | +string(GLenum name, GLuint index)` call [`glGetString`][] and | |
| 164 | +[`glGetStringi`][] respectively with the given arguments and return the result, | |
| 165 | +which obviates the need to cast the result (the OpenGL functions return | |
| 166 | +`GLubyte const *`). | |
| 167 | + | |
| 168 | +`GLint static integer(GLenum name)` calls [`glGetIntegerv`][] with the given | |
| 169 | +argument and returns the result, which obviates the need to declare a variable | |
| 170 | +beforehand. Make sure to only use values of `name` that get a single integer. | |
| 171 | + | |
| 172 | +[History of OpenGL]: https://www.khronos.org/opengl/wiki/History_of_OpenGL | |
| 173 | +[`glGetIntegerv`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGet.xhtml | |
| 174 | +[`glGetString`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetString.xhtml | |
| 175 | +[`glGetStringi`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetString.xhtml | |
| 176 | +[3.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history | |
| 177 | +[3.1]: https://en.wikipedia.org/wiki/OpenGL#Version_history | |
| 178 | +[profile]: https://www.khronos.org/opengl/wiki/OpenGL_Context#OpenGL_3.2_and_Profiles | |
| 179 | +[`ARB_compatibility`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_compatibility.txt | |
| 180 | + | |
| 181 | +### Path | |
| 182 | + | |
| 183 | +`Path` is an alias for `std::string`. | |
| 184 | + | |
| 185 | +`Paths` is an alias for `std::vector<Path>`. | |
| 186 | + | |
| 187 | +`Path static path_prefix_(Path const & path, Path const & prefix)` returns | |
| 188 | +`prefix` prepended to `path`, separated with a `/`, unless either | |
| 189 | + | |
| 190 | +1. `prefix` is empty | |
| 191 | +2. `path` starts with a `/` | |
| 192 | + | |
| 193 | +in which case `path` is returned as is. | |
| 194 | + | |
| 195 | +### TGA | |
| 196 | + | |
| 197 | +A nested `GLBase::TGA_` class is provided to handle [Truevision TGA][] images | |
| 198 | +in left-to-right, bottom-to-top, uncompressed [BGRA][] format. TGA was selected | |
| 199 | +because it is widely supported and has a trivial header and data layout. It is | |
| 200 | +also convenient because it has a pixel ordering compatible with the default | |
| 201 | +[pixel transfer parameters][] and `GL_BGRA` is often preferred by graphics | |
| 202 | +cards. | |
| 203 | + | |
| 204 | +`GLBase::TGA_` contains the following `static constexpr` member variables. | |
| 205 | + | |
| 206 | +- `char const name[]`: `"TGA"` | |
| 207 | +- `GLint columns`: `1` | |
| 208 | +- `GLint rows`: `4` | |
| 209 | +- `GLenum glsl`: `GL_FLOAT_VEC4` | |
| 210 | +- `GLenum format`: `GL_BGRA` | |
| 211 | +- `GLenum type`: `GL_UNSIGNED_BYTE` | |
| 212 | +- `GLenum internal_format`: `GL_RGBA8` | |
| 213 | +- `GLenum internal_format_srgb`: `GL_SRGB8_ALPHA8` | |
| 214 | +- `GLenum internal_format_compressed`: `GL_COMPRESSED_RGBA` | |
| 215 | +- `GLenum internal_format_compressed_srgb`: `GL_COMPRESSED_SRGB_ALPHA` | |
| 216 | +- `GLenum id`: `glsl` | |
| 217 | + | |
| 218 | +(These are the same `static constexpr` member variables defined by | |
| 219 | +[`GLTraits::Value`][].) | |
| 220 | + | |
| 221 | +`GLBase::TGA_` contains the following type definitions. | |
| 222 | + | |
| 223 | +- `Size`. An alias for `std::array<GLsizei, 2>`. | |
| 224 | +- `Data`. An alias for `std::vector<GLubyte>`. | |
| 225 | + | |
| 226 | +`GLBase::TGA_` contains the following member functions. | |
| 227 | + | |
| 228 | +-   `explicit TGA_(Size size, Data data, Path const & path = {})`. Instantiates | |
| 229 | + a `TGA_` object with the given `size` and `data`. `path`, if given, is only | |
| 230 | + used for error reporting. | |
| 231 | +- `TGA_ static read(std::string const & path)`. Reads the file `path` into a | |
| 232 | + `TGA_` object. | |
| 233 | +- `void write(std::string const & path) const`. Writes the `TGA_` object to | |
| 234 | + the file `path`. | |
| 235 | +- `Size size() const`. Gets the size of the TGA image. | |
| 236 | +- `Data const & data() const`. Gets the data of the TGA image. | |
| 237 | + | |
| 238 | +[Truevision TGA]: https://en.wikipedia.org/wiki/Truevision_TGA | |
| 239 | +[BGRA]: https://en.wikipedia.org/wiki/RGBA_color_model | |
| 240 | +[pixel transfer parameters]: https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_transfer_parameters | |
| 241 | +[`GLTraits::Value`]: https://git.rcrnstn.net/rcrnstn/gltraits/#value | |
| 242 | +[GLSL]: https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language | |
| 243 | + | |
| 244 | +### Exceptions | |
| 245 | + | |
| 246 | +All exceptions thrown are of the type `GLBase::Exception`, which inherits from | |
| 247 | +[`std::runtime_error`][]. | |
| 248 | + | |
| 249 | +[`std::runtime_error`]: https://en.cppreference.com/w/cpp/error/runtime_error | |
| 250 | + | |
| 251 | +### Debug | |
| 252 | + | |
| 253 | +A dynamic debug facility is used instead of asserts mainly because it allows | |
| 254 | +dynamic error messages and it is often desirable to turn on debugging only | |
| 255 | +during a problematic part of an application run. | |
| 256 | + | |
| 257 | +`DebugCallback` is an alias for [`std::function`][]`<void (std::string const & | |
| 258 | +message)>`. These functions may not [`throw`][] since they are called by | |
| 259 | +OpenGL, which may not support throwing exceptions across its stack frames. | |
| 260 | + | |
| 261 | +`int static debug({int debug})` gets/sets the global debug level. When `>= 1`, | |
| 262 | +potentially costly debug operations are performed as part of other operations. | |
| 263 | +When `>= 2` notifications may be emitted. Defaults to `0`. | |
| 264 | + | |
| 265 | +`DebugCallback static debug_callback({DebugCallback debug_callback})` gets/sets | |
| 266 | +a callback that may be called by `GLBase`-derived classes (typically through | |
| 267 | +`debug_message(...)`, see below). Defaults to a function which outputs the | |
| 268 | +`mesage` argument to [`std::cerr`][], appends a newline and flushes. | |
| 269 | + | |
| 270 | +`void static debug_message(std::string const & message)` calls the callback | |
| 271 | +registered with `debug_callback(...)` with `message` as argument if the | |
| 272 | +callback is not empty (i.e. set to `nullptr`). | |
| 273 | + | |
| 274 | +`void static debug_action_(std::string const & action, std::string const & | |
| 275 | +name)` calls `debug_message(...)` with a string containing `action` and `name`. | |
| 276 | + | |
| 277 | +[`std::function`]: https://en.cppreference.com/w/cpp/utility/functional/function | |
| 278 | +[`throw`]: https://en.cppreference.com/w/cpp/language/throw | |
| 279 | +[`std::cerr`]: https://en.cppreference.com/w/cpp/io/cerr | |
| 280 | + | |
| 281 | +### Check | |
| 282 | + | |
| 283 | +These functions throw an exception if some condition does not hold. It is | |
| 284 | +recommended that `GLBase`-derived classes use similar helper functions, defined | |
| 285 | +in an implementation file, to hide the string processing necessary to form a | |
| 286 | +helpful exception message. | |
| 287 | + | |
| 288 | +`GLBase`-derived classes should treat error checking as free during | |
| 289 | +construction and expensive data transfer operations. At all other times, | |
| 290 | +non-critical error checking should only be performed if `debug() >= 1`. | |
| 291 | + | |
| 292 | +`void static check_supported(Version version_min, std::string const & extension | |
| 293 | += {})` checks that `supported(...)` returns `true` for the given arguments. | |
| 294 | + | |
| 295 | +`void static check_path_(std::string const & path)` checks that `path` is | |
| 296 | +non-empty. | |
| 297 | + | |
| 298 | +`void static check_error_(GLenum error)` checks an error returned by | |
| 299 | +[`glGetError`][]. | |
| 300 | + | |
| 301 | +`void static check_type_(GLenum type, GLenum type_expected)` checks that `type` | |
| 302 | +matches `type_expected`. | |
| 303 | + | |
| 304 | +`void static check_format_(GLenum format, GLenum format_expected)` checks that | |
| 305 | +`format` matches `format_expected`. | |
| 306 | + | |
| 307 | +`void static check_internal_format_(GLenum internal_format)` checks that | |
| 308 | +`internal_format` is supported. | |
| 309 | + | |
| 310 | +[`glGetError`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetError.xhtml | |
| 311 | + | |
| 312 | +### Fail | |
| 313 | + | |
| 314 | +These functions throw an exception and should be marked [`[[noreturn]]`][]. It | |
| 315 | +is recommended that `GLBase`-derived classes use similar helper functions, | |
| 316 | +defined in an implementation file, to hide the string processing necessary to | |
| 317 | +form a helpful exception message. | |
| 318 | + | |
| 319 | +`[[noreturn]] void static fail_action_(std::string const & action, std::string | |
| 320 | +const & name)` calls [`std::terminate`][] if called outside a [`catch`][] | |
| 321 | +block. Otherwise, throws an exception with a message that includes `action` and | |
| 322 | +`name` followed by `":\n"` and the [`what()`][] of the current exception if it | |
| 323 | +is a (derives from) [`std::exception`][], otherwise simply rethrows the current | |
| 324 | +exception. | |
| 325 | + | |
| 326 | +[`[[noreturn]]`]: https://en.cppreference.com/w/cpp/language/attributes/noreturn | |
| 327 | +[`std::terminate`]: https://en.cppreference.com/w/cpp/error/terminate | |
| 328 | +[`catch`]: https://en.cppreference.com/w/cpp/language/try_catch | |
| 329 | +[`what()`]: https://en.cppreference.com/w/cpp/error/exception/what | |
| 330 | +[`std::exception`]: https://en.cppreference.com/w/cpp/error/exception | |
| 331 | + | |
| 332 | +### String | |
| 333 | + | |
| 334 | +`std::string static str_path_(Path const & path)` returns `path` surrounded by | |
| 335 | +double quotes. | |
| 336 | + | |
| 337 | +`std::string static str_paths_(Paths const & paths)` returns `paths` surrounded | |
| 338 | +by double quotes and joined with commas. | |
| 339 | + | |
| 340 | +`std::string static str_enum_(GLenum name)` returns the hexadecimal string | |
| 341 | +representation of `name` (often used as fallback). | |
| 342 | + | |
| 343 | +`std::string static str_error_(GLenum error)` returns the string representation | |
| 344 | +of values returned by [`glGetError`][]. | |
| 345 | + | |
| 346 | +`std::string static str_object_type_(GLenum object_type)` returns the string | |
| 347 | +representation of `object_type`. | |
| 348 | + | |
| 349 | +`std::string static str_glsl_(GLenum glsl)` returns the string representation | |
| 350 | +of `glsl`. | |
| 351 | + | |
| 352 | +`std::string static str_format_(GLenum format)` returns the string | |
| 353 | +representation of `format`. | |
| 354 | + | |
| 355 | +`std::string static str_type_(GLenum type)` returns the string representation | |
| 356 | +of `type`. | |
| 357 | + | |
| 358 | +`std::string static str_internal_format_(GLenum internal_format)` returns the | |
| 359 | +string representation of `internal_format`. | |
| 360 | + | |
| 361 | +## Texture compression formats | |
| 362 | + | |
| 363 | +This is here for reference only. | |
| 364 | + | |
| 365 | +Extension conventions are defined in [`GL_ARB_texture_compression`][]. Formats | |
| 366 | +are described in the [Khronons Data Format Specification "Compressed Texture | |
| 367 | +Image Formats"][] section. | |
| 368 | + | |
| 369 | +[Direct3D][] defines `BC*` texture "block" compression formats which | |
| 370 | +correspond with some of the formats described below. See: | |
| 371 | + | |
| 372 | +- [Direct3D 10 Texture Block Compression][] | |
| 373 | +- [Direct3D 11 Texture Block Compression][] | |
| 374 | + | |
| 375 | +A non-exhaustive list of compressed texture formats defined by OpenGL: | |
| 376 | + | |
| 377 | +- **S3TC** | |
| 378 | + - Support: Widely supported since OpenGL 1.3 (2001) (the non-sRGB | |
| 379 | + version is considered an "[ubiquitous extension][]"). Not core because | |
| 380 | + of patents, which expired 2017. [Mesa][] support since 17.3 (2017). | |
| 381 | + - Origin: Introduced by [S3 Graphics][]' [Savage 3D][] (1998) and | |
| 382 | + supported by [Nvidia][]'s more popular [GeForce 256][] (also known | |
| 383 | + as the "GeForce 1") (1999). (`DXT2` and `DXT4` are premultiplied alpha | |
| 384 | + formats and not supported by OpenGL.) | |
| 385 | + - Formats: | |
| 386 | +        -   `{RGB{,A},SRGB{,_ALPHA}}_S3TC_DXT1_EXT` (`BC1`). 6:1 compression | |
| 387 | + ratio. The alpha variants only have a single bit of alpha, and when | |
| 388 | + `A` is `0` RGB must all be `0` as well. Therefore, it is best to | |
| 389 | + use premultiplied alpha when using the alpha variants. | |
| 390 | +        -   `{RGBA,SRGB_ALPHA}_S3TC_DXT3_EXT` (`BC2`). 4:1 compression ratio. | |
| 391 | + Stores *uncompressed* alpha separately. Not generally recommended. | |
| 392 | +        -   `{RGBA,SRGB_ALPHA}_S3TC_DXT5_EXT` (`BC3`). 4:1 compression ratio. | |
| 393 | + Stores *compressed* alpha separately. | |
| 394 | + - References: | |
| 395 | + - [`GL_EXT_texture_compression_s3tc`][] | |
| 396 | + - [`GL_EXT_texture_compression_s3tc_srgb`][] | |
| 397 | + - [`GL_EXT_texture_sRGB`][] | |
| 398 | + - [`GL_NV_texture_compression_s3tc`][] | |
| 399 | + - [`GL_S3_s3tc`][] | |
| 400 | + - [OpenGL Wiki][S3TC OpenGL Wiki] | |
| 401 | + - [Wikipedia][S3TC Wikipedia] | |
| 402 | +- VTC | |
| 403 | + - Support: Not core. Only supported on Nvidia hardware. | |
| 404 | +    -   Origin: Extension of S3TC to 3D ("volume") textures. | |
| 405 | + - Formats: The same as S3TC, but interpreted differently for 3D textures. | |
| 406 | + - References: | |
| 407 | + - [`GL_NV_texture_compression_vtc`][] | |
| 408 | +- **RGTC** | |
| 409 | + - Support: Core since OpenGL 3.0 (2008). | |
| 410 | + - Origin: Uses a separate S3TC DXT5 alpha encoding for one or two | |
| 411 | + component red/green. Published at the same time as LATC. | |
| 412 | + - Formats: | |
| 413 | +        -   `{,SIGNED_}RED_RGTC1` (`BC4`). 2:1 compression ratio. | |
| 414 | +        -   `{,SIGNED_}RG_RGTC2` (`BC5`). 2:1 compression ratio. | |
| 415 | + - References: | |
| 416 | + - [`GL_ARB_texture_compression_rgtc`][] | |
| 417 | + - [`GL_EXT_texture_compression_rgtc`][] | |
| 418 | + - [OpenGL Wiki][RGTC OpenGL Wiki] | |
| 419 | + - [Wikipedia][RGTC Wikipedia] | |
| 420 | +- LATC: | |
| 421 | + - Support: Not core, no ARB extension. Luminance/alpha formats in general | |
| 422 | + have seen a decline since the introduction of the programmable | |
| 423 | + pipeline, which can use [swizzle][]s to achieve the same effect. | |
| 424 | + - Origin: Uses a separate S3TC DXT5 alpha encoding for one or two | |
| 425 | + component luminance/alpha. Published at the same time as RGTC. | |
| 426 | + - Formats: | |
| 427 | +        -   `{,SIGNED_}LUMINANCE_LATC1_EXT`. 2:1 compression ratio. | |
| 428 | +        -   `{,SIGNED_}LUMINANCE_ALPHA_LATC2_EXT`. 2:1 compression ratio. | |
| 429 | + - References | |
| 430 | + - [`GL_EXT_texture_compression_latc`][] | |
| 431 | + - [`GL_NV_texture_compression_latc`][] | |
| 432 | +- **BPTC** | |
| 433 | + - Support: Core since OpenGL 4.2 (2011). | |
| 434 | + - Origin: Block Partition texture compression. | |
| 435 | + - Formats: | |
| 436 | +        -   `RGB_BPTC_{UN,}SIGNED_FLOAT` (`BC6H`): 4:1 compression ratio. | |
| 437 | +            Unsigned/signed 16-bit ("high dynamic range") float RGB. | |
| 438 | +        -   `{RGBA,SRGB_ALPHA}_BPTC_UNORM` (`BC7`): 4:1 compression ratio. | |
| 439 | + Unsigned normalized integer RGBA/sRGBA. | |
| 440 | + - References: | |
| 441 | + - [`GL_ARB_texture_compression_bptc`][] | |
| 442 | + - [`GL_EXT_texture_compression_bptc`][] | |
| 443 | + - [OpenGL Wiki][BPTC OpenGL Wiki] | |
| 444 | + - [Wikipedia][BPTC Wikipedia] | |
| 445 | +- **ETC** | |
| 446 | + - Support: Core since OpenGL 4.3 (2012). Desktop OpenGL does not support | |
| 447 | + ETC1, only ETC2. Images encoded as ETC1 can be read by an ETC2 decoder. | |
| 448 | + - Origins: [Ericsson][]. EAC presumably stands for "Ericsson Alpha | |
| 449 | + Compression" and is used to compress one or two channels (much like | |
| 450 | + RGTC uses the alpha compression format of S3TC DX5). | |
| 451 | + - Formats: | |
| 452 | +        -   `{,S}RGB8{,_PUNCHTHROUGH_ALPHA1}_ETC2` 6:1 compression ratio. | |
| 453 | +        -   `{RGBA8,SRGB8_ALPHA8}_ETC2_EAC`. 4:1 compression ratio. | |
| 454 | +        -   `{,SIGNED_}R11_EAC` 2:1 compression ratio. | |
| 455 | +        -   `{,SIGNED_}RG11_EAC` 2:1 compression ratio. | |
| 456 | + - References: | |
| 457 | + - [`GL_ARB_ES3_compatibility`][] | |
| 458 | + - [`GL_OES_compressed_ETC1_RGB8_texture`][] | |
| 459 | + - [Wikipedia][ETC Wikipedia] | |
| 460 | +- ASTC: | |
| 461 | + - Support: Not core. The extension is written against OpenGL ES, and | |
| 462 | + there is no wide desktop support, at least for the HDR version. | |
| 463 | +    -   Origin: [ARM][] and [AMD][]. Variable block ("adaptive scalable") | |
| 464 | + texture compression. | |
| 465 | + - Formats: | |
| 466 | +        -   `{RGBA,SRGB8_ALPHA8}_ASTC_{4x4,5x{4,5},6x{5,6},8x{5,6,8},10x{5,6,8,10},12x{10,12}}_KHR` | |
| 467 | + A large number of variables are encoded per block so e.g. the | |
| 468 | + number of channels, dynamic range, and compression ratio vary. | |
| 469 | + - References: | |
| 470 | + - `GL_KHR_texture_compression_astc_ldr`, [`GL_KHR_texture_compression_astc_hdr`][] | |
| 471 | + - [`GL_KHR_texture_compression_astc_sliced_3d`][] | |
| 472 | + - [OpenGL Wiki][ASTC OpenGL Wiki] | |
| 473 | + - [Wikipedia][ASTC Wikipedia] | |
| 474 | + - [`ARM-software/astc-encoder`][] | |
| 475 | + | |
| 476 | +[`GL_ARB_texture_compression`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression.txt | |
| 477 | +[Khronons Data Format Specification "Compressed Texture Image Formats"]: https://registry.khronos.org/DataFormat/specs/1.1/dataformat.1.1.html#_compressed_texture_image_formats | |
| 478 | +[Direct3D]: https://en.wikipedia.org/wiki/Direct3D | |
| 479 | +[Direct3D 10 Texture Block Compression]: https://learn.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression | |
| 480 | +[Direct3D 11 Texture Block Compression]: https://learn.microsoft.com/en-us/windows/win32/direct3d11/texture-block-compression-in-direct3d-11 | |
| 481 | +[ubiquitous extension]: https://www.khronos.org/opengl/wiki/Ubiquitous_Extension | |
| 482 | +[Mesa]: https://en.wikipedia.org/wiki/Mesa_(computer_graphics) | |
| 483 | +[S3 Graphics]: https://en.wikipedia.org/wiki/S3_Graphics | |
| 484 | +[Savage 3D]: https://en.wikipedia.org/wiki/S3_Savage#Savage_3D | |
| 485 | +[Nvidia]: https://en.wikipedia.org/wiki/Nvidia | |
| 486 | +[GeForce 256]: https://en.wikipedia.org/wiki/GeForce_256 | |
| 487 | +[`GL_EXT_texture_compression_s3tc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc.txt | |
| 488 | +[`GL_EXT_texture_compression_s3tc_srgb`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc_srgb.txt | |
| 489 | +[`GL_EXT_texture_sRGB`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_sRGB.txt | |
| 490 | +[`GL_NV_texture_compression_s3tc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_s3tc.txt | |
| 491 | +[`GL_S3_s3tc`]: https://registry.khronos.org/OpenGL/extensions/S3/S3_s3tc.txt | |
| 492 | +[S3TC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/S3_Texture_Compression | |
| 493 | +[S3TC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression | |
| 494 | +[`GL_NV_texture_compression_vtc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_vtc.txt | |
| 495 | +[`GL_ARB_texture_compression_rgtc`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt | |
| 496 | +[`GL_EXT_texture_compression_rgtc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_rgtc.txt | |
| 497 | +[RGTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/Red_Green_Texture_Compression | |
| 498 | +[RGTC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression#BC4_and_BC5 | |
| 499 | +[swizzle]: https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Swizzling | |
| 500 | +[`GL_EXT_texture_compression_latc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_latc.txt | |
| 501 | +[`GL_NV_texture_compression_latc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_latc.txt | |
| 502 | +[`GL_ARB_texture_compression_bptc`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt | |
| 503 | +[`GL_EXT_texture_compression_bptc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_bptc.txt | |
| 504 | +[BPTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/BPTC_Texture_Compression | |
| 505 | +[BPTC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression#BC6H_and_BC7 | |
| 506 | +[Ericsson]: https://en.wikipedia.org/wiki/Ericsson | |
| 507 | +[`GL_ARB_ES3_compatibility`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_ES3_compatibility.txt | |
| 508 | +[`GL_OES_compressed_ETC1_RGB8_texture`]: https://registry.khronos.org/OpenGL/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt | |
| 509 | +[ETC Wikipedia]: https://en.wikipedia.org/wiki/Ericsson_Texture_Compression | |
| 510 | +[ARM]: https://en.wikipedia.org/wiki/Arm_(company) | |
| 511 | +[AMD]: https://en.wikipedia.org/wiki/AMD | |
| 512 | +[`GL_KHR_texture_compression_astc_hdr`]: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt | |
| 513 | +[`GL_KHR_texture_compression_astc_sliced_3d`]: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_sliced_3d.txt | |
| 514 | +[ASTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/ASTC_Texture_Compression | |
| 515 | +[ASTC Wikipedia]: https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression | |
| 516 | +[`ARM-software/astc-encoder`]: https://github.com/ARM-software/astc-encoder | |
| 9 | 517 |  | 
| 10 | 518 | ## Building | 
| 11 | 519 |  | 
| 12 | 520 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,211 @@ | 
| 1 | +/// Guards | |
| 2 | + | |
| 3 | +#ifndef GLBASE_HPP_ | |
| 4 | +#define GLBASE_HPP_ | |
| 5 | + | |
| 6 | + | |
| 7 | +/// Includes | |
| 8 | + | |
| 9 | +#include <array> | |
| 10 | +#include <functional> | |
| 11 | +#include <stdexcept> | |
| 12 | +#include <string> | |
| 13 | +#include <utility> | |
| 14 | +#include <vector> | |
| 15 | + | |
| 16 | +#ifndef GLBASE_INCLUDE | |
| 17 | +#define GLBASE_INCLUDE <GL/glew.h> | |
| 18 | +#endif | |
| 19 | +#include GLBASE_INCLUDE // IWYU pragma: export | |
| 20 | + | |
| 21 | + | |
| 22 | +/// Accessors | |
| 23 | + | |
| 24 | +#define GLBASE_GET_(TYPE, NAME, STATIC, CONST) \ | |
| 25 | + TYPE STATIC const & NAME() CONST \ | |
| 26 | +    { \ | |
| 27 | + return NAME##_; \ | |
| 28 | + } | |
| 29 | + | |
| 30 | +#define GLBASE_SET_(TYPE, NAME, STATIC, CONST) \ | |
| 31 | + template<typename Type> \ | |
| 32 | + TYPE STATIC NAME(Type && NAME) \ | |
| 33 | +    { \ | |
| 34 | + auto NAME##_old = std::move (NAME##_); \ | |
| 35 | + NAME##_ = std::forward(NAME); \ | |
| 36 | + return NAME##_old; \ | |
| 37 | + } | |
| 38 | + | |
| 39 | +#define GLBASE_GET( TYPE, NAME) GLBASE_GET_(TYPE, NAME,, const) | |
| 40 | +#define GLBASE_SET( TYPE, NAME) GLBASE_SET_(TYPE, NAME,, const) | |
| 41 | +#define GLBASE_GET_GLOBAL(TYPE, NAME) GLBASE_GET_(TYPE, NAME, static,) | |
| 42 | +#define GLBASE_SET_GLOBAL(TYPE, NAME) GLBASE_SET_(TYPE, NAME, static,) | |
| 43 | + | |
| 44 | +#define GLBASE_ACCESS(TYPE, NAME) \ | |
| 45 | + GLBASE_GET(TYPE, NAME) \ | |
| 46 | + GLBASE_SET(TYPE, NAME) | |
| 47 | + | |
| 48 | +#define GLBASE_ACCESS_GLOBAL(TYPE, NAME) \ | |
| 49 | + GLBASE_GET_GLOBAL(TYPE, NAME) \ | |
| 50 | + GLBASE_SET_GLOBAL(TYPE, NAME) | |
| 51 | + | |
| 52 | +#define GLBASE_GLOBAL(NAME, INIT) \ | |
| 53 | + decltype(NAME) thread_local NAME INIT; | |
| 54 | + | |
| 55 | + | |
| 56 | +/// GLBase | |
| 57 | + | |
| 58 | +class GLBase | |
| 59 | +{ | |
| 60 | + | |
| 61 | +public: | |
| 62 | + | |
| 63 | + //// Base | |
| 64 | + | |
| 65 | + using Version = std::array<GLint, 2>; | |
| 66 | + | |
| 67 | + GLBASE_ACCESS_GLOBAL(Version, version_max) | |
| 68 | + | |
| 69 | + bool static supported( | |
| 70 | + Version version_min, | |
| 71 | +        std::string const & extension = {} | |
| 72 | + ); | |
| 73 | + | |
| 74 | + char static const * string (GLenum name); | |
| 75 | + char static const * string (GLenum name, GLuint index); | |
| 76 | + GLint static integer(GLenum name); | |
| 77 | + | |
| 78 | + //// Path | |
| 79 | + | |
| 80 | + using Path = std::string; | |
| 81 | + using Paths = std::vector<Path>; | |
| 82 | + | |
| 83 | + //// Exceptions | |
| 84 | + | |
| 85 | + struct Exception : std::runtime_error | |
| 86 | +    { | |
| 87 | + using std::runtime_error::runtime_error; | |
| 88 | + }; | |
| 89 | + | |
| 90 | + //// Debug | |
| 91 | + | |
| 92 | + using DebugCallback = std::function<void (std::string const & message)>; | |
| 93 | + | |
| 94 | + GLBASE_GET_GLOBAL(int, debug) | |
| 95 | + int static debug(int debug); | |
| 96 | + | |
| 97 | + GLBASE_ACCESS_GLOBAL(DebugCallback, debug_callback) | |
| 98 | + | |
| 99 | + void static debug_message(std::string const & message) | |
| 100 | +    { | |
| 101 | + if (debug_callback()) | |
| 102 | + debug_callback()(message); | |
| 103 | + } | |
| 104 | + | |
| 105 | + //// Check | |
| 106 | + | |
| 107 | + void static check_supported( | |
| 108 | + Version version_min, | |
| 109 | +        std::string const & extension = {} | |
| 110 | + ); | |
| 111 | + | |
| 112 | +protected: | |
| 113 | + | |
| 114 | + //// Special member functions | |
| 115 | + | |
| 116 | + explicit GLBase() = default; | |
| 117 | + ~GLBase() = default; | |
| 118 | + | |
| 119 | + //// Path | |
| 120 | + | |
| 121 | + Path static path_prefix_( | |
| 122 | + Path const & path, | |
| 123 | + Path const & prefix | |
| 124 | + ); | |
| 125 | + | |
| 126 | + //// TGA | |
| 127 | + | |
| 128 | + class TGA_ | |
| 129 | +    { | |
| 130 | + public: | |
| 131 | + using Size = std::array<GLsizei, 2>; | |
| 132 | + using Data = std::vector<GLubyte>; | |
| 133 | +        explicit TGA_(Size size, Data data, Path const & path = {}); | |
| 134 | + TGA_ static read (Path const & path); | |
| 135 | + void write (Path const & path) const; | |
| 136 | + GLBASE_GET(Size, size); | |
| 137 | + GLBASE_GET(Data, data); | |
| 138 | + protected: | |
| 139 | + struct Header_ : std::array<GLubyte, 18> | |
| 140 | +        { | |
| 141 | + explicit Header_(Size size); | |
| 142 | + Size tga_size() const; | |
| 143 | + }; | |
| 144 | + std::string static name_(Path const & path); | |
| 145 | + void static check_header_(Header_ const & header); | |
| 146 | + void check_data_size_() const; | |
| 147 | + private: | |
| 148 | + Size size_; | |
| 149 | + Data data_; | |
| 150 | + }; | |
| 151 | + | |
| 152 | + //// Debug | |
| 153 | + | |
| 154 | + void static debug_action_( | |
| 155 | + std::string const & action, | |
| 156 | + std::string const & name | |
| 157 | + ); | |
| 158 | + | |
| 159 | + //// Check | |
| 160 | + | |
| 161 | + void static check_path_(Path const & path); | |
| 162 | + void static check_error_(GLenum error); | |
| 163 | + void static check_type_( | |
| 164 | + GLenum type, | |
| 165 | + GLenum type_expected | |
| 166 | + ); | |
| 167 | + void static check_format_( | |
| 168 | + GLenum format, | |
| 169 | + GLenum format_expected | |
| 170 | + ); | |
| 171 | + void static check_internal_format_( | |
| 172 | + GLenum internal_format | |
| 173 | + ); | |
| 174 | + | |
| 175 | + //// Fail | |
| 176 | + | |
| 177 | + [[noreturn]] | |
| 178 | + void static fail_action_( | |
| 179 | + std::string const & action, | |
| 180 | + std::string const & name | |
| 181 | + ); | |
| 182 | + | |
| 183 | + //// String | |
| 184 | + | |
| 185 | + std::string static str_path_ (Path const & path); | |
| 186 | + std::string static str_paths_ (Paths const & paths); | |
| 187 | + std::string static str_enum_ (GLenum name); | |
| 188 | + std::string static str_error_ (GLenum error); | |
| 189 | + std::string static str_object_type_ (GLenum object_type); | |
| 190 | + std::string static str_glsl_ (GLenum glsl); | |
| 191 | + std::string static str_format_ (GLenum format); | |
| 192 | + std::string static str_type_ (GLenum type); | |
| 193 | + std::string static str_internal_format_(GLenum internal_format); | |
| 194 | + | |
| 195 | +private: | |
| 196 | + | |
| 197 | + //// Base | |
| 198 | + | |
| 199 | + Version static thread_local version_max_; | |
| 200 | + | |
| 201 | + //// Debug | |
| 202 | + | |
| 203 | + int static thread_local debug_; | |
| 204 | + DebugCallback static thread_local debug_callback_; | |
| 205 | + | |
| 206 | +}; | |
| 207 | + | |
| 208 | + | |
| 209 | +/// Guards | |
| 210 | + | |
| 211 | +#endif | 
| 0 | 212 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,1034 @@ | 
| 1 | +/// Includes | |
| 2 | + | |
| 3 | + | |
| 4 | +#include <glbase.hpp> | |
| 5 | + | |
| 6 | +#include <algorithm> | |
| 7 | +#include <array> | |
| 8 | +#include <cstdio> | |
| 9 | +#include <fstream> | |
| 10 | +#include <iostream> | |
| 11 | +#include <iterator> | |
| 12 | +#include <sstream> | |
| 13 | +#include <string> | |
| 14 | +#include <unordered_set> | |
| 15 | + | |
| 16 | +#define STR_EXCEPTION GLBase::Exception | |
| 17 | +#include <str.hpp> | |
| 18 | + | |
| 19 | + | |
| 20 | +/// Base | |
| 21 | + | |
| 22 | + | |
| 23 | +GLBASE_GLOBAL(GLBase::version_max_, {}) | |
| 24 | + | |
| 25 | + | |
| 26 | +bool GLBase::supported( | |
| 27 | + Version version_min, | |
| 28 | + std::string const & extension | |
| 29 | +) | |
| 30 | +{ | |
| 31 | +    if (!extension.empty() && extension.rfind("GL_", 0) == std::string::npos) | |
| 32 | +        STR_THROW("Failed to parse extension \"" << extension << "\"."); | |
| 33 | +    auto static thread_local version    = Version{}; | |
| 34 | +    auto static thread_local extensions = std::unordered_set<std::string>{}; | |
| 35 | +    if (version == Version{}) | |
| 36 | +    { | |
| 37 | + auto const * version_str = string(GL_VERSION); | |
| 38 | + if (!version_str) | |
| 39 | + return false; | |
| 40 | + // NOLINTNEXTLINE | |
| 41 | + if (std::sscanf(version_str, "%d.%d", &version[0], &version[1]) != 2) | |
| 42 | +            STR_THROW("Failed to parse version \"" << version_str << "\"."); | |
| 43 | + if (version[0] >= 3) | |
| 44 | +        { | |
| 45 | + auto count = (GLuint)integer(GL_NUM_EXTENSIONS); | |
| 46 | +            for (auto index = GLuint{0}; index < count; ++index) | |
| 47 | +            { | |
| 48 | + auto const * extension_str = string(GL_EXTENSIONS, index); | |
| 49 | + if (extension_str) | |
| 50 | + extensions.insert(extension_str); | |
| 51 | + } | |
| 52 | + } | |
| 53 | + else | |
| 54 | +        { | |
| 55 | + auto const * extensions_str = string(GL_EXTENSIONS); | |
| 56 | + if (!extensions_str) | |
| 57 | + return false; | |
| 58 | + auto istream = std::istringstream(extensions_str); | |
| 59 | + using iterator = std::istream_iterator<std::string>; | |
| 60 | + std::copy( | |
| 61 | + iterator(istream), | |
| 62 | + iterator(), | |
| 63 | + std::inserter(extensions, extensions.end()) | |
| 64 | + ); | |
| 65 | + } | |
| 66 | + } | |
| 67 | +    if (version_max() != Version{}) | |
| 68 | + if | |
| 69 | + ( | |
| 70 | + version_min[0] > version_max()[0] || | |
| 71 | + ( | |
| 72 | + version_min[0] == version_max()[0] && | |
| 73 | + version_min[1] > version_max()[1] | |
| 74 | + ) | |
| 75 | + ) | |
| 76 | + return false; | |
| 77 | +    if (version_min != Version{}) | |
| 78 | + if | |
| 79 | + ( | |
| 80 | + version[0] > version_min[0] || | |
| 81 | + ( | |
| 82 | + version[0] == version_min[0] && | |
| 83 | + version[1] >= version_min[1] | |
| 84 | + ) | |
| 85 | + ) | |
| 86 | + return true; | |
| 87 | + if (!extension.empty()) | |
| 88 | + if (extensions.find(extension) != extensions.end()) | |
| 89 | + return true; | |
| 90 | + return false; | |
| 91 | +} | |
| 92 | + | |
| 93 | + | |
| 94 | +char const * GLBase::string(GLenum name) | |
| 95 | +try | |
| 96 | +{ | |
| 97 | + auto const * string = (char const *)glGetString(name); | |
| 98 | + check_error_(glGetError()); | |
| 99 | + return string; | |
| 100 | +} | |
| 101 | +catch (...) | |
| 102 | +{ | |
| 103 | +    fail_action_("get string", str_enum_(name)); | |
| 104 | +} | |
| 105 | + | |
| 106 | + | |
| 107 | +char const * GLBase::string(GLenum name, GLuint index) | |
| 108 | +try | |
| 109 | +{ | |
| 110 | + // if (debug() >= 1) | |
| 111 | +    //     check_supported({3, 0}); | |
| 112 | + auto const * string = (char const *)glGetStringi(name, index); | |
| 113 | + check_error_(glGetError()); | |
| 114 | + return string; | |
| 115 | +} | |
| 116 | +catch (...) | |
| 117 | +{ | |
| 118 | +    fail_action_("get string", STR(str_enum_(name) << "[" << index << "]")); | |
| 119 | +} | |
| 120 | + | |
| 121 | + | |
| 122 | +GLint GLBase::integer(GLenum name) | |
| 123 | +try | |
| 124 | +{ | |
| 125 | +    auto integer = GLint{}; | |
| 126 | + glGetIntegerv(name, &integer); | |
| 127 | + check_error_(glGetError()); | |
| 128 | + return integer; | |
| 129 | +} | |
| 130 | +catch (...) | |
| 131 | +{ | |
| 132 | +    fail_action_("get integer", str_enum_(name)); | |
| 133 | +} | |
| 134 | + | |
| 135 | + | |
| 136 | +/// Path | |
| 137 | + | |
| 138 | + | |
| 139 | +GLBase::Path GLBase::path_prefix_( | |
| 140 | + Path const & path, | |
| 141 | + Path const & prefix | |
| 142 | +) | |
| 143 | +{ | |
| 144 | + check_path_(path); | |
| 145 | + if (prefix.empty() || path[0] == '/') | |
| 146 | + return path; | |
| 147 | + return STR(prefix << "/" << path); | |
| 148 | +} | |
| 149 | + | |
| 150 | + | |
| 151 | +/// TGA | |
| 152 | + | |
| 153 | + | |
| 154 | +GLBase::TGA_::TGA_(Size size, Data data, Path const & path) | |
| 155 | +try | |
| 156 | +: | |
| 157 | +    size_{size}, | |
| 158 | +    data_{std::move(data)} | |
| 159 | +{ | |
| 160 | + check_data_size_(); | |
| 161 | +} | |
| 162 | +catch (...) | |
| 163 | +{ | |
| 164 | +    fail_action_("create", name_(path)); | |
| 165 | +} | |
| 166 | + | |
| 167 | + | |
| 168 | +GLBase::TGA_ GLBase::TGA_::read(Path const & path) | |
| 169 | +try | |
| 170 | +{ | |
| 171 | + auto istream = std::ifstream(path, std::ios::binary); | |
| 172 | +    auto header  = Header_({}); | |
| 173 | + istream.read((char *)header.data(), (std::streamsize)header.size()); | |
| 174 | + check_header_(header); | |
| 175 | + auto size = header.tga_size(); | |
| 176 | + auto data = Data(4 * (std::size_t)size[0] * (std::size_t)size[1]); | |
| 177 | + istream.read((char *)data.data(), (std::streamsize)data.size()); | |
| 178 | + if (!istream) | |
| 179 | + STR_THROW_ERRNO(); | |
| 180 | + if (!istream.eof()) | |
| 181 | +        STR_THROW("Garbage at end of file."); | |
| 182 | + return TGA_(size, std::move(data), path);; | |
| 183 | +} | |
| 184 | +catch (...) | |
| 185 | +{ | |
| 186 | +    fail_action_("read", name_(path)); | |
| 187 | +} | |
| 188 | + | |
| 189 | + | |
| 190 | +void GLBase::TGA_::write(Path const & path) const | |
| 191 | +try | |
| 192 | +{ | |
| 193 | + auto header = Header_(size()); | |
| 194 | + auto ostream = std::ofstream(path, std::ios::binary); | |
| 195 | + ostream.write((char *)header.data(), (std::streamsize)header.size()); | |
| 196 | + ostream.write((char *)data_ .data(), (std::streamsize)data_ .size()); | |
| 197 | + if (!ostream) | |
| 198 | + STR_THROW_ERRNO(); | |
| 199 | +} | |
| 200 | +catch (...) | |
| 201 | +{ | |
| 202 | +    fail_action_("write", name_(path)); | |
| 203 | +} | |
| 204 | + | |
| 205 | + | |
| 206 | +GLBase::TGA_::Header_::Header_(Size size) | |
| 207 | +: | |
| 208 | +    std::array<GLubyte, 18>{                // NOLINT | |
| 209 | + 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // NOLINT | |
| 210 | + (GLubyte)(size[0] >> 0), // NOLINT | |
| 211 | + (GLubyte)(size[0] >> 8), // NOLINT | |
| 212 | + (GLubyte)(size[1] >> 0), // NOLINT | |
| 213 | + (GLubyte)(size[1] >> 8), // NOLINT | |
| 214 | + 32, 0, // NOLINT | |
| 215 | + } | |
| 216 | +{ | |
| 217 | +} | |
| 218 | + | |
| 219 | + | |
| 220 | +GLBase::TGA_::Size GLBase::TGA_::Header_::tga_size() const | |
| 221 | +{ | |
| 222 | +    return { | |
| 223 | + (GLsizei)((*this)[12]) << 0 | // NOLINT | |
| 224 | + (GLsizei)((*this)[13]) << 8, // NOLINT | |
| 225 | + (GLsizei)((*this)[14]) << 0 | // NOLINT | |
| 226 | + (GLsizei)((*this)[15]) << 8, // NOLINT | |
| 227 | + }; | |
| 228 | +} | |
| 229 | + | |
| 230 | + | |
| 231 | +std::string GLBase::TGA_::name_(Path const & path) | |
| 232 | +{ | |
| 233 | +    return STR("TGA" << " " << str_path_(path)); | |
| 234 | +} | |
| 235 | + | |
| 236 | + | |
| 237 | +void GLBase::TGA_::check_header_(Header_ const & header) | |
| 238 | +{ | |
| 239 | + auto header_ = Header_(header.tga_size()); | |
| 240 | + if (header != header_) | |
| 241 | + STR_THROW( | |
| 242 | + "Expected TGA header" << " " << | |
| 243 | +            "[" << STR_JOIN(", ", byte, byte, header_) << "]" << ", " << | |
| 244 | + "got" << " " << | |
| 245 | +            "[" << STR_JOIN(", ", byte, byte, header)  << "]" << "." | |
| 246 | + ); | |
| 247 | +} | |
| 248 | + | |
| 249 | + | |
| 250 | +void GLBase::TGA_::check_data_size_() const | |
| 251 | +{ | |
| 252 | + auto size = this->size(); | |
| 253 | + auto data_size = (std::size_t)(4 * size[0] * size[1]); | |
| 254 | + if (data_size != data_.size()) | |
| 255 | + STR_THROW( | |
| 256 | + "Expected TGA data size " << data_size << ", " << | |
| 257 | + "got " << data_.size() << "." | |
| 258 | + ); | |
| 259 | +} | |
| 260 | + | |
| 261 | + | |
| 262 | +//// Debug | |
| 263 | + | |
| 264 | + | |
| 265 | +GLBASE_GLOBAL(GLBase::debug_,          {0}) | |
| 266 | +GLBASE_GLOBAL(GLBase::debug_callback_, {[](std::string const & message) { | |
| 267 | + std::cerr << message << std::endl; | |
| 268 | +}}) | |
| 269 | + | |
| 270 | + | |
| 271 | +int GLBase::debug(int debug) | |
| 272 | +{ | |
| 273 | + auto debug_old = debug_; | |
| 274 | + debug_ = debug; | |
| 275 | +    if (supported({4, 3}, "GL_KHR_debug")) | |
| 276 | +    { | |
| 277 | + if (debug_old && !debug) | |
| 278 | + glDisable(GL_DEBUG_OUTPUT); | |
| 279 | + if (!debug_old && debug) | |
| 280 | +        { | |
| 281 | + glEnable(GL_DEBUG_OUTPUT); | |
| 282 | + glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); | |
| 283 | + glDebugMessageControl( | |
| 284 | + GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, | |
| 285 | + 0, nullptr, | |
| 286 | + GL_TRUE | |
| 287 | + ); | |
| 288 | + } | |
| 289 | + if (debug_old >= 2 && debug < 2) | |
| 290 | + glDebugMessageControl( | |
| 291 | + GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, | |
| 292 | + 0, nullptr, | |
| 293 | + GL_FALSE | |
| 294 | + ); | |
| 295 | + if (debug_old < 2 && debug >= 2) | |
| 296 | + glDebugMessageControl( | |
| 297 | + GL_DONT_CARE, GL_DONT_CARE, GL_DEBUG_SEVERITY_NOTIFICATION, | |
| 298 | + 0, nullptr, | |
| 299 | + GL_TRUE | |
| 300 | + ); | |
| 301 | + } | |
| 302 | + return debug_old; | |
| 303 | +} | |
| 304 | + | |
| 305 | + | |
| 306 | +void GLBase::debug_action_( | |
| 307 | + std::string const & action, | |
| 308 | + std::string const & name | |
| 309 | +) | |
| 310 | +{ | |
| 311 | +    debug_message(STR("Trying to " << action << " " << name << ".")); | |
| 312 | +} | |
| 313 | + | |
| 314 | + | |
| 315 | +/// Check | |
| 316 | + | |
| 317 | + | |
| 318 | +void GLBase::check_path_(Path const & path) | |
| 319 | +{ | |
| 320 | + if (path.empty()) | |
| 321 | + STR_THROW( | |
| 322 | + "Expected " << "non-empty path" << ", " << | |
| 323 | + "got " << str_path_(path) << "." | |
| 324 | + ); | |
| 325 | +} | |
| 326 | + | |
| 327 | + | |
| 328 | +void GLBase::check_error_(GLenum error) | |
| 329 | +{ | |
| 330 | + if (error != GL_NO_ERROR) | |
| 331 | + STR_THROW( | |
| 332 | + "Expected " << "no error" << ", " << | |
| 333 | + "got " << str_error_(error) << "." | |
| 334 | + ); | |
| 335 | +} | |
| 336 | + | |
| 337 | + | |
| 338 | +void GLBase::check_supported( | |
| 339 | + Version version_min, | |
| 340 | + std::string const & extension | |
| 341 | +) | |
| 342 | +{ | |
| 343 | + if (!supported(version_min, extension)) | |
| 344 | +    { | |
| 345 | + auto const * version_str = string(GL_VERSION); | |
| 346 | + STR_THROW( | |
| 347 | + "Expected OpenGL version >=" << | |
| 348 | +                STR_JOIN(".", it, it, version_min) << | |
| 349 | + ( | |
| 350 | + !extension.empty() | |
| 351 | +                        ? STR(" or extension " << extension) | |
| 352 | + : "" | |
| 353 | + ) << | |
| 354 | + ", " << | |
| 355 | + "got " << | |
| 356 | + ( | |
| 357 | + version_str | |
| 358 | + ? version_str | |
| 359 | + : "none (no current context?)" | |
| 360 | + ) << | |
| 361 | + "." | |
| 362 | + ); | |
| 363 | + } | |
| 364 | +} | |
| 365 | + | |
| 366 | + | |
| 367 | +void GLBase::check_type_( | |
| 368 | + GLenum type, | |
| 369 | + GLenum type_expected | |
| 370 | +) | |
| 371 | +{ | |
| 372 | + if (type != type_expected) | |
| 373 | + STR_THROW( | |
| 374 | + "Expected type " << str_type_(type_expected) << ", " << | |
| 375 | + "got " << str_type_(type) << "." | |
| 376 | + ); | |
| 377 | +} | |
| 378 | + | |
| 379 | + | |
| 380 | +void GLBase::check_format_( | |
| 381 | + GLenum format, | |
| 382 | + GLenum format_expected | |
| 383 | +) | |
| 384 | +{ | |
| 385 | + if (format != format_expected) | |
| 386 | + STR_THROW( | |
| 387 | + "Expected format " << str_format_(format_expected) << ", " << | |
| 388 | + "got " << str_format_(format) << "." | |
| 389 | + ); | |
| 390 | +} | |
| 391 | + | |
| 392 | + | |
| 393 | +void GLBase::check_internal_format_(GLenum internal_format) | |
| 394 | +{ | |
| 395 | + switch (internal_format) | |
| 396 | +    { | |
| 397 | + case GL_RED: | |
| 398 | + case GL_RGB: | |
| 399 | + case GL_RGBA: | |
| 400 | + case GL_DEPTH_COMPONENT: | |
| 401 | + case GL_STENCIL_INDEX: | |
| 402 | +            check_supported({1, 0}); | |
| 403 | + return; | |
| 404 | + case GL_R3_G3_B2: | |
| 405 | +            check_supported({1, 1}); | |
| 406 | + return; | |
| 407 | + case GL_RGB4: | |
| 408 | + case GL_RGB5: | |
| 409 | + case GL_RGB8: | |
| 410 | + case GL_RGB10: | |
| 411 | + case GL_RGB12: | |
| 412 | + case GL_RGB16: | |
| 413 | + case GL_RGB5_A1: | |
| 414 | + case GL_RGB10_A2: | |
| 415 | + case GL_RGBA2: | |
| 416 | + case GL_RGBA4: | |
| 417 | + case GL_RGBA8: | |
| 418 | + case GL_RGBA12: | |
| 419 | + case GL_RGBA16: | |
| 420 | +            check_supported({1, 1}, "GL_EXT_texture"); | |
| 421 | + return; | |
| 422 | + case GL_RGB2_EXT: | |
| 423 | +            check_supported({}, "GL_EXT_texture"); | |
| 424 | + return; | |
| 425 | + case GL_COMPRESSED_RGB: | |
| 426 | + case GL_COMPRESSED_RGBA: | |
| 427 | +            check_supported({1, 3}, "GL_ARB_texture_compression"); | |
| 428 | + return; | |
| 429 | + case GL_DEPTH_COMPONENT16: | |
| 430 | + case GL_DEPTH_COMPONENT24: | |
| 431 | + case GL_DEPTH_COMPONENT32: | |
| 432 | +            check_supported({1, 4}, "GL_ARB_depth_texture"); | |
| 433 | + return; | |
| 434 | + case GL_SRGB: | |
| 435 | + case GL_SRGB8: | |
| 436 | + case GL_SRGB_ALPHA: | |
| 437 | + case GL_SRGB8_ALPHA8: | |
| 438 | + case GL_COMPRESSED_SRGB: | |
| 439 | + case GL_COMPRESSED_SRGB_ALPHA: | |
| 440 | +            check_supported({2, 1}, "GL_EXT_texture_sRGB"); | |
| 441 | + return; | |
| 442 | + case GL_SR8_EXT: | |
| 443 | +            check_supported({}, "GL_EXT_texture_sRGB_R8"); | |
| 444 | + return; | |
| 445 | + case GL_SRG8_EXT: | |
| 446 | +            check_supported({}, "GL_EXT_texture_sRGB_RG8"); | |
| 447 | + return; | |
| 448 | + case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: | |
| 449 | + case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: | |
| 450 | + case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: | |
| 451 | + case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: | |
| 452 | +            check_supported({}, "GL_EXT_texture_compression_s3tc"); | |
| 453 | + return; | |
| 454 | + case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: | |
| 455 | + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: | |
| 456 | + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: | |
| 457 | + case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: | |
| 458 | +            check_supported({}, "GL_EXT_texture_sRGB"); | |
| 459 | +            check_supported({}, "GL_EXT_texture_compression_s3tc"); | |
| 460 | + return; | |
| 461 | + case GL_COMPRESSED_RED: | |
| 462 | + case GL_COMPRESSED_RG: | |
| 463 | +            check_supported({3, 0}); | |
| 464 | + return; | |
| 465 | + case GL_COMPRESSED_RED_RGTC1: | |
| 466 | + case GL_COMPRESSED_RG_RGTC2: | |
| 467 | + case GL_COMPRESSED_SIGNED_RED_RGTC1: | |
| 468 | + case GL_COMPRESSED_SIGNED_RG_RGTC2: | |
| 469 | +            check_supported({3, 0}, "GL_ARB_texture_compression_rgtc"); | |
| 470 | + return; | |
| 471 | + case GL_RGB16F: | |
| 472 | + case GL_RGB32F: | |
| 473 | + case GL_RGBA16F: | |
| 474 | + case GL_RGBA32F: | |
| 475 | +            check_supported({3, 0}, "GL_ARB_texture_float"); | |
| 476 | + return; | |
| 477 | + case GL_RGB8I: | |
| 478 | + case GL_RGB8UI: | |
| 479 | + case GL_RGB16I: | |
| 480 | + case GL_RGB16UI: | |
| 481 | + case GL_RGB32I: | |
| 482 | + case GL_RGB32UI: | |
| 483 | + case GL_RGBA8I: | |
| 484 | + case GL_RGBA8UI: | |
| 485 | + case GL_RGBA16I: | |
| 486 | + case GL_RGBA16UI: | |
| 487 | + case GL_RGBA32I: | |
| 488 | + case GL_RGBA32UI: | |
| 489 | +            check_supported({3, 0}, "GL_EXT_texture_integer"); | |
| 490 | + return; | |
| 491 | + case GL_R8: | |
| 492 | + case GL_R8I: | |
| 493 | + case GL_R8UI: | |
| 494 | + case GL_R16: | |
| 495 | + case GL_R16I: | |
| 496 | + case GL_R16UI: | |
| 497 | + case GL_R32I: | |
| 498 | + case GL_R32UI: | |
| 499 | + case GL_R16F: | |
| 500 | + case GL_R32F: | |
| 501 | + case GL_RG: | |
| 502 | + case GL_RG8: | |
| 503 | + case GL_RG8I: | |
| 504 | + case GL_RG8UI: | |
| 505 | + case GL_RG16: | |
| 506 | + case GL_RG16I: | |
| 507 | + case GL_RG16UI: | |
| 508 | + case GL_RG32I: | |
| 509 | + case GL_RG32UI: | |
| 510 | + case GL_RG16F: | |
| 511 | + case GL_RG32F: | |
| 512 | +            check_supported({3, 0}, "GL_ARB_texture_rg"); | |
| 513 | + return; | |
| 514 | + case GL_R11F_G11F_B10F: | |
| 515 | +            check_supported({3, 0}, "GL_EXT_packed_float"); | |
| 516 | + return; | |
| 517 | + case GL_RGB9_E5: | |
| 518 | +            check_supported({3, 0}, "GL_EXT_texture_shared_exponent"); | |
| 519 | + return; | |
| 520 | + case GL_DEPTH_STENCIL: | |
| 521 | + case GL_DEPTH24_STENCIL8: | |
| 522 | +            check_supported({3, 0}, "GL_EXT_packed_depth_stencil"); | |
| 523 | + return; | |
| 524 | + case GL_DEPTH32F_STENCIL8: | |
| 525 | + case GL_DEPTH_COMPONENT32F: | |
| 526 | +            check_supported({3, 0}, "GL_ARB_depth_buffer_float"); | |
| 527 | + return; | |
| 528 | + case GL_STENCIL_INDEX1: | |
| 529 | + case GL_STENCIL_INDEX4: | |
| 530 | + case GL_STENCIL_INDEX8: | |
| 531 | + case GL_STENCIL_INDEX16: | |
| 532 | +            check_supported({3, 0}, "GL_ARB_framebuffer_object"); | |
| 533 | + return; | |
| 534 | + case GL_R8_SNORM: | |
| 535 | + case GL_R16_SNORM: | |
| 536 | + case GL_RG8_SNORM: | |
| 537 | + case GL_RG16_SNORM: | |
| 538 | + case GL_RGB8_SNORM: | |
| 539 | + case GL_RGB16_SNORM: | |
| 540 | + case GL_RGBA8_SNORM: | |
| 541 | + case GL_RGBA16_SNORM: | |
| 542 | +            check_supported({3, 1}, "GL_EXT_texture_snorm"); | |
| 543 | + return; | |
| 544 | + case GL_RGB10_A2UI: | |
| 545 | +            check_supported({3, 3}, "GL_ARB_texture_rgb10_a2ui"); | |
| 546 | + return; | |
| 547 | + case GL_RGB565: | |
| 548 | +            check_supported({4, 1}, "GL_ARB_ES2_compatibility"); | |
| 549 | + return; | |
| 550 | + case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: | |
| 551 | + case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: | |
| 552 | + case GL_COMPRESSED_RGBA_BPTC_UNORM: | |
| 553 | + case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: | |
| 554 | +            check_supported({4, 2}, "GL_ARB_texture_compression_bptc"); | |
| 555 | + return; | |
| 556 | + case GL_COMPRESSED_RGB8_ETC2: | |
| 557 | + case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| 558 | + case GL_COMPRESSED_SRGB8_ETC2: | |
| 559 | + case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: | |
| 560 | + case GL_COMPRESSED_RGBA8_ETC2_EAC: | |
| 561 | + case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: | |
| 562 | + case GL_COMPRESSED_R11_EAC: | |
| 563 | + case GL_COMPRESSED_RG11_EAC: | |
| 564 | + case GL_COMPRESSED_SIGNED_R11_EAC: | |
| 565 | + case GL_COMPRESSED_SIGNED_RG11_EAC: | |
| 566 | +            check_supported({4, 3}, "GL_ARB_ES3_compatibility"); | |
| 567 | + return; | |
| 568 | + case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: | |
| 569 | + case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: | |
| 570 | + case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: | |
| 571 | + case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: | |
| 572 | + case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: | |
| 573 | + case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: | |
| 574 | + case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: | |
| 575 | + case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: | |
| 576 | + case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: | |
| 577 | + case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: | |
| 578 | + case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: | |
| 579 | + case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: | |
| 580 | + case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: | |
| 581 | + case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: | |
| 582 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: | |
| 583 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: | |
| 584 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: | |
| 585 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: | |
| 586 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: | |
| 587 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: | |
| 588 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: | |
| 589 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: | |
| 590 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: | |
| 591 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: | |
| 592 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: | |
| 593 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: | |
| 594 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: | |
| 595 | + case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: | |
| 596 | +            check_supported({}, "GL_KHR_texture_compression_astc_ldr"); | |
| 597 | + return; | |
| 598 | + default: | |
| 599 | + STR_THROW( | |
| 600 | + "Expected " << "internal format" << ", " << | |
| 601 | + "got " << str_internal_format_(internal_format) << "." | |
| 602 | + ); | |
| 603 | + } | |
| 604 | +} | |
| 605 | + | |
| 606 | + | |
| 607 | +/// Fail | |
| 608 | + | |
| 609 | + | |
| 610 | +void GLBase::fail_action_( | |
| 611 | + std::string const & action, | |
| 612 | + std::string const & name | |
| 613 | +) | |
| 614 | +{ | |
| 615 | +    STR_RETHROW("Failed to " << action << " " << name << ":\n"); | |
| 616 | +} | |
| 617 | + | |
| 618 | + | |
| 619 | +/// String | |
| 620 | + | |
| 621 | + | |
| 622 | +std::string GLBase::str_path_(Path const & path) | |
| 623 | +{ | |
| 624 | +    return STR("\"" << path << "\""); | |
| 625 | +} | |
| 626 | + | |
| 627 | + | |
| 628 | +std::string GLBase::str_paths_(Paths const & paths) | |
| 629 | +{ | |
| 630 | +    return STR_JOIN(", ", path, str_path_(path), paths); | |
| 631 | +} | |
| 632 | + | |
| 633 | + | |
| 634 | +std::string GLBase::str_enum_(GLenum name) | |
| 635 | +{ | |
| 636 | + return STR(std::hex << std::showbase << std::uppercase << name); | |
| 637 | +} | |
| 638 | + | |
| 639 | + | |
| 640 | +std::string GLBase::str_error_(GLenum error) | |
| 641 | +{ | |
| 642 | + switch (error) | |
| 643 | +    { | |
| 644 | + STR_CASE(GL_NO_ERROR) | |
| 645 | + STR_CASE(GL_INVALID_ENUM) | |
| 646 | + STR_CASE(GL_INVALID_VALUE) | |
| 647 | + STR_CASE(GL_INVALID_OPERATION) | |
| 648 | + STR_CASE(GL_INVALID_FRAMEBUFFER_OPERATION) | |
| 649 | + STR_CASE(GL_OUT_OF_MEMORY) | |
| 650 | + STR_CASE(GL_STACK_OVERFLOW) | |
| 651 | + STR_CASE(GL_STACK_UNDERFLOW) | |
| 652 | + STR_CASE(GL_CONTEXT_LOST) // GL_KHR_robustness | |
| 653 | + default: | |
| 654 | + return str_enum_(error); | |
| 655 | + } | |
| 656 | +} | |
| 657 | + | |
| 658 | + | |
| 659 | +std::string GLBase::str_object_type_(GLenum object_type) | |
| 660 | +{ | |
| 661 | + switch (object_type) | |
| 662 | +    { | |
| 663 | + STR_CASE(GL_TEXTURE) | |
| 664 | + STR_CASE(GL_BUFFER) | |
| 665 | + STR_CASE(GL_SHADER) | |
| 666 | + STR_CASE(GL_PROGRAM) | |
| 667 | + STR_CASE(GL_PROGRAM_PIPELINE) | |
| 668 | + STR_CASE(GL_FRAMEBUFFER) | |
| 669 | + STR_CASE(GL_RENDERBUFFER) | |
| 670 | + STR_CASE(GL_VERTEX_ARRAY) | |
| 671 | + STR_CASE(GL_TRANSFORM_FEEDBACK) | |
| 672 | + STR_CASE(GL_SAMPLER) | |
| 673 | + STR_CASE(GL_QUERY) | |
| 674 | + default: | |
| 675 | + return str_enum_(object_type); | |
| 676 | + } | |
| 677 | +} | |
| 678 | + | |
| 679 | + | |
| 680 | +std::string GLBase::str_glsl_(GLenum glsl) | |
| 681 | +{ | |
| 682 | + switch (glsl) | |
| 683 | +    { | |
| 684 | + STR_CASE(GL_FLOAT) | |
| 685 | + STR_CASE(GL_FLOAT_VEC2) | |
| 686 | + STR_CASE(GL_FLOAT_VEC3) | |
| 687 | + STR_CASE(GL_FLOAT_VEC4) | |
| 688 | + STR_CASE(GL_FLOAT_MAT2) | |
| 689 | + STR_CASE(GL_FLOAT_MAT2x3) | |
| 690 | + STR_CASE(GL_FLOAT_MAT2x4) | |
| 691 | + STR_CASE(GL_FLOAT_MAT3x2) | |
| 692 | + STR_CASE(GL_FLOAT_MAT3) | |
| 693 | + STR_CASE(GL_FLOAT_MAT3x4) | |
| 694 | + STR_CASE(GL_FLOAT_MAT4x2) | |
| 695 | + STR_CASE(GL_FLOAT_MAT4x3) | |
| 696 | + STR_CASE(GL_FLOAT_MAT4) | |
| 697 | + STR_CASE(GL_INT) | |
| 698 | + STR_CASE(GL_INT_VEC2) | |
| 699 | + STR_CASE(GL_INT_VEC3) | |
| 700 | + STR_CASE(GL_INT_VEC4) | |
| 701 | + STR_CASE(GL_UNSIGNED_INT) | |
| 702 | + STR_CASE(GL_UNSIGNED_INT_VEC2) | |
| 703 | + STR_CASE(GL_UNSIGNED_INT_VEC3) | |
| 704 | + STR_CASE(GL_UNSIGNED_INT_VEC4) | |
| 705 | + STR_CASE(GL_DOUBLE) | |
| 706 | + STR_CASE(GL_DOUBLE_VEC2) | |
| 707 | + STR_CASE(GL_DOUBLE_VEC3) | |
| 708 | + STR_CASE(GL_DOUBLE_VEC4) | |
| 709 | + STR_CASE(GL_DOUBLE_MAT2) | |
| 710 | + STR_CASE(GL_DOUBLE_MAT2x3) | |
| 711 | + STR_CASE(GL_DOUBLE_MAT2x4) | |
| 712 | + STR_CASE(GL_DOUBLE_MAT3x2) | |
| 713 | + STR_CASE(GL_DOUBLE_MAT3) | |
| 714 | + STR_CASE(GL_DOUBLE_MAT3x4) | |
| 715 | + STR_CASE(GL_DOUBLE_MAT4x2) | |
| 716 | + STR_CASE(GL_DOUBLE_MAT4x3) | |
| 717 | + STR_CASE(GL_DOUBLE_MAT4) | |
| 718 | + STR_CASE(GL_BOOL) | |
| 719 | + STR_CASE(GL_BOOL_VEC2) | |
| 720 | + STR_CASE(GL_BOOL_VEC3) | |
| 721 | + STR_CASE(GL_BOOL_VEC4) | |
| 722 | + STR_CASE(GL_SAMPLER_1D) | |
| 723 | + STR_CASE(GL_SAMPLER_1D_SHADOW) | |
| 724 | + STR_CASE(GL_SAMPLER_1D_ARRAY) | |
| 725 | + STR_CASE(GL_SAMPLER_1D_ARRAY_SHADOW) | |
| 726 | + STR_CASE(GL_SAMPLER_2D) | |
| 727 | + STR_CASE(GL_SAMPLER_2D_SHADOW) | |
| 728 | + STR_CASE(GL_SAMPLER_2D_ARRAY) | |
| 729 | + STR_CASE(GL_SAMPLER_2D_ARRAY_SHADOW) | |
| 730 | + STR_CASE(GL_SAMPLER_2D_RECT) | |
| 731 | + STR_CASE(GL_SAMPLER_2D_RECT_SHADOW) | |
| 732 | + STR_CASE(GL_SAMPLER_2D_MULTISAMPLE) | |
| 733 | + STR_CASE(GL_SAMPLER_2D_MULTISAMPLE_ARRAY) | |
| 734 | + STR_CASE(GL_SAMPLER_3D) | |
| 735 | + STR_CASE(GL_SAMPLER_CUBE) | |
| 736 | + STR_CASE(GL_SAMPLER_CUBE_SHADOW) | |
| 737 | + STR_CASE(GL_SAMPLER_CUBE_MAP_ARRAY) | |
| 738 | + STR_CASE(GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW) | |
| 739 | + STR_CASE(GL_SAMPLER_BUFFER) | |
| 740 | + STR_CASE(GL_INT_SAMPLER_1D) | |
| 741 | + STR_CASE(GL_INT_SAMPLER_1D_ARRAY) | |
| 742 | + STR_CASE(GL_INT_SAMPLER_2D) | |
| 743 | + STR_CASE(GL_INT_SAMPLER_2D_ARRAY) | |
| 744 | + STR_CASE(GL_INT_SAMPLER_2D_RECT) | |
| 745 | + STR_CASE(GL_INT_SAMPLER_2D_MULTISAMPLE) | |
| 746 | + STR_CASE(GL_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) | |
| 747 | + STR_CASE(GL_INT_SAMPLER_3D) | |
| 748 | + STR_CASE(GL_INT_SAMPLER_CUBE) | |
| 749 | + STR_CASE(GL_INT_SAMPLER_CUBE_MAP_ARRAY) | |
| 750 | + STR_CASE(GL_INT_SAMPLER_BUFFER) | |
| 751 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_1D) | |
| 752 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_1D_ARRAY) | |
| 753 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_2D) | |
| 754 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_2D_ARRAY) | |
| 755 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_2D_RECT) | |
| 756 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE) | |
| 757 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_2D_MULTISAMPLE_ARRAY) | |
| 758 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_3D) | |
| 759 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_CUBE) | |
| 760 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY) | |
| 761 | + STR_CASE(GL_UNSIGNED_INT_SAMPLER_BUFFER) | |
| 762 | + STR_CASE(GL_IMAGE_1D) | |
| 763 | + STR_CASE(GL_IMAGE_1D_ARRAY) | |
| 764 | + STR_CASE(GL_IMAGE_2D) | |
| 765 | + STR_CASE(GL_IMAGE_2D_ARRAY) | |
| 766 | + STR_CASE(GL_IMAGE_2D_RECT) | |
| 767 | + STR_CASE(GL_IMAGE_2D_MULTISAMPLE) | |
| 768 | + STR_CASE(GL_IMAGE_2D_MULTISAMPLE_ARRAY) | |
| 769 | + STR_CASE(GL_IMAGE_3D) | |
| 770 | + STR_CASE(GL_IMAGE_CUBE) | |
| 771 | + STR_CASE(GL_IMAGE_CUBE_MAP_ARRAY) | |
| 772 | + STR_CASE(GL_IMAGE_BUFFER) | |
| 773 | + STR_CASE(GL_INT_IMAGE_1D) | |
| 774 | + STR_CASE(GL_INT_IMAGE_1D_ARRAY) | |
| 775 | + STR_CASE(GL_INT_IMAGE_2D) | |
| 776 | + STR_CASE(GL_INT_IMAGE_2D_ARRAY) | |
| 777 | + STR_CASE(GL_INT_IMAGE_2D_RECT) | |
| 778 | + STR_CASE(GL_INT_IMAGE_2D_MULTISAMPLE) | |
| 779 | + STR_CASE(GL_INT_IMAGE_2D_MULTISAMPLE_ARRAY) | |
| 780 | + STR_CASE(GL_INT_IMAGE_3D) | |
| 781 | + STR_CASE(GL_INT_IMAGE_CUBE) | |
| 782 | + STR_CASE(GL_INT_IMAGE_CUBE_MAP_ARRAY) | |
| 783 | + STR_CASE(GL_INT_IMAGE_BUFFER) | |
| 784 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_1D) | |
| 785 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_1D_ARRAY) | |
| 786 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_2D) | |
| 787 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_2D_ARRAY) | |
| 788 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_2D_RECT) | |
| 789 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE) | |
| 790 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_2D_MULTISAMPLE_ARRAY) | |
| 791 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_3D) | |
| 792 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_CUBE) | |
| 793 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY) | |
| 794 | + STR_CASE(GL_UNSIGNED_INT_IMAGE_BUFFER) | |
| 795 | + // GL_ARB_gpu_shader_int64 | |
| 796 | + STR_CASE(GL_INT64_ARB) | |
| 797 | + STR_CASE(GL_INT64_VEC2_ARB) | |
| 798 | + STR_CASE(GL_INT64_VEC3_ARB) | |
| 799 | + STR_CASE(GL_INT64_VEC4_ARB) | |
| 800 | + STR_CASE(GL_UNSIGNED_INT64_ARB) // GL_ARB_bindless_texture | |
| 801 | + STR_CASE(GL_UNSIGNED_INT64_VEC2_ARB) | |
| 802 | + STR_CASE(GL_UNSIGNED_INT64_VEC3_ARB) | |
| 803 | + STR_CASE(GL_UNSIGNED_INT64_VEC4_ARB) | |
| 804 | + default: | |
| 805 | + return str_enum_(glsl); | |
| 806 | + } | |
| 807 | +} | |
| 808 | + | |
| 809 | + | |
| 810 | +std::string GLBase::str_format_(GLenum format) | |
| 811 | +{ | |
| 812 | + switch (format) | |
| 813 | +    { | |
| 814 | + STR_CASE(GL_RED) | |
| 815 | + STR_CASE(GL_RED_INTEGER) | |
| 816 | + STR_CASE(GL_GREEN) | |
| 817 | + STR_CASE(GL_GREEN_INTEGER) | |
| 818 | + STR_CASE(GL_BLUE) | |
| 819 | + STR_CASE(GL_BLUE_INTEGER) | |
| 820 | + STR_CASE(GL_ALPHA) | |
| 821 | + STR_CASE(GL_ALPHA_INTEGER) | |
| 822 | + STR_CASE(GL_RG) | |
| 823 | + STR_CASE(GL_RG_INTEGER) | |
| 824 | + STR_CASE(GL_RGB) | |
| 825 | + STR_CASE(GL_RGB_INTEGER) | |
| 826 | + STR_CASE(GL_RGBA) | |
| 827 | + STR_CASE(GL_RGBA_INTEGER) | |
| 828 | + STR_CASE(GL_BGR) | |
| 829 | + STR_CASE(GL_BGR_INTEGER) | |
| 830 | + STR_CASE(GL_BGRA) | |
| 831 | + STR_CASE(GL_BGRA_INTEGER) | |
| 832 | + STR_CASE(GL_ABGR_EXT) // GL_EXT_abgr | |
| 833 | + STR_CASE(GL_DEPTH_STENCIL) | |
| 834 | + STR_CASE(GL_DEPTH_COMPONENT) | |
| 835 | + STR_CASE(GL_STENCIL_INDEX) | |
| 836 | + default: | |
| 837 | + return str_enum_(format); | |
| 838 | + } | |
| 839 | +} | |
| 840 | + | |
| 841 | + | |
| 842 | +std::string GLBase::str_type_(GLenum type) | |
| 843 | +{ | |
| 844 | + switch (type) | |
| 845 | +    { | |
| 846 | + STR_CASE(GL_FLOAT) | |
| 847 | + STR_CASE(GL_BYTE) | |
| 848 | + STR_CASE(GL_SHORT) | |
| 849 | + STR_CASE(GL_INT) | |
| 850 | + STR_CASE(GL_UNSIGNED_BYTE) | |
| 851 | + STR_CASE(GL_UNSIGNED_SHORT) | |
| 852 | + STR_CASE(GL_UNSIGNED_INT) | |
| 853 | + STR_CASE(GL_UNSIGNED_BYTE_3_3_2) | |
| 854 | + STR_CASE(GL_UNSIGNED_BYTE_2_3_3_REV) | |
| 855 | + STR_CASE(GL_UNSIGNED_SHORT_5_6_5) | |
| 856 | + STR_CASE(GL_UNSIGNED_SHORT_5_6_5_REV) | |
| 857 | + STR_CASE(GL_UNSIGNED_SHORT_4_4_4_4) | |
| 858 | + STR_CASE(GL_UNSIGNED_SHORT_4_4_4_4_REV) | |
| 859 | + STR_CASE(GL_UNSIGNED_SHORT_5_5_5_1) | |
| 860 | + STR_CASE(GL_UNSIGNED_SHORT_1_5_5_5_REV) | |
| 861 | + STR_CASE(GL_UNSIGNED_INT_8_8_8_8) | |
| 862 | + STR_CASE(GL_UNSIGNED_INT_8_8_8_8_REV) | |
| 863 | + STR_CASE(GL_UNSIGNED_INT_10_10_10_2) | |
| 864 | + STR_CASE(GL_UNSIGNED_INT_2_10_10_10_REV) | |
| 865 | + STR_CASE(GL_UNSIGNED_INT_10F_11F_11F_REV) | |
| 866 | + STR_CASE(GL_UNSIGNED_INT_5_9_9_9_REV) | |
| 867 | + STR_CASE(GL_UNSIGNED_INT_24_8) | |
| 868 | + STR_CASE(GL_FLOAT_32_UNSIGNED_INT_24_8_REV) | |
| 869 | + STR_CASE(GL_DOUBLE) | |
| 870 | + STR_CASE(GL_HALF_FLOAT) | |
| 871 | + STR_CASE(GL_FIXED) | |
| 872 | + // GL_ARB_gpu_shader_int64 | |
| 873 | + STR_CASE(GL_INT64_ARB) | |
| 874 | + STR_CASE(GL_UNSIGNED_INT64_ARB) // GL_ARB_bindless_texture | |
| 875 | + default: | |
| 876 | + return str_enum_(type); | |
| 877 | + } | |
| 878 | +} | |
| 879 | + | |
| 880 | + | |
| 881 | +std::string GLBase::str_internal_format_(GLenum internal_format) | |
| 882 | +{ | |
| 883 | + switch (internal_format) | |
| 884 | +    { | |
| 885 | + STR_CASE(GL_RED) | |
| 886 | + STR_CASE(GL_R8) | |
| 887 | + STR_CASE(GL_R8I) | |
| 888 | + STR_CASE(GL_R8UI) | |
| 889 | + STR_CASE(GL_R16) | |
| 890 | + STR_CASE(GL_R16I) | |
| 891 | + STR_CASE(GL_R16UI) | |
| 892 | + STR_CASE(GL_R32I) | |
| 893 | + STR_CASE(GL_R32UI) | |
| 894 | + STR_CASE(GL_R16F) | |
| 895 | + STR_CASE(GL_R32F) | |
| 896 | + STR_CASE(GL_RG) | |
| 897 | + STR_CASE(GL_RG8) | |
| 898 | + STR_CASE(GL_RG8I) | |
| 899 | + STR_CASE(GL_RG8UI) | |
| 900 | + STR_CASE(GL_RG16) | |
| 901 | + STR_CASE(GL_RG16I) | |
| 902 | + STR_CASE(GL_RG16UI) | |
| 903 | + STR_CASE(GL_RG32I) | |
| 904 | + STR_CASE(GL_RG32UI) | |
| 905 | + STR_CASE(GL_RG16F) | |
| 906 | + STR_CASE(GL_RG32F) | |
| 907 | + STR_CASE(GL_RGB) | |
| 908 | + STR_CASE(GL_RGB2_EXT) // GL_EXT_texture | |
| 909 | + STR_CASE(GL_R3_G3_B2) | |
| 910 | + STR_CASE(GL_RGB4) | |
| 911 | + STR_CASE(GL_RGB5) | |
| 912 | + STR_CASE(GL_RGB565) | |
| 913 | + STR_CASE(GL_RGB8) | |
| 914 | + STR_CASE(GL_RGB8I) | |
| 915 | + STR_CASE(GL_RGB8UI) | |
| 916 | + STR_CASE(GL_RGB10) | |
| 917 | + STR_CASE(GL_RGB12) | |
| 918 | + STR_CASE(GL_RGB16) | |
| 919 | + STR_CASE(GL_RGB16I) | |
| 920 | + STR_CASE(GL_RGB16UI) | |
| 921 | + STR_CASE(GL_RGB32I) | |
| 922 | + STR_CASE(GL_RGB32UI) | |
| 923 | + STR_CASE(GL_RGB16F) | |
| 924 | + STR_CASE(GL_RGB32F) | |
| 925 | + STR_CASE(GL_R11F_G11F_B10F) | |
| 926 | + STR_CASE(GL_RGB9_E5) | |
| 927 | + STR_CASE(GL_RGBA) | |
| 928 | + STR_CASE(GL_RGBA2) | |
| 929 | + STR_CASE(GL_RGBA4) | |
| 930 | + STR_CASE(GL_RGBA8) | |
| 931 | + STR_CASE(GL_RGBA8I) | |
| 932 | + STR_CASE(GL_RGBA8UI) | |
| 933 | + STR_CASE(GL_RGBA12) | |
| 934 | + STR_CASE(GL_RGBA16) | |
| 935 | + STR_CASE(GL_RGBA16I) | |
| 936 | + STR_CASE(GL_RGBA16UI) | |
| 937 | + STR_CASE(GL_RGBA32I) | |
| 938 | + STR_CASE(GL_RGBA32UI) | |
| 939 | + STR_CASE(GL_RGB5_A1) | |
| 940 | + STR_CASE(GL_RGB10_A2) | |
| 941 | + STR_CASE(GL_RGB10_A2UI) | |
| 942 | + STR_CASE(GL_RGBA16F) | |
| 943 | + STR_CASE(GL_RGBA32F) | |
| 944 | + STR_CASE(GL_R8_SNORM) | |
| 945 | + STR_CASE(GL_R16_SNORM) | |
| 946 | + STR_CASE(GL_RG8_SNORM) | |
| 947 | + STR_CASE(GL_RG16_SNORM) | |
| 948 | + STR_CASE(GL_RGB8_SNORM) | |
| 949 | + STR_CASE(GL_RGB16_SNORM) | |
| 950 | + STR_CASE(GL_RGBA8_SNORM) | |
| 951 | + STR_CASE(GL_RGBA16_SNORM) | |
| 952 | + STR_CASE(GL_SR8_EXT) // GL_EXT_texture_sRGB_R8 | |
| 953 | + STR_CASE(GL_SRG8_EXT) // GL_EXT_texture_sRGB_RG8 | |
| 954 | + STR_CASE(GL_SRGB) | |
| 955 | + STR_CASE(GL_SRGB8) | |
| 956 | + STR_CASE(GL_SRGB_ALPHA) | |
| 957 | + STR_CASE(GL_SRGB8_ALPHA8) | |
| 958 | + STR_CASE(GL_DEPTH_STENCIL) | |
| 959 | + STR_CASE(GL_DEPTH24_STENCIL8) | |
| 960 | + STR_CASE(GL_DEPTH32F_STENCIL8) | |
| 961 | + STR_CASE(GL_DEPTH_COMPONENT) | |
| 962 | + STR_CASE(GL_DEPTH_COMPONENT16) | |
| 963 | + STR_CASE(GL_DEPTH_COMPONENT24) | |
| 964 | + STR_CASE(GL_DEPTH_COMPONENT32) | |
| 965 | + STR_CASE(GL_DEPTH_COMPONENT32F) | |
| 966 | + STR_CASE(GL_STENCIL_INDEX) | |
| 967 | + STR_CASE(GL_STENCIL_INDEX1) | |
| 968 | + STR_CASE(GL_STENCIL_INDEX4) | |
| 969 | + STR_CASE(GL_STENCIL_INDEX8) | |
| 970 | + STR_CASE(GL_STENCIL_INDEX16) | |
| 971 | + STR_CASE(GL_COMPRESSED_RED) | |
| 972 | + STR_CASE(GL_COMPRESSED_RG) | |
| 973 | + STR_CASE(GL_COMPRESSED_RGB) | |
| 974 | + STR_CASE(GL_COMPRESSED_RGBA) | |
| 975 | + STR_CASE(GL_COMPRESSED_SRGB) | |
| 976 | + STR_CASE(GL_COMPRESSED_SRGB_ALPHA) | |
| 977 | + STR_CASE(GL_COMPRESSED_RGB_S3TC_DXT1_EXT) | |
| 978 | + STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) | |
| 979 | + STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) | |
| 980 | + STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) | |
| 981 | + STR_CASE(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT) | |
| 982 | + STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) | |
| 983 | + STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT) | |
| 984 | + STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) | |
| 985 | + STR_CASE(GL_COMPRESSED_RED_RGTC1) | |
| 986 | + STR_CASE(GL_COMPRESSED_RG_RGTC2) | |
| 987 | + STR_CASE(GL_COMPRESSED_SIGNED_RED_RGTC1) | |
| 988 | + STR_CASE(GL_COMPRESSED_SIGNED_RG_RGTC2) | |
| 989 | + STR_CASE(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) | |
| 990 | + STR_CASE(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) | |
| 991 | + STR_CASE(GL_COMPRESSED_RGBA_BPTC_UNORM) | |
| 992 | + STR_CASE(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) | |
| 993 | + STR_CASE(GL_COMPRESSED_RGB8_ETC2) | |
| 994 | + STR_CASE(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) | |
| 995 | + STR_CASE(GL_COMPRESSED_SRGB8_ETC2) | |
| 996 | + STR_CASE(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) | |
| 997 | + STR_CASE(GL_COMPRESSED_RGBA8_ETC2_EAC) | |
| 998 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) | |
| 999 | + STR_CASE(GL_COMPRESSED_R11_EAC) | |
| 1000 | + STR_CASE(GL_COMPRESSED_RG11_EAC) | |
| 1001 | + STR_CASE(GL_COMPRESSED_SIGNED_R11_EAC) | |
| 1002 | + STR_CASE(GL_COMPRESSED_SIGNED_RG11_EAC) | |
| 1003 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_4x4_KHR) | |
| 1004 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_5x4_KHR) | |
| 1005 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_5x5_KHR) | |
| 1006 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_6x5_KHR) | |
| 1007 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_6x6_KHR) | |
| 1008 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x5_KHR) | |
| 1009 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x6_KHR) | |
| 1010 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x8_KHR) | |
| 1011 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x5_KHR) | |
| 1012 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x6_KHR) | |
| 1013 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x8_KHR) | |
| 1014 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x10_KHR) | |
| 1015 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_12x10_KHR) | |
| 1016 | + STR_CASE(GL_COMPRESSED_RGBA_ASTC_12x12_KHR) | |
| 1017 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) | |
| 1018 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) | |
| 1019 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) | |
| 1020 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) | |
| 1021 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) | |
| 1022 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) | |
| 1023 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) | |
| 1024 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) | |
| 1025 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) | |
| 1026 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) | |
| 1027 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) | |
| 1028 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) | |
| 1029 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) | |
| 1030 | + STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) | |
| 1031 | + default: | |
| 1032 | + return str_enum_(internal_format); | |
| 1033 | + } | |
| 1034 | +} | 
| 0 | 1035 | new file mode 100644 | 
| ... | ... | @@ -0,0 +1,65 @@ | 
| 1 | +#include <exception> | |
| 2 | +#include <iostream> | |
| 3 | +#include <string> | |
| 4 | +#include <type_traits> | |
| 5 | + | |
| 6 | +#include <glbase.hpp> | |
| 7 | + | |
| 8 | + | |
| 9 | +struct GLBaseTest : protected GLBase | |
| 10 | +{ | |
| 11 | + explicit GLBaseTest() | |
| 12 | + : | |
| 13 | +        GLBase{} | |
| 14 | +    { | |
| 15 | + std::cout | |
| 16 | +            << path_prefix_("path", "")       << "\n" | |
| 17 | +            << path_prefix_("path", "prefix") << std::endl; | |
| 18 | + | |
| 19 | + try | |
| 20 | +        { | |
| 21 | +            TGA_::read("nonexistent"); | |
| 22 | + } | |
| 23 | + catch (std::exception const & exception) | |
| 24 | +        { | |
| 25 | + std::cout << exception.what() << std::endl; | |
| 26 | + } | |
| 27 | + | |
| 28 | + // NOLINTNEXTLINE | |
| 29 | +        TGA_ tga({1, 1}, {0, 0, 255, 127}); | |
| 30 | + std::cout | |
| 31 | + << "TGA:" << "\n" | |
| 32 | + << " size: " << tga.size()[0] << ", " << tga.size()[1] << "\n" | |
| 33 | + << " data size: " << tga.data().size() << std::endl; | |
| 34 | + | |
| 35 | + std::cout | |
| 36 | +            << str_path_           ("path")             << "\n" | |
| 37 | +            << str_paths_          ({"path1", "path2"}) << "\n" | |
| 38 | + << str_enum_ (0x01) << "\n" | |
| 39 | + << str_error_ (GL_NO_ERROR) << "\n" | |
| 40 | + << str_object_type_ (GL_TEXTURE) << "\n" | |
| 41 | + << str_glsl_ (GL_FLOAT_VEC3) << "\n" | |
| 42 | + << str_format_ (GL_RGBA) << "\n" | |
| 43 | + << str_type_ (GL_FLOAT) << "\n" | |
| 44 | + << str_internal_format_(GL_RGBA32F) << std::endl; | |
| 45 | + } | |
| 46 | +}; | |
| 47 | + | |
| 48 | + | |
| 49 | +int main() | |
| 50 | +{ | |
| 51 | + static_assert(std::is_empty<GLBase>::value, "GLBase must be empty"); | |
| 52 | + | |
| 53 | + std::cout | |
| 54 | + << "Supported 1.0: " | |
| 55 | +        << GLBase::supported({1, 0}) | |
| 56 | + << std::endl; | |
| 57 | + std::cout | |
| 58 | + << "GL_ACTIVE_TEXTURE: " | |
| 59 | + << GLBase::integer(GL_ACTIVE_TEXTURE) | |
| 60 | + << std::endl; | |
| 61 | + GLBase::debug(1); | |
| 62 | +    GLBase::debug_message("Debug message"); | |
| 63 | + | |
| 64 | +    GLBaseTest{}; | |
| 65 | +} |