Regarding the big-endian comment in the code, I meant little-endian.
If we use IntBuffer to write ABGR ints to ByteBuffer on a little-
endian-phone we get byte order we RGBA. However the same code running
on a big-endian phone should produce ABGR byte order, which is not
what opengl expects. So don't use intbuffer.
The following should also work, and allocates less memory, but I don't
quite trust it since I don't have a big-endian phone, and since I
cannot test it on a big-endian emulator:
private static final boolean IS_LITTLE_ENDIAN =
(ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN);
private void myTexImage2D(GL10 gl, Bitmap bitmap) {
// Don't loading using GLUtils, load using gl-method directly
// GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
int[] pixels = extractPixels(bitmap);
for (int i = pixels.length - 1; i >= 0; i--) {
int p = pixels[i];
int r = ((p >> 16) & 0xFF);
int g = ((p >> 8) & 0xFF); // green
int b = ((p) & 0xFF); // blue
int a = (p >> 24); // alpha
if (IS_LITTLE_ENDIAN) {
pixels[i] = a << 24 | b << 16 | g << 8 | r;
} else {
pixels[i] = r << 24 | g << 16 | b << 8 | a;
}
}
IntBuffer pixelBuffer = IntBuffer.wrap(pixels);
gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,
bitmap.getWidth(), bitmap.getHeight(), 0, GL10.GL_RGBA,
GL10.GL_UNSIGNED_BYTE, pixelBuffer);
}
Alex
On Aug 12, 10:17 am, arberg <[email protected]> wrote:
> Apparently the cause of thepremultipliedalphalies in GLUtils, or
> perhaps the way GLUtils works with the Bitmap class. We can get the
> correct non-premultipliedalphabehaviour by replacing
> GLUtils.texImage2D with theopenglmethod gl.glTexImage2D which takes
> a pixel component array as a parameter. Thus we can avoid
> thepremultipliedalphabehaviour, which means we can use the blend
> function gl.glBlendFunc(GL10.GL_SRC_ALPHA,
> GL10.GL_ONE_MINUS_SRC_ALPHA);
>
> Note for uninitiated confusedopenglandroid developers: I posted a
> question onopengl.org discussion forum, where I described the
> symptoms of the
> problem:http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&N...
>
> Here's how I loaded the image in Android:
>
> private int loadTexture(GL10 gl, int resourceId) {
> int[] textureNameWorkspace = new int[1];
> gl.glGenTextures(1, textureNameWorkspace, 0);
> int textureName = textureNameWorkspace[0];
> gl.glBindTexture(GL10.GL_TEXTURE_2D, textureName);
> gl.glTexParameterf(GL10.GL_TEXTURE_2D,
> GL10.GL_TEXTURE_MIN_FILTER,
> GL10.GL_LINEAR);
> gl.glTexParameterf(GL10.GL_TEXTURE_2D,
> GL10.GL_TEXTURE_MAG_FILTER,
> GL10.GL_LINEAR);
> gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_S,
> GL10.GL_REPEAT);
> gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_WRAP_T,
> GL10.GL_REPEAT);
>
> gl.glTexEnvf(GL10.GL_TEXTURE_ENV, GL10.GL_TEXTURE_ENV_MODE,
> GL10.GL_MODULATE);
>
> Bitmap bitmap = BitmapFactory.decodeResource(resources,
> resourceId);
> myTexImage2D(gl, bitmap);
> // Set the crop parameter because I use drawtexture extension
> ((GL11) gl).glTexParameteriv(GL10.GL_TEXTURE_2D,
> GL11Ext.GL_TEXTURE_CROP_RECT_OES,
> new int[] { 0, bitmap.getHeight(),
> bitmap.getWidth(), -
> bitmap.getHeight() }, 0);
> return textureName;
> }
>
> private void myTexImage2D(GL10 gl, Bitmap bitmap) {
> // Don't loading using GLUtils, load using gl-method directly
> // GLUtils.texImage2D(GL10.GL_TEXTURE_2D, 0, bitmap, 0);
> int[] pixels = extractPixels(bitmap);
> byte[] pixelComponents = new byte[pixels.length*4];
> int byteIndex = 0;
> for (int i = 0; i < pixels.length; i++) {
> int p = pixels[i];
> // Convert to byte representation RGBA required by
> gl.glTexImage2D.
> // We don't use intbuffer, because then we
> // would be relying on the intbuffer wrapping to
> write the ints in
> // big-endian format, which means it would work for
> the wrong
> // reasons, and it might brake on some hardware.
> pixelComponents[byteIndex++] = (byte) ((p >> 16) & 0xFF); //
> red
> pixelComponents[byteIndex++] = (byte) ((p >> 8) & 0xFF); //
> green
> pixelComponents[byteIndex++] = (byte) ((p) & 0xFF); // blue
> pixelComponents[byteIndex++] = (byte) (p >> 24); //alpha
> }
> ByteBuffer pixelBuffer = ByteBuffer.wrap(pixelComponents);
>
> gl.glTexImage2D(GL10.GL_TEXTURE_2D, 0, GL10.GL_RGBA,
> bitmap.getWidth(), bitmap.getHeight(), 0, GL10.GL_RGBA,
> GL10.GL_UNSIGNED_BYTE, pixelBuffer);
> }
>
> public static int[] extractPixels(Bitmap src) {
> int x = 0;
> int y = 0;
> int w = src.getWidth();
> int h = src.getHeight();
> int[] colors = new int[w * h];
> src.getPixels(colors, 0, w, x, y, w, h);
> return colors;
> }
>
> Since the above implementation does not use native code to convert the
> bitmap and since it also allocates the bitmap array twice besides
> loading the bitmap (thus taking three times the memory space) its not
> quite optimal. It would be quite reasonable that Android supplied a
> native method for doing this. Certainly the documenation for GLUtils
> should state that it loads apremultipliedalphatexture. Does anyone
> know if there is a bugreport/feature request on this on Android? I
> cant seem to find any mentioning of it in the issue
> list:http://code.google.com/p/android/issues/list
>
> Alex.
--
You received this message because you are subscribed to the Google
Groups "Android Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to
[email protected]
For more options, visit this group at
http://groups.google.com/group/android-developers?hl=en