Finished up GL_ARB_depth_texture and GL_ARB_shadow.
authorBrian Paul <brian.paul@tungstengraphics.com>
Fri, 15 Feb 2002 16:32:06 +0000 (16:32 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Fri, 15 Feb 2002 16:32:06 +0000 (16:32 +0000)
src/mesa/main/extensions.c
src/mesa/main/texobj.c
src/mesa/main/texstate.c
src/mesa/swrast/s_texture.c

index ee8eb4f5383298265603d11df66162b9d62549f4..8054360fd297b6f3546d85036ca06ce7f16d2ddc 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: extensions.c,v 1.68 2001/12/14 02:50:01 brianp Exp $ */
+/* $Id: extensions.c,v 1.69 2002/02/15 16:32:06 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
  * Version:  4.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -56,7 +56,7 @@ static struct {
    const char *name;
    int flag_offset;
 } default_extensions[] = {
-   { OFF, "GL_ARB_depth_texture",              F(SGIX_depth_texture) },
+   { OFF, "GL_ARB_depth_texture",              F(ARB_depth_texture) },
    { OFF, "GL_ARB_imaging",                    F(ARB_imaging) },
    { OFF, "GL_ARB_multisample",                F(ARB_multisample) },
    { OFF, "GL_ARB_multitexture",               F(ARB_multitexture) },
index a8a27ef3ed9e7017ea4c2d7c7a46bfc52a69d6c0..39f65940b5d608b927c7205a2294a01f897987d7 100644 (file)
@@ -1,10 +1,10 @@
-/* $Id: texobj.c,v 1.51 2001/12/04 23:44:56 brianp Exp $ */
+/* $Id: texobj.c,v 1.52 2002/02/15 16:32:06 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
- * Version:  3.5
+ * Version:  4.1
  *
- * Copyright (C) 1999-2001  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2002  Brian Paul   All Rights Reserved.
  *
  * Permission is hereby granted, free of charge, to any person obtaining a
  * copy of this software and associated documentation files (the "Software"),
@@ -84,7 +84,7 @@ _mesa_alloc_texture_object( struct gl_shared_state *shared,
       obj->CompareOperator = GL_TEXTURE_LEQUAL_R_SGIX;  /* SGIX_shadow */
       obj->CompareMode = GL_LUMINANCE;    /* ARB_shadow */
       obj->CompareFunc = GL_LEQUAL;       /* ARB_shadow */
-      obj->CompareResult = GL_LUMINANCE;  /* ARB_shadow */
+      obj->DepthMode = GL_LUMINANCE;      /* ARB_depth_texture */
       obj->ShadowAmbient = 0;             /* ARB/SGIX_shadow_ambient */
       _mesa_init_colortable(&obj->Palette);
 
@@ -360,6 +360,11 @@ _mesa_test_texobj_completeness( const GLcontext *ctx,
                   t->Complete = GL_FALSE;
                   return;
                }
+               if (t->Image[i]->Format == GL_DEPTH_COMPONENT) {
+                  t->Complete = GL_FALSE;
+                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
+                  return;
+               }
                if (t->Image[i]->Width2 != width) {
                   t->Complete = GL_FALSE;
                   incomplete(t, "3D Image[i] bad width");
@@ -393,6 +398,12 @@ _mesa_test_texobj_completeness( const GLcontext *ctx,
                height /= 2;
             }
             if (i >= minLevel && i <= maxLevel) {
+               /* Don't support GL_DEPTH_COMPONENT for cube maps */
+               if (t->Image[i]->Format == GL_DEPTH_COMPONENT) {
+                  t->Complete = GL_FALSE;
+                  incomplete(t, "GL_DEPTH_COMPONENT only works with 1/2D tex");
+                  return;
+               }
                /* check that we have images defined */
                if (!t->Image[i] || !t->NegX[i] ||
                    !t->PosY[i]  || !t->NegY[i] ||
index a8c70f0a4c5cb7ef37df4cf06152148c98b7b904..19e8984ad96ef8b79690a3ee6dc13262caf7b503 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: texstate.c,v 1.63 2002/01/09 02:14:29 brianp Exp $ */
+/* $Id: texstate.c,v 1.64 2002/02/15 16:32:06 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -46,7 +46,6 @@
 #ifndef GL_TEXTURE_COMPARE_MODE_ARB
 #define GL_TEXTURE_COMPARE_MODE_ARB    0x9990
 #define GL_TEXTURE_COMPARE_FUNC_ARB    0x9991
-#define GL_TEXTURE_COMPARE_RESULT_ARB  0x9992
 #define GL_COMPARE_R_TO_TEXTURE_ARB    0x9993
 #endif
 
@@ -1109,7 +1108,7 @@ _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
       case GL_TEXTURE_COMPARE_MODE_ARB:
          if (ctx->Extensions.ARB_shadow) {
             const GLenum mode = (GLenum) params[0];
-            if (mode == GL_LUMINANCE || mode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+            if (mode == GL_NONE || mode == GL_COMPARE_R_TO_TEXTURE_ARB) {
                FLUSH_VERTICES(ctx, _NEW_TEXTURE);
                texObj->CompareMode = params[0];
             }
@@ -1144,23 +1143,23 @@ _mesa_TexParameterfv( GLenum target, GLenum pname, const GLfloat *params )
             return;
          }
          break;
-      case GL_TEXTURE_COMPARE_RESULT_ARB:
-         if (ctx->Extensions.ARB_shadow) {
+      case GL_DEPTH_TEXTURE_MODE_ARB:
+         if (ctx->Extensions.ARB_depth_texture) {
             const GLenum result = (GLenum) params[0];
             if (result == GL_LUMINANCE || result == GL_INTENSITY
                 || result == GL_ALPHA) {
                FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-               texObj->CompareResult = params[0];
+               texObj->DepthMode = params[0];
             }
             else {
                _mesa_error(ctx, GL_INVALID_ENUM,
-                          "glTexParameter(bad GL_TEXTURE_COMPARE_RESULT_ARB)");
+                          "glTexParameter(bad GL_DEPTH_TEXTURE_MODE_ARB)");
                return;
             }
          }
          else {
             _mesa_error(ctx, GL_INVALID_ENUM,
-                        "glTexParameter(pname=GL_TEXTURE_COMPARE_RESULT_ARB)");
+                        "glTexParameter(pname=GL_DEPTH_TEXTURE_MODE_ARB)");
             return;
          }
          break;
@@ -1504,9 +1503,9 @@ _mesa_GetTexParameterfv( GLenum target, GLenum pname, GLfloat *params )
             return;
          }
          break;
-      case GL_TEXTURE_COMPARE_RESULT_ARB:
-         if (ctx->Extensions.ARB_shadow) {
-            *params = (GLfloat) obj->CompareResult;
+      case GL_DEPTH_TEXTURE_MODE_ARB:
+         if (ctx->Extensions.ARB_depth_texture) {
+            *params = (GLfloat) obj->DepthMode;
             return;
          }
          break;
@@ -1633,9 +1632,9 @@ _mesa_GetTexParameteriv( GLenum target, GLenum pname, GLint *params )
             return;
          }
          break;
-      case GL_TEXTURE_COMPARE_RESULT_ARB:
-         if (ctx->Extensions.ARB_shadow) {
-            *params = (GLint) obj->CompareResult;
+      case GL_DEPTH_TEXTURE_MODE_ARB:
+         if (ctx->Extensions.ARB_depth_texture) {
+            *params = (GLint) obj->DepthMode;
             return;
          }
          break;
index 206508559f0a1a8b1320ae4426c8bd9a291f7f06..0f1c5cdc9681755f6b7384a238d0b572e27e882f 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: s_texture.c,v 1.50 2002/02/15 03:41:47 brianp Exp $ */
+/* $Id: s_texture.c,v 1.51 2002/02/15 16:32:06 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -1753,140 +1753,477 @@ sample_lambda_cube( GLcontext *ctx, GLuint texUnit,
 }
 
 
+/*
+ * Sample a shadow/depth texture.
+ */
 static void
-null_sample_func( GLcontext *ctx, GLuint texUnit,
-                 const struct gl_texture_object *tObj, GLuint n,
-                 GLfloat texcoords[][4], const GLfloat lambda[],
-                 GLchan rgba[][4])
+sample_depth_texture( GLcontext *ctx, GLuint unit,
+                      const struct gl_texture_object *tObj, GLuint n,
+                      GLfloat texcoords[][4], const GLfloat lambda[],
+                      GLchan texel[][4] )
 {
-}
+   const GLint baseLevel = tObj->BaseLevel;
+   const struct gl_texture_image *texImage = tObj->Image[baseLevel];
+   const GLuint width = texImage->Width;
+   const GLuint height = texImage->Height;
+   const GLchan ambient = tObj->ShadowAmbient;
+   GLboolean lequal, gequal;
+   GLchan result;
 
+   (void) unit;
 
+   ASSERT(tObj->Image[tObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
+   ASSERT(tObj->Dimensions == 1 || tObj->Dimensions == 2);
 
-/**********************************************************************/
-/*                       Texture Sampling Setup                       */
-/**********************************************************************/
+   /* XXXX if tObj->MinFilter != tObj->MagFilter, we're ignoring lambda */
+
+   /* XXX this could be precomputed and saved in the texture object */
+   if (tObj->CompareFlag) {
+      /* GL_SGIX_shadow */
+      if (tObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
+         lequal = GL_TRUE;
+         gequal = GL_FALSE;
+      }
+      else {
+         ASSERT(tObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
+         lequal = GL_FALSE;
+         gequal = GL_TRUE;
+      }
+   }
+   else if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
+      /* GL_ARB_shadow */
+      if (tObj->CompareFunc == GL_LEQUAL) {
+         lequal = GL_TRUE;
+         gequal = GL_FALSE;
+      }
+      else {
+         ASSERT(tObj->CompareFunc == GL_GEQUAL);
+         lequal = GL_FALSE;
+         gequal = GL_TRUE;
+      }
+   }
+   else {
+      lequal = gequal = GL_FALSE;
+   }
 
+   if (tObj->MagFilter == GL_NEAREST) {
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         GLfloat depthSample;
+         GLint col, row;
+         COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapS, texcoords[i][0], width, col);
+         COMPUTE_NEAREST_TEXEL_LOCATION(tObj->WrapT, texcoords[i][1], height, row);
+         depthSample = *((const GLfloat *) texImage->Data + row * width + col);
 
-/*
- * Setup the texture sampling function for this texture object.
- */
-void
-_swrast_choose_texture_sample_func( GLcontext *ctx, GLuint texUnit,
-                                   const struct gl_texture_object *t )
-{
-   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+         if (lequal) {
+            if (texcoords[i][2] <= depthSample)
+               result = CHAN_MAX;
+            else
+               result = ambient;
+         }
+         else if (gequal) {
+            if (texcoords[i][2] >= depthSample)
+               result = CHAN_MAX;
+            else
+               result = ambient;
+         }
+         else {
+            /* no comparison */
+            CLAMPED_FLOAT_TO_CHAN(result, depthSample);
+         }
 
-  if (!t->Complete) {
-     swrast->TextureSample[texUnit] = null_sample_func;
+         switch (tObj->DepthMode) {
+         case GL_LUMINANCE:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = CHAN_MAX;
+            break;
+         case GL_INTENSITY:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = result;
+            break;
+         case GL_ALPHA:
+            texel[i][RCOMP] = 0;
+            texel[i][GCOMP] = 0;
+            texel[i][BCOMP] = 0;
+            texel[i][ACOMP] = result;
+            break;
+         default:
+            _mesa_problem(ctx, "Bad depth texture mode");
+         }
+      }
    }
    else {
-      GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
+      GLuint i;
+      ASSERT(tObj->MagFilter == GL_LINEAR);
+      for (i = 0; i < n; i++) {
+         GLfloat depth00, depth01, depth10, depth11;
+         GLint i0, i1, j0, j1;
+         GLfloat u, v;
+         GLuint useBorderTexel;
 
-      if (needLambda) {
-         /* Compute min/mag filter threshold */
-         if (t->MagFilter == GL_LINEAR
-             && (t->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
-                 t->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
-            swrast->_MinMagThresh[texUnit] = 0.5F;
+         COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapS, texcoords[i][0], u, width, i0, i1);
+         COMPUTE_LINEAR_TEXEL_LOCATIONS(tObj->WrapT, texcoords[i][1], v, height,j0, j1);
+
+         useBorderTexel = 0;
+         if (texImage->Border) {
+            i0 += texImage->Border;
+            i1 += texImage->Border;
+            j0 += texImage->Border;
+            j1 += texImage->Border;
          }
          else {
-            swrast->_MinMagThresh[texUnit] = 0.0F;
+            if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
+            if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
+            if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
+            if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
          }
-      }
 
-      switch (t->Dimensions) {
-         case 1:
-            if (needLambda) {
-               swrast->TextureSample[texUnit] = sample_lambda_1d;
-            }
-            else if (t->MinFilter==GL_LINEAR) {
-               swrast->TextureSample[texUnit] = sample_linear_1d;
+         /* get four depth samples from the texture */
+         if (useBorderTexel & (I0BIT | J0BIT)) {
+            depth00 = 1.0;
+         }
+         else {
+            depth00 = *((const GLfloat *) texImage->Data + j0 * width + i0);
+         }
+         if (useBorderTexel & (I1BIT | J0BIT)) {
+            depth10 = 1.0;
+         }
+         else {
+            depth10 = *((const GLfloat *) texImage->Data + j0 * width + i1);
+         }
+         if (useBorderTexel & (I0BIT | J1BIT)) {
+            depth01 = 1.0;
+         }
+         else {
+            depth01 = *((const GLfloat *) texImage->Data + j1 * width + i0);
+         }
+         if (useBorderTexel & (I1BIT | J1BIT)) {
+            depth11 = 1.0;
+         }
+         else {
+            depth11 = *((const GLfloat *) texImage->Data + j1 * width + i1);
+         }
+
+         if (0) {
+            /* compute a single weighted depth sample and do one comparison */
+            const GLfloat a = FRAC(u + 1.0F);
+            const GLfloat b = FRAC(v + 1.0F);
+            const GLfloat w00 = (1.0F - a) * (1.0F - b);
+            const GLfloat w10 = (       a) * (1.0F - b);
+            const GLfloat w01 = (1.0F - a) * (       b);
+            const GLfloat w11 = (       a) * (       b);
+            const GLfloat depthSample = w00 * depth00 + w10 * depth10
+                                      + w01 * depth01 + w11 * depth11;
+            if ((depthSample <= texcoords[i][2] && lequal) ||
+                (depthSample >= texcoords[i][2] && gequal)) {
+               result  = ambient;
             }
             else {
-               ASSERT(t->MinFilter==GL_NEAREST);
-               swrast->TextureSample[texUnit] = sample_nearest_1d;
+               result = CHAN_MAX;
             }
-            break;
-         case 2:
-            if (needLambda) {
-               swrast->TextureSample[texUnit] = sample_lambda_2d;
+         }
+         else {
+            /* Do four depth/R comparisons and compute a weighted result.
+             * If this touches on somebody's I.P., I'll remove this code
+             * upon request.
+             */
+            const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
+            GLfloat luminance = CHAN_MAXF;
+            if (lequal) {
+               if (depth00 <= texcoords[i][2])   luminance -= d;
+               if (depth01 <= texcoords[i][2])   luminance -= d;
+               if (depth10 <= texcoords[i][2])   luminance -= d;
+               if (depth11 <= texcoords[i][2])   luminance -= d;
+               result = (GLchan) luminance;
             }
-            else if (t->MinFilter==GL_LINEAR) {
-               swrast->TextureSample[texUnit] = sample_linear_2d;
+            else if (gequal) {
+               if (depth00 >= texcoords[i][2])   luminance -= d;
+               if (depth01 >= texcoords[i][2])   luminance -= d;
+               if (depth10 >= texcoords[i][2])   luminance -= d;
+               if (depth11 >= texcoords[i][2])   luminance -= d;
+               result = (GLchan) luminance;
             }
             else {
-               GLint baseLevel = t->BaseLevel;
-               ASSERT(t->MinFilter==GL_NEAREST);
-               if (t->WrapS == GL_REPEAT &&
-                   t->WrapT == GL_REPEAT &&
-                   t->Image[baseLevel]->Border == 0 &&
-                   t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
-                  swrast->TextureSample[texUnit] = opt_sample_rgb_2d;
-               }
-               else if (t->WrapS == GL_REPEAT &&
-                        t->WrapT == GL_REPEAT &&
-                        t->Image[baseLevel]->Border == 0 &&
-                        t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
-                  swrast->TextureSample[texUnit] = opt_sample_rgba_2d;
-               }
-               else
-                  swrast->TextureSample[texUnit] = sample_nearest_2d;
+               /* no comparison, just bilinear sampling */
+               const GLfloat a = FRAC(u + 1.0F);
+               const GLfloat b = FRAC(v + 1.0F);
+               const GLfloat w00 = (1.0F - a) * (1.0F - b);
+               const GLfloat w10 = (       a) * (1.0F - b);
+               const GLfloat w01 = (1.0F - a) * (       b);
+               const GLfloat w11 = (       a) * (       b);
+               const GLfloat depthSample = w00 * depth00 + w10 * depth10
+                                         + w01 * depth01 + w11 * depth11;
+               CLAMPED_FLOAT_TO_CHAN(result, depthSample);
             }
+         }
+
+         switch (tObj->DepthMode) {
+         case GL_LUMINANCE:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = CHAN_MAX;
             break;
-         case 3:
-            if (needLambda) {
-               swrast->TextureSample[texUnit] = sample_lambda_3d;
-            }
-            else if (t->MinFilter==GL_LINEAR) {
-               swrast->TextureSample[texUnit] = sample_linear_3d;
-            }
-            else {
-               ASSERT(t->MinFilter==GL_NEAREST);
-               swrast->TextureSample[texUnit] = sample_nearest_3d;
-            }
+         case GL_INTENSITY:
+            texel[i][RCOMP] = result;
+            texel[i][GCOMP] = result;
+            texel[i][BCOMP] = result;
+            texel[i][ACOMP] = result;
             break;
-         case 6: /* cube map */
-            if (needLambda) {
-               swrast->TextureSample[texUnit] = sample_lambda_cube;
-            }
-            else if (t->MinFilter==GL_LINEAR) {
-               swrast->TextureSample[texUnit] = sample_linear_cube;
-            }
-            else {
-               ASSERT(t->MinFilter==GL_NEAREST);
-               swrast->TextureSample[texUnit] = sample_nearest_cube;
-            }
+         case GL_ALPHA:
+            texel[i][RCOMP] = 0;
+            texel[i][GCOMP] = 0;
+            texel[i][BCOMP] = 0;
+            texel[i][ACOMP] = result;
             break;
          default:
-            _mesa_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
-      }
-   }
+            _mesa_problem(ctx, "Bad depth texture mode");
+         }
+      }  /* for */
+   }  /* if filter */
 }
 
 
-#define PROD(A,B)   ( (GLuint)(A) * ((GLuint)(B)+1) )
-#define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
-
-static INLINE void
-texture_combine(const GLcontext *ctx,
-                const struct gl_texture_unit *textureUnit,
-                GLuint n,
-                CONST GLchan (*primary_rgba)[4],
-                CONST GLchan (*texel)[4],
-                GLchan (*rgba)[4])
+#if 0
+/*
+ * Experimental depth texture sampling function.
+ */
+static void
+sample_depth_texture2(const GLcontext *ctx,
+                     const struct gl_texture_unit *texUnit,
+                     GLuint n, GLfloat texcoords[][4],
+                     GLchan texel[][4])
 {
-   const GLchan (*argRGB [3])[4];
-   const GLchan (*argA [3])[4];
-   GLuint i, j;
-   const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
-   const GLuint Ashift   = textureUnit->CombineScaleShiftA;
-#if CHAN_TYPE == GL_FLOAT
-   const GLchan RGBmult = (GLfloat) (1 << RGBshift);
-   const GLchan Amult = (GLfloat) (1 << Ashift);
-#else
-   const GLint half = (CHAN_MAX + 1) / 2;
-#endif
+   const struct gl_texture_object *texObj = texUnit->_Current;
+   const GLint baseLevel = texObj->BaseLevel;
+   const struct gl_texture_image *texImage = texObj->Image[baseLevel];
+   const GLuint width = texImage->Width;
+   const GLuint height = texImage->Height;
+   const GLchan ambient = texObj->ShadowAmbient;
+   GLboolean lequal, gequal;
+
+   if (texObj->Dimensions != 2) {
+      _mesa_problem(ctx, "only 2-D depth textures supported at this time");
+      return;
+   }
+
+   if (texObj->MinFilter != texObj->MagFilter) {
+      _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
+      return;
+   }
+
+   /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
+    * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
+    * isn't a depth texture.
+    */
+   if (texImage->Format != GL_DEPTH_COMPONENT) {
+      _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
+      return;
+   }
+
+   if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
+      lequal = GL_TRUE;
+      gequal = GL_FALSE;
+   }
+   else {
+      lequal = GL_FALSE;
+      gequal = GL_TRUE;
+   }
+
+   {
+      GLuint i;
+      for (i = 0; i < n; i++) {
+         const GLint K = 3;
+         GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
+         GLfloat w;
+         GLchan lum;
+         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0],
+                                       width, col);
+         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1],
+                                       height, row);
+
+         imin = col - K;
+         imax = col + K;
+         jmin = row - K;
+         jmax = row + K;
+
+         if (imin < 0)  imin = 0;
+         if (imax >= width)  imax = width - 1;
+         if (jmin < 0)  jmin = 0;
+         if (jmax >= height) jmax = height - 1;
+
+         samples = (imax - imin + 1) * (jmax - jmin + 1);
+         count = 0;
+         for (jj = jmin; jj <= jmax; jj++) {
+            for (ii = imin; ii <= imax; ii++) {
+               GLfloat depthSample = *((const GLfloat *) texImage->Data
+                                       + jj * width + ii);
+               if ((depthSample <= r[i] && lequal) ||
+                   (depthSample >= r[i] && gequal)) {
+                  count++;
+               }
+            }
+         }
+
+         w = (GLfloat) count / (GLfloat) samples;
+         w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
+         lum = (GLint) w;
+
+         texel[i][RCOMP] = lum;
+         texel[i][GCOMP] = lum;
+         texel[i][BCOMP] = lum;
+         texel[i][ACOMP] = CHAN_MAX;
+      }
+   }
+}
+#endif
+
+
+static void
+null_sample_func( GLcontext *ctx, GLuint texUnit,
+                 const struct gl_texture_object *tObj, GLuint n,
+                 GLfloat texcoords[][4], const GLfloat lambda[],
+                 GLchan rgba[][4])
+{
+}
+
+
+
+/**********************************************************************/
+/*                       Texture Sampling Setup                       */
+/**********************************************************************/
+
+
+/*
+ * Setup the texture sampling function for this texture object.
+ */
+void
+_swrast_choose_texture_sample_func( GLcontext *ctx, GLuint texUnit,
+                                   const struct gl_texture_object *t )
+{
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+
+   if (!t->Complete) {
+      swrast->TextureSample[texUnit] = null_sample_func;
+   }
+   else {
+      const GLboolean needLambda = (GLboolean) (t->MinFilter != t->MagFilter);
+      const GLenum format = t->Image[t->BaseLevel]->Format;
+
+      if (needLambda) {
+         /* Compute min/mag filter threshold */
+         if (t->MagFilter == GL_LINEAR
+             && (t->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
+                 t->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
+            swrast->_MinMagThresh[texUnit] = 0.5F;
+         }
+         else {
+            swrast->_MinMagThresh[texUnit] = 0.0F;
+         }
+      }
+
+      switch (t->Dimensions) {
+         case 1:
+            if (format == GL_DEPTH_COMPONENT) {
+               swrast->TextureSample[texUnit] = sample_depth_texture;
+            }
+            else if (needLambda) {
+               swrast->TextureSample[texUnit] = sample_lambda_1d;
+            }
+            else if (t->MinFilter == GL_LINEAR) {
+               swrast->TextureSample[texUnit] = sample_linear_1d;
+            }
+            else {
+               ASSERT(t->MinFilter == GL_NEAREST);
+               swrast->TextureSample[texUnit] = sample_nearest_1d;
+            }
+            break;
+         case 2:
+            if (format == GL_DEPTH_COMPONENT) {
+               swrast->TextureSample[texUnit] = sample_depth_texture;
+            }
+            else if (needLambda) {
+               swrast->TextureSample[texUnit] = sample_lambda_2d;
+            }
+            else if (t->MinFilter == GL_LINEAR) {
+               swrast->TextureSample[texUnit] = sample_linear_2d;
+            }
+            else {
+               GLint baseLevel = t->BaseLevel;
+               ASSERT(t->MinFilter == GL_NEAREST);
+               if (t->WrapS == GL_REPEAT &&
+                   t->WrapT == GL_REPEAT &&
+                   t->Image[baseLevel]->Border == 0 &&
+                   t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGB) {
+                  swrast->TextureSample[texUnit] = opt_sample_rgb_2d;
+               }
+               else if (t->WrapS == GL_REPEAT &&
+                        t->WrapT == GL_REPEAT &&
+                        t->Image[baseLevel]->Border == 0 &&
+                        t->Image[baseLevel]->TexFormat->MesaFormat == MESA_FORMAT_RGBA) {
+                  swrast->TextureSample[texUnit] = opt_sample_rgba_2d;
+               }
+               else
+                  swrast->TextureSample[texUnit] = sample_nearest_2d;
+            }
+            break;
+         case 3:
+            if (needLambda) {
+               swrast->TextureSample[texUnit] = sample_lambda_3d;
+            }
+            else if (t->MinFilter == GL_LINEAR) {
+               swrast->TextureSample[texUnit] = sample_linear_3d;
+            }
+            else {
+               ASSERT(t->MinFilter == GL_NEAREST);
+               swrast->TextureSample[texUnit] = sample_nearest_3d;
+            }
+            break;
+         case 6: /* cube map */
+            if (needLambda) {
+               swrast->TextureSample[texUnit] = sample_lambda_cube;
+            }
+            else if (t->MinFilter == GL_LINEAR) {
+               swrast->TextureSample[texUnit] = sample_linear_cube;
+            }
+            else {
+               ASSERT(t->MinFilter == GL_NEAREST);
+               swrast->TextureSample[texUnit] = sample_nearest_cube;
+            }
+            break;
+         default:
+            _mesa_problem(NULL, "invalid dimensions in _mesa_set_texture_sampler");
+      }
+   }
+}
+
+
+#define PROD(A,B)   ( (GLuint)(A) * ((GLuint)(B)+1) )
+#define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
+
+static INLINE void
+texture_combine(const GLcontext *ctx,
+                const struct gl_texture_unit *textureUnit,
+                GLuint n,
+                CONST GLchan (*primary_rgba)[4],
+                CONST GLchan (*texel)[4],
+                GLchan (*rgba)[4])
+{
+   const GLchan (*argRGB [3])[4];
+   const GLchan (*argA [3])[4];
+   GLuint i, j;
+   const GLuint RGBshift = textureUnit->CombineScaleShiftRGB;
+   const GLuint Ashift   = textureUnit->CombineScaleShiftA;
+#if CHAN_TYPE == GL_FLOAT
+   const GLchan RGBmult = (GLfloat) (1 << RGBshift);
+   const GLchan Amult = (GLfloat) (1 << Ashift);
+#else
+   const GLint half = (CHAN_MAX + 1) / 2;
+#endif
 
    DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4);  /* mac 32k limitation */
    CHECKARRAY(ccolor, return);  /* mac 32k limitation */
@@ -2344,8 +2681,8 @@ apply_texture( const GLcontext *ctx,
 
    format = texUnit->_Current->Image[baseLevel]->Format;
 
-   if (format==GL_COLOR_INDEX || format==GL_DEPTH_COMPONENT) {
-      format = GL_RGBA;  /* XXXX a hack! */
+   if (format == GL_COLOR_INDEX || format == GL_DEPTH_COMPONENT) {
+      format = GL_RGBA;  /* a bit of a hack */
    }
 
    switch (texUnit->EnvMode) {
@@ -2442,550 +2779,229 @@ apply_texture( const GLcontext *ctx,
            case GL_INTENSITY:
               for (i=0;i<n;i++) {
                  /* Cv = CfIt */
-                  GLchan It = texel[i][RCOMP];
-                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
-                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
-                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
-                 /* Av = AfIt */
-                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
-              }
-              break;
-           case GL_RGB:
-              for (i=0;i<n;i++) {
-                 /* Cv = CfCt */
-                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
-                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
-                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
-                 /* Av = Af */
-              }
-              break;
-           case GL_RGBA:
-              for (i=0;i<n;i++) {
-                 /* Cv = CfCt */
-                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
-                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
-                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
-                 /* Av = AfAt */
-                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
-              }
-              break;
-            default:
-               _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
-               return;
-        }
-        break;
-
-      case GL_DECAL:
-         switch (format) {
-            case GL_ALPHA:
-            case GL_LUMINANCE:
-            case GL_LUMINANCE_ALPHA:
-            case GL_INTENSITY:
-               /* undefined */
-               break;
-           case GL_RGB:
-              for (i=0;i<n;i++) {
-                 /* Cv = Ct */
-                 rgba[i][RCOMP] = texel[i][RCOMP];
-                 rgba[i][GCOMP] = texel[i][GCOMP];
-                 rgba[i][BCOMP] = texel[i][BCOMP];
-                 /* Av = Af */
-              }
-              break;
-           case GL_RGBA:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-At) + CtAt */
-                 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
-                 /* Av = Af */
-              }
-              break;
-            default:
-               _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
-               return;
-        }
-        break;
-
-      case GL_BLEND:
-         Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
-         Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
-         Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
-         Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
-        switch (format) {
-           case GL_ALPHA:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf */
-                 /* Av = AfAt */
-                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
-              }
-              break;
-            case GL_LUMINANCE:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-Lt) + CcLt */
-                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
-                 /* Av = Af */
-              }
-              break;
-           case GL_LUMINANCE_ALPHA:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-Lt) + CcLt */
-                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
-                 /* Av = AfAt */
-                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
-              }
-              break;
-            case GL_INTENSITY:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-It) + CcLt */
-                 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
-                  /* Av = Af(1-It) + Ac*It */
-                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
-               }
-               break;
-           case GL_RGB:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-Ct) + CcCt */
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
-                 /* Av = Af */
-              }
-              break;
-           case GL_RGBA:
-              for (i=0;i<n;i++) {
-                 /* Cv = Cf(1-Ct) + CcCt */
-                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
-                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
-                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
-                 /* Av = AfAt */
-                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
-              }
-              break;
-            default:
-               _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
-               return;
-        }
-        break;
-
-     /* XXX don't clamp results if GLchan is float??? */
-
-      case GL_ADD:  /* GL_EXT_texture_add_env */
-         switch (format) {
-            case GL_ALPHA:
-               for (i=0;i<n;i++) {
-                  /* Rv = Rf */
-                  /* Gv = Gf */
-                  /* Bv = Bf */
-                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
-               }
-               break;
-            case GL_LUMINANCE:
-               for (i=0;i<n;i++) {
-                  GLuint Lt = texel[i][RCOMP];
-                  GLuint r = rgba[i][RCOMP] + Lt;
-                  GLuint g = rgba[i][GCOMP] + Lt;
-                  GLuint b = rgba[i][BCOMP] + Lt;
-                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
-                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
-                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
-                  /* Av = Af */
-               }
-               break;
-            case GL_LUMINANCE_ALPHA:
-               for (i=0;i<n;i++) {
-                  GLuint Lt = texel[i][RCOMP];
-                  GLuint r = rgba[i][RCOMP] + Lt;
-                  GLuint g = rgba[i][GCOMP] + Lt;
-                  GLuint b = rgba[i][BCOMP] + Lt;
-                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
-                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
-                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
-                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
-               }
-               break;
-            case GL_INTENSITY:
-               for (i=0;i<n;i++) {
-                  GLchan It = texel[i][RCOMP];
-                  GLuint r = rgba[i][RCOMP] + It;
-                  GLuint g = rgba[i][GCOMP] + It;
-                  GLuint b = rgba[i][BCOMP] + It;
-                  GLuint a = rgba[i][ACOMP] + It;
-                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
-                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
-                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
-                  rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
-               }
-               break;
-           case GL_RGB:
-              for (i=0;i<n;i++) {
-                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
-                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
-                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
-                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
-                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
-                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
-                 /* Av = Af */
-              }
-              break;
-           case GL_RGBA:
-              for (i=0;i<n;i++) {
-                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
-                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
-                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
-                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
-                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
-                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
-                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
-               }
-               break;
-            default:
-               _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
-               return;
-        }
-        break;
-
-      case GL_COMBINE_EXT:
-         texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
-         break;
-
-      default:
-         _mesa_problem(ctx, "Bad env mode in apply_texture");
-         return;
-   }
-}
-
-
-
-/*
- * Sample a shadow/depth texture.
- * Input:  ctx - context
- *         texUnit - the texture unit
- *         n - number of samples
- *         s,t,r - array [n] of texture coordinates
- * In/Out:  rgba - array [n] of texel colors.
- */
-static void
-sample_depth_texture(const GLcontext *ctx,
-                     const struct gl_texture_unit *texUnit,
-                     GLuint n, GLfloat texcoords[][4],
-                     GLchan texel[][4])
-{
-   const struct gl_texture_object *texObj = texUnit->_Current;
-   const GLint baseLevel = texObj->BaseLevel;
-   const struct gl_texture_image *texImage = texObj->Image[baseLevel];
-   const GLuint width = texImage->Width;
-   const GLuint height = texImage->Height;
-   const GLchan ambient = texObj->ShadowAmbient;
-   GLboolean lequal, gequal;
-   GLchan result;
-
-   ASSERT(texObj->Image[texObj->BaseLevel]->Format == GL_DEPTH_COMPONENT);
-
-   if (texObj->Dimensions != 2) {
-      _mesa_problem(ctx, "only 2-D depth textures supported at this time");
-      return;
-   }
-
-   if (texObj->MinFilter != texObj->MagFilter) {
-      _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
-      return;
-   }
-
-   /* XXX this could be precomputed */
-   if (texObj->CompareFlag) {
-      /* GL_SGIX_shadow */
-      if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
-         lequal = GL_TRUE;
-         gequal = GL_FALSE;
-      }
-      else {
-         ASSERT(texObj->CompareOperator == GL_TEXTURE_GEQUAL_R_SGIX);
-         lequal = GL_FALSE;
-         gequal = GL_TRUE;
-      }
-   }
-   else if (texObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) {
-      /* GL_ARB_shadow */
-      if (texObj->CompareFunc == GL_LEQUAL) {
-         lequal = GL_TRUE;
-         gequal = GL_FALSE;
-      }
-      else {
-         ASSERT(texObj->CompareFunc == GL_GEQUAL);
-         lequal = GL_FALSE;
-         gequal = GL_TRUE;
-      }
-   }
-   else {
-      /* Treat this depth texture as a luminance texture */
-      _mesa_warning(ctx,
-         "Treating GL_DEPTH_COMPONENT as GL_LUMINANCE not implemented yet");
-      return;
-   }
-
-   if (texObj->MagFilter == GL_NEAREST) {
-      GLuint i;
-      for (i = 0; i < n; i++) {
-         GLfloat depthSample;
-         GLint col, row;
-         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0], width, col);
-         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1], height, row);
-         depthSample = *((const GLfloat *) texImage->Data + row * width + col);
-         if ((texcoords[i][2] <= depthSample && lequal) ||
-             (texcoords[i][2] >= depthSample && gequal)) {
-            result = CHAN_MAX;
-         }
-         else {
-            result = ambient;
-         }
-
-         switch (texObj->CompareResult) {
-         case GL_LUMINANCE:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = CHAN_MAX;
-            break;
-         case GL_INTENSITY:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = result;
-            break;
-         case GL_ALPHA:
-            texel[i][RCOMP] = 0;
-            texel[i][GCOMP] = 0;
-            texel[i][BCOMP] = 0;
-            texel[i][ACOMP] = result;
-            break;
-         default:
-            _mesa_problem(ctx, "Bad texture compare result value");
-         }
-      }
-   }
-   else {
-      GLuint i;
-      ASSERT(texObj->MagFilter == GL_LINEAR);
-      for (i = 0; i < n; i++) {
-         GLfloat depth00, depth01, depth10, depth11;
-         GLint i0, i1, j0, j1;
-         GLfloat u, v;
-         GLuint useBorderTexel;
-
-         COMPUTE_LINEAR_TEXEL_LOCATIONS(texObj->WrapS, texcoords[i][0], u, width, i0, i1);
-         COMPUTE_LINEAR_TEXEL_LOCATIONS(texObj->WrapT, texcoords[i][1], v, height,j0, j1);
-
-         useBorderTexel = 0;
-         if (texImage->Border) {
-            i0 += texImage->Border;
-            i1 += texImage->Border;
-            j0 += texImage->Border;
-            j1 += texImage->Border;
-         }
-         else {
-            if (i0 < 0 || i0 >= (GLint) width)   useBorderTexel |= I0BIT;
-            if (i1 < 0 || i1 >= (GLint) width)   useBorderTexel |= I1BIT;
-            if (j0 < 0 || j0 >= (GLint) height)  useBorderTexel |= J0BIT;
-            if (j1 < 0 || j1 >= (GLint) height)  useBorderTexel |= J1BIT;
-         }
-
-         /* get four depth samples from the texture */
-         if (useBorderTexel & (I0BIT | J0BIT)) {
-            depth00 = 1.0;
-         }
-         else {
-            depth00 = *((const GLfloat *) texImage->Data + j0 * width + i0);
-         }
-         if (useBorderTexel & (I1BIT | J0BIT)) {
-            depth10 = 1.0;
-         }
-         else {
-            depth10 = *((const GLfloat *) texImage->Data + j0 * width + i1);
-         }
-         if (useBorderTexel & (I0BIT | J1BIT)) {
-            depth01 = 1.0;
-         }
-         else {
-            depth01 = *((const GLfloat *) texImage->Data + j1 * width + i0);
-         }
-         if (useBorderTexel & (I1BIT | J1BIT)) {
-            depth11 = 1.0;
-         }
-         else {
-            depth11 = *((const GLfloat *) texImage->Data + j1 * width + i1);
-         }
-
-         if (0) {
-            /* compute a single weighted depth sample and do one comparison */
-            const GLfloat a = FRAC(u + 1.0F);
-            const GLfloat b = FRAC(v + 1.0F);
-            const GLfloat w00 = (1.0F - a) * (1.0F - b);
-            const GLfloat w10 = (       a) * (1.0F - b);
-            const GLfloat w01 = (1.0F - a) * (       b);
-            const GLfloat w11 = (       a) * (       b);
-            const GLfloat depthSample = w00 * depth00 + w10 * depth10
-                                      + w01 * depth01 + w11 * depth11;
-            if ((depthSample <= texcoords[i][2] && lequal) ||
-                (depthSample >= texcoords[i][2] && gequal)) {
-               result  = ambient;
-            }
-            else {
-               result = CHAN_MAX;
-            }
-         }
-         else {
-            /* Do four depth/R comparisons and compute a weighted result.
-             * If this touches on somebody's I.P., I'll remove this code
-             * upon request.
-             */
-            const GLfloat d = (CHAN_MAXF - (GLfloat) ambient) * 0.25F;
-            GLfloat luminance = CHAN_MAXF;
-            if (lequal) {
-               if (depth00 <= texcoords[i][2])   luminance -= d;
-               if (depth01 <= texcoords[i][2])   luminance -= d;
-               if (depth10 <= texcoords[i][2])   luminance -= d;
-               if (depth11 <= texcoords[i][2])   luminance -= d;
-            }
-            else {
-               if (depth00 >= texcoords[i][2])   luminance -= d;
-               if (depth01 >= texcoords[i][2])   luminance -= d;
-               if (depth10 >= texcoords[i][2])   luminance -= d;
-               if (depth11 >= texcoords[i][2])   luminance -= d;
-            }
-            result = (GLchan) luminance;
-         }
-
-         switch (texObj->CompareResult) {
-         case GL_LUMINANCE:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = CHAN_MAX;
-            break;
-         case GL_INTENSITY:
-            texel[i][RCOMP] = result;
-            texel[i][GCOMP] = result;
-            texel[i][BCOMP] = result;
-            texel[i][ACOMP] = result;
-            break;
-         case GL_ALPHA:
-            texel[i][RCOMP] = 0;
-            texel[i][GCOMP] = 0;
-            texel[i][BCOMP] = 0;
-            texel[i][ACOMP] = result;
-            break;
-         default:
-            _mesa_problem(ctx, "Bad texture compare result value");
-         }
-      }  /* for */
-   }  /* if filter */
-}
-
-
-#if 0
-/*
- * Experimental depth texture sampling function.
- */
-static void
-sample_depth_texture2(const GLcontext *ctx,
-                     const struct gl_texture_unit *texUnit,
-                     GLuint n, GLfloat texcoords[][4],
-                     GLchan texel[][4])
-{
-   const struct gl_texture_object *texObj = texUnit->_Current;
-   const GLint baseLevel = texObj->BaseLevel;
-   const struct gl_texture_image *texImage = texObj->Image[baseLevel];
-   const GLuint width = texImage->Width;
-   const GLuint height = texImage->Height;
-   const GLchan ambient = texObj->ShadowAmbient;
-   GLboolean lequal, gequal;
-
-   if (texObj->Dimensions != 2) {
-      _mesa_problem(ctx, "only 2-D depth textures supported at this time");
-      return;
-   }
-
-   if (texObj->MinFilter != texObj->MagFilter) {
-      _mesa_problem(ctx, "mipmapped depth textures not supported at this time");
-      return;
-   }
-
-   /* XXX the GL_SGIX_shadow extension spec doesn't say what to do if
-    * GL_TEXTURE_COMPARE_SGIX == GL_TRUE but the current texture object
-    * isn't a depth texture.
-    */
-   if (texImage->Format != GL_DEPTH_COMPONENT) {
-      _mesa_problem(ctx,"GL_TEXTURE_COMPARE_SGIX enabled with non-depth texture");
-      return;
-   }
-
-   if (texObj->CompareOperator == GL_TEXTURE_LEQUAL_R_SGIX) {
-      lequal = GL_TRUE;
-      gequal = GL_FALSE;
-   }
-   else {
-      lequal = GL_FALSE;
-      gequal = GL_TRUE;
-   }
+                  GLchan It = texel[i][RCOMP];
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], It );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], It );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], It );
+                 /* Av = AfIt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], It );
+              }
+              break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = CfCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT( rgba[i][RCOMP], texel[i][RCOMP] );
+                 rgba[i][GCOMP] = CHAN_PRODUCT( rgba[i][GCOMP], texel[i][GCOMP] );
+                 rgba[i][BCOMP] = CHAN_PRODUCT( rgba[i][BCOMP], texel[i][BCOMP] );
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT( rgba[i][ACOMP], texel[i][ACOMP] );
+              }
+              break;
+            default:
+               _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
+               return;
+        }
+        break;
 
-   {
-      GLuint i;
-      for (i = 0; i < n; i++) {
-         const GLint K = 3;
-         GLint col, row, ii, jj, imin, imax, jmin, jmax, samples, count;
-         GLfloat w;
-         GLchan lum;
-         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapS, texcoords[i][0],
-                                       width, col);
-         COMPUTE_NEAREST_TEXEL_LOCATION(texObj->WrapT, texcoords[i][1],
-                                       height, row);
+      case GL_DECAL:
+         switch (format) {
+            case GL_ALPHA:
+            case GL_LUMINANCE:
+            case GL_LUMINANCE_ALPHA:
+            case GL_INTENSITY:
+               /* undefined */
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = Ct */
+                 rgba[i][RCOMP] = texel[i][RCOMP];
+                 rgba[i][GCOMP] = texel[i][GCOMP];
+                 rgba[i][BCOMP] = texel[i][BCOMP];
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-At) + CtAt */
+                 GLint t = texel[i][ACOMP], s = CHAN_MAX - t;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(texel[i][RCOMP],t);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(texel[i][GCOMP],t);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(texel[i][BCOMP],t);
+                 /* Av = Af */
+              }
+              break;
+            default:
+               _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
+               return;
+        }
+        break;
 
