stencil wrap works, either HW or SW (Ian Romanick)
[mesa.git] / src / mesa / drivers / glide / fxsetup.c
index cdfef4755646a2910a12b1c7e7744f9e57e53970..71b66fcc1d7b15a4081eb7348a8070116145004a 100644 (file)
@@ -42,7 +42,9 @@
 
 #include "fxdrv.h"
 #include "enums.h"
+#include "tnl.h"
 #include "tnl/t_context.h"
+#include "swrast.h"
 
 static void
 fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
@@ -63,9 +65,9 @@ fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
 
    ti->tObj = tObj;
    minl = ti->minLevel = tObj->BaseLevel;
-   maxl = ti->maxLevel = MIN2(tObj->MaxLevel, tObj->Image[0]->MaxLog2);
+   maxl = ti->maxLevel = MIN2(tObj->MaxLevel, tObj->Image[0][0]->MaxLog2);
 
-#if 1||FX_RESCALE_BIG_TEXURES
+#if FX_RESCALE_BIG_TEXURES_HACK
 {
    extern void _mesa_rescale_teximage2d( GLuint bytesPerPixel,
                                          GLuint dstRowStride,
@@ -73,58 +75,40 @@ fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
                                          GLint dstWidth, GLint dstHeight,
                                          const GLvoid *srcImage, GLvoid *dstImage );
    fxMesaContext fxMesa = FX_CONTEXT(ctx);
-   if (maxl - minl > fxMesa->textureMaxLod) {
-      /* [dBorca]
-       * Ooooooook! Here's a(nother) long story.
-       * We get here because we need to handle a texture larger
-       * than hardware can support. Two cases:
-       * 1) we have mipmaps. Then we just push up to the first supported
-       *    LOD. A possible drawback is that Mesa will ignore the skipped
-       *    LODs on further texture handling.
-       *    Will this interfere with GL_TEXTURE_[MIN|BASE]_LEVEL? How?
-       * 2) we don't have mipmaps. We need to rescale texture; two ways:
-       *    a) create a new LOD and push up ti->minLevel and tObj->BaseLevel
-       *       but this means we need to rescale on both axes, which
-       *       yield unnecessary ugly texture. Also, same issues as 1)
-       *    b) rescale the biggest LOD in place and go two ways:
-       *       - update texImage->Width and texImage->Height, then
-       *         decrease maxLevel, so we won't rescale again on the
-       *         next validation. Changing texImage-> parameters is
-       *         not quite legal here (see convolution), but...
-       *       - leaving texImage-> parameters alone, while rescaling
-       *         texture and decreasing maxLevel makes Mesa puke. Also
-       *         this approach requires that mml->[wh]Scale go below 1,
-       *         otherwise bad ju-ju will be in our future (see fetch_texel)
-       *       Will this interfere with GL_TEXTURE_MAX_LEVEL? How?
-       *       The above approach is somehow dumb! we might have rescaled
-       *       once in TexImage2D to accomodate aspect ratio, and now we
-       *       are rescaling again. The thing is, in TexImage2D we don't
-       *       know whether we'll hit 1) or 2) by the time of validation.
-       * NB: we could handle mml->[wh]Scale nicely, using (biased) shifts.
-       *
-       * Which brings me to another issue. How can we handle NPOT textures?
-       * - rescaling NPOT to the next bigger POT (mml->[wh]Scale can't shift)
-       * - upping the max LOD to the next power-of-two, in fxTexGetInfo; then
-       *   choosing non-power-of-two values for ti->[st]Scale... Anyhow, we
-       *   still need to align mipmaps correctly in texture memory!
-       */
-      if ((tObj->MinFilter == GL_NEAREST) || (tObj->MinFilter == GL_LINEAR)) {
-         /* no mipmaps! need to rescale */
-         struct gl_texture_image *texImage = tObj->Image[minl];
-         tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
+   /* [dBorca]
+    * Fake textures larger than HW supports:
+    * 1) we have mipmaps. Then we just push up to the first supported
+    *    LOD. A possible drawback is that Mesa will ignore the skipped
+    *    LODs on further texture handling.
+    *    Will this interfere with GL_TEXTURE_[MIN|BASE]_LEVEL? How?
+    * 2) we don't have mipmaps. We need to rescale the big LOD in place.
+    *    The above approach is somehow dumb! we might have rescaled
+    *    once in TexImage2D to accomodate aspect ratio, and now we
+    *    are rescaling again. The thing is, in TexImage2D we don't
+    *    know whether we'll hit 1) or 2) by the time of validation.
+    */
+   if ((tObj->MinFilter == GL_NEAREST) || (tObj->MinFilter == GL_LINEAR)) {
+      /* no mipmaps! */
+      struct gl_texture_image *texImage = tObj->Image[0][minl];
+      tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
+      GLint _w, _h, maxSize = 1 << fxMesa->textureMaxLod;
+      if ((mml->width > maxSize) || (mml->height > maxSize)) {
+         /* need to rescale */
          GLint texelBytes = texImage->TexFormat->TexelBytes;
          GLvoid *texImage_Data = texImage->Data;
-         GLint _w = MIN2(mml->width, 1 << fxMesa->textureMaxLod);
-         GLint _h = MIN2(mml->height, 1 << fxMesa->textureMaxLod);
+         _w = MIN2(texImage->Width, maxSize);
+         _h = MIN2(texImage->Height, maxSize);
          if (TDFX_DEBUG & VERBOSE_TEXTURE) {
             fprintf(stderr, "fxTexValidate: rescaling %d x %d -> %d x %d\n",
-                            mml->width, mml->height,
-                            _w, _h);
+                            texImage->Width, texImage->Height, _w, _h);
          }
+         /* we should leave these as is and... (!) */
+         texImage->Width = _w;
+         texImage->Height = _h;
          fxTexGetInfo(_w, _h, NULL, NULL, NULL, NULL,
                       &(mml->wScale), &(mml->hScale));
-         texImage->Width = _w / mml->wScale;
-         texImage->Height = _h / mml->hScale;
+         _w *= mml->wScale;
+         _h *= mml->hScale;
          texImage->Data = MESA_PBUFFER_ALLOC(_w * _h * texelBytes);
          _mesa_rescale_teximage2d(texelBytes,
                                   _w * texelBytes, /* dst stride */
@@ -134,8 +118,11 @@ fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
          MESA_PBUFFER_FREE(texImage_Data);
          mml->width = _w;
          mml->height = _h;
-         maxl = ti->maxLevel = tObj->Image[0]->MaxLog2 = minl + fxMesa->textureMaxLod;
-      } else {
+         /* (!) ... and set mml->wScale = _w / texImage->Width */
+      }
+   } else {
+      /* mipmapping */
+      if (maxl - minl > fxMesa->textureMaxLod) {
          /* skip a certain number of LODs */
          minl += maxl - fxMesa->textureMaxLod;
          if (TDFX_DEBUG & VERBOSE_TEXTURE) {
@@ -147,19 +134,29 @@ fxTexValidate(GLcontext * ctx, struct gl_texture_object *tObj)
 }
 #endif
 
-   fxTexGetInfo(tObj->Image[minl]->Width, tObj->Image[minl]->Height,
+   fxTexGetInfo(tObj->Image[0][minl]->Width, tObj->Image[0][minl]->Height,
                &(FX_largeLodLog2(ti->info)), &(FX_aspectRatioLog2(ti->info)),
                &(ti->sScale), &(ti->tScale),
                NULL, NULL);
 
    if ((tObj->MinFilter != GL_NEAREST) && (tObj->MinFilter != GL_LINEAR))
-      fxTexGetInfo(tObj->Image[maxl]->Width, tObj->Image[maxl]->Height,
+      fxTexGetInfo(tObj->Image[0][maxl]->Width, tObj->Image[0][maxl]->Height,
                   &(FX_smallLodLog2(ti->info)), NULL,
                   NULL, NULL, NULL, NULL);
    else
       FX_smallLodLog2(ti->info) = FX_largeLodLog2(ti->info);
 
-   ti->baseLevelInternalFormat = tObj->Image[minl]->Format;
+   /* [dBorca] this is necessary because of fxDDCompressedTexImage2D */
+   if (ti->padded) {
+      struct gl_texture_image *texImage = tObj->Image[0][minl];
+      tfxMipMapLevel *mml = FX_MIPMAP_DATA(texImage);
+      if (mml->wScale != 1 || mml->hScale != 1) {
+         ti->sScale /= mml->wScale;
+         ti->tScale /= mml->hScale;
+      }
+   }
+
+   ti->baseLevelInternalFormat = tObj->Image[0][minl]->Format;
 
    ti->validated = GL_TRUE;
 
@@ -345,9 +342,7 @@ fxSetupSingleTMU_NoLock(fxMesaContext fxMesa, struct gl_texture_object *tObj)
       fprintf(stderr, "fxSetupSingleTMU_NoLock(%p (%d))\n", (void *)tObj, tObj->Name);
    }
 
-#if 1 /* [dBorca] Good... bad... I'm the guy with the gun! */
    ti->lastTimeUsed = fxMesa->texBindNumber;
-#endif
 
    /* Make sure we're not loaded incorrectly */
    if (ti->isInTM) {
@@ -497,10 +492,7 @@ fxSelectSingleTMUSrc_NoLock(fxMesaContext fxMesa, GLint tmu, FxBool LODblend)
          tex1.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
          tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
 
-        /* [dBorca] Hack alert:
-          * don't use GR_COMBINE_FUNCTION_SCALE_OTHER
-          * such that Glide recognizes TMU0 in passthrough mode
-          */
+        /* correct values to set TMU0 in passthrough mode */
          tex0.FunctionRGB   = GR_COMBINE_FUNCTION_BLEND;
          tex0.FactorRGB     = GR_COMBINE_FACTOR_ONE;
          tex0.FunctionAlpha = GR_COMBINE_FUNCTION_BLEND;
@@ -537,7 +529,7 @@ fxSetupTextureSingleTMU_NoLock(GLcontext * ctx, GLuint textureset)
    GLuint unitsmode;
    GLint ifmt;
    tfxTexInfo *ti;
-   struct gl_texture_object *tObj = ctx->Texture.Unit[textureset].Current2D;
+   struct gl_texture_object *tObj = ctx->Texture.Unit[textureset]._Current;
    int tmu;
 
    if (TDFX_DEBUG & VERBOSE_DRIVER) {
@@ -641,16 +633,25 @@ fxSetupTextureSingleTMU_NoLock(GLcontext * ctx, GLuint textureset)
          colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
          colorComb.Other    = GR_COMBINE_OTHER_NONE;
       } else {
-         /* [dBorca] Hack alert:
-          * only Voodoo^2 can GL_BLEND (GR_COMBINE_FACTOR_TEXTURE_RGB)
-          */
          if (fxMesa->type >= GR_SSTTYPE_Voodoo2) {
             colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
             colorComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_RGB;
             colorComb.Other    = GR_COMBINE_OTHER_CONSTANT;
+         } else if (ifmt == GL_INTENSITY) {
+            /* just a hack: RGB == ALPHA */
+            colorComb.Function = GR_COMBINE_FUNCTION_BLEND;
+            colorComb.Factor   = GR_COMBINE_FACTOR_TEXTURE_ALPHA;
+            colorComb.Other    = GR_COMBINE_OTHER_CONSTANT;
          } else {
+            /* Only Voodoo^2 can GL_BLEND (GR_COMBINE_FACTOR_TEXTURE_RGB)
+             * These settings assume that the TexEnv color is black and
+             * incoming fragment color is white.
+             */
+            colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+            colorComb.Invert   = FXTRUE;
             _mesa_problem(NULL, "can't GL_BLEND with SST1");
-            return;
          }
       }
 
@@ -698,7 +699,7 @@ fxSetupTextureSingleTMU_NoLock(GLcontext * ctx, GLuint textureset)
       }
       else {
          /* sum of texel and fragment alpha */
-         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+         alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
          alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
          alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
       }
@@ -711,7 +712,7 @@ fxSetupTextureSingleTMU_NoLock(GLcontext * ctx, GLuint textureset)
       }
       else {
          /* sum of texel and fragment rgb */
-         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL,
+         colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER_ADD_LOCAL;
          colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
          colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
       }
@@ -921,8 +922,8 @@ fxSetupTextureDoubleTMU_NoLock(GLcontext * ctx)
    struct tdfx_texcombine tex0, tex1;
    GrCombineLocal_t localc, locala;
    tfxTexInfo *ti0, *ti1;
-   struct gl_texture_object *tObj0 = ctx->Texture.Unit[1].Current2D;
-   struct gl_texture_object *tObj1 = ctx->Texture.Unit[0].Current2D;
+   struct gl_texture_object *tObj0 = ctx->Texture.Unit[1]._Current;
+   struct gl_texture_object *tObj1 = ctx->Texture.Unit[0]._Current;
    GLuint envmode, ifmt, unitsmode;
    int tmu0 = 0, tmu1 = 1;
 
@@ -1182,6 +1183,40 @@ fxSetupTextureDoubleTMU_NoLock(GLcontext * ctx)
          alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
         break;
       }
+
+   case (FX_UM_E0_MODULATE | FX_UM_E1_REPLACE): /* Homeworld2 */
+      {
+         tex1.FunctionRGB   = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex1.FunctionAlpha = GR_COMBINE_FUNCTION_ZERO;
+         tex1.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         tex0.FunctionRGB   = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorRGB     = GR_COMBINE_FACTOR_NONE;
+         tex0.FunctionAlpha = GR_COMBINE_FUNCTION_LOCAL;
+         tex0.FactorAlpha   = GR_COMBINE_FACTOR_NONE;
+
+         if (ifmt & (FX_UM_E0_RGB | FX_UM_E0_LUMINANCE)) {
+            alphaComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+            alphaComb.Factor   = GR_COMBINE_FACTOR_NONE;
+            alphaComb.Other    = GR_COMBINE_OTHER_NONE;
+         } else {
+            alphaComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            alphaComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            alphaComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+         }
+
+         if (ifmt & FX_UM_E0_ALPHA) {
+            colorComb.Function = GR_COMBINE_FUNCTION_LOCAL;
+            colorComb.Factor   = GR_COMBINE_FACTOR_NONE;
+            colorComb.Other    = GR_COMBINE_OTHER_NONE;
+         } else {
+            colorComb.Function = GR_COMBINE_FUNCTION_SCALE_OTHER;
+            colorComb.Factor   = GR_COMBINE_FACTOR_ONE;
+            colorComb.Other    = GR_COMBINE_OTHER_TEXTURE;
+         }
+         break;
+      }
    default:
       fprintf(stderr, "fxSetupTextureDoubleTMU_NoLock: Unexpected dual texture mode encountered\n");
       return;
@@ -1269,15 +1304,15 @@ fxSetupTexture_NoLock(GLcontext * ctx)
 
    if (fxMesa->HaveCmbExt) {
       /* Texture Combine, Color Combine and Alpha Combine. */
-      if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
-          ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT &&
+      if ((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
           fxMesa->haveTwoTMUs) {
          fxSetupTextureDoubleTMUNapalm_NoLock(ctx);
       }
-      else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+      else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
          fxSetupTextureSingleTMUNapalm_NoLock(ctx, 0);
       }
-      else if (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+      else if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
          fxSetupTextureSingleTMUNapalm_NoLock(ctx, 1);
       }
       else {
@@ -1285,15 +1320,15 @@ fxSetupTexture_NoLock(GLcontext * ctx)
       }
    } else {
       /* Texture Combine, Color Combine and Alpha Combine. */
-      if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT &&
-          ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT &&
+      if ((ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
+          (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) &&
           fxMesa->haveTwoTMUs) {
          fxSetupTextureDoubleTMU_NoLock(ctx);
       }
-      else if (ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) {
+      else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
          fxSetupTextureSingleTMU_NoLock(ctx, 0);
       }
-      else if (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) {
+      else if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) {
          fxSetupTextureSingleTMU_NoLock(ctx, 1);
       }
       else {
@@ -1319,48 +1354,32 @@ fxDDBlendFuncSeparate(GLcontext * ctx, GLenum sfactor, GLenum dfactor, GLenum as
 {
    fxMesaContext fxMesa = FX_CONTEXT(ctx);
    tfxUnitsState *us = &fxMesa->unitsState;
+   GLboolean isNapalm = (fxMesa->type >= GR_SSTTYPE_Voodoo4);
    GLboolean have32bpp = (fxMesa->colDepth == 32);
    GLboolean haveAlpha = fxMesa->haveHwAlpha;
    GrAlphaBlendFnc_t sfact, dfact, asfact, adfact;
 
-   /* [dBorca] Hack alert:
-    * We should condition *DST_ALPHA* modes
-    * by the boolean `haveAlpha' above!
-    * It indicates whether we really have HW alpha buffer...
+   /*
+    * 15/16 BPP alpha channel alpha blending modes
+    *   0x0    AZERO           Zero
+    *   0x4    AONE            One
+    *
+    * 32 BPP alpha channel alpha blending modes
+    *   0x0    AZERO           Zero
+    *   0x1    ASRC_ALPHA      Source alpha
+    *   0x3    ADST_ALPHA      Destination alpha
+    *   0x4    AONE            One
+    *   0x5    AOMSRC_ALPHA    1 - Source alpha
+    *   0x7    AOMDST_ALPHA    1 - Destination alpha
+    *
+    * If we don't have HW alpha buffer:
+    *   DST_ALPHA == 1
+    *   ONE_MINUS_DST_ALPHA == 0
+    * Unsupported modes are:
+    *   1 if used as src blending factor
+    *   0 if used as dst blending factor
     */
 
-/*
-When the value A_COLOR is selected as the destination alpha blending factor,
-the source pixel color is used as the destination blending factor.  When the
-value A_COLOR is selected as the source alpha blending factor, the destination
-pixel color is used as the source blending factor.  When the value A_SAMECOLOR
-is selected as the destination alpha blending factor, the destination pixel
-color is used as the destination blending factor.  When the value A_SAMECOLOR
-is selected as the source alpha blending factor, the source pixel color is
-used as the source blending factor.  Note also that the alpha blending
-function 0xf (A_COLORBEFOREFOG/ASATURATE) is different depending upon whether
-it is being used as a source or destination alpha blending function.  When the
-value 0xf is selected as the destination alpha blending factor, the source
-color before the fog unit ("unfogged" color) is used as the destination
-blending factor -- this alpha blending function is useful for multi-pass
-rendering with atmospheric effects.  When the value 0xf is selected as the
-source alpha blending factor, the alpha-saturate anti-aliasing algorithm is
-selected -- this MIN function performs polygonal anti-aliasing for polygons
-which are drawn front-to-back.
-
-15/16 BPP alpha channel alpha blending modes
-       0x0     AZERO           Zero
-       0x4     AONE            One
-
-32 BPP alpha channel alpha blending modes
-       0x0     AZERO           Zero
-       0x1     ASRC_ALPHA      Source alpha
-       0x3     ADST_ALPHA      Destination alpha
-       0x4     AONE            One
-       0x5     AOMSRC_ALPHA    1 - Source alpha
-       0x7     AOMDST_ALPHA    1 - Destination alpha
-*/
-
    switch (sfactor) {
    case GL_ZERO:
       sfact = GR_BLEND_ZERO;
@@ -1381,19 +1400,24 @@ which are drawn front-to-back.
       sfact = GR_BLEND_ONE_MINUS_SRC_ALPHA;
       break;
    case GL_DST_ALPHA:
-      sfact = GR_BLEND_DST_ALPHA;
+      sfact = haveAlpha ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
    case GL_ONE_MINUS_DST_ALPHA:
-      sfact = GR_BLEND_ONE_MINUS_DST_ALPHA;
+      sfact = haveAlpha ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
    case GL_SRC_ALPHA_SATURATE:
       sfact = GR_BLEND_ALPHA_SATURATE;
       break;
    case GL_SRC_COLOR:
+      if (isNapalm) {
+         sfact = GR_BLEND_SAME_COLOR_EXT;
+         break;
+      }
    case GL_ONE_MINUS_SRC_COLOR:
-      /* USELESS */
-      sfact = GR_BLEND_ONE;
-      break;
+      if (isNapalm) {
+         sfact = GR_BLEND_ONE_MINUS_SAME_COLOR_EXT;
+         break;
+      }
    default:
       sfact = GR_BLEND_ONE;
       break;
@@ -1406,34 +1430,27 @@ which are drawn front-to-back.
    case GL_ONE:
       asfact = GR_BLEND_ONE;
       break;
-   case GL_DST_COLOR:
-      asfact = GR_BLEND_ONE/*bad*/;
-      break;
-   case GL_ONE_MINUS_DST_COLOR:
-      asfact = GR_BLEND_ONE/*bad*/;
-      break;
+   case GL_SRC_COLOR:
    case GL_SRC_ALPHA:
       asfact = have32bpp ? GR_BLEND_SRC_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
+   case GL_ONE_MINUS_SRC_COLOR:
    case GL_ONE_MINUS_SRC_ALPHA:
       asfact = have32bpp ? GR_BLEND_ONE_MINUS_SRC_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
+   case GL_DST_COLOR:
    case GL_DST_ALPHA:
-      asfact = have32bpp ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      asfact = (have32bpp && haveAlpha) ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
+   case GL_ONE_MINUS_DST_COLOR:
    case GL_ONE_MINUS_DST_ALPHA:
-      asfact = have32bpp ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ONE/*bad*/;
+      asfact = (have32bpp && haveAlpha) ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
    case GL_SRC_ALPHA_SATURATE:
-      asfact = GR_BLEND_ONE/*bad*/;
-      break;
-   case GL_SRC_COLOR:
-   case GL_ONE_MINUS_SRC_COLOR:
-      /* USELESS */
-      asfact = GR_BLEND_ONE/*bad*/;
+      asfact = GR_BLEND_ONE;
       break;
    default:
-      asfact = GR_BLEND_ONE/*bad*/;
+      asfact = GR_BLEND_ONE;
       break;
    }
 
@@ -1457,21 +1474,21 @@ which are drawn front-to-back.
       dfact = GR_BLEND_ONE_MINUS_SRC_ALPHA;
       break;
    case GL_DST_ALPHA:
-      /* dfact=GR_BLEND_DST_ALPHA; */
-      /* We can't do DST_ALPHA */
-      dfact = GR_BLEND_ONE;
+      dfact = haveAlpha ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
    case GL_ONE_MINUS_DST_ALPHA:
-      /* dfact=GR_BLEND_ONE_MINUS_DST_ALPHA; */
-      /* We can't do DST_ALPHA */
-      dfact = GR_BLEND_ZERO;
+      dfact = haveAlpha ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
-   case GL_SRC_ALPHA_SATURATE:
    case GL_DST_COLOR:
+      if (isNapalm) {
+         dfact = GR_BLEND_SAME_COLOR_EXT;
+         break;
+      }
    case GL_ONE_MINUS_DST_COLOR:
-      /* USELESS */
-      dfact = GR_BLEND_ZERO;
-      break;
+      if (isNapalm) {
+         dfact = GR_BLEND_ONE_MINUS_SAME_COLOR_EXT;
+         break;
+      }
    default:
       dfact = GR_BLEND_ZERO;
       break;
@@ -1485,31 +1502,23 @@ which are drawn front-to-back.
       adfact = GR_BLEND_ONE;
       break;
    case GL_SRC_COLOR:
-      adfact = GR_BLEND_ZERO/*bad*/;
-      break;
-   case GL_ONE_MINUS_SRC_COLOR:
-      adfact = GR_BLEND_ZERO/*bad*/;
-      break;
    case GL_SRC_ALPHA:
       adfact = have32bpp ? GR_BLEND_SRC_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
+   case GL_ONE_MINUS_SRC_COLOR:
    case GL_ONE_MINUS_SRC_ALPHA:
       adfact = have32bpp ? GR_BLEND_ONE_MINUS_SRC_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
+   case GL_DST_COLOR:
    case GL_DST_ALPHA:
-      adfact = have32bpp ? GR_BLEND_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
+      adfact = (have32bpp && haveAlpha) ? GR_BLEND_DST_ALPHA : GR_BLEND_ONE/*bad*/;
       break;
-   case GL_ONE_MINUS_DST_ALPHA:
-      adfact = have32bpp ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
-      break;
-   case GL_SRC_ALPHA_SATURATE:
-   case GL_DST_COLOR:
    case GL_ONE_MINUS_DST_COLOR:
-      /* USELESS */
-      adfact = GR_BLEND_ZERO/*bad*/;
+   case GL_ONE_MINUS_DST_ALPHA:
+      adfact = (have32bpp && haveAlpha) ? GR_BLEND_ONE_MINUS_DST_ALPHA : GR_BLEND_ZERO/*bad*/;
       break;
    default:
-      adfact = GR_BLEND_ZERO/*bad*/;
+      adfact = GR_BLEND_ZERO;
       break;
    }
 
@@ -1527,28 +1536,45 @@ which are drawn front-to-back.
 }
 
 void
-fxDDBlendEquation(GLcontext * ctx, GLenum mode)
+fxDDBlendEquationSeparate(GLcontext * ctx, GLenum modeRGB, GLenum modeA)
 {
  fxMesaContext fxMesa = FX_CONTEXT(ctx);
  tfxUnitsState *us = &fxMesa->unitsState;
  GrAlphaBlendOp_t q;
 
- switch (mode) {
-        case GL_FUNC_ADD_EXT:
+ switch (modeRGB) {
+        case GL_FUNC_ADD:
              q = GR_BLEND_OP_ADD;
              break;
-        case GL_FUNC_SUBTRACT_EXT:
+        case GL_FUNC_SUBTRACT:
              q = GR_BLEND_OP_SUB;
              break;
-        case GL_FUNC_REVERSE_SUBTRACT_EXT:
+        case GL_FUNC_REVERSE_SUBTRACT:
              q = GR_BLEND_OP_REVSUB;
              break;
         default:
-             return;
+             q = us->blendEqRGB;
+ }
+ if (q != us->blendEqRGB) {
+    us->blendEqRGB = q;
+    fxMesa->new_state |= FX_NEW_BLEND;
  }
 
- if ((q != us->blendEq) && fxMesa->HavePixExt) {
-    us->blendEq = q;
+ switch (modeA) {
+        case GL_FUNC_ADD:
+             q = GR_BLEND_OP_ADD;
+             break;
+        case GL_FUNC_SUBTRACT:
+             q = GR_BLEND_OP_SUB;
+             break;
+        case GL_FUNC_REVERSE_SUBTRACT:
+             q = GR_BLEND_OP_REVSUB;
+             break;
+        default:
+             q = us->blendEqAlpha;
+ }
+ if (q != us->blendEqAlpha) {
+    us->blendEqAlpha = q;
     fxMesa->new_state |= FX_NEW_BLEND;
  }
 }
@@ -1562,9 +1588,9 @@ fxSetupBlend(GLcontext * ctx)
  if (fxMesa->HavePixExt) {
     if (us->blendEnabled) {
        fxMesa->Glide.grAlphaBlendFunctionExt(us->blendSrcFuncRGB, us->blendDstFuncRGB,
-                                             us->blendEq,
+                                             us->blendEqRGB,
                                              us->blendSrcFuncAlpha, us->blendDstFuncAlpha,
-                                             us->blendEq);
+                                             us->blendEqAlpha);
     } else {
        fxMesa->Glide.grAlphaBlendFunctionExt(GR_BLEND_ONE, GR_BLEND_ZERO,
                                              GR_BLEND_OP_ADD,
@@ -1743,7 +1769,7 @@ fxDDStencilOp (GLcontext *ctx, GLenum sfail, GLenum zfail, GLenum zpass)
    }
 }
 
-static void
+void
 fxSetupStencil (GLcontext * ctx)
 {
    fxMesaContext fxMesa = FX_CONTEXT(ctx);
@@ -1784,15 +1810,15 @@ fxSetupColorMask(GLcontext * ctx)
 {
    fxMesaContext fxMesa = FX_CONTEXT(ctx);
 
-   if (fxMesa->colDepth != 16) {
-      /* 32bpp mode or 15bpp mode */
+   if (fxMesa->colDepth == 32) {
+      /* 32bpp mode */
       fxMesa->Glide.grColorMaskExt(ctx->Color.ColorMask[RCOMP],
                                    ctx->Color.ColorMask[GCOMP],
                                    ctx->Color.ColorMask[BCOMP],
                                    ctx->Color.ColorMask[ACOMP] && fxMesa->haveHwAlpha);
    }
    else {
-      /* 16 bpp mode */
+      /* 15/16 bpp mode */
       grColorMask(ctx->Color.ColorMask[RCOMP] |
                   ctx->Color.ColorMask[GCOMP] |
                   ctx->Color.ColorMask[BCOMP],
@@ -1833,6 +1859,14 @@ fxSetupFog(GLcontext * ctx)
         case GL_LINEAR:
            guFogGenerateLinear(fxMesa->fogTable, ctx->Fog.Start,
                                ctx->Fog.End);
+           if (fxMesa->fogTable[0] > 63) {
+              /* [dBorca] Hack alert:
+               * As per Glide3 Programming Guide:
+               * The difference between consecutive fog values
+               * must be less than 64.
+               */
+              fxMesa->fogTable[0] = 63;
+           }
            break;
         case GL_EXP:
            guFogGenerateExp(fxMesa->fogTable, ctx->Fog.Density);
@@ -1850,7 +1884,15 @@ fxSetupFog(GLcontext * ctx)
       }
 
       grFogTable(fxMesa->fogTable);
-      grFogMode(GR_FOG_WITH_TABLE_ON_Q);
+      if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT) {
+         grVertexLayout(GR_PARAM_FOG_EXT, GR_VERTEX_FOG_OFFSET << 2,
+                                          GR_PARAM_ENABLE);
+         grFogMode(GR_FOG_WITH_TABLE_ON_FOGCOORD_EXT);
+      } else {
+         grVertexLayout(GR_PARAM_FOG_EXT, GR_VERTEX_FOG_OFFSET << 2,
+                                          GR_PARAM_DISABLE);
+         grFogMode(GR_FOG_WITH_TABLE_ON_Q);
+      }
    }
    else {
       grFogMode(GR_FOG_DISABLE);
@@ -1861,6 +1903,25 @@ void
 fxDDFogfv(GLcontext * ctx, GLenum pname, const GLfloat * params)
 {
    FX_CONTEXT(ctx)->new_state |= FX_NEW_FOG;
+   switch (pname) {
+      case GL_FOG_COORDINATE_SOURCE_EXT: {
+         GLenum p = (GLenum)*params;
+         if (p == GL_FOG_COORDINATE_EXT) {
+            _swrast_allow_vertex_fog(ctx, GL_TRUE);
+            _swrast_allow_pixel_fog(ctx, GL_FALSE);
+            _tnl_allow_vertex_fog( ctx, GL_TRUE);
+            _tnl_allow_pixel_fog( ctx, GL_FALSE);
+         } else {
+            _swrast_allow_vertex_fog(ctx, GL_FALSE);
+            _swrast_allow_pixel_fog(ctx, GL_TRUE);
+            _tnl_allow_vertex_fog( ctx, GL_FALSE);
+            _tnl_allow_pixel_fog( ctx, GL_TRUE);
+         }
+         break;
+      }
+      default:
+         ;
+   }
 }
 
 /************************************************************************/
@@ -2038,6 +2099,7 @@ fxDDEnable(GLcontext * ctx, GLenum cap, GLboolean state)
    case GL_LINE_STIPPLE:
    case GL_POINT_SMOOTH:
    case GL_POLYGON_SMOOTH:
+   case GL_TEXTURE_1D:
    case GL_TEXTURE_2D:
       fxMesa->new_state |= FX_NEW_TEXTURING;
       break;