Difference between revisions of "Texture Combiners"

From OpenGL Wiki
Jump to: navigation, search
(Adding vertex shader)
(Example : Interpolate tex0 and tex1 and multiply the result)
 
(20 intermediate revisions by 3 users not shown)
Line 24: Line 24:
 
=== Example : multiply tex0 and tex1 ===
 
=== Example : multiply tex0 and tex1 ===
 
The keyword here is GL_MODULATE, which does the actual multiplication.
 
The keyword here is GL_MODULATE, which does the actual multiplication.
 +
 +
Mathematically, it look like this
 +
  result_rgb = texture0_rgb    // Just read the texture
 +
  result_a = texture0_a
 +
  result_rgb = result_rgb * texture1_rgb
 +
  result_a = result_a * texture1_a
 +
 +
The setup code for the Texture Combiners will look like this
 +
<source lang="c">
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
   //Simply sample the texture
+
   // Simply sample the texture
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   //------------------------
+
   // --------------------
 
   glActiveTexture(GL_TEXTURE1);
 
   glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 
   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);
   //Sample RGB, multiply by previous texunit result
+
   // 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_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);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 
   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_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);  //Modulate ALPHA with ALPHA
+
   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);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
   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_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
+
</source>
 
The equivalent with GL 2.0 shaders
 
The equivalent with GL 2.0 shaders
   //Vertex shader
+
<source lang="glsl">
 +
   // Vertex shader
 
   #version 110
 
   #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  attribute vec2 InTexCoord1;
 
   uniform mat4 ProjectionModelviewMatrix;
 
   uniform mat4 ProjectionModelviewMatrix;
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   varying vec2 TexCoord1;    //Or just use TexCoord0
+
   varying vec2 TexCoord1;    // Or just use TexCoord0
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
     gl_Position = ProjectionModelviewMatrix * gl_Vertex;
+
     gl_Position = ProjectionModelviewMatrix * InVertex;
     TexCoord0 = gl_MultiTexCoord0.xy;
+
     TexCoord0 = InTexCoord0;
     TexCoord1 = gl_MultiTexCoord1.xy;
+
     TexCoord1 = InTexCoord1;
 
   }
 
   }
  //------------------------
+
</source>
   //Fragment shader
+
 
 +
<source lang="glsl">
 +
   // Fragment shader
 
   #version 110
 
   #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   varying vec2 TexCoord1;    //Or just use TexCoord0
+
   varying vec2 TexCoord1;    // Or just use TexCoord0
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 73: Line 90:
 
     gl_FragColor = texel;
 
     gl_FragColor = texel;
 
   }
 
   }
 +
</source>
  
 
=== 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.
 
The keyword here is GL_INTERPOLATE.
 +
<source lang="c">
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   //------------------------
+
   // --------------------
 
   glActiveTexture(GL_TEXTURE1);
 
   glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 
   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);   //Interpolate RGB with RGB
+
   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)
+
   // 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);
 
   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_OPERAND2_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_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);
   //GL_CONSTANT refers to the call we make with glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor)
+
   // 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_SOURCE2_ALPHA, GL_CONSTANT);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
   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_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
   //------------------------
+
   // --------------------
 
   float mycolor[4];
 
   float mycolor[4];
   mycolor[0]=mycolor[1]=mycolor[2]=0.0;    //RGB doesn't matter since we are not using it
+
   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
+
   mycolor[3]=0.75;                        // Set the blend factor with this
 
   glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor);
 
   glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor);
 +
</source>
 +
The equivalent with GL 2.0 shaders
 +
<source lang="glsl">
 +
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  attribute vec2 InTexCoord1;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    // Or just use TexCoord0
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
    TexCoord1 = InTexCoord1;
 +
  }
 +
</source>
  
The equivalent with GL 2.0 shaders
+
<source lang="glsl">
   //Fragment shader
+
   // Fragment shader
 +
  #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
 
   uniform float BlendFactor;
 
   uniform float BlendFactor;
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   varying vec2 TexCoord1;    //Or just use TexCoord0
+
   varying vec2 TexCoord1;    // Or just use TexCoord0
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 121: Line 162:
 
     gl_FragColor = mix(texel0, texel1, BlendFactor);
 
     gl_FragColor = mix(texel0, texel1, BlendFactor);
 
   }
 
   }
 
