Explorar o código

Added loading of ETC1 compressed textures on mobile devices. These need to be stored inside .ktx files.
Removed unneeded texture.

Lasse Öörni %!s(int64=13) %!d(string=hai) anos
pai
achega
d7d599be7b

BIN=BIN
Bin/Data/Textures/DiffuseMask.dds


+ 1 - 1
Docs/Reference.dox

@@ -542,7 +542,7 @@ These differences need to be observed when using the low-level rendering functio
 
 OpenGL ES 2.0 has further limitations:
 
-- Only DXT1 compressed textures will be uploaded as compressed if the EXT_texture_compression_dxt1 extension is present. Other compressed texture formats will be uploaded as uncompressed RGBA. Mobile hardware specific compression formats such as ETC or PVRTC are not yet supported.
+- Of the DXT formats, only DXT1 compressed textures will be uploaded as compressed, and only if the EXT_texture_compression_dxt1 extension is present. Other DXT formats will be uploaded as uncompressed RGBA. ETC1 compressed textures are supported through the .ktx file extension.
 
 - %Light pre-pass and deferred rendering are not supported due to missing multiple rendertarget support, and limited rendertarget formats.
 

+ 0 - 1
Docs/ScriptAPI.dox

@@ -2326,7 +2326,6 @@ Properties:<br>
 - bool hardwareDepthSupport (readonly)
 - bool hardwareShadowSupport (readonly)
 - bool hiresShadowSupport (readonly)
-- bool compressedTextureSupport (readonly)
 - bool forceSM2
 - IntVector2[]@ resolutions (readonly)
 - int[]@ multiSampleLevels (readonly)

+ 0 - 1
Engine/Engine/GraphicsAPI.cpp

@@ -788,7 +788,6 @@ static void RegisterGraphics(asIScriptEngine* engine)
     engine->RegisterObjectMethod("Graphics", "bool get_hardwareDepthSupport() const", asMETHOD(Graphics, GetHardwareDepthSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_hardwareShadowSupport() const", asMETHOD(Graphics, GetHardwareShadowSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_hiresShadowSupport() const", asMETHOD(Graphics, GetHiresShadowSupport), asCALL_THISCALL);
-    engine->RegisterObjectMethod("Graphics", "bool get_compressedTextureSupport() const", asMETHOD(Graphics, GetCompressedTextureSupport), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "void set_forceSM2(bool)", asMETHOD(Graphics, SetForceSM2), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "bool get_forceSM2() const", asMETHOD(Graphics, GetForceSM2), asCALL_THISCALL);
     engine->RegisterObjectMethod("Graphics", "Array<IntVector2>@ get_resolutions() const", asFUNCTION(GraphicsGetResolutions), asCALL_CDECL_OBJLAST);

+ 1 - 0
Engine/Engine/ResourceAPI.cpp

@@ -23,6 +23,7 @@
 
 #include "Precompiled.h"
 #include "APITemplates.h"
+#include "Image.h"
 #include "PackageFile.h"
 #include "ResourceCache.h"
 

+ 17 - 0
Engine/Graphics/Direct3D9/D3D9Graphics.cpp

@@ -1712,6 +1712,23 @@ PODVector<int> Graphics::GetMultiSampleLevels() const
     return ret;
 }
 
+unsigned Graphics::GetFormat(CompressedFormat format) const
+{
+    switch (format)
+    {
+    case CF_DXT1:
+        return D3DFMT_DXT1;
+        
+    case CF_DXT3:
+        return D3DFMT_DXT3;
+        
+    case CF_DXT5:
+        return D3DFMT_DXT5;
+    }
+    
+    return 0;
+}
+
 VertexBuffer* Graphics::GetVertexBuffer(unsigned index) const
 {
     return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : 0;

+ 3 - 2
Engine/Graphics/Direct3D9/D3D9Graphics.h

@@ -26,6 +26,7 @@
 #include "ArrayPtr.h"
 #include "Color.h"
 #include "HashMap.h"
+#include "Image.h"
 #include "Object.h"
 #include "Rect.h"
 #include "GraphicsDefs.h"
@@ -236,12 +237,12 @@ public:
     bool GetHiresShadowSupport() const { return hiresShadowSupport_; }
     /// Return whether stream offset is supported.
     bool GetStreamOffsetSupport() const { return streamOffsetSupport_; }
-    /// Return whether DXT texture compression is supported. Always true on Direct3D9.
-    bool GetCompressedTextureSupport() const { return true; }
     /// Return supported fullscreen resolutions.
     PODVector<IntVector2> GetResolutions() const;
     /// Return supported multisampling levels.
     PODVector<int> GetMultiSampleLevels() const;
+    /// Return hardware format for a compressed image format, or 0 if unsupported.
+    unsigned GetFormat(CompressedFormat format) const;
     /// Return vertex buffer by index.
     VertexBuffer* GetVertexBuffer(unsigned index) const;
     /// Return current index buffer.

+ 0 - 17
Engine/Graphics/Direct3D9/D3D9Texture.cpp

@@ -185,23 +185,6 @@ unsigned Texture::GetRowDataSize(int width) const
     }
 }
 
