Home | History | Annotate | Download | only in main
      1 /*
      2  * Mesa 3-D graphics library
      3  * Version:  7.5
      4  *
      5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
      6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
      7  *
      8  * Permission is hereby granted, free of charge, to any person obtaining a
      9  * copy of this software and associated documentation files (the "Software"),
     10  * to deal in the Software without restriction, including without limitation
     11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
     12  * and/or sell copies of the Software, and to permit persons to whom the
     13  * Software is furnished to do so, subject to the following conditions:
     14  *
     15  * The above copyright notice and this permission notice shall be included
     16  * in all copies or substantial portions of the Software.
     17  *
     18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
     19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
     22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     24  */
     25 
     26 /**
     27  * \file texenv.c
     28  *
     29  * glTexEnv-related functions
     30  */
     31 
     32 
     33 #include "main/glheader.h"
     34 #include "main/context.h"
     35 #include "main/enums.h"
     36 #include "main/macros.h"
     37 #include "main/mtypes.h"
     38 #include "main/state.h"
     39 #include "main/texenv.h"
     40 #include "main/texstate.h"
     41 
     42 
     43 #define TE_ERROR(errCode, msg, value)				\
     44    _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
     45 
     46 
     47 /** Set texture env mode */
     48 static void
     49 set_env_mode(struct gl_context *ctx,
     50              struct gl_texture_unit *texUnit,
     51              GLenum mode)
     52 {
     53    GLboolean legal;
     54 
     55    if (texUnit->EnvMode == mode)
     56       return;
     57 
     58    switch (mode) {
     59    case GL_MODULATE:
     60    case GL_BLEND:
     61    case GL_DECAL:
     62    case GL_REPLACE:
     63    case GL_ADD:
     64    case GL_COMBINE:
     65       legal = GL_TRUE;
     66       break;
     67    case GL_REPLACE_EXT:
     68       mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
     69       legal = GL_TRUE;
     70       break;
     71    case GL_COMBINE4_NV:
     72       legal = ctx->Extensions.NV_texture_env_combine4;
     73       break;
     74    default:
     75       legal = GL_FALSE;
     76    }
     77 
     78    if (legal) {
     79       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
     80       texUnit->EnvMode = mode;
     81    }
     82    else {
     83       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
     84    }
     85 }
     86 
     87 
     88 static void
     89 set_env_color(struct gl_context *ctx,
     90               struct gl_texture_unit *texUnit,
     91               const GLfloat *color)
     92 {
     93    if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
     94       return;
     95    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
     96    COPY_4FV(texUnit->EnvColorUnclamped, color);
     97    texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
     98    texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
     99    texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
    100    texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
    101 }
    102 
    103 
    104 /** Set an RGB or A combiner mode/function */
    105 static void
    106 set_combiner_mode(struct gl_context *ctx,
    107                   struct gl_texture_unit *texUnit,
    108                   GLenum pname, GLenum mode)
    109 {
    110    GLboolean legal;
    111 
    112    switch (mode) {
    113    case GL_REPLACE:
    114    case GL_MODULATE:
    115    case GL_ADD:
    116    case GL_ADD_SIGNED:
    117    case GL_INTERPOLATE:
    118       legal = GL_TRUE;
    119       break;
    120    case GL_SUBTRACT:
    121       legal = ctx->Extensions.ARB_texture_env_combine;
    122       break;
    123    case GL_DOT3_RGB_EXT:
    124    case GL_DOT3_RGBA_EXT:
    125       legal = (ctx->API == API_OPENGL &&
    126                ctx->Extensions.EXT_texture_env_dot3 &&
    127                pname == GL_COMBINE_RGB);
    128       break;
    129    case GL_DOT3_RGB:
    130    case GL_DOT3_RGBA:
    131       legal = (ctx->Extensions.ARB_texture_env_dot3 &&
    132                pname == GL_COMBINE_RGB);
    133       break;
    134    case GL_MODULATE_ADD_ATI:
    135    case GL_MODULATE_SIGNED_ADD_ATI:
    136    case GL_MODULATE_SUBTRACT_ATI:
    137       legal = (ctx->API == API_OPENGL &&
    138                ctx->Extensions.ATI_texture_env_combine3);
    139       break;
    140    case GL_BUMP_ENVMAP_ATI:
    141       legal = (ctx->API == API_OPENGL &&
    142                ctx->Extensions.ATI_envmap_bumpmap &&
    143                pname == GL_COMBINE_RGB);
    144       break;
    145    default:
    146       legal = GL_FALSE;
    147    }
    148 
    149    if (!legal) {
    150       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
    151       return;
    152    }
    153 
    154    switch (pname) {
    155    case GL_COMBINE_RGB:
    156       if (texUnit->Combine.ModeRGB == mode)
    157          return;
    158       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    159       texUnit->Combine.ModeRGB = mode;
    160       break;
    161 
    162    case GL_COMBINE_ALPHA:
    163       if (texUnit->Combine.ModeA == mode)
    164          return;
    165       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    166       texUnit->Combine.ModeA = mode;
    167       break;
    168    default:
    169       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    170    }
    171 }
    172 
    173 
    174 
    175 /** Set an RGB or A combiner source term */
    176 static void
    177 set_combiner_source(struct gl_context *ctx,
    178                     struct gl_texture_unit *texUnit,
    179                     GLenum pname, GLenum param)
    180 {
    181    GLuint term;
    182    GLboolean alpha, legal;
    183 
    184    /*
    185     * Translate pname to (term, alpha).
    186     *
    187     * The enums were given sequential values for a reason.
    188     */
    189    switch (pname) {
    190    case GL_SOURCE0_RGB:
    191    case GL_SOURCE1_RGB:
    192    case GL_SOURCE2_RGB:
    193    case GL_SOURCE3_RGB_NV:
    194       term = pname - GL_SOURCE0_RGB;
    195       alpha = GL_FALSE;
    196       break;
    197    case GL_SOURCE0_ALPHA:
    198    case GL_SOURCE1_ALPHA:
    199    case GL_SOURCE2_ALPHA:
    200    case GL_SOURCE3_ALPHA_NV:
    201       term = pname - GL_SOURCE0_ALPHA;
    202       alpha = GL_TRUE;
    203       break;
    204    default:
    205       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    206       return;
    207    }
    208 
    209    if ((term == 3) && (ctx->API != API_OPENGL
    210                        || !ctx->Extensions.NV_texture_env_combine4)) {
    211       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    212       return;
    213    }
    214 
    215    assert(term < MAX_COMBINER_TERMS);
    216 
    217    /*
    218     * Error-check param (the source term)
    219     */
    220    switch (param) {
    221    case GL_TEXTURE:
    222    case GL_CONSTANT:
    223    case GL_PRIMARY_COLOR:
    224    case GL_PREVIOUS:
    225       legal = GL_TRUE;
    226       break;
    227    case GL_TEXTURE0:
    228    case GL_TEXTURE1:
    229    case GL_TEXTURE2:
    230    case GL_TEXTURE3:
    231    case GL_TEXTURE4:
    232    case GL_TEXTURE5:
    233    case GL_TEXTURE6:
    234    case GL_TEXTURE7:
    235       legal = (ctx->Extensions.ARB_texture_env_crossbar &&
    236                param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
    237       break;
    238    case GL_ZERO:
    239       legal = (ctx->API == API_OPENGL &&
    240                (ctx->Extensions.ATI_texture_env_combine3 ||
    241                 ctx->Extensions.NV_texture_env_combine4));
    242       break;
    243    case GL_ONE:
    244       legal = (ctx->API == API_OPENGL &&
    245                ctx->Extensions.ATI_texture_env_combine3);
    246       break;
    247    default:
    248       legal = GL_FALSE;
    249    }
    250 
    251    if (!legal) {
    252       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
    253       return;
    254    }
    255 
    256    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    257 
    258    if (alpha)
    259       texUnit->Combine.SourceA[term] = param;
    260    else
    261       texUnit->Combine.SourceRGB[term] = param;
    262 }
    263 
    264 
    265 /** Set an RGB or A combiner operand term */
    266 static void
    267 set_combiner_operand(struct gl_context *ctx,
    268                      struct gl_texture_unit *texUnit,
    269                      GLenum pname, GLenum param)
    270 {
    271    GLuint term;
    272    GLboolean alpha, legal;
    273 
    274    /* The enums were given sequential values for a reason.
    275     */
    276    switch (pname) {
    277    case GL_OPERAND0_RGB:
    278    case GL_OPERAND1_RGB:
    279    case GL_OPERAND2_RGB:
    280    case GL_OPERAND3_RGB_NV:
    281       term = pname - GL_OPERAND0_RGB;
    282       alpha = GL_FALSE;
    283       break;
    284    case GL_OPERAND0_ALPHA:
    285    case GL_OPERAND1_ALPHA:
    286    case GL_OPERAND2_ALPHA:
    287    case GL_OPERAND3_ALPHA_NV:
    288       term = pname - GL_OPERAND0_ALPHA;
    289       alpha = GL_TRUE;
    290       break;
    291    default:
    292       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    293       return;
    294    }
    295 
    296    if ((term == 3) && (ctx->API != API_OPENGL
    297                        || !ctx->Extensions.NV_texture_env_combine4)) {
    298       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    299       return;
    300    }
    301 
    302    assert(term < MAX_COMBINER_TERMS);
    303 
    304    /*
    305     * Error-check param (the source operand)
    306     */
    307    switch (param) {
    308    case GL_SRC_COLOR:
    309    case GL_ONE_MINUS_SRC_COLOR:
    310       /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
    311        * version.  In the ARB and NV versions and OpenGL ES 1.x they can be
    312        * used for any RGB operand.
    313        */
    314       legal = !alpha
    315 	 && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
    316 	     || ctx->Extensions.NV_texture_env_combine4);
    317       break;
    318    case GL_ONE_MINUS_SRC_ALPHA:
    319       /* GL_ONE_MINUS_SRC_ALPHA can only be used with
    320        * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version.  In the ARB and NV
    321        * versions and OpenGL ES 1.x it can be used for any operand.
    322        */
    323       legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
    324 	 || ctx->Extensions.NV_texture_env_combine4;
    325       break;
    326    case GL_SRC_ALPHA:
    327       legal = GL_TRUE;
    328       break;
    329    default:
    330       legal = GL_FALSE;
    331    }
    332 
    333    if (!legal) {
    334       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
    335       return;
    336    }
    337 
    338    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    339 
    340    if (alpha)
    341       texUnit->Combine.OperandA[term] = param;
    342    else
    343       texUnit->Combine.OperandRGB[term] = param;
    344 }
    345 
    346 
    347 static void
    348 set_combiner_scale(struct gl_context *ctx,
    349                    struct gl_texture_unit *texUnit,
    350                    GLenum pname, GLfloat scale)
    351 {
    352    GLuint shift;
    353 
    354    if (scale == 1.0F) {
    355       shift = 0;
    356    }
    357    else if (scale == 2.0F) {
    358       shift = 1;
    359    }
    360    else if (scale == 4.0F) {
    361       shift = 2;
    362    }
    363    else {
    364       _mesa_error( ctx, GL_INVALID_VALUE,
    365                    "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
    366       return;
    367    }
    368 
    369    switch (pname) {
    370    case GL_RGB_SCALE:
    371       if (texUnit->Combine.ScaleShiftRGB == shift)
    372          return;
    373       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    374       texUnit->Combine.ScaleShiftRGB = shift;
    375       break;
    376    case GL_ALPHA_SCALE:
    377       if (texUnit->Combine.ScaleShiftA == shift)
    378          return;
    379       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    380       texUnit->Combine.ScaleShiftA = shift;
    381       break;
    382    default:
    383       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    384    }
    385 }
    386 
    387 
    388 
    389 void GLAPIENTRY
    390 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
    391 {
    392    const GLint iparam0 = (GLint) param[0];
    393    struct gl_texture_unit *texUnit;
    394    GLuint maxUnit;
    395 
    396    GET_CURRENT_CONTEXT(ctx);
    397    ASSERT_OUTSIDE_BEGIN_END(ctx);
    398 
    399    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
    400       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    401    if (ctx->Texture.CurrentUnit >= maxUnit) {
    402       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
    403       return;
    404    }
    405 
    406    texUnit = _mesa_get_current_tex_unit(ctx);
    407 
    408    if (target == GL_TEXTURE_ENV) {
    409       switch (pname) {
    410       case GL_TEXTURE_ENV_MODE:
    411          set_env_mode(ctx, texUnit, (GLenum) iparam0);
    412          break;
    413       case GL_TEXTURE_ENV_COLOR:
    414          set_env_color(ctx, texUnit, param);
    415          break;
    416       case GL_COMBINE_RGB:
    417       case GL_COMBINE_ALPHA:
    418          set_combiner_mode(ctx, texUnit, pname, (GLenum) iparam0);
    419 	 break;
    420       case GL_SOURCE0_RGB:
    421       case GL_SOURCE1_RGB:
    422       case GL_SOURCE2_RGB:
    423       case GL_SOURCE3_RGB_NV:
    424       case GL_SOURCE0_ALPHA:
    425       case GL_SOURCE1_ALPHA:
    426       case GL_SOURCE2_ALPHA:
    427       case GL_SOURCE3_ALPHA_NV:
    428          set_combiner_source(ctx, texUnit, pname, (GLenum) iparam0);
    429 	 break;
    430       case GL_OPERAND0_RGB:
    431       case GL_OPERAND1_RGB:
    432       case GL_OPERAND2_RGB:
    433       case GL_OPERAND3_RGB_NV:
    434       case GL_OPERAND0_ALPHA:
    435       case GL_OPERAND1_ALPHA:
    436       case GL_OPERAND2_ALPHA:
    437       case GL_OPERAND3_ALPHA_NV:
    438          set_combiner_operand(ctx, texUnit, pname, (GLenum) iparam0);
    439 	 break;
    440       case GL_RGB_SCALE:
    441       case GL_ALPHA_SCALE:
    442          set_combiner_scale(ctx, texUnit, pname, param[0]);
    443 	 break;
    444       case GL_BUMP_TARGET_ATI:
    445          if (ctx->API != API_OPENGL || !ctx->Extensions.ATI_envmap_bumpmap) {
    446 	    _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
    447 	    return;
    448 	 }
    449 	 if ((iparam0 < GL_TEXTURE0) ||
    450              (iparam0 > GL_TEXTURE31)) {
    451 	    /* spec doesn't say this but it seems logical */
    452 	    _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(param=0x%x)", iparam0);
    453 	    return;
    454 	 }
    455 	 if (!((1 << (iparam0 - GL_TEXTURE0)) & ctx->Const.SupportedBumpUnits)) {
    456 	    _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
    457 	    return;
    458 	 }
    459 	 else {
    460 	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    461 	    texUnit->BumpTarget = iparam0;
    462 	 }
    463 	 break;
    464       default:
    465 	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
    466 	 return;
    467       }
    468    }
    469    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
    470       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
    471 	 if (texUnit->LodBias == param[0])
    472 	    return;
    473 	 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    474          texUnit->LodBias = param[0];
    475       }
    476       else {
    477          TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
    478 	 return;
    479       }
    480    }
    481    else if (target == GL_POINT_SPRITE_NV) {
    482       /* GL_ARB_point_sprite / GL_NV_point_sprite */
    483       if (!ctx->Extensions.NV_point_sprite
    484 	  && !ctx->Extensions.ARB_point_sprite) {
    485 	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
    486 	 return;
    487       }
    488       if (pname == GL_COORD_REPLACE_NV) {
    489          if (iparam0 == GL_TRUE || iparam0 == GL_FALSE) {
    490             /* It's kind of weird to set point state via glTexEnv,
    491              * but that's what the spec calls for.
    492              */
    493             const GLboolean state = (GLboolean) iparam0;
    494             if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state)
    495                return;
    496             FLUSH_VERTICES(ctx, _NEW_POINT);
    497             ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state;
    498          }
    499          else {
    500             _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
    501             return;
    502          }
    503       }
    504       else {
    505          _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
    506          return;
    507       }
    508    }
    509    else {
    510       _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)",target );
    511       return;
    512    }
    513 
    514    if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
    515       _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n",
    516                   _mesa_lookup_enum_by_nr(target),
    517                   _mesa_lookup_enum_by_nr(pname),
    518                   *param,
    519                   _mesa_lookup_enum_by_nr((GLenum) iparam0));
    520 
    521    /* Tell device driver about the new texture environment */
    522    if (ctx->Driver.TexEnv) {
    523       (*ctx->Driver.TexEnv)( ctx, target, pname, param );
    524    }
    525 }
    526 
    527 
    528 void GLAPIENTRY
    529 _mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
    530 {
    531    GLfloat p[4];
    532    p[0] = param;
    533    p[1] = p[2] = p[3] = 0.0;
    534    _mesa_TexEnvfv( target, pname, p );
    535 }
    536 
    537 
    538 
    539 void GLAPIENTRY
    540 _mesa_TexEnvi( GLenum target, GLenum pname, GLint param )
    541 {
    542    GLfloat p[4];
    543    p[0] = (GLfloat) param;
    544    p[1] = p[2] = p[3] = 0.0;
    545    _mesa_TexEnvfv( target, pname, p );
    546 }
    547 
    548 
    549 void GLAPIENTRY
    550 _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
    551 {
    552    GLfloat p[4];
    553    if (pname == GL_TEXTURE_ENV_COLOR) {
    554       p[0] = INT_TO_FLOAT( param[0] );
    555       p[1] = INT_TO_FLOAT( param[1] );
    556       p[2] = INT_TO_FLOAT( param[2] );
    557       p[3] = INT_TO_FLOAT( param[3] );
    558    }
    559    else {
    560       p[0] = (GLfloat) param[0];
    561       p[1] = p[2] = p[3] = 0;  /* init to zero, just to be safe */
    562    }
    563    _mesa_TexEnvfv( target, pname, p );
    564 }
    565 
    566 
    567 
    568 /**
    569  * Helper for glGetTexEnvi/f()
    570  * \return  value of queried pname or -1 if error.
    571  */
    572 static GLint
    573 get_texenvi(struct gl_context *ctx, const struct gl_texture_unit *texUnit,
    574             GLenum pname)
    575 {
    576    switch (pname) {
    577    case GL_TEXTURE_ENV_MODE:
    578       return texUnit->EnvMode;
    579       break;
    580    case GL_COMBINE_RGB:
    581       return texUnit->Combine.ModeRGB;
    582    case GL_COMBINE_ALPHA:
    583       return texUnit->Combine.ModeA;
    584    case GL_SOURCE0_RGB:
    585    case GL_SOURCE1_RGB:
    586    case GL_SOURCE2_RGB: {
    587       const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
    588       return texUnit->Combine.SourceRGB[rgb_idx];
    589    }
    590    case GL_SOURCE3_RGB_NV:
    591       if (ctx->API == API_OPENGL && ctx->Extensions.NV_texture_env_combine4) {
    592          return texUnit->Combine.SourceRGB[3];
    593       }
    594       else {
    595          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    596       }
    597       break;
    598    case GL_SOURCE0_ALPHA:
    599    case GL_SOURCE1_ALPHA:
    600    case GL_SOURCE2_ALPHA: {
    601       const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
    602       return texUnit->Combine.SourceA[alpha_idx];
    603    }
    604    case GL_SOURCE3_ALPHA_NV:
    605       if (ctx->API == API_OPENGL && ctx->Extensions.NV_texture_env_combine4) {
    606          return texUnit->Combine.SourceA[3];
    607       }
    608       else {
    609          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    610       }
    611       break;
    612    case GL_OPERAND0_RGB:
    613    case GL_OPERAND1_RGB:
    614    case GL_OPERAND2_RGB: {
    615       const unsigned op_rgb = pname - GL_OPERAND0_RGB;
    616       return texUnit->Combine.OperandRGB[op_rgb];
    617    }
    618    case GL_OPERAND3_RGB_NV:
    619       if (ctx->API == API_OPENGL && ctx->Extensions.NV_texture_env_combine4) {
    620          return texUnit->Combine.OperandRGB[3];
    621       }
    622       else {
    623          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    624       }
    625       break;
    626    case GL_OPERAND0_ALPHA:
    627    case GL_OPERAND1_ALPHA:
    628    case GL_OPERAND2_ALPHA: {
    629       const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
    630       return texUnit->Combine.OperandA[op_alpha];
    631    }
    632    case GL_OPERAND3_ALPHA_NV:
    633       if (ctx->API == API_OPENGL && ctx->Extensions.NV_texture_env_combine4) {
    634          return texUnit->Combine.OperandA[3];
    635       }
    636       else {
    637          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    638       }
    639       break;
    640    case GL_RGB_SCALE:
    641       return 1 << texUnit->Combine.ScaleShiftRGB;
    642    case GL_ALPHA_SCALE:
    643       return 1 << texUnit->Combine.ScaleShiftA;
    644    case GL_BUMP_TARGET_ATI:
    645       /* spec doesn't say so, but I think this should be queryable */
    646       if (ctx->API == API_OPENGL && ctx->Extensions.ATI_envmap_bumpmap) {
    647          return texUnit->BumpTarget;
    648       }
    649       else {
    650          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    651       }
    652       break;
    653 
    654    default:
    655       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
    656       break;
    657    }
    658 
    659    return -1; /* error */
    660 }
    661 
    662 
    663 
    664 void GLAPIENTRY
    665 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
    666 {
    667    GLuint maxUnit;
    668    const struct gl_texture_unit *texUnit;
    669    GET_CURRENT_CONTEXT(ctx);
    670    ASSERT_OUTSIDE_BEGIN_END(ctx);
    671 
    672    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
    673       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    674    if (ctx->Texture.CurrentUnit >= maxUnit) {
    675       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
    676       return;
    677    }
    678 
    679    texUnit = _mesa_get_current_tex_unit(ctx);
    680 
    681    if (target == GL_TEXTURE_ENV) {
    682       if (pname == GL_TEXTURE_ENV_COLOR) {
    683          if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP))
    684             _mesa_update_state(ctx);
    685          if(ctx->Color._ClampFragmentColor)
    686             COPY_4FV( params, texUnit->EnvColor );
    687          else
    688             COPY_4FV( params, texUnit->EnvColorUnclamped );
    689       }
    690       else {
    691          GLint val = get_texenvi(ctx, texUnit, pname);
    692          if (val >= 0) {
    693             *params = (GLfloat) val;
    694          }
    695       }
    696    }
    697    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
    698       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
    699          *params = texUnit->LodBias;
    700       }
    701       else {
    702          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
    703 	 return;
    704       }
    705    }
    706    else if (target == GL_POINT_SPRITE_NV) {
    707       /* GL_ARB_point_sprite / GL_NV_point_sprite */
    708       if (!ctx->Extensions.NV_point_sprite
    709 	  && !ctx->Extensions.ARB_point_sprite) {
    710          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
    711          return;
    712       }
    713       if (pname == GL_COORD_REPLACE_NV) {
    714          *params = (GLfloat) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
    715       }
    716       else {
    717          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
    718          return;
    719       }
    720    }
    721    else {
    722       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
    723       return;
    724    }
    725 }
    726 
    727 
    728 void GLAPIENTRY
    729 _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
    730 {
    731    GLuint maxUnit;
    732    const struct gl_texture_unit *texUnit;
    733    GET_CURRENT_CONTEXT(ctx);
    734    ASSERT_OUTSIDE_BEGIN_END(ctx);
    735 
    736    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
    737       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
    738    if (ctx->Texture.CurrentUnit >= maxUnit) {
    739       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
    740       return;
    741    }
    742 
    743    texUnit = _mesa_get_current_tex_unit(ctx);
    744 
    745    if (target == GL_TEXTURE_ENV) {
    746       if (pname == GL_TEXTURE_ENV_COLOR) {
    747          params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
    748          params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
    749          params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
    750          params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
    751       }
    752       else {
    753          GLint val = get_texenvi(ctx, texUnit, pname);
    754          if (val >= 0) {
    755             *params = val;
    756          }
    757       }
    758    }
    759    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
    760       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
    761          *params = (GLint) texUnit->LodBias;
    762       }
    763       else {
    764          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
    765 	 return;
    766       }
    767    }
    768    else if (target == GL_POINT_SPRITE_NV) {
    769       /* GL_ARB_point_sprite / GL_NV_point_sprite */
    770       if (!ctx->Extensions.NV_point_sprite
    771 	  && !ctx->Extensions.ARB_point_sprite) {
    772          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
    773          return;
    774       }
    775       if (pname == GL_COORD_REPLACE_NV) {
    776          *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
    777       }
    778       else {
    779          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
    780          return;
    781       }
    782    }
    783    else {
    784       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
    785       return;
    786    }
    787 }
    788 
    789 
    790 /**
    791  * Why does ATI_envmap_bumpmap require new entrypoints? Should just
    792  * reuse TexEnv ones...
    793  */
    794 void GLAPIENTRY
    795 _mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
    796 {
    797    GLfloat p[4];
    798    GET_CURRENT_CONTEXT(ctx);
    799    ASSERT_OUTSIDE_BEGIN_END(ctx);
    800 
    801    if (!ctx->Extensions.ATI_envmap_bumpmap) {
    802       /* This isn't an "official" error case, but let's tell the user
    803        * that something's wrong.
    804        */
    805       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
    806       return;
    807    }
    808 
    809    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
    810       /* hope that conversion is correct here */
    811       p[0] = INT_TO_FLOAT( param[0] );
    812       p[1] = INT_TO_FLOAT( param[1] );
    813       p[2] = INT_TO_FLOAT( param[2] );
    814       p[3] = INT_TO_FLOAT( param[3] );
    815    }
    816    else {
    817       p[0] = (GLfloat) param[0];
    818       p[1] = p[2] = p[3] = 0.0F;  /* init to zero, just to be safe */
    819    }
    820    _mesa_TexBumpParameterfvATI( pname, p );
    821 }
    822 
    823 
    824 void GLAPIENTRY
    825 _mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
    826 {
    827    struct gl_texture_unit *texUnit;
    828    GET_CURRENT_CONTEXT(ctx);
    829    ASSERT_OUTSIDE_BEGIN_END(ctx);
    830 
    831    if (!ctx->Extensions.ATI_envmap_bumpmap) {
    832       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
    833       return;
    834    }
    835 
    836    texUnit = _mesa_get_current_tex_unit(ctx);
    837 
    838    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
    839       if (TEST_EQ_4V(param, texUnit->RotMatrix))
    840          return;
    841       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
    842       COPY_4FV(texUnit->RotMatrix, param);
    843    }
    844    else {
    845       _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
    846       return;
    847    }
    848    /* Drivers might want to know about this, instead of dedicated function
    849       just shove it into TexEnv where it really belongs anyway */
    850    if (ctx->Driver.TexEnv) {
    851       (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
    852    }
    853 }
    854 
    855 
    856 void GLAPIENTRY
    857 _mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
    858 {
    859    const struct gl_texture_unit *texUnit;
    860    GLuint i;
    861    GET_CURRENT_CONTEXT(ctx);
    862    ASSERT_OUTSIDE_BEGIN_END(ctx);
    863 
    864    if (!ctx->Extensions.ATI_envmap_bumpmap) {
    865       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
    866       return;
    867    }
    868 
    869    texUnit = _mesa_get_current_tex_unit(ctx);
    870 
    871    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
    872       /* spec leaves open to support larger matrices.
    873          Don't think anyone would ever want to use it
    874          (and apps almost certainly would not understand it and
    875          thus fail to submit matrices correctly) so hardcode this. */
    876       *param = 4;
    877    }
    878    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
    879       /* hope that conversion is correct here */
    880       param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
    881       param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
    882       param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
    883       param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
    884    }
    885    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
    886       GLint count = 0;
    887       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
    888          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
    889             count++;
    890          }
    891       }
    892       *param = count;
    893    }
    894    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
    895       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
    896          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
    897             *param++ = i + GL_TEXTURE0;
    898          }
    899       }
    900    }
    901    else {
    902       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
    903       return;
    904    }
    905 }
    906 
    907 
    908 void GLAPIENTRY
    909 _mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
    910 {
    911    const struct gl_texture_unit *texUnit;
    912    GLuint i;
    913    GET_CURRENT_CONTEXT(ctx);
    914    ASSERT_OUTSIDE_BEGIN_END(ctx);
    915 
    916    if (!ctx->Extensions.ATI_envmap_bumpmap) {
    917       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
    918       return;
    919    }
    920 
    921    texUnit = _mesa_get_current_tex_unit(ctx);
    922 
    923    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
    924       /* spec leaves open to support larger matrices.
    925          Don't think anyone would ever want to use it
    926          (and apps might not understand it) so hardcode this. */
    927       *param = 4.0F;
    928    }
    929    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
    930       param[0] = texUnit->RotMatrix[0];
    931       param[1] = texUnit->RotMatrix[1];
    932       param[2] = texUnit->RotMatrix[2];
    933       param[3] = texUnit->RotMatrix[3];
    934    }
    935    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
    936       GLint count = 0;
    937       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
    938          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
    939             count++;
    940          }
    941       }
    942       *param = (GLfloat) count;
    943    }
    944    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
    945       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
    946          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
    947             *param++ = (GLfloat) (i + GL_TEXTURE0);
    948          }
    949       }
    950    }
    951    else {
    952       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
    953       return;
    954    }
    955 }
    956