+
</source>
 
=== Example : Blend tex0 and tex1 based on alpha of tex0 ===
 
=== Example : Blend tex0 and tex1 based on alpha of tex0 ===
 
The keyword here is GL_INTERPOLATE.
 
The keyword here is GL_INTERPOLATE.
 +
<source lang="c">
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   //------------------------
+
   // --------------------
 
   glActiveTexture(GL_TEXTURE1);
 
   glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 
   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);   //Interpolate RGB with RGB
+
   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);
Line 138: Line 182:
 
   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_OPERAND2_RGB, GL_SRC_ALPHA);
 
   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_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 146: Line 190:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 +
</source>
  
 
The equivalent with GL 2.0 shaders
 
The equivalent with GL 2.0 shaders
   //Fragment shader
+
<source lang="glsl">
 +
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  attribute vec2 InTexCoord1;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    // Or just use TexCoord0
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
    TexCoord1 = InTexCoord1;
 +
  }
 +
</source>
 +
<source lang="glsl">
 +
   // Fragment shader
 +
  #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   varying vec2 TexCoord1;    //Or just use TexCoord0
+
   varying vec2 TexCoord1;    // Or just use TexCoord0
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 161: Line 225:
 
     gl_FragColor = mix(texel0, texel1, texel0.a);
 
     gl_FragColor = mix(texel0, texel1, texel0.a);
 
   }
 
   }
 +
</source>
 +
=== Example : Blend tex1 and tex2 based on alpha of tex0 ===
 +
The keyword here is GL_INTERPOLATE.
  
 
=== Example : Blend tex1 and tex2 based on alpha of tex0 ===
 
The keyword here is GL_INTERPOLATE.<br>
 
 
tex0's ALPHA is the mask.
 
tex0's ALPHA is the mask.
 +
<source lang="c">
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
+
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   //------------------------
+
   // --------------------
 
   glActiveTexture(GL_TEXTURE1);
 
   glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 
   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_DECAL);    //Get RGB of this texture (tex1)
+
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);    // Get RGB of this texture (tex1)
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_TEXTURE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 
   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_COMBINE_ALPHA, GL_REPLACE);   // Get ALPHA of previous TUI (tex0)
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_PREVIOUS);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
   glActiveTexture(GL_TEXTURE2);
 
   glActiveTexture(GL_TEXTURE2);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID2);
 
   glBindTexture(GL_TEXTURE_2D, textureID2);
 
   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);   //Interpolate RGB with RGB
+
   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);
Line 190: Line 258:
 
   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_OPERAND2_RGB, GL_SRC_ALPHA);
 
   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_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 198: Line 266:
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, GL_SRC_ALPHA);
 
+
</source>
 
With shaders, things are much more flexible.
 
With shaders, things are much more flexible.
   //Fragment shader
+
<source lang="glsl">
   uniform sampler2D Texture0;  //Mask
+
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
  }
 +
</source>
 +
<source lang="glsl">
 +
   // Fragment shader
 +
  #version 110
 +
   uniform sampler2D Texture0;  // Mask
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture2;
 
   uniform sampler2D Texture2;
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 214: Line 298:
 
     gl_FragColor = mix(texel1, texel2, texel0.a);
 
     gl_FragColor = mix(texel1, texel2, texel0.a);
 
   }
 
   }
 
+
</source>
In this one, we place the mask at TIU 2
+
In this one, we place the mask at TIU 2 (You can in fact have your texture with the alpha mask on any TIU you want)
   //Fragment shader
+
<source lang="glsl">
 +
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
  }
 +
</source>
 +
<source lang="glsl">
 +
   // Fragment shader
 +
  #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
   uniform sampler2D Texture2;   //Mask
+
   uniform sampler2D Texture2; // Mask
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 230: Line 330:
 
     gl_FragColor = mix(texel0, texel1, texel2.a);
 
     gl_FragColor = mix(texel0, texel1, texel2.a);
 
   }
 
   }
 
+
</source>
 
=== Example : Add tex0 and tex1 ===
 
=== Example : Add tex0 and tex1 ===
 
The keyword here is GL_ADD.
 