-unsigned Texture::GetDXTFormat(CompressedFormat format)
-{
-    switch (format)
-    {
-    case CF_DXT1:
-        return D3DFMT_DXT1;
-        
-    case CF_DXT3:
-        return D3DFMT_DXT3;
-        
-    case CF_DXT5:
-        return D3DFMT_DXT5;
-    }
-    
-    return 0;
-}
-
 void Texture::LoadParameters()
 {
     ResourceCache* cache = GetSubsystem<ResourceCache>();

+ 0 - 2
Engine/Graphics/Direct3D9/D3D9Texture.h

@@ -86,8 +86,6 @@ public:
     unsigned GetDataSize(int width, int height) const;
     /// Return data size in bytes for a pixel or block row.
     unsigned GetRowDataSize(int width) const;
-    /// Return API-specific DXT compressed texture format.
-    static unsigned GetDXTFormat(CompressedFormat format);
     
     /// Load parameters.
     void LoadParameters();

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9Texture2D.cpp

@@ -334,7 +334,7 @@ bool Texture2D::Load(SharedPtr<Image> image, bool useAlpha)
         int width = image->GetWidth();
         int height = image->GetHeight();
         unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = GetDXTFormat(image->GetCompressedFormat());
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
         
         unsigned mipsToSkip = mipsToSkip_[quality];
         if (mipsToSkip >= levels)

+ 1 - 1
Engine/Graphics/Direct3D9/D3D9TextureCube.cpp

@@ -413,7 +413,7 @@ bool TextureCube::Load(CubeMapFace face, SharedPtr<Image> image, bool useAlpha)
         int width = image->GetWidth();
         int height = image->GetHeight();
         unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = GetDXTFormat(image->GetCompressedFormat());
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
         
         if (width != height)
         {

+ 28 - 3
Engine/Graphics/OpenGL/OGLGraphics.cpp

@@ -141,7 +141,7 @@ Graphics::Graphics(Context* context_) :
     lightPrepassSupport_(false),
     deferredSupport_(false),
     hardwareDepthSupport_(false),
-    compressedTextureSupport_(false),
+    dxtTextureSupport_(false),
     numPrimitives_(0),
     numBatches_(0),
     defaultTextureFilterMode_(FILTER_BILINEAR),
@@ -300,9 +300,9 @@ bool Graphics::SetMode(int width, int height, bool fullscreen, bool vsync, bool
             return false;
         }
         
-        compressedTextureSupport_ = CheckExtension("EXT_texture_compression_s3tc");
+        dxtTextureSupport_ = CheckExtension("EXT_texture_compression_s3tc");
         #else
-        compressedTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
+        dxtTextureSupport_ = CheckExtension("EXT_texture_compression_dxt1");
         #endif
     }
     
@@ -1583,6 +1583,31 @@ PODVector<int> Graphics::GetMultiSampleLevels() const
     return ret;
 }
 
