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