texenv.c revision c1f859d4
1/*
2 * Mesa 3-D graphics library
3 * Version:  7.1
4 *
5 * Copyright (C) 1999-2008  Brian Paul   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 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25/**
26 * \file texenv.c
27 *
28 * glTexEnv-related functions
29 */
30
31
32#include "main/glheader.h"
33#include "main/context.h"
34#include "main/enums.h"
35#include "main/macros.h"
36#include "main/texenv.h"
37#include "math/m_xform.h"
38
39
40
41void GLAPIENTRY
42_mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
43{
44   GLuint maxUnit;
45   GET_CURRENT_CONTEXT(ctx);
46   struct gl_texture_unit *texUnit;
47   ASSERT_OUTSIDE_BEGIN_END(ctx);
48
49   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
50      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
51   if (ctx->Texture.CurrentUnit >= maxUnit) {
52      _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
53      return;
54   }
55
56   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
57
58#define TE_ERROR(errCode, msg, value)				\
59   _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
60
61   if (target == GL_TEXTURE_ENV) {
62      switch (pname) {
63      case GL_TEXTURE_ENV_MODE:
64         {
65            GLenum mode = (GLenum) (GLint) *param;
66            if (mode == GL_REPLACE_EXT)
67               mode = GL_REPLACE;
68	    if (texUnit->EnvMode == mode)
69	       return;
70            if (mode == GL_MODULATE ||
71                mode == GL_BLEND ||
72                mode == GL_DECAL ||
73                mode == GL_REPLACE ||
74                (mode == GL_ADD && ctx->Extensions.EXT_texture_env_add) ||
75                (mode == GL_COMBINE &&
76                 (ctx->Extensions.EXT_texture_env_combine ||
77                  ctx->Extensions.ARB_texture_env_combine))) {
78               /* legal */
79               FLUSH_VERTICES(ctx, _NEW_TEXTURE);
80               texUnit->EnvMode = mode;
81            }
82            else {
83               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
84               return;
85            }
86         }
87         break;
88      case GL_TEXTURE_ENV_COLOR:
89         {
90            GLfloat tmp[4];
91            tmp[0] = CLAMP( param[0], 0.0F, 1.0F );
92            tmp[1] = CLAMP( param[1], 0.0F, 1.0F );
93            tmp[2] = CLAMP( param[2], 0.0F, 1.0F );
94            tmp[3] = CLAMP( param[3], 0.0F, 1.0F );
95            if (TEST_EQ_4V(tmp, texUnit->EnvColor))
96               return;
97            FLUSH_VERTICES(ctx, _NEW_TEXTURE);
98            COPY_4FV(texUnit->EnvColor, tmp);
99         }
100         break;
101      case GL_COMBINE_RGB:
102	 if (ctx->Extensions.EXT_texture_env_combine ||
103             ctx->Extensions.ARB_texture_env_combine) {
104	    const GLenum mode = (GLenum) (GLint) *param;
105	    if (texUnit->Combine.ModeRGB == mode)
106	       return;
107	    switch (mode) {
108	    case GL_REPLACE:
109	    case GL_MODULATE:
110	    case GL_ADD:
111	    case GL_ADD_SIGNED:
112	    case GL_INTERPOLATE:
113               /* OK */
114	       break;
115            case GL_SUBTRACT:
116               if (!ctx->Extensions.ARB_texture_env_combine) {
117                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
118                  return;
119               }
120               break;
121	    case GL_DOT3_RGB_EXT:
122	    case GL_DOT3_RGBA_EXT:
123	       if (!ctx->Extensions.EXT_texture_env_dot3) {
124                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
125		  return;
126	       }
127	       break;
128	    case GL_DOT3_RGB:
129	    case GL_DOT3_RGBA:
130	       if (!ctx->Extensions.ARB_texture_env_dot3) {
131                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
132		  return;
133	       }
134	       break;
135	    case GL_MODULATE_ADD_ATI:
136	    case GL_MODULATE_SIGNED_ADD_ATI:
137	    case GL_MODULATE_SUBTRACT_ATI:
138	       if (!ctx->Extensions.ATI_texture_env_combine3) {
139                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
140		  return;
141	       }
142	       break;
143	    default:
144               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
145	       return;
146	    }
147	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
148	    texUnit->Combine.ModeRGB = mode;
149	 }
150	 else {
151            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
152	    return;
153	 }
154         break;
155      case GL_COMBINE_ALPHA:
156	 if (ctx->Extensions.EXT_texture_env_combine ||
157             ctx->Extensions.ARB_texture_env_combine) {
158	    const GLenum mode = (GLenum) (GLint) *param;
159	    if (texUnit->Combine.ModeA == mode)
160	       return;
161            switch (mode) {
162	    case GL_REPLACE:
163	    case GL_MODULATE:
164	    case GL_ADD:
165	    case GL_ADD_SIGNED:
166	    case GL_INTERPOLATE:
167	       /* OK */
168	       break;
169	    case GL_SUBTRACT:
170	       if (!ctx->Extensions.ARB_texture_env_combine) {
171		  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
172		  return;
173	       }
174	       break;
175	    case GL_MODULATE_ADD_ATI:
176	    case GL_MODULATE_SIGNED_ADD_ATI:
177	    case GL_MODULATE_SUBTRACT_ATI:
178	       if (!ctx->Extensions.ATI_texture_env_combine3) {
179                  TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
180		  return;
181	       }
182	       break;
183	    default:
184	       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
185	       return;
186	    }
187	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
188	    texUnit->Combine.ModeA = mode;
189	 }
190	 else {
191            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
192	    return;
193	 }
194	 break;
195      case GL_SOURCE0_RGB:
196      case GL_SOURCE1_RGB:
197      case GL_SOURCE2_RGB:
198	 if (ctx->Extensions.EXT_texture_env_combine ||
199	     ctx->Extensions.ARB_texture_env_combine) {
200	    const GLenum source = (GLenum) (GLint) *param;
201	    const GLuint s = pname - GL_SOURCE0_RGB;
202	    if (texUnit->Combine.SourceRGB[s] == source)
203	       return;
204            if (source == GL_TEXTURE ||
205                source == GL_CONSTANT ||
206                source == GL_PRIMARY_COLOR ||
207                source == GL_PREVIOUS ||
208                (ctx->Extensions.ARB_texture_env_crossbar &&
209                 source >= GL_TEXTURE0 &&
210                 source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) ||
211                (ctx->Extensions.ATI_texture_env_combine3 &&
212                 (source == GL_ZERO || source == GL_ONE))) {
213               /* legal */
214	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
215	       texUnit->Combine.SourceRGB[s] = source;
216            }
217            else {
218               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source);
219	       return;
220	    }
221	 }
222	 else {
223            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
224	    return;
225	 }
226	 break;
227      case GL_SOURCE0_ALPHA:
228      case GL_SOURCE1_ALPHA:
229      case GL_SOURCE2_ALPHA:
230	 if (ctx->Extensions.EXT_texture_env_combine ||
231             ctx->Extensions.ARB_texture_env_combine) {
232	    const GLenum source = (GLenum) (GLint) *param;
233	    const GLuint s = pname - GL_SOURCE0_ALPHA;
234	    if (texUnit->Combine.SourceA[s] == source)
235	       return;
236            if (source == GL_TEXTURE ||
237                source == GL_CONSTANT ||
238                source == GL_PRIMARY_COLOR ||
239                source == GL_PREVIOUS ||
240                (ctx->Extensions.ARB_texture_env_crossbar &&
241                 source >= GL_TEXTURE0 &&
242                 source < GL_TEXTURE0 + ctx->Const.MaxTextureUnits) ||
243		(ctx->Extensions.ATI_texture_env_combine3 &&
244                 (source == GL_ZERO || source == GL_ONE))) {
245               /* legal */
246	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
247	       texUnit->Combine.SourceA[s] = source;
248            }
249            else {
250               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", source);
251	       return;
252	    }
253	 }
254	 else {
255            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
256	    return;
257	 }
258	 break;
259      case GL_OPERAND0_RGB:
260      case GL_OPERAND1_RGB:
261	 if (ctx->Extensions.EXT_texture_env_combine ||
262	     ctx->Extensions.ARB_texture_env_combine) {
263	    const GLenum operand = (GLenum) (GLint) *param;
264	    const GLuint s = pname - GL_OPERAND0_RGB;
265	    if (texUnit->Combine.OperandRGB[s] == operand)
266	       return;
267	    switch (operand) {
268	    case GL_SRC_COLOR:
269	    case GL_ONE_MINUS_SRC_COLOR:
270	    case GL_SRC_ALPHA:
271	    case GL_ONE_MINUS_SRC_ALPHA:
272	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
273	       texUnit->Combine.OperandRGB[s] = operand;
274	       break;
275	    default:
276               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
277	       return;
278	    }
279	 }
280	 else {
281            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
282	    return;
283	 }
284	 break;
285      case GL_OPERAND0_ALPHA:
286      case GL_OPERAND1_ALPHA:
287	 if (ctx->Extensions.EXT_texture_env_combine ||
288             ctx->Extensions.ARB_texture_env_combine) {
289	    const GLenum operand = (GLenum) (GLint) *param;
290	    if (texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] == operand)
291	       return;
292	    switch (operand) {
293	    case GL_SRC_ALPHA:
294	    case GL_ONE_MINUS_SRC_ALPHA:
295	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
296	       texUnit->Combine.OperandA[pname-GL_OPERAND0_ALPHA] = operand;
297	       break;
298	    default:
299               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
300	       return;
301	    }
302	 }
303	 else {
304            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
305	    return;
306	 }
307	 break;
308      case GL_OPERAND2_RGB:
309	 if (ctx->Extensions.ARB_texture_env_combine) {
310	    const GLenum operand = (GLenum) (GLint) *param;
311	    if (texUnit->Combine.OperandRGB[2] == operand)
312	       return;
313	    switch (operand) {
314	    case GL_SRC_COLOR:           /* ARB combine only */
315	    case GL_ONE_MINUS_SRC_COLOR: /* ARB combine only */
316	    case GL_SRC_ALPHA:
317	    case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */
318	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
319	       texUnit->Combine.OperandRGB[2] = operand;
320               break;
321	    default:
322               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
323	       return;
324	    }
325	 }
326	 else if (ctx->Extensions.EXT_texture_env_combine) {
327	    const GLenum operand = (GLenum) (GLint) *param;
328	    if (texUnit->Combine.OperandRGB[2] == operand)
329	       return;
330	    /* operand must be GL_SRC_ALPHA which is the initial value - thus
331	       don't need to actually compare the operand to the possible value */
332	    else {
333               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
334	       return;
335	    }
336	 }
337	 else {
338            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
339	    return;
340	 }
341	 break;
342      case GL_OPERAND2_ALPHA:
343	 if (ctx->Extensions.ARB_texture_env_combine) {
344	    const GLenum operand = (GLenum) (GLint) *param;
345	    if (texUnit->Combine.OperandA[2] == operand)
346	       return;
347	    switch (operand) {
348	    case GL_SRC_ALPHA:
349	    case GL_ONE_MINUS_SRC_ALPHA: /* ARB combine only */
350	       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
351	       texUnit->Combine.OperandA[2] = operand;
352	       break;
353	    default:
354               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
355	       return;
356	    }
357	 }
358	 else if (ctx->Extensions.EXT_texture_env_combine) {
359	    const GLenum operand = (GLenum) (GLint) *param;
360	    if (texUnit->Combine.OperandA[2] == operand)
361	       return;
362	    /* operand must be GL_SRC_ALPHA which is the initial value - thus
363	       don't need to actually compare the operand to the possible value */
364	    else {
365               TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", operand);
366	       return;
367	    }
368	 }
369	 else {
370            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
371	    return;
372	 }
373	 break;
374      case GL_RGB_SCALE:
375	 if (ctx->Extensions.EXT_texture_env_combine ||
376             ctx->Extensions.ARB_texture_env_combine) {
377	    GLuint newshift;
378	    if (*param == 1.0) {
379	       newshift = 0;
380	    }
381	    else if (*param == 2.0) {
382	       newshift = 1;
383	    }
384	    else if (*param == 4.0) {
385	       newshift = 2;
386	    }
387	    else {
388	       _mesa_error( ctx, GL_INVALID_VALUE,
389                            "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
390	       return;
391	    }
392	    if (texUnit->Combine.ScaleShiftRGB == newshift)
393	       return;
394	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
395	    texUnit->Combine.ScaleShiftRGB = newshift;
396	 }
397	 else {
398            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
399	    return;
400	 }
401	 break;
402      case GL_ALPHA_SCALE:
403	 if (ctx->Extensions.EXT_texture_env_combine ||
404             ctx->Extensions.ARB_texture_env_combine) {
405	    GLuint newshift;
406	    if (*param == 1.0) {
407	       newshift = 0;
408	    }
409	    else if (*param == 2.0) {
410	       newshift = 1;
411	    }
412	    else if (*param == 4.0) {
413	       newshift = 2;
414	    }
415	    else {
416	       _mesa_error( ctx, GL_INVALID_VALUE,
417                            "glTexEnv(GL_ALPHA_SCALE not 1, 2 or 4)" );
418	       return;
419	    }
420	    if (texUnit->Combine.ScaleShiftA == newshift)
421	       return;
422	    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
423	    texUnit->Combine.ScaleShiftA = newshift;
424	 }
425	 else {
426            TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
427	    return;
428	 }
429	 break;
430      default:
431	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
432	 return;
433      }
434   }
435   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
436      /* GL_EXT_texture_lod_bias */
437      if (!ctx->Extensions.EXT_texture_lod_bias) {
438	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
439	 return;
440      }
441      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
442	 if (texUnit->LodBias == param[0])
443	    return;
444	 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
445         texUnit->LodBias = param[0];
446      }
447      else {
448         TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
449	 return;
450      }
451   }
452   else if (target == GL_POINT_SPRITE_NV) {
453      /* GL_ARB_point_sprite / GL_NV_point_sprite */
454      if (!ctx->Extensions.NV_point_sprite
455	  && !ctx->Extensions.ARB_point_sprite) {
456	 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
457	 return;
458      }
459      if (pname == GL_COORD_REPLACE_NV) {
460         const GLenum value = (GLenum) param[0];
461         if (value == GL_TRUE || value == GL_FALSE) {
462            /* It's kind of weird to set point state via glTexEnv,
463             * but that's what the spec calls for.
464             */
465            const GLboolean state = (GLboolean) value;
466            if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state)
467               return;
468            FLUSH_VERTICES(ctx, _NEW_POINT);
469            ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state;
470         }
471         else {
472            _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", value);
473            return;
474         }
475      }
476      else {
477         _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
478         return;
479      }
480   }
481   else {
482      _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)",target );
483      return;
484   }
485
486   if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
487      _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n",
488                  _mesa_lookup_enum_by_nr(target),
489                  _mesa_lookup_enum_by_nr(pname),
490                  *param,
491                  _mesa_lookup_enum_by_nr((GLenum) (GLint) *param));
492
493   /* Tell device driver about the new texture environment */
494   if (ctx->Driver.TexEnv) {
495      (*ctx->Driver.TexEnv)( ctx, target, pname, param );
496   }
497}
498
499
500void GLAPIENTRY
501_mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
502{
503   _mesa_TexEnvfv( target, pname, &param );
504}
505
506
507
508void GLAPIENTRY
509_mesa_TexEnvi( GLenum target, GLenum pname, GLint param )
510{
511   GLfloat p[4];
512   p[0] = (GLfloat) param;
513   p[1] = p[2] = p[3] = 0.0;
514   _mesa_TexEnvfv( target, pname, p );
515}
516
517
518void GLAPIENTRY
519_mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
520{
521   GLfloat p[4];
522   if (pname == GL_TEXTURE_ENV_COLOR) {
523      p[0] = INT_TO_FLOAT( param[0] );
524      p[1] = INT_TO_FLOAT( param[1] );
525      p[2] = INT_TO_FLOAT( param[2] );
526      p[3] = INT_TO_FLOAT( param[3] );
527   }
528   else {
529      p[0] = (GLfloat) param[0];
530      p[1] = p[2] = p[3] = 0;  /* init to zero, just to be safe */
531   }
532   _mesa_TexEnvfv( target, pname, p );
533}
534
535
536
537/**
538 * Helper for glGetTexEnvi/f()
539 * \return  value of queried pname or -1 if error.
540 */
541static GLint
542get_texenvi(GLcontext *ctx, const struct gl_texture_unit *texUnit,
543            GLenum pname)
544{
545   switch (pname) {
546   case GL_TEXTURE_ENV_MODE:
547      return texUnit->EnvMode;
548      break;
549   case GL_COMBINE_RGB:
550      if (ctx->Extensions.EXT_texture_env_combine ||
551          ctx->Extensions.ARB_texture_env_combine) {
552         return texUnit->Combine.ModeRGB;
553      }
554      else {
555         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
556      }
557      break;
558   case GL_COMBINE_ALPHA:
559      if (ctx->Extensions.EXT_texture_env_combine ||
560          ctx->Extensions.ARB_texture_env_combine) {
561         return texUnit->Combine.ModeA;
562      }
563      else {
564         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
565      }
566      break;
567   case GL_SOURCE0_RGB:
568   case GL_SOURCE1_RGB:
569   case GL_SOURCE2_RGB:
570      if (ctx->Extensions.EXT_texture_env_combine ||
571          ctx->Extensions.ARB_texture_env_combine) {
572         const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
573         return texUnit->Combine.SourceRGB[rgb_idx];
574      }
575      else {
576         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
577      }
578      break;
579   case GL_SOURCE0_ALPHA:
580   case GL_SOURCE1_ALPHA:
581   case GL_SOURCE2_ALPHA:
582      if (ctx->Extensions.EXT_texture_env_combine ||
583          ctx->Extensions.ARB_texture_env_combine) {
584         const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
585         return texUnit->Combine.SourceA[alpha_idx];
586      }
587      else {
588         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
589      }
590      break;
591   case GL_OPERAND0_RGB:
592   case GL_OPERAND1_RGB:
593   case GL_OPERAND2_RGB:
594      if (ctx->Extensions.EXT_texture_env_combine ||
595          ctx->Extensions.ARB_texture_env_combine) {
596         const unsigned op_rgb = pname - GL_OPERAND0_RGB;
597         return texUnit->Combine.OperandRGB[op_rgb];
598      }
599      else {
600         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
601      }
602      break;
603   case GL_OPERAND0_ALPHA:
604   case GL_OPERAND1_ALPHA:
605   case GL_OPERAND2_ALPHA:
606      if (ctx->Extensions.EXT_texture_env_combine ||
607          ctx->Extensions.ARB_texture_env_combine) {
608         const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
609         return texUnit->Combine.OperandA[op_alpha];
610      }
611      else {
612         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
613      }
614      break;
615   case GL_RGB_SCALE:
616      if (ctx->Extensions.EXT_texture_env_combine ||
617          ctx->Extensions.ARB_texture_env_combine) {
618         return 1 << texUnit->Combine.ScaleShiftRGB;
619      }
620      else {
621         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
622      }
623      break;
624   case GL_ALPHA_SCALE:
625      if (ctx->Extensions.EXT_texture_env_combine ||
626          ctx->Extensions.ARB_texture_env_combine) {
627         return 1 << texUnit->Combine.ScaleShiftA;
628      }
629      else {
630         _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
631      }
632      break;
633   default:
634      ;
635   }
636
637   return -1; /* error */
638}
639
640
641
642void GLAPIENTRY
643_mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
644{
645   GLuint maxUnit;
646   const struct gl_texture_unit *texUnit;
647   GET_CURRENT_CONTEXT(ctx);
648   ASSERT_OUTSIDE_BEGIN_END(ctx);
649
650   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
651      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
652   if (ctx->Texture.CurrentUnit >= maxUnit) {
653      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
654      return;
655   }
656
657   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
658
659   if (target == GL_TEXTURE_ENV) {
660      if (pname == GL_TEXTURE_ENV_COLOR) {
661         COPY_4FV( params, texUnit->EnvColor );
662      }
663      else {
664         GLint val = get_texenvi(ctx, texUnit, pname);
665         if (val >= 0) {
666            *params = (GLfloat) val;
667         }
668      }
669   }
670   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
671      /* GL_EXT_texture_lod_bias */
672      if (!ctx->Extensions.EXT_texture_lod_bias) {
673	 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
674	 return;
675      }
676      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
677         *params = texUnit->LodBias;
678      }
679      else {
680         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
681	 return;
682      }
683   }
684   else if (target == GL_POINT_SPRITE_NV) {
685      /* GL_ARB_point_sprite / GL_NV_point_sprite */
686      if (!ctx->Extensions.NV_point_sprite
687	  && !ctx->Extensions.ARB_point_sprite) {
688         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
689         return;
690      }
691      if (pname == GL_COORD_REPLACE_NV) {
692         *params = (GLfloat) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
693      }
694      else {
695         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
696         return;
697      }
698   }
699   else {
700      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
701      return;
702   }
703}
704
705
706void GLAPIENTRY
707_mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
708{
709   GLuint maxUnit;
710   const struct gl_texture_unit *texUnit;
711   GET_CURRENT_CONTEXT(ctx);
712   ASSERT_OUTSIDE_BEGIN_END(ctx);
713
714   maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
715      ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxTextureImageUnits;
716   if (ctx->Texture.CurrentUnit >= maxUnit) {
717      _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
718      return;
719   }
720
721   texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit];
722
723   if (target == GL_TEXTURE_ENV) {
724      if (pname == GL_TEXTURE_ENV_COLOR) {
725         params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
726         params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
727         params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
728         params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
729      }
730      else {
731         GLint val = get_texenvi(ctx, texUnit, pname);
732         if (val >= 0) {
733            *params = val;
734         }
735      }
736   }
737   else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
738      /* GL_EXT_texture_lod_bias */
739      if (!ctx->Extensions.EXT_texture_lod_bias) {
740	 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
741	 return;
742      }
743      if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
744         *params = (GLint) texUnit->LodBias;
745      }
746      else {
747         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
748	 return;
749      }
750   }
751   else if (target == GL_POINT_SPRITE_NV) {
752      /* GL_ARB_point_sprite / GL_NV_point_sprite */
753      if (!ctx->Extensions.NV_point_sprite
754	  && !ctx->Extensions.ARB_point_sprite) {
755         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
756         return;
757      }
758      if (pname == GL_COORD_REPLACE_NV) {
759         *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
760      }
761      else {
762         _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
763         return;
764      }
765   }
766   else {
767      _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
768      return;
769   }
770}
771
772
773