A bit of an overhaul of the fog code.
authorBrian Paul <brian.paul@tungstengraphics.com>
Tue, 17 Feb 2004 21:03:03 +0000 (21:03 +0000)
committerBrian Paul <brian.paul@tungstengraphics.com>
Tue, 17 Feb 2004 21:03:03 +0000 (21:03 +0000)
glFogCoord didn't always work reliably.
ARB fragment program fog options work now.
Per-fragment fog computations are now perspective corrected.

src/mesa/swrast/s_context.c
src/mesa/swrast/s_context.h
src/mesa/swrast/s_fog.c
src/mesa/swrast/s_span.c
src/mesa/swrast/s_triangle.c
src/mesa/swrast/s_tritemp.h
src/mesa/tnl/t_context.c
src/mesa/tnl/t_context.h
src/mesa/tnl/t_vb_fog.c
src/mesa/tnl/tnl.h

index c69d4cfd5d400b6a890b98505d91277365323d74..800f79080f88208f413153c9fdac2cf1c64288f8 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  5.1
+ * Version:  6.1
  *
- * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2004  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"),
@@ -28,6 +28,7 @@
 
 #include "imports.h"
 #include "context.h"
+#include "colormac.h"
 #include "mtypes.h"
 #include "texobj.h"
 #include "nvfragprog.h"
@@ -141,15 +142,17 @@ _swrast_update_polygon( GLcontext *ctx )
 
 
 static void
-_swrast_update_hint( GLcontext *ctx )
+_swrast_update_fog_hint( GLcontext *ctx )
 {
    SWcontext *swrast = SWRAST_CONTEXT(ctx);
    swrast->_PreferPixelFog = (!swrast->AllowVertexFog ||
+                              ctx->FragmentProgram.Enabled ||
                              (ctx->Hint.Fog == GL_NICEST &&
                               swrast->AllowPixelFog));
 }
 
 
+
 /*
  * Update the swrast->_AnyTextureCombine flag.
  */
@@ -169,6 +172,36 @@ _swrast_update_texture_env( GLcontext *ctx )
 }
 
 
+/*
+ * Update swrast->_FogColor and swrast->_FogEnable values.
+ */
+static void
+_swrast_update_fog_state( GLcontext *ctx )
+{
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+
+   /* convert fog color to GLchan values */
+   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[RCOMP], ctx->Fog.Color[RCOMP]);
+   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[GCOMP], ctx->Fog.Color[GCOMP]);
+   CLAMPED_FLOAT_TO_CHAN(swrast->_FogColor[BCOMP], ctx->Fog.Color[BCOMP]);
+
+   /* determine if fog is needed */
+   swrast->_FogEnabled = GL_FALSE;
+   if (ctx->Fog.Enabled) {
+      swrast->_FogEnabled = GL_TRUE;
+   }
+   else if (ctx->FragmentProgram.Enabled &&
+        ctx->FragmentProgram.Current->Base.Target == GL_FRAGMENT_PROGRAM_ARB) {
+      const struct fragment_program *p;
+      p = (struct fragment_program *) ctx->FragmentProgram.Current;
+      if (p->FogOption != GL_NONE) {
+         swrast->_FogEnabled = GL_TRUE;
+      }
+   }
+}
+
+
+
 #define _SWRAST_NEW_DERIVED (_SWRAST_NEW_RASTERMASK |  \
                             _NEW_TEXTURE |             \
                             _NEW_HINT |                \
@@ -393,12 +426,16 @@ _swrast_validate_derived( GLcontext *ctx )
       if (swrast->NewState & _NEW_POLYGON)
         _swrast_update_polygon( ctx );
 
-      if (swrast->NewState & _NEW_HINT)
-        _swrast_update_hint( ctx );
+      if (swrast->NewState & (_NEW_HINT | _NEW_PROGRAM))
+        _swrast_update_fog_hint( ctx );
 
       if (swrast->NewState & _SWRAST_NEW_TEXTURE_ENV_MODE)
         _swrast_update_texture_env( ctx );
 
+      if (swrast->NewState & _NEW_FOG) {
+         _swrast_update_fog_state( ctx );
+      }
+
       swrast->NewState = 0;
       swrast->StateChanges = 0;
       swrast->InvalidateState = _swrast_invalidate_state;
