问题
I'm trying to load textures to use with NDK OpenGL from Java with the Bitmap class. It works, but I'm having problems with the pixel format.
First, in Java, I load a bitmap from the assets folder like this:
Bitmap bitmap = BitmapFactory.decodeStream(amgr.open(path));
return bitmap.copy(Bitmap.Config.ARGB_8888, false);
the bitmap config does not have an option for RGBA channel order.
[JNI things happen here]
Using GLES 1, I then buffer the texture like so:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// `pixels` is the pixel buffer I produced earlier.
As you can see, there is a problem with the pixel format. glTexImage2D
does not have an option for ARGB, but the Java Bitmap class does not have an option to create a buffer in RGBA. So I end up with messed up color channels. I do need the alpha channel by the way.
The question is: how do I most efficiently produce a pixel buffer in RGBA8888 format from the Java bitmap class, or, how do I load a GL texture in ARGB8888 format?
Surely there is a way other than manually swapping bytes pixel-by-pixel?
I am currently doing this:
void pxl::swap_channels_ARGB_to_RGBA(void *pixBuf, const int len)
{
jint *pixels = (jint *)pixBuf;
for(int i = 0; i < len; i++)
{
jint pixel = pixels[i];
jint a = (pixel >> 24) & 0xFF;
jint r = (pixel >> 16) & 0xFF;
jint g = (pixel >> 8) & 0xFF;
jint b = (pixel >> 0) & 0xFF;
pixels[i] = (jint)(a | (r << 24 ) | (g << 16) | (b << 8));
}
}
Or maybe there is another error? Not exactly sure about the glTexImage2D
options to be honest.
Thanks!
回答1:
I think there's no method to do that, but you can optimize your algorithm with this
void pxl::swap_channels_ARGB_to_RGBA(void *pixBuf, const int len) {
jint *pixels = (jint *)pixBuf;
for(int i = 0; i < len; i++) {
unsigned int aux = (int)pixels[i];
pixels[i] = (aux << 8) | (aux >> 24);
}
}
回答2:
This issue can't be solved in OpenGL ES 1.1 but it would be solvable in OpenGL ES 3.0 or by OpenGL extension EXT_texture_swizzle:
Since OpenGL ES 3.0 you can use the texture swizzle parameters to swap the color channels. See glTexParameter:
GL_TEXTURE_SWIZZLE_R
Sets the swizzle that will be applied to the r component of a texel before it is returned to the shader. Valid values for param are
GL_RED
,GL_GREEN
,GL_BLUE
,GL_ALPHA
,GL_ZERO
andGL_ONE
. IfGL_TEXTURE_SWIZZLE_R
isGL_RED
, the value for r will be taken from the first channel of the fetched texel. IfGL_TEXTURE_SWIZZLE_R
isGL_GREEN
, the value for r will be taken from the second channel of the fetched texel. ...
This means the color channels will be swapped when the texture is looked up, when you set the following texture parameters to the texture object:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_R, GL_GREEN);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_BLUE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_ALPHA);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_A, GL_RED);
The relevant part in the specification can be found at OpenGL ES 3.0.5 Specification; 3.8.14 Texture State; page 162
To check if an OpenGL extension is valid, glGetString(GL_EXTENSIONS) can be use, which returns a space-separated list of supported extensions.
A completely different solution would be to use a Canvas for the conversion. Draw the Bitmap on the canvas, and then use the target bitmap, which is hold by the canvas.
I found this solution on GitHub: fix android 2.3 can't decode bitmap in rgba8888 format
public static Bitmap convert(Bitmap bitmap, Bitmap.Config config) {
Bitmap convertedBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), config);
Canvas canvas = new Canvas(convertedBitmap);
Paint paint = new Paint();
paint.setColor(Color.BLACK);
canvas.drawBitmap(bitmap, 0, 0, paint);
return convertedBitmap;
}
来源:https://stackoverflow.com/questions/34705921/android-bitmap-pixel-format-for-glteximage2d