OSDN Git Service

84731dddab5d78b1bfddde0cbc69f885ea686a67
[android-x86/external-mesa.git] / src / mesa / main / texenv.c
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  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24  * OTHER DEALINGS IN THE SOFTWARE.
25  */
26
27 /** 
28  * \file texenv.c
29  *
30  * glTexEnv-related functions
31  */
32
33
34 #include "main/glheader.h"
35 #include "main/context.h"
36 #include "main/blend.h"
37 #include "main/enums.h"
38 #include "main/macros.h"
39 #include "main/mtypes.h"
40 #include "main/state.h"
41 #include "main/texenv.h"
42 #include "main/texstate.h"
43
44
45 #define TE_ERROR(errCode, msg, value)                           \
46    _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
47
48
49 /** Set texture env mode */
50 static void
51 set_env_mode(struct gl_context *ctx,
52              struct gl_texture_unit *texUnit,
53              GLenum mode)
54 {
55    GLboolean legal;
56
57    if (texUnit->EnvMode == mode)
58       return;
59
60    switch (mode) {
61    case GL_MODULATE:
62    case GL_BLEND:
63    case GL_DECAL:
64    case GL_REPLACE:
65    case GL_ADD:
66    case GL_COMBINE:
67       legal = GL_TRUE;
68       break;
69    case GL_REPLACE_EXT:
70       mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
71       legal = GL_TRUE;
72       break;
73    case GL_COMBINE4_NV:
74       legal = ctx->Extensions.NV_texture_env_combine4;
75       break;
76    default:
77       legal = GL_FALSE;
78    }
79
80    if (legal) {
81       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
82       texUnit->EnvMode = mode;
83    }
84    else {
85       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
86    }
87 }
88
89
90 static void
91 set_env_color(struct gl_context *ctx,
92               struct gl_texture_unit *texUnit,
93               const GLfloat *color)
94 {
95    if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
96       return;
97    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
98    COPY_4FV(texUnit->EnvColorUnclamped, color);
99    texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
100    texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
101    texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
102    texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
103 }
104
105
106 /** Set an RGB or A combiner mode/function */
107 static void
108 set_combiner_mode(struct gl_context *ctx,
109                   struct gl_texture_unit *texUnit,
110                   GLenum pname, GLenum mode)
111 {
112    GLboolean legal;
113
114    switch (mode) {
115    case GL_REPLACE:
116    case GL_MODULATE:
117    case GL_ADD:
118    case GL_ADD_SIGNED:
119    case GL_INTERPOLATE:
120       legal = GL_TRUE;
121       break;
122    case GL_SUBTRACT:
123       legal = ctx->Extensions.ARB_texture_env_combine;
124       break;
125    case GL_DOT3_RGB_EXT:
126    case GL_DOT3_RGBA_EXT:
127       legal = (ctx->API == API_OPENGL_COMPAT &&
128                ctx->Extensions.EXT_texture_env_dot3 &&
129                pname == GL_COMBINE_RGB);
130       break;
131    case GL_DOT3_RGB:
132    case GL_DOT3_RGBA:
133       legal = (ctx->Extensions.ARB_texture_env_dot3 &&
134                pname == GL_COMBINE_RGB);
135       break;
136    case GL_MODULATE_ADD_ATI:
137    case GL_MODULATE_SIGNED_ADD_ATI:
138    case GL_MODULATE_SUBTRACT_ATI:
139       legal = (ctx->API == API_OPENGL_COMPAT &&
140                ctx->Extensions.ATI_texture_env_combine3);
141       break;
142    case GL_BUMP_ENVMAP_ATI:
143       legal = (ctx->API == API_OPENGL_COMPAT &&
144                ctx->Extensions.ATI_envmap_bumpmap &&
145                pname == GL_COMBINE_RGB);
146       break;
147    default:
148       legal = GL_FALSE;
149    }
150
151    if (!legal) {
152       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
153       return;
154    }
155
156    switch (pname) {
157    case GL_COMBINE_RGB:
158       if (texUnit->Combine.ModeRGB == mode)
159          return;
160       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
161       texUnit->Combine.ModeRGB = mode;
162       break;
163
164    case GL_COMBINE_ALPHA:
165       if (texUnit->Combine.ModeA == mode)
166          return;
167       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
168       texUnit->Combine.ModeA = mode;
169       break;
170    default:
171       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
172    }
173 }
174
175
176
177 /** Set an RGB or A combiner source term */
178 static void
179 set_combiner_source(struct gl_context *ctx,
180                     struct gl_texture_unit *texUnit,
181                     GLenum pname, GLenum param)
182 {
183    GLuint term;
184    GLboolean alpha, legal;
185
186    /*
187     * Translate pname to (term, alpha).
188     *
189     * The enums were given sequential values for a reason.
190     */
191    switch (pname) {
192    case GL_SOURCE0_RGB:
193    case GL_SOURCE1_RGB:
194    case GL_SOURCE2_RGB:
195    case GL_SOURCE3_RGB_NV:
196       term = pname - GL_SOURCE0_RGB;
197       alpha = GL_FALSE;
198       break;
199    case GL_SOURCE0_ALPHA:
200    case GL_SOURCE1_ALPHA:
201    case GL_SOURCE2_ALPHA:
202    case GL_SOURCE3_ALPHA_NV:
203       term = pname - GL_SOURCE0_ALPHA;
204       alpha = GL_TRUE;
205       break;
206    default:
207       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
208       return;
209    }
210
211    if ((term == 3) && (ctx->API != API_OPENGL_COMPAT
212                        || !ctx->Extensions.NV_texture_env_combine4)) {
213       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
214       return;
215    }
216
217    assert(term < MAX_COMBINER_TERMS);
218
219    /*
220     * Error-check param (the source term)
221     */
222    switch (param) {
223    case GL_TEXTURE:
224    case GL_CONSTANT:
225    case GL_PRIMARY_COLOR:
226    case GL_PREVIOUS:
227       legal = GL_TRUE;
228       break;
229    case GL_TEXTURE0:
230    case GL_TEXTURE1:
231    case GL_TEXTURE2:
232    case GL_TEXTURE3:
233    case GL_TEXTURE4:
234    case GL_TEXTURE5:
235    case GL_TEXTURE6:
236    case GL_TEXTURE7:
237       legal = (ctx->Extensions.ARB_texture_env_crossbar &&
238                param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
239       break;
240    case GL_ZERO:
241       legal = (ctx->API == API_OPENGL_COMPAT &&
242                (ctx->Extensions.ATI_texture_env_combine3 ||
243                 ctx->Extensions.NV_texture_env_combine4));
244       break;
245    case GL_ONE:
246       legal = (ctx->API == API_OPENGL_COMPAT &&
247                ctx->Extensions.ATI_texture_env_combine3);
248       break;
249    default:
250       legal = GL_FALSE;
251    }
252
253    if (!legal) {
254       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
255       return;
256    }
257
258    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
259
260    if (alpha)
261       texUnit->Combine.SourceA[term] = param;
262    else
263       texUnit->Combine.SourceRGB[term] = param;
264 }
265
266
267 /** Set an RGB or A combiner operand term */
268 static void
269 set_combiner_operand(struct gl_context *ctx,
270                      struct gl_texture_unit *texUnit,
271                      GLenum pname, GLenum param)
272 {
273    GLuint term;
274    GLboolean alpha, legal;
275
276    /* The enums were given sequential values for a reason.
277     */
278    switch (pname) {
279    case GL_OPERAND0_RGB:
280    case GL_OPERAND1_RGB:
281    case GL_OPERAND2_RGB:
282    case GL_OPERAND3_RGB_NV:
283       term = pname - GL_OPERAND0_RGB;
284       alpha = GL_FALSE;
285       break;
286    case GL_OPERAND0_ALPHA:
287    case GL_OPERAND1_ALPHA:
288    case GL_OPERAND2_ALPHA:
289    case GL_OPERAND3_ALPHA_NV:
290       term = pname - GL_OPERAND0_ALPHA;
291       alpha = GL_TRUE;
292       break;
293    default:
294       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
295       return;
296    }
297
298    if ((term == 3) && (ctx->API != API_OPENGL_COMPAT
299                        || !ctx->Extensions.NV_texture_env_combine4)) {
300       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
301       return;
302    }
303
304    assert(term < MAX_COMBINER_TERMS);
305
306    /*
307     * Error-check param (the source operand)
308     */
309    switch (param) {
310    case GL_SRC_COLOR:
311    case GL_ONE_MINUS_SRC_COLOR:
312       /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
313        * version.  In the ARB and NV versions and OpenGL ES 1.x they can be
314        * used for any RGB operand.
315        */
316       legal = !alpha
317          && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
318              || ctx->Extensions.NV_texture_env_combine4);
319       break;
320    case GL_ONE_MINUS_SRC_ALPHA:
321       /* GL_ONE_MINUS_SRC_ALPHA can only be used with
322        * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version.  In the ARB and NV
323        * versions and OpenGL ES 1.x it can be used for any operand.
324        */
325       legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
326          || ctx->Extensions.NV_texture_env_combine4;
327       break;
328    case GL_SRC_ALPHA:
329       legal = GL_TRUE;
330       break;
331    default:
332       legal = GL_FALSE;
333    }
334
335    if (!legal) {
336       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
337       return;
338    }
339
340    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
341
342    if (alpha)
343       texUnit->Combine.OperandA[term] = param;
344    else
345       texUnit->Combine.OperandRGB[term] = param;
346 }
347
348
349 static void
350 set_combiner_scale(struct gl_context *ctx,
351                    struct gl_texture_unit *texUnit,
352                    GLenum pname, GLfloat scale)
353 {
354    GLuint shift;
355
356    if (scale == 1.0F) {
357       shift = 0;
358    }
359    else if (scale == 2.0F) {
360       shift = 1;
361    }
362    else if (scale == 4.0F) {
363       shift = 2;
364    }
365    else {
366       _mesa_error( ctx, GL_INVALID_VALUE,
367                    "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
368       return;
369    }
370
371    switch (pname) {
372    case GL_RGB_SCALE:
373       if (texUnit->Combine.ScaleShiftRGB == shift)
374          return;
375       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
376       texUnit->Combine.ScaleShiftRGB = shift;
377       break;
378    case GL_ALPHA_SCALE:
379       if (texUnit->Combine.ScaleShiftA == shift)
380          return;
381       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
382       texUnit->Combine.ScaleShiftA = shift;
383       break;
384    default:
385       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
386    }
387 }
388
389
390
391 void GLAPIENTRY
392 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
393 {
394    const GLint iparam0 = (GLint) param[0];
395    struct gl_texture_unit *texUnit;
396    GLuint maxUnit;
397    GET_CURRENT_CONTEXT(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_COMPAT || !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=%s)",
511                   _mesa_lookup_enum_by_nr(target));
512       return;
513    }
514
515    if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
516       _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n",
517                   _mesa_lookup_enum_by_nr(target),
518                   _mesa_lookup_enum_by_nr(pname),
519                   *param,
520                   _mesa_lookup_enum_by_nr((GLenum) iparam0));
521
522    /* Tell device driver about the new texture environment */
523    if (ctx->Driver.TexEnv) {
524       (*ctx->Driver.TexEnv)( ctx, target, pname, param );
525    }
526 }
527
528
529 void GLAPIENTRY
530 _mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
531 {
532    GLfloat p[4];
533    p[0] = param;
534    p[1] = p[2] = p[3] = 0.0;
535    _mesa_TexEnvfv( target, pname, p );
536 }
537
538
539
540 void GLAPIENTRY
541 _mesa_TexEnvi( GLenum target, GLenum pname, GLint param )
542 {
543    GLfloat p[4];
544    p[0] = (GLfloat) param;
545    p[1] = p[2] = p[3] = 0.0;
546    _mesa_TexEnvfv( target, pname, p );
547 }
548
549
550 void GLAPIENTRY
551 _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
552 {
553    GLfloat p[4];
554    if (pname == GL_TEXTURE_ENV_COLOR) {
555       p[0] = INT_TO_FLOAT( param[0] );
556       p[1] = INT_TO_FLOAT( param[1] );
557       p[2] = INT_TO_FLOAT( param[2] );
558       p[3] = INT_TO_FLOAT( param[3] );
559    }
560    else {
561       p[0] = (GLfloat) param[0];
562       p[1] = p[2] = p[3] = 0;  /* init to zero, just to be safe */
563    }
564    _mesa_TexEnvfv( target, pname, p );
565 }
566
567
568
569 /**
570  * Helper for glGetTexEnvi/f()
571  * \return  value of queried pname or -1 if error.
572  */
573 static GLint
574 get_texenvi(struct gl_context *ctx, const struct gl_texture_unit *texUnit,
575             GLenum pname)
576 {
577    switch (pname) {
578    case GL_TEXTURE_ENV_MODE:
579       return texUnit->EnvMode;
580       break;
581    case GL_COMBINE_RGB:
582       return texUnit->Combine.ModeRGB;
583    case GL_COMBINE_ALPHA:
584       return texUnit->Combine.ModeA;
585    case GL_SOURCE0_RGB:
586    case GL_SOURCE1_RGB:
587    case GL_SOURCE2_RGB: {
588       const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
589       return texUnit->Combine.SourceRGB[rgb_idx];
590    }
591    case GL_SOURCE3_RGB_NV:
592       if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
593          return texUnit->Combine.SourceRGB[3];
594       }
595       else {
596          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
597       }
598       break;
599    case GL_SOURCE0_ALPHA:
600    case GL_SOURCE1_ALPHA:
601    case GL_SOURCE2_ALPHA: {
602       const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
603       return texUnit->Combine.SourceA[alpha_idx];
604    }
605    case GL_SOURCE3_ALPHA_NV:
606       if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
607          return texUnit->Combine.SourceA[3];
608       }
609       else {
610          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
611       }
612       break;
613    case GL_OPERAND0_RGB:
614    case GL_OPERAND1_RGB:
615    case GL_OPERAND2_RGB: {
616       const unsigned op_rgb = pname - GL_OPERAND0_RGB;
617       return texUnit->Combine.OperandRGB[op_rgb];
618    }
619    case GL_OPERAND3_RGB_NV:
620       if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
621          return texUnit->Combine.OperandRGB[3];
622       }
623       else {
624          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
625       }
626       break;
627    case GL_OPERAND0_ALPHA:
628    case GL_OPERAND1_ALPHA:
629    case GL_OPERAND2_ALPHA: {
630       const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
631       return texUnit->Combine.OperandA[op_alpha];
632    }
633    case GL_OPERAND3_ALPHA_NV:
634       if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
635          return texUnit->Combine.OperandA[3];
636       }
637       else {
638          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
639       }
640       break;
641    case GL_RGB_SCALE:
642       return 1 << texUnit->Combine.ScaleShiftRGB;
643    case GL_ALPHA_SCALE:
644       return 1 << texUnit->Combine.ScaleShiftA;
645    case GL_BUMP_TARGET_ATI:
646       /* spec doesn't say so, but I think this should be queryable */
647       if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_envmap_bumpmap) {
648          return texUnit->BumpTarget;
649       }
650       else {
651          _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
652       }
653       break;
654
655    default:
656       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
657       break;
658    }
659
660    return -1; /* error */
661 }
662
663
664
665 void GLAPIENTRY
666 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
667 {
668    GLuint maxUnit;
669    const struct gl_texture_unit *texUnit;
670    GET_CURRENT_CONTEXT(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 (_mesa_get_clamp_fragment_color(ctx))
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
735    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
736       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
737    if (ctx->Texture.CurrentUnit >= maxUnit) {
738       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
739       return;
740    }
741
742    texUnit = _mesa_get_current_tex_unit(ctx);
743
744    if (target == GL_TEXTURE_ENV) {
745       if (pname == GL_TEXTURE_ENV_COLOR) {
746          params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
747          params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
748          params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
749          params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
750       }
751       else {
752          GLint val = get_texenvi(ctx, texUnit, pname);
753          if (val >= 0) {
754             *params = val;
755          }
756       }
757    }
758    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
759       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
760          *params = (GLint) texUnit->LodBias;
761       }
762       else {
763          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
764          return;
765       }
766    }
767    else if (target == GL_POINT_SPRITE_NV) {
768       /* GL_ARB_point_sprite / GL_NV_point_sprite */
769       if (!ctx->Extensions.NV_point_sprite
770           && !ctx->Extensions.ARB_point_sprite) {
771          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
772          return;
773       }
774       if (pname == GL_COORD_REPLACE_NV) {
775          *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
776       }
777       else {
778          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
779          return;
780       }
781    }
782    else {
783       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
784       return;
785    }
786 }
787
788
789 /**
790  * Why does ATI_envmap_bumpmap require new entrypoints? Should just
791  * reuse TexEnv ones...
792  */
793 void GLAPIENTRY
794 _mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
795 {
796    GLfloat p[4];
797    GET_CURRENT_CONTEXT(ctx);
798
799    if (!ctx->Extensions.ATI_envmap_bumpmap) {
800       /* This isn't an "official" error case, but let's tell the user
801        * that something's wrong.
802        */
803       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
804       return;
805    }
806
807    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
808       /* hope that conversion is correct here */
809       p[0] = INT_TO_FLOAT( param[0] );
810       p[1] = INT_TO_FLOAT( param[1] );
811       p[2] = INT_TO_FLOAT( param[2] );
812       p[3] = INT_TO_FLOAT( param[3] );
813    }
814    else {
815       p[0] = (GLfloat) param[0];
816       p[1] = p[2] = p[3] = 0.0F;  /* init to zero, just to be safe */
817    }
818    _mesa_TexBumpParameterfvATI( pname, p );
819 }
820
821
822 void GLAPIENTRY
823 _mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
824 {
825    struct gl_texture_unit *texUnit;
826    GET_CURRENT_CONTEXT(ctx);
827
828    if (!ctx->Extensions.ATI_envmap_bumpmap) {
829       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
830       return;
831    }
832
833    texUnit = _mesa_get_current_tex_unit(ctx);
834
835    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
836       if (TEST_EQ_4V(param, texUnit->RotMatrix))
837          return;
838       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
839       COPY_4FV(texUnit->RotMatrix, param);
840    }
841    else {
842       _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
843       return;
844    }
845    /* Drivers might want to know about this, instead of dedicated function
846       just shove it into TexEnv where it really belongs anyway */
847    if (ctx->Driver.TexEnv) {
848       (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
849    }
850 }
851
852
853 void GLAPIENTRY
854 _mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
855 {
856    const struct gl_texture_unit *texUnit;
857    GLuint i;
858    GET_CURRENT_CONTEXT(ctx);
859
860    if (!ctx->Extensions.ATI_envmap_bumpmap) {
861       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
862       return;
863    }
864
865    texUnit = _mesa_get_current_tex_unit(ctx);
866
867    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
868       /* spec leaves open to support larger matrices.
869          Don't think anyone would ever want to use it
870          (and apps almost certainly would not understand it and
871          thus fail to submit matrices correctly) so hardcode this. */
872       *param = 4;
873    }
874    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
875       /* hope that conversion is correct here */
876       param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
877       param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
878       param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
879       param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
880    }
881    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
882       GLint count = 0;
883       for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
884          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
885             count++;
886          }
887       }
888       *param = count;
889    }
890    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
891       for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
892          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
893             *param++ = i + GL_TEXTURE0;
894          }
895       }
896    }
897    else {
898       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
899       return;
900    }
901 }
902
903
904 void GLAPIENTRY
905 _mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
906 {
907    const struct gl_texture_unit *texUnit;
908    GLuint i;
909    GET_CURRENT_CONTEXT(ctx);
910
911    if (!ctx->Extensions.ATI_envmap_bumpmap) {
912       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
913       return;
914    }
915
916    texUnit = _mesa_get_current_tex_unit(ctx);
917
918    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
919       /* spec leaves open to support larger matrices.
920          Don't think anyone would ever want to use it
921          (and apps might not understand it) so hardcode this. */
922       *param = 4.0F;
923    }
924    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
925       param[0] = texUnit->RotMatrix[0];
926       param[1] = texUnit->RotMatrix[1];
927       param[2] = texUnit->RotMatrix[2];
928       param[3] = texUnit->RotMatrix[3];
929    }
930    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
931       GLint count = 0;
932       for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
933          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
934             count++;
935          }
936       }
937       *param = (GLfloat) count;
938    }
939    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
940       for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
941          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
942             *param++ = (GLfloat) (i + GL_TEXTURE0);
943          }
944       }
945    }
946    else {
947       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
948       return;
949    }
950 }