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