Name Mode Size
..
glbase.cpp 100644 31 kb
README.md
# [`glbase`][] A [C++11][]/[OpenGL][]>=[1.0][] basics library. This library wraps up some common basic OpenGL functionality for convenience, including checking for supported OpenGL [version][]s and [extension][]s, basic image loading and saving, debugging helpers, error checking, and string helpers. [`glbase`]: https://git.rcrnstn.net/rcrnstn/glbase [C++11]: https://en.wikipedia.org/wiki/C++11 [OpenGL]: https://en.wikipedia.org/wiki/OpenGL [1.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history [version]: https://en.wikipedia.org/wiki/OpenGL#Version_history [extension]: https://www.khronos.org/opengl/wiki/OpenGL_Extension ## Usage ### OpenGL loading library This library can be used with an arbitrary [OpenGL loading library][] by making sure `GLBASE_INCLUDE` is defined to the file to `#include`, e.g. `<glad/glad.h>` (either in the source or through a compiler switch, probably defined in the build system). Note that double quotes or angle brackets are required. The default if none is defined is `<GL/glew.h>`. If [CMake][] is used for building (see [Building][]), the `GLBASE_INCLUDE` CMake variable can be set to tell `glbase` to not use the default [GLEW][], and to set the corresponding define. In this case, the CMake variables `GLBASE_PACKAGES` and `GLBASE_TARGETS` can be used to set the packages and targets respectively to use for OpenGL and the loading library (either or both can be empty). [OpenGL loading library]: https://www.khronos.org/opengl/wiki/OpenGL_Loading_Library [CMake]: https://cmake.org [Building]: #building [GLEW]: https://glew.sourceforge.net ### Thread safety "Global" state (usually used to mirror some OpenGL [context][] internal state for performance) is declared [`thread_local`][] and initialized lazily. This means that a given thread may create at most one OpenGL context, and the `GLBase`-derived objects created while that context is current may be used only from that thread. Driver vendors recommend to not share OpenGL contexts between threads, for performance. The underlying mechanism used to retrieve system error messages may be thread unsafe. (`GLBase`-derived classes are encouraged to use `std::generic_category().message(errno)`, which often is, but is not required to be, thread safe, instead of [`std::strerror`][]`(errno)`, which is thread unsafe on most platforms). [context]: https://www.khronos.org/opengl/wiki/OpenGL_Context [`thread_local`]: https://en.cppreference.com/w/cpp/keyword/thread_local [`std::strerror`]: https://en.cppreference.com/w/cpp/string/byte/strerror ### Conventions The following table summarizes the [naming convention][] used. | Category | Capitalization | Public | Protected | Private | | -------- | -------------- | ------ | ---------- | ---------- | | Type | `PascalCase` | | `_` suffix | `_` suffix | | Function | `snake_case` | | `_` suffix | `_` suffix | | Variable | `snake_case` | (none) | (none) | `_` suffix | | Macro | `MACRO_CASE` | (few) | | `_` suffix | "Private" in this case includes things with [internal linkage][]. The [storage duration][] or whether members are bound to class instances or not does not affect naming. Parameters (including template parameters) are considered public even though their use obviously is constrained to a scope inaccessible to the outside user. As can be seen in the table, class member variables are always private and (either public or protected) access is provided by [Accessors][]. `GLBase`-derived classes should prefer to use their own protected member functions over their private member variables. [naming convention]: https://en.wikipedia.org/wiki/Naming_convention_(programming) [internal linkage]: https://en.cppreference.com/w/cpp/language/storage_duration#internal_linkage [storage duration]: https://en.cppreference.com/w/cpp/language/storage_duration#storage_duration [Accessors]: #accessors ### Size `GLBase` is an [empty][] class and the [empty base optimization][] applies. [empty]: https://en.cppreference.com/w/cpp/types/is_empty [empty base optimization]: https://en.cppreference.com/w/cpp/language/ebo ### Special member functions Both the constructor and the destructor are [`protected`][]. End users should use a `GLBase`-derived class to instantiate objects. Note that the destructor is not [`virtual`][]. `GLBase`-derived objects must not be destroyed through `GLBase` pointers. [`protected`]: https://en.cppreference.com/w/cpp/keyword/protected [`virtual`]: https://en.cppreference.com/w/cpp/language/virtual ### Accessors Getter and setter functions share the same name and use function overloading to disambiguate. Getters (which can be run on `const` objects) take no argument and return the value (by `const` reference). Setters take a [forwarding reference][] argument and return the old value (by value, after move). Macros that aid in the implementation of (potentially "global" static thread local) getters and setters are defined. These should be used in the class definition. They define functions named `NAME`, which operate on a variable named `NAME##_`. The underlying variable is not declared automatically, this must be done manually (probably [`private`][]). The `ACCESS` variant defines both `GET` and `SET`. `GLBASE_{GET,SET,ACCESS}{,_GLOBAL}(TYPE, NAME)` Additionally, "global" static thread local member variables need to be defined in exactly one [translation unit][]. A macro to help with this is defined as well. Note that, since the definition is outside the class definition, the `NAME` needs to be qualified with the class name. `GLBASE_GLOBAL(NAME, INIT)` [forwarding reference]: https://en.cppreference.com/w/cpp/language/reference#Forwarding_references [`private`]: https://en.cppreference.com/w/cpp/keyword/private [translation unit]: https://en.wikipedia.org/wiki/Translation_unit_(programming) ### Base `Version` is an alias for `std::array<GLint, 2>`. `bool static supported(Version version_min, std::string const & extension = {})` returns `true` if the current OpenGL [context][] implements the given, or a later (but see `version_max(...)` below), version or the given extension. If no version check is desired, provide `{}` (or, equivalently, `{0, 0}`). If no extension check is desired, provide an empty extension string (the default). If a non-empty `extension` is provided, it must start with `"GL_"`. If no check at all is performed, `false` is returned. Being able to check for both version and extension is convenient because extensions are often absorbed into newer versions of the OpenGL specification itself, and some platforms stop reporting support for the extension for those versions, so only checking if the extension is available fails. [History of OpenGL][] has a list of which versions of OpenGL absorbed which extensions. Since this library is agnostic to the used [OpenGL loading library][] (which is usually used to perform these kind of checks), the OpenGL API itself is queried. A new method of determining supported extensions was introduced in OpenGL [3.0][] and the old method deprecated and removed in OpenGL [3.1][]. This function uses the method appropriate for the current OpenGL [context][]. Note that no other checks are performed, including checks for a compatibility [profile][] [context][] or support for the [`ARB_compatibility`][] extension. `Version version_max({Version version_max})` gets/sets the maximum version for which `supported(...)` described above will return `true`. To disable this functionality, provide `{}` (or, equivalently, `{0, 0}`), which is the default value. Setting it to any other value also disables extension checking in `supported(...)`. This is useful for testing fallback code paths, regardless of the version present on a development machine (many platforms will provide a [context][] with a version higher than the one requested). `char const * static string(GLenum name)` and `char const * static string(GLenum name, GLuint index)` call [`glGetString`][] and [`glGetStringi`][] respectively with the given arguments and return the result, which obviates the need to cast the result (the OpenGL functions return `GLubyte const *`). `GLint static integer(GLenum name)` calls [`glGetIntegerv`][] with the given argument and returns the result, which obviates the need to declare a variable beforehand. Make sure to only use values of `name` that get a single integer. [History of OpenGL]: https://www.khronos.org/opengl/wiki/History_of_OpenGL [`glGetIntegerv`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGet.xhtml [`glGetString`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetString.xhtml [`glGetStringi`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetString.xhtml [3.0]: https://en.wikipedia.org/wiki/OpenGL#Version_history [3.1]: https://en.wikipedia.org/wiki/OpenGL#Version_history [profile]: https://www.khronos.org/opengl/wiki/OpenGL_Context#OpenGL_3.2_and_Profiles [`ARB_compatibility`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_compatibility.txt ### Path `Path` is an alias for `std::string`. `Paths` is an alias for `std::vector<Path>`. `Path static path_prefix_(Path const & path, Path const & prefix)` returns `prefix` prepended to `path`, separated with a `/`, unless either 1. `prefix` is empty 2. `path` starts with a `/` in which case `path` is returned as is. ### TGA A nested `GLBase::TGA_` class is provided to handle [Truevision TGA][] images in left-to-right, bottom-to-top, uncompressed [BGRA][] format. TGA was selected because it is widely supported and has a trivial header and data layout. It is also convenient because it has a pixel ordering compatible with the default [pixel transfer parameters][] and `GL_BGRA` is often preferred by graphics cards. `GLBase::TGA_` contains the following `static constexpr` member variables. - `char const name[]`: `"TGA"` - `GLint columns`: `1` - `GLint rows`: `4` - `GLenum glsl`: `GL_FLOAT_VEC4` - `GLenum format`: `GL_BGRA` - `GLenum type`: `GL_UNSIGNED_BYTE` - `GLenum internal_format`: `GL_RGBA8` - `GLenum internal_format_srgb`: `GL_SRGB8_ALPHA8` - `GLenum internal_format_compressed`: `GL_COMPRESSED_RGBA` - `GLenum internal_format_compressed_srgb`: `GL_COMPRESSED_SRGB_ALPHA` - `GLenum id`: `glsl` (These are the same `static constexpr` member variables defined by [`GLTraits::Value`][].) `GLBase::TGA_` contains the following type definitions. - `Size`. An alias for `std::array<GLsizei, 2>`. - `Data`. An alias for `std::vector<GLubyte>`. `GLBase::TGA_` contains the following member functions. - `explicit TGA_(Size size, Data data, Path const & path = {})`. Instantiates a `TGA_` object with the given `size` and `data`. `path`, if given, is only used for error reporting. - `TGA_ static read(std::string const & path)`. Reads the file `path` into a `TGA_` object. - `void write(std::string const & path) const`. Writes the `TGA_` object to the file `path`. - `Size size() const`. Gets the size of the TGA image. - `Data const & data() const`. Gets the data of the TGA image. [Truevision TGA]: https://en.wikipedia.org/wiki/Truevision_TGA [BGRA]: https://en.wikipedia.org/wiki/RGBA_color_model [pixel transfer parameters]: https://www.khronos.org/opengl/wiki/Pixel_Transfer#Pixel_transfer_parameters [`GLTraits::Value`]: https://git.rcrnstn.net/rcrnstn/gltraits/#value [GLSL]: https://www.khronos.org/opengl/wiki/OpenGL_Shading_Language ### Exceptions All exceptions thrown are of the type `GLBase::Exception`, which inherits from [`std::runtime_error`][]. [`std::runtime_error`]: https://en.cppreference.com/w/cpp/error/runtime_error ### Debug A dynamic debug facility is used instead of asserts mainly because it allows dynamic error messages and it is often desirable to turn on debugging only during a problematic part of an application run. `DebugCallback` is an alias for [`std::function`][]`<void (std::string const & message)>`. These functions may not [`throw`][] since they are called by OpenGL, which may not support throwing exceptions across its stack frames. `int static debug({int debug})` gets/sets the global debug level. When `>= 1`, potentially costly debug operations are performed as part of other operations. When `>= 2` notifications may be emitted. Defaults to `0`. `DebugCallback static debug_callback({DebugCallback debug_callback})` gets/sets a callback that may be called by `GLBase`-derived classes (typically through `debug_message(...)`, see below). Defaults to a function which outputs the `mesage` argument to [`std::cerr`][], appends a newline and flushes. `void static debug_message(std::string const & message)` calls the callback registered with `debug_callback(...)` with `message` as argument if the callback is not empty (i.e. set to `nullptr`). `void static debug_action_(std::string const & action, std::string const & name)` calls `debug_message(...)` with a string containing `action` and `name`. [`std::function`]: https://en.cppreference.com/w/cpp/utility/functional/function [`throw`]: https://en.cppreference.com/w/cpp/language/throw [`std::cerr`]: https://en.cppreference.com/w/cpp/io/cerr ### Check These functions throw an exception if some condition does not hold. It is recommended that `GLBase`-derived classes use similar helper functions, defined in an implementation file, to hide the string processing necessary to form a helpful exception message. `GLBase`-derived classes should treat error checking as free during construction and expensive data transfer operations. At all other times, non-critical error checking should only be performed if `debug() >= 1`. `void static check_supported(Version version_min, std::string const & extension = {})` checks that `supported(...)` returns `true` for the given arguments. `void static check_path_(std::string const & path)` checks that `path` is non-empty. `void static check_error_(GLenum error)` checks an error returned by [`glGetError`][]. `void static check_type_(GLenum type, GLenum type_expected)` checks that `type` matches `type_expected`. `void static check_format_(GLenum format, GLenum format_expected)` checks that `format` matches `format_expected`. `void static check_internal_format_(GLenum internal_format)` checks that `internal_format` is supported. [`glGetError`]: https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetError.xhtml ### Fail These functions throw an exception and should be marked [`[[noreturn]]`][]. It is recommended that `GLBase`-derived classes use similar helper functions, defined in an implementation file, to hide the string processing necessary to form a helpful exception message. `[[noreturn]] void static fail_action_(std::string const & action, std::string const & name)` calls [`std::terminate`][] if called outside a [`catch`][] block. Otherwise, throws an exception with a message that includes `action` and `name` followed by `":\n"` and the [`what()`][] of the current exception if it is a (derives from) [`std::exception`][], otherwise simply rethrows the current exception. [`[[noreturn]]`]: https://en.cppreference.com/w/cpp/language/attributes/noreturn [`std::terminate`]: https://en.cppreference.com/w/cpp/error/terminate [`catch`]: https://en.cppreference.com/w/cpp/language/try_catch [`what()`]: https://en.cppreference.com/w/cpp/error/exception/what [`std::exception`]: https://en.cppreference.com/w/cpp/error/exception ### String `std::string static str_path_(Path const & path)` returns `path` surrounded by double quotes. `std::string static str_paths_(Paths const & paths)` returns `paths` surrounded by double quotes and joined with commas. `std::string static str_enum_(GLenum name)` returns the hexadecimal string representation of `name` (often used as fallback). `std::string static str_error_(GLenum error)` returns the string representation of values returned by [`glGetError`][]. `std::string static str_object_type_(GLenum object_type)` returns the string representation of `object_type`. `std::string static str_glsl_(GLenum glsl)` returns the string representation of `glsl`. `std::string static str_format_(GLenum format)` returns the string representation of `format`. `std::string static str_type_(GLenum type)` returns the string representation of `type`. `std::string static str_internal_format_(GLenum internal_format)` returns the string representation of `internal_format`. ## Texture compression formats This is here for reference only. Extension conventions are defined in [`GL_ARB_texture_compression`][]. Formats are described in the [Khronons Data Format Specification "Compressed Texture Image Formats"][] section. [Direct3D][] defines `BC*` texture "block" compression formats which correspond with some of the formats described below. See: - [Direct3D 10 Texture Block Compression][] - [Direct3D 11 Texture Block Compression][] A non-exhaustive list of compressed texture formats defined by OpenGL: - **S3TC** - Support: Widely supported since OpenGL 1.3 (2001) (the non-sRGB version is considered an "[ubiquitous extension][]"). Not core because of patents, which expired 2017. [Mesa][] support since 17.3 (2017). - Origin: Introduced by [S3 Graphics][]' [Savage 3D][] (1998) and supported by [Nvidia][]'s more popular [GeForce 256][] (also known as the "GeForce 1") (1999). (`DXT2` and `DXT4` are premultiplied alpha formats and not supported by OpenGL.) - Formats: - `{RGB{,A},SRGB{,_ALPHA}}_S3TC_DXT1_EXT` (`BC1`). 6:1 compression ratio. The alpha variants only have a single bit of alpha, and when `A` is `0` RGB must all be `0` as well. Therefore, it is best to use premultiplied alpha when using the alpha variants. - `{RGBA,SRGB_ALPHA}_S3TC_DXT3_EXT` (`BC2`). 4:1 compression ratio. Stores *uncompressed* alpha separately. Not generally recommended. - `{RGBA,SRGB_ALPHA}_S3TC_DXT5_EXT` (`BC3`). 4:1 compression ratio. Stores *compressed* alpha separately. - References: - [`GL_EXT_texture_compression_s3tc`][] - [`GL_EXT_texture_compression_s3tc_srgb`][] - [`GL_EXT_texture_sRGB`][] - [`GL_NV_texture_compression_s3tc`][] - [`GL_S3_s3tc`][] - [OpenGL Wiki][S3TC OpenGL Wiki] - [Wikipedia][S3TC Wikipedia] - VTC - Support: Not core. Only supported on Nvidia hardware. - Origin: Extension of S3TC to 3D ("volume") textures. - Formats: The same as S3TC, but interpreted differently for 3D textures. - References: - [`GL_NV_texture_compression_vtc`][] - **RGTC** - Support: Core since OpenGL 3.0 (2008). - Origin: Uses a separate S3TC DXT5 alpha encoding for one or two component red/green. Published at the same time as LATC. - Formats: - `{,SIGNED_}RED_RGTC1` (`BC4`). 2:1 compression ratio. - `{,SIGNED_}RG_RGTC2` (`BC5`). 2:1 compression ratio. - References: - [`GL_ARB_texture_compression_rgtc`][] - [`GL_EXT_texture_compression_rgtc`][] - [OpenGL Wiki][RGTC OpenGL Wiki] - [Wikipedia][RGTC Wikipedia] - LATC: - Support: Not core, no ARB extension. Luminance/alpha formats in general have seen a decline since the introduction of the programmable pipeline, which can use [swizzle][]s to achieve the same effect. - Origin: Uses a separate S3TC DXT5 alpha encoding for one or two component luminance/alpha. Published at the same time as RGTC. - Formats: - `{,SIGNED_}LUMINANCE_LATC1_EXT`. 2:1 compression ratio. - `{,SIGNED_}LUMINANCE_ALPHA_LATC2_EXT`. 2:1 compression ratio. - References - [`GL_EXT_texture_compression_latc`][] - [`GL_NV_texture_compression_latc`][] - **BPTC** - Support: Core since OpenGL 4.2 (2011). - Origin: Block Partition texture compression. - Formats: - `RGB_BPTC_{UN,}SIGNED_FLOAT` (`BC6H`): 4:1 compression ratio. Unsigned/signed 16-bit ("high dynamic range") float RGB. - `{RGBA,SRGB_ALPHA}_BPTC_UNORM` (`BC7`): 4:1 compression ratio. Unsigned normalized integer RGBA/sRGBA. - References: - [`GL_ARB_texture_compression_bptc`][] - [`GL_EXT_texture_compression_bptc`][] - [OpenGL Wiki][BPTC OpenGL Wiki] - [Wikipedia][BPTC Wikipedia] - **ETC** - Support: Core since OpenGL 4.3 (2012). Desktop OpenGL does not support ETC1, only ETC2. Images encoded as ETC1 can be read by an ETC2 decoder. - Origins: [Ericsson][]. EAC presumably stands for "Ericsson Alpha Compression" and is used to compress one or two channels (much like RGTC uses the alpha compression format of S3TC DX5). - Formats: - `{,S}RGB8{,_PUNCHTHROUGH_ALPHA1}_ETC2` 6:1 compression ratio. - `{RGBA8,SRGB8_ALPHA8}_ETC2_EAC`. 4:1 compression ratio. - `{,SIGNED_}R11_EAC` 2:1 compression ratio. - `{,SIGNED_}RG11_EAC` 2:1 compression ratio. - References: - [`GL_ARB_ES3_compatibility`][] - [`GL_OES_compressed_ETC1_RGB8_texture`][] - [Wikipedia][ETC Wikipedia] - ASTC: - Support: Not core. The extension is written against OpenGL ES, and there is no wide desktop support, at least for the HDR version. - Origin: [ARM][] and [AMD][]. Variable block ("adaptive scalable") texture compression. - Formats: - `{RGBA,SRGB8_ALPHA8}_ASTC_{4x4,5x{4,5},6x{5,6},8x{5,6,8},10x{5,6,8,10},12x{10,12}}_KHR` A large number of variables are encoded per block so e.g. the number of channels, dynamic range, and compression ratio vary. - References: - `GL_KHR_texture_compression_astc_ldr`, [`GL_KHR_texture_compression_astc_hdr`][] - [`GL_KHR_texture_compression_astc_sliced_3d`][] - [OpenGL Wiki][ASTC OpenGL Wiki] - [Wikipedia][ASTC Wikipedia] - [`ARM-software/astc-encoder`][] [`GL_ARB_texture_compression`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression.txt [Khronons Data Format Specification "Compressed Texture Image Formats"]: https://registry.khronos.org/DataFormat/specs/1.1/dataformat.1.1.html#_compressed_texture_image_formats [Direct3D]: https://en.wikipedia.org/wiki/Direct3D [Direct3D 10 Texture Block Compression]: https://learn.microsoft.com/en-us/windows/win32/direct3d10/d3d10-graphics-programming-guide-resources-block-compression [Direct3D 11 Texture Block Compression]: https://learn.microsoft.com/en-us/windows/win32/direct3d11/texture-block-compression-in-direct3d-11 [ubiquitous extension]: https://www.khronos.org/opengl/wiki/Ubiquitous_Extension [Mesa]: https://en.wikipedia.org/wiki/Mesa_(computer_graphics) [S3 Graphics]: https://en.wikipedia.org/wiki/S3_Graphics [Savage 3D]: https://en.wikipedia.org/wiki/S3_Savage#Savage_3D [Nvidia]: https://en.wikipedia.org/wiki/Nvidia [GeForce 256]: https://en.wikipedia.org/wiki/GeForce_256 [`GL_EXT_texture_compression_s3tc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc.txt [`GL_EXT_texture_compression_s3tc_srgb`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_s3tc_srgb.txt [`GL_EXT_texture_sRGB`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_sRGB.txt [`GL_NV_texture_compression_s3tc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_s3tc.txt [`GL_S3_s3tc`]: https://registry.khronos.org/OpenGL/extensions/S3/S3_s3tc.txt [S3TC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/S3_Texture_Compression [S3TC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression [`GL_NV_texture_compression_vtc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_vtc.txt [`GL_ARB_texture_compression_rgtc`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression_rgtc.txt [`GL_EXT_texture_compression_rgtc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_rgtc.txt [RGTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/Red_Green_Texture_Compression [RGTC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression#BC4_and_BC5 [swizzle]: https://www.khronos.org/opengl/wiki/Data_Type_(GLSL)#Swizzling [`GL_EXT_texture_compression_latc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_latc.txt [`GL_NV_texture_compression_latc`]: https://registry.khronos.org/OpenGL/extensions/NV/NV_texture_compression_latc.txt [`GL_ARB_texture_compression_bptc`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_texture_compression_bptc.txt [`GL_EXT_texture_compression_bptc`]: https://registry.khronos.org/OpenGL/extensions/EXT/EXT_texture_compression_bptc.txt [BPTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/BPTC_Texture_Compression [BPTC Wikipedia]: https://en.wikipedia.org/wiki/S3_Texture_Compression#BC6H_and_BC7 [Ericsson]: https://en.wikipedia.org/wiki/Ericsson [`GL_ARB_ES3_compatibility`]: https://registry.khronos.org/OpenGL/extensions/ARB/ARB_ES3_compatibility.txt [`GL_OES_compressed_ETC1_RGB8_texture`]: https://registry.khronos.org/OpenGL/extensions/OES/OES_compressed_ETC1_RGB8_texture.txt [ETC Wikipedia]: https://en.wikipedia.org/wiki/Ericsson_Texture_Compression [ARM]: https://en.wikipedia.org/wiki/Arm_(company) [AMD]: https://en.wikipedia.org/wiki/AMD [`GL_KHR_texture_compression_astc_hdr`]: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_hdr.txt [`GL_KHR_texture_compression_astc_sliced_3d`]: https://registry.khronos.org/OpenGL/extensions/KHR/KHR_texture_compression_astc_sliced_3d.txt [ASTC OpenGL Wiki]: https://www.khronos.org/opengl/wiki/ASTC_Texture_Compression [ASTC Wikipedia]: https://en.wikipedia.org/wiki/Adaptive_scalable_texture_compression [`ARM-software/astc-encoder`]: https://github.com/ARM-software/astc-encoder ## 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