[A5] Sending Two Allegro Bitmaps to a GLSL Fragment/Pixel Shader
Kris Asick

OK, so I've run into a problem I know has a solution because I've seen raw GLSL code that does this, but since I'm using Allegro for everything except my fragment (pixel) shaders I'm trying to figure out how to make this work.

Essentially, here's what I'm trying to do:

1. Render the entire scene to a Bitmap (Bmp1).
2. Render Bmp1 to Bmp2 using a fragment shader.
3. Render both Bmp1 and Bmp2 to the screen, blended together.

Step 1 and 2 are both working, but I'm having trouble with Step 3 because the two bitmaps need to be blended in a VERY specific way that cannot be done with Allegro's built-in blending functions.

Essentially, the fragment shader I'm trying to write to blend the two bitmaps looks like this:

uniform sampler2D Bmp1;
uniform sampler2D Bmp2;
void main(void) {
    vec2 v = gl_TexCoord[0].st;
    vec4 c1 = texture2D(Bmp1,v);
    vec4 c2 = texture2D(Bmp2,v);
    vec4 final;
    if (c1.r > c2.r) final.r = c1.r; else final.r = c2.r;
    if (c1.g > c2.g) final.g = c1.g; else final.g = c2.g;
    if (c1.b > c2.b) final.b = c1.b; else final.b = c2.b;
    if (c1.a > c2.a) final.a = c1.a; else final.a = c2.a;
    gl_FragColor = final; }

However, when I tried to pass two bitmaps down the graphics pipeline through this fragment shader, BOTH ended up pointing to the one being drawn by the al_draw_bitmap() command! I did some further testing and noticed my calls to glUniform1iARB() weren't being honoured and that even if I changed them to completely bogus values in the fragment shaders I already had working, they continued working.

Here's how I'm preapring the fragment shaders for use:

sceneblend_shader = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
glShaderSourceARB(sceneblend_shader,sceneblend_code_len,sceneblend_code,NULL);
glCompileShaderARB(sceneblend_shader);
sceneblend = glCreateProgramObjectARB();
glAttachObjectARB(sceneblend,sceneblend_shader);
glLinkProgramARB(sceneblend);
loc = glGetUniformLocationARB(sceneblend,"Bmp1");
glUniform1iARB(loc,al_get_opengl_texture(_bitmap_1));
loc = glGetUniformLocationARB(sceneblend,"Bmp2");
glUniform1iARB(loc,al_get_opengl_texture(_bitmap_2));

Note, everything so far has been pseudocode because I've been re-writing the heck out of it all trying to make it work, but this is what I originally tried.

Any ideas?

Trent Gamblin

Yes, you're doing it wrong. You don't pass OpenGL textures for sampler2Ds, you're supposed to pass texture units. So your code should look a little like this:

glActiveTexture(0);
glBindTexture(bmp1);
glActiveTexture(1);
glBindTexture(bmp2);
glUniform1i(blah, 0);
glUniform1i(blah2, 1);

If you had used the shader addon, this would be done for you :P.

Dario ff
Kris Asick

Someone might wanna tell that to whoever wrote ex_opengl_pixel_shader.c to go with the A5 examples. :P

However, even after making this change it still isn't working. It appears as though texture 0 is always the bitmap Allegro is drawing from and anything beyond that is cleared away. If I try assigning a texture to ID 1, nothing goes through, yet even if I assign it to ID 1 then pass ID 0 to glUniform1iARB(), it goes through fine, but then I'm still left only able to get one texture through the pipeline and not two.

I'm using 5.0.5 until 5.1 is considered a stable release with pre-compiled MSVC10 binaries and such, so I don't have access to the shader addon.

EDIT: *looks through Dario's situation* So... waitaminute... is the solution nothing more than just manually drawing the texture and skipping on Allegro's drawing functions?

*tries this, will be back momentarily*

Dario ff

So... waitaminute... is the solution nothing more than just manually drawing the texture and skipping on Allegro's drawing functions?

I didn't actually mean that, but then again that solution was for code I was trying to get to work ONE year ago. I'm not sure how much has A5 changed from then in regards to it.

Still, if you're using GLSL I'm gonna guess you're staying OpenGL only, so I don't see any reasons to not use specific code like that. :P

Kris Asick

After much tweaking, I finally have it working, WITH the built-in Allegro functions! :)

Basically, once I enable the fragment shader, I have to do this:

  glActiveTexture(GL_TEXTURE0);
  glBindTexture(GL_TEXTURE_2D,al_get_opengl_texture(_bitmap_1));
  loc = glGetUniformLocationARB(sceneblend,"Bmp1");
  glUniform1iARB(loc,0);
  glActiveTexture(GL_TEXTURE1);
  glBindTexture(GL_TEXTURE_2D,al_get_opengl_texture(_bitmap_2));
  loc = glGetUniformLocationARB(sceneblend,"Bmp2");
  glUniform1iARB(loc,1);
  glActiveTexture(GL_TEXTURE0);

Then I can call the Allegro function to draw the bitmap to the screen and it will process both textures through the pipeline. :)

After a whole bunch of tweaking, the real trick to this entire mess was, no matter what texture IDs you use, to specifically call glActiveTexture(GL_TEXTURE0) after setting up both textures. Failing to do this throws the entire thing out of whack, even when trying to handle everything manually through OpenGL calls.

At first it didn't work and I was spending nearly half an hour trying everything until I realized I forgot to turn the fragment shader off afterwards, thus it was getting used to render the scene elements themselves, which obviously wasn't going to work properly. :P

And of course, my sceneblend shader isn't perfect and needs tweaking. Ah well, the fact that it's working means tweaking it will be simple enough. ;)

Thanks, guys! ;D

Trent Gamblin

After a whole bunch of tweaking, the real trick to this entire mess was, no matter what texture IDs you use, to specifically call glActiveTexture(GL_TEXTURE0) after setting up both textures. Failing to do this throws the entire thing out of whack, even when trying to handle everything manually through OpenGL calls.

Makes sense. The Allegro draw functions bind the texture, so without that final call, it would bind the texture on unit 1, and they would then both be pointing at the same bitmap :).

Thread #609539. Printed from Allegro.cc