Load PVRTC2/4 Compress Texture on Android

The Advantage of Compress texture
Note, the texture compress method here means some formats that also be supported by our display card.
So compress texture will take less storage, less bandwidth and hardware optimized.

Of course, such texture compression will make a bit loss, but it will not be so obviously in the game.

 

Check hardware supported texture compress format
Before we do texture compress, we need to make sure whether our hardware support PVRTC texture compression support. For android device, we could use glGetString function to get support features. The following code used check which texture compress format supported on our device:

复制代码
    string ext = (const char*)glGetString(GL_EXTENSIONS);
    if ( -1 != ext.find("GL_IMG_texture_compression_pvrtc") )
    {
        //"GL_IMG_texture_compression_pvrtc" supported;
    }
    else if ( -1 != ext.find("GL_AMD_compressed_ATC_texture") )
    {
        // "GL_AMD_compressed_ATC_texture" supported
    }
    else if ( -1 != ext.find("GL_OES_texture_compression_S3TC") )
    {
        // GL_OES_texture_compression_S3TC" supported
    }
    else
    {
        "unsupported texture compression";
    }
复制代码

 

Compress texture with PVRTC format

You could use external tool named “PVRTexTool”to do the texture compression, and you could download this tool from Imagination without pay. You could compress texture as following command:

// 2 bits per texture pixel
PVRTexToolCL.exe -f OGLPVRTC2 -i arrow.png -o arrow.pvr
// 4 bits per texture pixel
PVRTexToolCL.exe -f OGLPVRTC4 -i arrow.bmp -o arrow.pvr

And the compression process will take care of the alpha channel at the same time if you provide this channel at the same time. But if you want to more higher precision, I would suggestion you use OGLPVRTC4 instead of OGLPVRTC2.  

 

Load the PVRTC compression texture

You could find some useful document about the PVRTC file format under the PVRTexTool directory. The follow is the code that used to load one PVRTC compressed texture without mip-maps. The workflow is very cleanly here:
1) check the PVRTC file header first;
2) find the meta data block size, skip the meta data block to the texture content address [If you check my code carefully, you will find that I calculated an offset value to get the real texture data instead of strictly following the document guide. The document guide says that the real texture data located after the meta data without any offset, but the situation is some offset must need. And another thing you may notice is the way calculating the texture size based on the texture size and compression format];
3) now you know the texture size ,PVRTC compression format and texture content, so you could create a OpenGL texture object and upload the texture data with function glCompressedTexImage2D.

复制代码
    NFile file;

    if ( !file.Load(fname) )
        return ;

    int len = file.GetLength();
    if ( len <= sizeof(PVRTextureHeaderV3) + 1 )
    {
        file.Close();
        return ;
    }

    U8* fileConent = new U8[len];
    int count = file.Read(fileConent, len);
    assert(count == len);
    file.Close();
    
    // check the file header first
    PVRTextureHeaderV3* texHeader = (PVRTextureHeaderV3*)fileConent;
    if ( texHeader->u32Version != PVRTEX_CURR_IDENT )
    {
        delete[] fileConent;
        return ;
    }
    
    // skip to the texture part
    int texStart = sizeof(PVRTextureHeaderV3) + texHeader->u32MetaDataSize;
    int texLen = len - texStart;
    if ( texLen > 0 )
    {
        int width = texHeader->u32Width;
        int height = texHeader->u32Height ;

        GLenum format;
        int size;
        if ( texHeader->u64PixelFormat == ePVRTCI_2bpp_RGB )
        {
            format = GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;    
            size = (width * height) >> 2;
        }
        else if ( texHeader->u64PixelFormat == ePVRTCI_2bpp_RGBA )
        {
            format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
            size = (width * height) >> 2;
        }
        else if ( texHeader->u64PixelFormat == ePVRTCI_4bpp_RGB )
        {
            format = GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
            size = (width * height) >> 1;
        }
        else if ( texHeader->u64PixelFormat == ePVRTCI_4bpp_RGBA )
        {
            format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
            size = (width * height) >> 1;
        }
        else
        {
            assert(false && "Unsupported PVRTC texture compression!");
            format = 0;
            size = 0;
        }
        
        glEnable(GL_TEXTURE_2D);
        glGenTextures( 1, &m_tex ); 
        glBindTexture( GL_TEXTURE_2D, m_tex );

        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );

        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
        glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
        
        // assume that the texture data located at the end of the file
        int offset = len - size;
        U8* texData = fileConent + offset;

        glCompressedTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, size, texData);

        delete[] fileConent;
    }
复制代码

 

Reference

http://stackoverflow.com/questions/9148795/android-opengl-texture-compression
http://www.brokenteapotstudios.com/android-game-development-blog/2011/06/android-pvrtc-texture-encoding-and-performance.html

posted @   opencoder  阅读(1187)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
点击右上角即可分享
微信分享提示