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