+unsigned Graphics::GetFormat(CompressedFormat format) const
+{
+    switch (format)
+    {
+    #if !defined(GL_ES_VERSION_2_0) || defined(ANDROID)
+    case CF_DXT1:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT1_EXT : 0;
+    #endif
+        
+    #ifndef GL_ES_VERSION_2_0
+    case CF_DXT3:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : 0;
+        
+    case CF_DXT5:
+        return dxtTextureSupport_ ? GL_COMPRESSED_RGBA_S3TC_DXT5_EXT : 0;
+    #else
+    case CF_ETC1:
+        return GL_ETC1_RGB8_OES;
+    #endif
+    }
+    
+    return 0;
+}
+
+
 VertexBuffer* Graphics::GetVertexBuffer(unsigned index) const
 {
     return index < MAX_VERTEX_STREAMS ? vertexBuffers_[index] : 0;

+ 5 - 4
Engine/Graphics/OpenGL/OGLGraphics.h

@@ -27,6 +27,7 @@
 #include "Color.h"
 #include "GraphicsDefs.h"
 #include "HashMap.h"
+#include "Image.h"
 #include "Matrix3x4.h"
 #include "Object.h"
 #include "Rect.h"
@@ -244,12 +245,12 @@ public:
     bool GetHiresShadowSupport() const { return true; }
     /// Return whether stream offset is supported. Always false on OpenGL.
     bool GetStreamOffsetSupport() const { return false; }
-    /// Return whether DXT texture compression is supported.
-    bool GetCompressedTextureSupport() const { return compressedTextureSupport_; }
     /// Return supported fullscreen resolutions.
     PODVector<IntVector2> GetResolutions() const;
     /// Return supported multisampling levels.
     PODVector<int> GetMultiSampleLevels() const;
+    /// Return hardware format for a compressed image format, or 0 if unsupported.
+    unsigned GetFormat(CompressedFormat format) const;
     /// Return vertex buffer by index.
     VertexBuffer* GetVertexBuffer(unsigned index) const;
     /// Return index buffer.
@@ -387,8 +388,8 @@ private:
     bool deferredSupport_;
     /// Hardware depth support flag.
     bool hardwareDepthSupport_;
-    /// Compressed texture support flag.
-    bool compressedTextureSupport_;
+    /// DXT format support flag.
+    bool dxtTextureSupport_;
     /// Number of primitives this frame.
     unsigned numPrimitives_;
     /// Number of batches this frame.

+ 7 - 28
Engine/Graphics/OpenGL/OGLTexture.cpp

@@ -202,9 +202,9 @@ bool Texture::IsCompressed() const
         format_ == GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
     #else
     #ifdef ANDROID
-    return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+    return format_ == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT || format_ == GL_ETC1_RGB8_OES;
     #else
-    return false;
+    return format_ == GL_ETC1_RGB8_OES;
     #endif
     #endif
 }
@@ -265,11 +265,14 @@ unsigned Texture::GetRowDataSize(int width) const
     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:
         return ((width + 3) >> 2) * 16;
+    #else
+    case GL_ETC1_RGB8_OES:
+        return ((width + 3) >> 2) * 8;
     #endif
         
     default:
@@ -277,27 +280,6 @@ unsigned Texture::GetRowDataSize(int width) const
     }
 }
 
-unsigned Texture::GetDXTFormat(CompressedFormat format)
-{
-    switch (format)
-    {
-    #if !defined(GL_ES_VERSION_2_0) || defined(ANDROID)
-    case CF_DXT1:
-        return GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
-    #endif
-            
-    #ifndef GL_ES_VERSION_2_0
-    case CF_DXT3:
-        return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-        
-    case CF_DXT5:
-        return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-    #endif
-    }
-    
-    return 0;
-}
-
 unsigned Texture::GetExternalFormat(unsigned format)
 {
     #ifndef GL_ES_VERSION_2_0
@@ -311,10 +293,7 @@ unsigned Texture::GetExternalFormat(unsigned format)
     else
         return format;
     #else
-    if (format == GL_DEPTH_COMPONENT || format == GL_DEPTH_COMPONENT16 || format == GL_DEPTH_COMPONENT24_OES)
-        return GL_DEPTH_COMPONENT;
-    else
-        return format;
+    return format;
     #endif
 }
 

+ 0 - 3
Engine/Graphics/OpenGL/OGLTexture.h

@@ -27,7 +27,6 @@
 #include "Color.h"
 #include "GPUObject.h"
 #include "GraphicsDefs.h"
-#include "Image.h"
 #include "Resource.h"
 
 static const int MAX_TEXTURE_QUALITY_LEVELS = 3;
@@ -99,8 +98,6 @@ public:
     unsigned GetDataSize(int width, int height) const;
     /// Return data size in bytes for a pixel or block row.
     unsigned GetRowDataSize(int width) const;
