remove duplicate declaration
[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 GLAPIENTRY
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 GLAPIENTRY
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 GLAPIENTRY
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._LogicOpEnabled = (ctx->Color.ColorLogicOpEnabled ||
338 (ctx->Color.BlendEnabled &&
339 mode == GL_LOGIC_OP));
340
341 if (ctx->Driver.BlendEquation)
342 (*ctx->Driver.BlendEquation)( ctx, mode );
343 }
344
345 #endif
346
347
348 /**
349 * Set the blending color.
350 *
351 * \param red red color component.
352 * \param green green color component.
353 * \param blue blue color component.
354 * \param alpha alpha color component.
355 *
356 * \sa glBlendColor().
357 *
358 * Clamps the parameters and updates gl_colorbuffer_attrib::BlendColor. On a
359 * change, flushes the vertices and notifies the driver via
360 * dd_function_table::BlendColor callback.
361 */
362 void GLAPIENTRY
363 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
364 {
365 GLfloat tmp[4];
366 GET_CURRENT_CONTEXT(ctx);
367 ASSERT_OUTSIDE_BEGIN_END(ctx);
368
369 tmp[0] = CLAMP( red, 0.0F, 1.0F );
370 tmp[1] = CLAMP( green, 0.0F, 1.0F );
371 tmp[2] = CLAMP( blue, 0.0F, 1.0F );
372 tmp[3] = CLAMP( alpha, 0.0F, 1.0F );
373
374 if (TEST_EQ_4V(tmp, ctx->Color.BlendColor))
375 return;
376
377 FLUSH_VERTICES(ctx, _NEW_COLOR);
378 COPY_4FV( ctx->Color.BlendColor, tmp );
379
380 if (ctx->Driver.BlendColor)
381 (*ctx->Driver.BlendColor)(ctx, tmp);
382 }
383
384
385 /**
386 * Specify the alpha test function.
387 *
388 * \param func alpha comparison function.
389 * \param ref reference value.
390 *
391 * Verifies the parameters and updates gl_colorbuffer_attrib.
392 * On a change, flushes the vertices and notifies the driver via
393 * dd_function_table::AlphaFunc callback.
394 */
395 void GLAPIENTRY
396 _mesa_AlphaFunc( GLenum func, GLclampf ref )
397 {
398 GET_CURRENT_CONTEXT(ctx);
399 ASSERT_OUTSIDE_BEGIN_END(ctx);
400
401 switch (func) {
402 case GL_NEVER:
403 case GL_LESS:
404 case GL_EQUAL:
405 case GL_LEQUAL:
406 case GL_GREATER:
407 case GL_NOTEQUAL:
408 case GL_GEQUAL:
409 case GL_ALWAYS:
410 ref = CLAMP(ref, 0.0F, 1.0F);
411
412 if (ctx->Color.AlphaFunc == func && ctx->Color.AlphaRef == ref)
413 return; /* no change */
414
415 FLUSH_VERTICES(ctx, _NEW_COLOR);
416 ctx->Color.AlphaFunc = func;
417 ctx->Color.AlphaRef = ref;
418
419 if (ctx->Driver.AlphaFunc)
420 ctx->Driver.AlphaFunc(ctx, func, ref);
421 return;
422
423 default:
424 _mesa_error( ctx, GL_INVALID_ENUM, "glAlphaFunc(func)" );
425 return;
426 }
427 }
428
429
430 /**
431 * Specify a logic pixel operation for color index rendering.
432 *
433 * \param opcode operation.
434 *
435 * Verifies that \p opcode is a valid enum and updates
436 gl_colorbuffer_attrib::LogicOp.
437 * On a change, flushes the vertices and notifies the driver via the
438 * dd_function_table::LogicOpcode callback.
439 */
440 void GLAPIENTRY
441 _mesa_LogicOp( GLenum opcode )
442 {
443 GET_CURRENT_CONTEXT(ctx);
444 ASSERT_OUTSIDE_BEGIN_END(ctx);
445
446 switch (opcode) {
447 case GL_CLEAR:
448 case GL_SET:
449 case GL_COPY:
450 case GL_COPY_INVERTED:
451 case GL_NOOP:
452 case GL_INVERT:
453 case GL_AND:
454 case GL_NAND:
455 case GL_OR:
456 case GL_NOR:
457 case GL_XOR:
458 case GL_EQUIV:
459 case GL_AND_REVERSE:
460 case GL_AND_INVERTED:
461 case GL_OR_REVERSE:
462 case GL_OR_INVERTED:
463 break;
464 default:
465 _mesa_error( ctx, GL_INVALID_ENUM, "glLogicOp" );
466 return;
467 }
468
469 if (ctx->Color.LogicOp == opcode)
470 return;
471
472 FLUSH_VERTICES(ctx, _NEW_COLOR);
473 ctx->Color.LogicOp = opcode;
474
475 if (ctx->Driver.LogicOpcode)
476 ctx->Driver.LogicOpcode( ctx, opcode );
477 }
478
479 #if _HAVE_FULL_GL
480 void GLAPIENTRY
481 _mesa_IndexMask( GLuint mask )
482 {
483 GET_CURRENT_CONTEXT(ctx);
484 ASSERT_OUTSIDE_BEGIN_END(ctx);
485
486 if (ctx->Color.IndexMask == mask)
487 return;
488
489 FLUSH_VERTICES(ctx, _NEW_COLOR);
490 ctx->Color.IndexMask = mask;
491
492 if (ctx->Driver.IndexMask)
493 ctx->Driver.IndexMask( ctx, mask );
494 }
495 #endif
496
497
498 /**
499 * Enable or disable writing of frame buffer color components.
500 *
501 * \param red whether to mask writing of the red color component.
502 * \param green whether to mask writing of the green color component.
503 * \param blue whether to mask writing of the blue color component.
504 * \param alpha whether to mask writing of the alpha color component.
505 *
506 * \sa glColorMask().
507 *
508 * Sets the appropriate value of gl_colorbuffer_attrib::ColorMask. On a
509 * change, flushes the vertices and notifies the driver via the
510 * dd_function_table::ColorMask callback.
511 */
512 void GLAPIENTRY
513 _mesa_ColorMask( GLboolean red, GLboolean green,
514 GLboolean blue, GLboolean alpha )
515 {
516 GET_CURRENT_CONTEXT(ctx);
517 GLubyte tmp[4];
518 ASSERT_OUTSIDE_BEGIN_END(ctx);
519
520 if (MESA_VERBOSE & VERBOSE_API)
521 _mesa_debug(ctx, "glColorMask %d %d %d %d\n", red, green, blue, alpha);
522
523 /* Shouldn't have any information about channel depth in core mesa
524 * -- should probably store these as the native booleans:
525 */
526 tmp[RCOMP] = red ? 0xff : 0x0;
527 tmp[GCOMP] = green ? 0xff : 0x0;
528 tmp[BCOMP] = blue ? 0xff : 0x0;
529 tmp[ACOMP] = alpha ? 0xff : 0x0;
530
531 if (TEST_EQ_4UBV(tmp, ctx->Color.ColorMask))
532 return;
533
534 FLUSH_VERTICES(ctx, _NEW_COLOR);
535 COPY_4UBV(ctx->Color.ColorMask, tmp);
536
537 if (ctx->Driver.ColorMask)
538 ctx->Driver.ColorMask( ctx, red, green, blue, alpha );
539 }
540
541 /**********************************************************************/
542 /** \name Initialization */
543 /*@{*/
544
545 /**
546 * Initialization of the context color data.
547 *
548 * \param ctx GL context.
549 *
550 * Initializes the related fields in the context color attribute group,
551 * __GLcontextRec::Color.
552 */
553 void _mesa_init_color( GLcontext * ctx )
554 {
555 /* Color buffer group */
556 ctx->Color.IndexMask = 0xffffffff;
557 ctx->Color.ColorMask[0] = 0xff;
558 ctx->Color.ColorMask[1] = 0xff;
559 ctx->Color.ColorMask[2] = 0xff;
560 ctx->Color.ColorMask[3] = 0xff;
561 ctx->Color.ClearIndex = 0;
562 ASSIGN_4V( ctx->Color.ClearColor, 0, 0, 0, 0 );
563 ctx->Color.DrawBuffer = GL_FRONT;
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.BlendEquation = GL_FUNC_ADD_EXT;
573 ASSIGN_4V( ctx->Color.BlendColor, 0.0, 0.0, 0.0, 0.0 );
574 ctx->Color.IndexLogicOpEnabled = GL_FALSE;
575 ctx->Color.ColorLogicOpEnabled = GL_FALSE;
576 ctx->Color._LogicOpEnabled = GL_FALSE;
577 ctx->Color.LogicOp = GL_COPY;
578 ctx->Color.DitherFlag = GL_TRUE;
579
580 if (ctx->Visual.doubleBufferMode) {
581 ctx->Color.DrawBuffer = GL_BACK;
582 ctx->Color._DrawDestMask = BACK_LEFT_BIT;
583 }
584 else {
585 ctx->Color.DrawBuffer = GL_FRONT;
586 ctx->Color._DrawDestMask = FRONT_LEFT_BIT;
587 }
588 }
589
590 /*@}*/