1 /** 2 * \file blend.c 3 * Blending operations. 4 */ 5 6 /* 7 * Mesa 3-D graphics library 8 * Version: 6.5.1 9 * 10 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved. 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN 26 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 27 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28 */ 29 30 31 32 #include "glheader.h" 33 #include "blend.h" 34 #include "context.h" 35 #include "enums.h" 36 #include "macros.h" 37 #include "mtypes.h" 38 39 40 41 /** 42 * Check if given blend source factor is legal. 43 * \return GL_TRUE if legal, GL_FALSE otherwise. 44 */ 45 static GLboolean 46 legal_src_factor(const struct gl_context *ctx, GLenum factor) 47 { 48 switch (factor) { 49 case GL_SRC_COLOR: 50 case GL_ONE_MINUS_SRC_COLOR: 51 return ctx->Extensions.NV_blend_square; 52 case GL_ZERO: 53 case GL_ONE: 54 case GL_DST_COLOR: 55 case GL_ONE_MINUS_DST_COLOR: 56 case GL_SRC_ALPHA: 57 case GL_ONE_MINUS_SRC_ALPHA: 58 case GL_DST_ALPHA: 59 case GL_ONE_MINUS_DST_ALPHA: 60 case GL_SRC_ALPHA_SATURATE: 61 return GL_TRUE; 62 case GL_CONSTANT_COLOR: 63 case GL_ONE_MINUS_CONSTANT_COLOR: 64 case GL_CONSTANT_ALPHA: 65 case GL_ONE_MINUS_CONSTANT_ALPHA: 66 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 67 case GL_SRC1_COLOR: 68 case GL_SRC1_ALPHA: 69 case GL_ONE_MINUS_SRC1_COLOR: 70 case GL_ONE_MINUS_SRC1_ALPHA: 71 return _mesa_is_desktop_gl(ctx) 72 && ctx->Extensions.ARB_blend_func_extended; 73 default: 74 return GL_FALSE; 75 } 76 } 77 78 79 /** 80 * Check if given blend destination factor is legal. 81 * \return GL_TRUE if legal, GL_FALSE otherwise. 82 */ 83 static GLboolean 84 legal_dst_factor(const struct gl_context *ctx, GLenum factor) 85 { 86 switch (factor) { 87 case GL_DST_COLOR: 88 case GL_ONE_MINUS_DST_COLOR: 89 return ctx->Extensions.NV_blend_square; 90 case GL_ZERO: 91 case GL_ONE: 92 case GL_SRC_COLOR: 93 case GL_ONE_MINUS_SRC_COLOR: 94 case GL_SRC_ALPHA: 95 case GL_ONE_MINUS_SRC_ALPHA: 96 case GL_DST_ALPHA: 97 case GL_ONE_MINUS_DST_ALPHA: 98 return GL_TRUE; 99 case GL_CONSTANT_COLOR: 100 case GL_ONE_MINUS_CONSTANT_COLOR: 101 case GL_CONSTANT_ALPHA: 102 case GL_ONE_MINUS_CONSTANT_ALPHA: 103 return _mesa_is_desktop_gl(ctx) || ctx->API == API_OPENGLES2; 104 case GL_SRC_ALPHA_SATURATE: 105 return (_mesa_is_desktop_gl(ctx) 106 && ctx->Extensions.ARB_blend_func_extended) 107 || _mesa_is_gles3(ctx); 108 case GL_SRC1_COLOR: 109 case GL_SRC1_ALPHA: 110 case GL_ONE_MINUS_SRC1_COLOR: 111 case GL_ONE_MINUS_SRC1_ALPHA: 112 return _mesa_is_desktop_gl(ctx) 113 && ctx->Extensions.ARB_blend_func_extended; 114 default: 115 return GL_FALSE; 116 } 117 } 118 119 120 /** 121 * Check if src/dest RGB/A blend factors are legal. If not generate 122 * a GL error. 123 * \return GL_TRUE if factors are legal, GL_FALSE otherwise. 124 */ 125 static GLboolean 126 validate_blend_factors(struct gl_context *ctx, const char *func, 127 GLenum sfactorRGB, GLenum dfactorRGB, 128 GLenum sfactorA, GLenum dfactorA) 129 { 130 if (!legal_src_factor(ctx, sfactorRGB)) { 131 _mesa_error(ctx, GL_INVALID_ENUM, 132 "%s(sfactorRGB = %s)", func, 133 _mesa_lookup_enum_by_nr(sfactorRGB)); 134 return GL_FALSE; 135 } 136 137 if (!legal_dst_factor(ctx, dfactorRGB)) { 138 _mesa_error(ctx, GL_INVALID_ENUM, 139 "%s(dfactorRGB = %s)", func, 140 _mesa_lookup_enum_by_nr(dfactorRGB)); 141 return GL_FALSE; 142 } 143 144 if (sfactorA != sfactorRGB && !legal_src_factor(ctx, sfactorA)) { 145 _mesa_error(ctx, GL_INVALID_ENUM, 146 "%s(sfactorA = %s)", func, 147 _mesa_lookup_enum_by_nr(sfactorA)); 148 return GL_FALSE; 149 } 150 151 if (dfactorA != dfactorRGB && !legal_dst_factor(ctx, dfactorA)) { 152 _mesa_error(ctx, GL_INVALID_ENUM, 153 "%s(dfactorA = %s)", func, 154 _mesa_lookup_enum_by_nr(dfactorA)); 155 return GL_FALSE; 156 } 157 158 return GL_TRUE; 159 } 160 161 162 /** 163 * Specify the blending operation. 164 * 165 * \param sfactor source factor operator. 166 * \param dfactor destination factor operator. 167 * 168 * \sa glBlendFunc, glBlendFuncSeparateEXT 169 */ 170 void GLAPIENTRY 171 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 172 { 173 _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); 174 } 175 176 static GLboolean 177 blend_factor_is_dual_src(GLenum factor) 178 { 179 return (factor == GL_SRC1_COLOR || 180 factor == GL_SRC1_ALPHA || 181 factor == GL_ONE_MINUS_SRC1_COLOR || 182 factor == GL_ONE_MINUS_SRC1_ALPHA); 183 } 184 185 static void 186 update_uses_dual_src(struct gl_context *ctx, int buf) 187 { 188 ctx->Color.Blend[buf]._UsesDualSrc = 189 (blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcRGB) || 190 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstRGB) || 191 blend_factor_is_dual_src(ctx->Color.Blend[buf].SrcA) || 192 blend_factor_is_dual_src(ctx->Color.Blend[buf].DstA)); 193 } 194 195 /** 196 * Set the separate blend source/dest factors for all draw buffers. 197 * 198 * \param sfactorRGB RGB source factor operator. 199 * \param dfactorRGB RGB destination factor operator. 200 * \param sfactorA alpha source factor operator. 201 * \param dfactorA alpha destination factor operator. 202 */ 203 void GLAPIENTRY 204 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, 205 GLenum sfactorA, GLenum dfactorA ) 206 { 207 GLuint buf, numBuffers; 208 GLboolean changed; 209 GET_CURRENT_CONTEXT(ctx); 210 ASSERT_OUTSIDE_BEGIN_END(ctx); 211 212 if (MESA_VERBOSE & VERBOSE_API) 213 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 214 _mesa_lookup_enum_by_nr(sfactorRGB), 215 _mesa_lookup_enum_by_nr(dfactorRGB), 216 _mesa_lookup_enum_by_nr(sfactorA), 217 _mesa_lookup_enum_by_nr(dfactorA)); 218 219 if (!validate_blend_factors(ctx, "glBlendFuncSeparate", 220 sfactorRGB, dfactorRGB, 221 sfactorA, dfactorA)) { 222 return; 223 } 224 225 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 226 ? ctx->Const.MaxDrawBuffers : 1; 227 228 changed = GL_FALSE; 229 for (buf = 0; buf < numBuffers; buf++) { 230 if (ctx->Color.Blend[buf].SrcRGB != sfactorRGB || 231 ctx->Color.Blend[buf].DstRGB != dfactorRGB || 232 ctx->Color.Blend[buf].SrcA != sfactorA || 233 ctx->Color.Blend[buf].DstA != dfactorA) { 234 changed = GL_TRUE; 235 break; 236 } 237 } 238 if (!changed) 239 return; 240 241 FLUSH_VERTICES(ctx, _NEW_COLOR); 242 243 for (buf = 0; buf < numBuffers; buf++) { 244 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 245 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 246 ctx->Color.Blend[buf].SrcA = sfactorA; 247 ctx->Color.Blend[buf].DstA = dfactorA; 248 update_uses_dual_src(ctx, buf); 249 } 250 ctx->Color._BlendFuncPerBuffer = GL_FALSE; 251 252 if (ctx->Driver.BlendFuncSeparate) { 253 ctx->Driver.BlendFuncSeparate(ctx, sfactorRGB, dfactorRGB, 254 sfactorA, dfactorA); 255 } 256 } 257 258 259 #if _HAVE_FULL_GL 260 261 262 /** 263 * Set blend source/dest factors for one color buffer/target. 264 */ 265 void GLAPIENTRY 266 _mesa_BlendFunci(GLuint buf, GLenum sfactor, GLenum dfactor) 267 { 268 _mesa_BlendFuncSeparatei(buf, sfactor, dfactor, sfactor, dfactor); 269 } 270 271 272 /** 273 * Set separate blend source/dest factors for one color buffer/target. 274 */ 275 void GLAPIENTRY 276 _mesa_BlendFuncSeparatei(GLuint buf, GLenum sfactorRGB, GLenum dfactorRGB, 277 GLenum sfactorA, GLenum dfactorA) 278 { 279 GET_CURRENT_CONTEXT(ctx); 280 ASSERT_OUTSIDE_BEGIN_END(ctx); 281 282 if (!ctx->Extensions.ARB_draw_buffers_blend) { 283 _mesa_error(ctx, GL_INVALID_OPERATION, "glBlendFunc[Separate]i()"); 284 return; 285 } 286 287 if (buf >= ctx->Const.MaxDrawBuffers) { 288 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 289 buf); 290 return; 291 } 292 293 if (!validate_blend_factors(ctx, "glBlendFuncSeparatei", 294 sfactorRGB, dfactorRGB, 295 sfactorA, dfactorA)) { 296 return; 297 } 298 299 if (ctx->Color.Blend[buf].SrcRGB == sfactorRGB && 300 ctx->Color.Blend[buf].DstRGB == dfactorRGB && 301 ctx->Color.Blend[buf].SrcA == sfactorA && 302 ctx->Color.Blend[buf].DstA == dfactorA) 303 return; /* no change */ 304 305 FLUSH_VERTICES(ctx, _NEW_COLOR); 306 307 ctx->Color.Blend[buf].SrcRGB = sfactorRGB; 308 ctx->Color.Blend[buf].DstRGB = dfactorRGB; 309 ctx->Color.Blend[buf].SrcA = sfactorA; 310 ctx->Color.Blend[buf].DstA = dfactorA; 311 update_uses_dual_src(ctx, buf); 312 ctx->Color._BlendFuncPerBuffer = GL_TRUE; 313 314 if (ctx->Driver.BlendFuncSeparatei) { 315 ctx->Driver.BlendFuncSeparatei(ctx, buf, sfactorRGB, dfactorRGB, 316 sfactorA, dfactorA); 317 } 318 } 319 320 321 /** 322 * Check if given blend equation is legal. 323 * \return GL_TRUE if legal, GL_FALSE otherwise. 324 */ 325 static GLboolean 326 legal_blend_equation(const struct gl_context *ctx, GLenum mode) 327 { 328 switch (mode) { 329 case GL_FUNC_ADD: 330 case GL_FUNC_SUBTRACT: 331 case GL_FUNC_REVERSE_SUBTRACT: 332 return GL_TRUE; 333 case GL_MIN: 334 case GL_MAX: 335 return ctx->Extensions.EXT_blend_minmax; 336 default: 337 return GL_FALSE; 338 } 339 } 340 341 342 /* This is really an extension function! */ 343 void GLAPIENTRY 344 _mesa_BlendEquation( GLenum mode ) 345 { 346 GLuint buf, numBuffers; 347 GLboolean changed; 348 GET_CURRENT_CONTEXT(ctx); 349 ASSERT_OUTSIDE_BEGIN_END(ctx); 350 351 if (MESA_VERBOSE & VERBOSE_API) 352 _mesa_debug(ctx, "glBlendEquation(%s)\n", 353 _mesa_lookup_enum_by_nr(mode)); 354 355 if (!legal_blend_equation(ctx, mode)) { 356 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 357 return; 358 } 359 360 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 361 ? ctx->Const.MaxDrawBuffers : 1; 362 363 changed = GL_FALSE; 364 for (buf = 0; buf < numBuffers; buf++) { 365 if (ctx->Color.Blend[buf].EquationRGB != mode || 366 ctx->Color.Blend[buf].EquationA != mode) { 367 changed = GL_TRUE; 368 break; 369 } 370 } 371 if (!changed) 372 return; 373 374 FLUSH_VERTICES(ctx, _NEW_COLOR); 375 for (buf = 0; buf < numBuffers; buf++) { 376 ctx->Color.Blend[buf].EquationRGB = mode; 377 ctx->Color.Blend[buf].EquationA = mode; 378 } 379 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 380 381 if (ctx->Driver.BlendEquationSeparate) 382 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 383 } 384 385 386 /** 387 * Set blend equation for one color buffer/target. 388 */ 389 void GLAPIENTRY 390 _mesa_BlendEquationi(GLuint buf, GLenum mode) 391 { 392 GET_CURRENT_CONTEXT(ctx); 393 ASSERT_OUTSIDE_BEGIN_END(ctx); 394 395 if (MESA_VERBOSE & VERBOSE_API) 396 _mesa_debug(ctx, "glBlendEquationi(%u, %s)\n", 397 buf, _mesa_lookup_enum_by_nr(mode)); 398 399 if (buf >= ctx->Const.MaxDrawBuffers) { 400 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendFuncSeparatei(buffer=%u)", 401 buf); 402 return; 403 } 404 405 if (!legal_blend_equation(ctx, mode)) { 406 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationi"); 407 return; 408 } 409 410 if (ctx->Color.Blend[buf].EquationRGB == mode && 411 ctx->Color.Blend[buf].EquationA == mode) 412 return; /* no change */ 413 414 FLUSH_VERTICES(ctx, _NEW_COLOR); 415 ctx->Color.Blend[buf].EquationRGB = mode; 416 ctx->Color.Blend[buf].EquationA = mode; 417 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 418 419 if (ctx->Driver.BlendEquationSeparatei) 420 ctx->Driver.BlendEquationSeparatei(ctx, buf, mode, mode); 421 } 422 423 424 void GLAPIENTRY 425 _mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) 426 { 427 GLuint buf, numBuffers; 428 GLboolean changed; 429 GET_CURRENT_CONTEXT(ctx); 430 ASSERT_OUTSIDE_BEGIN_END(ctx); 431 432 if (MESA_VERBOSE & VERBOSE_API) 433 _mesa_debug(ctx, "glBlendEquationSeparateEXT(%s %s)\n", 434 _mesa_lookup_enum_by_nr(modeRGB), 435 _mesa_lookup_enum_by_nr(modeA)); 436 437 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 438 _mesa_error(ctx, GL_INVALID_OPERATION, 439 "glBlendEquationSeparateEXT not supported by driver"); 440 return; 441 } 442 443 if (!legal_blend_equation(ctx, modeRGB)) { 444 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 445 return; 446 } 447 448 if (!legal_blend_equation(ctx, modeA)) { 449 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 450 return; 451 } 452 453 numBuffers = ctx->Extensions.ARB_draw_buffers_blend 454 ? ctx->Const.MaxDrawBuffers : 1; 455 456 changed = GL_FALSE; 457 for (buf = 0; buf < numBuffers; buf++) { 458 if (ctx->Color.Blend[buf].EquationRGB != modeRGB || 459 ctx->Color.Blend[buf].EquationA != modeA) { 460 changed = GL_TRUE; 461 break; 462 } 463 } 464 if (!changed) 465 return; 466 467 FLUSH_VERTICES(ctx, _NEW_COLOR); 468 for (buf = 0; buf < numBuffers; buf++) { 469 ctx->Color.Blend[buf].EquationRGB = modeRGB; 470 ctx->Color.Blend[buf].EquationA = modeA; 471 } 472 ctx->Color._BlendEquationPerBuffer = GL_FALSE; 473 474 if (ctx->Driver.BlendEquationSeparate) 475 ctx->Driver.BlendEquationSeparate(ctx, modeRGB, modeA); 476 } 477 478 479 /** 480 * Set separate blend equations for one color buffer/target. 481 */ 482 void GLAPIENTRY 483 _mesa_BlendEquationSeparatei(GLuint buf, GLenum modeRGB, GLenum modeA) 484 { 485 GET_CURRENT_CONTEXT(ctx); 486 ASSERT_OUTSIDE_BEGIN_END(ctx); 487 488 if (MESA_VERBOSE & VERBOSE_API) 489 _mesa_debug(ctx, "glBlendEquationSeparatei(%u, %s %s)\n", buf, 490 _mesa_lookup_enum_by_nr(modeRGB), 491 _mesa_lookup_enum_by_nr(modeA)); 492 493 if (buf >= ctx->Const.MaxDrawBuffers) { 494 _mesa_error(ctx, GL_INVALID_VALUE, "glBlendEquationSeparatei(buffer=%u)", 495 buf); 496 return; 497 } 498 499 if (!legal_blend_equation(ctx, modeRGB)) { 500 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeRGB)"); 501 return; 502 } 503 504 if (!legal_blend_equation(ctx, modeA)) { 505 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparatei(modeA)"); 506 return; 507 } 508 509 if (ctx->Color.Blend[buf].EquationRGB == modeRGB && 510 ctx->Color.Blend[buf].EquationA == modeA) 511 return; /* no change */ 512 513 FLUSH_VERTICES(ctx, _NEW_COLOR); 514 ctx->Color.Blend[buf].EquationRGB = modeRGB; 515 ctx->Color.Blend[buf].EquationA = modeA; 516 ctx->Color._BlendEquationPerBuffer = GL_TRUE; 517 518 if (ctx->Driver.BlendEquationSeparatei) 519 ctx->Driver.BlendEquationSeparatei(ctx, buf, modeRGB, modeA); 520 } 521 522 523 524 #endif /* _HAVE_FULL_GL */ 525 526 527 /** 528 * Set the blending color. 529 * 530 * \param red red color component. 531 * \param green green color component. 532 * \param blue blue color component. 533 * \param alpha alpha color component. 534 * 535 * \sa glBlendColor(). 536 * 537 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 538 * change, flushes the vertices and notifies the driver via 539 * dd_function_table::BlendColor callback. 540 */ 541 void GLAPIENTRY 542 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 543 { 544 GLfloat tmp[4]; 545 GET_CURRENT_CONTEXT(ctx); 546 ASSERT_OUTSIDE_BEGIN_END(ctx); 547 548 tmp[0] = red; 549 tmp[1] = green; 550 tmp[2] = blue; 551 tmp[3] = alpha; 552 553 if (TEST_EQ_4V(tmp, ctx->Color.BlendColorUnclamped)) 554 return; 555 556 FLUSH_VERTICES(ctx, _NEW_COLOR); 557 COPY_4FV( ctx->Color.BlendColorUnclamped, tmp ); 558 559 ctx->Color.BlendColor[0] = CLAMP(tmp[0], 0.0F, 1.0F); 560 ctx->Color.BlendColor[1] = CLAMP(tmp[1], 0.0F, 1.0F); 561 ctx->Color.BlendColor[2] = CLAMP(tmp[2], 0.0F, 1.0F); 562 ctx->Color.BlendColor[3] = CLAMP(tmp[3], 0.0F, 1.0F); 563 564 if (ctx->Driver.BlendColor) 565 (*ctx->Driver.BlendColor)(ctx, ctx->Color.BlendColor); 566 } 567 568 569 /** 570 * Specify the alpha test function. 571 * 572 * \param func alpha comparison function. 573 * \param ref reference value. 574 * 575 * Verifies the parameters and updates gl_colorbuffer_attrib. 576 * On a change, flushes the vertices and notifies the driver via 577 * dd_function_table::AlphaFunc callback. 578 */ 579 void GLAPIENTRY 580 _mesa_AlphaFunc( GLenum func, GLclampf ref ) 581 { 582 GET_CURRENT_CONTEXT(ctx); 583 ASSERT_OUTSIDE_BEGIN_END(ctx); 584 585 if (MESA_VERBOSE & VERBOSE_API) 586 _mesa_debug(ctx, "glAlphaFunc(%s, %f)\n", 587 _mesa_lookup_enum_by_nr(func), ref); 588 589 switch (func) { 590 case GL_NEVER: 591 case GL_LESS: 592 case GL_EQUAL: 593 case GL_LEQUAL: 594 case GL_GREATER: 595 case GL_NOTEQUAL: 596 case GL_GEQUAL: 597 case GL_ALWAYS: 598 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRefUnclamped == ref) 599 return; /* no change */ 600 601 FLUSH_VERTICES(ctx, _NEW_COLOR); 602 ctx->Color.AlphaFunc = func; 603 ctx->Color.AlphaRefUnclamped = ref; 604 ctx->Color.AlphaRef = CLAMP(ref, 0.0F, 1.0F); 605 606 if (ctx->Driver.AlphaFunc) 607 ctx->Driver.AlphaFunc(ctx, func, ctx->Color.AlphaRef); 608 return; 609 610 default: 611 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 612 return; 613 } 614 } 615 616 617 /** 618 * Specify a logic pixel operation for color index rendering. 619 * 620 * \param opcode operation. 621 * 622 * Verifies that \p opcode is a valid enum and updates 623 gl_colorbuffer_attrib::LogicOp. 624 * On a change, flushes the vertices and notifies the driver via the 625 * dd_function_table::LogicOpcode callback. 626 */ 627 void GLAPIENTRY 628 _mesa_LogicOp( GLenum opcode ) 629 { 630 GET_CURRENT_CONTEXT(ctx); 631 ASSERT_OUTSIDE_BEGIN_END(ctx); 632 633 if (MESA_VERBOSE & VERBOSE_API) 634 _mesa_debug(ctx, "glLogicOp(%s)\n", _mesa_lookup_enum_by_nr(opcode)); 635 636 switch (opcode) { 637 case GL_CLEAR: 638 case GL_SET: 639 case GL_COPY: 640 case GL_COPY_INVERTED: 641 case GL_NOOP: 642 case GL_INVERT: 643 case GL_AND: 644 case GL_NAND: 645 case GL_OR: 646 case GL_NOR: 647 case GL_XOR: 648 case GL_EQUIV: 649 case GL_AND_REVERSE: 650 case GL_AND_INVERTED: 651 case GL_OR_REVERSE: 652 case GL_OR_INVERTED: 653 break; 654 default: 655 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 656 return; 657 } 658 659 if (ctx->Color.LogicOp == opcode) 660 return; 661 662 FLUSH_VERTICES(ctx, _NEW_COLOR); 663 ctx->Color.LogicOp = opcode; 664 665 if (ctx->Driver.LogicOpcode) 666 ctx->Driver.LogicOpcode( ctx, opcode ); 667 } 668 669 #if _HAVE_FULL_GL 670 void GLAPIENTRY 671 _mesa_IndexMask( GLuint mask ) 672 { 673 GET_CURRENT_CONTEXT(ctx); 674 ASSERT_OUTSIDE_BEGIN_END(ctx); 675 676 if (ctx->Color.IndexMask == mask) 677 return; 678 679 FLUSH_VERTICES(ctx, _NEW_COLOR); 680 ctx->Color.IndexMask = mask; 681 } 682 #endif 683 684 685 /** 686 * Enable or disable writing of frame buffer color components. 687 * 688 * \param red whether to mask writing of the red color component. 689 * \param green whether to mask writing of the green color component. 690 * \param blue whether to mask writing of the blue color component. 691 * \param alpha whether to mask writing of the alpha color component. 692 * 693 * \sa glColorMask(). 694 * 695 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 696 * change, flushes the vertices and notifies the driver via the 697 * dd_function_table::ColorMask callback. 698 */ 699 void GLAPIENTRY 700 _mesa_ColorMask( GLboolean red, GLboolean green, 701 GLboolean blue, GLboolean alpha ) 702 { 703 GET_CURRENT_CONTEXT(ctx); 704 GLubyte tmp[4]; 705 GLuint i; 706 GLboolean flushed; 707 ASSERT_OUTSIDE_BEGIN_END(ctx); 708 709 if (MESA_VERBOSE & VERBOSE_API) 710 _mesa_debug(ctx, "glColorMask(%d, %d, %d, %d)\n", 711 red, green, blue, alpha); 712 713 /* Shouldn't have any information about channel depth in core mesa 714 * -- should probably store these as the native booleans: 715 */ 716 tmp[RCOMP] = red ? 0xff : 0x0; 717 tmp[GCOMP] = green ? 0xff : 0x0; 718 tmp[BCOMP] = blue ? 0xff : 0x0; 719 tmp[ACOMP] = alpha ? 0xff : 0x0; 720 721 flushed = GL_FALSE; 722 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 723 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 724 if (!flushed) { 725 FLUSH_VERTICES(ctx, _NEW_COLOR); 726 } 727 flushed = GL_TRUE; 728 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 729 } 730 } 731 732 if (ctx->Driver.ColorMask) 733 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 734 } 735 736 737 /** 738 * For GL_EXT_draw_buffers2 and GL3 739 */ 740 void GLAPIENTRY 741 _mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, 742 GLboolean blue, GLboolean alpha ) 743 { 744 GLubyte tmp[4]; 745 GET_CURRENT_CONTEXT(ctx); 746 ASSERT_OUTSIDE_BEGIN_END(ctx); 747 748 if (MESA_VERBOSE & VERBOSE_API) 749 _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", 750 buf, red, green, blue, alpha); 751 752 if (buf >= ctx->Const.MaxDrawBuffers) { 753 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); 754 return; 755 } 756 757 /* Shouldn't have any information about channel depth in core mesa 758 * -- should probably store these as the native booleans: 759 */ 760 tmp[RCOMP] = red ? 0xff : 0x0; 761 tmp[GCOMP] = green ? 0xff : 0x0; 762 tmp[BCOMP] = blue ? 0xff : 0x0; 763 tmp[ACOMP] = alpha ? 0xff : 0x0; 764 765 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 766 return; 767 768 FLUSH_VERTICES(ctx, _NEW_COLOR); 769 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 770 771 if (ctx->Driver.ColorMaskIndexed) 772 ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); 773 } 774 775 776 void GLAPIENTRY 777 _mesa_ClampColorARB(GLenum target, GLenum clamp) 778 { 779 GET_CURRENT_CONTEXT(ctx); 780 781 ASSERT_OUTSIDE_BEGIN_END(ctx); 782 783 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 784 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 785 return; 786 } 787 788 switch (target) { 789 case GL_CLAMP_VERTEX_COLOR_ARB: 790 FLUSH_VERTICES(ctx, _NEW_LIGHT); 791 ctx->Light.ClampVertexColor = clamp; 792 break; 793 case GL_CLAMP_FRAGMENT_COLOR_ARB: 794 FLUSH_VERTICES(ctx, _NEW_FRAG_CLAMP); 795 ctx->Color.ClampFragmentColor = clamp; 796 break; 797 case GL_CLAMP_READ_COLOR_ARB: 798 FLUSH_VERTICES(ctx, _NEW_COLOR); 799 ctx->Color.ClampReadColor = clamp; 800 break; 801 default: 802 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); 803 return; 804 } 805 } 806 807 808 809 810 /**********************************************************************/ 811 /** \name Initialization */ 812 /*@{*/ 813 814 /** 815 * Initialization of the context's Color attribute group. 816 * 817 * \param ctx GL context. 818 * 819 * Initializes the related fields in the context color attribute group, 820 * __struct gl_contextRec::Color. 821 */ 822 void _mesa_init_color( struct gl_context * ctx ) 823 { 824 GLuint i; 825 826 /* Color buffer group */ 827 ctx->Color.IndexMask = ~0u; 828 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 829 ctx->Color.ClearIndex = 0; 830 ASSIGN_4V( ctx->Color.ClearColor.f, 0, 0, 0, 0 ); 831 ctx->Color.AlphaEnabled = GL_FALSE; 832 ctx->Color.AlphaFunc = GL_ALWAYS; 833 ctx->Color.AlphaRef = 0; 834 ctx->Color.BlendEnabled = 0x0; 835 for (i = 0; i < Elements(ctx->Color.Blend); i++) { 836 ctx->Color.Blend[i].SrcRGB = GL_ONE; 837 ctx->Color.Blend[i].DstRGB = GL_ZERO; 838 ctx->Color.Blend[i].SrcA = GL_ONE; 839 ctx->Color.Blend[i].DstA = GL_ZERO; 840 ctx->Color.Blend[i].EquationRGB = GL_FUNC_ADD; 841 ctx->Color.Blend[i].EquationA = GL_FUNC_ADD; 842 } 843 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 844 ASSIGN_4V( ctx->Color.BlendColorUnclamped, 0.0, 0.0, 0.0, 0.0 ); 845 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 846 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 847 ctx->Color.LogicOp = GL_COPY; 848 ctx->Color.DitherFlag = GL_TRUE; 849 850 if (ctx->Visual.doubleBufferMode) { 851 ctx->Color.DrawBuffer[0] = GL_BACK; 852 } 853 else { 854 ctx->Color.DrawBuffer[0] = GL_FRONT; 855 } 856 857 ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; 858 ctx->Color._ClampFragmentColor = GL_TRUE; 859 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 860 ctx->Color._ClampReadColor = GL_TRUE; 861 } 862 863 /*@}*/ 864