Difference between revisions of "Texture Combiners"

From OpenGL Wiki
Jump to: navigation, search
(Example : Blend tex0 and tex1 based on a blending factor you supply)
Line 1: Line 1:
Texture combiners became core in GL 1.3. You can combine by multiplying, replacing, adding, subtracting, DOT3 product.<br>
+
Texture combiners became core in GL 1.3. You can combine by multiplying, replacing, adding, subtracting, or doing a DOT3 product.<br>
 
GL 1.4 added to the core a crossbar feature. This means that you sample GL_TEXTUREX from any other texture image unit (TIU).<br>
 
GL 1.4 added to the core a crossbar feature. This means that you sample GL_TEXTUREX from any other texture image unit (TIU).<br>
 +
For example, at TUI 4, you can sample GL_TEXTURE0 or GL_TEXTURE1 or GL_TEXTURE2 or GL_TEXTURE3.<br>
 +
The examples here also show the equivalent shader code in GLSL to encourage people to use shaders instead of the fixed pipeline.<br>
 
<br>
 
<br>
 
=== Example : multiply tex0 and tex1 ===
 
=== Example : multiply tex0 and tex1 ===
 +
The keyword here is GL_MODULATE, which does the actual multiplication.
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
Line 12: Line 15:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 
   //Sample RGB, multiply by previous texunit result
 
   //Sample RGB, multiply by previous texunit result
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);   //Modulate RGB with RGB
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
Line 18: Line 21:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 
   //Sample ALPHA, multiply by previous texunit result
 
   //Sample ALPHA, multiply by previous texunit result
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE); //Modulate ALPHA with ALPHA
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
Line 40: Line 43:
  
 
=== Example : Blend tex0 and tex1 based on a blending factor you supply ===
 
=== Example : Blend tex0 and tex1 based on a blending factor you supply ===
 +
The keyword here is GL_INTERPOLATE.
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
Line 47: Line 51:
 
   glBindTexture(GL_TEXTURE_2D, textureID1);
 
   glBindTexture(GL_TEXTURE_2D, textureID1);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);   //Interpolate RGB with RGB
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 +
  //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor)
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
Line 55: Line 60:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
 
   //------------------------
 
   //------------------------
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);   //Interpolate ALPHA with ALPHA
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
Line 83: Line 88:
 
     vec4 texel1 = texture2D(Texture1, TexCoord1);
 
     vec4 texel1 = texture2D(Texture1, TexCoord1);
 
     gl_FragColor = mix(texel0, texel1, BlendFactor);
 
     gl_FragColor = mix(texel0, texel1, BlendFactor);
 +
  }
 +
 +
=== Example : Blend tex0 and tex1 based on alpha of tex0 ===
 +
The keyword here is GL_INTERPOLATE.
 +
  glActiveTexture(GL_TEXTURE0);
 +
  glBindTexture(GL_TEXTURE_2D, textureID0);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 +
  //------------------------
 +
  glActiveTexture(GL_TEXTURE1);
 +
  glBindTexture(GL_TEXTURE_2D, textureID1);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);  //Interpolate RGB with RGB
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
 +
  //------------------------
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);  //Interpolate ALPHA with ALPHA
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 +
 +
The equivalent with GL 2.0 shaders
 +
  //Fragment shader
 +
  uniform sampler2D Texture0;
 +
  uniform sampler2D Texture1;
 +
  //------------------------
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    //Or just use TexCoord0
 +
  //------------------------
 +
  void main()
 +
  {
 +
    vec4 texel0 = texture2D(Texture0, TexCoord0);
 +
    vec4 texel1 = texture2D(Texture1, TexCoord1);
 +
    gl_FragColor = mix(texel0, texel1, texel0.a);
 +
  }
 +
 +
 +
=== Example : Blend tex1 and tex2 based on alpha of tex0 ===
 +
The keyword here is GL_INTERPOLATE.<br>
 +
