Browse Source

Fixed missing horizontal flip from the vertical cross cubemap layout.

Lasse Öörni 11 years ago
parent
commit
5ce05d4cb6

+ 3 - 0
Source/Engine/Graphics/Direct3D9/D3D9TextureCube.cpp

@@ -168,7 +168,10 @@ bool TextureCube::BeginLoad(Deserializer& source)
             loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight);
             loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 3, faceWidth, faceHeight);
             if (loadImages_[FACE_NEGATIVE_Z])
+            {
                 loadImages_[FACE_NEGATIVE_Z]->FlipVertical();
+                loadImages_[FACE_NEGATIVE_Z]->FlipHorizontal();
+            }
             break;
             
         case CML_BLENDER:

+ 3 - 0
Source/Engine/Graphics/OpenGL/OGLTextureCube.cpp

@@ -169,7 +169,10 @@ bool TextureCube::BeginLoad(Deserializer& source)
             loadImages_[FACE_NEGATIVE_Y] = GetTileImage(image, 1, 2, faceWidth, faceHeight);
             loadImages_[FACE_NEGATIVE_Z] = GetTileImage(image, 1, 3, faceWidth, faceHeight);
             if (loadImages_[FACE_NEGATIVE_Z])
+            {
                 loadImages_[FACE_NEGATIVE_Z]->FlipVertical();
+                loadImages_[FACE_NEGATIVE_Z]->FlipHorizontal();
+            }
             break;
             
         case CML_BLENDER:

+ 1 - 0
Source/Engine/LuaScript/pkgs/Resource/Image.pkg

@@ -26,6 +26,7 @@ class Image : public Resource
     void SetPixelInt(int x, int y, int z, unsigned uintColor);
     bool LoadColorLUT(Deserializer& source);
     tolua_outside bool ImageLoadColorLUT @ LoadColorLUT(const String fileName);
+    bool FlipHorizontal();
     bool FlipVertical();
     bool Resize(int width, int height);
     void Clear(const Color& color);

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

@@ -996,4 +996,69 @@ void FlipBlockVertical(unsigned char* dest, unsigned char* src, CompressedFormat
     }
 }
 
+static unsigned char FlipDXT1Horizontal(unsigned char src)
+{
+    return ((src & 0x3) << 6) | ((src & 0xc) << 2) | ((src & 0x30) >> 2) | ((src & 0xc0) >> 6);
+}
+
+static unsigned FlipDXT5AlphaHorizontal(unsigned src)
+{
+    // Works on 2 lines at a time
+    return ((src & 0x7) << 9) | ((src & 0x38) << 3) | ((src & 0x1c0) >> 3) | ((src & 0xe00) >> 9) |
+        ((src & 0x7000) << 9) | ((src & 0x38000) << 3) | ((src & 0x1c0000) >> 3) | ((src & 0xe00000) >> 9);
+}
+
+void FlipBlockHorizontal(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] = FlipDXT1Horizontal(src[i + 4]);
+        }
+        break;
+        
+    case CF_DXT3:
+        for (unsigned i = 0; i < 8; i += 2)
+        {
+            dest[i] = ((src[i+1] & 0xf0) >> 4) | ((src[i+1] & 0xf) << 4);
+            dest[i+1] = ((src[i] & 0xf0) >> 4) | ((src[i] & 0xf) << 4);
+        }
+        for (unsigned i = 0; i < 4; ++i)
+        {
+            dest[i + 8] = src[i + 8];
+            dest[i + 12] = FlipDXT1Horizontal(src[i + 12]);
+        }
+        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 = FlipDXT5AlphaHorizontal(a1);
+            unsigned b2 = FlipDXT5AlphaHorizontal(a2);
+            dest[2] = b1 & 0xff;
+            dest[3] = (b1 >> 8) & 0xff;
+            dest[4] = (b1 >> 16) & 0xff;
+            dest[5] = b2 & 0xff;
+            dest[6] = (b2 >> 8) & 0xff;
+            dest[7] = (b2 >> 16) & 0xff;
+        }
+        for (unsigned i = 0; i < 4; ++i)
+        {
+            dest[i + 8] = src[i + 8];
+            dest[i + 12] = FlipDXT1Horizontal(src[i + 12]);
+        }
+        break;
+        
+    default:
+        /// ETC1 & PVRTC not yet implemented
+        break;
+    }
+}
+
 }

