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