blend.c revision cdc920a0
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 * Specify the blending operation. 42 * 43 * \param sfactor source factor operator. 44 * \param dfactor destination factor operator. 45 * 46 * \sa glBlendFunc, glBlendFuncSeparateEXT 47 */ 48void GLAPIENTRY 49_mesa_BlendFunc( GLenum sfactor, GLenum dfactor ) 50{ 51 _mesa_BlendFuncSeparateEXT(sfactor, dfactor, sfactor, dfactor); 52} 53 54 55/** 56 * Process GL_EXT_blend_func_separate(). 57 * 58 * \param sfactorRGB RGB source factor operator. 59 * \param dfactorRGB RGB destination factor operator. 60 * \param sfactorA alpha source factor operator. 61 * \param dfactorA alpha destination factor operator. 62 * 63 * Verifies the parameters and updates gl_colorbuffer_attrib. 64 * On a change, flush the vertices and notify the driver via 65 * dd_function_table::BlendFuncSeparate. 66 */ 67void GLAPIENTRY 68_mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB, 69 GLenum sfactorA, GLenum dfactorA ) 70{ 71 GET_CURRENT_CONTEXT(ctx); 72 ASSERT_OUTSIDE_BEGIN_END(ctx); 73 74 if (MESA_VERBOSE & VERBOSE_API) 75 _mesa_debug(ctx, "glBlendFuncSeparate %s %s %s %s\n", 76 _mesa_lookup_enum_by_nr(sfactorRGB), 77 _mesa_lookup_enum_by_nr(dfactorRGB), 78 _mesa_lookup_enum_by_nr(sfactorA), 79 _mesa_lookup_enum_by_nr(dfactorA)); 80 81 switch (sfactorRGB) { 82 case GL_SRC_COLOR: 83 case GL_ONE_MINUS_SRC_COLOR: 84 if (!ctx->Extensions.NV_blend_square) { 85 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 86 return; 87 } 88 /* fall-through */ 89 case GL_ZERO: 90 case GL_ONE: 91 case GL_DST_COLOR: 92 case GL_ONE_MINUS_DST_COLOR: 93 case GL_SRC_ALPHA: 94 case GL_ONE_MINUS_SRC_ALPHA: 95 case GL_DST_ALPHA: 96 case GL_ONE_MINUS_DST_ALPHA: 97 case GL_SRC_ALPHA_SATURATE: 98 case GL_CONSTANT_COLOR: 99 case GL_ONE_MINUS_CONSTANT_COLOR: 100 case GL_CONSTANT_ALPHA: 101 case GL_ONE_MINUS_CONSTANT_ALPHA: 102 break; 103 default: 104 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorRGB)"); 105 return; 106 } 107 108 switch (dfactorRGB) { 109 case GL_DST_COLOR: 110 case GL_ONE_MINUS_DST_COLOR: 111 if (!ctx->Extensions.NV_blend_square) { 112 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 113 return; 114 } 115 /* fall-through */ 116 case GL_ZERO: 117 case GL_ONE: 118 case GL_SRC_COLOR: 119 case GL_ONE_MINUS_SRC_COLOR: 120 case GL_SRC_ALPHA: 121 case GL_ONE_MINUS_SRC_ALPHA: 122 case GL_DST_ALPHA: 123 case GL_ONE_MINUS_DST_ALPHA: 124 case GL_CONSTANT_COLOR: 125 case GL_ONE_MINUS_CONSTANT_COLOR: 126 case GL_CONSTANT_ALPHA: 127 case GL_ONE_MINUS_CONSTANT_ALPHA: 128 break; 129 default: 130 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorRGB)"); 131 return; 132 } 133 134 switch (sfactorA) { 135 case GL_SRC_COLOR: 136 case GL_ONE_MINUS_SRC_COLOR: 137 if (!ctx->Extensions.NV_blend_square) { 138 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 139 return; 140 } 141 /* fall-through */ 142 case GL_ZERO: 143 case GL_ONE: 144 case GL_DST_COLOR: 145 case GL_ONE_MINUS_DST_COLOR: 146 case GL_SRC_ALPHA: 147 case GL_ONE_MINUS_SRC_ALPHA: 148 case GL_DST_ALPHA: 149 case GL_ONE_MINUS_DST_ALPHA: 150 case GL_SRC_ALPHA_SATURATE: 151 case GL_CONSTANT_COLOR: 152 case GL_ONE_MINUS_CONSTANT_COLOR: 153 case GL_CONSTANT_ALPHA: 154 case GL_ONE_MINUS_CONSTANT_ALPHA: 155 break; 156 default: 157 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (sfactorA)"); 158 return; 159 } 160 161 switch (dfactorA) { 162 case GL_DST_COLOR: 163 case GL_ONE_MINUS_DST_COLOR: 164 if (!ctx->Extensions.NV_blend_square) { 165 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)"); 166 return; 167 } 168 /* fall-through */ 169 case GL_ZERO: 170 case GL_ONE: 171 case GL_SRC_COLOR: 172 case GL_ONE_MINUS_SRC_COLOR: 173 case GL_SRC_ALPHA: 174 case GL_ONE_MINUS_SRC_ALPHA: 175 case GL_DST_ALPHA: 176 case GL_ONE_MINUS_DST_ALPHA: 177 case GL_CONSTANT_COLOR: 178 case GL_ONE_MINUS_CONSTANT_COLOR: 179 case GL_CONSTANT_ALPHA: 180 case GL_ONE_MINUS_CONSTANT_ALPHA: 181 break; 182 default: 183 _mesa_error( ctx, GL_INVALID_ENUM, "glBlendFunc or glBlendFuncSeparate (dfactorA)" ); 184 return; 185 } 186 187 if (ctx->Color.BlendSrcRGB == sfactorRGB && 188 ctx->Color.BlendDstRGB == dfactorRGB && 189 ctx->Color.BlendSrcA == sfactorA && 190 ctx->Color.BlendDstA == dfactorA) 191 return; 192 193 FLUSH_VERTICES(ctx, _NEW_COLOR); 194 195 ctx->Color.BlendSrcRGB = sfactorRGB; 196 ctx->Color.BlendDstRGB = dfactorRGB; 197 ctx->Color.BlendSrcA = sfactorA; 198 ctx->Color.BlendDstA = dfactorA; 199 200 if (ctx->Driver.BlendFuncSeparate) { 201 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB, 202 sfactorA, dfactorA ); 203 } 204} 205 206 207#if _HAVE_FULL_GL 208 209static GLboolean 210_mesa_validate_blend_equation( GLcontext *ctx, 211 GLenum mode, GLboolean is_separate ) 212{ 213 switch (mode) { 214 case GL_FUNC_ADD: 215 break; 216 case GL_MIN: 217 case GL_MAX: 218 if (!ctx->Extensions.EXT_blend_minmax && 219 !ctx->Extensions.ARB_imaging) { 220 return GL_FALSE; 221 } 222 break; 223 /* glBlendEquationSeparate cannot take GL_LOGIC_OP as a parameter. 224 */ 225 case GL_LOGIC_OP: 226 if (!ctx->Extensions.EXT_blend_logic_op || is_separate) { 227 return GL_FALSE; 228 } 229 break; 230 case GL_FUNC_SUBTRACT: 231 case GL_FUNC_REVERSE_SUBTRACT: 232 if (!ctx->Extensions.EXT_blend_subtract && 233 !ctx->Extensions.ARB_imaging) { 234 return GL_FALSE; 235 } 236 break; 237 default: 238 return GL_FALSE; 239 } 240 241 return GL_TRUE; 242} 243 244 245/* This is really an extension function! */ 246void GLAPIENTRY 247_mesa_BlendEquation( GLenum mode ) 248{ 249 GET_CURRENT_CONTEXT(ctx); 250 ASSERT_OUTSIDE_BEGIN_END(ctx); 251 252 if (MESA_VERBOSE & VERBOSE_API) 253 _mesa_debug(ctx, "glBlendEquation %s\n", 254 _mesa_lookup_enum_by_nr(mode)); 255 256 if ( ! _mesa_validate_blend_equation( ctx, mode, GL_FALSE ) ) { 257 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquation"); 258 return; 259 } 260 261 if ( (ctx->Color.BlendEquationRGB == mode) && 262 (ctx->Color.BlendEquationA == mode) ) 263 return; 264 265 FLUSH_VERTICES(ctx, _NEW_COLOR); 266 ctx->Color.BlendEquationRGB = mode; 267 ctx->Color.BlendEquationA = mode; 268 269 if (ctx->Driver.BlendEquationSeparate) 270 (*ctx->Driver.BlendEquationSeparate)( ctx, mode, mode ); 271} 272 273 274void GLAPIENTRY 275_mesa_BlendEquationSeparateEXT( GLenum modeRGB, GLenum modeA ) 276{ 277 GET_CURRENT_CONTEXT(ctx); 278 ASSERT_OUTSIDE_BEGIN_END(ctx); 279 280 if (MESA_VERBOSE & VERBOSE_API) 281 _mesa_debug(ctx, "glBlendEquationSeparateEXT %s %s\n", 282 _mesa_lookup_enum_by_nr(modeRGB), 283 _mesa_lookup_enum_by_nr(modeA)); 284 285 if ( (modeRGB != modeA) && !ctx->Extensions.EXT_blend_equation_separate ) { 286 _mesa_error(ctx, GL_INVALID_OPERATION, 287 "glBlendEquationSeparateEXT not supported by driver"); 288 return; 289 } 290 291 if ( ! _mesa_validate_blend_equation( ctx, modeRGB, GL_TRUE ) ) { 292 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeRGB)"); 293 return; 294 } 295 296 if ( ! _mesa_validate_blend_equation( ctx, modeA, GL_TRUE ) ) { 297 _mesa_error(ctx, GL_INVALID_ENUM, "glBlendEquationSeparateEXT(modeA)"); 298 return; 299 } 300 301 302 if ( (ctx->Color.BlendEquationRGB == modeRGB) && 303 (ctx->Color.BlendEquationA == modeA) ) 304 return; 305 306 FLUSH_VERTICES(ctx, _NEW_COLOR); 307 ctx->Color.BlendEquationRGB = modeRGB; 308 ctx->Color.BlendEquationA = modeA; 309 310 if (ctx->Driver.BlendEquationSeparate) 311 (*ctx->Driver.BlendEquationSeparate)( ctx, modeRGB, modeA ); 312} 313#endif 314 315 316/** 317 * Set the blending color. 318 * 319 * \param red red color component. 320 * \param green green color component. 321 * \param blue blue color component. 322 * \param alpha alpha color component. 323 * 324 * \sa glBlendColor(). 325 * 326 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a 327 * change, flushes the vertices and notifies the driver via 328 * dd_function_table::BlendColor callback. 329 */ 330void GLAPIENTRY 331_mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) 332{ 333 GLfloat tmp[4]; 334 GET_CURRENT_CONTEXT(ctx); 335 ASSERT_OUTSIDE_BEGIN_END(ctx); 336 337 tmp[0] = CLAMP( red, 0.0F, 1.0F ); 338 tmp[1] = CLAMP( green, 0.0F, 1.0F ); 339 tmp[2] = CLAMP( blue, 0.0F, 1.0F ); 340 tmp[3] = CLAMP( alpha, 0.0F, 1.0F ); 341 342 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor)) 343 return; 344 345 FLUSH_VERTICES(ctx, _NEW_COLOR); 346 COPY_4FV( ctx->Color.BlendColor, tmp ); 347 348 if (ctx->Driver.BlendColor) 349 (*ctx->Driver.BlendColor)(ctx, tmp); 350} 351 352 353/** 354 * Specify the alpha test function. 355 * 356 * \param func alpha comparison function. 357 * \param ref reference value. 358 * 359 * Verifies the parameters and updates gl_colorbuffer_attrib. 360 * On a change, flushes the vertices and notifies the driver via 361 * dd_function_table::AlphaFunc callback. 362 */ 363void GLAPIENTRY 364_mesa_AlphaFunc( GLenum func, GLclampf ref ) 365{ 366 GET_CURRENT_CONTEXT(ctx); 367 ASSERT_OUTSIDE_BEGIN_END(ctx); 368 369 switch (func) { 370 case GL_NEVER: 371 case GL_LESS: 372 case GL_EQUAL: 373 case GL_LEQUAL: 374 case GL_GREATER: 375 case GL_NOTEQUAL: 376 case GL_GEQUAL: 377 case GL_ALWAYS: 378 ref = CLAMP(ref, 0.0F, 1.0F); 379 380 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref) 381 return; /* no change */ 382 383 FLUSH_VERTICES(ctx, _NEW_COLOR); 384 ctx->Color.AlphaFunc = func; 385 ctx->Color.AlphaRef = ref; 386 387 if (ctx->Driver.AlphaFunc) 388 ctx->Driver.AlphaFunc(ctx, func, ref); 389 return; 390 391 default: 392 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" ); 393 return; 394 } 395} 396 397 398/** 399 * Specify a logic pixel operation for color index rendering. 400 * 401 * \param opcode operation. 402 * 403 * Verifies that \p opcode is a valid enum and updates 404gl_colorbuffer_attrib::LogicOp. 405 * On a change, flushes the vertices and notifies the driver via the 406 * dd_function_table::LogicOpcode callback. 407 */ 408void GLAPIENTRY 409_mesa_LogicOp( GLenum opcode ) 410{ 411 GET_CURRENT_CONTEXT(ctx); 412 ASSERT_OUTSIDE_BEGIN_END(ctx); 413 414 switch (opcode) { 415 case GL_CLEAR: 416 case GL_SET: 417 case GL_COPY: 418 case GL_COPY_INVERTED: 419 case GL_NOOP: 420 case GL_INVERT: 421 case GL_AND: 422 case GL_NAND: 423 case GL_OR: 424 case GL_NOR: 425 case GL_XOR: 426 case GL_EQUIV: 427 case GL_AND_REVERSE: 428 case GL_AND_INVERTED: 429 case GL_OR_REVERSE: 430 case GL_OR_INVERTED: 431 break; 432 default: 433 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" ); 434 return; 435 } 436 437 if (ctx->Color.LogicOp == opcode) 438 return; 439 440 FLUSH_VERTICES(ctx, _NEW_COLOR); 441 ctx->Color.LogicOp = opcode; 442 443 if (ctx->Driver.LogicOpcode) 444 ctx->Driver.LogicOpcode( ctx, opcode ); 445} 446 447#if _HAVE_FULL_GL 448void GLAPIENTRY 449_mesa_IndexMask( GLuint mask ) 450{ 451 GET_CURRENT_CONTEXT(ctx); 452 ASSERT_OUTSIDE_BEGIN_END(ctx); 453 454 if (ctx->Color.IndexMask == mask) 455 return; 456 457 FLUSH_VERTICES(ctx, _NEW_COLOR); 458 ctx->Color.IndexMask = mask; 459} 460#endif 461 462 463/** 464 * Enable or disable writing of frame buffer color components. 465 * 466 * \param red whether to mask writing of the red color component. 467 * \param green whether to mask writing of the green color component. 468 * \param blue whether to mask writing of the blue color component. 469 * \param alpha whether to mask writing of the alpha color component. 470 * 471 * \sa glColorMask(). 472 * 473 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a 474 * change, flushes the vertices and notifies the driver via the 475 * dd_function_table::ColorMask callback. 476 */ 477void GLAPIENTRY 478_mesa_ColorMask( GLboolean red, GLboolean green, 479 GLboolean blue, GLboolean alpha ) 480{ 481 GET_CURRENT_CONTEXT(ctx); 482 GLubyte tmp[4]; 483 GLuint i; 484 GLboolean flushed; 485 ASSERT_OUTSIDE_BEGIN_END(ctx); 486 487 if (MESA_VERBOSE & VERBOSE_API) 488 _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha); 489 490 /* Shouldn't have any information about channel depth in core mesa 491 * -- should probably store these as the native booleans: 492 */ 493 tmp[RCOMP] = red ? 0xff : 0x0; 494 tmp[GCOMP] = green ? 0xff : 0x0; 495 tmp[BCOMP] = blue ? 0xff : 0x0; 496 tmp[ACOMP] = alpha ? 0xff : 0x0; 497 498 flushed = GL_FALSE; 499 for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { 500 if (!TEST_EQ_4V(tmp, ctx->Color.ColorMask[i])) { 501 if (!flushed) { 502 FLUSH_VERTICES(ctx, _NEW_COLOR); 503 } 504 flushed = GL_TRUE; 505 COPY_4UBV(ctx->Color.ColorMask[i], tmp); 506 } 507 } 508 509 if (ctx->Driver.ColorMask) 510 ctx->Driver.ColorMask( ctx, red, green, blue, alpha ); 511} 512 513 514/** 515 * For GL_EXT_draw_buffers2 and GL3 516 */ 517void GLAPIENTRY 518_mesa_ColorMaskIndexed( GLuint buf, GLboolean red, GLboolean green, 519 GLboolean blue, GLboolean alpha ) 520{ 521 GLubyte tmp[4]; 522 GET_CURRENT_CONTEXT(ctx); 523 ASSERT_OUTSIDE_BEGIN_END(ctx); 524 525 if (MESA_VERBOSE & VERBOSE_API) 526 _mesa_debug(ctx, "glColorMaskIndexed %u %d %d %d %d\n", 527 buf, red, green, blue, alpha); 528 529 if (buf >= ctx->Const.MaxDrawBuffers) { 530 _mesa_error(ctx, GL_INVALID_VALUE, "glColorMaskIndexed(buf=%u)", buf); 531 return; 532 } 533 534 /* Shouldn't have any information about channel depth in core mesa 535 * -- should probably store these as the native booleans: 536 */ 537 tmp[RCOMP] = red ? 0xff : 0x0; 538 tmp[GCOMP] = green ? 0xff : 0x0; 539 tmp[BCOMP] = blue ? 0xff : 0x0; 540 tmp[ACOMP] = alpha ? 0xff : 0x0; 541 542 if (TEST_EQ_4V(tmp, ctx->Color.ColorMask[buf])) 543 return; 544 545 FLUSH_VERTICES(ctx, _NEW_COLOR); 546 COPY_4UBV(ctx->Color.ColorMask[buf], tmp); 547 548 if (ctx->Driver.ColorMaskIndexed) 549 ctx->Driver.ColorMaskIndexed(ctx, buf, red, green, blue, alpha); 550} 551 552 553extern void GLAPIENTRY 554_mesa_ClampColorARB(GLenum target, GLenum clamp) 555{ 556 GET_CURRENT_CONTEXT(ctx); 557 558 ASSERT_OUTSIDE_BEGIN_END(ctx); 559 560 if (clamp != GL_TRUE && clamp != GL_FALSE && clamp != GL_FIXED_ONLY_ARB) { 561 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(clamp)"); 562 return; 563 } 564 565 switch (target) { 566 case GL_CLAMP_VERTEX_COLOR_ARB: 567 ctx->Light.ClampVertexColor = clamp; 568 break; 569 case GL_CLAMP_FRAGMENT_COLOR_ARB: 570 ctx->Color.ClampFragmentColor = clamp; 571 break; 572 case GL_CLAMP_READ_COLOR_ARB: 573 ctx->Color.ClampReadColor = clamp; 574 break; 575 default: 576 _mesa_error(ctx, GL_INVALID_ENUM, "glClampColorARB(target)"); 577 return; 578 } 579} 580 581 582 583 584/**********************************************************************/ 585/** \name Initialization */ 586/*@{*/ 587 588/** 589 * Initialization of the context's Color attribute group. 590 * 591 * \param ctx GL context. 592 * 593 * Initializes the related fields in the context color attribute group, 594 * __GLcontextRec::Color. 595 */ 596void _mesa_init_color( GLcontext * ctx ) 597{ 598 /* Color buffer group */ 599 ctx->Color.IndexMask = ~0u; 600 memset(ctx->Color.ColorMask, 0xff, sizeof(ctx->Color.ColorMask)); 601 ctx->Color.ClearIndex = 0; 602 ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 ); 603 ctx->Color.AlphaEnabled = GL_FALSE; 604 ctx->Color.AlphaFunc = GL_ALWAYS; 605 ctx->Color.AlphaRef = 0; 606 ctx->Color.BlendEnabled = 0x0; 607 ctx->Color.BlendSrcRGB = GL_ONE; 608 ctx->Color.BlendDstRGB = GL_ZERO; 609 ctx->Color.BlendSrcA = GL_ONE; 610 ctx->Color.BlendDstA = GL_ZERO; 611 ctx->Color.BlendEquationRGB = GL_FUNC_ADD; 612 ctx->Color.BlendEquationA = GL_FUNC_ADD; 613 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 ); 614 ctx->Color.IndexLogicOpEnabled = GL_FALSE; 615 ctx->Color.ColorLogicOpEnabled = GL_FALSE; 616 ctx->Color._LogicOpEnabled = GL_FALSE; 617 ctx->Color.LogicOp = GL_COPY; 618 ctx->Color.DitherFlag = GL_TRUE; 619 620 if (ctx->Visual.doubleBufferMode) { 621 ctx->Color.DrawBuffer[0] = GL_BACK; 622 } 623 else { 624 ctx->Color.DrawBuffer[0] = GL_FRONT; 625 } 626 627 ctx->Color.ClampFragmentColor = GL_FIXED_ONLY_ARB; 628 ctx->Color.ClampReadColor = GL_FIXED_ONLY_ARB; 629} 630 631/*@}*/ 632