Merge branch 'gallium-polygon-stipple'
[mesa.git] / src / mesa / main / texenv.c
index e072cea136ecb924357b0619159dd5ba28dc248a..c0d0f3779b2b07851294d5e739e37659836e86dd 100644 (file)
@@ -1,8 +1,9 @@
 /*
  * Mesa 3-D graphics library
- * Version:  7.1
+ * Version:  7.5
  *
  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009  VMware, Inc.  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"),
 #include "main/context.h"
 #include "main/enums.h"
 #include "main/macros.h"
+#include "main/mtypes.h"
+#include "main/state.h"
 #include "main/texenv.h"
-#include "math/m_xform.h"
+#include "main/texstate.h"
+
+
+#define TE_ERROR(errCode, msg, value)                          \
+   _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
+
+
+/** Set texture env mode */
+static void
+set_env_mode(struct gl_context *ctx,
+             struct gl_texture_unit *texUnit,
+             GLenum mode)
+{
+   GLboolean legal;
+
+   if (texUnit->EnvMode == mode)
+      return;
+
+   switch (mode) {
+   case GL_MODULATE:
+   case GL_BLEND:
+   case GL_DECAL:
+   case GL_REPLACE:
+      legal = GL_TRUE;
+      break;
+   case GL_REPLACE_EXT:
+      mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
+      legal = GL_TRUE;
+      break;
+   case GL_ADD:
+      legal = ctx->Extensions.EXT_texture_env_add;
+      break;
+   case GL_COMBINE:
+      legal = (ctx->Extensions.EXT_texture_env_combine ||
+               ctx->Extensions.ARB_texture_env_combine);
+      break;
+   case GL_COMBINE4_NV:
+      legal = ctx->Extensions.NV_texture_env_combine4;
+      break;
+   default:
+      legal = GL_FALSE;
+   }
+
+   if (legal) {
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      texUnit->EnvMode = mode;
+   }
+   else {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
+   }
+}
+
+
+static void
+set_env_color(struct gl_context *ctx,
+              struct gl_texture_unit *texUnit,
+              const GLfloat *color)
+{
+   if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
+      return;
+   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+   COPY_4FV(texUnit->EnvColorUnclamped, color);
+   texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
+   texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
+   texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
+   texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
+}
+
+
+/** Set an RGB or A combiner mode/function */
+static void
+set_combiner_mode(struct gl_context *ctx,
+                  struct gl_texture_unit *texUnit,
+                  GLenum pname, GLenum mode)
+{
+   GLboolean legal;
+
+   if (!ctx->Extensions.EXT_texture_env_combine &&
+       !ctx->Extensions.ARB_texture_env_combine) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+      return;
+   }
+
+   switch (mode) {
+   case GL_REPLACE:
+   case GL_MODULATE:
+   case GL_ADD:
+   case GL_ADD_SIGNED:
+   case GL_INTERPOLATE:
+      legal = GL_TRUE;
+      break;
+   case GL_SUBTRACT:
+      legal = ctx->Extensions.ARB_texture_env_combine;
+      break;
+   case GL_DOT3_RGB_EXT:
+   case GL_DOT3_RGBA_EXT:
+      legal = (ctx->Extensions.EXT_texture_env_dot3 &&
+               pname == GL_COMBINE_RGB);
+      break;
+   case GL_DOT3_RGB:
+   case GL_DOT3_RGBA:
+      legal = (ctx->Extensions.ARB_texture_env_dot3 &&
+               pname == GL_COMBINE_RGB);
+      break;
+   case GL_MODULATE_ADD_ATI:
+   case GL_MODULATE_SIGNED_ADD_ATI:
+   case GL_MODULATE_SUBTRACT_ATI:
+      legal = ctx->Extensions.ATI_texture_env_combine3;
+      break;
+   case GL_BUMP_ENVMAP_ATI:
+      legal = (ctx->Extensions.ATI_envmap_bumpmap &&
+               pname == GL_COMBINE_RGB);
+      break;
+   default:
+      legal = GL_FALSE;
+   }
+
+   if (!legal) {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
+      return;
+   }
+
+   switch (pname) {
+   case GL_COMBINE_RGB:
+      if (texUnit->Combine.ModeRGB == mode)
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      texUnit->Combine.ModeRGB = mode;
+      break;
+
+   case GL_COMBINE_ALPHA:
+      if (texUnit->Combine.ModeA == mode)
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      texUnit->Combine.ModeA = mode;
+      break;
+   default:
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+   }
+}
+
+
+
+/** Set an RGB or A combiner source term */
+static void
+set_combiner_source(struct gl_context *ctx,
+                    struct gl_texture_unit *texUnit,
+                    GLenum pname, GLenum param)
+{
+   GLuint term;
+   GLboolean alpha, legal;
+
+   if (!ctx->Extensions.EXT_texture_env_combine &&
+       !ctx->Extensions.ARB_texture_env_combine) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+      return;
+   }
+
+   /*
+    * Translate pname to (term, alpha).
+    *
+    * The enums were given sequential values for a reason.
+    */
+   switch (pname) {
+   case GL_SOURCE0_RGB:
+   case GL_SOURCE1_RGB:
+   case GL_SOURCE2_RGB:
+   case GL_SOURCE3_RGB_NV:
+      term = pname - GL_SOURCE0_RGB;
+      alpha = GL_FALSE;
+      break;
+   case GL_SOURCE0_ALPHA:
+   case GL_SOURCE1_ALPHA:
+   case GL_SOURCE2_ALPHA:
+   case GL_SOURCE3_ALPHA_NV:
+      term = pname - GL_SOURCE0_ALPHA;
+      alpha = GL_TRUE;
+      break;
+   default:
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+      return;
+   }
+
+   if ((term == 3) && !ctx->Extensions.NV_texture_env_combine4) {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+      return;
+   }
+
+   assert(term < MAX_COMBINER_TERMS);
+
+   /*
+    * Error-check param (the source term)
+    */
+   switch (param) {
+   case GL_TEXTURE:
+   case GL_CONSTANT:
+   case GL_PRIMARY_COLOR:
+   case GL_PREVIOUS:
+      legal = GL_TRUE;
+      break;
+   case GL_TEXTURE0:
+   case GL_TEXTURE1:
+   case GL_TEXTURE2:
+   case GL_TEXTURE3:
+   case GL_TEXTURE4:
+   case GL_TEXTURE5:
+   case GL_TEXTURE6:
+   case GL_TEXTURE7:
+      legal = (ctx->Extensions.ARB_texture_env_crossbar &&
+               param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
+      break;
+   case GL_ZERO:
+      legal = (ctx->Extensions.ATI_texture_env_combine3 ||
+               ctx->Extensions.NV_texture_env_combine4);
+      break;
+   case GL_ONE:
+      legal = ctx->Extensions.ATI_texture_env_combine3;
+      break;
+   default:
+      legal = GL_FALSE;
+   }
+
+   if (!legal) {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
+      return;
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+   if (alpha)
+      texUnit->Combine.SourceA[term] = param;
+   else
+      texUnit->Combine.SourceRGB[term] = param;
+}
+
+
+/** Set an RGB or A combiner operand term */
+static void
+set_combiner_operand(struct gl_context *ctx,
+                     struct gl_texture_unit *texUnit,
+                     GLenum pname, GLenum param)
+{
+   GLuint term;
+   GLboolean alpha, legal;
+
+   if (!ctx->Extensions.EXT_texture_env_combine &&
+       !ctx->Extensions.ARB_texture_env_combine) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+      return;
+   }
+
+   /* The enums were given sequential values for a reason.
+    */
+   switch (pname) {
+   case GL_OPERAND0_RGB:
+   case GL_OPERAND1_RGB:
+   case GL_OPERAND2_RGB:
+   case GL_OPERAND3_RGB_NV:
+      term = pname - GL_OPERAND0_RGB;
+      alpha = GL_FALSE;
+      break;
+   case GL_OPERAND0_ALPHA:
+   case GL_OPERAND1_ALPHA:
+   case GL_OPERAND2_ALPHA:
+   case GL_OPERAND3_ALPHA_NV:
+      term = pname - GL_OPERAND0_ALPHA;
+      alpha = GL_TRUE;
+      break;
+   default:
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+      return;
+   }
+
+   if ((term == 3) && !ctx->Extensions.NV_texture_env_combine4) {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+      return;
+   }
+
+   assert(term < MAX_COMBINER_TERMS);
+
+   /*
+    * Error-check param (the source operand)
+    */
+   switch (param) {
+   case GL_SRC_COLOR:
+   case GL_ONE_MINUS_SRC_COLOR:
+      /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
+       * version.  In the ARB and NV versions they can be used for any RGB
+       * operand.
+       */
+      legal = !alpha
+        && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
+            || ctx->Extensions.NV_texture_env_combine4);
+      break;
+   case GL_ONE_MINUS_SRC_ALPHA:
+      /* GL_ONE_MINUS_SRC_ALPHA can only be used with
+       * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version.  In the ARB and NV
+       * versions it can be used for any operand.
+       */
+      legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
+        || ctx->Extensions.NV_texture_env_combine4;
+      break;
+   case GL_SRC_ALPHA:
+      legal = GL_TRUE;
+      break;
+   default:
+      legal = GL_FALSE;
+   }
+
+   if (!legal) {
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
+      return;
+   }
+
+   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+
+   if (alpha)
+      texUnit->Combine.OperandA[term] = param;
+   else
+      texUnit->Combine.OperandRGB[term] = param;
+}
+
+
+static void
+set_combiner_scale(struct gl_context *ctx,
+                   struct gl_texture_unit *texUnit,
+                   GLenum pname, GLfloat scale)
+{
+   GLuint shift;
+
+   if (!ctx->Extensions.EXT_texture_env_combine &&
+       !ctx->Extensions.ARB_texture_env_combine) {
+      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
+      return;
+   }
+
+   if (scale == 1.0F) {
+      shift = 0;
+   }
+   else if (scale == 2.0F) {
+      shift = 1;
+   }
+   else if (scale == 4.0F) {
+      shift = 2;
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_VALUE,
+                   "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
+      return;
+   }
+
+   switch (pname) {
+   case GL_RGB_SCALE:
+      if (texUnit->Combine.ScaleShiftRGB == shift)
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      texUnit->Combine.ScaleShiftRGB = shift;
+      break;
+   case GL_ALPHA_SCALE:
+      if (texUnit->Combine.ScaleShiftA == shift)
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      texUnit->Combine.ScaleShiftA = shift;
+      break;
+   default:
+      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+   }
+}
 
 
 
 void GLAPIENTRY
 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
 {
+   const GLint iparam0 = (GLint) param[0];
+   struct gl_texture_unit *texUnit;
    GLuint maxUnit;
+
    GET_CURRENT_CONTEXT(ctx);
-   struct gl_texture_unit *texUnit;
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
-      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    if (ctx->Texture.CurrentUnit >= maxUnit) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
       return;
    }
 
