Reputation: 190
I'm trying to use compressed textures on my android application. I have a problem loading textures, textures seem to be "cut-off" on the right side of the object.
For compressing textures I'm using ATI's "TheCompressonator". For testing I'm using Nexus 5.
I'm suspecting the problem is with my "calculated" size of the texture, but can't find any refenreces / specification of this compression format.
Does anyone know how to properly read this file format?
Here is screenshot from nexus:
Here is how it should have looked (don't mind black object textures, the image for that was missing)
Here is my code snippet.
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);
int offset = 0; // 64 bit = header, 15 bit = metadata
bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
bf.order(ByteOrder.LITTLE_ENDIAN);
int height = bf.getInt(16);
int width = bf.getInt(12);
int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
Log.d("TextureHelper","Buffer size: "+width+" "+height+" "+size);
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,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bf);
Log.d("TextureHelper","Buffer size: "+bf.capacity()+" : "+buffer.length+" error:"+GLES20.glGetError());
glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return textureObjectIds[0];
EDIT: Solution
buffer = new byte[bitmap.available()];
bitmap.read(buffer);
int offset = 128; // 64 bit = header, 15 bit = metadata
bf = ByteBuffer.wrap(buffer, offset, buffer.length-offset);
bf.order(ByteOrder.LITTLE_ENDIAN);
int height = bf.getInt(16);
int width = bf.getInt(12);
int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
Log.d("TextureHelper","Buffer size: "+width+" "+height+" "+size);
bf.compact();///////SOLUTION!
bf.position(0);
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,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bf);
Log.d("TextureHelper","Buffer size: "+bf.capacity()+" : "+buffer.length+" error:"+GLES20.glGetError());
glBindTexture(GL_TEXTURE_2D, 0); //unbind texture
Note: You need to have data at 0 position, if you just offset position(128) it will throw invalid pointer exception.
Upvotes: 0
Views: 131
Reputation: 66
Your size computation looks correct, but you're uploading the header as image data. After you extract the width and height from the header, offset your byte buffer by the appropriate amount to skip the header and start pointing at the image data.
There are a few ways you could do this, but something like this may work as an example (this could be optimized to remove the second bytebuffer). Also, I'm not sure what texture format you're using, but let's assume your header is, oh, 124 bytes long.
// assumption that buffer[] is the fully loaded contents of the file
byte[] buffer = ... // load entire file from input stream
// read the header
ByteBuffer bfHeader = ByteBuffer.wrap(buffer);
bfHeader.order(ByteOrder.LITTLE_ENDIAN);
int height = bfHeader.getInt(16);
int width = bfHeader.getInt(12);
// offset to image data
int headerSize = 124; // (replace with correct header size)
ByteBuffer bfData = ByteBuffer.wrap(buffer, headerSize, buffer.length-headerSize);
bfData.order(ByteOrder.LITTLE_ENDIAN);
// load image data
int size = ((height + 3) / 4) * ((width + 3) / 4) * 16;
glBindTexture(GL_TEXTURE_2D, textureObjectIds[0]);
GLES20.glCompressedTexImage2D(GL_TEXTURE_2D, 0,ATC_RGBA_EXPLICIT_ALPHA_AMD, width, height, 0, size, bfData);
Upvotes: 1