Поддержка текстур формата ARGB в OpenGL
Как известно, в OpenGL «из коробки» поддерживаются текстуры в форматах RGB, RGBA и BRGA. Что же делать, если из внешней библиотеки пришло изображение в ином формате, например в ARGB? Такое случается довольно часто, если OpenGL используется совместно с библиотекой Qt.
Один из вариантов решения — использовать встроенную в Qt функцию конвертации. Однако, конвертация выполняется на процессоре и требует дополнительного копирования памяти. Другой, более быстрый способ, — использовать текстуру в том виде, в котором отдает ее Qt, сделав преобразование на видеокарте.
Допустим, мы хотим в OpenGL использовать текстуру как RGBA. Тогда шейдер преобразования будет выглядить так (язык GLSL):
uniform sampler2D RGBtex; void main(void) { float nx,ny,r,g,b,a; nx=gl_TexCoord[0].x; ny=gl_TexCoord[0].y; r=texture2D(RGBtex,vec2(nx,ny)).b; g=texture2D(RGBtex,vec2(nx,ny)).g; b=texture2D(RGBtex,vec2(nx,ny)).r; a=texture2D(RGBtex,vec2(nx,ny)).a; r *= a; g *= a; b *= a; gl_FragColor=vec4(r,g,b,a); }
Не все видеокарты поддерживают OpenGL 2.0 и GLSL, поэтому, для совместимости, с помощью следующей команды преобразуем шейдер в ассемблер для использования совместно с расширением ARB_fragment_program:
cgc -oglsl -profile arbfp1 argb2rgba.glsl
Утилита cgc входит в состав nVidia SDK, однако, полученный код будет работать и на любой другой видеокарте:
!!ARBfp1.0 TEMP R0; TEX R0, fragment.texcoord[0], texture[0], 2D; MUL result.color.xyz, R0.zyxw, R0.w; MOV result.color.w, R0; END
Остается заключительный этап — загрузка и использование шейдера:
static const char *program= "!!ARBfp1.0\n" "TEMP R0;\n" "TEX R0, fragment.texcoord[0], texture[0], 2D;\n" "MUL result.color.xyz, R0.zyxw, R0.w;\n" "MOV result.color.w, R0;\n" "END"; unsigned int shader; glEnable(GL_FRAGMENT_PROGRAM_ARB); glGenProgramsARB(1, &shader); glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader); glProgramStringARB(GL_FRAGMENT_PROGRAM_ARB, GL_PROGRAM_FORMAT_ASCII_ARB, program, strlen(program)); if ( glGetError () == GL_INVALID_OPERATION ) { // ошибка загрузки шейдера } // ... glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, shader); QImage image = get_image(); // используем текстуру как обычно // glBindTexture(GL_TEXTURE_2D, texture_id) // glTexImage2D/glTexSubImage2D(GL_TEXTURE_2D, ..., GL_RGBA, // ..., gimage.bits()); // glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0);