Implemented GL_ARB_texture_env_crossbar.
[mesa.git] / src / mesa / swrast / s_texture.c
index e1ba95841775cad60bf6073ea53ff0c4070b602c..97a8447c3062d23970839f78386b24b55c201037 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: s_texture.c,v 1.57 2002/03/23 16:33:53 brianp Exp $ */
+/* $Id: s_texture.c,v 1.62 2002/05/02 00:59:20 brianp Exp $ */
 
 /*
  * Mesa 3-D graphics library
@@ -2250,7 +2250,7 @@ sample_depth_texture( GLcontext *ctx, GLuint unit,
                result = 0;
                break;
             case GL_NEVER:
-               result = CHAN_MAXF;
+               result = CHAN_MAX;
                break;
             case GL_NONE:
                /* ordinary bilinear filtering */
@@ -2394,6 +2394,9 @@ sample_depth_texture2(const GLcontext *ctx,
 #endif
 
 
+/**
+ * We use this function when a texture object is in an "incomplete" state.
+ */
 static void
 null_sample_func( GLcontext *ctx, GLuint texUnit,
                  const struct gl_texture_object *tObj, GLuint n,
@@ -2404,12 +2407,7 @@ null_sample_func( GLcontext *ctx, GLuint texUnit,
 
 
 
-/**********************************************************************/
-/*                       Texture Sampling Setup                       */
-/**********************************************************************/
-
-
-/*
+/**
  * Setup the texture sampling function for this texture object.
  */
 void
@@ -2516,17 +2514,27 @@ _swrast_choose_texture_sample_func( GLcontext *ctx, GLuint texUnit,
 #define PROD(A,B)   ( (GLuint)(A) * ((GLuint)(B)+1) )
 #define S_PROD(A,B) ( (GLint)(A) * ((GLint)(B)+1) )
 
+
+/**
+ * Do texture application for GL_ARB/EXT_texture_env_combine.
+ * Input:
+ *     ctx - rendering context
+ *     textureUnit - the texture unit to apply
+ *     n - number of fragments to process (span width)
+ *     primary_rgba - incoming fragment color array
+ *     texelBuffer - pointer to texel colors for all texture units
+ * Input/Output:
+ *     rgba - incoming colors, which get modified here
+ */
 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])
+texture_combine( const GLcontext *ctx, GLuint unit, GLuint n,
+                 CONST GLchan (*primary_rgba)[4],
+                 CONST GLchan *texelBuffer,
+                 GLchan (*rgba)[4] )
 {
+   const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
    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
@@ -2535,20 +2543,38 @@ texture_combine(const GLcontext *ctx,
 #else
    const GLint half = (CHAN_MAX + 1) / 2;
 #endif
+   GLuint i, j;
 
+   /* GLchan ccolor[3][4]; */
    DEFMNARRAY(GLchan, ccolor, 3, 3 * MAX_WIDTH, 4);  /* mac 32k limitation */
    CHECKARRAY(ccolor, return);  /* mac 32k limitation */
 
    ASSERT(ctx->Extensions.EXT_texture_env_combine ||
           ctx->Extensions.ARB_texture_env_combine);
+   ASSERT(SWRAST_CONTEXT(ctx)->_AnyTextureCombine);
+
+
+   /*
+   printf("modeRGB 0x%x  modeA 0x%x  srcRGB1 0x%x  srcA1 0x%x  srcRGB2 0x%x  srcA2 0x%x\n",
+          textureUnit->CombineModeRGB,
+          textureUnit->CombineModeA,
+          textureUnit->CombineSourceRGB[0],
+          textureUnit->CombineSourceA[0],
+          textureUnit->CombineSourceRGB[1],
+          textureUnit->CombineSourceA[1]);
+   */
 
    /*
     * Do operand setup for up to 3 operands.  Loop over the terms.
     */
    for (j = 0; j < 3; j++) {
-      switch (textureUnit->CombineSourceA[j]) {
+      const GLenum srcA = textureUnit->CombineSourceA[j];
+      const GLenum srcRGB = textureUnit->CombineSourceRGB[j];
+
+      switch (srcA) {
          case GL_TEXTURE:
-            argA[j] = texel;
+            argA[j] = (const GLchan (*)[4])
+               (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
             break;
          case GL_PRIMARY_COLOR_EXT:
             argA[j] = primary_rgba;
@@ -2566,12 +2592,21 @@ texture_combine(const GLcontext *ctx,
             }
             break;
          default:
-            _mesa_problem(ctx, "invalid combine source");
+            /* ARB_texture_env_crossbar source */
+            {
+               const GLuint srcUnit = srcA - GL_TEXTURE0_ARB;
+               ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
+               if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
+                  return;
+               argA[j] = (const GLchan (*)[4])
+                  (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
+            }
       }
 
-      switch (textureUnit->CombineSourceRGB[j]) {
+      switch (srcRGB) {
          case GL_TEXTURE:
-            argRGB[j] = texel;
+            argRGB[j] = (const GLchan (*)[4])
+               (texelBuffer + unit * (n * 4 * sizeof(GLchan)));
             break;
          case GL_PRIMARY_COLOR_EXT:
             argRGB[j] = primary_rgba;
@@ -2597,7 +2632,16 @@ texture_combine(const GLcontext *ctx,
             }
             break;
          default:
-            _mesa_problem(ctx, "invalid combine source");
+            /* ARB_texture_env_crossbar source */
+            {
+               const GLuint srcUnit = srcRGB - GL_TEXTURE0_ARB;
+               ASSERT(srcUnit < ctx->Const.MaxTextureUnits);
+               if (!ctx->Texture.Unit[srcUnit]._ReallyEnabled)
+                  return;
+               argRGB[j] = (const GLchan (*)[4])
+                  (texelBuffer + srcUnit * (n * 4 * sizeof(GLchan)));
+               printf("unit %d from unit %d\n", unit, srcUnit);
+            }
       }
 
       if (textureUnit->CombineOperandRGB[j] != GL_SRC_COLOR) {
@@ -2689,7 +2733,7 @@ texture_combine(const GLcontext *ctx,
             const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
             const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
 #if CHAN_TYPE != GL_FLOAT
-            const GLint shift = 8 - RGBshift;
+            const GLint shift = CHAN_BITS - RGBshift;
 #endif
             for (i = 0; i < n; i++) {
 #if CHAN_TYPE == GL_FLOAT
@@ -2756,7 +2800,7 @@ texture_combine(const GLcontext *ctx,
             const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
             const GLchan (*arg2)[4] = (const GLchan (*)[4]) argRGB[2];
 #if CHAN_TYPE != GL_FLOAT
-            const GLint shift = 8 - RGBshift;
+            const GLint shift = CHAN_BITS - RGBshift;
 #endif
             for (i = 0; i < n; i++) {
 #if CHAN_TYPE == GL_FLOAT
@@ -2803,15 +2847,37 @@ texture_combine(const GLcontext *ctx,
             }
          }
          break;
+      case GL_DOT3_RGB_EXT:
+      case GL_DOT3_RGBA_EXT:
+         {
+            /* Do not scale the result by 1 2 or 4 */
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            for (i = 0; i < n; i++) {
+#if CHAN_TYPE == GL_FLOAT
+               GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
+                             (arg0[i][GCOMP]-0.5F) * (arg1[i][GCOMP]-0.5F) +
+                             (arg0[i][BCOMP]-0.5F) * (arg1[i][BCOMP]-0.5F))
+                            * 4.0F;
+#else
+               GLint dot = (S_PROD((GLint)arg0[i][RCOMP] - half,
+                                  (GLint)arg1[i][RCOMP] - half) +
+                           S_PROD((GLint)arg0[i][GCOMP] - half,
+                                  (GLint)arg1[i][GCOMP] - half) +
+                           S_PROD((GLint)arg0[i][BCOMP] - half,
+                                  (GLint)arg1[i][BCOMP] - half)) >> 6;
+#endif
+               dot = CLAMP(dot, 0, CHAN_MAX);
+               rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
+            }
+         }
+         break;
       case GL_DOT3_RGB_ARB:
       case GL_DOT3_RGBA_ARB:
          {
+            /* DO scale the result by 1 2 or 4 */
             const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
             const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
-           /* ATI's EXT extension has a constant scale by 4.  The ARB
-            * one will likely remove this restriction, and we should
-            * drop the EXT extension in favour of the ARB one.
-            */
             for (i = 0; i < n; i++) {
 #if CHAN_TYPE == GL_FLOAT
                GLchan dot = ((arg0[i][RCOMP]-0.5F) * (arg1[i][RCOMP]-0.5F) +
@@ -2826,7 +2892,7 @@ texture_combine(const GLcontext *ctx,
                            S_PROD((GLint)arg0[i][BCOMP] - half,
                                   (GLint)arg1[i][BCOMP] - half)) >> 6;
 #endif
-               dot = CLAMP(dot, 0, CHAN_MAX);
+               dot = CLAMP(dot, 0, CHAN_MAX) << RGBshift;
                rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = (GLchan) dot;
             }
          }
@@ -2861,7 +2927,7 @@ texture_combine(const GLcontext *ctx,
             const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
             const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
 #if CHAN_TYPE != GL_FLOAT
-            const GLint shift = 8 - Ashift;
+            const GLint shift = CHAN_BITS - Ashift;
 #endif
             for (i = 0; i < n; i++) {
 #if CHAN_TYPE == GL_FLOAT
@@ -2908,7 +2974,7 @@ texture_combine(const GLcontext *ctx,
             const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
             const GLchan (*arg2)[4] = (const GLchan (*)[4]) argA[2];
 #if CHAN_TYPE != GL_FLOAT
-            const GLint shift = 8 - Ashift;
+            const GLint shift = CHAN_BITS - Ashift;
 #endif
             for (i=0; i<n; i++) {
 #if CHAN_TYPE == GL_FLOAT
@@ -2926,13 +2992,13 @@ texture_combine(const GLcontext *ctx,
          break;
       case GL_SUBTRACT_ARB:
          {
-            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argRGB[0];
-            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argRGB[1];
+            const GLchan (*arg0)[4] = (const GLchan (*)[4]) argA[0];
+            const GLchan (*arg1)[4] = (const GLchan (*)[4]) argA[1];
             for (i = 0; i < n; i++) {
 #if CHAN_TYPE == GL_FLOAT
                rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * Amult;
 #else
-               GLint a = ((GLint) arg0[i][ACOMP] - (GLint) arg1[i][ACOMP]) << RGBshift;
+               GLint a = ((GLint) arg0[i][ACOMP] - (GLint) arg1[i][ACOMP]) << Ashift;
                rgba[i][ACOMP] = (GLchan) CLAMP(a, 0, CHAN_MAX);
 #endif
             }
@@ -2943,7 +3009,10 @@ texture_combine(const GLcontext *ctx,
          _mesa_problem(ctx, "invalid combine mode");
    }
 
-   /* Fix the alpha component for GL_DOT3_RGBA_EXT combining.
+   /* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
+    * This is kind of a kludge.  It would have been better if the spec
+    * were written such that the GL_COMBINE_ALPHA value could be set to
+    * GL_DOT3.
     */
    if (textureUnit->CombineModeRGB == GL_DOT3_RGBA_EXT ||
        textureUnit->CombineModeRGB == GL_DOT3_RGBA_ARB) {
@@ -2956,14 +3025,23 @@ texture_combine(const GLcontext *ctx,
 #undef PROD
 
 
+/**
+ * Implement NVIDIA's GL_NV_texture_env_combine4 extension when
+ * texUnit->EnvMode == GL_COMBINE4_NV.
+ */
+static INLINE void
+texture_combine4( const GLcontext *ctx, GLuint unit, GLuint n,
+                  CONST GLchan (*primary_rgba)[4],
+                  CONST GLchan *texelBuffer,
+                  GLchan (*rgba)[4] )
+{
+}
 
-/**********************************************************************/
-/*                      Texture Application                           */
-/**********************************************************************/
 
 
-/*
- * Combine incoming fragment color with texel color to produce output color.
+/**
+ * Apply a conventional OpenGL texture env mode (REPLACE, ADD, BLEND,
+ * MODULATE, or DECAL) to an array of fragments.
  * Input:  textureUnit - pointer to texture unit to apply
  *         format - base internal texture format
  *         n - number of fragments
@@ -2973,7 +3051,7 @@ texture_combine(const GLcontext *ctx,
  *                according to the texture environment mode.
  */
 static void
-apply_texture( const GLcontext *ctx,
+texture_apply( const GLcontext *ctx,
                const struct gl_texture_unit *texUnit,
                GLuint n,
                CONST GLchan primary_rgba[][4], CONST GLchan texel[][4],
@@ -3052,7 +3130,7 @@ apply_texture( const GLcontext *ctx,
               }
               break;
             default:
-               _mesa_problem(ctx, "Bad format (GL_REPLACE) in apply_texture");
+               _mesa_problem(ctx, "Bad format (GL_REPLACE) in texture_apply");
                return;
         }
         break;
@@ -3118,7 +3196,7 @@ apply_texture( const GLcontext *ctx,
               }
               break;
             default:
-               _mesa_problem(ctx, "Bad format (GL_MODULATE) in apply_texture");
+               _mesa_problem(ctx, "Bad format (GL_MODULATE) in texture_apply");
                return;
         }
         break;
@@ -3151,7 +3229,7 @@ apply_texture( const GLcontext *ctx,
               }
               break;
             default:
-               _mesa_problem(ctx, "Bad format (GL_DECAL) in apply_texture");
+               _mesa_problem(ctx, "Bad format (GL_DECAL) in texture_apply");
                return;
         }
         break;
@@ -3221,7 +3299,7 @@ apply_texture( const GLcontext *ctx,
               }
               break;
             default:
-               _mesa_problem(ctx, "Bad format (GL_BLEND) in apply_texture");
+               _mesa_problem(ctx, "Bad format (GL_BLEND) in texture_apply");
                return;
         }
         break;
@@ -3298,59 +3376,57 @@ apply_texture( const GLcontext *ctx,
                }
                break;
             default:
-               _mesa_problem(ctx, "Bad format (GL_ADD) in apply_texture");
+               _mesa_problem(ctx, "Bad format (GL_ADD) in texture_apply");
                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");
+         _mesa_problem(ctx, "Bad env mode in texture_apply");
          return;
    }
 }
 
 
 
-/*
- * Apply a unit of texture mapping to the incoming fragments.
+/**
+ * Apply texture mapping to a span of fragments.
  */
 void
-_swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
-                              GLfloat texcoords[][4], GLfloat lambda[],
-                              CONST GLchan primary_rgba[][4],
-                              GLchan rgba[][4] )
+_swrast_texture_span( GLcontext *ctx, struct sw_span *span )
 {
-   const GLuint mask = TEXTURE0_ANY << (texUnit * 4);
-
-   if (ctx->Texture._ReallyEnabled & mask) {
-      const struct gl_texture_unit *textureUnit = &ctx->Texture.Unit[texUnit];
-      
-      if (textureUnit->_Current) {   /* XXX need this? */
-         const struct gl_texture_object *curObj = textureUnit->_Current;
-         GLchan texel[MAX_WIDTH][4];
-         
-         if (lambda) {
-#if 0
-            float min, max;
-            int i;
-            min = max = lambda[0];
-            for (i = 1; i < n; i++) {
-               if (lambda[i] > max)
-                  max = lambda[i];
-               if (lambda[i] < min)
-                  min = lambda[i];
-            }
-            printf("min/max %g / %g\n", min, max);
-#endif
-            if (textureUnit->LodBias != 0.0F) {
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   GLchan primary_rgba[MAX_WIDTH][4];
+   GLuint unit;
+
+   ASSERT(span->end < MAX_WIDTH);
+   ASSERT(span->arrayMask & SPAN_TEXTURE);
+
+   /*
+    * Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
+    */
+   if (swrast->_AnyTextureCombine)
+      MEMCPY(primary_rgba, span->color.rgba, 4 * span->end * sizeof(GLchan));
+
+   /*
+    * Must do all texture sampling before combining in order to
+    * accomodate GL_ARB_texture_env_crossbar.
+    */
+   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+         const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+         const struct gl_texture_object *curObj = texUnit->_Current;
+         GLfloat *lambda = span->lambda[unit];
+         GLchan (*texels)[4] = (GLchan (*)[4])
+            (swrast->TexelBuffer + unit * (span->end * 4 * sizeof(GLchan)));
+
+         /* adjust texture lod (lambda) */
+         if (span->arrayMask | SPAN_LAMBDA) {
+            if (texUnit->LodBias != 0.0F) {
                /* apply LOD bias, but don't clamp yet */
                GLuint i;
-               for (i=0;i<n;i++) {
-                  lambda[i] += textureUnit->LodBias;
+               for (i = 0; i < span->end; i++) {
+                  lambda[i] += texUnit->LodBias;
                }
             }
 
@@ -3359,67 +3435,50 @@ _swrast_texture_fragments( GLcontext *ctx, GLuint texUnit, GLuint n,
                const GLfloat min = curObj->MinLod;
                const GLfloat max = curObj->MaxLod;
                GLuint i;
-               for (i=0;i<n;i++) {
+               for (i = 0; i < span->end; i++) {
                   GLfloat l = lambda[i];
                   lambda[i] = CLAMP(l, min, max);
                }
             }
          }
 
-         /* Sample the texture for n fragments */
-         SWRAST_CONTEXT(ctx)->TextureSample[texUnit]( ctx, texUnit,
-                                                      textureUnit->_Current,
-                                                      n, texcoords,
-                                                      lambda, texel );
-
-         apply_texture( ctx, textureUnit, n, primary_rgba,
-                        (const GLchan (*)[4]) texel, rgba );
+         /* Sample the texture (span->end fragments) */
+         swrast->TextureSample[unit]( ctx, unit, texUnit->_Current,
+                                      span->end, span->texcoords[unit],
+                                      lambda, texels );
       }
    }
-}
-
-
-/*
- * Apply multiple texture stages (or just unit 0) to the span.
- * At some point in the future we'll probably modify this so that
- * texels from any texture unit are available in any combiner unit.
- * That'll require doing all the texture sampling first, and then
- * all the application (blending) afterward.
- */
-void
-_swrast_multitexture_fragments( GLcontext *ctx, struct sw_span *span )
-{
-   if (ctx->Texture._ReallyEnabled & ~TEXTURE0_ANY) {
-      /* multitexture */
-      GLchan primary_rgba[MAX_WIDTH][4];
-      GLuint unit;
-
-      ASSERT(span->end < MAX_WIDTH);
-
-      /* save copy of the span colors (the GL_PRIMARY_COLOR) */
-      MEMCPY(primary_rgba, span->color.rgba, 4 * span->end * sizeof(GLchan));
 
-      /* loop over texture units, modifying the span->color.rgba values */
-      for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
-         if (ctx->Texture.Unit[unit]._ReallyEnabled) {
-            _swrast_texture_fragments( ctx, unit, span->end,
-                                           span->texcoords[unit],
-                                           (span->arrayMask & SPAN_LAMBDA) ?
-                                              span->lambda[unit] : NULL,
-                                           (CONST GLchan (*)[4]) primary_rgba,
-                                           span->color.rgba );
+   /*
+    * OK, now apply the texture (aka texture combine/blend).
+    * We modify the span->color.rgba values.
+    */
+   for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
+      if (ctx->Texture.Unit[unit]._ReallyEnabled) {
+         const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
+         if (texUnit->EnvMode == GL_COMBINE_EXT) {
+            /* GL_ARB/EXT_texture_env_combine */
+            texture_combine( ctx, unit, span->end,
+                             (CONST GLchan (*)[4]) primary_rgba,
+                             swrast->TexelBuffer,
+                             span->color.rgba );
+         }
+         else if (texUnit->EnvMode == GL_COMBINE4_NV) {
+            /* GL_NV_texture_env_combine4 */
+            texture_combine4( ctx, unit, span->end,
+                              (CONST GLchan (*)[4]) primary_rgba,
+                              swrast->TexelBuffer,
+                              span->color.rgba );
+         }
+         else {
+            /* conventional texture blend */
+            const GLchan (*texels)[4] = (const GLchan (*)[4])
+               (swrast->TexelBuffer + unit *
+                (span->end * 4 * sizeof(GLchan)));
+            texture_apply( ctx, texUnit, span->end,
+                           (CONST GLchan (*)[4]) primary_rgba, texels,
+                           span->color.rgba );
          }
       }
    }
-   else {
-      /* Just unit 0 enabled */
-      ASSERT(ctx->Texture._ReallyEnabled & TEXTURE0_ANY);
-
-      _swrast_texture_fragments( ctx, 0, span->end,
-                                     span->texcoords[0],
-                                     (span->arrayMask & SPAN_LAMBDA) ?
-                                        span->lambda[0] : NULL,
-                                     (CONST GLchan (*)[4]) span->color.rgba,
-                                     span->color.rgba );
-   }
 }