From 89b9acbb1d2c3222729b11cfed64d76ec62ebeff Mon Sep 17 00:00:00 2001 From: Adam Johnson Date: Thu, 12 Jun 2025 13:09:19 -0500 Subject: [PATCH] Properly export all mip levels. We can now properly export all mip levels without crashing, thanks to H-uru/libhsplasma#298 :) --- cmake/Dependencies.cmake | 2 +- korlib/texture.cpp | 17 +++++++++-------- korman/korlib/texture.py | 17 +++++++++-------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake index 3fe33b0..99abbca 100644 --- a/cmake/Dependencies.cmake +++ b/cmake/Dependencies.cmake @@ -273,7 +273,7 @@ if(korman_BUILD_HSPLASMA) korman_add_external_project(HSPlasma GIT_REPOSITORY "https://github.com/H-uru/libhsplasma.git" # Be sure to increase this as the feature set used by Korman increases - GIT_TAG 93fb48b5ce0911e0f58b731f7d7b3e4e5ccabfd8 + GIT_TAG 6bd82dfcddb3bec424c3d9c950847a49dd269d1f # We can only do shallow checkouts if the above is a branch or tag. GIT_SHALLOW FALSE CMAKE_CACHE_ARGS diff --git a/korlib/texture.cpp b/korlib/texture.cpp index 00182da..e1e2559 100644 --- a/korlib/texture.cpp +++ b/korlib/texture.cpp @@ -77,18 +77,19 @@ static inline bool _get_float(PyObject* source, const char* attr, float& result) static inline int _get_num_levels(size_t width, size_t height) { int num_levels = (int)std::floor(std::log2(std::max((float)width, (float)height))) + 1; - // Major Workaround Ahoy - // There is a bug in Cyan's level size algorithm that causes it to not allocate enough memory - // for the color block in certain mipmaps. I personally have encountered an access violation on - // 1x1 DXT5 mip levels -- the code only allocates an alpha block and not a color block. Paradox - // reports that if any dimension is smaller than 4px in a mip level, OpenGL doesn't like Cyan generated - // data. So, we're going to lop off the last two mip levels, which should be 1px and 2px as the smallest. - // This bug is basically unfixable without crazy hacks because of the way Plasma reads in texture data. + // Major Workaround No More! + // Previously, we lopped off the last two mip levels. DXT compression acts on 4x4 blocks, so + // it's not possible to DXT compress anything smaller than that. libHSPlasma used to not take + // that into account and would try to allocate memory for things like 2x2 and 1x1 mip levels. + // These allocations were never correct, and would crash the exporter when libHSPlasma tried to + // compress those too-small mip levels. As of libHSPlasma#298, mip levels smaller than 4x4 are + // stored uncompressed, so we can now use the technically correct level calculation from above. + // Technically correct is often the best kind of correct, but this is still relevant: // " I feel like any texture at a 1x1 level is essentially academic. I mean, JPEG/DXT // doesn't even compress that, and what is it? Just the average color of the whole // texture in a single pixel?" // :) - return std::max(num_levels - 2, 2); + return num_levels; } static void _scale_image(const uint8_t* srcBuf, const size_t srcW, const size_t srcH, diff --git a/korman/korlib/texture.py b/korman/korlib/texture.py index 68f1dc0..5d681cb 100644 --- a/korman/korlib/texture.py +++ b/korman/korlib/texture.py @@ -280,18 +280,19 @@ class GLTexture: def num_levels(self): numLevels = math.floor(math.log(max(self.size_npot), 2)) + 1 - # Major Workaround Ahoy - # There is a bug in Cyan's level size algorithm that causes it to not allocate enough memory - # for the color block in certain mipmaps. I personally have encountered an access violation on - # 1x1 DXT5 mip levels -- the code only allocates an alpha block and not a color block. Paradox - # reports that if any dimension is smaller than 4px in a mip level, OpenGL doesn't like Cyan generated - # data. So, we're going to lop off the last two mip levels, which should be 1px and 2px as the smallest. - # This bug is basically unfixable without crazy hacks because of the way Plasma reads in texture data. + # Major Workaround No More! + # Previously, we lopped off the last two mip levels. DXT compression acts on 4x4 blocks, so + # it's not possible to DXT compress anything smaller than that. libHSPlasma used to not take + # that into account and would try to allocate memory for things like 2x2 and 1x1 mip levels. + # These allocations were never correct, and would crash the exporter when libHSPlasma tried to + # compress those too-small mip levels. As of libHSPlasma#298, mip levels smaller than 4x4 are + # stored uncompressed, so we can now use the technically correct level calculation from above. + # Technically correct is often the best kind of correct, but this is still relevant: # " I feel like any texture at a 1x1 level is essentially academic. I mean, JPEG/DXT # doesn't even compress that, and what is it? Just the average color of the whole # texture in a single pixel?" # :) - return max(numLevels - 2, 2) + return numLevels @property def size_npot(self):