Browse Source

Added support for flipping DXT1,3,5 compressed images vertically.

Lasse Öörni 11 years ago
parent
commit
0330a94d42

+ 53 - 0
Source/Engine/Resource/Decompress.cpp

@@ -943,4 +943,57 @@ void DecompressImagePVRTC(unsigned char* dest, const void *blocks, int width, in
     }
 }
 
+void FlipBlockVertical(unsigned char* dest, unsigned char* src, CompressedFormat format)
+{
+    switch (format)
+    {
+    case CF_DXT1:
+        for (unsigned i = 0; i < 4; ++i)
+        {
+            dest[i] = src[i];
+            dest[i + 4] = src[7 - i];
+        }
+        break;
+        
+    case CF_DXT3:
+        for (unsigned i = 0; i < 8; i += 2)
+        {
+            dest[i] = src[6 - i];
+            dest[i + 1] = src[6 - i + 1];
+        }
+        for (unsigned i = 0; i < 4; ++i)
+        {
+            dest[i + 8] = src[i + 8];
+            dest[i + 12] = src[15 - i];
+        }
+        break;
+        
+    case CF_DXT5:
+        dest[0] = src[0];
+        dest[1] = src[1];
+        {
+            unsigned a1 = src[2] | ((unsigned)src[3] << 8) | ((unsigned)src[4] << 16);
+            unsigned a2 = src[5] | ((unsigned)src[6] << 8) | ((unsigned)src[7] << 16);
+            unsigned b1 = ((a1 & 0x000fff) << 12) | (a1 & 0xfff000) >> 12;
+            unsigned b2 = ((a2 & 0x000fff) << 12) | (a2 & 0xfff000) >> 12;
+            dest[2] = b2 & 0xff;
+            dest[3] = (b2 >> 8) & 0xff;
+            dest[4] = (b2 >> 16) & 0xff;
+            dest[5] = b1 & 0xff;
+            dest[6] = (b1 >> 8) & 0xff;
+            dest[7] = (b1 >> 16) & 0xff;
+        }
+        for (unsigned i = 0; i < 4; ++i)
+        {
+            dest[i + 8] = src[i + 8];
+            dest[i + 12] = src[15 - i];
+        }
+        break;
+        
+    default:
+        /// ETC1 & PVRTC not yet implemented
+        break;
+    }
+}
+
 }

+ 2 - 0
Source/Engine/Resource/Decompress.h

@@ -33,5 +33,7 @@ URHO3D_API void DecompressImageDXT(unsigned char* dest, const void* blocks, int
 URHO3D_API void DecompressImageETC(unsigned char* dest, const void* blocks, int width, int height);
 /// Decompress a PVRTC compressed image to RGBA.
 URHO3D_API void DecompressImagePVRTC(unsigned char* dest, const void* blocks, int width, int height, CompressedFormat format);
+/// Flip a compressed block.
+URHO3D_API void FlipBlockVertical(unsigned char* dest, unsigned char* src, CompressedFormat format);
 
 }

+ 43 - 11
Source/Engine/Resource/Image.cpp

@@ -654,25 +654,57 @@ void Image::FlipVertical()
     if (!data_)
         return;
 
-    if (IsCompressed())
-    {
-        LOGERROR("FlipVertical not supported for compressed images");
-        return;
-    }
-
     if (depth_ > 1)
     {
         LOGERROR("FlipVertical not supported for 3D images");
         return;
     }
 
-    SharedArrayPtr<unsigned char> newData(new unsigned char[width_ * height_ * components_]);
-    unsigned rowSize = width_ * components_;
+    if (!IsCompressed())
+    {
+        SharedArrayPtr<unsigned char> newData(new unsigned char[width_ * height_ * components_]);
+        unsigned rowSize = width_ * components_;
 
-    for (int y = 0; y < height_; ++y)
-        memcpy(&newData[(height_ - y - 1) * rowSize], &data_[y * rowSize], rowSize);
+        for (int y = 0; y < height_; ++y)
+            memcpy(&newData[(height_ - y - 1) * rowSize], &data_[y * rowSize], rowSize);
 
-    data_ = newData;
+        data_ = newData;
+    }
+    else
+    {
+        if (compressedFormat_ > CF_DXT5)
+        {
+            LOGERROR("FlipVertical not yet implemented for other compressed formats than DXT1,3,5");
+            return;
+        }
+        
+        // Memory use = combined size of the compressed mip levels
+        SharedArrayPtr<unsigned char> newData(new unsigned char[GetMemoryUse()]);
+        unsigned dataOffset = 0;
+        
+        for (unsigned i = 0; i < numCompressedLevels_; ++i)
+        {
+            CompressedLevel level = GetCompressedLevel(i);
+            if (!level.data_)
+            {
+                LOGERROR("Got compressed level with no data, aborting vertical flip");
+                return;
+            }
+            
+            for (unsigned y = 0; y < level.rows_; ++y)
+            {
+                unsigned char* src = level.data_ + y * level.rowSize_;
+                unsigned char* dest = newData.Get() + dataOffset + (level.rows_ - y - 1) * level.rowSize_;
+                
+                for (unsigned x = 0; x < level.rowSize_; x += level.blockSize_)
+                    FlipBlockVertical(dest + x, src + x, compressedFormat_);
+            }
+            
+            dataOffset += level.dataSize_;
+        }
+        
+        data_ = newData;
+    }
 }
 
 bool Image::Resize(int width, int height)