tex0's ALPHA is the mask.
 +
  glActiveTexture(GL_TEXTURE0);
 +
  glBindTexture(GL_TEXTURE_2D, textureID0);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 +
  //------------------------
 +
  glActiveTexture(GL_TEXTURE1);
 +
  glBindTexture(GL_TEXTURE_2D, textureID1);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DECAL);    //Get RGB of this texture (tex1)
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 +
  //------------------------
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_DECAL);  //Get ALPHA of previous TUI (tex0)
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
  glActiveTexture(GL_TEXTURE2);
 +
  glBindTexture(GL_TEXTURE_2D, textureID2);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);  //Interpolate RGB with RGB
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
 +
  //------------------------
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);  //Interpolate ALPHA with ALPHA
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 +
 +
With shaders, things are much more flexible.
 +
  //Fragment shader
 +
  uniform sampler2D Texture0;  //Mask
 +
  uniform sampler2D Texture1;
 +
  uniform sampler2D Texture2;
 +
  //------------------------
 +
  varying vec2 TexCoord0;
 +
  //------------------------
 +
  void main()
 +
  {
 +
    vec4 texel0 = texture2D(Texture0, TexCoord0);
 +
    vec4 texel1 = texture2D(Texture1, TexCoord0);
 +
    vec4 texel2 = texture2D(Texture2, TexCoord0);
 +
    gl_FragColor = mix(texel1, texel2, texel0.a);
 +
  }
 +
 +
In this one, we place the mask at TIU 2
 +
  //Fragment shader
 +
  uniform sampler2D Texture0;
 +
  uniform sampler2D Texture1;
 +
  uniform sampler2D Texture2;  //Mask
 +
  //------------------------
 +
  varying vec2 TexCoord0;
 +
  //------------------------
 +
  void main()
 +
  {
 +
    vec4 texel0 = texture2D(Texture0, TexCoord0);
 +
    vec4 texel1 = texture2D(Texture1, TexCoord0);
 +
    vec4 texel2 = texture2D(Texture2, TexCoord0);
 +
    gl_FragColor = mix(texel0, texel1, texel2.a);
 
   }
 
   }
  
 
=== Example : Add tex0 and tex1 ===
 
=== Example : Add tex0 and tex1 ===
 +
The keyword here is GL_ADD.
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
Line 93: Line 207:
 
   glBindTexture(GL_TEXTURE_2D, textureID1);
 
   glBindTexture(GL_TEXTURE_2D, textureID1);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);   //Add RGB with RGB
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
Line 99: Line 213:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 
   //------------------------
 
   //------------------------
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);   //Add ALPHA with ALPHA
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);

Revision as of 14:15, 11 July 2009

Texture combiners became core in GL 1.3. You can combine by multiplying, replacing, adding, subtracting, or doing a DOT3 product.
GL 1.4 added to the core a crossbar feature. This means that you sample GL_TEXTUREX from any other texture image unit (TIU).
For example, at TUI 4, you can sample GL_TEXTURE0 or GL_TEXTURE1 or GL_TEXTURE2 or GL_TEXTURE3.
The examples here also show the equivalent shader code in GLSL to encourage people to use shaders instead of the fixed pipeline.

Example : multiply tex0 and tex1

The keyword here is GL_MODULATE, which does the actual multiplication.

 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, textureID0);
 //Simply sample the texture
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 //------------------------
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, textureID1);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 //Sample RGB, multiply by previous texunit result
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);   //Modulate RGB with RGB
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 //Sample ALPHA, multiply by previous texunit result
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);  //Modulate ALPHA with ALPHA
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

The equivalent with GL 2.0 shaders

 //Fragment shader
 uniform sampler2D Texture0;
 uniform sampler2D Texture1;
 //------------------------
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
    vec4 texel = texture2D(Texture0, TexCoord0);
    texel *= texture2D(Texture1, TexCoord1);
    gl_FragColor = texel;
 }

Example : Blend tex0 and tex1 based on a blending factor you supply

