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