Browse Source

Started work on PVRTC texture format support.

Lasse Öörni 13 years ago
parent
commit
729df6e65b

+ 14 - 0
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -143,6 +143,7 @@ Graphics::Graphics(Context* context_) :
     hardwareDepthSupport_(false),
     dxtTextureSupport_(false),
     etcTextureSupport_(false),
+    pvrtcTextureSupport_(false),
     numPrimitives_(0),
     numBatches_(0),
     defaultTextureFilterMode_(FILTER_BILINEAR),
@@ -305,6 +306,7 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool vsync, bool
         #else
         dxtTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
         etcTextureSupport_ = CheckExtension("OES_compressed_ETC1_RGB8_texture");
+        pvrtcTextureSupport_ = CheckExtension("IMG_texture_compression_pvrtc");
         #endif
     }
     
@@ -1601,6 +1603,18 @@ unsigned Graphics::GetFormat(CompressedFormat format) const
     #else
     case CF_ETC1:
         return etcTextureSupport_ ? GL_ETC1_RGB8_OES : 0;
+        
+    case CF_PVRTC_RGB_2BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_2BPPV1_IMG : 0;
+        
+    case CF_PVRTC_RGB_4BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGB_PVRTC_4BPPV1_IMG : 0;
+        
+    case CF_PVRTC_RGBA_2BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_2BPPV1_IMG : 0;
+        
+    case CF_PVRTC_RGBA_4BPP:
+        return pvrtcTextureSupport_ ? COMPRESSED_RGBA_PVRTC_4BPPV1_IMG : 0;
     #endif
     }
     

+ 2 - 0
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -392,6 +392,8 @@ private:
     bool dxtTextureSupport_;
     /// ETC1 format support flag.
     bool etcTextureSupport_;
+    /// PVRTC formats support flag.
+    bool pvrtcTextureSupport_;
     /// Number of primitives this frame.
     unsigned numPrimitives_;
     /// Number of batches this frame.

+ 11 - 1
Engine/Graphics/OpenGL/OGLGraphicsImpl.h

@@ -37,13 +37,23 @@
 #include <GLee.h>
 #endif
 
-#ifdef GL_ES_VERSION_2_0
 #ifndef GL_COMPRESSED_RGBA_S3TC_DXT1_EXT
 #define GL_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83f1
 #endif
 #ifndef GL_ETC1_RGB8_OES
 #define GL_ETC1_RGB8_OES 0x8d64
 #endif
+#ifndef COMPRESSED_RGB_PVRTC_4BPPV1_IMG
+#define COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8c00
+#endif
+#ifndef COMPRESSED_RGB_PVRTC_2BPPV1_IMG
+#define COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8c01
+#endif
+#ifndef COMPRESSED_RGBA_PVRTC_4BPPV1_IMG
+#define COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8c02
+#endif
+#ifndef COMPRESSED_RGBA_PVRTC_2BPPV1_IMG
+#define COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8c03
 #endif
 
 #include <SDL.h>

+ 17 - 4
Engine/Graphics/OpenGL/OGLTexture.cpp

@@ -235,7 +235,14 @@ TextureUsage Texture::GetUsage() const
 unsigned Texture::GetDataSize(int width, int height) const
 {
     if (IsCompressed())
-        return GetRowDataSize(width) * ((height + 3) >> 2);
+    {
+        if (format_ == COMPRESSED_RGB_PVRTC_4BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_4BPPV1_IMG)
+            return (Max(width_, 8) * Max(height_, 8) * 4 + 7) >> 3;
+        else if (format_ == COMPRESSED_RGB_PVRTC_2BPPV1_IMG || format_ == COMPRESSED_RGBA_PVRTC_2BPPV1_IMG)
+            return (Max(width_, 8) * Max(height_, 8) * 2 + 7) >> 3;
+        else
+            return GetRowDataSize(width) * ((height + 3) >> 2);
+    }
     else
         return GetRowDataSize(width) * height;
 }
@@ -261,11 +268,9 @@ unsigned Texture::GetRowDataSize(int width) const
     #endif
         return width * 4;
         
-    #if !defined(GL_ES_VERSION_2_0) || defined(ANDROID)
     case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
         return ((width + 3) >> 2) * 8;
