Home | History | Annotate | Download | only in main
      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