glTexImage2D的android位图像素格式

glTexImage2D的android位图像素格式,android,opengl-es,bitmap,java-native-interface,textures,Android,Opengl Es,Bitmap,Java Native Interface,Textures,我正在尝试从Java和Bitmap类加载要与NDK OpenGL一起使用的纹理。它可以工作,但我的像素格式有问题 首先,在Java中,我从assets文件夹加载位图,如下所示: Bitmap bitmap = BitmapFactory.decodeStream(amgr.open(path)); return bitmap.copy(Bitmap.Config.ARGB_8888, false); 位图配置没有RGBA通道顺序选项 [JNI在这里发生的事情] 然后使用GLES 1缓冲纹理,如

我正在尝试从Java和Bitmap类加载要与NDK OpenGL一起使用的纹理。它可以工作,但我的像素格式有问题

首先,在Java中,我从assets文件夹加载位图,如下所示:

Bitmap bitmap = BitmapFactory.decodeStream(amgr.open(path));
return bitmap.copy(Bitmap.Config.ARGB_8888, false);
位图配置没有RGBA通道顺序选项

[JNI在这里发生的事情]

然后使用GLES 1缓冲纹理,如下所示:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
// `pixels` is the pixel buffer I produced earlier.
如您所见,像素格式存在问题
glTexImage2D
没有ARGB选项,但是Java位图类没有在RGBA中创建缓冲区的选项。所以我的颜色通道被弄乱了。顺便说一下,我需要阿尔法通道

问题是:如何最有效地从Java位图类生成RGBA888格式的像素缓冲区,或者如何加载argb888格式的GL纹理

除了手动逐像素交换字节之外,肯定还有其他方法吗

我目前正在这样做:

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));
    }
}
void pxl::将信道ARGB交换到RGBA(void*pixBuf,const int len)
{
jint*像素=(jint*)pixBuf;
对于(int i=0;i>24)&0xFF;
jint r=(像素>>16)&0xFF;
jint g=(像素>>8)&0xFF;
jint b=(像素>>0)&0xFF;

像素[i]=(jint)(a |)(r我认为没有办法做到这一点,但你可以用这个优化你的算法

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);
    }

}
void pxl::将信道ARGB交换到RGBA(void*pixBuf,const int len){
jint*像素=(jint*)pixBuf;
对于(int i=0;i24);
}
}

此问题无法在OpenGL ES 1.1中解决,但可以在OpenGL ES 3.0中或通过OpenGL扩展解决:

自OpenGL ES 3.0以来,您可以使用纹理swizzle参数交换颜色通道。请参阅:

GL\u纹理\u SWIZZLE\R

设置在返回着色器之前将应用于纹理的r分量的旋转。参数的有效值为
GL_RED
GL_GREEN
GL_BLUE
GL_ALPHA
GL_ZERO
GL_ONE
。如果
GL_TEXTURE_旋转
GL_RED
,则r wi的值如果
GL\u TEXTURE\u SWIZZLE\u R
GL\u GREEN
,则R的值将从提取纹理的第二个通道中获取

这意味着,当您将以下纹理参数设置到纹理对象时,在查找纹理时,颜色通道将被交换:

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);

有关本规范的相关部分,请访问

要检查OpenGL扩展是否有效,可以使用,它将返回以空格分隔的受支持扩展列表



另一种完全不同的解决方案是使用A进行转换。在画布上绘制,然后使用画布上保留的目标位图。
我在GitHub上找到了此解决方案:


你需要在JNI侧上进行GLTEXIGE2D调用吗?或者你可以使用GLUTILL。TXGIVEGE2D在java端上传它,然后把纹理ID作为一个int通过JNI。谢谢,但是我想把C++中的所有GL东西都保留下来。它对我来说是手动交换的,我只是好奇如果有一个更优雅的解决方案。我很好奇。o、 因为不做任何交换,但它可以工作。它通过将位图对象作为jobject传递给JNI并调用getPixels()。检查util_texImage2D函数。能否显示在传递给JNI之前如何从位图提取数据?是否使用getPixels()或copyPixelsToBuffer()?
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;
}