Using Texture combiners to create a grayscale tex

Hi guys,

I’m been struggling to use texture combiners for a while now. If anyone could help me, that’d be nice. I cannot use shaders because we have to cater for low end graphics cards. So my only option is texture combiners.

What I want to is this:

  1. Add the color (0.5,0.5,0.5,1.0) to texture0
  2. Perform a dot3 operation with texture1 and the result of Step1.

Texture0 is a nice picture of a girl.
Texture1 is a flat color with values (0.58, 0.58, 0.58 );

If all goes well, I should get the grayscale texture as my final result. That’s because the dot3 operation performs the following operation:

4 * ( ( ( r0 - 0.5 ) * (r1 - 0.5 ) ) +
( ( g0 - 0.5 ) * (g1 - 0.5 ) ) +
( ( b0 - 0.5 ) * (b1 - 0.5 ) ) );

So if I add r0,g0,b0 with 0.5 (thus canceling the -0.5 that occurs during the dot3 operation) and perform a dot3 operation with a texture having a color of (0.58 0.58, 0.58 ), i should end up with a result of

( ( r0 * 0.33 ) + ( g0 * 0.33 ) + ( b0 * 0.33 ) )

I tried it out and I get a greyscale image for sure. But it’s heavily contrasted. And I mean heavily! I did some debugging and it looks that the first operation is not being taken into account. i.e the GL_ADD operation

Can someone please tell me what I’m doing wrong.

thx.

Below is my code:

glActiveTextureARB( GL_TEXTURE0 );
glEnable(GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_textureID0 );

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );

//Color Operation
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD );

//source 0
GLfloat rgba[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba );
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );
//Source 1
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0 );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );

glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE );
//Color Operation
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
//Source 0
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );

glActiveTextureARB( GL_TEXTURE1 );
glEnable(GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_textureID1 );

//Source 1
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1 );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );

glActiveTextureARB( GL_TEXTURE1 );
glDisable(GL_TEXTURE_2D );

glBegin( GL_QUADS );

glMultiTexCoord2fARB( GL_TEXTURE0, 0,  0	);
glVertex3d(			  -1, -1, -2.0	);

glMultiTexCoord2fARB( GL_TEXTURE0, 1,  0	);
glVertex3d(			   1, -1, -2.0	);

glMultiTexCoord2fARB( GL_TEXTURE0, 1,  1	);
glVertex3d(			   1,  1, -2.0	);

glMultiTexCoord2fARB( GL_TEXTURE0, 0,  1	);
glVertex3d(			  -1,  1, -2.0	);

glEnd();

glActiveTextureARB( GL_TEXTURE0 );
glDisable(GL_TEXTURE_2D );

Allow me to note that any low-level card manufactured during last five years support fragment shaders. Or do you have to support stuff like Geforce 4 too?

Hi Zengar,

We have to support intel GMA 900 cards or something like that. And it’s a card that we know for sure (we emailed intel ) does not support shaders.

First, you assume that the DOT3_RGB formula works on unclamped color values.
As the spec says the DOT3 uses pseudo-signed math (alas the -0.5 bias) I don’t expect it to work with values outside the range [0,1].
If that’s the case your algorithm is doomed.

Adding 0.5 to a color value above 0.5 might saturate at 1.0 BEFORE the -0.5 bias is done inside the DOT3 operation.

Your code looks bugged.

OpenGL is a state machine. You have a
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD );

glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );
after each other, which cancels out the GL_ADD.

You actually disabled texture unit 1 before rendering and don’t send texture coordinates for it which makes the GL_SOURCE1_RGB, GL_TEXTURE1 setup futile.
The fixed function pipeline has a one-to-one relationship between units and MultiTextCoord slots.

BTW, a nicer greyscale conversion from RGB uses the factors (0.3, 0.59, 0.11) in the dot product because green is percieved brightest, then red, then blue. Means you could even distinguish differently colored parts in the final greyscale image.

