mesa: skip _MaxElement computation unless driver needs strict bounds checking
[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 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
22 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24 * OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27 /**
28 * \file texenv.c
29 *
30 * glTexEnv-related functions
31 */
32
33
34 #include "main/glheader.h"
35 #include "main/context.h"
36 #include "main/blend.h"
37 #include "main/enums.h"
38 #include "main/macros.h"
39 #include "main/mtypes.h"
40 #include "main/state.h"
41 #include "main/texenv.h"
42 #include "main/texstate.h"
43
44
45 #define TE_ERROR(errCode, msg, value) \
46 _mesa_error(ctx, errCode, msg, _mesa_lookup_enum_by_nr(value));
47
48
49 /** Set texture env mode */
50 static void
51 set_env_mode(struct gl_context *ctx,
52 struct gl_texture_unit *texUnit,
53 GLenum mode)
54 {
55 GLboolean legal;
56
57 if (texUnit->EnvMode == mode)
58 return;
59
60 switch (mode) {
61 case GL_MODULATE:
62 case GL_BLEND:
63 case GL_DECAL:
64 case GL_REPLACE:
65 case GL_ADD:
66 case GL_COMBINE:
67 legal = GL_TRUE;
68 break;
69 case GL_REPLACE_EXT:
70 mode = GL_REPLACE; /* GL_REPLACE_EXT != GL_REPLACE */
71 legal = GL_TRUE;
72 break;
73 case GL_COMBINE4_NV:
74 legal = ctx->Extensions.NV_texture_env_combine4;
75 break;
76 default:
77 legal = GL_FALSE;
78 }
79
80 if (legal) {
81 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
82 texUnit->EnvMode = mode;
83 }
84 else {
85 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
86 }
87 }
88
89
90 static void
91 set_env_color(struct gl_context *ctx,
92 struct gl_texture_unit *texUnit,
93 const GLfloat *color)
94 {
95 if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped))
96 return;
97 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
98 COPY_4FV(texUnit->EnvColorUnclamped, color);
99 texUnit->EnvColor[0] = CLAMP(color[0], 0.0F, 1.0F);
100 texUnit->EnvColor[1] = CLAMP(color[1], 0.0F, 1.0F);
101 texUnit->EnvColor[2] = CLAMP(color[2], 0.0F, 1.0F);
102 texUnit->EnvColor[3] = CLAMP(color[3], 0.0F, 1.0F);
103 }
104
105
106 /** Set an RGB or A combiner mode/function */
107 static void
108 set_combiner_mode(struct gl_context *ctx,
109 struct gl_texture_unit *texUnit,
110 GLenum pname, GLenum mode)
111 {
112 GLboolean legal;
113
114 switch (mode) {
115 case GL_REPLACE:
116 case GL_MODULATE:
117 case GL_ADD:
118 case GL_ADD_SIGNED:
119 case GL_INTERPOLATE:
120 legal = GL_TRUE;
121 break;
122 case GL_SUBTRACT:
123 legal = ctx->Extensions.ARB_texture_env_combine;
124 break;
125 case GL_DOT3_RGB_EXT:
126 case GL_DOT3_RGBA_EXT:
127 legal = (ctx->API == API_OPENGL_COMPAT &&
128 ctx->Extensions.EXT_texture_env_dot3 &&
129 pname == GL_COMBINE_RGB);
130 break;
131 case GL_DOT3_RGB:
132 case GL_DOT3_RGBA:
133 legal = (ctx->Extensions.ARB_texture_env_dot3 &&
134 pname == GL_COMBINE_RGB);
135 break;
136 case GL_MODULATE_ADD_ATI:
137 case GL_MODULATE_SIGNED_ADD_ATI:
138 case GL_MODULATE_SUBTRACT_ATI:
139 legal = (ctx->API == API_OPENGL_COMPAT &&
140 ctx->Extensions.ATI_texture_env_combine3);
141 break;
142 case GL_BUMP_ENVMAP_ATI:
143 legal = (ctx->API == API_OPENGL_COMPAT &&
144 ctx->Extensions.ATI_envmap_bumpmap &&
145 pname == GL_COMBINE_RGB);
146 break;
147 default:
148 legal = GL_FALSE;
149 }
150
151 if (!legal) {
152 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
153 return;
154 }
155
156 switch (pname) {
157 case GL_COMBINE_RGB:
158 if (texUnit->Combine.ModeRGB == mode)
159 return;
160 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
161 texUnit->Combine.ModeRGB = mode;
162 break;
163
164 case GL_COMBINE_ALPHA:
165 if (texUnit->Combine.ModeA == mode)
166 return;
167 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
168 texUnit->Combine.ModeA = mode;
169 break;
170 default:
171 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
172 }
173 }
174
175
176
177 /** Set an RGB or A combiner source term */
178 static void
179 set_combiner_source(struct gl_context *ctx,
180 struct gl_texture_unit *texUnit,
181 GLenum pname, GLenum param)
182 {
183 GLuint term;
184 GLboolean alpha, legal;
185
186 /*
187 * Translate pname to (term, alpha).
188 *
189 * The enums were given sequential values for a reason.
190 */
191 switch (pname) {
192 case GL_SOURCE0_RGB:
193 case GL_SOURCE1_RGB:
194 case GL_SOURCE2_RGB:
195 case GL_SOURCE3_RGB_NV:
196 term = pname - GL_SOURCE0_RGB;
197 alpha = GL_FALSE;
198 break;
199 case GL_SOURCE0_ALPHA:
200 case GL_SOURCE1_ALPHA:
201 case GL_SOURCE2_ALPHA:
202 case GL_SOURCE3_ALPHA_NV:
203 term = pname - GL_SOURCE0_ALPHA;
204 alpha = GL_TRUE;
205 break;
206 default:
207 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
208 return;
209 }
210
211 if ((term == 3) && (ctx->API != API_OPENGL_COMPAT
212 || !ctx->Extensions.NV_texture_env_combine4)) {
213 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
214 return;
215 }
216
217 assert(term < MAX_COMBINER_TERMS);
218
219 /*
220 * Error-check param (the source term)
221 */
222 switch (param) {
223 case GL_TEXTURE:
224 case GL_CONSTANT:
225 case GL_PRIMARY_COLOR:
226 case GL_PREVIOUS:
227 legal = GL_TRUE;
228 break;
229 case GL_TEXTURE0:
230 case GL_TEXTURE1:
231 case GL_TEXTURE2:
232 case GL_TEXTURE3:
233 case GL_TEXTURE4:
234 case GL_TEXTURE5:
235 case GL_TEXTURE6:
236 case GL_TEXTURE7:
237 legal = (ctx->Extensions.ARB_texture_env_crossbar &&
238 param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
239 break;
240 case GL_ZERO:
241 legal = (ctx->API == API_OPENGL_COMPAT &&
242 (ctx->Extensions.ATI_texture_env_combine3 ||
243 ctx->Extensions.NV_texture_env_combine4));
244 break;
245 case GL_ONE:
246 legal = (ctx->API == API_OPENGL_COMPAT &&
247 ctx->Extensions.ATI_texture_env_combine3);
248 break;
249 default:
250 legal = GL_FALSE;
251 }
252
253 if (!legal) {
254 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
255 return;
256 }
257
258 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
259
260 if (alpha)
261 texUnit->Combine.SourceA[term] = param;
262 else
263 texUnit->Combine.SourceRGB[term] = param;
264 }
265
266
267 /** Set an RGB or A combiner operand term */
268 static void
269 set_combiner_operand(struct gl_context *ctx,
270 struct gl_texture_unit *texUnit,
271 GLenum pname, GLenum param)
272 {
273 GLuint term;
274 GLboolean alpha, legal;
275
276 /* The enums were given sequential values for a reason.
277 */
278 switch (pname) {
279 case GL_OPERAND0_RGB:
280 case GL_OPERAND1_RGB:
281 case GL_OPERAND2_RGB:
282 case GL_OPERAND3_RGB_NV:
283 term = pname - GL_OPERAND0_RGB;
284 alpha = GL_FALSE;
285 break;
286 case GL_OPERAND0_ALPHA:
287 case GL_OPERAND1_ALPHA:
288 case GL_OPERAND2_ALPHA:
289 case GL_OPERAND3_ALPHA_NV:
290 term = pname - GL_OPERAND0_ALPHA;
291 alpha = GL_TRUE;
292 break;
293 default:
294 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
295 return;
296 }
297
298 if ((term == 3) && (ctx->API != API_OPENGL_COMPAT
299 || !ctx->Extensions.NV_texture_env_combine4)) {
300 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
301 return;
302 }
303
304 assert(term < MAX_COMBINER_TERMS);
305
306 /*
307 * Error-check param (the source operand)
308 */
309 switch (param) {
310 case GL_SRC_COLOR:
311 case GL_ONE_MINUS_SRC_COLOR:
312 /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
313 * version. In the ARB and NV versions and OpenGL ES 1.x they can be
314 * used for any RGB operand.
315 */
316 legal = !alpha
317 && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
318 || ctx->Extensions.NV_texture_env_combine4);
319 break;
320 case GL_ONE_MINUS_SRC_ALPHA:
321 /* GL_ONE_MINUS_SRC_ALPHA can only be used with
322 * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version. In the ARB and NV
323 * versions and OpenGL ES 1.x it can be used for any operand.
324 */
325 legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
326 || ctx->Extensions.NV_texture_env_combine4;
327 break;
328 case GL_SRC_ALPHA:
329 legal = GL_TRUE;
330 break;
331 default:
332 legal = GL_FALSE;
333 }
334
335 if (!legal) {
336 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
337 return;
338 }
339
340 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
341
342 if (alpha)
343 texUnit->Combine.OperandA[term] = param;
344 else
345 texUnit->Combine.OperandRGB[term] = param;
346 }
347
348
349 static void
350 set_combiner_scale(struct gl_context *ctx,
351 struct gl_texture_unit *texUnit,
352 GLenum pname, GLfloat scale)
353 {
354 GLuint shift;
355
356 if (scale == 1.0F) {
357 shift = 0;
358 }
359 else if (scale == 2.0F) {
360 shift = 1;
361 }
362 else if (scale == 4.0F) {
363 shift = 2;
364 }
365 else {
366 _mesa_error( ctx, GL_INVALID_VALUE,
367 "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
368 return;
369 }
370
371 switch (pname) {
372 case GL_RGB_SCALE:
373 if (texUnit->Combine.ScaleShiftRGB == shift)
374 return;
375 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
376 texUnit->Combine.ScaleShiftRGB = shift;
377 break;
378 case GL_ALPHA_SCALE:
379 if (texUnit->Combine.ScaleShiftA == shift)
380 return;
381 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
382 texUnit->Combine.ScaleShiftA = shift;
383 break;
384 default:
385 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
386 }
387 }
388
389
390
391 void GLAPIENTRY
392 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
393 {
394 const GLint iparam0 = (GLint) param[0];
395 struct gl_texture_unit *texUnit;
396 GLuint maxUnit;
397 GET_CURRENT_CONTEXT(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_COMPAT || !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=%s)",
511 _mesa_lookup_enum_by_nr(target));
512 return;
513 }
514
515 if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE))
516 _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n",
517 _mesa_lookup_enum_by_nr(target),
518 _mesa_lookup_enum_by_nr(pname),
519 *param,
520 _mesa_lookup_enum_by_nr((GLenum) iparam0));
521
522 /* Tell device driver about the new texture environment */
523 if (ctx->Driver.TexEnv) {
524 (*ctx->Driver.TexEnv)( ctx, target, pname, param );
525 }
526 }
527
528
529 void GLAPIENTRY
530 _mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param )
531 {
532 GLfloat p[4];
533 p[0] = param;
534 p[1] = p[2] = p[3] = 0.0;
535 _mesa_TexEnvfv( target, pname, p );
536 }
537
538
539
540 void GLAPIENTRY
541 _mesa_TexEnvi( GLenum target, GLenum pname, GLint param )
542 {
543 GLfloat p[4];
544 p[0] = (GLfloat) param;
545 p[1] = p[2] = p[3] = 0.0;
546 _mesa_TexEnvfv( target, pname, p );
547 }
548
549
550 void GLAPIENTRY
551 _mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param )
552 {
553 GLfloat p[4];
554 if (pname == GL_TEXTURE_ENV_COLOR) {
555 p[0] = INT_TO_FLOAT( param[0] );
556 p[1] = INT_TO_FLOAT( param[1] );
557 p[2] = INT_TO_FLOAT( param[2] );
558 p[3] = INT_TO_FLOAT( param[3] );
559 }
560 else {
561 p[0] = (GLfloat) param[0];
562 p[1] = p[2] = p[3] = 0; /* init to zero, just to be safe */
563 }
564 _mesa_TexEnvfv( target, pname, p );
565 }
566
567
568
569 /**
570 * Helper for glGetTexEnvi/f()
571 * \return value of queried pname or -1 if error.
572 */
573 static GLint
574 get_texenvi(struct gl_context *ctx, const struct gl_texture_unit *texUnit,
575 GLenum pname)
576 {
577 switch (pname) {
578 case GL_TEXTURE_ENV_MODE:
579 return texUnit->EnvMode;
580 break;
581 case GL_COMBINE_RGB:
582 return texUnit->Combine.ModeRGB;
583 case GL_COMBINE_ALPHA:
584 return texUnit->Combine.ModeA;
585 case GL_SOURCE0_RGB:
586 case GL_SOURCE1_RGB:
587 case GL_SOURCE2_RGB: {
588 const unsigned rgb_idx = pname - GL_SOURCE0_RGB;
589 return texUnit->Combine.SourceRGB[rgb_idx];
590 }
591 case GL_SOURCE3_RGB_NV:
592 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
593 return texUnit->Combine.SourceRGB[3];
594 }
595 else {
596 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
597 }
598 break;
599 case GL_SOURCE0_ALPHA:
600 case GL_SOURCE1_ALPHA:
601 case GL_SOURCE2_ALPHA: {
602 const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA;
603 return texUnit->Combine.SourceA[alpha_idx];
604 }
605 case GL_SOURCE3_ALPHA_NV:
606 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
607 return texUnit->Combine.SourceA[3];
608 }
609 else {
610 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
611 }
612 break;
613 case GL_OPERAND0_RGB:
614 case GL_OPERAND1_RGB:
615 case GL_OPERAND2_RGB: {
616 const unsigned op_rgb = pname - GL_OPERAND0_RGB;
617 return texUnit->Combine.OperandRGB[op_rgb];
618 }
619 case GL_OPERAND3_RGB_NV:
620 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
621 return texUnit->Combine.OperandRGB[3];
622 }
623 else {
624 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
625 }
626 break;
627 case GL_OPERAND0_ALPHA:
628 case GL_OPERAND1_ALPHA:
629 case GL_OPERAND2_ALPHA: {
630 const unsigned op_alpha = pname - GL_OPERAND0_ALPHA;
631 return texUnit->Combine.OperandA[op_alpha];
632 }
633 case GL_OPERAND3_ALPHA_NV:
634 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) {
635 return texUnit->Combine.OperandA[3];
636 }
637 else {
638 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
639 }
640 break;
641 case GL_RGB_SCALE:
642 return 1 << texUnit->Combine.ScaleShiftRGB;
643 case GL_ALPHA_SCALE:
644 return 1 << texUnit->Combine.ScaleShiftA;
645 case GL_BUMP_TARGET_ATI:
646 /* spec doesn't say so, but I think this should be queryable */
647 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.ATI_envmap_bumpmap) {
648 return texUnit->BumpTarget;
649 }
650 else {
651 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
652 }
653 break;
654
655 default:
656 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)");
657 break;
658 }
659
660 return -1; /* error */
661 }
662
663
664
665 void GLAPIENTRY
666 _mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params )
667 {
668 GLuint maxUnit;
669 const struct gl_texture_unit *texUnit;
670 GET_CURRENT_CONTEXT(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 (_mesa_get_clamp_fragment_color(ctx))
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
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
735 maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
736 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
737 if (ctx->Texture.CurrentUnit >= maxUnit) {
738 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
739 return;
740 }
741
742 texUnit = _mesa_get_current_tex_unit(ctx);
743
744 if (target == GL_TEXTURE_ENV) {
745 if (pname == GL_TEXTURE_ENV_COLOR) {
746 params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
747 params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
748 params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
749 params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
750 }
751 else {
752 GLint val = get_texenvi(ctx, texUnit, pname);
753 if (val >= 0) {
754 *params = val;
755 }
756 }
757 }
758 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
759 if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
760 *params = (GLint) texUnit->LodBias;
761 }
762 else {
763 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
764 return;
765 }
766 }
767 else if (target == GL_POINT_SPRITE_NV) {
768 /* GL_ARB_point_sprite / GL_NV_point_sprite */
769 if (!ctx->Extensions.NV_point_sprite
770 && !ctx->Extensions.ARB_point_sprite) {
771 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
772 return;
773 }
774 if (pname == GL_COORD_REPLACE_NV) {
775 *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
776 }
777 else {
778 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
779 return;
780 }
781 }
782 else {
783 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
784 return;
785 }
786 }
787
788
789 /**
790 * Why does ATI_envmap_bumpmap require new entrypoints? Should just
791 * reuse TexEnv ones...
792 */
793 void GLAPIENTRY
794 _mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
795 {
796 GLfloat p[4];
797 GET_CURRENT_CONTEXT(ctx);
798
799 if (!ctx->Extensions.ATI_envmap_bumpmap) {
800 /* This isn't an "official" error case, but let's tell the user
801 * that something's wrong.
802 */
803 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
804 return;
805 }
806
807 if (pname == GL_BUMP_ROT_MATRIX_ATI) {
808 /* hope that conversion is correct here */
809 p[0] = INT_TO_FLOAT( param[0] );
810 p[1] = INT_TO_FLOAT( param[1] );
811 p[2] = INT_TO_FLOAT( param[2] );
812 p[3] = INT_TO_FLOAT( param[3] );
813 }
814 else {
815 p[0] = (GLfloat) param[0];
816 p[1] = p[2] = p[3] = 0.0F; /* init to zero, just to be safe */
817 }
818 _mesa_TexBumpParameterfvATI( pname, p );
819 }
820
821
822 void GLAPIENTRY
823 _mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
824 {
825 struct gl_texture_unit *texUnit;
826 GET_CURRENT_CONTEXT(ctx);
827
828 if (!ctx->Extensions.ATI_envmap_bumpmap) {
829 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
830 return;
831 }
832
833 texUnit = _mesa_get_current_tex_unit(ctx);
834
835 if (pname == GL_BUMP_ROT_MATRIX_ATI) {
836 if (TEST_EQ_4V(param, texUnit->RotMatrix))
837 return;
838 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
839 COPY_4FV(texUnit->RotMatrix, param);
840 }
841 else {
842 _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
843 return;
844 }
845 /* Drivers might want to know about this, instead of dedicated function
846 just shove it into TexEnv where it really belongs anyway */
847 if (ctx->Driver.TexEnv) {
848 (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
849 }
850 }
851
852
853 void GLAPIENTRY
854 _mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
855 {
856 const struct gl_texture_unit *texUnit;
857 GLuint i;
858 GET_CURRENT_CONTEXT(ctx);
859
860 if (!ctx->Extensions.ATI_envmap_bumpmap) {
861 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
862 return;
863 }
864
865 texUnit = _mesa_get_current_tex_unit(ctx);
866
867 if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
868 /* spec leaves open to support larger matrices.
869 Don't think anyone would ever want to use it
870 (and apps almost certainly would not understand it and
871 thus fail to submit matrices correctly) so hardcode this. */
872 *param = 4;
873 }
874 else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
875 /* hope that conversion is correct here */
876 param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
877 param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
878 param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
879 param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
880 }
881 else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
882 GLint count = 0;
883 for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
884 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
885 count++;
886 }
887 }
888 *param = count;
889 }
890 else if (pname == GL_BUMP_TEX_UNITS_ATI) {
891 for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
892 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
893 *param++ = i + GL_TEXTURE0;
894 }
895 }
896 }
897 else {
898 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
899 return;
900 }
901 }
902
903
904 void GLAPIENTRY
905 _mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
906 {
907 const struct gl_texture_unit *texUnit;
908 GLuint i;
909 GET_CURRENT_CONTEXT(ctx);
910
911 if (!ctx->Extensions.ATI_envmap_bumpmap) {
912 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
913 return;
914 }
915
916 texUnit = _mesa_get_current_tex_unit(ctx);
917
918 if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
919 /* spec leaves open to support larger matrices.
920 Don't think anyone would ever want to use it
921 (and apps might not understand it) so hardcode this. */
922 *param = 4.0F;
923 }
924 else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
925 param[0] = texUnit->RotMatrix[0];
926 param[1] = texUnit->RotMatrix[1];
927 param[2] = texUnit->RotMatrix[2];
928 param[3] = texUnit->RotMatrix[3];
929 }
930 else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
931 GLint count = 0;
932 for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
933 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
934 count++;
935 }
936 }
937 *param = (GLfloat) count;
938 }
939 else if (pname == GL_BUMP_TEX_UNITS_ATI) {
940 for (i = 0; i < ctx->Const.FragmentProgram.MaxTextureImageUnits; i++) {
941 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
942 *param++ = (GLfloat) (i + GL_TEXTURE0);
943 }
944 }
945 }
946 else {
947 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
948 return;
949 }
950 }