-   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
-
-#define TE_ERROR(errCode, msg, value)                          \
-   _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
+   texUnit = _mesa_get_current_tex_unit(ctx);
 
    if (target == GL_TEXTURE_ENV) {
       switch (pname) {
       case GL_TEXTURE_ENV_MODE:
-         {
-            GLenum mode = (GLenum) (GLint) *param;
-            if (mode == GL_REPLACE_EXT)
-               mode = GL_REPLACE;
-           if (texUnit->EnvMode == mode)
-              return;
-            if (mode == GL_MODULATE ||
-                mode == GL_BLEND ||
-                mode == GL_DECAL ||
-                mode == GL_REPLACE ||
-                (mode == GL_ADD && ctx->Extensions.EXT_texture_env_add) ||
-                (mode == GL_COMBINE &&
-                 (ctx->Extensions.EXT_texture_env_combine ||
-                  ctx->Extensions.ARB_texture_env_combine))) {
-               /* legal */
-               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-               texUnit->EnvMode = mode;
-            }
-            else {
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-               return;
-            }
-         }
+         set_env_mode(ctx, texUnit, (GLenum) iparam0);
          break;
       case GL_TEXTURE_ENV_COLOR:
-         {
-            GLfloat tmp[4];
-            tmp[0] = CLAMP( param[0], 0.0F, 1.0F );
-            tmp[1] = CLAMP( param[1], 0.0F, 1.0F );
-            tmp[2] = CLAMP( param[2], 0.0F, 1.0F );
-            tmp[3] = CLAMP( param[3], 0.0F, 1.0F );
-            if (TEST_EQ_4V(tmp, texUnit->EnvColor))
-               return;
-            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-            COPY_4FV(texUnit->EnvColor, tmp);
-         }
+         set_env_color(ctx, texUnit, param);
          break;
       case GL_COMBINE_RGB:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum mode = (GLenum) (GLint) *param;
-           if (texUnit->Combine.ModeRGB == mode)
-              return;
-           switch (mode) {
-           case GL_REPLACE:
-           case GL_MODULATE:
-           case GL_ADD:
-           case GL_ADD_SIGNED:
-           case GL_INTERPOLATE:
-               /* OK */
-              break;
-            case GL_SUBTRACT:
-               if (!ctx->Extensions.ARB_texture_env_combine) {
-                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                  return;
-               }
-               break;
-           case GL_DOT3_RGB_EXT:
-           case GL_DOT3_RGBA_EXT:
-              if (!ctx->Extensions.EXT_texture_env_dot3) {
-                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                 return;
-              }
-              break;
-           case GL_DOT3_RGB:
-           case GL_DOT3_RGBA:
-              if (!ctx->Extensions.ARB_texture_env_dot3) {
-                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                 return;
-              }
-              break;
-           case GL_MODULATE_ADD_ATI:
-           case GL_MODULATE_SIGNED_ADD_ATI:
-           case GL_MODULATE_SUBTRACT_ATI:
-              if (!ctx->Extensions.ATI_texture_env_combine3) {
-                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                 return;
-              }
-              break;
-           default:
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-              return;
-           }
-           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->Combine.ModeRGB = mode;
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
-         break;
       case GL_COMBINE_ALPHA:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum mode = (GLenum) (GLint) *param;
-           if (texUnit->Combine.ModeA == mode)
-              return;
-            switch (mode) {
-           case GL_REPLACE:
-           case GL_MODULATE:
-           case GL_ADD:
-           case GL_ADD_SIGNED:
-           case GL_INTERPOLATE:
-              /* OK */
-              break;
-           case GL_SUBTRACT:
-              if (!ctx->Extensions.ARB_texture_env_combine) {
-                 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                 return;
-              }
-              break;
-           case GL_MODULATE_ADD_ATI:
-           case GL_MODULATE_SIGNED_ADD_ATI:
-           case GL_MODULATE_SUBTRACT_ATI:
-              if (!ctx->Extensions.ATI_texture_env_combine3) {
-                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-                 return;
-              }
-              break;
-           default:
-              TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
-              return;
-           }
-           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->Combine.ModeA = mode;
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
+         set_combiner_mode(ctx, texUnit, pname, (GLenum) iparam0);
         break;
       case GL_SOURCE0_RGB:
       case GL_SOURCE1_RGB:
       case GL_SOURCE2_RGB:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-            ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum source = (GLenum) (GLint) *param;
-           const GLuint s = pname - GL_SOURCE0_RGB;
-           if (texUnit->Combine.SourceRGB[s] == source)
-              return;
-            if (source == GL_TEXTURE ||
-                source == GL_CONSTANT ||
-                source == GL_PRIMARY_COLOR ||
-                source == GL_PREVIOUS ||
-                (ctx->Extensions.ARB_texture_env_crossbar &&
-                 source >= GL_TEXTURE0 &&
-                 source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) ||
-                (ctx->Extensions.ATI_texture_env_combine3 &&
-                 (source == GL_ZERO || source == GL_ONE))) {
-               /* legal */
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.SourceRGB[s] = source;
-            }
-            else {
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
-        break;
+      case GL_SOURCE3_RGB_NV:
       case GL_SOURCE0_ALPHA:
       case GL_SOURCE1_ALPHA:
       case GL_SOURCE2_ALPHA:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum source = (GLenum) (GLint) *param;
-           const GLuint s = pname - GL_SOURCE0_ALPHA;
-           if (texUnit->Combine.SourceA[s] == source)
-              return;
-            if (source == GL_TEXTURE ||
-                source == GL_CONSTANT ||
-                source == GL_PRIMARY_COLOR ||
-                source == GL_PREVIOUS ||
-                (ctx->Extensions.ARB_texture_env_crossbar &&
-                 source >= GL_TEXTURE0 &&
-                 source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) ||
-               (ctx->Extensions.ATI_texture_env_combine3 &&
-                 (source == GL_ZERO || source == GL_ONE))) {
-               /* legal */
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.SourceA[s] = source;
-            }
-            else {
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
+      case GL_SOURCE3_ALPHA_NV:
+         set_combiner_source(ctx, texUnit, pname, (GLenum) iparam0);
         break;
       case GL_OPERAND0_RGB:
       case GL_OPERAND1_RGB:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-            ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           const GLuint s = pname - GL_OPERAND0_RGB;
-           if (texUnit->Combine.OperandRGB[s] == operand)
-              return;
-           switch (operand) {
-           case GL_SRC_COLOR:
-           case GL_ONE_MINUS_SRC_COLOR:
-           case GL_SRC_ALPHA:
-           case GL_ONE_MINUS_SRC_ALPHA:
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.OperandRGB[s] = operand;
-              break;
-           default:
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
-        break;
+      case GL_OPERAND2_RGB:
+      case GL_OPERAND3_RGB_NV:
       case GL_OPERAND0_ALPHA:
       case GL_OPERAND1_ALPHA:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           if (texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] == operand)
-              return;
-           switch (operand) {
-           case GL_SRC_ALPHA:
-           case GL_ONE_MINUS_SRC_ALPHA:
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] = operand;
-              break;
-           default:
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
-        break;
-      case GL_OPERAND2_RGB:
-        if (ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           if (texUnit->Combine.OperandRGB[2] == operand)
-              return;
-           switch (operand) {
-           case GL_SRC_COLOR:           /* ARB combine only */
-           case GL_ONE_MINUS_SRC_COLOR: /* ARB combine only */
-           case GL_SRC_ALPHA:
-           case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.OperandRGB[2] = operand;
-               break;
-           default:
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else if (ctx->Extensions.EXT_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           if (texUnit->Combine.OperandRGB[2] == operand)
-              return;
-           /* operand must be GL_SRC_ALPHA which is the initial value - thus
-              don't need to actually compare the operand to the possible value */
-           else {
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
-        break;
       case GL_OPERAND2_ALPHA:
-        if (ctx->Extensions.ARB_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           if (texUnit->Combine.OperandA[2] == operand)
-              return;
-           switch (operand) {
-           case GL_SRC_ALPHA:
-           case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */
-              FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-              texUnit->Combine.OperandA[2] = operand;
-              break;
-           default:
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else if (ctx->Extensions.EXT_texture_env_combine) {
-           const GLenum operand = (GLenum) (GLint) *param;
-           if (texUnit->Combine.OperandA[2] == operand)
-              return;
-           /* operand must be GL_SRC_ALPHA which is the initial value - thus
-              don't need to actually compare the operand to the possible value */
-           else {
-               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
-              return;
-           }
-        }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
-        }
+      case GL_OPERAND3_ALPHA_NV:
+         set_combiner_operand(ctx, texUnit, pname, (GLenum) iparam0);
         break;
       case GL_RGB_SCALE:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           GLuint newshift;
-           if (*param == 1.0) {
-              newshift = 0;
-           }
-           else if (*param == 2.0) {
-              newshift = 1;
-           }
-           else if (*param == 4.0) {
-              newshift = 2;
-           }
-           else {
-              _mesa_error( ctx, GL_INVALID_VALUE,
-                            "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
-              return;
-           }
-           if (texUnit->Combine.ScaleShiftRGB == newshift)
-              return;
-           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->Combine.ScaleShiftRGB = newshift;
+      case GL_ALPHA_SCALE:
+         set_combiner_scale(ctx, texUnit, pname, param[0]);
+        break;
+      case GL_BUMP_TARGET_ATI:
+         if (!ctx->Extensions.ATI_envmap_bumpmap) {
+           _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
+           return;
         }
-        else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
+        if ((iparam0 < GL_TEXTURE0) ||
+             (iparam0 > GL_TEXTURE31)) {
+           /* spec doesn't say this but it seems logical */
+           _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(param=0x%x)", iparam0);
            return;
         }
-        break;
-      case GL_ALPHA_SCALE:
-        if (ctx->Extensions.EXT_texture_env_combine ||
-             ctx->Extensions.ARB_texture_env_combine) {
-           GLuint newshift;
-           if (*param == 1.0) {
-              newshift = 0;
-           }
-           else if (*param == 2.0) {
-              newshift = 1;
-           }
-           else if (*param == 4.0) {
-              newshift = 2;
-           }
-           else {
-              _mesa_error( ctx, GL_INVALID_VALUE,
-                            "glTexEnv(GL_ALPHA_SCALE not 1, 2 or 4)" );
-              return;
-           }
-           if (texUnit->Combine.ScaleShiftA == newshift)
-              return;
-           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
-           texUnit->Combine.ScaleShiftA = newshift;
+        if (!((1 << (iparam0 - GL_TEXTURE0)) & ctx->Const.SupportedBumpUnits)) {
+           _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
+           return;
         }
         else {
-            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
-           return;
+           FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+           texUnit->BumpTarget = iparam0;
         }
         break;
       default:
@@ -457,19 +513,18 @@ _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
         return;
       }
       if (pname == GL_COORD_REPLACE_NV) {
-         const GLenum value = (GLenum) param[0];
-         if (value == GL_TRUE || value == GL_FALSE) {
+         if (iparam0 == GL_TRUE || iparam0 == GL_FALSE) {
             /* It's kind of weird to set point state via glTexEnv,
              * but that's what the spec calls for.
              */
-            const GLboolean state = (GLboolean) value;
+            const GLboolean state = (GLboolean) iparam0;
             if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state)
                return;
             FLUSH_VERTICES(ctx, _NEW_POINT);
             ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state;
          }
          else {
-            _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", value);
+            _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
             return;
          }
       }
@@ -488,7 +543,7 @@ _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
                   _mesa_lookup_enum_by_nr(target),
                   _mesa_lookup_enum_by_nr(pname),
                   *param,
-                  _mesa_lookup_enum_by_nr((GLenum) (GLint) *param));
+                  _mesa_lookup_enum_by_nr((GLenum) iparam0));
 
    /* Tell device driver about the new texture environment */
    if (ctx->Driver.TexEnv) {
@@ -500,7 +555,10 @@ _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
 void GLAPIENTRY
 _mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
 {
-   _mesa_TexEnvfv( target, pname, &param );
+   GLfloat p[4];
+   p[0] = param;
+   p[1] = p[2] = p[3] = 0.0;
+   _mesa_TexEnvfv( target, pname, p );
 }
 
 
@@ -533,6 +591,154 @@ _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
 }
 
 
+
+/**
+ * Helper for glGetTexEnvi/f()
+ * \return  value of queried pname or -1 if error.
+ */
+static GLint
+get_texenvi(struct gl_context *ctx, const struct gl_texture_unit *texUnit,
+            GLenum pname)
+{
+   switch (pname) {
+   case GL_TEXTURE_ENV_MODE:
+      return texUnit->EnvMode;
+      break;
+   case GL_COMBINE_RGB:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         return texUnit->Combine.ModeRGB;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_COMBINE_ALPHA:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         return texUnit->Combine.ModeA;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_SOURCE0_RGB:
+   case GL_SOURCE1_RGB:
+   case GL_SOURCE2_RGB:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
+         return texUnit->Combine.SourceRGB[rgb_idx];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_SOURCE3_RGB_NV:
+      if (ctx->Extensions.NV_texture_env_combine4) {
+         return texUnit->Combine.SourceRGB[3];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_SOURCE0_ALPHA:
+   case GL_SOURCE1_ALPHA:
+   case GL_SOURCE2_ALPHA:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
+         return texUnit->Combine.SourceA[alpha_idx];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_SOURCE3_ALPHA_NV:
+      if (ctx->Extensions.NV_texture_env_combine4) {
+         return texUnit->Combine.SourceA[3];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_OPERAND0_RGB:
+   case GL_OPERAND1_RGB:
+   case GL_OPERAND2_RGB:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         const unsigned op_rgb = pname - GL_OPERAND0_RGB;
+         return texUnit->Combine.OperandRGB[op_rgb];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_OPERAND3_RGB_NV:
+      if (ctx->Extensions.NV_texture_env_combine4) {
+         return texUnit->Combine.OperandRGB[3];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_OPERAND0_ALPHA:
+   case GL_OPERAND1_ALPHA:
+   case GL_OPERAND2_ALPHA:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
+         return texUnit->Combine.OperandA[op_alpha];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_OPERAND3_ALPHA_NV:
+      if (ctx->Extensions.NV_texture_env_combine4) {
+         return texUnit->Combine.OperandA[3];
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_RGB_SCALE:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         return 1 << texUnit->Combine.ScaleShiftRGB;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_ALPHA_SCALE:
+      if (ctx->Extensions.EXT_texture_env_combine ||
+          ctx->Extensions.ARB_texture_env_combine) {
+         return 1 << texUnit->Combine.ScaleShiftA;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+   case GL_BUMP_TARGET_ATI:
+      /* spec doesn't say so, but I think this should be queryable */
+      if (ctx->Extensions.ATI_envmap_bumpmap) {
+         return texUnit->BumpTarget;
+      }
+      else {
+         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
+      }
+      break;
+
+   default:
+      ;
+   }
+
+   return -1; /* error */
+}
+
+
+
 void GLAPIENTRY
 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
 {
@@ -542,120 +748,28 @@ _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
-      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    if (ctx->Texture.CurrentUnit >= maxUnit) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
       return;
    }
 
-   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   texUnit = _mesa_get_current_tex_unit(ctx);
 
    if (target == GL_TEXTURE_ENV) {
-      switch (pname) {
-         case GL_TEXTURE_ENV_MODE:
-            *params = ENUM_TO_FLOAT(texUnit->EnvMode);
-            break;
-         case GL_TEXTURE_ENV_COLOR:
+      if (pname == GL_TEXTURE_ENV_COLOR) {
+         if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP))
+            _mesa_update_state(ctx);
+         if(ctx->Color._ClampFragmentColor)
             COPY_4FV( params, texUnit->EnvColor );
-            break;
-         case GL_COMBINE_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               *params = (GLfloat) texUnit->Combine.ModeRGB;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_COMBINE_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               *params = (GLfloat) texUnit->Combine.ModeA;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_SOURCE0_RGB:
-         case GL_SOURCE1_RGB:
-         case GL_SOURCE2_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
-               *params = (GLfloat) texUnit->Combine.SourceRGB[rgb_idx];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_SOURCE0_ALPHA:
-         case GL_SOURCE1_ALPHA:
-         case GL_SOURCE2_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
-               *params = (GLfloat) texUnit->Combine.SourceA[alpha_idx];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_OPERAND0_RGB:
-         case GL_OPERAND1_RGB:
-         case GL_OPERAND2_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned op_rgb = pname - GL_OPERAND0_RGB;
-               *params = (GLfloat) texUnit->Combine.OperandRGB[op_rgb];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_OPERAND0_ALPHA:
-         case GL_OPERAND1_ALPHA:
-         case GL_OPERAND2_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
-               *params = (GLfloat) texUnit->Combine.OperandA[op_alpha];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-            }
-            break;
-         case GL_RGB_SCALE:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               if (texUnit->Combine.ScaleShiftRGB == 0)
-                  *params = 1.0;
-               else if (texUnit->Combine.ScaleShiftRGB == 1)
-                  *params = 2.0;
-               else
-                  *params = 4.0;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-               return;
-            }
-            break;
-         case GL_ALPHA_SCALE:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               if (texUnit->Combine.ScaleShiftA == 0)
-                  *params = 1.0;
-               else if (texUnit->Combine.ScaleShiftA == 1)
-                  *params = 2.0;
-               else
-                  *params = 4.0;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
-               return;
-            }
-            break;
-         default:
-            _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname=0x%x)", pname);
+         else
+            COPY_4FV( params, texUnit->EnvColorUnclamped );
+      }
+      else {
+         GLint val = get_texenvi(ctx, texUnit, pname);
+         if (val >= 0) {
+            *params = (GLfloat) val;
+         }
       }
    }
    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
@@ -703,124 +817,26 @@ _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
    ASSERT_OUTSIDE_BEGIN_END(ctx);
 
    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
-      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
+      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    if (ctx->Texture.CurrentUnit >= maxUnit) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
       return;
    }
 
-   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
+   texUnit = _mesa_get_current_tex_unit(ctx);
 
    if (target == GL_TEXTURE_ENV) {
-      switch (pname) {
-         case GL_TEXTURE_ENV_MODE:
-            *params = (GLint) texUnit->EnvMode;
-            break;
-         case GL_TEXTURE_ENV_COLOR:
-            params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
-            params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
-            params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
-            params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
-            break;
-         case GL_COMBINE_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               *params = (GLint) texUnit->Combine.ModeRGB;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_COMBINE_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               *params = (GLint) texUnit->Combine.ModeA;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_SOURCE0_RGB:
-         case GL_SOURCE1_RGB:
-         case GL_SOURCE2_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
-               *params = (GLint) texUnit->Combine.SourceRGB[rgb_idx];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_SOURCE0_ALPHA:
-         case GL_SOURCE1_ALPHA:
-         case GL_SOURCE2_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
-               *params = (GLint) texUnit->Combine.SourceA[alpha_idx];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_OPERAND0_RGB:
-         case GL_OPERAND1_RGB:
-         case GL_OPERAND2_RGB:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned op_rgb = pname - GL_OPERAND0_RGB;
-               *params = (GLint) texUnit->Combine.OperandRGB[op_rgb];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_OPERAND0_ALPHA:
-         case GL_OPERAND1_ALPHA:
-         case GL_OPERAND2_ALPHA:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-              const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
-               *params = (GLint) texUnit->Combine.OperandA[op_alpha];
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-            }
-            break;
-         case GL_RGB_SCALE:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               if (texUnit->Combine.ScaleShiftRGB == 0)
-                  *params = 1;
-               else if (texUnit->Combine.ScaleShiftRGB == 1)
-                  *params = 2;
-               else
-                  *params = 4;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-               return;
-            }
-            break;
-         case GL_ALPHA_SCALE:
-            if (ctx->Extensions.EXT_texture_env_combine ||
-                ctx->Extensions.ARB_texture_env_combine) {
-               if (texUnit->Combine.ScaleShiftA == 0)
-                  *params = 1;
-               else if (texUnit->Combine.ScaleShiftA == 1)
-                  *params = 2;
-               else
-                  *params = 4;
-            }
-            else {
-               _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)");
-               return;
-            }
-            break;
-         default:
-            _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname=0x%x)",
-                        pname);
+      if (pname == GL_TEXTURE_ENV_COLOR) {
+         params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
+         params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
+         params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
+         params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
+      }
+      else {
+         GLint val = get_texenvi(ctx, texUnit, pname);
+         if (val >= 0) {
+            *params = val;
+         }
       }
    }
    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
@@ -859,3 +875,169 @@ _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
 }
 
 
+/**
+ * Why does ATI_envmap_bumpmap require new entrypoints? Should just
+ * reuse TexEnv ones...
+ */
+void GLAPIENTRY
+_mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
+{
+   GLfloat p[4];
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ATI_envmap_bumpmap) {
+      /* This isn't an "official" error case, but let's tell the user
+       * that something's wrong.
+       */
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
+      return;
+   }
+
+   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      /* hope that conversion is correct here */
+      p[0] = INT_TO_FLOAT( param[0] );
+      p[1] = INT_TO_FLOAT( param[1] );
+      p[2] = INT_TO_FLOAT( param[2] );
+      p[3] = INT_TO_FLOAT( param[3] );
+   }
+   else {
+      p[0] = (GLfloat) param[0];
+      p[1] = p[2] = p[3] = 0.0F;  /* init to zero, just to be safe */
+   }
+   _mesa_TexBumpParameterfvATI( pname, p );
+}
+
+
+void GLAPIENTRY
+_mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
+{
+   struct gl_texture_unit *texUnit;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ATI_envmap_bumpmap) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
+      return;
+   }
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+
+   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      if (TEST_EQ_4V(param, texUnit->RotMatrix))
+         return;
+      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
+      COPY_4FV(texUnit->RotMatrix, param);
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
+      return;
+   }
+   /* Drivers might want to know about this, instead of dedicated function
+      just shove it into TexEnv where it really belongs anyway */
+   if (ctx->Driver.TexEnv) {
+      (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
+{
+   const struct gl_texture_unit *texUnit;
+   GLuint i;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ATI_envmap_bumpmap) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
+      return;
+   }
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+
+   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
+      /* spec leaves open to support larger matrices.
+         Don't think anyone would ever want to use it
+         (and apps almost certainly would not understand it and
+         thus fail to submit matrices correctly) so hardcode this. */
+      *param = 4;
+   }
+   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      /* hope that conversion is correct here */
+      param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
+      param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
+      param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
+      param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
+   }
+   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
+      GLint count = 0;
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            count++;
+         }
+      }
+      *param = count;
+   }
+   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            *param++ = i + GL_TEXTURE0;
+         }
+      }
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
+      return;
+   }
+}
+
+
+void GLAPIENTRY
+_mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
+{
+   const struct gl_texture_unit *texUnit;
+   GLuint i;
+   GET_CURRENT_CONTEXT(ctx);
+   ASSERT_OUTSIDE_BEGIN_END(ctx);
+
+   if (!ctx->Extensions.ATI_envmap_bumpmap) {
+      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
+      return;
+   }
+
+   texUnit = _mesa_get_current_tex_unit(ctx);
+
+   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
+      /* spec leaves open to support larger matrices.
+         Don't think anyone would ever want to use it
+         (and apps might not understand it) so hardcode this. */
+      *param = 4.0F;
+   }
+   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
+      param[0] = texUnit->RotMatrix[0];
+      param[1] = texUnit->RotMatrix[1];
+      param[2] = texUnit->RotMatrix[2];
+      param[3] = texUnit->RotMatrix[3];
+   }
+   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
+      GLint count = 0;
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            count++;
+         }
+      }
+      *param = (GLfloat) count;
+   }
+   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
+      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
+         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
+            *param++ = (GLfloat) (i + GL_TEXTURE0);
+         }
+      }
+   }
+   else {
+      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
+      return;
+   }
+}