Browse Source

Fix ETC1/ETC2 decompression error. (#2553)

Fix ETC1/ETC2 decompression error by using 4x4 local buffer.
Initializing ETCPACK in DecompressImageETC.
ssinai1 6 years ago
parent
commit
1ab1f07144
1 changed files with 29 additions and 5 deletions
  1. 29 5
      Source/Urho3D/Resource/Decompress.cpp

+ 29 - 5
Source/Urho3D/Resource/Decompress.cpp

@@ -32,6 +32,7 @@ typedef short int16;
 // Implemented by ETCPACK
 // Implemented by ETCPACK
 extern void decompressBlockAlphaC(uint8* data, uint8* img, int width, int height, int ix, int iy, int channels);
 extern void decompressBlockAlphaC(uint8* data, uint8* img, int width, int height, int ix, int iy, int channels);
 extern void decompressBlockETC2c(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty, int channels);
 extern void decompressBlockETC2c(unsigned int block_part1, unsigned int block_part2, uint8 *img, int width, int height, int startx, int starty, int channels);
+extern void setupAlphaTable();
 
 
 // DXT decompression based on the Squish library, modified for Urho3D
 // DXT decompression based on the Squish library, modified for Urho3D
 
 
@@ -908,19 +909,27 @@ static void ReadBigEndian4byteWord(uint32_t* pBlock, const unsigned char *s)
 // Use ETCPACK to decompress ETC texture.
 // Use ETCPACK to decompress ETC texture.
 void DecompressImageETC(unsigned char* dstImage, const void* blocks, int width, int height, bool hasAlpha)
 void DecompressImageETC(unsigned char* dstImage, const void* blocks, int width, int height, bool hasAlpha)
 {
 {
+    // ETCPACK initialization.
+    static const bool placeholder = []() { setupAlphaTable(); return true; }();
+
     const int channelCount = hasAlpha ? 4 : 3;
     const int channelCount = hasAlpha ? 4 : 3;
     unsigned char* src = (unsigned char*)blocks;
     unsigned char* src = (unsigned char*)blocks;
     unsigned int blockPart1, blockPart2;
     unsigned int blockPart1, blockPart2;
 
 
-    memset(dstImage, 0xFF, width * height * 4);
+    // ETCPACK write 4x4 blocks, so it needs padding.
+    int w4 = ((width + 3) / 4);
+    int h4 = ((height + 3) / 4);
+
+    unsigned char buffer4x4[4 * 4 * 4];
 
 
-    for (int y = 0; y < height / 4; ++y) 
+    for (int y = 0; y < h4; ++y) 
     {
     {
-        for (int x = 0; x < width / 4; ++x) 
+        for (int x = 0; x < w4; ++x) 
         {
         {
+            memset(&buffer4x4[0], 0xFF, 4 * 4 * 4);
             if (hasAlpha)
             if (hasAlpha)
             {
             {
-                decompressBlockAlphaC(src, dstImage + 3, width, height, 4 * x, 4 * y, channelCount);
+                decompressBlockAlphaC(src, &buffer4x4[3], 4, 4, 0, 0, channelCount);
                 src += 8;
                 src += 8;
             }
             }
 
 
@@ -928,7 +937,22 @@ void DecompressImageETC(unsigned char* dstImage, const void* blocks, int width,
             src += 4;
             src += 4;
             ReadBigEndian4byteWord(&blockPart2, src);
             ReadBigEndian4byteWord(&blockPart2, src);
             src += 4;
             src += 4;
-            decompressBlockETC2c(blockPart1, blockPart2, dstImage, width, height, 4 * x, 4 * y, 4);
+            decompressBlockETC2c(blockPart1, blockPart2, &buffer4x4[0], 4, 4, 0, 0, 4);
+
+            int wbuf = Min(width - x * 4, 4);
+            int hbuf = Min(height - y * 4, 4);
+            for(int dy = 0; dy < hbuf; ++dy)
+            {
+                for (int dx = 0; dx < wbuf; ++dx)
+                {
+                    int idst = ((y * 4 + dy) * width + x * 4 + dx) * 4;
+                    int ibuf = (dy * 4 + dx) * 4;
+                    dstImage[idst] = buffer4x4[ibuf];
+                    dstImage[idst + 1] = buffer4x4[ibuf + 1];
+                    dstImage[idst + 2] = buffer4x4[ibuf + 2];
+                    dstImage[idst + 3] = buffer4x4[ibuf + 3];
+                }
+            }
         }
         }
     }
     }
 }
 }