index a9144af700adc5207b276e5fd7c3d7d57ba65150..081d2557ad5a05af4b8e0fc137f8249472b5deb2 100644 (file)
@@ -1,8 +1,8 @@
 /*
  * Mesa 3-D graphics library
- * Version:  5.1
+ * Version:  6.1
  *
- * Copyright (C) 1999-2003  Brian Paul   All Rights Reserved.
+ * Copyright (C) 1999-2004  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"),
@@ -271,8 +271,10 @@ typedef struct
    GLuint _RasterMask;
    GLfloat _MinMagThresh[MAX_TEXTURE_IMAGE_UNITS];
    GLfloat _BackfaceSign;
-   GLboolean _PreferPixelFog;
+   GLboolean _PreferPixelFog;    /* Compute fog blend factor per fragment? */
    GLboolean _AnyTextureCombine;
+   GLchan _FogColor[3];
+   GLboolean _FogEnabled;
 
    /* Accum buffer temporaries.
     */
index da06e3f3543f57c9e4d4aecdcdf60cdb080769f9..c46032b53c7f6d8694f27a9fc8b6cdc55ce29d94 100644 (file)
@@ -67,204 +67,144 @@ _swrast_z_to_fogfactor(GLcontext *ctx, GLfloat z)
 }
 
 
-
 /**
- * Calculate fog factors (in [0,1]) from window z values
- * Input:  n - number of pixels
- *         z - array of integer depth values
- *         red, green, blue, alpha - pixel colors
- * Output:  red, green, blue, alpha - fogged pixel colors
- *
- * Use lookup table & interpolation?
+ * Apply fog to a span of RGBA pixels.
+ * The fog value are either in the span->array->fog array or interpolated from
+ * the fog/fogStep values.
+ * They fog values are either fog coordinates (Z) or fog blend factors.
+ * _PreferPixelFog should be in sync with that state!
  */
-static void
-compute_fog_factors_from_z( const GLcontext *ctx,
-                            GLuint n,
-                            const GLdepth z[],
-                            GLfloat fogFact[] )
+void
+_swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
 {
-   const GLfloat *proj = ctx->ProjectionMatrixStack.Top->m;
-   const GLboolean ortho = (proj[15] != 0.0F);
-   const GLfloat p10 = proj[10];
-   const GLfloat p14 = proj[14];
-   const GLfloat tz = ctx->Viewport._WindowMap.m[MAT_TZ];
-   GLfloat szInv;
-   GLuint i;
+   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   const GLchan rFog = swrast->_FogColor[RCOMP];
+   const GLchan gFog = swrast->_FogColor[GCOMP];
+   const GLchan bFog = swrast->_FogColor[BCOMP];
+   const GLuint haveW = (span->interpMask & SPAN_W);
+   GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba;
 
-   if (ctx->Viewport._WindowMap.m[MAT_SZ] == 0.0)
-      szInv = 1.0F;
-   else
-      szInv = 1.0F / ctx->Viewport._WindowMap.m[MAT_SZ];
+   ASSERT(swrast->_FogEnabled);
+   ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
+   ASSERT(span->arrayMask & SPAN_RGBA);
 
-   /*
-    * Note: to compute eyeZ from the ndcZ we have to solve the following:
-    *
-    *        p[10] * eyeZ + p[14] * eyeW
-    * ndcZ = ---------------------------
-    *        p[11] * eyeZ + p[15] * eyeW
-    *
-    * Thus:
-    *
-    *        p[14] * eyeW - p[15] * eyeW * ndcZ
-    * eyeZ = ----------------------------------
-    *             p[11] * ndcZ - p[10]
-    *
-    * If we note:
-    *    a) if using an orthographic projection, p[11] = 0 and p[15] = 1.
-    *    b) if using a perspective projection, p[11] = -1 and p[15] = 0.
-    *    c) we assume eyeW = 1 (not always true- glVertex4)
-    *
-    * Then we can simplify the calculation of eyeZ quite a bit.  We do
-    * separate calculations for the orthographic and perspective cases below.
-    * Note that we drop a negative sign or two since they don't matter.
+   /* NOTE: if haveW is true, that means the fog start/step values are
+    * perspective-corrected and we have to divide each fog coord by W.
     */
 
-   switch (ctx->Fog.Mode) {
+   /* we need to compute fog blend factors */
+   if (swrast->_PreferPixelFog) {
+      /* The span's fog values are fog coordinates, now compute blend factors
+       * and blend the fragment colors with the fog color.
+       */
+      switch (ctx->Fog.Mode) {
       case GL_LINEAR:
          {
-            GLfloat fogEnd = ctx->Fog.End;
-            GLfloat fogScale;
-            if (ctx->Fog.Start == ctx->Fog.End)
-               fogScale = 1.0;
-            else
-               fogScale = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
-            if (ortho) {
-               for (i=0;i<n;i++) {
-                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-                  GLfloat eyez = (ndcz - p14) / p10;
-                  GLfloat f;
-                  if (eyez < 0.0)
-                     eyez = -eyez;
-                  f = (fogEnd - eyez) * fogScale;
-                  fogFact[i] = CLAMP(f, 0.0F, 1.0F);
-               }
-            }
-            else {
-               /* perspective */
-               for (i=0;i<n;i++) {
-                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-                  GLfloat eyez = p14 / (ndcz + p10);
-                  GLfloat f;
-                  if (eyez < 0.0)
-                     eyez = -eyez;
-                  f = (fogEnd - eyez) * fogScale;
-                  fogFact[i] = CLAMP(f, 0.0F, 1.0F);
-               }
+            const GLfloat fogEnd = ctx->Fog.End;
+            const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
+               ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               GLfloat f, oneMinusF;
+               f = (fogEnd - FABSF(fogCoord/w)) * fogScale;
+               f = CLAMP(f, 0.0F, 1.0F);
+               oneMinusF = 1.0F - f;
+               rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog);
+               rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog);
+               rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog);
+               fogCoord += fogStep;
+               w += wStep;
             }
          }
-        break;
+         break;
       case GL_EXP:
-         if (ortho) {
-            for (i=0;i<n;i++) {
-               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-               GLfloat eyez = (ndcz - p14) / p10;
-               if (eyez < 0.0)
-                  eyez = -eyez;
-               fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
-            }
-         }
-         else {
-            /* perspective */
-            for (i=0;i<n;i++) {
-               GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-               GLfloat eyez = p14 / (ndcz + p10);
-               if (eyez < 0.0)
-                  eyez = -eyez;
-               fogFact[i] = (GLfloat) exp( -ctx->Fog.Density * eyez );
+         {
+            const GLfloat density = -ctx->Fog.Density;
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               GLfloat f, oneMinusF;
+               f = (GLfloat) exp(density * FABSF(fogCoord/w));
+               oneMinusF = 1.0F - f;
+               rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog);
+               rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog);
+               rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog);
+               fogCoord += fogStep;
+               w += wStep;
             }
          }