The keyword here is GL_ADD.
 +
<source lang="c">
 
   glActiveTexture(GL_TEXTURE0);
 
   glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glBindTexture(GL_TEXTURE_2D, textureID0);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
   //------------------------
+
   // --------------------
 
   glActiveTexture(GL_TEXTURE1);
 
   glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 
   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);    //Add RGB with RGB
+
   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);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
 
   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_OPERAND1_RGB, GL_SRC_COLOR);
   //------------------------
+
   // --------------------
   glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_ADD);    //Add ALPHA with ALPHA
+
   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);
 
   glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 
   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_OPERAND1_ALPHA, GL_SRC_ALPHA);
 
+
</source>
 
The equivalent with GL 2.0 shaders
 
The equivalent with GL 2.0 shaders
   //Fragment shader
+
<source lang="glsl">
 +
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
  }
 +
</source>
 +
<source lang="glsl">
 +
   // Fragment shader
 +
  #version 110
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture0;
 
   uniform sampler2D Texture1;
 
   uniform sampler2D Texture1;
   //------------------------
+
   // --------------------
 
   varying vec2 TexCoord0;
 
   varying vec2 TexCoord0;
   //------------------------
+
   // --------------------
 
   void main()
 
   void main()
 
   {
 
   {
Line 265: Line 384:
 
     gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0);
 
     gl_FragColor = clamp(texel0 + texel1, 0.0, 1.0);
 
   }
 
   }
 +
</source>
 +
=== Example : Interpolate tex0 and tex1 and multiply the result===
 +
This shows one of the limitations of Texture Combiners and how Shaders really come to the rescue. But at least, this case can be done with Texture Combiners!
 +
 +
From looking at the above examples, you have already noticed how texture image units and texcoord are not decoupled in Texture Combiners. This example also shows this.
 +
 +
Mathematically, we want to do
 +
  result_rgb = (Tex0_rgb * factor) + (Tex1_rgb * (1 - factor))    // Interpolate
 +
  result_rgb = result_rgb * color_rgb    // Multiply by a color factor
 +
 +
Tex0 can be placed on Texture Image Unit (TIU) 0 and Tex1 can be placed on TIU 1. For doing color_rgb, you are going to need another TIU. You have to bind a dummy texture and activate the TIU. You aren't forced to send texcoords for TIU 2.
 +
 +
Here is the Texture Combiner setup code :
 +
<source lang="c">
 +
  glActiveTexture(GL_TEXTURE0);
 +
  glEnable(GL_TEXTURE_2D);
 +
  glBindTexture(GL_TEXTURE_2D, textureID0);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
 +
  // --------------------
 +
  glActiveTexture(GL_TEXTURE1);
 +
  glEnable(GL_TEXTURE_2D);
 +
  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_REPLACE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);    // REPLACE just need a SOURCE0 and OPERAND0
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_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);
 +
  glActiveTexture(GL_TEXTURE2);
 +
  glEnable(GL_TEXTURE_2D);    // Activate the unit
 +
  glBindTexture(GL_TEXTURE_2D, dummyTexture);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
 +
  // GL_CONSTANT refers to the call we make with  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2)
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_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_COMBINE_ALPHA, GL_REPLACE);
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);    // REPLACE just need a SOURCE0 and OPERAND0
 +
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
 +
  // --------------------
 +
  float mycolor2[4];
 +
  mycolor2[0]=0.6;    // Red
 +
  mycolor2[1]=0.8;    // Green
 +
  mycolor2[2]=1.0;    // Blue
 +
  mycolor2[3]=1.0;    // Alpha
 +
  // This glTexEnvfv call is loaded on TIU 2 because of the call to glActiveTexture(GL_TEXTURE2)
 +
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2);
 +
</source>
 +
So the above Texture Combiner setup looks really complicated and nasty. The Shader version will look like this.
 +
 +
The equivalent with GL 2.0 shaders
 +
<source lang="glsl">
 +
  // Vertex shader
 +
  #version 110
 +
  attribute vec4 InVertex;
 +
  attribute vec2 InTexCoord0;
 +
  attribute vec2 InTexCoord1;
 +
  uniform mat4 ProjectionModelviewMatrix;
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    // Or just use TexCoord0
 +
  // --------------------
 +
  void main()
 +
  {
 +
    gl_Position = ProjectionModelviewMatrix * InVertex;
 +
    TexCoord0 = InTexCoord0;
 +
    TexCoord1 = InTexCoord1;
 +
  }
 +
