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 @ 2012-12-15 14:50  opencoder  阅读(1182)  评论(0编辑  收藏  举报