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