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