texenv.c revision 4a49301e
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/texenv.h"
38#include "main/texstate.h"
39
40
41#define TE_ERROR(errCode, msg, value)				\
42   _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
43
44
45/** Set texture env mode */
46static void
47set_env_mode(GLcontext *ctx,
48             struct gl_texture_unit *texUnit,
49             GLenum mode)
50{
51   GLboolean legal;
52
53   if (texUnit->EnvMode == mode)
54      return;
55
56   switch (mode) {
57   case GL_MODULATE:
58   case GL_BLEND:
59   case GL_DECAL:
60   case GL_REPLACE:
61      legal = GL_TRUE;
62      break;
63   case GL_REPLACE_EXT:
64      mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
65      legal = GL_TRUE;
66      break;
67   case GL_ADD:
68      legal = ctx->Extensions.EXT_texture_env_add;
69      break;
70   case GL_COMBINE:
71      legal = (ctx->Extensions.EXT_texture_env_combine ||
72               ctx->Extensions.ARB_texture_env_combine);
73      break;
74   case GL_COMBINE4_NV:
75      legal = ctx->Extensions.NV_texture_env_combine4;
76      break;
77   default:
78      legal = GL_FALSE;
79   }
80
81   if (legal) {
82      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
83      texUnit->EnvMode = mode;
84   }
85   else {
86      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
87   }
88}
89
90
91static void
92set_env_color(GLcontext *ctx,
93              struct gl_texture_unit *texUnit,
94              const GLfloat *color)
95{
96   GLfloat tmp[4];
97   tmp[0] = CLAMP(color[0], 0.0F, 1.0F);
98   tmp[1] = CLAMP(color[1], 0.0F, 1.0F);
99   tmp[2] = CLAMP(color[2], 0.0F, 1.0F);
100   tmp[3] = CLAMP(color[3], 0.0F, 1.0F);
101   if (TEST_EQ_4V(tmp, texUnit->EnvColor))
102      return;
103   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
104   COPY_4FV(texUnit->EnvColor, tmp);
105}
106
107
108/** Set an RGB or A combiner mode/function */
109static void
110set_combiner_mode(GLcontext *ctx,
111                  struct gl_texture_unit *texUnit,
112                  GLenum pname, GLenum mode)
113{
114   GLboolean legal;
115
116   if (!ctx->Extensions.EXT_texture_env_combine &&
117       !ctx->Extensions.ARB_texture_env_combine) {
118      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
119      return;
120   }
121
122   switch (mode) {
123   case GL_REPLACE:
124   case GL_MODULATE:
125   case GL_ADD:
126   case GL_ADD_SIGNED:
127   case GL_INTERPOLATE:
128      legal = GL_TRUE;
129      break;
130   case GL_SUBTRACT:
131      legal = ctx->Extensions.ARB_texture_env_combine;
132      break;
133   case GL_DOT3_RGB_EXT:
134   case GL_DOT3_RGBA_EXT:
135      legal = (ctx->Extensions.EXT_texture_env_dot3 &&
136               pname == GL_COMBINE_RGB);
137      break;
138   case GL_DOT3_RGB:
139   case GL_DOT3_RGBA:
140      legal = (ctx->Extensions.ARB_texture_env_dot3 &&
141               pname == GL_COMBINE_RGB);
142      break;
143   case GL_MODULATE_ADD_ATI:
144   case GL_MODULATE_SIGNED_ADD_ATI:
145   case GL_MODULATE_SUBTRACT_ATI:
146      legal = ctx->Extensions.ATI_texture_env_combine3;
147      break;
148   case GL_BUMP_ENVMAP_ATI:
149      legal = (ctx->Extensions.ATI_envmap_bumpmap &&
150               pname == GL_COMBINE_RGB);
151      break;
152   default:
153      legal = GL_FALSE;
154   }
155
156   if (!legal) {
157      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
158      return;
159   }
160
161   switch (pname) {
162   case GL_COMBINE_RGB:
163      if (texUnit->Combine.ModeRGB == mode)
164         return;
165      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
166      texUnit->Combine.ModeRGB = mode;
167      break;
168
169   case GL_COMBINE_ALPHA:
170      if (texUnit->Combine.ModeA == mode)
171         return;
172      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
173      texUnit->Combine.ModeA = mode;
174      break;
175   default:
176      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
177   }
178}
179
180
181
182/** Set an RGB or A combiner source term */
183static void
184set_combiner_source(GLcontext *ctx,
185                    struct gl_texture_unit *texUnit,
186                    GLenum pname, GLenum param)
187{
188   GLuint term;
189   GLboolean alpha, legal;
190
191   if (!ctx->Extensions.EXT_texture_env_combine &&
192       !ctx->Extensions.ARB_texture_env_combine) {
193      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
194      return;
195   }
196
197   /*
198    * Translate pname to (term, alpha).
199    */
200   switch (pname) {
201   case GL_SOURCE0_RGB:
202      term = 0;
203      alpha = GL_FALSE;
204      break;
205   case GL_SOURCE1_RGB:
206      term = 1;
207      alpha = GL_FALSE;
208      break;
209   case GL_SOURCE2_RGB:
210      term = 2;
211      alpha = GL_FALSE;
212      break;
213   case GL_SOURCE3_RGB_NV:
214      if (ctx->Extensions.NV_texture_env_combine4) {
215         term = 3;
216         alpha = GL_FALSE;
217      }
218      else {
219         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
220         return;
221      }
222      break;
223   case GL_SOURCE0_ALPHA:
224      term = 0;
225      alpha = GL_TRUE;
226      break;
227   case GL_SOURCE1_ALPHA:
228      term = 1;
229      alpha = GL_TRUE;
230      break;
231   case GL_SOURCE2_ALPHA:
232      term = 2;
233      alpha = GL_TRUE;
234      break;
235   case GL_SOURCE3_ALPHA_NV:
236      if (ctx->Extensions.NV_texture_env_combine4) {
237         term = 3;
238         alpha = GL_TRUE;
239      }
240      else {
241         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
242         return;
243      }
244      break;
245   default:
246      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
247      return;
248   }
249
250   assert(term < MAX_COMBINER_TERMS);
251
252   /*
253    * Error-check param (the source term)
254    */
255   switch (param) {
256   case GL_TEXTURE:
257   case GL_CONSTANT:
258   case GL_PRIMARY_COLOR:
259   case GL_PREVIOUS:
260      legal = GL_TRUE;
261      break;
262   case GL_TEXTURE0:
263   case GL_TEXTURE1:
264   case GL_TEXTURE2:
265   case GL_TEXTURE3:
266   case GL_TEXTURE4:
267   case GL_TEXTURE5:
268   case GL_TEXTURE6:
269   case GL_TEXTURE7:
270      legal = (ctx->Extensions.ARB_texture_env_crossbar &&
271               param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
272      break;
273   case GL_ZERO:
274      legal = (ctx->Extensions.ATI_texture_env_combine3 ||
275               ctx->Extensions.NV_texture_env_combine4);
276      break;
277   case GL_ONE:
278      legal = ctx->Extensions.ATI_texture_env_combine3;
279      break;
280   default:
281      legal = GL_FALSE;
282   }
283
284   if (!legal) {
285      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
286      return;
287   }
288
289   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
290
291   if (alpha)
292      texUnit->Combine.SourceA[term] = param;
293   else
294      texUnit->Combine.SourceRGB[term] = param;
295}
296
297
298/** Set an RGB or A combiner operand term */
299static void
300set_combiner_operand(GLcontext *ctx,
301                     struct gl_texture_unit *texUnit,
302                     GLenum pname, GLenum param)
303{
304   GLuint term;
305   GLboolean alpha, legal;
306
307   if (!ctx->Extensions.EXT_texture_env_combine &&
308       !ctx->Extensions.ARB_texture_env_combine) {
309      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
310      return;
311   }
312
313   switch (pname) {
314   case GL_OPERAND0_RGB:
315      term = 0;
316      alpha = GL_FALSE;
317      break;
318   case GL_OPERAND1_RGB:
319      term = 1;
320      alpha = GL_FALSE;
321      break;
322   case GL_OPERAND2_RGB:
323      if (ctx->Extensions.ARB_texture_env_combine) {
324         term = 2;
325         alpha = GL_FALSE;
326      }
327      else {
328         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
329         return;
330      }
331      break;
332   case GL_OPERAND3_RGB_NV:
333      if (ctx->Extensions.NV_texture_env_combine4) {
334         term = 3;
335         alpha = GL_FALSE;
336      }
337      else {
338         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
339         return;
340      }
341      break;
342   case GL_OPERAND0_ALPHA:
343      term = 0;
344      alpha = GL_TRUE;
345      break;
346   case GL_OPERAND1_ALPHA:
347      term = 1;
348      alpha = GL_TRUE;
349      break;
350   case GL_OPERAND2_ALPHA:
351      if (ctx->Extensions.ARB_texture_env_combine) {
352         term = 2;
353         alpha = GL_TRUE;
354      }
355      else {
356         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
357         return;
358      }
359      break;
360   case GL_OPERAND3_ALPHA_NV:
361      if (ctx->Extensions.NV_texture_env_combine4) {
362         term = 3;
363         alpha = GL_TRUE;
364      }
365      else {
366         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
367         return;
368      }
369      break;
370   default:
371      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
372      return;
373   }
374
375   assert(term < MAX_COMBINER_TERMS);
376
377   /*
378    * Error-check param (the source operand)
379    */
380   switch (param) {
381   case GL_SRC_COLOR:
382   case GL_ONE_MINUS_SRC_COLOR:
383      legal = !alpha;
384      break;
385   case GL_SRC_ALPHA:
386   case GL_ONE_MINUS_SRC_ALPHA:
387      legal = GL_TRUE;
388      break;
389   default:
390      legal = GL_FALSE;
391   }
392
393   if (!legal) {
394      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
395      return;
396   }
397
398   FLUSH_VERTICES(ctx, _NEW_TEXTURE);
399
400   if (alpha)
401      texUnit->Combine.OperandA[term] = param;
402   else
403      texUnit->Combine.OperandRGB[term] = param;
404}
405
406
407static void
408set_combiner_scale(GLcontext *ctx,
409                   struct gl_texture_unit *texUnit,
410                   GLenum pname, GLfloat scale)
411{
412   GLuint shift;
413
414   if (!ctx->Extensions.EXT_texture_env_combine &&
415       !ctx->Extensions.ARB_texture_env_combine) {
416      _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(pname)");
417      return;
418   }
419
420   if (scale == 1.0F) {
421      shift = 0;
422   }
423   else if (scale == 2.0F) {
424      shift = 1;
425   }
426   else if (scale == 4.0F) {
427      shift = 2;
428   }
429   else {
430      _mesa_error( ctx, GL_INVALID_VALUE,
431                   "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
432      return;
433   }
434
435   switch (pname) {
436   case GL_RGB_SCALE:
437      if (texUnit->Combine.ScaleShiftRGB == shift)
438         return;
439      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
440      texUnit->Combine.ScaleShiftRGB = shift;
441      break;
442   case GL_ALPHA_SCALE:
443      if (texUnit->Combine.ScaleShiftA == shift)
444         return;
445      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
446      texUnit->Combine.ScaleShiftA = shift;
447      break;
448   default:
449      TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
450   }
451}
452
453
454
455void GLAPIENTRY
456_mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
457{
458   GLuint maxUnit;
459   GET_CURRENT_CONTEXT(ctx);
460   struct gl_texture_unit *texUnit;
461   ASSERT_OUTSIDE_BEGIN_END(ctx);
462
463   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
464      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
465   if (ctx->Texture.CurrentUnit >= maxUnit) {
466      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
467      return;
468   }
469
470   texUnit = _mesa_get_current_tex_unit(ctx);
471
472   if (target == GL_TEXTURE_ENV) {
473      switch (pname) {
474      case GL_TEXTURE_ENV_MODE:
475         set_env_mode(ctx, texUnit, (GLenum) (GLint) param[0]);
476         break;
477      case GL_TEXTURE_ENV_COLOR:
478         set_env_color(ctx, texUnit, param);
479         break;
480      case GL_COMBINE_RGB:
481      case GL_COMBINE_ALPHA:
482         set_combiner_mode(ctx, texUnit, pname, (GLenum) (GLint) param[0]);
483	 break;
484      case GL_SOURCE0_RGB:
485      case GL_SOURCE1_RGB:
486      case GL_SOURCE2_RGB:
487      case GL_SOURCE3_RGB_NV:
488      case GL_SOURCE0_ALPHA:
489      case GL_SOURCE1_ALPHA:
490      case GL_SOURCE2_ALPHA:
491      case GL_SOURCE3_ALPHA_NV:
492         set_combiner_source(ctx, texUnit, pname, (GLenum) (GLint) param[0]);
493	 break;
494      case GL_OPERAND0_RGB:
495      case GL_OPERAND1_RGB:
496      case GL_OPERAND2_RGB:
497      case GL_OPERAND3_RGB_NV:
498      case GL_OPERAND0_ALPHA:
499      case GL_OPERAND1_ALPHA:
500      case GL_OPERAND2_ALPHA:
501      case GL_OPERAND3_ALPHA_NV:
502         set_combiner_operand(ctx, texUnit, pname, (GLenum) (GLint) param[0]);
503	 break;
504      case GL_RGB_SCALE:
505      case GL_ALPHA_SCALE:
506         set_combiner_scale(ctx, texUnit, pname, param[0]);
507	 break;
508      case GL_BUMP_TARGET_ATI:
509         if (!ctx->Extensions.ATI_envmap_bumpmap) {
510	    _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
511	    return;
512	 }
513	 if (((GLenum) (GLint) param[0] < GL_TEXTURE0) ||
514	 ((GLenum) (GLint) param[0] > GL_TEXTURE31)) {
515	    /* spec doesn't say this but it seems logical */
516	    _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(param=0x%x)", (GLenum) (GLint) param[0]);
517	    return;
518	 }
519	 if (!((1 << ((GLenum) (GLint) param[0] - GL_TEXTURE0)) & ctx->Const.SupportedBumpUnits)) {
520	    _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", (GLenum) (GLint) param[0]);
521	    return;
522	 }
523	 else {
524	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
525	    texUnit->BumpTarget = (GLenum) (GLint) param[0];
526	 }
527	 break;
528      default:
529	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
530	 return;
531      }
532   }
533   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
534      /* GL_EXT_texture_lod_bias */
535      if (!ctx->Extensions.EXT_texture_lod_bias) {
536	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
537	 return;
538      }
539      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
540	 if (texUnit->LodBias == param[0])
541	    return;
542	 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
543         texUnit->LodBias = param[0];
544      }
545      else {
546         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
547	 return;
548      }
549   }
550   else if (target == GL_POINT_SPRITE_NV) {
551      /* GL_ARB_point_sprite / GL_NV_point_sprite */
552      if (!ctx->Extensions.NV_point_sprite
553	  && !ctx->Extensions.ARB_point_sprite) {
554	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
555	 return;
556      }
557      if (pname == GL_COORD_REPLACE_NV) {
558         const GLenum value = (GLenum) param[0];
559         if (value == GL_TRUE || value == GL_FALSE) {
560            /* It's kind of weird to set point state via glTexEnv,
561             * but that's what the spec calls for.
562             */
563            const GLboolean state = (GLboolean) value;
564            if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state)
565               return;
566            FLUSH_VERTICES(ctx, _NEW_POINT);
567            ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state;
568         }
569         else {
570            _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", value);
571            return;
572         }
573      }
574      else {
575         _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
576         return;
577      }
578   }
579   else {
580      _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)",target );
581      return;
582   }
583
584   if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
585      _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n",
586                  _mesa_lookup_enum_by_nr(target),
587                  _mesa_lookup_enum_by_nr(pname),
588                  *param,
589                  _mesa_lookup_enum_by_nr((GLenum) (GLint) *param));
590
591   /* Tell device driver about the new texture environment */
592   if (ctx->Driver.TexEnv) {
593      (*ctx->Driver.TexEnv)( ctx, target, pname, param );
594   }
595}
596
597
598void GLAPIENTRY
599_mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
600{
601   GLfloat p[4];
602   p[0] = param;
603   p[1] = p[2] = p[3] = 0.0;
604   _mesa_TexEnvfv( target, pname, p );
605}
606
607
608
609void GLAPIENTRY
610_mesa_TexEnvi( GLenum target, GLenum pname, GLint param )
611{
612   GLfloat p[4];
613   p[0] = (GLfloat) param;
614   p[1] = p[2] = p[3] = 0.0;
615   _mesa_TexEnvfv( target, pname, p );
616}
617
618
619void GLAPIENTRY
620_mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
621{
622   GLfloat p[4];
623   if (pname == GL_TEXTURE_ENV_COLOR) {
624      p[0] = INT_TO_FLOAT( param[0] );
625      p[1] = INT_TO_FLOAT( param[1] );
626      p[2] = INT_TO_FLOAT( param[2] );
627      p[3] = INT_TO_FLOAT( param[3] );
628   }
629   else {
630      p[0] = (GLfloat) param[0];
631      p[1] = p[2] = p[3] = 0;  /* init to zero, just to be safe */
632   }
633   _mesa_TexEnvfv( target, pname, p );
634}
635
636
637
638/**
639 * Helper for glGetTexEnvi/f()
640 * \return  value of queried pname or -1 if error.
641 */
642static GLint
643get_texenvi(GLcontext *ctx, const struct gl_texture_unit *texUnit,
644            GLenum pname)
645{
646   switch (pname) {
647   case GL_TEXTURE_ENV_MODE:
648      return texUnit->EnvMode;
649      break;
650   case GL_COMBINE_RGB:
651      if (ctx->Extensions.EXT_texture_env_combine ||
652          ctx->Extensions.ARB_texture_env_combine) {
653         return texUnit->Combine.ModeRGB;
654      }
655      else {
656         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
657      }
658      break;
659   case GL_COMBINE_ALPHA:
660      if (ctx->Extensions.EXT_texture_env_combine ||
661          ctx->Extensions.ARB_texture_env_combine) {
662         return texUnit->Combine.ModeA;
663      }
664      else {
665         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
666      }
667      break;
668   case GL_SOURCE0_RGB:
669   case GL_SOURCE1_RGB:
670   case GL_SOURCE2_RGB:
671      if (ctx->Extensions.EXT_texture_env_combine ||
672          ctx->Extensions.ARB_texture_env_combine) {
673         const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
674         return texUnit->Combine.SourceRGB[rgb_idx];
675      }
676      else {
677         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
678      }
679      break;
680   case GL_SOURCE3_RGB_NV:
681      if (ctx->Extensions.NV_texture_env_combine4) {
682         return texUnit->Combine.SourceRGB[3];
683      }
684      else {
685         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
686      }
687      break;
688   case GL_SOURCE0_ALPHA:
689   case GL_SOURCE1_ALPHA:
690   case GL_SOURCE2_ALPHA:
691      if (ctx->Extensions.EXT_texture_env_combine ||
692          ctx->Extensions.ARB_texture_env_combine) {
693         const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
694         return texUnit->Combine.SourceA[alpha_idx];
695      }
696      else {
697         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
698      }
699      break;
700   case GL_SOURCE3_ALPHA_NV:
701      if (ctx->Extensions.NV_texture_env_combine4) {
702         return texUnit->Combine.SourceA[3];
703      }
704      else {
705         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
706      }
707      break;
708   case GL_OPERAND0_RGB:
709   case GL_OPERAND1_RGB:
710   case GL_OPERAND2_RGB:
711      if (ctx->Extensions.EXT_texture_env_combine ||
712          ctx->Extensions.ARB_texture_env_combine) {
713         const unsigned op_rgb = pname - GL_OPERAND0_RGB;
714         return texUnit->Combine.OperandRGB[op_rgb];
715      }
716      else {
717         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
718      }
719      break;
720   case GL_OPERAND3_RGB_NV:
721      if (ctx->Extensions.NV_texture_env_combine4) {
722         return texUnit->Combine.OperandRGB[3];
723      }
724      else {
725         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
726      }
727      break;
728   case GL_OPERAND0_ALPHA:
729   case GL_OPERAND1_ALPHA:
730   case GL_OPERAND2_ALPHA:
731      if (ctx->Extensions.EXT_texture_env_combine ||
732          ctx->Extensions.ARB_texture_env_combine) {
733         const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
734         return texUnit->Combine.OperandA[op_alpha];
735      }
736      else {
737         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
738      }
739      break;
740   case GL_OPERAND3_ALPHA_NV:
741      if (ctx->Extensions.NV_texture_env_combine4) {
742         return texUnit->Combine.OperandA[3];
743      }
744      else {
745         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
746      }
747      break;
748   case GL_RGB_SCALE:
749      if (ctx->Extensions.EXT_texture_env_combine ||
750          ctx->Extensions.ARB_texture_env_combine) {
751         return 1 << texUnit->Combine.ScaleShiftRGB;
752      }
753      else {
754         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
755      }
756      break;
757   case GL_ALPHA_SCALE:
758      if (ctx->Extensions.EXT_texture_env_combine ||
759          ctx->Extensions.ARB_texture_env_combine) {
760         return 1 << texUnit->Combine.ScaleShiftA;
761      }
762      else {
763         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
764      }
765      break;
766   case GL_BUMP_TARGET_ATI:
767      /* spec doesn't say so, but I think this should be queryable */
768      if (ctx->Extensions.ATI_envmap_bumpmap) {
769         return texUnit->BumpTarget;
770      }
771      else {
772         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
773      }
774      break;
775
776   default:
777      ;
778   }
779
780   return -1; /* error */
781}
782
783
784
785void GLAPIENTRY
786_mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
787{
788   GLuint maxUnit;
789   const struct gl_texture_unit *texUnit;
790   GET_CURRENT_CONTEXT(ctx);
791   ASSERT_OUTSIDE_BEGIN_END(ctx);
792
793   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
794      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
795   if (ctx->Texture.CurrentUnit >= maxUnit) {
796      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
797      return;
798   }
799
800   texUnit = _mesa_get_current_tex_unit(ctx);
801
802   if (target == GL_TEXTURE_ENV) {
803      if (pname == GL_TEXTURE_ENV_COLOR) {
804         COPY_4FV( params, texUnit->EnvColor );
805      }
806      else {
807         GLint val = get_texenvi(ctx, texUnit, pname);
808         if (val >= 0) {
809            *params = (GLfloat) val;
810         }
811      }
812   }
813   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
814      /* GL_EXT_texture_lod_bias */
815      if (!ctx->Extensions.EXT_texture_lod_bias) {
816	 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
817	 return;
818      }
819      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
820         *params = texUnit->LodBias;
821      }
822      else {
823         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
824	 return;
825      }
826   }
827   else if (target == GL_POINT_SPRITE_NV) {
828      /* GL_ARB_point_sprite / GL_NV_point_sprite */
829      if (!ctx->Extensions.NV_point_sprite
830	  && !ctx->Extensions.ARB_point_sprite) {
831         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
832         return;
833      }
834      if (pname == GL_COORD_REPLACE_NV) {
835         *params = (GLfloat) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
836      }
837      else {
838         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
839         return;
840      }
841   }
842   else {
843      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
844      return;
845   }
846}
847
848
849void GLAPIENTRY
850_mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
851{
852   GLuint maxUnit;
853   const struct gl_texture_unit *texUnit;
854   GET_CURRENT_CONTEXT(ctx);
855   ASSERT_OUTSIDE_BEGIN_END(ctx);
856
857   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
858      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
859   if (ctx->Texture.CurrentUnit >= maxUnit) {
860      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
861      return;
862   }
863
864   texUnit = _mesa_get_current_tex_unit(ctx);
865
866   if (target == GL_TEXTURE_ENV) {
867      if (pname == GL_TEXTURE_ENV_COLOR) {
868         params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
869         params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
870         params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
871         params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
872      }
873      else {
874         GLint val = get_texenvi(ctx, texUnit, pname);
875         if (val >= 0) {
876            *params = val;
877         }
878      }
879   }
880   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
881      /* GL_EXT_texture_lod_bias */
882      if (!ctx->Extensions.EXT_texture_lod_bias) {
883	 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
884	 return;
885      }
886      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
887         *params = (GLint) texUnit->LodBias;
888      }
889      else {
890         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
891	 return;
892      }
893   }
894   else if (target == GL_POINT_SPRITE_NV) {
895      /* GL_ARB_point_sprite / GL_NV_point_sprite */
896      if (!ctx->Extensions.NV_point_sprite
897	  && !ctx->Extensions.ARB_point_sprite) {
898         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
899         return;
900      }
901      if (pname == GL_COORD_REPLACE_NV) {
902         *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
903      }
904      else {
905         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
906         return;
907      }
908   }
909   else {
910      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
911      return;
912   }
913}
914
915
916/**
917 * Why does ATI_envmap_bumpmap require new entrypoints? Should just
918 * reuse TexEnv ones...
919 */
920void GLAPIENTRY
921_mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
922{
923   GLfloat p[4];
924   GET_CURRENT_CONTEXT(ctx);
925   ASSERT_OUTSIDE_BEGIN_END(ctx);
926
927   if (!ctx->Extensions.ATI_envmap_bumpmap) {
928      /* This isn't an "official" error case, but let's tell the user
929       * that something's wrong.
930       */
931      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
932      return;
933   }
934
935   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
936      /* hope that conversion is correct here */
937      p[0] = INT_TO_FLOAT( param[0] );
938      p[1] = INT_TO_FLOAT( param[1] );
939      p[2] = INT_TO_FLOAT( param[2] );
940      p[3] = INT_TO_FLOAT( param[3] );
941   }
942   else {
943      p[0] = (GLfloat) param[0];
944      p[1] = p[2] = p[3] = 0.0F;  /* init to zero, just to be safe */
945   }
946   _mesa_TexBumpParameterfvATI( pname, p );
947}
948
949
950void GLAPIENTRY
951_mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
952{
953   struct gl_texture_unit *texUnit;
954   GET_CURRENT_CONTEXT(ctx);
955   ASSERT_OUTSIDE_BEGIN_END(ctx);
956
957   if (!ctx->Extensions.ATI_envmap_bumpmap) {
958      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
959      return;
960   }
961
962   texUnit = _mesa_get_current_tex_unit(ctx);
963
964   if (pname == GL_BUMP_ROT_MATRIX_ATI) {
965      if (TEST_EQ_4V(param, texUnit->RotMatrix))
966         return;
967      FLUSH_VERTICES(ctx, _NEW_TEXTURE);
968      COPY_4FV(texUnit->RotMatrix, param);
969   }
970   else {
971      _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
972      return;
973   }
974   /* Drivers might want to know about this, instead of dedicated function
975      just shove it into TexEnv where it really belongs anyway */
976   if (ctx->Driver.TexEnv) {
977      (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
978   }
979}
980
981
982void GLAPIENTRY
983_mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
984{
985   const struct gl_texture_unit *texUnit;
986   GLuint i;
987   GET_CURRENT_CONTEXT(ctx);
988   ASSERT_OUTSIDE_BEGIN_END(ctx);
989
990   if (!ctx->Extensions.ATI_envmap_bumpmap) {
991      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
992      return;
993   }
994
995   texUnit = _mesa_get_current_tex_unit(ctx);
996
997   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
998      /* spec leaves open to support larger matrices.
999         Don't think anyone would ever want to use it
1000         (and apps almost certainly would not understand it and
1001         thus fail to submit matrices correctly) so hardcode this. */
1002      *param = 4;
1003   }
1004   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
1005      /* hope that conversion is correct here */
1006      param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
1007      param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
1008      param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
1009      param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
1010   }
1011   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
1012      GLint count = 0;
1013      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1014         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1015            count++;
1016         }
1017      }
1018      *param = count;
1019   }
1020   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
1021      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1022         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1023            *param++ = i + GL_TEXTURE0;
1024         }
1025      }
1026   }
1027   else {
1028      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
1029      return;
1030   }
1031}
1032
1033
1034void GLAPIENTRY
1035_mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
1036{
1037   const struct gl_texture_unit *texUnit;
1038   GLuint i;
1039   GET_CURRENT_CONTEXT(ctx);
1040   ASSERT_OUTSIDE_BEGIN_END(ctx);
1041
1042   if (!ctx->Extensions.ATI_envmap_bumpmap) {
1043      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
1044      return;
1045   }
1046
1047   texUnit = _mesa_get_current_tex_unit(ctx);
1048
1049   if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
1050      /* spec leaves open to support larger matrices.
1051         Don't think anyone would ever want to use it
1052         (and apps might not understand it) so hardcode this. */
1053      *param = 4.0F;
1054   }
1055   else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
1056      param[0] = texUnit->RotMatrix[0];
1057      param[1] = texUnit->RotMatrix[1];
1058      param[2] = texUnit->RotMatrix[2];
1059      param[3] = texUnit->RotMatrix[3];
1060   }
1061   else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
1062      GLint count = 0;
1063      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1064         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1065            count++;
1066         }
1067      }
1068      *param = (GLfloat) count;
1069   }
1070   else if (pname == GL_BUMP_TEX_UNITS_ATI) {
1071      for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1072         if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1073            *param++ = (GLfloat) (i + GL_TEXTURE0);
1074         }
1075      }
1076   }
1077   else {
1078      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
1079      return;
1080   }
1081}
1082