Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / main / texenv.c
1 /*
2  * Mesa 3-D graphics library
3  * Version:  7.5
4  *
5  * Copyright (C) 1999-2008  Brian Paul   All Rights Reserved.
6  * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included
16  * in all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
21  * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22  * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
23  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  */
25
26 /** 
27  * \file texenv.c
28  *
29  * glTexEnv-related functions
30  */
31
32
33 #include "main/glheader.h"
34 #include "main/context.h"
35 #include "main/enums.h"
36 #include "main/macros.h"
37 #include "main/mtypes.h"
38 #include "main/state.h"
39 #include "main/texenv.h"
40 #include "main/texstate.h"
41
42
43 #define TE_ERROR(errCode, msg, value)                           \
44    _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
45
46
47 /** Set texture env mode */
48 static void
49 set_env_mode(struct gl_context *ctx,
50              struct gl_texture_unit *texUnit,
51              GLenum mode)
52 {
53    GLboolean legal;
54
55    if (texUnit->EnvMode == mode)
56       return;
57
58    switch (mode) {
59    case GL_MODULATE:
60    case GL_BLEND:
61    case GL_DECAL:
62    case GL_REPLACE:
63       legal = GL_TRUE;
64       break;
65    case GL_REPLACE_EXT:
66       mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
67       legal = GL_TRUE;
68       break;
69    case GL_ADD:
70       legal = ctx->Extensions.EXT_texture_env_add;
71       break;
72    case GL_COMBINE:
73       legal = (ctx->Extensions.EXT_texture_env_combine ||
74                ctx->Extensions.ARB_texture_env_combine);
75       break;
76    case GL_COMBINE4_NV:
77       legal = ctx->Extensions.NV_texture_env_combine4;
78       break;
79    default:
80       legal = GL_FALSE;
81    }
82
83    if (legal) {
84       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
85       texUnit->EnvMode = mode;
86    }
87    else {
88       TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
89    }
90 }
91
92
93 static void
94 set_env_color(struct gl_context *ctx,
95               struct gl_texture_unit *texUnit,
96               const GLfloat *color)
97 {
98    if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
99       return;
100    FLUSH_VERTICES(ctx, _NEW_TEXTURE);
101    COPY_4FV(texUnit->EnvColorUnclamped, color);
102    texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
103    texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
104    texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
105    texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
106 }
107
108
109 /** Set an RGB or A combiner mode/function */
110 static void
111 set_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 */
184 static void
185 set_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 */
277 static void
278 set_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
363 static void
364 set_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
411 void 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.MaxCombinedTextureImageUnits;
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
555 void 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
566 void 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
576 void 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  */
599 static GLint
600 get_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       _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
735       break;
736    }
737
738    return -1; /* error */
739 }
740
741
742
743 void GLAPIENTRY
744 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
745 {
746    GLuint maxUnit;
747    const struct gl_texture_unit *texUnit;
748    GET_CURRENT_CONTEXT(ctx);
749    ASSERT_OUTSIDE_BEGIN_END(ctx);
750
751    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
752       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
753    if (ctx->Texture.CurrentUnit >= maxUnit) {
754       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
755       return;
756    }
757
758    texUnit = _mesa_get_current_tex_unit(ctx);
759
760    if (target == GL_TEXTURE_ENV) {
761       if (pname == GL_TEXTURE_ENV_COLOR) {
762          if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP))
763             _mesa_update_state(ctx);
764          if(ctx->Color._ClampFragmentColor)
765             COPY_4FV( params, texUnit->EnvColor );
766          else
767             COPY_4FV( params, texUnit->EnvColorUnclamped );
768       }
769       else {
770          GLint val = get_texenvi(ctx, texUnit, pname);
771          if (val >= 0) {
772             *params = (GLfloat) val;
773          }
774       }
775    }
776    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
777       /* GL_EXT_texture_lod_bias */
778       if (!ctx->Extensions.EXT_texture_lod_bias) {
779          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
780          return;
781       }
782       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
783          *params = texUnit->LodBias;
784       }
785       else {
786          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
787          return;
788       }
789    }
790    else if (target == GL_POINT_SPRITE_NV) {
791       /* GL_ARB_point_sprite / GL_NV_point_sprite */
792       if (!ctx->Extensions.NV_point_sprite
793           && !ctx->Extensions.ARB_point_sprite) {
794          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
795          return;
796       }
797       if (pname == GL_COORD_REPLACE_NV) {
798          *params = (GLfloat) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
799       }
800       else {
801          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
802          return;
803       }
804    }
805    else {
806       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
807       return;
808    }
809 }
810
811
812 void GLAPIENTRY
813 _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
814 {
815    GLuint maxUnit;
816    const struct gl_texture_unit *texUnit;
817    GET_CURRENT_CONTEXT(ctx);
818    ASSERT_OUTSIDE_BEGIN_END(ctx);
819
820    maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
821       ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
822    if (ctx->Texture.CurrentUnit >= maxUnit) {
823       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
824       return;
825    }
826
827    texUnit = _mesa_get_current_tex_unit(ctx);
828
829    if (target == GL_TEXTURE_ENV) {
830       if (pname == GL_TEXTURE_ENV_COLOR) {
831          params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
832          params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
833          params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
834          params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
835       }
836       else {
837          GLint val = get_texenvi(ctx, texUnit, pname);
838          if (val >= 0) {
839             *params = val;
840          }
841       }
842    }
843    else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
844       /* GL_EXT_texture_lod_bias */
845       if (!ctx->Extensions.EXT_texture_lod_bias) {
846          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
847          return;
848       }
849       if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
850          *params = (GLint) texUnit->LodBias;
851       }
852       else {
853          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
854          return;
855       }
856    }
857    else if (target == GL_POINT_SPRITE_NV) {
858       /* GL_ARB_point_sprite / GL_NV_point_sprite */
859       if (!ctx->Extensions.NV_point_sprite
860           && !ctx->Extensions.ARB_point_sprite) {
861          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
862          return;
863       }
864       if (pname == GL_COORD_REPLACE_NV) {
865          *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
866       }
867       else {
868          _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
869          return;
870       }
871    }
872    else {
873       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
874       return;
875    }
876 }
877
878
879 /**
880  * Why does ATI_envmap_bumpmap require new entrypoints? Should just
881  * reuse TexEnv ones...
882  */
883 void GLAPIENTRY
884 _mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
885 {
886    GLfloat p[4];
887    GET_CURRENT_CONTEXT(ctx);
888    ASSERT_OUTSIDE_BEGIN_END(ctx);
889
890    if (!ctx->Extensions.ATI_envmap_bumpmap) {
891       /* This isn't an "official" error case, but let's tell the user
892        * that something's wrong.
893        */
894       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
895       return;
896    }
897
898    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
899       /* hope that conversion is correct here */
900       p[0] = INT_TO_FLOAT( param[0] );
901       p[1] = INT_TO_FLOAT( param[1] );
902       p[2] = INT_TO_FLOAT( param[2] );
903       p[3] = INT_TO_FLOAT( param[3] );
904    }
905    else {
906       p[0] = (GLfloat) param[0];
907       p[1] = p[2] = p[3] = 0.0F;  /* init to zero, just to be safe */
908    }
909    _mesa_TexBumpParameterfvATI( pname, p );
910 }
911
912
913 void GLAPIENTRY
914 _mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
915 {
916    struct gl_texture_unit *texUnit;
917    GET_CURRENT_CONTEXT(ctx);
918    ASSERT_OUTSIDE_BEGIN_END(ctx);
919
920    if (!ctx->Extensions.ATI_envmap_bumpmap) {
921       _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
922       return;
923    }
924
925    texUnit = _mesa_get_current_tex_unit(ctx);
926
927    if (pname == GL_BUMP_ROT_MATRIX_ATI) {
928       if (TEST_EQ_4V(param, texUnit->RotMatrix))
929          return;
930       FLUSH_VERTICES(ctx, _NEW_TEXTURE);
931       COPY_4FV(texUnit->RotMatrix, param);
932    }
933    else {
934       _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
935       return;
936    }
937    /* Drivers might want to know about this, instead of dedicated function
938       just shove it into TexEnv where it really belongs anyway */
939    if (ctx->Driver.TexEnv) {
940       (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
941    }
942 }
943
944
945 void GLAPIENTRY
946 _mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
947 {
948    const struct gl_texture_unit *texUnit;
949    GLuint i;
950    GET_CURRENT_CONTEXT(ctx);
951    ASSERT_OUTSIDE_BEGIN_END(ctx);
952
953    if (!ctx->Extensions.ATI_envmap_bumpmap) {
954       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
955       return;
956    }
957
958    texUnit = _mesa_get_current_tex_unit(ctx);
959
960    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
961       /* spec leaves open to support larger matrices.
962          Don't think anyone would ever want to use it
963          (and apps almost certainly would not understand it and
964          thus fail to submit matrices correctly) so hardcode this. */
965       *param = 4;
966    }
967    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
968       /* hope that conversion is correct here */
969       param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
970       param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
971       param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
972       param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
973    }
974    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
975       GLint count = 0;
976       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
977          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
978             count++;
979          }
980       }
981       *param = count;
982    }
983    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
984       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
985          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
986             *param++ = i + GL_TEXTURE0;
987          }
988       }
989    }
990    else {
991       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
992       return;
993    }
994 }
995
996
997 void GLAPIENTRY
998 _mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
999 {
1000    const struct gl_texture_unit *texUnit;
1001    GLuint i;
1002    GET_CURRENT_CONTEXT(ctx);
1003    ASSERT_OUTSIDE_BEGIN_END(ctx);
1004
1005    if (!ctx->Extensions.ATI_envmap_bumpmap) {
1006       _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
1007       return;
1008    }
1009
1010    texUnit = _mesa_get_current_tex_unit(ctx);
1011
1012    if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
1013       /* spec leaves open to support larger matrices.
1014          Don't think anyone would ever want to use it
1015          (and apps might not understand it) so hardcode this. */
1016       *param = 4.0F;
1017    }
1018    else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
1019       param[0] = texUnit->RotMatrix[0];
1020       param[1] = texUnit->RotMatrix[1];
1021       param[2] = texUnit->RotMatrix[2];
1022       param[3] = texUnit->RotMatrix[3];
1023    }
1024    else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
1025       GLint count = 0;
1026       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1027          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1028             count++;
1029          }
1030       }
1031       *param = (GLfloat) count;
1032    }
1033    else if (pname == GL_BUMP_TEX_UNITS_ATI) {
1034       for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
1035          if (ctx->Const.SupportedBumpUnits & (1 << i)) {
1036             *param++ = (GLfloat) (i + GL_TEXTURE0);
1037          }
1038       }
1039    }
1040    else {
1041       _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
1042       return;
1043    }
1044 }