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