From bc311a445ef97f179d02f27affbf0bbfab6f9f16 Mon Sep 17 00:00:00 2001 From: Benau Date: Sat, 19 Nov 2022 16:01:54 +0800 Subject: [PATCH] Use libsquish for skybox texture compression --- src/graphics/skybox.cpp | 120 ++++++++++++++++++++++++++++++++-------- 1 file changed, 98 insertions(+), 22 deletions(-) diff --git a/src/graphics/skybox.cpp b/src/graphics/skybox.cpp index c4e64fbfc..87d7a9671 100644 --- a/src/graphics/skybox.cpp +++ b/src/graphics/skybox.cpp @@ -18,15 +18,26 @@ #ifndef SERVER_ONLY #include "graphics/skybox.hpp" +#include "config/stk_config.hpp" #include "graphics/central_settings.hpp" #include "graphics/irr_driver.hpp" +#include "graphics/sp/sp_base.hpp" #include "graphics/texture_shader.hpp" +#include + #include #include #include +#include +extern "C" +{ + #include + #include +} + using namespace irr; @@ -137,6 +148,9 @@ namespace { } //namespace +// ============================================================================ +extern "C" void squishCompressImage(uint8_t* rgba, int width, int height, + int pitch, void* blocks, unsigned flags); // ---------------------------------------------------------------------------- /** Generate an opengl cubemap texture from 6 2d textures */ void Skybox::generateCubeMapFromTextures() @@ -160,16 +174,22 @@ void Skybox::generateCubeMapFromTextures() { unsigned idx = texture_permutation[i]; video::IImage* img = m_skybox_textures[idx]; -#if defined(USE_GLES2) - uint8_t* data = (uint8_t*)img->lock(); - for (unsigned int j = 0; j < - img->getDimension().Width * img->getDimension().Height; j++) - { - uint8_t tmp_val = data[j * 4]; - data[j * 4] = data[j * 4 + 2]; - data[j * 4 + 2] = tmp_val; - } + + bool is_gles = false; +#ifdef USE_GLES2 + is_gles = true; #endif + if (CVS->isTextureCompressionEnabled() || is_gles) + { + uint8_t* data = (uint8_t*)img->lock(); + for (unsigned int j = 0; j < + img->getDimension().Width * img->getDimension().Height; j++) + { + uint8_t tmp_val = data[j * 4]; + data[j * 4] = data[j * 4 + 2]; + data[j * 4 + 2] = tmp_val; + } + } img->copyToScaling(rgba[i], size, size); @@ -188,24 +208,80 @@ void Skybox::generateCubeMapFromTextures() } img->drop(); + bool needs_srgb_format = CVS->isDeferredEnabled(); glBindTexture(GL_TEXTURE_CUBE_MAP, m_cube_map); - bool needs_srgb_format = CVS->isDeferredEnabled(); - - GLint format = GL_RGBA; - GLint internal_format = needs_srgb_format ? GL_SRGB8_ALPHA8 : GL_RGBA8; -#if !defined(USE_GLES2) + const unsigned tc_flag = squish::kDxt5 | stk_config->m_tc_quality; if (CVS->isTextureCompressionEnabled()) - internal_format = needs_srgb_format ? GL_COMPRESSED_SRGB_ALPHA - : GL_COMPRESSED_RGBA; - format = GL_BGRA; -#endif + { + unsigned tex_size = GE::get4x4CompressedTextureSize(size, size); + uint8_t* compressed = new uint8_t[tex_size]; + squishCompressImage((uint8_t*)rgba[i], size, size, size * 4, + compressed, tc_flag); + GLint internal_format = needs_srgb_format ? + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, + internal_format, size, size, 0, tex_size, compressed); + delete[] compressed; + } + else + { + GLint format = GL_BGRA; + if (is_gles) + format = GL_RGBA; + GLint internal_format = needs_srgb_format ? GL_SRGB8_ALPHA8 : GL_RGBA8; + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, + internal_format, size, size, 0, format, + GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); + } - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, - internal_format, size, size, 0, format, - GL_UNSIGNED_BYTE, (GLvoid*)rgba[i]); + if (CVS->isTextureCompressionEnabled()) + { + imMipmapCascade cascade; + imReduceOptions options; + imReduceSetOptions(&options, IM_REDUCE_FILTER_LINEAR/*filter*/, + 2/*hopcount*/, 2.0f/*alpha*/, 1.0f/*amplifynormal*/, + 0.0f/*normalsustainfactor*/); +#ifdef DEBUG + int ret = imBuildMipmapCascade(&cascade, rgba[i], size, size, + 1/*layercount*/, 4, size * 4, &options, 0); + assert(ret == 1); +#else + imBuildMipmapCascade(&cascade, rgba[i], size, size, + 1/*layercount*/, 4, size * 4, &options, 0); +#endif + std::vector mipmap_sizes; + unsigned width = size; + while (true) + { + width = width < 2 ? 1 : width >> 1; + mipmap_sizes.push_back(width); + if (width == 1) + break; + } + for (unsigned mip = 0; mip < mipmap_sizes.size(); mip++) + { + unsigned cur_size = mipmap_sizes[mip]; + unsigned tex_size = GE::get4x4CompressedTextureSize(cur_size, + cur_size); + uint8_t* compressed = new uint8_t[tex_size]; + squishCompressImage((uint8_t*)cascade.mipmap[mip + 1], + cur_size, cur_size, cur_size * 4, compressed, tc_flag); + GLint internal_format = needs_srgb_format ? + GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : + GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; + glCompressedTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, + mip + 1, internal_format, cur_size, cur_size, 0, tex_size, + compressed); + delete[] compressed; + } + imFreeMipmapCascade(&cascade); + } } - glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + if (!CVS->isTextureCompressionEnabled()) + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); for (unsigned i = 0; i < 6; i++) delete[] rgba[i]; } // generateCubeMapFromTextures