texenv.c revision 8a263b6efd2c520a4ed9c98b9c8142c6c2c6f389
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 */
48static void
49set_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
88static void
89set_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 */
105static void
106set_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 */
176static void
177set_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 */
266static void
267set_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
347static void
348set_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
389void 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
528void 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
539void 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
549void 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 */
572static GLint
573get_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->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->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->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->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->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
664void 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
728void 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 */
794void 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
824void 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
856void 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
908void 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