Original Post
I have an existing terrain system with textures like so: Base Detail 1 Detail 1 Alpha Detail 2 Detail 2 Alpha Detail 3 Detail 3 Alpha Shadow Color (basically a simple white w/ glColorf()) Shadow Alpha The details are sometimes left out, so the grand total varies between 3 and 9 textures needed. On a system where GL_MAX_TEXTURE_UNITS_ARB is 1, this will never look right, ever ever. When GL_MAX_TEXTURE_UNITS_ARB is 2, it can look right, but only if its split into 2-5 passes. I have this working. If GL_MAX_TEXTURE_UNITS_ARB is 4, I think it can be reduced to 1-3 passes, depending on detail count. The resolution is the alpha maps is higher hen the resolution of the terrain position vertices, so I figured trying to combine the alphas into a color array and using the color-as-alpha shader splat trick wouldn't work real well (read: wouldn't produce the exact same output as the existing 5 pass method). So I figured I could just layer the textures ontop of each other, up to GL_MAX_TEXTURE_UNITS_ARB per pass, and do something with glTexEnv() and it would still work out. Well, its not. Funnily enough, if I fool my program into thinking GL_MAX_TEXTURE_UNITS_ARB is 2 when its splits the layers up into passes it renders fine, so the glTexEnv stuff isn't horribly screwing up the first layers. But when GL_MAX_TEXTURE_UNITS_ARB is allowed to be the cards natural 4, when it tried to combine Base + Detail 1 + Detail 1 Alpha is goes nuts. And it goes nuts trying to combined Detail 2 + Detail 2 Alpha + Detail 3 + Detail 3 Alpha as well. I'm starting to suspect its just not possible to get this to work right since the details and alphas are separate layers.
int TexUnit = 0;
for(int Loop = 0; Loop < Passes[PassNum].Layers.size(); Loop++) {
glActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glEnable(GL_TEXTURE_2D);
Passes[PassNum].Layers[Loop].BaseTexture->Bind();
glClientActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, Passes[PassNum].Layers[Loop].BaseTexCoords);
if(PassNum == 0 && Loop == 0)
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
else {
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ARB,GL_ADD);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_RGB,GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE1_RGB,GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV,GL_SOURCE0_ALPHA,GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV,GL_COMBINE_ALPHA,GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND0_RGB,GL_SRC_COLOR);
glTexEnvi(GL_TEXTURE_ENV,GL_OPERAND1_RGB,GL_SRC_COLOR);
}
TexUnit++;
if(Passes[PassNum].Layers[Loop].AlphaTexture != NULL) {
glActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glEnable(GL_TEXTURE_2D);
Passes[PassNum].Layers[Loop].AlphaTexture->Bind();
glClientActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, Passes[PassNum].Layers[Loop].AlphaTexCoords);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);
glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);
glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_PREVIOUS);
TexUnit++;
}
glColor4fv((float*)&Passes[PassNum].Layers[Loop].BaseColor);
}
for( ; TexUnit < MaxTexturesPerPass; TexUnit++) {
glActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glClientActiveTextureARB(GL_TEXTURE0_ARB+TexUnit);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}