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