#include <globject.hpp> #include <algorithm> #include <array> #include <cerrno> #include <cstdio> #include <cstring> #include <fstream> #include <iostream> #include <iterator> #include <sstream> #include <string> #include <unordered_set> // NOLINTNEXTLINE #define STR_EXCEPTION GLObject::Exception #include <str.hpp> /// Special member functions GLObject::GLObject( GLGenObjects gl_gen_objects, GLDeleteObjects gl_delete_objects, GLenum object_type, // cppcheck-suppress passedByValue std::string object_label ) : gl_delete_objects_{gl_delete_objects}, object_type_ {object_type}, object_label_ {std::move(object_label)}, object_ {0} { try { if (gl_gen_objects) gl_gen_objects(1, &object_); else object_ = object_pseudo_; check_error_(glGetError()); GLOBJECT_DEBUG_IF(1) { debug_label_(); debug_objects_push_back_(this); debug_callback()("Create " + debug_name()); } } catch (...) { if (gl_delete_objects_) gl_delete_objects_(1, &object_); fail_action_("create"); } } GLObject::GLObject(GLObject && other) noexcept : gl_delete_objects_{other.gl_delete_objects_}, object_type_ {other.object_type_}, object_label_ {std::move(other.object_label_)}, object_ {other.object_} { other.object_ = 0; GLOBJECT_DEBUG_IF(1) { debug_objects_erase_(&other); debug_objects_push_back_(this); debug_callback()("Move " + debug_name()); } } GLObject::~GLObject() { if (gl_delete_objects_) gl_delete_objects_(1, &object_); GLOBJECT_DEBUG_IF(1) { debug_objects_erase_(this); debug_callback()("Destroy " + debug_name()); } } /// Core bool GLObject::supported( Version version_min, std::string const & extension ) { auto static version = Version{0, 0}; auto static extensions = std::unordered_set<std::string>{}; if (extension.size() && extension.rfind("GL_", 0) == extension.npos) STR_THROW("Failed to parse extension \"" << extension << "\"."); if (version == Version{0, 0}) { auto const * version_str = (char const *)glGetString(GL_VERSION); if (!version_str) return false; // NOLINTNEXTLINE if (2 != std::sscanf(version_str, "%d.%d", &version[0], &version[1])) STR_THROW("Failed to parse version \"" << version_str << "\"."); if (version[0] >= 3) { auto extension_count = get_integer(GL_NUM_EXTENSIONS); for (auto i = 0; i < extension_count; ++i) extensions.insert( (char const *)glGetStringi(GL_EXTENSIONS, (GLuint)i) ); } else { auto istream = std::istringstream( (char const *)glGetString(GL_EXTENSIONS) ); std::copy( std::istream_iterator<std::string>(istream), std::istream_iterator<std::string>(), std::inserter(extensions, extensions.end()) ); } } if ( (version_min != Version{0, 0}) && ( (version[0] > version_min[0]) || ( version[0] == version_min[0] && version[1] >= version_min[1] ) ) ) return true; if ( extension.size() && extensions.find(extension) != extensions.end() ) return true; return false; } GLint GLObject::get_integer(GLenum name) try { auto value = GLint{}; glGetIntegerv(name, &value); GLOBJECT_DEBUG_IF(1) check_error_(glGetError()); return value; } catch (...) { STR_THROW_NESTED("Failed to get integer " << str_enum_(name) << ":"); } /// Path GLObject::Path GLObject::path_prefix_( Path const & path, Path const & prefix ) { if (prefix.empty() || path[0] == '/') return path; return STR(prefix << "/" << path); } /// TGA GLObject::TGA::TGA(Size size, Data data) try : header_{size}, data_{std::move(data)} { check_data_(); } catch (...) { STR_THROW_NESTED("Failed to create TGA " << str_size_(size) << ":"); } GLObject::TGA GLObject::TGA::read(Path const & path) try { auto tga = TGA({}, {}); auto istream = std::ifstream(path, std::ios::binary); istream.read( (char *) tga.header_.data(), (std::streamsize)tga.header_.size() ); tga.check_header_(); tga.data_.resize((std::size_t)(4 * tga.size()[0] * tga.size()[1])); istream.read( (char *) tga.data_.data(), (std::streamsize)tga.data_.size() ); istream.close(); if (!istream) // NOLINTNEXTLINE STR_THROW(std::strerror(errno)); return tga; } catch (...) { STR_THROW_NESTED("Failed to read TGA " << str_path_(path) << ":"); } void GLObject::TGA::write(Path const & path) const try { check_data_(); auto ostream = std::ofstream(path, std::ios::binary); ostream.write((char *)header_.data(), (std::streamsize)header_.size()); ostream.write((char *)data_ .data(), (std::streamsize)data_ .size()); ostream.close(); if (!ostream) // NOLINTNEXTLINE STR_THROW(std::strerror(errno)); } catch (...) { STR_THROW_NESTED("Failed to write TGA " << str_path_(path) << ":"); } GLObject::TGA::Data const & GLObject::TGA::data() { return data_; } GLObject::TGA::Size GLObject::TGA::size() const { return { (GLsizei)(header_[12]) << 0 | // NOLINT (GLsizei)(header_[13]) << 8, // NOLINT (GLsizei)(header_[14]) << 0 | // NOLINT (GLsizei)(header_[15]) << 8, // NOLINT }; } GLObject::TGA::Header::Header(Size size) : std::array<GLubyte, 18>{ // NOLINT 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, // NOLINT (GLubyte)(size[0] >> 0), // NOLINT (GLubyte)(size[0] >> 8), // NOLINT (GLubyte)(size[1] >> 0), // NOLINT (GLubyte)(size[1] >> 8), // NOLINT 32, 8, // NOLINT } { } std::string GLObject::TGA::str_size_(Size size) { return STR("{" << STR_JOIN(", ", it, it, size) << "}"); } void GLObject::TGA::check_header_() const { auto header = Header(size()); if (header_ != header) STR_THROW( "Expected TGA header" << " " << "[" << STR_JOIN(", ", byte, byte, header) << "]" << ", " << "got" << " " << "[" << STR_JOIN(", ", byte, byte, header_) << "]" << "." ); } void GLObject::TGA::check_data_() const { auto data_size = (std::size_t)(4 * size()[0] * size()[1]); if (data_size != data_.size()) STR_THROW( "Expected TGA data size " << data_size << ", " << "got " << data_.size() << "." ); } /// Debug GLOBJECT_THREAD(GLObject::debug_, {1}) GLOBJECT_THREAD(GLObject::debug_objects_, {}) GLOBJECT_THREAD(GLObject::debug_callback_, {[](std::string const & debug) { std::cerr << debug << std::endl; }}) std::string GLObject::debug_name() const { return STR_JOIN(" ", it, it, { object_type_ == 0 ? "<GLObject>" : str_object_type_(object_type_), object_label_, object_ == 0 ? "<INVALID>" : object_ == object_pseudo_ ? "<PSEUDO>" : STR(object_), }); } void GLObject::debug_label_() const { if ( object_type_ && object_label_.size() && object_ ) { if (supported({4, 3}, "GL_KHR_debug")) { auto static object_label_length_max = get_integer( GL_MAX_LABEL_LENGTH ); auto object_label_length = std::min( (GLsizei)object_label_length_max, (GLsizei)object_label_.length() ); glObjectLabel( object_type_, object_, object_label_length, object_label_.c_str() ); } } } std::string static debug_objects_data_( std::string (GLObject::*debug_data)() const ) { auto const & objects = GLObject::debug_objects(); auto header = STR("GLObjects: " << objects.size()); auto data = STR_JOIN( "\n", object, " " << (object->*debug_data)(), objects ); return STR_JOIN("\n", it, it, {header, data}); } std::string GLObject::debug_objects_name() { return debug_objects_data_(&GLObject::debug_name); } std::string GLObject::debug_objects_info() { return debug_objects_data_(&GLObject::debug_info); } std::string GLObject::debug_info() const { return debug_name(); } void GLObject::debug_objects_push_back_(GLObject * debug_object) { debug_objects_.push_back(debug_object); } void GLObject::debug_objects_erase_(GLObject * debug_object) { debug_objects_.erase( std::remove( debug_objects_.begin(), debug_objects_.end(), debug_object ), debug_objects_.end() ); } /// Check void GLObject::check_path_(std::string const & path) { if (!path.size()) STR_THROW( "Expected " << "non-empty path" << ", " << "got " << "\"" << path << "\"" << "." ); } void GLObject::check_error_(GLenum error) { if (error != GL_NO_ERROR) STR_THROW( "Expected " << "no error" << ", " << "got " << str_error_(error) << "." ); } void GLObject::check_supported_( Version version_min, std::string const & extension ) { if (!supported(version_min, extension)) STR_THROW( "Expected GL version " << STR_JOIN(".", it, it, version_min) << (extension.size() ? STR(" or extension " << extension) : "") << " " "got " << glGetString(GL_VERSION) << "." ); } void GLObject::check_format_( GLenum format, GLenum format_expected ) { if (format != format_expected) STR_THROW( "Expected format " << str_format_(format_expected) << ", " << "got " << str_format_(format) << "." ); } void GLObject::check_type_( GLenum type, GLenum type_expected ) { if (type != type_expected) STR_THROW( "Expected type " << str_type_(type_expected) << ", " << "got " << str_type_(type) << "." ); } void GLObject::check_internal_format_(GLenum internal_format) { switch (internal_format) { case GL_RED: case GL_RGB: case GL_RGBA: case GL_DEPTH_COMPONENT: case GL_STENCIL_INDEX: case GL_R3_G3_B2: check_supported_({1, 0}); return; case GL_RGB4: case GL_RGB5: case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: case GL_RGBA2: case GL_RGBA4: case GL_RGBA8: case GL_RGBA12: case GL_RGBA16: case GL_RGB5_A1: case GL_RGB10_A2: check_supported_({1, 1}, "GL_EXT_texture"); return; case GL_COMPRESSED_RGB: case GL_COMPRESSED_RGBA: check_supported_({1, 3}, "GL_ARB_texture_compression"); return; case GL_DEPTH_COMPONENT16: case GL_DEPTH_COMPONENT24: case GL_DEPTH_COMPONENT32: check_supported_({1, 4}, "GL_ARB_depth_texture"); return; case GL_SRGB: case GL_SRGB8: case GL_SRGB_ALPHA: case GL_SRGB8_ALPHA8: case GL_COMPRESSED_SRGB: case GL_COMPRESSED_SRGB_ALPHA: check_supported_({2, 1}, "GL_EXT_texture_sRGB"); return; case GL_SR8_EXT: check_supported_({}, "GL_EXT_texture_sRGB_R8"); return; case GL_SRG8_EXT: check_supported_({}, "GL_EXT_texture_sRGB_RG8"); return; case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: check_supported_({}, "GL_EXT_texture_compression_s3tc"); return; case GL_COMPRESSED_SRGB_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT: case GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: check_supported_({}, "GL_EXT_texture_sRGB"); check_supported_({}, "GL_EXT_texture_compression_s3tc"); return; case GL_COMPRESSED_RED: case GL_COMPRESSED_RG: check_supported_({3, 0}); return; case GL_COMPRESSED_RED_RGTC1: case GL_COMPRESSED_SIGNED_RED_RGTC1: case GL_COMPRESSED_RG_RGTC2: case GL_COMPRESSED_SIGNED_RG_RGTC2: check_supported_({3, 0}, "GL_ARB_texture_compression_rgtc"); return; case GL_RGB16F: case GL_RGB32F: case GL_RGBA16F: case GL_RGBA32F: check_supported_({3, 0}, "GL_ARB_texture_float"); return; case GL_RGB8I: case GL_RGB16I: case GL_RGB32I: case GL_RGB8UI: case GL_RGB16UI: case GL_RGB32UI: case GL_RGBA8I: case GL_RGBA16I: case GL_RGBA32I: case GL_RGBA8UI: case GL_RGBA16UI: case GL_RGBA32UI: check_supported_({3, 0}, "GL_EXT_texture_integer"); return; case GL_R16F: case GL_R32F: case GL_RG16F: case GL_RG32F: case GL_R8: case GL_R8I: case GL_R8UI: case GL_R16: case GL_R16I: case GL_R16UI: case GL_R32I: case GL_R32UI: case GL_RG: case GL_RG8: case GL_RG8I: case GL_RG8UI: case GL_RG16: case GL_RG16I: case GL_RG16UI: case GL_RG32I: case GL_RG32UI: check_supported_({3, 0}, "GL_ARB_texture_rg"); return; case GL_R11F_G11F_B10F: check_supported_({3, 0}, "GL_EXT_packed_float"); return; case GL_RGB9_E5: check_supported_({3, 0}, "GL_EXT_texture_shared_exponent"); return; case GL_DEPTH_STENCIL: case GL_DEPTH24_STENCIL8: check_supported_({3, 0}, "GL_EXT_packed_depth_stencil"); return; case GL_DEPTH32F_STENCIL8: case GL_DEPTH_COMPONENT32F: check_supported_({3, 0}, "GL_ARB_depth_buffer_float"); return; case GL_STENCIL_INDEX8: check_supported_({3, 0}, "GL_ARB_texture_stencil8"); return; case GL_STENCIL_INDEX1: case GL_STENCIL_INDEX4: case GL_STENCIL_INDEX16: check_supported_({3, 0}, "GL_ARB_framebuffer_object"); return; case GL_R8_SNORM: case GL_R16_SNORM: case GL_RG8_SNORM: case GL_RG16_SNORM: case GL_RGB8_SNORM: case GL_RGB16_SNORM: case GL_RGBA8_SNORM: case GL_RGBA16_SNORM: check_supported_({3, 1}, "GL_EXT_texture_snorm"); return; case GL_RGB10_A2UI: check_supported_({3, 3}, "GL_ARB_texture_rgb10_a2ui"); return; case GL_RGB565: check_supported_({4, 1}, "GL_ARB_ES2_compatibility"); return; case GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT: case GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT: case GL_COMPRESSED_RGBA_BPTC_UNORM: case GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM: check_supported_({4, 2}, "GL_ARB_texture_compression_bptc"); return; case GL_COMPRESSED_R11_EAC: case GL_COMPRESSED_RG11_EAC: case GL_COMPRESSED_SIGNED_R11_EAC: case GL_COMPRESSED_SIGNED_RG11_EAC: case GL_COMPRESSED_RGB8_ETC2: case GL_COMPRESSED_SRGB8_ETC2: case GL_COMPRESSED_RGBA8_ETC2_EAC: case GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC: case GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2: case GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2: check_supported_({4, 2}, "GL_ARB_ES3_compatibility"); return; case GL_COMPRESSED_RGBA_ASTC_4x4_KHR: case GL_COMPRESSED_RGBA_ASTC_5x4_KHR: case GL_COMPRESSED_RGBA_ASTC_5x5_KHR: case GL_COMPRESSED_RGBA_ASTC_6x5_KHR: case GL_COMPRESSED_RGBA_ASTC_6x6_KHR: case GL_COMPRESSED_RGBA_ASTC_8x5_KHR: case GL_COMPRESSED_RGBA_ASTC_8x6_KHR: case GL_COMPRESSED_RGBA_ASTC_8x8_KHR: case GL_COMPRESSED_RGBA_ASTC_10x5_KHR: case GL_COMPRESSED_RGBA_ASTC_10x6_KHR: case GL_COMPRESSED_RGBA_ASTC_10x8_KHR: case GL_COMPRESSED_RGBA_ASTC_10x10_KHR: case GL_COMPRESSED_RGBA_ASTC_12x10_KHR: case GL_COMPRESSED_RGBA_ASTC_12x12_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR: case GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR: check_supported_({4, 2}, "GL_KHR_texture_compression_astc_ldr"); return; default: STR_THROW( "Expected " << "supported internal format" << ", " "got " << str_internal_format_(internal_format) << "." ); } } /// Fail void GLObject::fail_action_(std::string const & action) const { STR_THROW_NESTED("Failed to " << action << " " << debug_name() << ":"); } /// String std::string GLObject::str_path_(Path const & path) { return STR("\"" << path << "\""); } std::string GLObject::str_paths_(Paths const & paths) { return STR_JOIN(", ", path, str_path_(path), paths); } std::string GLObject::str_enum_(GLenum name) { return STR(std::hex << std::showbase << name); } std::string GLObject::str_error_(GLenum error) { switch (error) { STR_CASE(GL_NO_ERROR) STR_CASE(GL_INVALID_ENUM) STR_CASE(GL_INVALID_VALUE) STR_CASE(GL_INVALID_OPERATION) STR_CASE(GL_INVALID_FRAMEBUFFER_OPERATION) STR_CASE(GL_OUT_OF_MEMORY) STR_CASE(GL_STACK_UNDERFLOW) STR_CASE(GL_STACK_OVERFLOW) default: return str_enum_(error); } } std::string GLObject::str_object_type_(GLenum object_type) { switch (object_type) { STR_CASE(GL_BUFFER) STR_CASE(GL_SHADER) STR_CASE(GL_PROGRAM) STR_CASE(GL_VERTEX_ARRAY) STR_CASE(GL_QUERY) STR_CASE(GL_PROGRAM_PIPELINE) STR_CASE(GL_TRANSFORM_FEEDBACK) STR_CASE(GL_SAMPLER) STR_CASE(GL_TEXTURE) STR_CASE(GL_RENDERBUFFER) STR_CASE(GL_FRAMEBUFFER) default: return str_enum_(object_type); } } std::string GLObject::str_format_(GLenum format) { switch (format) { STR_CASE(GL_RED) STR_CASE(GL_R) STR_CASE(GL_RG) STR_CASE(GL_RGB) STR_CASE(GL_RGBA) STR_CASE(GL_BGR) STR_CASE(GL_BGRA) STR_CASE(GL_DEPTH_COMPONENT) STR_CASE(GL_STENCIL_INDEX) default: return str_enum_(format); } } std::string GLObject::str_type_(GLenum type) { switch (type) { STR_CASE(GL_FLOAT) STR_CASE(GL_BYTE) STR_CASE(GL_SHORT) STR_CASE(GL_INT) STR_CASE(GL_UNSIGNED_BYTE) STR_CASE(GL_UNSIGNED_SHORT) STR_CASE(GL_UNSIGNED_INT) STR_CASE(GL_UNSIGNED_BYTE_3_3_2) STR_CASE(GL_UNSIGNED_BYTE_2_3_3_REV) STR_CASE(GL_UNSIGNED_SHORT_5_6_5) STR_CASE(GL_UNSIGNED_SHORT_5_6_5_REV) STR_CASE(GL_UNSIGNED_SHORT_4_4_4_4) STR_CASE(GL_UNSIGNED_SHORT_4_4_4_4_REV) STR_CASE(GL_UNSIGNED_SHORT_5_5_5_1) STR_CASE(GL_UNSIGNED_SHORT_1_5_5_5_REV) STR_CASE(GL_UNSIGNED_INT_8_8_8_8) STR_CASE(GL_UNSIGNED_INT_8_8_8_8_REV) STR_CASE(GL_UNSIGNED_INT_10_10_10_2) STR_CASE(GL_UNSIGNED_INT_2_10_10_10_REV) default: return str_enum_(type); } } std::string GLObject::str_internal_format_(GLenum internal_format) { switch (internal_format) { STR_CASE(GL_RED) STR_CASE(GL_RGB) STR_CASE(GL_RGBA) STR_CASE(GL_DEPTH_COMPONENT) STR_CASE(GL_STENCIL_INDEX) STR_CASE(GL_R3_G3_B2) STR_CASE(GL_RGB4) STR_CASE(GL_RGB5) STR_CASE(GL_RGB8) STR_CASE(GL_RGB10) STR_CASE(GL_RGB12) STR_CASE(GL_RGB16) STR_CASE(GL_RGBA2) STR_CASE(GL_RGBA4) STR_CASE(GL_RGBA8) STR_CASE(GL_RGBA12) STR_CASE(GL_RGBA16) STR_CASE(GL_RGB5_A1) STR_CASE(GL_RGB10_A2) STR_CASE(GL_COMPRESSED_RGB) STR_CASE(GL_COMPRESSED_RGBA) STR_CASE(GL_DEPTH_COMPONENT16) STR_CASE(GL_DEPTH_COMPONENT24) STR_CASE(GL_DEPTH_COMPONENT32) STR_CASE(GL_SRGB) STR_CASE(GL_SRGB8) STR_CASE(GL_SRGB_ALPHA) STR_CASE(GL_SRGB8_ALPHA8) STR_CASE(GL_COMPRESSED_SRGB) STR_CASE(GL_COMPRESSED_SRGB_ALPHA) STR_CASE(GL_SR8_EXT) STR_CASE(GL_SRG8_EXT) STR_CASE(GL_COMPRESSED_RGB_S3TC_DXT1_EXT) STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT) STR_CASE(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT) STR_CASE(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT) STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT) STR_CASE(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) STR_CASE(GL_COMPRESSED_RED) STR_CASE(GL_COMPRESSED_RG) STR_CASE(GL_COMPRESSED_RED_RGTC1) STR_CASE(GL_COMPRESSED_SIGNED_RED_RGTC1) STR_CASE(GL_COMPRESSED_RG_RGTC2) STR_CASE(GL_COMPRESSED_SIGNED_RG_RGTC2) STR_CASE(GL_RGB16F) STR_CASE(GL_RGB32F) STR_CASE(GL_RGBA16F) STR_CASE(GL_RGBA32F) STR_CASE(GL_RGB8I) STR_CASE(GL_RGB16I) STR_CASE(GL_RGB32I) STR_CASE(GL_RGB8UI) STR_CASE(GL_RGB16UI) STR_CASE(GL_RGB32UI) STR_CASE(GL_RGBA8I) STR_CASE(GL_RGBA16I) STR_CASE(GL_RGBA32I) STR_CASE(GL_RGBA8UI) STR_CASE(GL_RGBA16UI) STR_CASE(GL_RGBA32UI) STR_CASE(GL_R16F) STR_CASE(GL_R32F) STR_CASE(GL_RG16F) STR_CASE(GL_RG32F) STR_CASE(GL_R8) STR_CASE(GL_R8I) STR_CASE(GL_R8UI) STR_CASE(GL_R16) STR_CASE(GL_R16I) STR_CASE(GL_R16UI) STR_CASE(GL_R32I) STR_CASE(GL_R32UI) STR_CASE(GL_RG) STR_CASE(GL_RG8) STR_CASE(GL_RG8I) STR_CASE(GL_RG8UI) STR_CASE(GL_RG16) STR_CASE(GL_RG16I) STR_CASE(GL_RG16UI) STR_CASE(GL_RG32I) STR_CASE(GL_RG32UI) STR_CASE(GL_R11F_G11F_B10F) STR_CASE(GL_RGB9_E5) STR_CASE(GL_DEPTH_STENCIL) STR_CASE(GL_DEPTH24_STENCIL8) STR_CASE(GL_DEPTH32F_STENCIL8) STR_CASE(GL_DEPTH_COMPONENT32F) STR_CASE(GL_STENCIL_INDEX8) STR_CASE(GL_STENCIL_INDEX1) STR_CASE(GL_STENCIL_INDEX4) STR_CASE(GL_STENCIL_INDEX16) STR_CASE(GL_R8_SNORM) STR_CASE(GL_R16_SNORM) STR_CASE(GL_RG8_SNORM) STR_CASE(GL_RG16_SNORM) STR_CASE(GL_RGB8_SNORM) STR_CASE(GL_RGB16_SNORM) STR_CASE(GL_RGBA8_SNORM) STR_CASE(GL_RGBA16_SNORM) STR_CASE(GL_RGB10_A2UI) STR_CASE(GL_RGB565) STR_CASE(GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT) STR_CASE(GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT) STR_CASE(GL_COMPRESSED_RGBA_BPTC_UNORM) STR_CASE(GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM) STR_CASE(GL_COMPRESSED_R11_EAC) STR_CASE(GL_COMPRESSED_RG11_EAC) STR_CASE(GL_COMPRESSED_SIGNED_R11_EAC) STR_CASE(GL_COMPRESSED_SIGNED_RG11_EAC) STR_CASE(GL_COMPRESSED_RGB8_ETC2) STR_CASE(GL_COMPRESSED_SRGB8_ETC2) STR_CASE(GL_COMPRESSED_RGBA8_ETC2_EAC) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC) STR_CASE(GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2) STR_CASE(GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2) STR_CASE(GL_COMPRESSED_RGBA_ASTC_4x4_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_5x4_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_5x5_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_6x5_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_6x6_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x5_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x6_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_8x8_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x5_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x6_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x8_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_10x10_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_12x10_KHR) STR_CASE(GL_COMPRESSED_RGBA_ASTC_12x12_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR) STR_CASE(GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR) default: return str_enum_(internal_format); } }