-    #endif
-    
+        
     #ifndef GL_ES_VERSION_2_0
     case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
     case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
@@ -273,6 +278,14 @@ unsigned Texture::GetRowDataSize(int width) const
     #else
     case GL_ETC1_RGB8_OES:
         return ((width + 3) >> 2) * 8;
+        
+    case COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
+    case COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
+        return (width * 4 + 7) >> 3;
+        
+    case COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
+    case COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
+        return (width * 2 + 7) >> 3;
     #endif
         
     default:

+ 176 - 28
Engine/Resource/Image.cpp

@@ -209,7 +209,7 @@ void Image::RegisterObject(Context* context)
 
 bool Image::Load(Deserializer& source)
 {
-    // Check for DDS or KTX compressed format
+    // Check for DDS, KTX or PVR compressed format
     String fileID = source.ReadFileID();
     
     if (fileID == "DDS ")
@@ -314,11 +314,31 @@ bool Image::Load(Deserializer& source)
             compressedFormat_ = CF_ETC1;
             components_ = 3;
             break;
+            
+        case 0x8c00:
+            compressedFormat_ = CF_PVRTC_RGB_4BPP;
+            components_ = 3;
+            break;
+            
+        case 0x8c01:
+            compressedFormat_ = CF_PVRTC_RGB_2BPP;
+            components_ = 3;
+            break;
+            
+        case 0x8c02:
+            compressedFormat_ = CF_PVRTC_RGBA_4BPP;
+            components_ = 4;
+            break;
+            
+        case 0x8c03:
+            compressedFormat_ = CF_PVRTC_RGBA_2BPP;
+            components_ = 4;
+            break;
         }
         
         if (compressedFormat_ == CF_NONE)
         {
-            LOGERROR("Unrecognized texture format in KTX file");
+            LOGERROR("Unsupported texture format in KTX file");
             return false;
         }
         
@@ -340,9 +360,97 @@ bool Image::Load(Deserializer& source)
         
         SetMemoryUse(dataSize);
     }
