4f20d269ac2b20f695e3fa64a2c0f822dd43b42a
[mesa.git] / src / mesa / main / blend.c
1 /* $Id: blend.c,v 1.23 2000/10/30 16:32:43 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.5
6 *
7 * Copyright (C) 1999-2000 Brian Paul All Rights Reserved.
8 *
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
15 *
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
18 *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
23 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 */
26
27
28
29 #ifdef PC_HEADER
30 #include "all.h"
31 #else
32 #include "glheader.h"
33 #include "alphabuf.h"
34 #include "blend.h"
35 #include "context.h"
36 #include "enums.h"
37 #include "macros.h"
38 #include "pb.h"
39 #include "span.h"
40 #include "types.h"
41 #endif
42
43
44 void
45 _mesa_BlendFunc( GLenum sfactor, GLenum dfactor )
46 {
47 GET_CURRENT_CONTEXT(ctx);
48 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFunc");
49
50 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
51 fprintf(stderr, "glBlendFunc %s %s\n",
52 gl_lookup_enum_by_nr(sfactor),
53 gl_lookup_enum_by_nr(dfactor));
54
55 switch (sfactor) {
56 case GL_SRC_COLOR:
57 case GL_ONE_MINUS_SRC_COLOR:
58 if (!ctx->Extensions.NV_blend_square) {
59 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
60 return;
61 }
62 /* fall-through */
63 case GL_ZERO:
64 case GL_ONE:
65 case GL_DST_COLOR:
66 case GL_ONE_MINUS_DST_COLOR:
67 case GL_SRC_ALPHA:
68 case GL_ONE_MINUS_SRC_ALPHA:
69 case GL_DST_ALPHA:
70 case GL_ONE_MINUS_DST_ALPHA:
71 case GL_SRC_ALPHA_SATURATE:
72 case GL_CONSTANT_COLOR:
73 case GL_ONE_MINUS_CONSTANT_COLOR:
74 case GL_CONSTANT_ALPHA:
75 case GL_ONE_MINUS_CONSTANT_ALPHA:
76 ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor;
77 break;
78 default:
79 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
80 return;
81 }
82
83 switch (dfactor) {
84 case GL_DST_COLOR:
85 case GL_ONE_MINUS_DST_COLOR:
86 if (!ctx->Extensions.NV_blend_square) {
87 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
88 return;
89 }
90 /* fall-through */
91 case GL_ZERO:
92 case GL_ONE:
93 case GL_SRC_COLOR:
94 case GL_ONE_MINUS_SRC_COLOR:
95 case GL_SRC_ALPHA:
96 case GL_ONE_MINUS_SRC_ALPHA:
97 case GL_DST_ALPHA:
98 case GL_ONE_MINUS_DST_ALPHA:
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 ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor;
104 break;
105 default:
106 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
107 return;
108 }
109
110 if (ctx->Driver.BlendFunc) {
111 (*ctx->Driver.BlendFunc)( ctx, sfactor, dfactor );
112 }
113
114 ctx->Color.BlendFunc = NULL;
115 ctx->NewState |= _NEW_COLOR;
116 }
117
118
119 /* GL_EXT_blend_func_separate */
120 void
121 _mesa_BlendFuncSeparateEXT( GLenum sfactorRGB, GLenum dfactorRGB,
122 GLenum sfactorA, GLenum dfactorA )
123 {
124 GET_CURRENT_CONTEXT(ctx);
125 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFuncSeparate");
126
127 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
128 fprintf(stderr, "glBlendFuncSeperate %s %s %s %s\n",
129 gl_lookup_enum_by_nr(sfactorRGB),
130 gl_lookup_enum_by_nr(dfactorRGB),
131 gl_lookup_enum_by_nr(sfactorA),
132 gl_lookup_enum_by_nr(dfactorA));
133
134 switch (sfactorRGB) {
135 case GL_SRC_COLOR:
136 case GL_ONE_MINUS_SRC_COLOR:
137 if (!ctx->Extensions.NV_blend_square) {
138 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
139 return;
140 }
141 /* fall-through */
142 case GL_ZERO:
143 case GL_ONE:
144 case GL_DST_COLOR:
145 case GL_ONE_MINUS_DST_COLOR:
146 case GL_SRC_ALPHA:
147 case GL_ONE_MINUS_SRC_ALPHA:
148 case GL_DST_ALPHA:
149 case GL_ONE_MINUS_DST_ALPHA:
150 case GL_SRC_ALPHA_SATURATE:
151 case GL_CONSTANT_COLOR:
152 case GL_ONE_MINUS_CONSTANT_COLOR:
153 case GL_CONSTANT_ALPHA:
154 case GL_ONE_MINUS_CONSTANT_ALPHA:
155 ctx->Color.BlendSrcRGB = sfactorRGB;
156 break;
157 default:
158 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)");
159 return;
160 }
161
162 switch (dfactorRGB) {
163 case GL_DST_COLOR:
164 case GL_ONE_MINUS_DST_COLOR:
165 if (!ctx->Extensions.NV_blend_square) {
166 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
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 ctx->Color.BlendDstRGB = dfactorRGB;
183 break;
184 default:
185 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)");
186 return;
187 }
188
189 switch (sfactorA) {
190 case GL_SRC_COLOR:
191 case GL_ONE_MINUS_SRC_COLOR:
192 if (!ctx->Extensions.NV_blend_square) {
193 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
194 return;
195 }
196 /* fall-through */
197 case GL_ZERO:
198 case GL_ONE:
199 case GL_DST_COLOR:
200 case GL_ONE_MINUS_DST_COLOR:
201 case GL_SRC_ALPHA:
202 case GL_ONE_MINUS_SRC_ALPHA:
203 case GL_DST_ALPHA:
204 case GL_ONE_MINUS_DST_ALPHA:
205 case GL_SRC_ALPHA_SATURATE:
206 case GL_CONSTANT_COLOR:
207 case GL_ONE_MINUS_CONSTANT_COLOR:
208 case GL_CONSTANT_ALPHA:
209 case GL_ONE_MINUS_CONSTANT_ALPHA:
210 ctx->Color.BlendSrcA = sfactorA;
211 break;
212 default:
213 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)");
214 return;
215 }
216
217 switch (dfactorA) {
218 case GL_DST_COLOR:
219 case GL_ONE_MINUS_DST_COLOR:
220 if (!ctx->Extensions.NV_blend_square) {
221 gl_error(ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)");
222 return;
223 }
224 /* fall-through */
225 case GL_ZERO:
226 case GL_ONE:
227 case GL_SRC_COLOR:
228 case GL_ONE_MINUS_SRC_COLOR:
229 case GL_SRC_ALPHA:
230 case GL_ONE_MINUS_SRC_ALPHA:
231 case GL_DST_ALPHA:
232 case GL_ONE_MINUS_DST_ALPHA:
233 case GL_CONSTANT_COLOR:
234 case GL_ONE_MINUS_CONSTANT_COLOR:
235 case GL_CONSTANT_ALPHA:
236 case GL_ONE_MINUS_CONSTANT_ALPHA:
237 ctx->Color.BlendDstA = dfactorA;
238 break;
239 default:
240 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" );
241 return;
242 }
243
244 ctx->Color.BlendFunc = NULL;
245 ctx->NewState |= _NEW_COLOR;
246
247 if (ctx->Driver.BlendFuncSeparate) {
248 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
249 sfactorA, dfactorA );
250 }
251 }
252
253
254
255 /* This is really an extension function! */
256 void
257 _mesa_BlendEquation( GLenum mode )
258 {
259 GET_CURRENT_CONTEXT(ctx);
260 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendEquation");
261
262 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
263 fprintf(stderr, "glBlendEquation %s\n",
264 gl_lookup_enum_by_nr(mode));
265
266 switch (mode) {
267 case GL_MIN_EXT:
268 case GL_MAX_EXT:
269 case GL_FUNC_ADD_EXT:
270 if (ctx->Extensions.EXT_blend_minmax) {
271 ctx->Color.BlendEquation = mode;
272 }
273 else {
274 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
275 return;
276 }
277 case GL_LOGIC_OP:
278 ctx->Color.BlendEquation = mode;
279 break;
280 case GL_FUNC_SUBTRACT_EXT:
281 case GL_FUNC_REVERSE_SUBTRACT_EXT:
282 if (ctx->Extensions.EXT_blend_subtract) {
283 ctx->Color.BlendEquation = mode;
284 }
285 else {
286 gl_error(ctx, GL_INVALID_ENUM, "glBlendEquation");
287 return;
288 }
289 break;
290 default:
291 gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
292 return;
293 }
294
295 /* This is needed to support 1.1's RGB logic ops AND
296 * 1.0's blending logicops.
297 */
298 if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) {
299 ctx->Color.ColorLogicOpEnabled = GL_TRUE;
300 }
301 else {
302 ctx->Color.ColorLogicOpEnabled = GL_FALSE;
303 }
304
305 ctx->Color.BlendFunc = NULL;
306 ctx->NewState |= _NEW_COLOR;
307
308 if (ctx->Driver.BlendEquation)
309 ctx->Driver.BlendEquation( ctx, mode );
310 }
311
312
313
314 void
315 _mesa_BlendColor( GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha )
316 {
317 GET_CURRENT_CONTEXT(ctx);
318 ctx->Color.BlendColor[0] = CLAMP( red, 0.0F, 1.0F );
319 ctx->Color.BlendColor[1] = CLAMP( green, 0.0F, 1.0F );
320 ctx->Color.BlendColor[2] = CLAMP( blue, 0.0F, 1.0F );
321 ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0F, 1.0F );
322 ctx->NewState |= _NEW_COLOR;
323 }
324
325 #ifdef USE_MMX_ASM
326 #define _BLENDAPI _ASMAPI
327 #else
328 #define _BLENDAPI
329 #endif
330
331 /*
332 * Common transparency blending mode.
333 */
334 static void _BLENDAPI
335 blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
336 GLchan rgba[][4], CONST GLchan dest[][4] )
337 {
338 GLuint i;
339 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
340 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
341 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
342 (void) ctx;
343
344 for (i=0;i<n;i++) {
345 if (mask[i]) {
346 const GLint t = rgba[i][ACOMP]; /* t in [0, CHAN_MAX] */
347 if (t == 0) {
348 /* 0% alpha */
349 rgba[i][RCOMP] = dest[i][RCOMP];
350 rgba[i][GCOMP] = dest[i][GCOMP];
351 rgba[i][BCOMP] = dest[i][BCOMP];
352 rgba[i][ACOMP] = dest[i][ACOMP];
353 }
354 else if (t == CHAN_MAX) {
355 /* 100% alpha, no-op */
356 }
357 else {
358 #if 0
359 /* This is pretty close, but Glean complains */
360 const GLint s = CHAN_MAX - t;
361 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s + 1) >> 8;
362 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s + 1) >> 8;
363 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s + 1) >> 8;
364 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s + 1) >> 8;
365 #elif 0
366 /* This is slower but satisfies Glean */
367 const GLint s = CHAN_MAX - t;
368 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / 255;
369 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / 255;
370 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / 255;
371 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / 255;
372 #else
373 #if CHAN_BITS == 8
374 /* This satisfies Glean and should be reasonably fast */
375 /* Contributed by Nathan Hand */
376 #define DIV255(X) (((X) << 8) + (X) + 256) >> 16
377 const GLint s = CHAN_MAX - t;
378 const GLint r = DIV255(rgba[i][RCOMP] * t + dest[i][RCOMP] * s);
379 const GLint g = DIV255(rgba[i][GCOMP] * t + dest[i][GCOMP] * s);
380 const GLint b = DIV255(rgba[i][BCOMP] * t + dest[i][BCOMP] * s);
381 const GLint a = DIV255(rgba[i][ACOMP] * t + dest[i][ACOMP] * s);
382 #undef DIV255
383 #else
384 const GLint s = CHAN_MAX - t;
385 const GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) / CHAN_MAX;
386 const GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) / CHAN_MAX;
387 const GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) / CHAN_MAX;
388 const GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) / CHAN_MAX;
389 #endif
390 #endif
391 ASSERT(r <= CHAN_MAX);
392 ASSERT(g <= CHAN_MAX);
393 ASSERT(b <= CHAN_MAX);
394 ASSERT(a <= CHAN_MAX);
395 rgba[i][RCOMP] = (GLchan) r;
396 rgba[i][GCOMP] = (GLchan) g;
397 rgba[i][BCOMP] = (GLchan) b;
398 rgba[i][ACOMP] = (GLchan) a;
399 }
400 }
401 }
402 }
403
404
405
406 /*
407 * Add src and dest.
408 */
409 static void _BLENDAPI
410 blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
411 GLchan rgba[][4], CONST GLchan dest[][4] )
412 {
413 GLuint i;
414 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
415 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
416 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
417 (void) ctx;
418
419 for (i=0;i<n;i++) {
420 if (mask[i]) {
421 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
422 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
423 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
424 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
425 rgba[i][RCOMP] = (GLchan) MIN2( r, CHAN_MAX );
426 rgba[i][GCOMP] = (GLchan) MIN2( g, CHAN_MAX );
427 rgba[i][BCOMP] = (GLchan) MIN2( b, CHAN_MAX );
428 rgba[i][ACOMP] = (GLchan) MIN2( a, CHAN_MAX );
429 }
430 }
431 }
432
433
434
435 /*
436 * Blend min function (for GL_EXT_blend_minmax)
437 */
438 static void _BLENDAPI
439 blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
440 GLchan rgba[][4], CONST GLchan dest[][4] )
441 {
442 GLuint i;
443 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
444 (void) ctx;
445
446 for (i=0;i<n;i++) {
447 if (mask[i]) {
448 rgba[i][RCOMP] = (GLchan) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
449 rgba[i][GCOMP] = (GLchan) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
450 rgba[i][BCOMP] = (GLchan) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
451 rgba[i][ACOMP] = (GLchan) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
452 }
453 }
454 }
455
456
457
458 /*
459 * Blend max function (for GL_EXT_blend_minmax)
460 */
461 static void _BLENDAPI
462 blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
463 GLchan rgba[][4], CONST GLchan dest[][4] )
464 {
465 GLuint i;
466 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
467 (void) ctx;
468
469 for (i=0;i<n;i++) {
470 if (mask[i]) {
471 rgba[i][RCOMP] = (GLchan) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
472 rgba[i][GCOMP] = (GLchan) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
473 rgba[i][BCOMP] = (GLchan) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
474 rgba[i][ACOMP] = (GLchan) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
475 }
476 }
477 }
478
479
480
481 /*
482 * Modulate: result = src * dest
483 */
484 static void _BLENDAPI
485 blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
486 GLchan rgba[][4], CONST GLchan dest[][4] )
487 {
488 GLuint i;
489 (void) ctx;
490
491 for (i=0;i<n;i++) {
492 if (mask[i]) {
493 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
494 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
495 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
496 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
497 rgba[i][RCOMP] = (GLchan) r;
498 rgba[i][GCOMP] = (GLchan) g;
499 rgba[i][BCOMP] = (GLchan) b;
500 rgba[i][ACOMP] = (GLchan) a;
501 }
502 }
503 }
504
505
506
507 /*
508 * General case blend pixels.
509 * Input: n - number of pixels
510 * mask - the usual write mask
511 * In/Out: rgba - the incoming and modified pixels
512 * Input: dest - the pixels from the dest color buffer
513 */
514 static void _BLENDAPI
515 blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
516 GLchan rgba[][4], CONST GLchan dest[][4] )
517 {
518 GLfloat rscale = 1.0F / CHAN_MAXF;
519 GLfloat gscale = 1.0F / CHAN_MAXF;
520 GLfloat bscale = 1.0F / CHAN_MAXF;
521 GLfloat ascale = 1.0F / CHAN_MAXF;
522 GLuint i;
523
524 for (i=0;i<n;i++) {
525 if (mask[i]) {
526 GLint Rs, Gs, Bs, As; /* Source colors */
527 GLint Rd, Gd, Bd, Ad; /* Dest colors */
528 GLfloat sR, sG, sB, sA; /* Source scaling */
529 GLfloat dR, dG, dB, dA; /* Dest scaling */
530 GLfloat r, g, b, a;
531
532 /* Source Color */
533 Rs = rgba[i][RCOMP];
534 Gs = rgba[i][GCOMP];
535 Bs = rgba[i][BCOMP];
536 As = rgba[i][ACOMP];
537
538 /* Frame buffer color */
539 Rd = dest[i][RCOMP];
540 Gd = dest[i][GCOMP];
541 Bd = dest[i][BCOMP];
542 Ad = dest[i][ACOMP];
543
544 /* Source RGB factor */
545 switch (ctx->Color.BlendSrcRGB) {
546 case GL_ZERO:
547 sR = sG = sB = 0.0F;
548 break;
549 case GL_ONE:
550 sR = sG = sB = 1.0F;
551 break;
552 case GL_DST_COLOR:
553 sR = (GLfloat) Rd * rscale;
554 sG = (GLfloat) Gd * gscale;
555 sB = (GLfloat) Bd * bscale;
556 break;
557 case GL_ONE_MINUS_DST_COLOR:
558 sR = 1.0F - (GLfloat) Rd * rscale;
559 sG = 1.0F - (GLfloat) Gd * gscale;
560 sB = 1.0F - (GLfloat) Bd * bscale;
561 break;
562 case GL_SRC_ALPHA:
563 sR = sG = sB = (GLfloat) As * ascale;
564 break;
565 case GL_ONE_MINUS_SRC_ALPHA:
566 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
567 break;
568 case GL_DST_ALPHA:
569 sR = sG = sB = (GLfloat) Ad * ascale;
570 break;
571 case GL_ONE_MINUS_DST_ALPHA:
572 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
573 break;
574 case GL_SRC_ALPHA_SATURATE:
575 if (As < CHAN_MAX - Ad) {
576 sR = sG = sB = (GLfloat) As * ascale;
577 }
578 else {
579 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
580 }
581 break;
582 case GL_CONSTANT_COLOR:
583 sR = ctx->Color.BlendColor[0];
584 sG = ctx->Color.BlendColor[1];
585 sB = ctx->Color.BlendColor[2];
586 break;
587 case GL_ONE_MINUS_CONSTANT_COLOR:
588 sR = 1.0F - ctx->Color.BlendColor[0];
589 sG = 1.0F - ctx->Color.BlendColor[1];
590 sB = 1.0F - ctx->Color.BlendColor[2];
591 break;
592 case GL_CONSTANT_ALPHA:
593 sR = sG = sB = ctx->Color.BlendColor[3];
594 break;
595 case GL_ONE_MINUS_CONSTANT_ALPHA:
596 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
597 break;
598 case GL_SRC_COLOR: /* GL_NV_blend_square */
599 sR = (GLfloat) Rs * rscale;
600 sG = (GLfloat) Gs * gscale;
601 sB = (GLfloat) Bs * bscale;
602 break;
603 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
604 sR = 1.0F - (GLfloat) Rs * rscale;
605 sG = 1.0F - (GLfloat) Gs * gscale;
606 sB = 1.0F - (GLfloat) Bs * bscale;
607 break;
608 default:
609 /* this should never happen */
610 gl_problem(ctx, "Bad blend source RGB factor in do_blend");
611 return;
612 }
613
614 /* Source Alpha factor */
615 switch (ctx->Color.BlendSrcA) {
616 case GL_ZERO:
617 sA = 0.0F;
618 break;
619 case GL_ONE:
620 sA = 1.0F;
621 break;
622 case GL_DST_COLOR:
623 sA = (GLfloat) Ad * ascale;
624 break;
625 case GL_ONE_MINUS_DST_COLOR:
626 sA = 1.0F - (GLfloat) Ad * ascale;
627 break;
628 case GL_SRC_ALPHA:
629 sA = (GLfloat) As * ascale;
630 break;
631 case GL_ONE_MINUS_SRC_ALPHA:
632 sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
633 break;
634 case GL_DST_ALPHA:
635 sA =(GLfloat) Ad * ascale;
636 break;
637 case GL_ONE_MINUS_DST_ALPHA:
638 sA = 1.0F - (GLfloat) Ad * ascale;
639 break;
640 case GL_SRC_ALPHA_SATURATE:
641 sA = 1.0;
642 break;
643 case GL_CONSTANT_COLOR:
644 sA = ctx->Color.BlendColor[3];
645 break;
646 case GL_ONE_MINUS_CONSTANT_COLOR:
647 sA = 1.0F - ctx->Color.BlendColor[3];
648 break;
649 case GL_CONSTANT_ALPHA:
650 sA = ctx->Color.BlendColor[3];
651 break;
652 case GL_ONE_MINUS_CONSTANT_ALPHA:
653 sA = 1.0F - ctx->Color.BlendColor[3];
654 break;
655 case GL_SRC_COLOR: /* GL_NV_blend_square */
656 sA = (GLfloat) As * ascale;
657 break;
658 case GL_ONE_MINUS_SRC_COLOR: /* GL_NV_blend_square */
659 sA = 1.0F - (GLfloat) As * ascale;
660 break;
661 default:
662 /* this should never happen */
663 sA = 0.0F;
664 gl_problem(ctx, "Bad blend source A factor in do_blend");
665 }
666
667 /* Dest RGB factor */
668 switch (ctx->Color.BlendDstRGB) {
669 case GL_ZERO:
670 dR = dG = dB = 0.0F;
671 break;
672 case GL_ONE:
673 dR = dG = dB = 1.0F;
674 break;
675 case GL_SRC_COLOR:
676 dR = (GLfloat) Rs * rscale;
677 dG = (GLfloat) Gs * gscale;
678 dB = (GLfloat) Bs * bscale;
679 break;
680 case GL_ONE_MINUS_SRC_COLOR:
681 dR = 1.0F - (GLfloat) Rs * rscale;
682 dG = 1.0F - (GLfloat) Gs * gscale;
683 dB = 1.0F - (GLfloat) Bs * bscale;
684 break;
685 case GL_SRC_ALPHA:
686 dR = dG = dB = (GLfloat) As * ascale;
687 break;
688 case GL_ONE_MINUS_SRC_ALPHA:
689 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
690 break;
691 case GL_DST_ALPHA:
692 dR = dG = dB = (GLfloat) Ad * ascale;
693 break;
694 case GL_ONE_MINUS_DST_ALPHA:
695 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
696 break;
697 case GL_CONSTANT_COLOR:
698 dR = ctx->Color.BlendColor[0];
699 dG = ctx->Color.BlendColor[1];
700 dB = ctx->Color.BlendColor[2];
701 break;
702 case GL_ONE_MINUS_CONSTANT_COLOR:
703 dR = 1.0F - ctx->Color.BlendColor[0];
704 dG = 1.0F - ctx->Color.BlendColor[1];
705 dB = 1.0F - ctx->Color.BlendColor[2];
706 break;
707 case GL_CONSTANT_ALPHA:
708 dR = dG = dB = ctx->Color.BlendColor[3];
709 break;
710 case GL_ONE_MINUS_CONSTANT_ALPHA:
711 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
712 break;
713 case GL_DST_COLOR: /* GL_NV_blend_square */
714 dR = (GLfloat) Rd * rscale;
715 dG = (GLfloat) Gd * gscale;
716 dB = (GLfloat) Bd * bscale;
717 break;
718 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
719 dR = 1.0F - (GLfloat) Rd * rscale;
720 dG = 1.0F - (GLfloat) Gd * gscale;
721 dB = 1.0F - (GLfloat) Bd * bscale;
722 break;
723 default:
724 /* this should never happen */
725 dR = dG = dB = 0.0F;
726 gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
727 }
728
729 /* Dest Alpha factor */
730 switch (ctx->Color.BlendDstA) {
731 case GL_ZERO:
732 dA = 0.0F;
733 break;
734 case GL_ONE:
735 dA = 1.0F;
736 break;
737 case GL_SRC_COLOR:
738 dA = (GLfloat) As * ascale;
739 break;
740 case GL_ONE_MINUS_SRC_COLOR:
741 dA = 1.0F - (GLfloat) As * ascale;
742 break;
743 case GL_SRC_ALPHA:
744 dA = (GLfloat) As * ascale;
745 break;
746 case GL_ONE_MINUS_SRC_ALPHA:
747 dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
748 break;
749 case GL_DST_ALPHA:
750 dA = (GLfloat) Ad * ascale;
751 break;
752 case GL_ONE_MINUS_DST_ALPHA:
753 dA = 1.0F - (GLfloat) Ad * ascale;
754 break;
755 case GL_CONSTANT_COLOR:
756 dA = ctx->Color.BlendColor[3];
757 break;
758 case GL_ONE_MINUS_CONSTANT_COLOR:
759 dA = 1.0F - ctx->Color.BlendColor[3];
760 break;
761 case GL_CONSTANT_ALPHA:
762 dA = ctx->Color.BlendColor[3];
763 break;
764 case GL_ONE_MINUS_CONSTANT_ALPHA:
765 dA = 1.0F - ctx->Color.BlendColor[3];
766 break;
767 case GL_DST_COLOR: /* GL_NV_blend_square */
768 dA = (GLfloat) Ad * ascale;
769 break;
770 case GL_ONE_MINUS_DST_COLOR: /* GL_NV_blend_square */
771 dA = 1.0F - (GLfloat) Ad * ascale;
772 break;
773 default:
774 /* this should never happen */
775 dA = 0.0F;
776 gl_problem(ctx, "Bad blend dest A factor in do_blend");
777 return;
778 }
779
780 /* Due to round-off problems we have to clamp against zero. */
781 /* Optimization: we don't have to do this for all src & dst factors */
782 if (dA < 0.0F) dA = 0.0F;
783 if (dR < 0.0F) dR = 0.0F;
784 if (dG < 0.0F) dG = 0.0F;
785 if (dB < 0.0F) dB = 0.0F;
786 if (sA < 0.0F) sA = 0.0F;
787 if (sR < 0.0F) sR = 0.0F;
788 if (sG < 0.0F) sG = 0.0F;
789 if (sB < 0.0F) sB = 0.0F;
790
791 ASSERT( sR <= 1.0 );
792 ASSERT( sG <= 1.0 );
793 ASSERT( sB <= 1.0 );
794 ASSERT( sA <= 1.0 );
795 ASSERT( dR <= 1.0 );
796 ASSERT( dG <= 1.0 );
797 ASSERT( dB <= 1.0 );
798 ASSERT( dA <= 1.0 );
799
800 /* compute blended color */
801 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
802 r = Rs * sR + Rd * dR + 0.5F;
803 g = Gs * sG + Gd * dG + 0.5F;
804 b = Bs * sB + Bd * dB + 0.5F;
805 a = As * sA + Ad * dA + 0.5F;
806 }
807 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
808 r = Rs * sR - Rd * dR + 0.5F;
809 g = Gs * sG - Gd * dG + 0.5F;
810 b = Bs * sB - Bd * dB + 0.5F;
811 a = As * sA - Ad * dA + 0.5F;
812 }
813 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
814 r = Rd * dR - Rs * sR + 0.5F;
815 g = Gd * dG - Gs * sG + 0.5F;
816 b = Bd * dB - Bs * sB + 0.5F;
817 a = Ad * dA - As * sA + 0.5F;
818 }
819 else {
820 /* should never get here */
821 r = g = b = a = 0.0F; /* silence uninitialized var warning */
822 gl_problem(ctx, "unexpected BlendEquation in blend_general()");
823 }
824
825 /* final clamping */
826 rgba[i][RCOMP] = (GLchan) (GLint) CLAMP( r, 0.0F, CHAN_MAXF );
827 rgba[i][GCOMP] = (GLchan) (GLint) CLAMP( g, 0.0F, CHAN_MAXF );
828 rgba[i][BCOMP] = (GLchan) (GLint) CLAMP( b, 0.0F, CHAN_MAXF );
829 rgba[i][ACOMP] = (GLchan) (GLint) CLAMP( a, 0.0F, CHAN_MAXF );
830 }
831 }
832 }
833
834
835
836 #if defined(USE_MMX_ASM)
837 #include "X86/mmx.h"
838 #include "X86/common_x86_asm.h"
839 #endif
840
841
842 /*
843 * Analyze current blending parameters to pick fastest blending function.
844 * Result: the ctx->Color.BlendFunc pointer is updated.
845 */
846 static void set_blend_function( GLcontext *ctx )
847 {
848 const GLenum eq = ctx->Color.BlendEquation;
849 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
850 const GLenum dstRGB = ctx->Color.BlendDstRGB;
851 const GLenum srcA = ctx->Color.BlendSrcA;
852 const GLenum dstA = ctx->Color.BlendDstA;
853
854 #if defined(USE_MMX_ASM)
855 /* Hmm. A table here would have 12^4 == way too many entries.
856 * Provide a hook for MMX instead.
857 */
858 if ( cpu_has_mmx ) {
859 gl_mmx_set_blend_function( ctx );
860 }
861 else
862 #endif
863 if (srcRGB != srcA || dstRGB != dstA) {
864 ctx->Color.BlendFunc = blend_general;
865 }
866 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
867 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
868 ctx->Color.BlendFunc = blend_transparency;
869 }
870 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
871 ctx->Color.BlendFunc = blend_add;
872 }
873 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
874 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
875 ||
876 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
877 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
878 ctx->Color.BlendFunc = blend_modulate;
879 }
880 else if (eq==GL_MIN_EXT) {
881 ctx->Color.BlendFunc = blend_min;
882 }
883 else if (eq==GL_MAX_EXT) {
884 ctx->Color.BlendFunc = blend_max;
885 }
886 else {
887 ctx->Color.BlendFunc = blend_general;
888 }
889 }
890
891
892
893 /*
894 * Apply the blending operator to a span of pixels.
895 * Input: n - number of pixels in span
896 * x, y - location of leftmost pixel in span in window coords.
897 * mask - boolean mask indicating which pixels to blend.
898 * In/Out: rgba - pixel values
899 */
900 void
901 _mesa_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
902 GLchan rgba[][4], const GLubyte mask[] )
903 {
904 GLchan dest[MAX_WIDTH][4];
905
906 /* Check if device driver can do the work */
907 if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
908 !ctx->Color.ColorLogicOpEnabled) {
909 return;
910 }
911
912 /* Read span of current frame buffer pixels */
913 gl_read_rgba_span( ctx, ctx->DrawBuffer, n, x, y, dest );
914
915 if (!ctx->Color.BlendFunc)
916 set_blend_function(ctx);
917
918 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
919 }
920
921
922
923 /*
924 * Apply the blending operator to an array of pixels.
925 * Input: n - number of pixels in span
926 * x, y - array of pixel locations
927 * mask - boolean mask indicating which pixels to blend.
928 * In/Out: rgba - pixel values
929 */
930 void
931 _mesa_blend_pixels( GLcontext *ctx,
932 GLuint n, const GLint x[], const GLint y[],
933 GLchan rgba[][4], const GLubyte mask[] )
934 {
935 GLchan dest[PB_SIZE][4];
936
937 /* Check if device driver can do the work */
938 if (ctx->Color.BlendEquation==GL_LOGIC_OP &&
939 !ctx->Color.ColorLogicOpEnabled) {
940 return;
941 }
942
943 /* Read pixels from current color buffer */
944 (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
945 if (ctx->RasterMask & ALPHABUF_BIT) {
946 _mesa_read_alpha_pixels( ctx, n, x, y, dest, mask );
947 }
948
949 if (!ctx->Color.BlendFunc)
950 set_blend_function(ctx);
951
952 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLchan (*)[4])dest );
953 }