-    /// Return API-specific compressed texture format.
-    static unsigned GetDXTFormat(CompressedFormat format);
     /// Return the non-internal texture format corresponding to an OpenGL internal format.
     static unsigned GetExternalFormat(unsigned format);
     /// Return the data type corresponding to an OpenGL internal format.

+ 2 - 2
Engine/Graphics/OpenGL/OGLTexture2D.cpp

@@ -280,10 +280,10 @@ bool Texture2D::Load(SharedPtr<Image> image, bool useAlpha)
         int width = image->GetWidth();
         int height = image->GetHeight();
         unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = GetDXTFormat(image->GetCompressedFormat());
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
         bool needDecompress = false;
         
-        if (!graphics_->GetCompressedTextureSupport() || !format)
+        if (!format)
         {
             format = Graphics::GetRGBAFormat();
             needDecompress = true;

+ 2 - 2
Engine/Graphics/OpenGL/OGLTextureCube.cpp

@@ -364,7 +364,7 @@ bool TextureCube::Load(CubeMapFace face, SharedPtr<Image> image, bool useAlpha)
         int width = image->GetWidth();
         int height = image->GetHeight();
         unsigned levels = image->GetNumCompressedLevels();
-        unsigned format = GetDXTFormat(image->GetCompressedFormat());
+        unsigned format = graphics_->GetFormat(image->GetCompressedFormat());
         bool needDecompress = false;
         
         if (width != height)
@@ -373,7 +373,7 @@ bool TextureCube::Load(CubeMapFace face, SharedPtr<Image> image, bool useAlpha)
             return false;
         }
         
-        if (!graphics_->GetCompressedTextureSupport() || !format)
+        if (!format)
         {
             format = Graphics::GetRGBAFormat();
             needDecompress = true;

+ 118 - 23
Engine/Resource/Image.cpp

@@ -162,7 +162,7 @@ struct DDSurfaceDesc2
     unsigned dwTextureStage_;
 };
 
-void CompressedLevel::Decompress(unsigned char* dest)
+bool CompressedLevel::Decompress(unsigned char* dest)
 {
     int flags = 0;
     
@@ -181,8 +181,11 @@ void CompressedLevel::Decompress(unsigned char* dest)
         break;
     }
     
-    if (data_)
-        squish::DecompressImage(dest, width_, height_, data_, flags);
+    if (!flags || !data_)
+        return false;
+    
+    squish::DecompressImage(dest, width_, height_, data_, flags);
+    return true;
 }
 
 OBJECTTYPESTATIC(Image);
@@ -206,24 +209,10 @@ void Image::RegisterObject(Context* context)
 
 bool Image::Load(Deserializer& source)
 {
-    // Check for DDS compressed format
-    if (source.ReadFileID() != "DDS ")
-    {
-        // Not DDS, use STBImage to load other image formats as uncompressed
-        source.Seek(0);
-        int width, height;
-        unsigned components;
-        unsigned char* pixelData = GetImageData(source, width, height, components);
-        if (!pixelData)
-        {
-            LOGERROR("Could not load image: " + String(stbi_failure_reason()));
-            return false;
-        }
-        SetSize(width, height, components);
-        SetData(pixelData);
-        FreeImageData(pixelData);
-    }
-    else
+    // Check for DDS or KTX compressed format
+    String fileID = source.ReadFileID();
+    
+    if (fileID == "DDS ")
     {
         // DDS compressed format
         DDSurfaceDesc2 ddsd;
@@ -250,7 +239,7 @@ bool Image::Load(Deserializer& source)
             LOGERROR("Unsupported DDS format");
             return false;
         }
-
+        
         unsigned dataSize = source.GetSize() - source.GetPosition();
         data_ = new unsigned char[dataSize];
         width_ = ddsd.dwWidth_;
@@ -261,6 +250,112 @@ bool Image::Load(Deserializer& source)
         SetMemoryUse(dataSize);
         source.Read(data_.Get(), dataSize);
     }
