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