-         imin = col - K;
-         imax = col + K;
-         jmin = row - K;
-         jmax = row + K;
+      case GL_BLEND:
+         Rc = (GLint) (texUnit->EnvColor[0] * CHAN_MAXF);
+         Gc = (GLint) (texUnit->EnvColor[1] * CHAN_MAXF);
+         Bc = (GLint) (texUnit->EnvColor[2] * CHAN_MAXF);
+         Ac = (GLint) (texUnit->EnvColor[3] * CHAN_MAXF);
+        switch (format) {
+           case GL_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf */
+                 /* Av = AfAt */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+              }
+              break;
+            case GL_LUMINANCE:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Lt) + CcLt */
+                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+                 /* Av = Af */
+              }
+              break;
+           case GL_LUMINANCE_ALPHA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Lt) + CcLt */
+                 GLchan Lt = texel[i][RCOMP], s = CHAN_MAX - Lt;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, Lt);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, Lt);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, Lt);
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+              }
+              break;
+            case GL_INTENSITY:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-It) + CcLt */
+                 GLchan It = texel[i][RCOMP], s = CHAN_MAX - It;
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], s) + CHAN_PRODUCT(Rc, It);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], s) + CHAN_PRODUCT(Gc, It);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], s) + CHAN_PRODUCT(Bc, It);
+                  /* Av = Af(1-It) + Ac*It */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], s) + CHAN_PRODUCT(Ac, It);
+               }
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Ct) + CcCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                 /* Cv = Cf(1-Ct) + CcCt */
+                 rgba[i][RCOMP] = CHAN_PRODUCT(rgba[i][RCOMP], (CHAN_MAX-texel[i][RCOMP])) + CHAN_PRODUCT(Rc,texel[i][RCOMP]);
+                 rgba[i][GCOMP] = CHAN_PRODUCT(rgba[i][GCOMP], (CHAN_MAX-texel[i][GCOMP])) + CHAN_PRODUCT(Gc,texel[i][GCOMP]);
+                 rgba[i][BCOMP] = CHAN_PRODUCT(rgba[i][BCOMP], (CHAN_MAX-texel[i][BCOMP])) + CHAN_PRODUCT(Bc,texel[i][BCOMP]);
+                 /* Av = AfAt */
+                 rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP],texel[i][ACOMP]);
+              }
+              break;
+            default:
+               _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
+               return;
+        }
+        break;
 
