Can't get transparency to work...

I’ve banged my head for a couple days, now I need to ask for help.

I’m doing 2D work with simple layers and bitmaps - load up some bitmaps, go into ortho mode, and draw some quads and lines, at various values of z. All is well. I can draw bitmaps on top of bitmaps, lines across bitmaps, all very pretty and proper.

Now I’m trying to graduate to bitmaps with alpha channels. I’ve verified that the images really do have pixels with alpha=0. I’m sorting my objects so that I draw far (high z) objects before near objects, which for me also happens to mean opaque objects get drawn before transparent ones.

What I get is that things draw correctly, colors are right, etc., except for transparent areas of bitmaps, which look uniformly greyish and show no hint of the underlying image.

Here are the relevant fragments of code (this is Windows):

init contains:
pfd.dwFlags = PFD_SUPPORT_OPENGL |PFD_DRAW_TO_WINDOW| PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
format = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat, etc.

Loading up the bitmaps as textures:
glGenTextures( 1, &textureId_);
// select our current texture
glBindTexture( GL_TEXTURE_2D, textureId_ );
//tell OpenGL we packed bytes tight
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0,
GL_RGBA,
br.width_, br.height_, //bitmap dimensions
0,
GL_BGRA_EXT,
GL_UNSIGNED_BYTE,
p);

Preparing to draw looks like
glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
RECT r;
GetClientRect(Windex::hWnd_, &r);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0, r.right, 0, r.bottom, -1, 1);
glViewport(0, 0, r.right, r.bottom);
glDisable(GL_CULL_FACE);
glDisable(GL_LIGHTING);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

drawing each bitmap looks like:
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_DECAL);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBegin(GL_QUADS);
glTexCoord2f(0,0);
glVertex3d(r.left, r.bottom, r.z);
glTexCoord2f(1,0);
glVertex3d(r.right, r.bottom, r.z);
glTexCoord2f(1,1);
glVertex3d(r.right, r.top, r.z);
glTexCoord2f(0,1);
glVertex3d(r.left, r.top, r.z);
glEnd();
glDisable(GL_TEXTURE_2D);

After drawing stuff:
glFlush();
SwapBuffers(hdc_);

Please, which step did I screw up or miss?

Addendum:
I hacked my code to run over the image in memory, to hammer all the alpha values to a fixed value, before I do the glGenTextures, glBindTexture, glTexImage2D dance.

When I hammer it to 0, the images become uniform grey rectangles.
When I hammer it to 127, the images are dimly visible but colors are greyed.
When I hammer it to 255, the images appear unmodified.

The grey color is a color I use to draw occasional thin lines; it gets passed to glColor4ub() before I draw lines, in between calls to my quad-drawing function. For whatever reason, it looks like the color passed to glColor4 is always what I’m blending with, NOT the colors already in the frame. So I’m probably in some weird blending mode I didn’t intend; can someone suggest what I missed?

(Commenting out the call to glColor4 didn’t help; I just end up blending with white.)

I’m sorting my objects so that I draw far (high z) objects before near objects,

Please note that normally you are looking down the negative z axis in eye space, that means far objects have smaller z than closer ones.

Sorry, I misspoke. But the objects are properly in view, and the foreground object is drawn in front of the background one. The only problem is that the background object isn’t visible through the transparent parts of the foreground object.

OK, a lot more banging around reveals the following:

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_DECAL) blends with the last color set by glColor4(), which is not what I want. I have no idea why it does that; it makes no sense to me.

glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE) seems to accomplish exactly what I’m after. Again, I have no idea why.

If anyone can explain to me how this works, I’d appreciate it.

Read the details for GL_DECAL and GL_MODULATE :
http://www.opengl.org/sdk/docs/man/xhtml/glTexEnv.xml

Decal is typically used when you have a “sticker-like” texture to be applied to an object. The alpha values of the texture control the crossfade between object color and texture color. So you should use a color like x,x,x,0 if you want transparency when the texture has alpha = 0.

Modulate (the default) is more frequently used, and works as expected if you want lighting for example. In this mode, the object color is multiplied by the texture color, component by component, so to display the texture with no change you have to use color 1,1,1,1 (multiplication by one [well 255 if using bytes] does not change anything).

Thanks ScottM for your head banging it solved my issue :

http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=292635#Post292635

OK, I finally figured this out.

GL_DECAL wasn’t what I wanted. It applies when you are in the process of painting an object - it doesn’t apply when you are painting a new object (with transparency) in front of an existing object. For that, you need GL_MODULATE.

The key (as ZBuffeR noted) is to set glColor4(1,1,1,1) before painting the new texture. Without that, painting a textured transparent/lucent surface in front of another just won’t work right. Note that this works with lighting turned OFF, which is my situation. (All the pages that talk about GL_MODULATE make it sound like it’s only used for when lighting is enabled. Untrue.)

Anyway, it took some banging, but I finally have properly drawn widgets. Thanks.

If you’re just rendering widgets GL_REPLACE might be better than GL_MODULATE. It ignores glColor entirely which’ll save you the bother of setting it to ones in order to nullify the effect of multiplying by it.