</source>
 +
<source lang="glsl">
 +
  // Fragment shader
 +
  #version 110
 +
  uniform sampler2D Texture0;
 +
  uniform sampler2D Texture1;
 +
  uniform float BlendFactor;
 +
  uniform vec4 ColorFactor;
 +
  // --------------------
 +
  varying vec2 TexCoord0;
 +
  varying vec2 TexCoord1;    // Or just use TexCoord0
 +
  // --------------------
 +
  void main()
 +
  {
 +
    vec4 ColorResult;
 +
    vec4 texel0 = texture2D(Texture0, TexCoord0);
 +
    vec4 texel1 = texture2D(Texture1, TexCoord1);
 +
    ColorResult = mix(texel0,  texel1, BlendFactor);
 +
    gl_FragColor = ColorResult * ColorFactor;
 +
  }
 +
</source>
 +
The shader above is using custom attributes InVertex, InTexCoord0 and InTexCoord1. It is using 2 texcoord inputs although perhaps you don't need 2 if both will be the same. That is entirely up to you. There are 2 texture image units we are sampling. You don't need a dummy texture in this world of shaders and total flexibility. The ColorFactor is just another uniform. You just upload it with a glUniform* call. The shader code is short and clearcut compared to the dozens of lines for setting up a Texture Combiners.
 +
[[Category:Deprecated]]

Latest revision as of 10:26, 3 January 2018

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.

For the fixed pipeline, to know how many texture units are supported, call glGetIntegerv(GL_MAX_TEXTURE_UNITS, &MaxTextureUnits).
For early hw like nVidia TNT and Geforce 256, it would be 2 units.
Even on a modern GPU like a Gf 8, the number is 4, although in reality the GPU can do far more in the programmable pipeline.
Each unit has its own texture bind, its own texture coordinate, its own texture matrix, its own TexGen, its own TexEnv states.
The examples below show us binding a texture and TexEnv.

For the programmable pipeline, the texture image samplers and texcoords are dissociated. You could for example use TexCoord0 to sample Texture Unit 5.
In the programmable pipeline, there are no texture matrices. There are no TexGen states and no TexEnv states.
You upload the matrices yourself with glUniformMatrix and the mathematics of TexGen and TexEnv, you simply code it yourself.
This page explains the math for glTexGen http://www.opengl.org/wiki/Mathematics_of_glTexGen

glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &MaxTextureImageUnits) tells you how many samplers you have. This might be 16 or 32.
glGetIntegerv(GL_MAX_TEXTURE_COORDS, &MaxTextureCoords) tells you how many texcoords you have. This might be 8.
Most people don't need to send much texcoords to their vertex shaders but they need to sample a lot of textures, that is why the numbers are always not equal on all GPUs.
In the programmable pipeline, a sampler means texture image units. The states are the MIN and MAG filter, anisotropy, lower mip level.

Example : multiply tex0 and tex1

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

Mathematically, it look like this

 result_rgb = texture0_rgb    // Just read the texture
 result_a = texture0_a
 result_rgb = result_rgb * texture1_rgb
 result_a = result_a * texture1_a

The setup code for the Texture Combiners will look like this

  glActiveTexture(GL_TEXTURE0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  // Simply sample the texture
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  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

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  attribute vec2 InTexCoord1;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  varying vec2 TexCoord1;    // Or just use TexCoord0
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
    TexCoord1 = InTexCoord1;
  }
  // Fragment shader
  #version 110
  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);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  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

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  attribute vec2 InTexCoord1;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  varying vec2 TexCoord1;    // Or just use TexCoord0
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
    TexCoord1 = InTexCoord1;
  }
  // Fragment shader
  #version 110
  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);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  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

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  attribute vec2 InTexCoord1;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  varying vec2 TexCoord1;    // Or just use TexCoord0
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
    TexCoord1 = InTexCoord1;
  }
  // Fragment shader
  #version 110
  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);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID1);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_REPLACE);    // 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_REPLACE);    // 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);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID2);
  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);

