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