-         if (imin < 0)  imin = 0;
-         if (imax >= width)  imax = width - 1;
-         if (jmin < 0)  jmin = 0;
-         if (jmax >= height) jmax = height - 1;
+     /* XXX don't clamp results if GLchan is float??? */
 
-         samples = (imax - imin + 1) * (jmax - jmin + 1);
-         count = 0;
-         for (jj = jmin; jj <= jmax; jj++) {
-            for (ii = imin; ii <= imax; ii++) {
-               GLfloat depthSample = *((const GLfloat *) texImage->Data
-                                       + jj * width + ii);
-               if ((depthSample <= r[i] && lequal) ||
-                   (depthSample >= r[i] && gequal)) {
-                  count++;
+      case GL_ADD:  /* GL_EXT_texture_add_env */
+         switch (format) {
+            case GL_ALPHA:
+               for (i=0;i<n;i++) {
+                  /* Rv = Rf */
+                  /* Gv = Gf */
+                  /* Bv = Bf */
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
                }
-            }
-         }
+               break;
+            case GL_LUMINANCE:
+               for (i=0;i<n;i++) {
+                  GLuint Lt = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + Lt;
+                  GLuint g = rgba[i][GCOMP] + Lt;
+                  GLuint b = rgba[i][BCOMP] + Lt;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  /* Av = Af */
+               }
+               break;
+            case GL_LUMINANCE_ALPHA:
+               for (i=0;i<n;i++) {
+                  GLuint Lt = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + Lt;
+                  GLuint g = rgba[i][GCOMP] + Lt;
+                  GLuint b = rgba[i][BCOMP] + Lt;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+               }
+               break;
+            case GL_INTENSITY:
+               for (i=0;i<n;i++) {
+                  GLchan It = texel[i][RCOMP];
+                  GLuint r = rgba[i][RCOMP] + It;
+                  GLuint g = rgba[i][GCOMP] + It;
+                  GLuint b = rgba[i][BCOMP] + It;
+                  GLuint a = rgba[i][ACOMP] + It;
+                  rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                  rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                  rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = MIN2(a, CHAN_MAX);
+               }
+               break;
+           case GL_RGB:
+              for (i=0;i<n;i++) {
+                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                 /* Av = Af */
+              }
+              break;
+           case GL_RGBA:
+              for (i=0;i<n;i++) {
+                  GLuint r = rgba[i][RCOMP] + texel[i][RCOMP];
+                  GLuint g = rgba[i][GCOMP] + texel[i][GCOMP];
+                  GLuint b = rgba[i][BCOMP] + texel[i][BCOMP];
+                 rgba[i][RCOMP] = MIN2(r, CHAN_MAX);
+                 rgba[i][GCOMP] = MIN2(g, CHAN_MAX);
+                 rgba[i][BCOMP] = MIN2(b, CHAN_MAX);
+                  rgba[i][ACOMP] = CHAN_PRODUCT(rgba[i][ACOMP], texel[i][ACOMP]);
+               }
+               break;
+            default:
+               _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
+               return;
+        }
+        break;
 
-         w = (GLfloat) count / (GLfloat) samples;
-         w = CHAN_MAXF - w * (CHAN_MAXF - (GLfloat) ambient);
-         lum = (GLint) w;
+      case GL_COMBINE_EXT:
+         texture_combine(ctx, texUnit, n, primary_rgba, texel, rgba);
+         break;
 
-         texel[i][RCOMP] = lum;
-         texel[i][GCOMP] = lum;
-         texel[i][BCOMP] = lum;
-         texel[i][ACOMP] = CHAN_MAX;
-      }
+      default:
+         _mesa_problem(ctx, "Bad env mode in apply_texture");
+         return;
    }
 }
-#endif
+
 
 
 /*
@@ -3027,17 +3043,22 @@ _swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
          }
 
          /* Sample the texture. */
+#if 000
          if (curObj->Image[curObj->BaseLevel]->Format == GL_DEPTH_COMPONENT) {
             /* depth texture */
-            sample_depth_texture(ctx, textureUnit, n, texcoords, texel);
+            sample_depth_texture(ctx, texUnit, textureUnit->_Current,
+                                 n, texcoords, lambda, texel);
          }
          else {
             /* color texture */
+#endif
             SWRAST_CONTEXT(ctx)->TextureSample[texUnit]( ctx, texUnit,
                                                          textureUnit->_Current,
                                                          n, texcoords,
                                                          lambda, texel );
+#if 0
          }
+#endif
          apply_texture( ctx, textureUnit, n, primary_rgba,
                         (const GLchan (*)[4]) texel, rgba );
       }