The keyword here is GL_INTERPOLATE.

 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, textureID0);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 //------------------------
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, textureID1);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);   //Interpolate RGB with RGB
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor)
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_CONSTANT);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_COLOR);
 //------------------------
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);   //Interpolate ALPHA with ALPHA
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor)
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_CONSTANT);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 //------------------------
 float mycolor[4];
 mycolor[0]=mycolor[1]=mycolor[2]=0.0;    //RGB doesn't matter since we are not using it
 mycolor[3]=0.75;                         //Set the blend factor with this
 glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor);

The equivalent with GL 2.0 shaders

 //Fragment shader
 uniform sampler2D Texture0;
 uniform sampler2D Texture1;
 uniform float BlendFactor;
 //------------------------
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
    vec4 texel0 = texture2D(Texture0, TexCoord0);
    vec4 texel1 = texture2D(Texture1, TexCoord1);
    gl_FragColor = mix(texel0, texel1, BlendFactor);
 }

Example : Blend tex0 and tex1 based on alpha of tex0

The keyword here is GL_INTERPOLATE.

 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, textureID0);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 //------------------------
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, textureID1);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);   //Interpolate RGB with RGB
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
 //------------------------
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);   //Interpolate ALPHA with ALPHA
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);

The equivalent with GL 2.0 shaders

 //Fragment shader
 uniform sampler2D Texture0;
 uniform sampler2D Texture1;
 //------------------------
 varying vec2 TexCoord0;
 varying vec2 TexCoord1;    //Or just use TexCoord0
 //------------------------
 void main()
 {
    vec4 texel0 = texture2D(Texture0, TexCoord0);
    vec4 texel1 = texture2D(Texture1, TexCoord1);
    gl_FragColor = mix(texel0, texel1, texel0.a);
 }


Example : Blend tex1 and tex2 based on alpha of tex0

The keyword here is GL_INTERPOLATE.
tex0's ALPHA is the mask.

 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, textureID0);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
 //------------------------
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, textureID1);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_DECAL);    //Get RGB of this texture (tex1)
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 //------------------------
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_DECAL);  //Get ALPHA of previous TUI (tex0)
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glActiveTexture(GL_TEXTURE2);
 glBindTexture(GL_TEXTURE_2D, textureID2);
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);   //Interpolate RGB with RGB
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
 //------------------------
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_INTERPOLATE);   //Interpolate ALPHA with ALPHA
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);

With shaders, things are much more flexible.

 //Fragment shader
 uniform sampler2D Texture0;  //Mask
 uniform sampler2D Texture1;
 uniform sampler2D Texture2;
 //------------------------
 varying vec2 TexCoord0;
 //------------------------
 void main()
 {
    vec4 texel0 = texture2D(Texture0, TexCoord0);
    vec4 texel1 = texture2D(Texture1, TexCoord0);
    vec4 texel2 = texture2D(Texture2, TexCoord0);
    gl_FragColor = mix(texel1, texel2, texel0.a);
 }

In this one, we place the mask at TIU 2

 //Fragment shader
 uniform sampler2D Texture0;
 uniform sampler2D Texture1;
 uniform sampler2D Texture2;   //Mask
 //------------------------
 varying vec2 TexCoord0;
 //------------------------
 void main()
 {
    vec4 texel0 = texture2D(Texture0, TexCoord0);
    vec4 texel1 = texture2D(Texture1, TexCoord0);
    vec4 texel2 = texture2D(Texture2, TexCoord0);
    gl_FragColor = mix(texel0, texel1, texel2.a);
 }

Example : Add tex0 and tex1

The keyword here is GL_ADD.

 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, textureID0);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 //------------------------
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, textureID1);
 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_ADD);    //Add RGB with RGB
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
 //------------------------
 glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);    //Add ALPHA with ALPHA
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA, GL_TEXTURE);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

The equivalent with GL 2.0 shaders

 //Fragment shader
 uniform sampler2D Texture0;
 uniform sampler2D Texture1;
 //------------------------
 varying vec2 TexCoord0;
 //------------------------
 void main()
 {
    vec4 texel0 = texture2D(Texture0, TexCoord0);
    vec4 texel1 = texture2D(Texture1, TexCoord0);
    gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0);
 }