1/* 2 * Mesa 3-D graphics library 3 * 4 * Copyright (C) 1999-2008 Brian Paul All Rights Reserved. 5 * Copyright (C) 2009 VMware, Inc. All Rights Reserved. 6 * 7 * Permission is hereby granted, free of charge, to any person obtaining a 8 * copy of this software and associated documentation files (the "Software"), 9 * to deal in the Software without restriction, including without limitation 10 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 11 * and/or sell copies of the Software, and to permit persons to whom the 12 * Software is furnished to do so, subject to the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be included 15 * in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR 21 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 22 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 23 * 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/texstate.h" 41#include "api_exec_decl.h" 42 43 44#define TE_ERROR(errCode, msg, value) \ 45 _mesa_error(ctx, errCode, msg, _mesa_enum_to_string(value)); 46 47 48/** Set texture env mode */ 49static void 50set_env_mode(struct gl_context *ctx, 51 struct gl_fixedfunc_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_STATE, GL_TEXTURE_BIT); 81 texUnit->EnvMode = mode; 82 } 83 else { 84 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); 85 } 86} 87 88 89static void 90set_env_color(struct gl_context *ctx, 91 struct gl_fixedfunc_texture_unit *texUnit, 92 const GLfloat *color) 93{ 94 if (TEST_EQ_4V(color, texUnit->EnvColorUnclamped)) 95 return; 96 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 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 */ 106static bool 107set_combiner_mode(struct gl_context *ctx, 108 struct gl_fixedfunc_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 case GL_SUBTRACT: 120 legal = GL_TRUE; 121 break; 122 case GL_DOT3_RGB_EXT: 123 case GL_DOT3_RGBA_EXT: 124 legal = (ctx->API == API_OPENGL_COMPAT && 125 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 = (pname == GL_COMBINE_RGB); 131 break; 132 case GL_MODULATE_ADD_ATI: 133 case GL_MODULATE_SIGNED_ADD_ATI: 134 case GL_MODULATE_SUBTRACT_ATI: 135 legal = (ctx->API == API_OPENGL_COMPAT && 136 ctx->Extensions.ATI_texture_env_combine3); 137 break; 138 default: 139 legal = GL_FALSE; 140 } 141 142 if (!legal) { 143 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", mode); 144 return false; 145 } 146 147 switch (pname) { 148 case GL_COMBINE_RGB: 149 if (texUnit->Combine.ModeRGB == mode) 150 return true; 151 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 152 texUnit->Combine.ModeRGB = mode; 153 break; 154 155 case GL_COMBINE_ALPHA: 156 if (texUnit->Combine.ModeA == mode) 157 return true; 158 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 159 texUnit->Combine.ModeA = mode; 160 break; 161 default: 162 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 163 return false; 164 } 165 166 return true; 167} 168 169 170 171/** Set an RGB or A combiner source term */ 172static bool 173set_combiner_source(struct gl_context *ctx, 174 struct gl_fixedfunc_texture_unit *texUnit, 175 GLenum pname, GLenum param) 176{ 177 GLuint term; 178 GLboolean alpha, legal; 179 180 /* 181 * Translate pname to (term, alpha). 182 * 183 * The enums were given sequential values for a reason. 184 */ 185 switch (pname) { 186 case GL_SOURCE0_RGB: 187 case GL_SOURCE1_RGB: 188 case GL_SOURCE2_RGB: 189 case GL_SOURCE3_RGB_NV: 190 term = pname - GL_SOURCE0_RGB; 191 alpha = GL_FALSE; 192 break; 193 case GL_SOURCE0_ALPHA: 194 case GL_SOURCE1_ALPHA: 195 case GL_SOURCE2_ALPHA: 196 case GL_SOURCE3_ALPHA_NV: 197 term = pname - GL_SOURCE0_ALPHA; 198 alpha = GL_TRUE; 199 break; 200 default: 201 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 202 return false; 203 } 204 205 if ((term == 3) && (ctx->API != API_OPENGL_COMPAT 206 || !ctx->Extensions.NV_texture_env_combine4)) { 207 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 208 return false; 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 = (param - GL_TEXTURE0 < ctx->Const.MaxTextureUnits); 232 break; 233 case GL_ZERO: 234 legal = (ctx->API == API_OPENGL_COMPAT && 235 (ctx->Extensions.ATI_texture_env_combine3 || 236 ctx->Extensions.NV_texture_env_combine4)); 237 break; 238 case GL_ONE: 239 legal = (ctx->API == API_OPENGL_COMPAT && 240 ctx->Extensions.ATI_texture_env_combine3); 241 break; 242 default: 243 legal = GL_FALSE; 244 } 245 246 if (!legal) { 247 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param); 248 return false; 249 } 250 251 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 252 253 if (alpha) 254 texUnit->Combine.SourceA[term] = param; 255 else 256 texUnit->Combine.SourceRGB[term] = param; 257 258 return true; 259} 260 261 262/** Set an RGB or A combiner operand term */ 263static bool 264set_combiner_operand(struct gl_context *ctx, 265 struct gl_fixedfunc_texture_unit *texUnit, 266 GLenum pname, GLenum param) 267{ 268 GLuint term; 269 GLboolean alpha, legal; 270 271 /* The enums were given sequential values for a reason. 272 */ 273 switch (pname) { 274 case GL_OPERAND0_RGB: 275 case GL_OPERAND1_RGB: 276 case GL_OPERAND2_RGB: 277 case GL_OPERAND3_RGB_NV: 278 term = pname - GL_OPERAND0_RGB; 279 alpha = GL_FALSE; 280 break; 281 case GL_OPERAND0_ALPHA: 282 case GL_OPERAND1_ALPHA: 283 case GL_OPERAND2_ALPHA: 284 case GL_OPERAND3_ALPHA_NV: 285 term = pname - GL_OPERAND0_ALPHA; 286 alpha = GL_TRUE; 287 break; 288 default: 289 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 290 return false; 291 } 292 293 if ((term == 3) && (ctx->API != API_OPENGL_COMPAT 294 || !ctx->Extensions.NV_texture_env_combine4)) { 295 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 296 return false; 297 } 298 299 assert(term < MAX_COMBINER_TERMS); 300 301 /* 302 * Error-check param (the source operand) 303 */ 304 switch (param) { 305 case GL_SRC_COLOR: 306 case GL_ONE_MINUS_SRC_COLOR: 307 legal = !alpha; 308 break; 309 case GL_ONE_MINUS_SRC_ALPHA: 310 case GL_SRC_ALPHA: 311 legal = GL_TRUE; 312 break; 313 default: 314 legal = GL_FALSE; 315 } 316 317 if (!legal) { 318 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(param=%s)", param); 319 return false; 320 } 321 322 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 323 324 if (alpha) 325 texUnit->Combine.OperandA[term] = param; 326 else 327 texUnit->Combine.OperandRGB[term] = param; 328 329 return true; 330} 331 332 333static bool 334set_combiner_scale(struct gl_context *ctx, 335 struct gl_fixedfunc_texture_unit *texUnit, 336 GLenum pname, GLfloat scale) 337{ 338 GLuint shift; 339 340 if (scale == 1.0F) { 341 shift = 0; 342 } 343 else if (scale == 2.0F) { 344 shift = 1; 345 } 346 else if (scale == 4.0F) { 347 shift = 2; 348 } 349 else { 350 _mesa_error( ctx, GL_INVALID_VALUE, 351 "glTexEnv(GL_RGB_SCALE not 1, 2 or 4)" ); 352 return false; 353 } 354 355 switch (pname) { 356 case GL_RGB_SCALE: 357 if (texUnit->Combine.ScaleShiftRGB == shift) 358 return true; 359 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 360 texUnit->Combine.ScaleShiftRGB = shift; 361 break; 362 case GL_ALPHA_SCALE: 363 if (texUnit->Combine.ScaleShiftA == shift) 364 return true; 365 FLUSH_VERTICES(ctx, _NEW_TEXTURE_STATE, GL_TEXTURE_BIT); 366 texUnit->Combine.ScaleShiftA = shift; 367 break; 368 default: 369 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 370 return false; 371 } 372 373 return true; 374} 375 376 377static void 378_mesa_texenvfv_indexed( struct gl_context* ctx, GLuint texunit, GLenum target, 379 GLenum pname, const GLfloat *param ) 380{ 381 const GLint iparam0 = (GLint) param[0]; 382 GLuint maxUnit; 383 384 maxUnit = (target == GL_POINT_SPRITE && pname == GL_COORD_REPLACE) 385 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits; 386 if (texunit >= maxUnit) { 387 _mesa_error(ctx, GL_INVALID_OPERATION, "glTexEnvfv(texunit=%d)", texunit); 388 return; 389 } 390 391 if (target == GL_TEXTURE_ENV) { 392 struct gl_fixedfunc_texture_unit *texUnit = 393 _mesa_get_fixedfunc_tex_unit(ctx, texunit); 394 395 /* The GL spec says that we should report an error if the unit is greater 396 * than GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, but in practice, only 397 * fixed-function units are usable. This is probably a spec bug. 398 * Ignore glTexEnv(GL_TEXTURE_ENV) calls for non-fixed-func units, 399 * because we don't want to process calls that have no effect. 400 */ 401 if (!texUnit) 402 return; 403 404 switch (pname) { 405 case GL_TEXTURE_ENV_MODE: 406 set_env_mode(ctx, texUnit, (GLenum) iparam0); 407 break; 408 case GL_TEXTURE_ENV_COLOR: 409 set_env_color(ctx, texUnit, param); 410 break; 411 case GL_COMBINE_RGB: 412 case GL_COMBINE_ALPHA: 413 if (!set_combiner_mode(ctx, texUnit, pname, (GLenum) iparam0)) 414 return; 415 break; 416 case GL_SOURCE0_RGB: 417 case GL_SOURCE1_RGB: 418 case GL_SOURCE2_RGB: 419 case GL_SOURCE3_RGB_NV: 420 case GL_SOURCE0_ALPHA: 421 case GL_SOURCE1_ALPHA: 422 case GL_SOURCE2_ALPHA: 423 case GL_SOURCE3_ALPHA_NV: 424 if (!set_combiner_source(ctx, texUnit, pname, (GLenum) iparam0)) 425 return; 426 break; 427 case GL_OPERAND0_RGB: 428 case GL_OPERAND1_RGB: 429 case GL_OPERAND2_RGB: 430 case GL_OPERAND3_RGB_NV: 431 case GL_OPERAND0_ALPHA: 432 case GL_OPERAND1_ALPHA: 433 case GL_OPERAND2_ALPHA: 434 case GL_OPERAND3_ALPHA_NV: 435 if (!set_combiner_operand(ctx, texUnit, pname, (GLenum) iparam0)) 436 return; 437 break; 438 case GL_RGB_SCALE: 439 case GL_ALPHA_SCALE: 440 if (!set_combiner_scale(ctx, texUnit, pname, param[0])) 441 return; 442 break; 443 default: 444 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname)" ); 445 return; 446 } 447 } 448 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) { 449 struct gl_texture_unit *texUnit = 450 _mesa_get_tex_unit(ctx, texunit); 451 452 if (pname == GL_TEXTURE_LOD_BIAS_EXT) { 453 if (texUnit->LodBias == param[0]) 454 return; 455 FLUSH_VERTICES(ctx, _NEW_TEXTURE_OBJECT, GL_TEXTURE_BIT); 456 texUnit->LodBias = param[0]; 457 texUnit->LodBiasQuantized = util_quantize_lod_bias(param[0]); 458 } 459 else { 460 TE_ERROR(GL_INVALID_ENUM, "glTexEnv(pname=%s)", pname); 461 return; 462 } 463 } 464 else if (target == GL_POINT_SPRITE) { 465 /* GL_ARB_point_sprite */ 466 if (!ctx->Extensions.ARB_point_sprite) { 467 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(target=0x%x)", target ); 468 return; 469 } 470 if (pname == GL_COORD_REPLACE) { 471 /* It's kind of weird to set point state via glTexEnv, 472 * but that's what the spec calls for. 473 */ 474 if (iparam0 == GL_TRUE) { 475 if (ctx->Point.CoordReplace & (1u << texunit)) 476 return; 477 FLUSH_VERTICES(ctx, _NEW_POINT | _NEW_FF_VERT_PROGRAM, 478 GL_POINT_BIT); 479 ctx->Point.CoordReplace |= (1u << texunit); 480 } else if (iparam0 == GL_FALSE) { 481 if (~(ctx->Point.CoordReplace) & (1u << texunit)) 482 return; 483 FLUSH_VERTICES(ctx, _NEW_POINT | _NEW_FF_VERT_PROGRAM, 484 GL_POINT_BIT); 485 ctx->Point.CoordReplace &= ~(1u << texunit); 486 } else { 487 _mesa_error( ctx, GL_INVALID_VALUE, "glTexEnv(param=0x%x)", iparam0); 488 return; 489 } 490 } 491 else { 492 _mesa_error( ctx, GL_INVALID_ENUM, "glTexEnv(pname=0x%x)", pname ); 493 return; 494 } 495 } 496 else { 497 _mesa_error(ctx, GL_INVALID_ENUM, "glTexEnv(target=%s)", 498 _mesa_enum_to_string(target)); 499 return; 500 } 501 502 if (MESA_VERBOSE&(VERBOSE_API|VERBOSE_TEXTURE)) 503 _mesa_debug(ctx, "glTexEnv %s %s %.1f(%s) ...\n", 504 _mesa_enum_to_string(target), 505 _mesa_enum_to_string(pname), 506 *param, 507 _mesa_enum_to_string((GLenum) iparam0)); 508} 509 510 511void GLAPIENTRY 512_mesa_TexEnvfv( GLenum target, GLenum pname, const GLfloat *param ) 513{ 514 GET_CURRENT_CONTEXT(ctx); 515 _mesa_texenvfv_indexed(ctx, ctx->Texture.CurrentUnit, target, pname, param); 516} 517 518 519void GLAPIENTRY 520_mesa_TexEnvf( GLenum target, GLenum pname, GLfloat param ) 521{ 522 GLfloat p[4]; 523 p[0] = param; 524 p[1] = p[2] = p[3] = 0.0; 525 _mesa_TexEnvfv( target, pname, p ); 526} 527 528 529void GLAPIENTRY 530_mesa_TexEnvi( GLenum target, GLenum pname, GLint param ) 531{ 532 GLfloat p[4]; 533 p[0] = (GLfloat) param; 534 p[1] = p[2] = p[3] = 0.0; 535 _mesa_TexEnvfv( target, pname, p ); 536} 537 538 539void GLAPIENTRY 540_mesa_TexEnviv( GLenum target, GLenum pname, const GLint *param ) 541{ 542 GLfloat p[4]; 543 if (pname == GL_TEXTURE_ENV_COLOR) { 544 p[0] = INT_TO_FLOAT( param[0] ); 545 p[1] = INT_TO_FLOAT( param[1] ); 546 p[2] = INT_TO_FLOAT( param[2] ); 547 p[3] = INT_TO_FLOAT( param[3] ); 548 } 549 else { 550 p[0] = (GLfloat) param[0]; 551 p[1] = p[2] = p[3] = 0; /* init to zero, just to be safe */ 552 } 553 _mesa_TexEnvfv( target, pname, p ); 554} 555 556 557void GLAPIENTRY 558_mesa_MultiTexEnvfEXT( GLenum texunit, GLenum target, 559 GLenum pname, GLfloat param ) 560{ 561 GET_CURRENT_CONTEXT(ctx); 562 GLfloat p[4]; 563 p[0] = param; 564 p[1] = p[2] = p[3] = 0.0; 565 _mesa_texenvfv_indexed(ctx, texunit - GL_TEXTURE0, target, pname, p); 566} 567 568void GLAPIENTRY 569_mesa_MultiTexEnvfvEXT( GLenum texunit, GLenum target, 570 GLenum pname, const GLfloat *param ) 571{ 572 GET_CURRENT_CONTEXT(ctx); 573 _mesa_texenvfv_indexed(ctx, texunit - GL_TEXTURE0, target, pname, param); 574} 575 576 577void GLAPIENTRY 578_mesa_MultiTexEnviEXT( GLenum texunit, GLenum target, 579 GLenum pname, GLint param ) 580{ 581 GET_CURRENT_CONTEXT(ctx); 582 GLfloat p[4]; 583 p[0] = (GLfloat) param; 584 p[1] = p[2] = p[3] = 0.0; 585 _mesa_texenvfv_indexed( ctx, texunit - GL_TEXTURE0, target, pname, p ); 586} 587 588 589void GLAPIENTRY 590_mesa_MultiTexEnvivEXT( GLenum texunit, GLenum target, 591 GLenum pname, const GLint *param ) 592{ 593 GET_CURRENT_CONTEXT(ctx); 594 GLfloat p[4]; 595 if (pname == GL_TEXTURE_ENV_COLOR) { 596 p[0] = INT_TO_FLOAT( param[0] ); 597 p[1] = INT_TO_FLOAT( param[1] ); 598 p[2] = INT_TO_FLOAT( param[2] ); 599 p[3] = INT_TO_FLOAT( param[3] ); 600 } 601 else { 602 p[0] = (GLfloat) param[0]; 603 p[1] = p[2] = p[3] = 0; /* init to zero, just to be safe */ 604 } 605 _mesa_texenvfv_indexed( ctx, texunit - GL_TEXTURE0, target, pname, p ); 606} 607 608 609 610 611/** 612 * Helper for glGetTexEnvi/f() 613 * \return value of queried pname or -1 if error. 614 */ 615static GLint 616get_texenvi(struct gl_context *ctx, 617 const struct gl_fixedfunc_texture_unit *texUnit, 618 GLenum pname) 619{ 620 switch (pname) { 621 case GL_TEXTURE_ENV_MODE: 622 return texUnit->EnvMode; 623 break; 624 case GL_COMBINE_RGB: 625 return texUnit->Combine.ModeRGB; 626 case GL_COMBINE_ALPHA: 627 return texUnit->Combine.ModeA; 628 case GL_SOURCE0_RGB: 629 case GL_SOURCE1_RGB: 630 case GL_SOURCE2_RGB: { 631 const unsigned rgb_idx = pname - GL_SOURCE0_RGB; 632 return texUnit->Combine.SourceRGB[rgb_idx]; 633 } 634 case GL_SOURCE3_RGB_NV: 635 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) { 636 return texUnit->Combine.SourceRGB[3]; 637 } 638 else { 639 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)"); 640 } 641 break; 642 case GL_SOURCE0_ALPHA: 643 case GL_SOURCE1_ALPHA: 644 case GL_SOURCE2_ALPHA: { 645 const unsigned alpha_idx = pname - GL_SOURCE0_ALPHA; 646 return texUnit->Combine.SourceA[alpha_idx]; 647 } 648 case GL_SOURCE3_ALPHA_NV: 649 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) { 650 return texUnit->Combine.SourceA[3]; 651 } 652 else { 653 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)"); 654 } 655 break; 656 case GL_OPERAND0_RGB: 657 case GL_OPERAND1_RGB: 658 case GL_OPERAND2_RGB: { 659 const unsigned op_rgb = pname - GL_OPERAND0_RGB; 660 return texUnit->Combine.OperandRGB[op_rgb]; 661 } 662 case GL_OPERAND3_RGB_NV: 663 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) { 664 return texUnit->Combine.OperandRGB[3]; 665 } 666 else { 667 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)"); 668 } 669 break; 670 case GL_OPERAND0_ALPHA: 671 case GL_OPERAND1_ALPHA: 672 case GL_OPERAND2_ALPHA: { 673 const unsigned op_alpha = pname - GL_OPERAND0_ALPHA; 674 return texUnit->Combine.OperandA[op_alpha]; 675 } 676 case GL_OPERAND3_ALPHA_NV: 677 if (ctx->API == API_OPENGL_COMPAT && ctx->Extensions.NV_texture_env_combine4) { 678 return texUnit->Combine.OperandA[3]; 679 } 680 else { 681 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)"); 682 } 683 break; 684 case GL_RGB_SCALE: 685 return 1 << texUnit->Combine.ScaleShiftRGB; 686 case GL_ALPHA_SCALE: 687 return 1 << texUnit->Combine.ScaleShiftA; 688 default: 689 _mesa_error(ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)"); 690 break; 691 } 692 693 return -1; /* error */ 694} 695 696 697static void 698_mesa_gettexenvfv_indexed( GLuint texunit, GLenum target, GLenum pname, GLfloat *params ) 699{ 700 GLuint maxUnit; 701 GET_CURRENT_CONTEXT(ctx); 702 703 maxUnit = (target == GL_POINT_SPRITE && pname == GL_COORD_REPLACE) 704 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits; 705 if (texunit >= maxUnit) { 706 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnvfv(texunit=%d)", texunit); 707 return; 708 } 709 710 if (target == GL_TEXTURE_ENV) { 711 struct gl_fixedfunc_texture_unit *texUnit = 712 _mesa_get_fixedfunc_tex_unit(ctx, texunit); 713 714 /* The GL spec says that we should report an error if the unit is greater 715 * than GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, but in practice, only 716 * fixed-function units are usable. This is probably a spec bug. 717 * Ignore calls for non-fixed-func units, because we don't process 718 * glTexEnv for them either. 719 */ 720 if (!texUnit) 721 return; 722 723 if (pname == GL_TEXTURE_ENV_COLOR) { 724 if (_mesa_get_clamp_fragment_color(ctx, ctx->DrawBuffer)) 725 COPY_4FV( params, texUnit->EnvColor ); 726 else 727 COPY_4FV( params, texUnit->EnvColorUnclamped ); 728 } 729 else { 730 GLint val = get_texenvi(ctx, texUnit, pname); 731 if (val >= 0) { 732 *params = (GLfloat) val; 733 } 734 } 735 } 736 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) { 737 const struct gl_texture_unit *texUnit = _mesa_get_tex_unit(ctx, texunit); 738 739 if (pname == GL_TEXTURE_LOD_BIAS_EXT) { 740 *params = texUnit->LodBias; 741 } 742 else { 743 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" ); 744 return; 745 } 746 } 747 else if (target == GL_POINT_SPRITE) { 748 /* GL_ARB_point_sprite */ 749 if (!ctx->Extensions.ARB_point_sprite) { 750 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" ); 751 return; 752 } 753 if (pname == GL_COORD_REPLACE) { 754 if (ctx->Point.CoordReplace & (1u << texunit)) 755 *params = 1.0f; 756 else 757 *params = 0.0f; 758 } 759 else { 760 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(pname)" ); 761 return; 762 } 763 } 764 else { 765 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnvfv(target)" ); 766 return; 767 } 768} 769 770 771static void 772_mesa_gettexenviv_indexed( GLuint texunit, GLenum target, 773 GLenum pname, GLint *params ) 774{ 775 GLuint maxUnit; 776 GET_CURRENT_CONTEXT(ctx); 777 778 maxUnit = (target == GL_POINT_SPRITE && pname == GL_COORD_REPLACE) 779 ? ctx->Const.MaxTextureCoordUnits : ctx->Const.MaxCombinedTextureImageUnits; 780 if (texunit >= maxUnit) { 781 _mesa_error(ctx, GL_INVALID_OPERATION, "glGetTexEnviv(texunit=%d)", 782 texunit); 783 return; 784 } 785 786 if (target == GL_TEXTURE_ENV) { 787 struct gl_fixedfunc_texture_unit *texUnit = 788 _mesa_get_fixedfunc_tex_unit(ctx, texunit); 789 790 /* The GL spec says that we should report an error if the unit is greater 791 * than GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, but in practice, only 792 * fixed-function units are usable. This is probably a spec bug. 793 * Ignore calls for non-fixed-func units, because we don't process 794 * glTexEnv for them either. 795 */ 796 if (!texUnit) 797 return; 798 799 if (pname == GL_TEXTURE_ENV_COLOR) { 800 params[0] = FLOAT_TO_INT( texUnit->EnvColor[0] ); 801 params[1] = FLOAT_TO_INT( texUnit->EnvColor[1] ); 802 params[2] = FLOAT_TO_INT( texUnit->EnvColor[2] ); 803 params[3] = FLOAT_TO_INT( texUnit->EnvColor[3] ); 804 } 805 else { 806 GLint val = get_texenvi(ctx, texUnit, pname); 807 if (val >= 0) { 808 *params = val; 809 } 810 } 811 } 812 else if (target == GL_TEXTURE_FILTER_CONTROL_EXT) { 813 const struct gl_texture_unit *texUnit = _mesa_get_tex_unit(ctx, texunit); 814 815 if (pname == GL_TEXTURE_LOD_BIAS_EXT) { 816 *params = (GLint) texUnit->LodBias; 817 } 818 else { 819 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" ); 820 return; 821 } 822 } 823 else if (target == GL_POINT_SPRITE) { 824 /* GL_ARB_point_sprite */ 825 if (!ctx->Extensions.ARB_point_sprite) { 826 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" ); 827 return; 828 } 829 if (pname == GL_COORD_REPLACE) { 830 if (ctx->Point.CoordReplace & (1u << texunit)) 831 *params = GL_TRUE; 832 else 833 *params = GL_FALSE; 834 } 835 else { 836 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(pname)" ); 837 return; 838 } 839 } 840 else { 841 _mesa_error( ctx, GL_INVALID_ENUM, "glGetTexEnviv(target)" ); 842 return; 843 } 844} 845 846 847void GLAPIENTRY 848_mesa_GetTexEnvfv( GLenum target, GLenum pname, GLfloat *params ) 849{ 850 GET_CURRENT_CONTEXT(ctx); 851 _mesa_gettexenvfv_indexed(ctx->Texture.CurrentUnit, target, pname, params); 852} 853 854 855void GLAPIENTRY 856_mesa_GetMultiTexEnvfvEXT( GLenum texunit, GLenum target, 857 GLenum pname, GLfloat *params ) 858{ 859 _mesa_gettexenvfv_indexed(texunit - GL_TEXTURE0, target, pname, params); 860} 861 862 863void GLAPIENTRY 864_mesa_GetTexEnviv( GLenum target, GLenum pname, GLint *params ) 865{ 866 GET_CURRENT_CONTEXT(ctx); 867 _mesa_gettexenviv_indexed(ctx->Texture.CurrentUnit, target, pname, params); 868} 869 870 871void GLAPIENTRY 872_mesa_GetMultiTexEnvivEXT( GLenum texunit, GLenum target, 873 GLenum pname, GLint *params ) 874{ 875 _mesa_gettexenviv_indexed(texunit - GL_TEXTURE0, target, pname, params); 876} 877