1

I'm trying to optimize my app by having compressed textures. Since a lot of my textures require alpha I can't use ETC1.

I've successfully compressed textures to other formats using hints from this post. Android OpenGL Texture Compression

Problem is I can't seem to adapt my code, to read this textures. The only thing I get with this code is black (colour, instead of texture).

Here is the method, that loads textures:

public static int loadCompressedTexture(Context context, int resourceId){
    final int[] textureObjectIds = new int[1];

    glGenTextures(1, textureObjectIds, 0);

    if(textureObjectIds[0] == 0){
        logTextureHelper(Log.WARN, "Could not generate a new OpenGL texture object");
        return 0;
    }

    final InputStream bitmap = context.getResources().openRawResource(resourceId);
    byte[] buffer;
    ByteBuffer bf;

    try {
        buffer = new byte[bitmap.available()];
        bitmap.read(buffer);
        bf  = ByteBuffer.wrap(buffer);

        glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);//binds texture to texture object

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);//minimization filter
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

        //texImage2D(GL_TEXTURE_2D, 0, bitmap, 0);//send texture data to OpenGL to the CURRENTLY BOUND object
        GLES20.glCompressedTexImage2D(GLES20.GL_TEXTURE_2D, 0, GL10.GL_PALETTE4_RGBA8_OES, 512, 512, 0, bf.capacity(), bf);


        //glGenerateMipmap(GL_TEXTURE_2D);
        glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return textureObjectIds[0];
}

I currently trying to load resource that is 512x512px, compressed with PvrTexTool, using PVRTC 4bpp RGBA encoding.

Can anyone see what the problem is? Or better yet, point me to an example that works? From what I found I could only find examples for ETC1, who use some ETCUtil to load textures.

EDIT2: Ok I've solved it. There were 2 problems. First you need to use these texture filters.

GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST); GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

Secondly I was not aware that pvrtc had a seperate header. The correct offset is thus 67 bytes. PVRTC format specification

This code now works correctly:

            buffer = new byte[bitmap.available()];
            bitmap.read(buffer);

            int offset = 67; // 52 bit = header, 15 bit = metadata
            bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
            bf.order(ByteOrder.LITTLE_ENDIAN);

            long version     = bf.getInt(0) & 0xFFFFFFFFL;
            long flags       = bf.getInt(4);
            long pixelFormat = bf.getLong(8);
            long colorF      = bf.getInt(16);
            long chanel      = bf.getInt(20);
            int height       = bf.getInt(24);
            int width        = bf.getInt(28);
            long depth       = bf.getInt(32);
            long nsurf       = bf.getInt(36);
            long nface       = bf.getInt(40);
            long mipC        = bf.getInt(44);
            long mSize       = bf.getInt(48);
            long fourCC      = bf.getInt(52)& 0xFFFFFFFFL;
            long key         = bf.getInt(56)& 0xFFFFFFFFL;
            long dataSize    = bf.getInt(60)& 0xFFFFFFFFL;



//              Log.d("TextureHelper","Buffer size: "+version+" "+flags+" "+pixelFormat+" "+colorF+" "+chanel+" "+height+" w: "+width+" h: "+height+" "+depth+" "+nsurf+" "+nface+" "+mipC+" "+mSize);
//              Log.d("TextureHelper","Buffer size: "+fourCC+" "+key+" "+dataSize);


            glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
            glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
            glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);


            GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, width, height, 0, bf.capacity()-offset, bf);
            Log.d("TextureHelper","Buffer size: "+bf.capacity()+"   : "+buffer.length+" error:"+GLES20.glGetError());

            glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
Community
  • 1
  • 1
Jani
  • 190
  • 2
  • 12
  • The `available()` method on `InputStream` is not guaranteed to give the entire length of the resource. Can you check what it returns, and make sure that it matches the length of the file? – Reto Koradi Dec 29 '14 at 05:33
  • I've checked. The size is the same in windows file properties in byte[] buffer and in ByteBuffer bf, it is 131139 bytes. – Jani Dec 29 '14 at 10:15

1 Answers1

3

You want to load PVRTC 4bpp RGBA texture via glCompressedTexImage2D? You should use COMPRESSED_RGBA_PVRTC_4BPPV1_IMG instead of GL10.GL_PALETTE4_RGBA8_OES.

IMG_texture_compression_pvrtc https://www.khronos.org/registry/gles/extensions/IMG/IMG_texture_compression_pvrtc.txt

I'm not sure but it seems Android GLES20 doesn't have those constants, so you need to define it.

// PowerVR Texture compression constants
public static final int GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG = 0x8C00;
public static final int GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG = 0x8C01;
public static final int GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG = 0x8C02;
public static final int GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG = 0x8C03;

And you should check glGetError after glCompressedTexImage2D calling. The value of glGetError should be GL_NO_ERROR.

Kazuki Sakamoto
  • 13,929
  • 2
  • 34
  • 96
  • Thank you for your reply! Sadly this still hasn't fixed my problem. //EDIT (enter by mistake) I've implemented your constants and outprinted the error. Error number now is: 1281 (invalid input). This would suggest that the size of buffer is not correct? I've printed out bf.capacity() = 131 139 (if I go in windows and look at details it's the same). The PVR tool says that image should have 15 bytes of metadata. If I set bf.position(15), and reduce capacity-15, I still get same error. – Jani Dec 25 '14 at 00:40
  • I have one question. Are you sure you are using PowerVR GPU Android device? – Kazuki Sakamoto Dec 25 '14 at 00:47
  • `glGetString(GL10.GL_EXTENSIONS)` includes `GL_IMG_texture_compression_pvrtc`, right? – Kazuki Sakamoto Dec 25 '14 at 00:59
  • Yes, I have a methond in onSurfaceCreated that checks for extensions. I'm currently testing on samsung tab 2 (7'') and it has GL_IMG_texture_compression_pvrtc – Jani Dec 25 '14 at 11:05