-        break;
+         break;
       case GL_EXP2:
          {
-            GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
-            if (ortho) {
-               for (i=0;i<n;i++) {
-                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-                  GLfloat eyez = (ndcz - p14) / p10;
-                  GLfloat tmp = negDensitySquared * eyez * eyez;
+            const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               const GLfloat coord = fogCoord / w;
+               GLfloat tmp = negDensitySquared * coord * coord;
+               GLfloat f, oneMinusF;
 #if defined(__alpha__) || defined(__alpha)
-                  /* XXX this underflow check may be needed for other systems*/
-                  if (tmp < FLT_MIN_10_EXP)
-                     tmp = FLT_MIN_10_EXP;
+               /* XXX this underflow check may be needed for other systems*/
+               if (tmp < FLT_MIN_10_EXP)
+                  tmp = FLT_MIN_10_EXP;
 #endif
-                  fogFact[i] = (GLfloat) exp( tmp );
-               }
-            }
-            else {
-               /* perspective */
-               for (i=0;i<n;i++) {
-                  GLfloat ndcz = ((GLfloat) z[i] - tz) * szInv;
-                  GLfloat eyez = p14 / (ndcz + p10);
-                  GLfloat tmp = negDensitySquared * eyez * eyez;
-#if defined(__alpha__) || defined(__alpha)
-                  /* XXX this underflow check may be needed for other systems*/
-                  if (tmp < FLT_MIN_10_EXP)
-                     tmp = FLT_MIN_10_EXP;
-#endif
-                  fogFact[i] = (GLfloat) exp( tmp );
-               }
+               f = (GLfloat) exp(tmp);
+               f = CLAMP(f, 0.0F, 1.0F);
+               oneMinusF = 1.0F - f;
+               rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog);
+               rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog);
+               rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog);
+               fogCoord += fogStep;
+               w += wStep;
             }
          }
-        break;
+         break;
       default:
-         _mesa_problem(ctx, "Bad fog mode in compute_fog_factors_from_z");
+         _mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span");
          return;
+      }
    }