+    else if (fileID == "PVR\3")
+    {
+        unsigned flags = source.ReadUInt();
+        unsigned pixelFormatLo = source.ReadUInt();
+        unsigned pixelFormatHi = source.ReadUInt();
+        unsigned colourSpace = source.ReadUInt();
+        unsigned channelType = source.ReadUInt();
+        unsigned height = source.ReadUInt();
+        unsigned width = source.ReadUInt();
+        unsigned depth = source.ReadUInt();
+        unsigned numSurfaces = source.ReadUInt();
+        unsigned numFaces = source.ReadUInt();
+        unsigned mipmapCount = source.ReadUInt();
+        unsigned metaDataSize = source.ReadUInt();
+        
+        if (depth > 1 || numFaces > 1)
+        {
+            LOGERROR("3D or cube PVR files not supported");
+            return false;
+        }
+        
+        if (mipmapCount == 0)
+        {
+            LOGERROR("PVR files without explicitly specified mipmap count not supported");
+            return false;
+        }
+        
+        compressedFormat_ = CF_NONE;
+        switch (pixelFormatLo)
+        {
+        case 0:
+            compressedFormat_ = CF_PVRTC_RGB_2BPP;
+            components_ = 3;
+            break;
+            
+        case 1:
+            compressedFormat_ = CF_PVRTC_RGBA_2BPP;
+            components_ = 4;
+            break;
+            
+        case 2:
+            compressedFormat_ = CF_PVRTC_RGB_4BPP;
+            components_ = 3;
+            break;
+            
+        case 3:
+            compressedFormat_ = CF_PVRTC_RGBA_4BPP;
+            components_ = 4;
+            break;
+            
+        case 6:
+            compressedFormat_ = CF_ETC1;
+            components_ = 3;
+            break;
+            
+        case 7:
+            compressedFormat_ = CF_DXT1;
+            components_ = 4;
+            break;
+            
+        case 9:
+            compressedFormat_ = CF_DXT3;
+            components_ = 4;
+            break;
+            
+        case 11:
+            compressedFormat_ = CF_DXT5;
+            components_ = 4;
+            break;
+        }
+        
+        if (compressedFormat_ == CF_NONE)
+        {
+            LOGERROR("Unsupported texture format in PVR file");
+            return false;
+        }
+        
+        source.Seek(source.GetPosition() + metaDataSize);
+        unsigned dataSize = source.GetSize() - source.GetPosition();
+        
+        data_ = new unsigned char[dataSize];
+        width_ = width;
+        height_ = height;
+        numCompressedLevels_ = mipmapCount;
+        
+        source.Read(data_.Get(), dataSize);
+        SetMemoryUse(dataSize);
+    }
     else
     {
-        // Not DDS or KTX, use STBImage to load other image formats as uncompressed
+        // Not DDS, KTX or PVR, use STBImage to load other image formats as uncompressed
         source.Seek(0);
         int width, height;
         unsigned components;
@@ -601,36 +709,76 @@ CompressedLevel Image::GetCompressedLevel(unsigned index) const
     level.compressedFormat_ = compressedFormat_;
     level.width_ = width_;
     level.height_ = height_;
-    level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
-    unsigned i = 0;
-    unsigned offset = 0;
     
-    for (;;)
+    if (compressedFormat_ < CF_PVRTC_RGB_2BPP)
     {
-        if (!level.width_)
-            level.width_ = 1;
-        if (!level.height_)
-            level.height_ = 1;
-        
-        level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
-        level.rows_ = ((level.height_ + 3) / 4);
-        level.data_ = data_.Get() + offset;
-        level.dataSize_ = level.rows_ * level.rowSize_;
+        level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
+        unsigned i = 0;
+        unsigned offset = 0;
         
-        if (offset + level.dataSize_ > GetMemoryUse())
+        for (;;)
         {
-            LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
-                " Datasize: " + String(GetMemoryUse()));
-            level.data_ = 0;
-            return level;
+            if (!level.width_)
+                level.width_ = 1;
+            if (!level.height_)
+                level.height_ = 1;
+            
+            level.rowSize_ = ((level.width_ + 3) / 4) * level.blockSize_;
+            level.rows_ = ((level.height_ + 3) / 4);
+            level.data_ = data_.Get() + offset;
+            level.dataSize_ = level.rows_ * level.rowSize_;
+            
+            if (offset + level.dataSize_ > GetMemoryUse())
+            {
+                LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
+                    " Datasize: " + String(GetMemoryUse()));
+                level.data_ = 0;
+                return level;
+            }
+            
+            if (i == index)
+                return level;
+            
+            offset += level.dataSize_;
+            level.width_ /= 2;
+            level.height_ /= 2;
+            ++i;
         }
+    }
+    else
+    {
+        level.blockSize_ = compressedFormat_ < CF_PVRTC_RGB_4BPP ? 2 : 4;
+        unsigned i = 0;
+        unsigned offset = 0;
         
-        if (i == index)
-            return level;
-        
-        offset += level.dataSize_;
-        level.width_ /= 2;
-        level.height_ /= 2;
-        ++i;
+        for (;;)
+        {
+            if (!level.width_)
+                level.width_ = 1;
+            if (!level.height_)
+                level.height_ = 1;
+            
+            int dataWidth = Max(level.width_, 8);
+            int dataHeight = Max(level.height_, 8);
+            level.dataSize_ = (dataWidth * dataHeight * level.blockSize_ + 7) >> 3;
+            level.rows_ = dataHeight;
+            level.rowSize_ = level.dataSize_ / level.rows_;
+            
+            if (offset + level.dataSize_ > GetMemoryUse())
+            {
+                LOGERROR("Compressed level is outside image data. Offset: " + String(offset) + " Size: " + String(level.dataSize_) +
+                    " Datasize: " + String(GetMemoryUse()));
+                level.data_ = 0;
+                return level;
+            }
+            
+            if (i == index)
+                return level;
+            
+            offset += level.dataSize_;
+            level.width_ /= 2;
+            level.height_ /= 2;
+            ++i;
+        }
     }
 }

+ 5 - 1
Engine/Resource/Image.h

@@ -33,7 +33,11 @@ enum CompressedFormat
     CF_DXT1,
     CF_DXT3,
     CF_DXT5,
-    CF_ETC1
+    CF_ETC1,
+    CF_PVRTC_RGB_2BPP,
+    CF_PVRTC_RGBA_2BPP,
+    CF_PVRTC_RGB_4BPP,
+    CF_PVRTC_RGBA_4BPP,
 };
 
 /// Compressed image mip level.