Performance tip: Avoid double typed OpenGL API entry functions.

Try if this works a little better. Untested!
Mind, it’ll never work this way if I’m right with the clamping at 1.0.
(Combiners are outdated functionality. Get over it.)

 glActiveTextureARB( GL_TEXTURE0 );
glEnable(GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_textureID0 ); 


glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); 
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD );

//source 0
GLfloat rgba[4] = { 0.5f, 0.5f, 0.5f, 1.0f };
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, rgba );

glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_CONSTANT );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );

//Source 1
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE0 );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );


glActiveTextureARB( GL_TEXTURE1 );
glEnable(GL_TEXTURE_2D );
glBindTexture( GL_TEXTURE_2D, m_textureID1 );


glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE ); 
glTexEnvi( GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DOT3_RGB );

//Source 0
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR );

//Source 1
glTexEnvi( GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE1 );
glTexEnvi( GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR );


glBegin( GL_QUADS );

glMultiTexCoord2fARB( GL_TEXTURE0, 0.0f, 0.0f );
glMultiTexCoord2fARB( GL_TEXTURE1, 0.0f, 0.0f );
glVertex3f( -1.0f, -1.0f, -2.0f );

glMultiTexCoord2fARB( GL_TEXTURE0, 1.0f, 0.0f );
glMultiTexCoord2fARB( GL_TEXTURE1, 1.0f, 0.0f );
glVertex3f( 1.0f, -1.0f, -2.0f );

glMultiTexCoord2fARB( GL_TEXTURE0, 1.0f, 1.0f );
glMultiTexCoord2fARB( GL_TEXTURE1, 1.0f, 1.0f );
glVertex3f( 1.0f, 1.0f, -2.0f );

glMultiTexCoord2fARB( GL_TEXTURE0, 0.0f, 1.0f );
glMultiTexCoord2fARB( GL_TEXTURE0, 0.0f, 1.0f );
glVertex3f( -1.0f, 1.0f, -2.0f );

glEnd();

glDisable(GL_TEXTURE_2D );  // Unit 1

glActiveTextureARB( GL_TEXTURE0 );
glDisable(GL_TEXTURE_2D ); 


[quote=“Zengar”]

Allow me to note that any low-level card manufactured during last five years support fragment shaders. Or do you have to support stuff like Geforce 4 too? [/QUOTE]

My TiBook is from 2002. While it’s approaching time to replace the thing, it’s still good enough for most purposes. I wouldn’t assume “low-end” doesn’t include it and similarly aged machines.

Ah, texture combiners, register combiners, it’s all coming back to me now. What a living nightmare they were. I reallocated that part of my brain for other things a long time ago, like for tax returns. Good luck.

Hi guys,

Tnx for all your responses.

Relic, I tried what you suggested, ie disable texture unit 1 after drawing the quad. That doesnt seem to work cos I get a black screen.

I was told that clamping only occured at the last step. So that’s why I attempted the algorithm.

Anyways I think it’s time to give up those texture combiners. I’ve tried as much as possible to make it work.

Tnx again for all your responses.

Don’t combiners give better control over the displayed image then shaders? I would be interested in some links to working examples for shaders, preferably if they were for xcode. Thanks.

No, they don’t. Shaders are much, much more flexible and general. :slight_smile: Take a look here for shaders.

If you have to deal with low end cards, you can always multi pass ( and don’t care about the performance anyways) and accumulate the gray scale image in the frame buffer using blending (with all the precision issues). So you would render the texture three times, each time computing 0.33 times the respective color channel and using GL_ONE, GL_ONE as the blend function.

According to http://en.wikipedia.org/wiki/Intel_GMA#Table_of_GMA_graphics_cores_and_chipsets, the GMA 9XX chips are DX shader model 2.0 cards, so they should have basic GLSL support. But given intels driver policy, you might be screwed :frowning:

What OS do you have to support?

Why create rendering code for graphics chipsets that don’t even deserve that name at all? I mean, you cannot satisfy everybody.