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
set_env_mode(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum mode)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
set_env_color(struct gl_context * ctx,struct gl_texture_unit * texUnit,const GLfloat * color)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
set_combiner_mode(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum pname,GLenum mode)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->API == API_OPENGL &&
126 ctx->Extensions.EXT_texture_env_dot3 &&
127 pname == GL_COMBINE_RGB);
128 break;
129 case GL_DOT3_RGB:
130 case GL_DOT3_RGBA:
131 legal = (ctx->Extensions.ARB_texture_env_dot3 &&
132 pname == GL_COMBINE_RGB);
133 break;
134 case GL_MODULATE_ADD_ATI:
135 case GL_MODULATE_SIGNED_ADD_ATI:
136 case GL_MODULATE_SUBTRACT_ATI:
137 legal = (ctx->API == API_OPENGL &&
138 ctx->Extensions.ATI_texture_env_combine3);
139 break;
140 case GL_BUMP_ENVMAP_ATI:
141 legal = (ctx->API == API_OPENGL &&
142 ctx->Extensions.ATI_envmap_bumpmap &&
143 pname == GL_COMBINE_RGB);
144 break;
145 default:
146 legal = GL_FALSE;
147 }
148
149 if (!legal) {
150 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode);
151 return;
152 }
153
154 switch (pname) {
155 case GL_COMBINE_RGB:
156 if (texUnit->Combine.ModeRGB == mode)
157 return;
158 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
159 texUnit->Combine.ModeRGB = mode;
160 break;
161
162 case GL_COMBINE_ALPHA:
163 if (texUnit->Combine.ModeA == mode)
164 return;
165 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
166 texUnit->Combine.ModeA = mode;
167 break;
168 default:
169 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
170 }
171 }
172
173
174
175 /** Set an RGB or A combiner source term */
176 static void
set_combiner_source(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum pname,GLenum param)177 set_combiner_source(struct gl_context *ctx,
178 struct gl_texture_unit *texUnit,
179 GLenum pname, GLenum param)
180 {
181 GLuint term;
182 GLboolean alpha, legal;
183
184 /*
185 * Translate pname to (term, alpha).
186 *
187 * The enums were given sequential values for a reason.
188 */
189 switch (pname) {
190 case GL_SOURCE0_RGB:
191 case GL_SOURCE1_RGB:
192 case GL_SOURCE2_RGB:
193 case GL_SOURCE3_RGB_NV:
194 term = pname - GL_SOURCE0_RGB;
195 alpha = GL_FALSE;
196 break;
197 case GL_SOURCE0_ALPHA:
198 case GL_SOURCE1_ALPHA:
199 case GL_SOURCE2_ALPHA:
200 case GL_SOURCE3_ALPHA_NV:
201 term = pname - GL_SOURCE0_ALPHA;
202 alpha = GL_TRUE;
203 break;
204 default:
205 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
206 return;
207 }
208
209 if ((term == 3) && (ctx->API != API_OPENGL
210 || !ctx->Extensions.NV_texture_env_combine4)) {
211 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
212 return;
213 }
214
215 assert(term < MAX_COMBINER_TERMS);
216
217 /*
218 * Error-check param (the source term)
219 */
220 switch (param) {
221 case GL_TEXTURE:
222 case GL_CONSTANT:
223 case GL_PRIMARY_COLOR:
224 case GL_PREVIOUS:
225 legal = GL_TRUE;
226 break;
227 case GL_TEXTURE0:
228 case GL_TEXTURE1:
229 case GL_TEXTURE2:
230 case GL_TEXTURE3:
231 case GL_TEXTURE4:
232 case GL_TEXTURE5:
233 case GL_TEXTURE6:
234 case GL_TEXTURE7:
235 legal = (ctx->Extensions.ARB_texture_env_crossbar &&
236 param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits);
237 break;
238 case GL_ZERO:
239 legal = (ctx->API == API_OPENGL &&
240 (ctx->Extensions.ATI_texture_env_combine3 ||
241 ctx->Extensions.NV_texture_env_combine4));
242 break;
243 case GL_ONE:
244 legal = (ctx->API == API_OPENGL &&
245 ctx->Extensions.ATI_texture_env_combine3);
246 break;
247 default:
248 legal = GL_FALSE;
249 }
250
251 if (!legal) {
252 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
253 return;
254 }
255
256 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
257
258 if (alpha)
259 texUnit->Combine.SourceA[term] = param;
260 else
261 texUnit->Combine.SourceRGB[term] = param;
262 }
263
264
265 /** Set an RGB or A combiner operand term */
266 static void
set_combiner_operand(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum pname,GLenum param)267 set_combiner_operand(struct gl_context *ctx,
268 struct gl_texture_unit *texUnit,
269 GLenum pname, GLenum param)
270 {
271 GLuint term;
272 GLboolean alpha, legal;
273
274 /* The enums were given sequential values for a reason.
275 */
276 switch (pname) {
277 case GL_OPERAND0_RGB:
278 case GL_OPERAND1_RGB:
279 case GL_OPERAND2_RGB:
280 case GL_OPERAND3_RGB_NV:
281 term = pname - GL_OPERAND0_RGB;
282 alpha = GL_FALSE;
283 break;
284 case GL_OPERAND0_ALPHA:
285 case GL_OPERAND1_ALPHA:
286 case GL_OPERAND2_ALPHA:
287 case GL_OPERAND3_ALPHA_NV:
288 term = pname - GL_OPERAND0_ALPHA;
289 alpha = GL_TRUE;
290 break;
291 default:
292 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
293 return;
294 }
295
296 if ((term == 3) && (ctx->API != API_OPENGL
297 || !ctx->Extensions.NV_texture_env_combine4)) {
298 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
299 return;
300 }
301
302 assert(term < MAX_COMBINER_TERMS);
303
304 /*
305 * Error-check param (the source operand)
306 */
307 switch (param) {
308 case GL_SRC_COLOR:
309 case GL_ONE_MINUS_SRC_COLOR:
310 /* The color input can only be used with GL_OPERAND[01]_RGB in the EXT
311 * version. In the ARB and NV versions and OpenGL ES 1.x they can be
312 * used for any RGB operand.
313 */
314 legal = !alpha
315 && ((term < 2) || ctx->Extensions.ARB_texture_env_combine
316 || ctx->Extensions.NV_texture_env_combine4);
317 break;
318 case GL_ONE_MINUS_SRC_ALPHA:
319 /* GL_ONE_MINUS_SRC_ALPHA can only be used with
320 * GL_OPERAND[01]_(RGB|ALPHA) in the EXT version. In the ARB and NV
321 * versions and OpenGL ES 1.x it can be used for any operand.
322 */
323 legal = (term < 2) || ctx->Extensions.ARB_texture_env_combine
324 || ctx->Extensions.NV_texture_env_combine4;
325 break;
326 case GL_SRC_ALPHA:
327 legal = GL_TRUE;
328 break;
329 default:
330 legal = GL_FALSE;
331 }
332
333 if (!legal) {
334 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param);
335 return;
336 }
337
338 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
339
340 if (alpha)
341 texUnit->Combine.OperandA[term] = param;
342 else
343 texUnit->Combine.OperandRGB[term] = param;
344 }
345
346
347 static void
set_combiner_scale(struct gl_context * ctx,struct gl_texture_unit * texUnit,GLenum pname,GLfloat scale)348 set_combiner_scale(struct gl_context *ctx,
349 struct gl_texture_unit *texUnit,
350 GLenum pname, GLfloat scale)
351 {
352 GLuint shift;
353
354 if (scale == 1.0F) {
355 shift = 0;
356 }
357 else if (scale == 2.0F) {
358 shift = 1;
359 }
360 else if (scale == 4.0F) {
361 shift = 2;
362 }
363 else {
364 _mesa_error( ctx, GL_INVALID_VALUE,
365 "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" );
366 return;
367 }
368
369 switch (pname) {
370 case GL_RGB_SCALE:
371 if (texUnit->Combine.ScaleShiftRGB == shift)
372 return;
373 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
374 texUnit->Combine.ScaleShiftRGB = shift;
375 break;
376 case GL_ALPHA_SCALE:
377 if (texUnit->Combine.ScaleShiftA == shift)
378 return;
379 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
380 texUnit->Combine.ScaleShiftA = shift;
381 break;
382 default:
383 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
384 }
385 }
386
387
388
389 void GLAPIENTRY
_mesa_TexEnvfv(GLenum target,GLenum pname,const GLfloat * param)390 _mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param )
391 {
392 const GLint iparam0 = (GLint) param[0];
393 struct gl_texture_unit *texUnit;
394 GLuint maxUnit;
395
396 GET_CURRENT_CONTEXT(ctx);
397 ASSERT_OUTSIDE_BEGIN_END(ctx);
398
399 maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
400 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
401 if (ctx->Texture.CurrentUnit >= maxUnit) {
402 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(current unit)");
403 return;
404 }
405
406 texUnit = _mesa_get_current_tex_unit(ctx);
407
408 if (target == GL_TEXTURE_ENV) {
409 switch (pname) {
410 case GL_TEXTURE_ENV_MODE:
411 set_env_mode(ctx, texUnit, (GLenum) iparam0);
412 break;
413 case GL_TEXTURE_ENV_COLOR:
414 set_env_color(ctx, texUnit, param);
415 break;
416 case GL_COMBINE_RGB:
417 case GL_COMBINE_ALPHA:
418 set_combiner_mode(ctx, texUnit, pname, (GLenum) iparam0);
419 break;
420 case GL_SOURCE0_RGB:
421 case GL_SOURCE1_RGB:
422 case GL_SOURCE2_RGB:
423 case GL_SOURCE3_RGB_NV:
424 case GL_SOURCE0_ALPHA:
425 case GL_SOURCE1_ALPHA:
426 case GL_SOURCE2_ALPHA:
427 case GL_SOURCE3_ALPHA_NV:
428 set_combiner_source(ctx, texUnit, pname, (GLenum) iparam0);
429 break;
430 case GL_OPERAND0_RGB:
431 case GL_OPERAND1_RGB:
432 case GL_OPERAND2_RGB:
433 case GL_OPERAND3_RGB_NV:
434 case GL_OPERAND0_ALPHA:
435 case GL_OPERAND1_ALPHA:
436 case GL_OPERAND2_ALPHA:
437 case GL_OPERAND3_ALPHA_NV:
438 set_combiner_operand(ctx, texUnit, pname, (GLenum) iparam0);
439 break;
440 case GL_RGB_SCALE:
441 case GL_ALPHA_SCALE:
442 set_combiner_scale(ctx, texUnit, pname, param[0]);
443 break;
444 case GL_BUMP_TARGET_ATI:
445 if (ctx->API != API_OPENGL || !ctx->Extensions.ATI_envmap_bumpmap) {
446 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
447 return;
448 }
449 if ((iparam0 < GL_TEXTURE0) ||
450 (iparam0 > GL_TEXTURE31)) {
451 /* spec doesn't say this but it seems logical */
452 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(param=0x%x)", iparam0);
453 return;
454 }
455 if (!((1 << (iparam0 - GL_TEXTURE0)) & ctx->Const.SupportedBumpUnits)) {
456 _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
457 return;
458 }
459 else {
460 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
461 texUnit->BumpTarget = iparam0;
462 }
463 break;
464 default:
465 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" );
466 return;
467 }
468 }
469 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
470 if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
471 if (texUnit->LodBias == param[0])
472 return;
473 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
474 texUnit->LodBias = param[0];
475 }
476 else {
477 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname);
478 return;
479 }
480 }
481 else if (target == GL_POINT_SPRITE_NV) {
482 /* GL_ARB_point_sprite / GL_NV_point_sprite */
483 if (!ctx->Extensions.NV_point_sprite
484 && !ctx->Extensions.ARB_point_sprite) {
485 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target );
486 return;
487 }
488 if (pname == GL_COORD_REPLACE_NV) {
489 if (iparam0 == GL_TRUE || iparam0 == GL_FALSE) {
490 /* It's kind of weird to set point state via glTexEnv,
491 * but that's what the spec calls for.
492 */
493 const GLboolean state = (GLboolean) iparam0;
494 if (ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] == state)
495 return;
496 FLUSH_VERTICES(ctx, _NEW_POINT);
497 ctx->Point.CoordReplace[ctx->Texture.CurrentUnit] = state;
498 }
499 else {
500 _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0);
501 return;
502 }
503 }
504 else {
505 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname );
506 return;
507 }
508 }
509 else {
510 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)",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
_mesa_TexEnvf(GLenum target,GLenum pname,GLfloat param)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
_mesa_TexEnvi(GLenum target,GLenum pname,GLint param)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
_mesa_TexEnviv(GLenum target,GLenum pname,const GLint * param)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
get_texenvi(struct gl_context * ctx,const struct gl_texture_unit * texUnit,GLenum pname)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 && 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 && 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 && 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 && 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 && 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
_mesa_GetTexEnvfv(GLenum target,GLenum pname,GLfloat * params)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 ASSERT_OUTSIDE_BEGIN_END(ctx);
671
672 maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
673 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
674 if (ctx->Texture.CurrentUnit >= maxUnit) {
675 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(current unit)");
676 return;
677 }
678
679 texUnit = _mesa_get_current_tex_unit(ctx);
680
681 if (target == GL_TEXTURE_ENV) {
682 if (pname == GL_TEXTURE_ENV_COLOR) {
683 if(ctx->NewState & (_NEW_BUFFERS | _NEW_FRAG_CLAMP))
684 _mesa_update_state(ctx);
685 if(ctx->Color._ClampFragmentColor)
686 COPY_4FV( params, texUnit->EnvColor );
687 else
688 COPY_4FV( params, texUnit->EnvColorUnclamped );
689 }
690 else {
691 GLint val = get_texenvi(ctx, texUnit, pname);
692 if (val >= 0) {
693 *params = (GLfloat) val;
694 }
695 }
696 }
697 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
698 if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
699 *params = texUnit->LodBias;
700 }
701 else {
702 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
703 return;
704 }
705 }
706 else if (target == GL_POINT_SPRITE_NV) {
707 /* GL_ARB_point_sprite / GL_NV_point_sprite */
708 if (!ctx->Extensions.NV_point_sprite
709 && !ctx->Extensions.ARB_point_sprite) {
710 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
711 return;
712 }
713 if (pname == GL_COORD_REPLACE_NV) {
714 *params = (GLfloat) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
715 }
716 else {
717 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" );
718 return;
719 }
720 }
721 else {
722 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" );
723 return;
724 }
725 }
726
727
728 void GLAPIENTRY
_mesa_GetTexEnviv(GLenum target,GLenum pname,GLint * params)729 _mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params )
730 {
731 GLuint maxUnit;
732 const struct gl_texture_unit *texUnit;
733 GET_CURRENT_CONTEXT(ctx);
734 ASSERT_OUTSIDE_BEGIN_END(ctx);
735
736 maxUnit = (target == GL_POINT_SPRITE_NV && pname == GL_COORD_REPLACE_NV)
737 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits;
738 if (ctx->Texture.CurrentUnit >= maxUnit) {
739 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(current unit)");
740 return;
741 }
742
743 texUnit = _mesa_get_current_tex_unit(ctx);
744
745 if (target == GL_TEXTURE_ENV) {
746 if (pname == GL_TEXTURE_ENV_COLOR) {
747 params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] );
748 params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] );
749 params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] );
750 params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] );
751 }
752 else {
753 GLint val = get_texenvi(ctx, texUnit, pname);
754 if (val >= 0) {
755 *params = val;
756 }
757 }
758 }
759 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) {
760 if (pname == GL_TEXTURE_LOD_BIAS_EXT) {
761 *params = (GLint) texUnit->LodBias;
762 }
763 else {
764 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
765 return;
766 }
767 }
768 else if (target == GL_POINT_SPRITE_NV) {
769 /* GL_ARB_point_sprite / GL_NV_point_sprite */
770 if (!ctx->Extensions.NV_point_sprite
771 && !ctx->Extensions.ARB_point_sprite) {
772 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
773 return;
774 }
775 if (pname == GL_COORD_REPLACE_NV) {
776 *params = (GLint) ctx->Point.CoordReplace[ctx->Texture.CurrentUnit];
777 }
778 else {
779 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" );
780 return;
781 }
782 }
783 else {
784 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" );
785 return;
786 }
787 }
788
789
790 /**
791 * Why does ATI_envmap_bumpmap require new entrypoints? Should just
792 * reuse TexEnv ones...
793 */
794 void GLAPIENTRY
_mesa_TexBumpParameterivATI(GLenum pname,const GLint * param)795 _mesa_TexBumpParameterivATI( GLenum pname, const GLint *param )
796 {
797 GLfloat p[4];
798 GET_CURRENT_CONTEXT(ctx);
799 ASSERT_OUTSIDE_BEGIN_END(ctx);
800
801 if (!ctx->Extensions.ATI_envmap_bumpmap) {
802 /* This isn't an "official" error case, but let's tell the user
803 * that something's wrong.
804 */
805 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterivATI");
806 return;
807 }
808
809 if (pname == GL_BUMP_ROT_MATRIX_ATI) {
810 /* hope that conversion is correct here */
811 p[0] = INT_TO_FLOAT( param[0] );
812 p[1] = INT_TO_FLOAT( param[1] );
813 p[2] = INT_TO_FLOAT( param[2] );
814 p[3] = INT_TO_FLOAT( param[3] );
815 }
816 else {
817 p[0] = (GLfloat) param[0];
818 p[1] = p[2] = p[3] = 0.0F; /* init to zero, just to be safe */
819 }
820 _mesa_TexBumpParameterfvATI( pname, p );
821 }
822
823
824 void GLAPIENTRY
_mesa_TexBumpParameterfvATI(GLenum pname,const GLfloat * param)825 _mesa_TexBumpParameterfvATI( GLenum pname, const GLfloat *param )
826 {
827 struct gl_texture_unit *texUnit;
828 GET_CURRENT_CONTEXT(ctx);
829 ASSERT_OUTSIDE_BEGIN_END(ctx);
830
831 if (!ctx->Extensions.ATI_envmap_bumpmap) {
832 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexBumpParameterfvATI");
833 return;
834 }
835
836 texUnit = _mesa_get_current_tex_unit(ctx);
837
838 if (pname == GL_BUMP_ROT_MATRIX_ATI) {
839 if (TEST_EQ_4V(param, texUnit->RotMatrix))
840 return;
841 FLUSH_VERTICES(ctx, _NEW_TEXTURE);
842 COPY_4FV(texUnit->RotMatrix, param);
843 }
844 else {
845 _mesa_error( ctx, GL_INVALID_ENUM, "glTexBumpParameter(pname)" );
846 return;
847 }
848 /* Drivers might want to know about this, instead of dedicated function
849 just shove it into TexEnv where it really belongs anyway */
850 if (ctx->Driver.TexEnv) {
851 (*ctx->Driver.TexEnv)( ctx, 0, pname, param );
852 }
853 }
854
855
856 void GLAPIENTRY
_mesa_GetTexBumpParameterivATI(GLenum pname,GLint * param)857 _mesa_GetTexBumpParameterivATI( GLenum pname, GLint *param )
858 {
859 const struct gl_texture_unit *texUnit;
860 GLuint i;
861 GET_CURRENT_CONTEXT(ctx);
862 ASSERT_OUTSIDE_BEGIN_END(ctx);
863
864 if (!ctx->Extensions.ATI_envmap_bumpmap) {
865 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterivATI");
866 return;
867 }
868
869 texUnit = _mesa_get_current_tex_unit(ctx);
870
871 if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
872 /* spec leaves open to support larger matrices.
873 Don't think anyone would ever want to use it
874 (and apps almost certainly would not understand it and
875 thus fail to submit matrices correctly) so hardcode this. */
876 *param = 4;
877 }
878 else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
879 /* hope that conversion is correct here */
880 param[0] = FLOAT_TO_INT(texUnit->RotMatrix[0]);
881 param[1] = FLOAT_TO_INT(texUnit->RotMatrix[1]);
882 param[2] = FLOAT_TO_INT(texUnit->RotMatrix[2]);
883 param[3] = FLOAT_TO_INT(texUnit->RotMatrix[3]);
884 }
885 else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
886 GLint count = 0;
887 for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
888 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
889 count++;
890 }
891 }
892 *param = count;
893 }
894 else if (pname == GL_BUMP_TEX_UNITS_ATI) {
895 for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
896 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
897 *param++ = i + GL_TEXTURE0;
898 }
899 }
900 }
901 else {
902 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
903 return;
904 }
905 }
906
907
908 void GLAPIENTRY
_mesa_GetTexBumpParameterfvATI(GLenum pname,GLfloat * param)909 _mesa_GetTexBumpParameterfvATI( GLenum pname, GLfloat *param )
910 {
911 const struct gl_texture_unit *texUnit;
912 GLuint i;
913 GET_CURRENT_CONTEXT(ctx);
914 ASSERT_OUTSIDE_BEGIN_END(ctx);
915
916 if (!ctx->Extensions.ATI_envmap_bumpmap) {
917 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexBumpParameterfvATI");
918 return;
919 }
920
921 texUnit = _mesa_get_current_tex_unit(ctx);
922
923 if (pname == GL_BUMP_ROT_MATRIX_SIZE_ATI) {
924 /* spec leaves open to support larger matrices.
925 Don't think anyone would ever want to use it
926 (and apps might not understand it) so hardcode this. */
927 *param = 4.0F;
928 }
929 else if (pname == GL_BUMP_ROT_MATRIX_ATI) {
930 param[0] = texUnit->RotMatrix[0];
931 param[1] = texUnit->RotMatrix[1];
932 param[2] = texUnit->RotMatrix[2];
933 param[3] = texUnit->RotMatrix[3];
934 }
935 else if (pname == GL_BUMP_NUM_TEX_UNITS_ATI) {
936 GLint count = 0;
937 for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
938 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
939 count++;
940 }
941 }
942 *param = (GLfloat) count;
943 }
944 else if (pname == GL_BUMP_TEX_UNITS_ATI) {
945 for (i = 0; i < ctx->Const.MaxTextureImageUnits; i++) {
946 if (ctx->Const.SupportedBumpUnits & (1 << i)) {
947 *param++ = (GLfloat) (i + GL_TEXTURE0);
948 }
949 }
950 }
951 else {
952 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexBumpParameter(pname)" );
953 return;
954 }
955 }
956