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