-}
-
-
-
-/**
- * Apply fog to a span of RGBA pixels.
- * The fog factors are either in the span->array->fog or stored as base/step.
- * These are fog _factors_, not fog coords.  Fog coords were converted to
- * fog factors per vertex.
- */
-void
-_swrast_fog_rgba_span( const GLcontext *ctx, struct sw_span *span )
-{
-   const SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   const GLuint n = span->end;
-   GLchan (*rgba)[4] = (GLchan (*)[4]) span->array->rgba;
-   GLchan rFog, gFog, bFog;
-
-   ASSERT(ctx->Fog.Enabled);
-   ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
-   ASSERT(span->arrayMask & SPAN_RGBA);
-
-   UNCLAMPED_FLOAT_TO_CHAN(rFog, ctx->Fog.Color[RCOMP]);
-   UNCLAMPED_FLOAT_TO_CHAN(gFog, ctx->Fog.Color[GCOMP]);
-   UNCLAMPED_FLOAT_TO_CHAN(bFog, ctx->Fog.Color[BCOMP]);
-
-   if (swrast->_PreferPixelFog) {
-      /* compute fog factor from each fragment's Z value */
-      if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
-         _swrast_span_interpolate_z(ctx, span);
-      compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
-      span->arrayMask |= SPAN_FOG;
-   }
-
-   if (span->arrayMask & SPAN_FOG) {
-      /* use fog array in span */
+   else if (span->arrayMask & SPAN_FOG) {
+      /* The span's fog array values are blend factors.
+       * They were previously computed per-vertex.
+       */
       GLuint i;
-      for (i = 0; i < n; i++) {
-         const GLfloat fog = span->array->fog[i];
-         const GLfloat oneMinusFog = 1.0F - fog;
-         rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
-         rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
-         rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
+      for (i = 0; i < span->end; i++) {
+         const GLfloat f = span->array->fog[i];
+         const GLfloat oneMinusF = 1.0F - f;
+         rgba[i][RCOMP] = (GLchan) (f * rgba[i][RCOMP] + oneMinusF * rFog);
+         rgba[i][GCOMP] = (GLchan) (f * rgba[i][GCOMP] + oneMinusF * gFog);
+         rgba[i][BCOMP] = (GLchan) (f * rgba[i][BCOMP] + oneMinusF * bFog);
       }
    }
    else {
-      /* interpolate fog factors */
-      GLfloat fog = span->fog, dFog = span->fogStep;
+      /* The span's fog start/step values are blend factors.
+       * They were previously computed per-vertex.
+       */
+      const GLfloat fogStep = span->fogStep;
+      GLfloat fog = span->fog;
+      const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+      GLfloat w = haveW ? span->w : 1.0F;
       GLuint i;
-      for (i = 0; i < n; i++) {
-         const GLfloat oneMinusFog = 1.0F - fog;
-         rgba[i][RCOMP] = (GLchan) (fog * rgba[i][RCOMP] + oneMinusFog * rFog);
-         rgba[i][GCOMP] = (GLchan) (fog * rgba[i][GCOMP] + oneMinusFog * gFog);
-         rgba[i][BCOMP] = (GLchan) (fog * rgba[i][BCOMP] + oneMinusFog * bFog);
-         fog += dFog;
+      ASSERT(span->interpMask & SPAN_FOG);
+      for (i = 0; i < span->end; i++) {
+         const GLfloat fact = fog / w;
+         const GLfloat oneMinusF = 1.0F - fact;
+         rgba[i][RCOMP] = (GLchan) (fact * rgba[i][RCOMP] + oneMinusF * rFog);
+         rgba[i][GCOMP] = (GLchan) (fact * rgba[i][GCOMP] + oneMinusF * gFog);
+         rgba[i][BCOMP] = (GLchan) (fact * rgba[i][BCOMP] + oneMinusF * bFog);
+         fog += fogStep;
+         w += wStep;
       }
    }
 }
@@ -277,37 +217,110 @@ void
 _swrast_fog_ci_span( const GLcontext *ctx, struct sw_span *span )
 {
    const SWcontext *swrast = SWRAST_CONTEXT(ctx);
-   const GLuint n = span->end;
+   const GLuint haveW = (span->interpMask & SPAN_W);
+   const GLuint fogIndex = (GLuint) ctx->Fog.Index;
    GLuint *index = span->array->index;
 
-   ASSERT(ctx->Fog.Enabled);
+   ASSERT(swrast->_FogEnabled);
    ASSERT(span->arrayMask & SPAN_INDEX);
    ASSERT((span->interpMask | span->arrayMask) & SPAN_FOG);
 
+   /* we need to compute fog blend factors */
    if (swrast->_PreferPixelFog) {
-      /* compute fog factor from each fragment's Z value */
-      if ((span->interpMask & SPAN_Z) && (span->arrayMask & SPAN_Z) == 0)
-         _swrast_span_interpolate_z(ctx, span);
-      compute_fog_factors_from_z(ctx, n, span->array->z, span->array->fog);
-      span->arrayMask |= SPAN_FOG;
+      /* The span's fog values are fog coordinates, now compute blend factors
+       * and blend the fragment colors with the fog color.
+       */
+      switch (ctx->Fog.Mode) {
+      case GL_LINEAR:
+         {
+            const GLfloat fogEnd = ctx->Fog.End;
+            const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
+               ? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               GLfloat f = (fogEnd - FABSF(fogCoord/w)) * fogScale;
+               f = CLAMP(f, 0.0F, 1.0F);
+               index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
+               fogCoord += fogStep;
+               w += wStep;
+            }
+         }
+         break;
+      case GL_EXP:
+         {
+            const GLfloat density = -ctx->Fog.Density;
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               GLfloat f = (GLfloat) exp(density * FABSF(fogCoord/w));
+               index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
+               fogCoord += fogStep;
+               w += wStep;
+            }
+         }
+         break;
+      case GL_EXP2:
+         {
+            const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
+            const GLfloat fogStep = span->fogStep;
+            GLfloat fogCoord = span->fog;
+            const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+            GLfloat w = haveW ? span->w : 1.0F;
+            GLuint i;
+            for (i = 0; i < span->end; i++) {
+               const GLfloat coord = fogCoord / w;
+               GLfloat tmp = negDensitySquared * coord * coord;
+               GLfloat f;
+#if defined(__alpha__) || defined(__alpha)
+               /* XXX this underflow check may be needed for other systems*/
+               if (tmp < FLT_MIN_10_EXP)
+                  tmp = FLT_MIN_10_EXP;
+#endif
+               f = (GLfloat) exp(tmp);
+               f = CLAMP(f, 0.0F, 1.0F);
+               index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
+               fogCoord += fogStep;
+               w += wStep;
+            }
+         }
+         break;
+      default:
+         _mesa_problem(ctx, "Bad fog mode in _swrast_fog_ci_span");
+         return;
+      }
    }
-
-   if (span->arrayMask & SPAN_FOG) {
-      const GLuint idx = (GLuint) ctx->Fog.Index;
+   else if (span->arrayMask & SPAN_FOG) {
+      /* The span's fog array values are blend factors.
+       * They were previously computed per-vertex.
+       */
       GLuint i;
-      for (i = 0; i < n; i++) {
-         const GLfloat f = CLAMP(span->array->fog[i], 0.0F, 1.0F);
-         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
+      for (i = 0; i < span->end; i++) {
+         const GLfloat f = span->array->fog[i];
+         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
       }
    }
    else {
-      GLfloat fog = span->fog, dFog = span->fogStep;
-      const GLuint idx = (GLuint) ctx->Fog.Index;
+      /* The span's fog start/step values are blend factors.
+       * They were previously computed per-vertex.
+       */
+      const GLfloat fogStep = span->fogStep;
+      GLfloat fog = span->fog;
+      const GLfloat wStep = haveW ? span->dwdx : 0.0F;
+      GLfloat w = haveW ? span->w : 1.0F;
       GLuint i;
-      for (i = 0; i < n; i++) {
-         const GLfloat f = CLAMP(fog, 0.0F, 1.0F);
-         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * idx);
-         fog += dFog;
+      ASSERT(span->interpMask & SPAN_FOG);
+      for (i = 0; i < span->end; i++) {
+         const GLfloat f = fog / w;
+         index[i] = (GLuint) ((GLfloat) index[i] + (1.0F - f) * fogIndex);
+         fog += fogStep;
+         w += wStep;
       }
    }
 }
index ee46f323076e64964e54b481ce5e4db10be95472..cdd97f613a1b498ca7cec28b67a21317a0378c3d 100644 (file)
@@ -1079,7 +1079,7 @@ _swrast_write_rgba_span( GLcontext *ctx, struct sw_span *span)
    }
 
    /* Fog */
-   if (ctx->Fog.Enabled) {
+   if (swrast->_FogEnabled) {
       _swrast_fog_rgba_span(ctx, span);
       monoColor = GL_FALSE;
    }
@@ -1354,7 +1354,7 @@ _swrast_write_texture_span( GLcontext *ctx, struct sw_span *span)
    }
 
    /* Fog */
-   if (ctx->Fog.Enabled) {
+   if (swrast->_FogEnabled) {
       _swrast_fog_rgba_span(ctx, span);
    }
 
index 257f06c24ddde76e03172da68485107cdd4a51a7..01cd754e4abd0d98b024ffa0115725fd415c356c 100644 (file)
@@ -798,6 +798,7 @@ fast_persp_span(GLcontext *ctx, struct sw_span *span,
  */
 #define NAME persp_textured_triangle
 #define INTERP_Z 1
+#define INTERP_W 1
 #define INTERP_FOG 1
 #define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
 #define INTERP_RGB 1
index 28a80dee66fa4552dda7bf664cdb0c1464b2bef4..2e25e531cc8256dc8c72afeace8f0fa7f07ab09d 100644 (file)
@@ -411,8 +411,14 @@ static void NAME(GLcontext *ctx, const SWvertex *v0,
 #ifdef INTERP_FOG
       span.interpMask |= SPAN_FOG;
       {
+#  ifdef INTERP_W
+         const GLfloat wMax = vMax->win[3], wMin = vMin->win[3], wMid = vMid->win[3];
+         const GLfloat eMaj_dfog = vMax->fog * wMax - vMin->fog * wMin;
+         const GLfloat eBot_dfog = vMid->fog * wMid - vMin->fog * wMin;
+#  else
          const GLfloat eMaj_dfog = vMax->fog - vMin->fog;
          const GLfloat eBot_dfog = vMid->fog - vMin->fog;
+#  endif
          span.dfogdx = oneOverArea * (eMaj_dfog * eBot.dy - eMaj.dy * eBot_dfog);
          span.dfogdy = oneOverArea * (eMaj.dx * eBot_dfog - eMaj_dfog * eBot.dx);
          span.fogStep = span.dfogdx;
@@ -802,7 +808,11 @@ static void NAME(GLcontext *ctx, const SWvertex *v0,
                dwOuter = span.dwdy + dxOuter * span.dwdx;
 #endif
 #ifdef INTERP_FOG
+#  ifdef INTERP_W
+               fogLeft = vLower->fog * vLower->win[3] + (span.dfogdx * adjx + span.dfogdy * adjy) * (1.0F/FIXED_SCALE);
+#  else
                fogLeft = vLower->fog + (span.dfogdx * adjx + span.dfogdy * adjy) * (1.0F/FIXED_SCALE);
+#  endif
                dfogOuter = span.dfogdy + dxOuter * span.dfogdx;
 #endif
 #ifdef INTERP_RGB
index ec5f88cd96cd9e36b69e218457c41e3633f21434..626aa5290e63fafa12c23c3dac157fef82f6167c 100644 (file)
@@ -102,6 +102,7 @@ _tnl_CreateContext( GLcontext *ctx )
    tnl->NeedNdcCoords = GL_TRUE;
    tnl->LoopbackDListCassettes = GL_FALSE;
    tnl->CalcDListNormalLengths = GL_TRUE;
+   tnl->AllowVertexFog = GL_TRUE;
 
    /* Hook our functions into exec and compile dispatch tables.
     */
@@ -144,6 +145,10 @@ _tnl_InvalidateState( GLcontext *ctx, GLuint new_state )
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
 
+   if (new_state & (_NEW_HINT)) {
+      tnl->_DoVertexFog = tnl->AllowVertexFog && (ctx->Hint.Fog != GL_NICEST);
+   }
+
    if (new_state & _NEW_ARRAY) {
       tnl->pipeline.run_input_changes |= ctx->Array.NewState; /* overkill */
    }
@@ -259,3 +264,11 @@ _tnl_isolate_materials( GLcontext *ctx, GLboolean mode )
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    tnl->IsolateMaterials = mode;
 }
+
+void
+_tnl_allow_vertex_fog( GLcontext *ctx, GLboolean value )
+{
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   tnl->AllowVertexFog = value;
+}
+
index a9d36d24882a80ca5a413c30c3af2abf236bcf92..b7aff6c6266f019a1d63a48b3dbd501e752c4834 100644 (file)
@@ -364,11 +364,6 @@ struct tnl_save {
 };
 
 
-
-
-
-
-
 struct tnl_vertex_arrays
 {
    /* Conventional vertex attribute arrays */
@@ -433,14 +428,13 @@ struct vertex_buffer
    /* Private data from _tnl_render_stage that has no business being
     * in this struct.
     */
-
 };
 
 
-
 /** Describes an individual operation on the pipeline.
  */
-struct tnl_pipeline_stage {
+struct tnl_pipeline_stage
+{
    const char *name;
    GLuint check_state;         /* All state referenced in check() --
                                 * When is the pipeline_stage struct
@@ -513,7 +507,8 @@ typedef void (*insert_func)( const struct tnl_clipspace_attr *a, GLubyte *v,
                             const GLfloat *in );
 
 
-struct tnl_clipspace_attr {
+struct tnl_clipspace_attr
+{
    int attrib;
    int vertoffset;
    int vertattrsize;
@@ -546,7 +541,8 @@ typedef void (*setup_func)( GLcontext *ctx,
 
 
 
-struct tnl_clipspace {
+struct tnl_clipspace
+{
    GLboolean need_extras;
    
    GLuint new_inputs;
@@ -564,7 +560,8 @@ struct tnl_clipspace {
 };
 
 
-struct tnl_device_driver {
+struct tnl_device_driver
+{
    /***
     *** TNL Pipeline
     ***/
@@ -588,7 +585,8 @@ struct tnl_device_driver {
    /***
     *** Rendering -- These functions called only from t_vb_render.c
     ***/
-   struct {
+   struct
+   {
       void (*Start)(GLcontext *ctx);
       void (*Finish)(GLcontext *ctx);
       /* Called before and after all rendering operations, including DrawPixels,
@@ -667,8 +665,11 @@ struct tnl_device_driver {
 };
    
 
-typedef struct {
-
+/**
+ * Context state for T&L context.
+ */
+typedef struct
+{
    /* Driver interface.
     */
    struct tnl_device_driver Driver;
@@ -693,23 +694,21 @@ typedef struct {
    struct tnl_vertex_arrays current;
    struct tnl_vertex_arrays array_inputs;
 
-
    /* Clipspace/ndc/window vertex managment:
     */
    struct tnl_clipspace clipspace;
 
-
    /* Probably need a better configuration mechanism:
     */
    GLboolean NeedNdcCoords;
    GLboolean LoopbackDListCassettes;
    GLboolean CalcDListNormalLengths;
    GLboolean IsolateMaterials;
+   GLboolean AllowVertexFog;
 
-   /* 
-    */
-   GLuint render_inputs;
+   GLboolean _DoVertexFog;  /* eval fog function at each vertex? */
 
+   GLuint render_inputs;
 
    GLvertexformat exec_vtxfmt;
    GLvertexformat save_vtxfmt;
index 34f1e811cc341c3425eb84b81185adb45d355a6e..3be62e887bd4390f87b2d8a6888e79c18f3b4f65 100644 (file)
@@ -71,7 +71,11 @@ do {                                                         \
 #endif
 
 
-static void init_static_data( void )
+/**
+ * Initialize the exp_table[] lookup table for approximating exp().
+ */
+static void
+init_static_data( void )
 {
    GLfloat f = 0.0F;
    GLint i = 0;
@@ -89,8 +93,8 @@ static void init_static_data( void )
  * near and far clip plane distances).
  * Fog blend factors are in the range [0,1].
  */
-static void compute_fog_blend_factors( GLcontext *ctx, GLvector4f *out,
-                                       const GLvector4f *in )
+static void
+compute_fog_blend_factors(GLcontext *ctx, GLvector4f *out, const GLvector4f *in)
 {
    GLfloat end  = ctx->Fog.End;
    GLfloat *v = in->start;
@@ -109,19 +113,22 @@ static void compute_fog_blend_factors( GLcontext *ctx, GLvector4f *out,
       else
          d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
       for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
-         GLfloat f = (end - FABSF(*v)) * d;
+         const GLfloat z = FABSF(*v);
+         GLfloat f = (end - z) * d;
         data[i][0] = CLAMP(f, 0.0F, 1.0F);
       }
       break;
    case GL_EXP:
       d = ctx->Fog.Density;
-      for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride))
-         NEG_EXP( data[i][0], d * FABSF(*v) );
+      for ( i = 0 ; i < n ; i++, STRIDE_F(v,stride)) {
+         const GLfloat z = FABSF(*v);
+         NEG_EXP( data[i][0], d * z );
+      }
       break;
    case GL_EXP2:
       d = ctx->Fog.Density*ctx->Fog.Density;
       for ( i = 0 ; i < n ; i++, STRIDE_F(v, stride)) {
-         GLfloat z = *v;
+         const GLfloat z = *v;
          NEG_EXP( data[i][0], d * z * z );
       }
       break;
@@ -132,10 +139,11 @@ static void compute_fog_blend_factors( GLcontext *ctx, GLvector4f *out,
 }
 
 
-static GLboolean run_fog_stage( GLcontext *ctx,
-                               struct tnl_pipeline_stage *stage )
+static GLboolean
+run_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
 {
-   struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb;
+   TNLcontext *tnl = TNL_CONTEXT(ctx);
+   struct vertex_buffer *VB = &tnl->vb;
    struct fog_stage_data *store = FOG_STAGE_DATA(stage);
    GLvector4f *input;
 
@@ -143,12 +151,13 @@ static GLboolean run_fog_stage( GLcontext *ctx,
       return GL_TRUE;
 
    if (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT) {
-      /* fog computed from Z depth */
+      /* Fog is computed from vertex or fragment Z values */
       /* source = VB->ObjPtr or VB->EyePtr coords */
       /* dest = VB->FogCoordPtr = fog stage private storage */
       VB->FogCoordPtr = &store->fogcoord;
 
       if (!ctx->_NeedEyeCoords) {
+         /* compute fog coords from object coords */
         const GLfloat *m = ctx->ModelviewMatrixStack.Top->m;
         GLfloat plane[4];
 
@@ -171,6 +180,7 @@ static GLboolean run_fog_stage( GLcontext *ctx,
         input->count = VB->ObjPtr->count;
       }
       else {
+         /* fog coordinates = eye Z coordinates (use ABS later) */
         input = &store->input;
 
         if (VB->EyePtr->size < 2)
@@ -184,21 +194,26 @@ static GLboolean run_fog_stage( GLcontext *ctx,
    }
    else {
       /* use glFogCoord() coordinates */
-      /* source = VB->FogCoordPtr */
-      input = VB->FogCoordPtr;
-      /* dest = fog stage private storage */
-      VB->FogCoordPtr = &store->fogcoord;
+      input = VB->FogCoordPtr;  /* source data */
+      VB->FogCoordPtr = &store->fogcoord;  /* dest data */
    }
 
-   /* compute blend factors from fog coordinates */
-   compute_fog_blend_factors( ctx, VB->FogCoordPtr, input );
+   if (tnl->_DoVertexFog) {
+      /* compute blend factors from fog coordinates */
+      compute_fog_blend_factors( ctx, VB->FogCoordPtr, input );
+   }
+   else {
+      /* results = incoming fog coords (compute fog per-fragment later) */
+      VB->FogCoordPtr = input;
+   }
 
    VB->AttribPtr[_TNL_ATTRIB_FOG] = VB->FogCoordPtr;
    return GL_TRUE;
 }
 
 
-static void check_fog_stage( GLcontext *ctx, struct tnl_pipeline_stage *stage )
+static void
+check_fog_stage(GLcontext *ctx, struct tnl_pipeline_stage *stage)
 {
    stage->active = ctx->Fog.Enabled && !ctx->VertexProgram.Enabled;
 
@@ -211,8 +226,8 @@ static void check_fog_stage( GLcontext *ctx, struct tnl_pipeline_stage *stage )
 
 /* Called the first time stage->run() is invoked.
  */
-static GLboolean alloc_fog_data( GLcontext *ctx,
-                                struct tnl_pipeline_stage *stage )
+static GLboolean
+alloc_fog_data(GLcontext *ctx, struct tnl_pipeline_stage *stage)
 {
    TNLcontext *tnl = TNL_CONTEXT(ctx);
    struct fog_stage_data *store;
@@ -234,7 +249,8 @@ static GLboolean alloc_fog_data( GLcontext *ctx,
 }
 
 
-static void free_fog_data( struct tnl_pipeline_stage *stage )
+static void
+free_fog_data(struct tnl_pipeline_stage *stage)
 {
    struct fog_stage_data *store = FOG_STAGE_DATA(stage);
    if (store) {
index 9a2241d8fce5e1479d7c8e38eef571d409994c4c..3be222a6e02d8eb20be262fbb4b370f3821d681a 100644 (file)
@@ -75,4 +75,10 @@ extern void
 _tnl_isolate_materials( GLcontext *ctx, GLboolean flag );
 
 
+/* Control whether T&L does per-vertex fog
+ */
+extern void
+_tnl_allow_vertex_fog( GLcontext *ctx, GLboolean value );
+
+
 #endif