+    else if (fileID == "\253KTX")
+    {
+        source.Seek(12);
+        
+        unsigned endianness = source.ReadUInt();
+        unsigned type = source.ReadUInt();
+        unsigned typeSize = source.ReadUInt();
+        unsigned format = source.ReadUInt();
+        unsigned internalFormat = source.ReadUInt();
+        unsigned baseInternalFormat = source.ReadUInt();
+        unsigned width = source.ReadUInt();
+        unsigned height = source.ReadUInt();
+        unsigned depth = source.ReadUInt();
+        unsigned arrayElements = source.ReadUInt();
+        unsigned faces = source.ReadUInt();
+        unsigned mipmaps = source.ReadUInt();
+        unsigned keyValueBytes = source.ReadUInt();
+        
+        if (endianness != 0x04030201)
+        {
+            LOGERROR("Big-endian KTX files not supported");
+            return false;
+        }
+        
+        if (type != 0 || format != 0)
+        {
+            LOGERROR("Uncompressed KTX files not supported");
+            return false;
+        }
+        
+        if (faces > 1 || depth > 1)
+        {
+            LOGERROR("3D or cube KTX files not supported");
+            return false;
+        }
+        
+        if (mipmaps == 0)
+        {
+            LOGERROR("KTX files without explicitly specified mipmap count not supported");
+            return false;
+        }
+        
+        compressedFormat_ = CF_NONE;
+        switch (internalFormat)
+        {
+        case 0x83f1:
+            compressedFormat_ = CF_DXT1;
+            components_ = 4;
+            break;
+            
+        case 0x83f2:
+            compressedFormat_ = CF_DXT3;
+            components_ = 4;
+            break;
+            
+        case 0x83f3:
+            compressedFormat_ = CF_DXT5;
+            components_ = 4;
+            break;
+            
+        case 0x8d64:
+            compressedFormat_ = CF_ETC1;
+            components_ = 3;
+            break;
+        }
+        
+        if (compressedFormat_ == CF_NONE)
+        {
+            LOGERROR("Unrecognized texture format in KTX file");
+            return false;
+        }
+        
+        source.Seek(source.GetPosition() + keyValueBytes);
+        unsigned dataSize = source.GetSize() - source.GetPosition() - mipmaps * sizeof(unsigned);
+        
+        data_ = new unsigned char[dataSize];
+        width_ = width;
+        height_ = height;
+        numCompressedLevels_ = mipmaps;
+        
+        unsigned dataOffset = 0;
+        for (unsigned i = 0; i < mipmaps; ++i)
+        {
+            unsigned levelSize = source.ReadUInt();
+            source.Read(&data_[dataOffset], levelSize);
+            dataOffset += levelSize;
+        }
+        
+        SetMemoryUse(dataSize);
+    }
+    else
+    {
+        // Not DDS or KTX, use STBImage to load other image formats as uncompressed
+        source.Seek(0);
+        int width, height;
+        unsigned components;
+        unsigned char* pixelData = GetImageData(source, width, height, components);
+        if (!pixelData)
+        {
+            LOGERROR("Could not load image: " + String(stbi_failure_reason()));
+            return false;
+        }
+        SetSize(width, height, components);
+        SetData(pixelData);
+       
+    }
     
     return true;
 }
@@ -506,7 +601,7 @@ CompressedLevel Image::GetCompressedLevel(unsigned index) const
     level.compressedFormat_ = compressedFormat_;
     level.width_ = width_;
     level.height_ = height_;
-    level.blockSize_ = compressedFormat_ == CF_DXT1 ? 8 : 16;
+    level.blockSize_ = (compressedFormat_ == CF_DXT1 || compressedFormat_ == CF_ETC1) ? 8 : 16;
     unsigned i = 0;
     unsigned offset = 0;
     

+ 4 - 3
Engine/Resource/Image.h

@@ -32,7 +32,8 @@ enum CompressedFormat
     CF_NONE = 0,
     CF_DXT1,
     CF_DXT3,
-    CF_DXT5
+    CF_DXT5,
+    CF_ETC1
 };
 
 /// Compressed image mip level.
@@ -50,8 +51,8 @@ struct CompressedLevel
     {
     }
     
-    /// Decompress. The destination buffer required is width * height * 4 bytes.
-    void Decompress(unsigned char* dest);
+    /// Decompress. The destination buffer required is width * height * 4 bytes. Return true if successful.
+    bool Decompress(unsigned char* dest);
     
     /// Compressed image data.
     unsigned char* data_;