+ 3 - 1
Source/Engine/Resource/Decompress.h

@@ -33,7 +33,9 @@ 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.
+/// Flip a compressed block vertically.
 URHO3D_API void FlipBlockVertical(unsigned char* dest, unsigned char* src, CompressedFormat format);
+/// Flip a compressed block horizontally.
+URHO3D_API void FlipBlockHorizontal(unsigned char* dest, unsigned char* src, CompressedFormat format);
 
 }

+ 67 - 0
Source/Engine/Resource/Image.cpp

@@ -649,6 +649,73 @@ bool Image::LoadColorLUT(Deserializer& source)
     return true;
 }
 
+bool Image::FlipHorizontal()
+{
+    if (!data_)
+        return false;
+
+    if (depth_ > 1)
+    {
+        LOGERROR("FlipHorizontal not supported for 3D images");
+        return false;
+    }
+
+    if (!IsCompressed())
+    {
+        SharedArrayPtr<unsigned char> newData(new unsigned char[width_ * height_ * components_]);
+        unsigned rowSize = width_ * components_;
+
+        for (int y = 0; y < height_; ++y)
+        {
+            for (int x = 0; x < width_; ++x)
+            {
+                for (unsigned c = 0; c < components_; ++c)
+                    newData[y * rowSize + x * components_ + c] = data_[y * rowSize + (width_ - x - 1) * components_ + c];
+            }
+        }
+        
+        data_ = newData;
+    }
+    else
+    {
+        if (compressedFormat_ > CF_DXT5)
+        {
+            LOGERROR("FlipHorizontal not yet implemented for other compressed formats than DXT1,3,5");
+            return false;
+        }
+        
+        // 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 horizontal flip");
+                return false;
+            }
+            
+            for (unsigned y = 0; y < level.rows_; ++y)
+            {
+                for (unsigned x = 0; x < level.rowSize_; x += level.blockSize_)
+                {
+                    unsigned char* src = level.data_ + y * level.rowSize_ + (level.rowSize_ - level.blockSize_ - x);
+                    unsigned char* dest = newData.Get() + y * level.rowSize_ + x;
+                    FlipBlockHorizontal(dest, src, compressedFormat_);
+                }
+            }
+            
+            dataOffset += level.dataSize_;
+        }
+        
+        data_ = newData;
+    }
+    
+    return true;
+}
+
 bool Image::FlipVertical()
 {
     if (!data_)

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

@@ -119,6 +119,8 @@ public:
     void SetPixelInt(int x, int y, int z, unsigned uintColor);
     /// Load as color LUT. Return true if successful.
     bool LoadColorLUT(Deserializer& source);
+    /// Flip image horizontally. Return true if successful.
+    bool FlipHorizontal();
     /// Flip image vertically. Return true if successful.
     bool FlipVertical();
     /// Resize image by bilinear resampling. Return true if successful.

+ 1 - 0
Source/Engine/Script/ResourceAPI.cpp

@@ -162,6 +162,7 @@ static void RegisterImage(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Image", "void SetPixelInt(int, int, int, uint)", asMETHODPR(Image, SetPixelInt, (int, int, int, unsigned), void), asCALL_THISCALL);
     engine->RegisterObjectMethod("Image", "bool LoadColorLUT(File@+)", asFUNCTION(ImageLoadColorLUT), asCALL_CDECL_OBJLAST);
     engine->RegisterObjectMethod("Image", "bool LoadColorLUT(VectorBuffer&)", asFUNCTION(ImageLoadColorLUTVectorBuffer), asCALL_CDECL_OBJLAST);
+    engine->RegisterObjectMethod("Image", "bool FlipHorizontal()", asMETHOD(Image, FlipHorizontal), asCALL_THISCALL);
     engine->RegisterObjectMethod("Image", "bool FlipVertical()", asMETHOD(Image, FlipVertical), asCALL_THISCALL);
     engine->RegisterObjectMethod("Image", "bool Resize(int, int)", asMETHOD(Image, Resize), asCALL_THISCALL);
     engine->RegisterObjectMethod("Image", "void Clear(const Color&in)", asMETHOD(Image, Clear), asCALL_THISCALL);