With shaders, things are much more flexible.

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
  }
  // Fragment shader
  #version 110
  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 (You can in fact have your texture with the alpha mask on any TIU you want)

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
  }
  // Fragment shader
  #version 110
  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);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  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

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
  }
  // Fragment shader
  #version 110
  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);
  }

Example : Interpolate tex0 and tex1 and multiply the result

This shows one of the limitations of Texture Combiners and how Shaders really come to the rescue. But at least, this case can be done with Texture Combiners!

From looking at the above examples, you have already noticed how texture image units and texcoord are not decoupled in Texture Combiners. This example also shows this.

Mathematically, we want to do

 result_rgb = (Tex0_rgb * factor) + (Tex1_rgb * (1 - factor))    // Interpolate
 result_rgb = result_rgb * color_rgb    // Multiply by a color factor

Tex0 can be placed on Texture Image Unit (TIU) 0 and Tex1 can be placed on TIU 1. For doing color_rgb, you are going to need another TIU. You have to bind a dummy texture and activate the TIU. You aren't forced to send texcoords for TIU 2.

Here is the Texture Combiner setup code :

  glActiveTexture(GL_TEXTURE0);
  glEnable(GL_TEXTURE_2D);
  glBindTexture(GL_TEXTURE_2D, textureID0);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
  // --------------------
  glActiveTexture(GL_TEXTURE1);
  glEnable(GL_TEXTURE_2D);
  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_REPLACE);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_TEXTURE);    // REPLACE just need a SOURCE0 and OPERAND0
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_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);
  glActiveTexture(GL_TEXTURE2);
  glEnable(GL_TEXTURE_2D);    // Activate the unit
  glBindTexture(GL_TEXTURE_2D, dummyTexture);
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
  glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB, GL_PREVIOUS);
  // GL_CONSTANT refers to the call we make with  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2)
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_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_COMBINE_ALPHA, GL_REPLACE);
  glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA, GL_CONSTANT);    // REPLACE just need a SOURCE0 and OPERAND0
  glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);
  // --------------------
  float mycolor2[4];
  mycolor2[0]=0.6;    // Red
  mycolor2[1]=0.8;    // Green
  mycolor2[2]=1.0;    // Blue
  mycolor2[3]=1.0;    // Alpha
  // This glTexEnvfv call is loaded on TIU 2 because of the call to glActiveTexture(GL_TEXTURE2)
  glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, mycolor2);

So the above Texture Combiner setup looks really complicated and nasty. The Shader version will look like this.

The equivalent with GL 2.0 shaders

  // Vertex shader
  #version 110
  attribute vec4 InVertex;
  attribute vec2 InTexCoord0;
  attribute vec2 InTexCoord1;
  uniform mat4 ProjectionModelviewMatrix;
  varying vec2 TexCoord0;
  varying vec2 TexCoord1;    // Or just use TexCoord0
  // --------------------
  void main()
  {
    gl_Position = ProjectionModelviewMatrix * InVertex;
    TexCoord0 = InTexCoord0;
    TexCoord1 = InTexCoord1;
  }
  // Fragment shader
  #version 110
  uniform sampler2D Texture0;
  uniform sampler2D Texture1;
  uniform float BlendFactor;
  uniform vec4 ColorFactor;
  // --------------------
  varying vec2 TexCoord0;
  varying vec2 TexCoord1;    // Or just use TexCoord0
  // --------------------
  void main()
  {
     vec4 ColorResult;
     vec4 texel0 = texture2D(Texture0, TexCoord0);
     vec4 texel1 = texture2D(Texture1, TexCoord1);
     ColorResult = mix(texel0,  texel1, BlendFactor);
     gl_FragColor = ColorResult * ColorFactor;
  }

The shader above is using custom attributes InVertex, InTexCoord0 and InTexCoord1. It is using 2 texcoord inputs although perhaps you don't need 2 if both will be the same. That is entirely up to you. There are 2 texture image units we are sampling. You don't need a dummy texture in this world of shaders and total flexibility. The ColorFactor is just another uniform. You just upload it with a glUniform* call. The shader code is short and clearcut compared to the dozens of lines for setting up a Texture Combiners.