357d1265c2fa971d2e429c0e6bb75fb3b40b954e
[mesa.git] / src / mesa / main / blend.c
1 /* $Id: blend.c,v 1.7 1999/11/08 15:28:08 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 3.1
6 *
7 * Copyright (C) 1999 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 #ifndef XFree86Server
33 #include <stdio.h>
34 #include <assert.h>
35 #include <stdlib.h>
36 #else
37 #include "GL/xf86glx.h"
38 #endif
39 #include "alphabuf.h"
40 #include "blend.h"
41 #include "context.h"
42 #include "enums.h"
43 #include "macros.h"
44 #include "pb.h"
45 #include "span.h"
46 #include "types.h"
47 #endif
48
49
50 void gl_BlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor )
51 {
52 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFunc");
53
54 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
55 fprintf(stderr, "glBlendFunc %s %s\n",
56 gl_lookup_enum_by_nr(sfactor),
57 gl_lookup_enum_by_nr(dfactor));
58
59 switch (sfactor) {
60 case GL_ZERO:
61 case GL_ONE:
62 case GL_DST_COLOR:
63 case GL_ONE_MINUS_DST_COLOR:
64 case GL_SRC_ALPHA:
65 case GL_ONE_MINUS_SRC_ALPHA:
66 case GL_DST_ALPHA:
67 case GL_ONE_MINUS_DST_ALPHA:
68 case GL_SRC_ALPHA_SATURATE:
69 case GL_CONSTANT_COLOR:
70 case GL_ONE_MINUS_CONSTANT_COLOR:
71 case GL_CONSTANT_ALPHA:
72 case GL_ONE_MINUS_CONSTANT_ALPHA:
73 ctx->Color.BlendSrcRGB = ctx->Color.BlendSrcA = sfactor;
74 break;
75 default:
76 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
77 return;
78 }
79
80 switch (dfactor) {
81 case GL_ZERO:
82 case GL_ONE:
83 case GL_SRC_COLOR:
84 case GL_ONE_MINUS_SRC_COLOR:
85 case GL_SRC_ALPHA:
86 case GL_ONE_MINUS_SRC_ALPHA:
87 case GL_DST_ALPHA:
88 case GL_ONE_MINUS_DST_ALPHA:
89 case GL_CONSTANT_COLOR:
90 case GL_ONE_MINUS_CONSTANT_COLOR:
91 case GL_CONSTANT_ALPHA:
92 case GL_ONE_MINUS_CONSTANT_ALPHA:
93 ctx->Color.BlendDstRGB = ctx->Color.BlendDstA = dfactor;
94 break;
95 default:
96 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
97 return;
98 }
99
100 if (ctx->Driver.BlendFunc) {
101 (*ctx->Driver.BlendFunc)( ctx, sfactor, dfactor );
102 }
103
104 ctx->Color.BlendFunc = NULL;
105 ctx->NewState |= NEW_RASTER_OPS;
106 }
107
108
109 /* GL_INGR_blend_func_separate */
110 void
111 gl_BlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB, GLenum dfactorRGB,
112 GLenum sfactorA, GLenum dfactorA )
113 {
114 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendFuncSeparate");
115
116 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
117 fprintf(stderr, "glBlendFuncSeperate %s %s %s %s\n",
118 gl_lookup_enum_by_nr(sfactorRGB),
119 gl_lookup_enum_by_nr(dfactorRGB),
120 gl_lookup_enum_by_nr(sfactorA),
121 gl_lookup_enum_by_nr(dfactorA));
122
123 switch (sfactorRGB) {
124 case GL_ZERO:
125 case GL_ONE:
126 case GL_DST_COLOR:
127 case GL_ONE_MINUS_DST_COLOR:
128 case GL_SRC_ALPHA:
129 case GL_ONE_MINUS_SRC_ALPHA:
130 case GL_DST_ALPHA:
131 case GL_ONE_MINUS_DST_ALPHA:
132 case GL_SRC_ALPHA_SATURATE:
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 ctx->Color.BlendSrcRGB = sfactorRGB;
138 break;
139 default:
140 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorRGB)" );
141 return;
142 }
143
144 switch (dfactorRGB) {
145 case GL_ZERO:
146 case GL_ONE:
147 case GL_SRC_COLOR:
148 case GL_ONE_MINUS_SRC_COLOR:
149 case GL_SRC_ALPHA:
150 case GL_ONE_MINUS_SRC_ALPHA:
151 case GL_DST_ALPHA:
152 case GL_ONE_MINUS_DST_ALPHA:
153 case GL_CONSTANT_COLOR:
154 case GL_ONE_MINUS_CONSTANT_COLOR:
155 case GL_CONSTANT_ALPHA:
156 case GL_ONE_MINUS_CONSTANT_ALPHA:
157 ctx->Color.BlendDstRGB = dfactorRGB;
158 break;
159 default:
160 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorRGB)" );
161 return;
162 }
163
164 switch (sfactorA) {
165 case GL_ZERO:
166 case GL_ONE:
167 case GL_DST_COLOR:
168 case GL_ONE_MINUS_DST_COLOR:
169 case GL_SRC_ALPHA:
170 case GL_ONE_MINUS_SRC_ALPHA:
171 case GL_DST_ALPHA:
172 case GL_ONE_MINUS_DST_ALPHA:
173 case GL_SRC_ALPHA_SATURATE:
174 case GL_CONSTANT_COLOR:
175 case GL_ONE_MINUS_CONSTANT_COLOR:
176 case GL_CONSTANT_ALPHA:
177 case GL_ONE_MINUS_CONSTANT_ALPHA:
178 ctx->Color.BlendSrcA = sfactorA;
179 break;
180 default:
181 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(sfactorA)" );
182 return;
183 }
184
185 switch (dfactorA) {
186 case GL_ZERO:
187 case GL_ONE:
188 case GL_SRC_COLOR:
189 case GL_ONE_MINUS_SRC_COLOR:
190 case GL_SRC_ALPHA:
191 case GL_ONE_MINUS_SRC_ALPHA:
192 case GL_DST_ALPHA:
193 case GL_ONE_MINUS_DST_ALPHA:
194 case GL_CONSTANT_COLOR:
195 case GL_ONE_MINUS_CONSTANT_COLOR:
196 case GL_CONSTANT_ALPHA:
197 case GL_ONE_MINUS_CONSTANT_ALPHA:
198 ctx->Color.BlendDstA = dfactorA;
199 break;
200 default:
201 gl_error( ctx, GL_INVALID_ENUM, "glBlendFuncSeparate(dfactorA)" );
202 return;
203 }
204
205 ctx->Color.BlendFunc = NULL;
206 ctx->NewState |= NEW_RASTER_OPS;
207
208 if (ctx->Driver.BlendFuncSeparate) {
209 (*ctx->Driver.BlendFuncSeparate)( ctx, sfactorRGB, dfactorRGB,
210 sfactorA, dfactorA );
211 }
212 }
213
214
215
216 /* This is really an extension function! */
217 void gl_BlendEquation( GLcontext *ctx, GLenum mode )
218 {
219 ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx, "glBlendEquation");
220
221 if (MESA_VERBOSE & (VERBOSE_API|VERBOSE_TEXTURE))
222 fprintf(stderr, "glBlendEquation %s\n",
223 gl_lookup_enum_by_nr(mode));
224
225
226 switch (mode) {
227 case GL_MIN_EXT:
228 case GL_MAX_EXT:
229 case GL_LOGIC_OP:
230 case GL_FUNC_ADD_EXT:
231 case GL_FUNC_SUBTRACT_EXT:
232 case GL_FUNC_REVERSE_SUBTRACT_EXT:
233 ctx->Color.BlendEquation = mode;
234 break;
235 default:
236 gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" );
237 return;
238 }
239
240 /* This is needed to support 1.1's RGB logic ops AND
241 * 1.0's blending logicops.
242 */
243 if (mode==GL_LOGIC_OP && ctx->Color.BlendEnabled) {
244 ctx->Color.ColorLogicOpEnabled = GL_TRUE;
245 }
246 else {
247 ctx->Color.ColorLogicOpEnabled = GL_FALSE;
248 }
249
250 ctx->Color.BlendFunc = NULL;
251 ctx->NewState |= NEW_RASTER_OPS;
252
253 if (ctx->Driver.BlendEquation)
254 ctx->Driver.BlendEquation( ctx, mode );
255 }
256
257
258
259 void gl_BlendColor( GLcontext *ctx, GLclampf red, GLclampf green,
260 GLclampf blue, GLclampf alpha )
261 {
262 ctx->Color.BlendColor[0] = CLAMP( red, 0.0F, 1.0F );
263 ctx->Color.BlendColor[1] = CLAMP( green, 0.0F, 1.0F );
264 ctx->Color.BlendColor[2] = CLAMP( blue, 0.0F, 1.0F );
265 ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0F, 1.0F );
266 }
267
268
269
270 /*
271 * Common transparency blending mode.
272 */
273 static void blend_transparency( GLcontext *ctx, GLuint n, const GLubyte mask[],
274 GLubyte rgba[][4], CONST GLubyte dest[][4] )
275 {
276 GLuint i;
277 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
278 ASSERT(ctx->Color.BlendSrcRGB==GL_SRC_ALPHA);
279 ASSERT(ctx->Color.BlendDstRGB==GL_ONE_MINUS_SRC_ALPHA);
280 (void) ctx;
281
282 for (i=0;i<n;i++) {
283 if (mask[i]) {
284 GLint t = rgba[i][ACOMP]; /* t in [0,255] */
285 if (t == 0) {
286 rgba[i][RCOMP] = dest[i][RCOMP];
287 rgba[i][GCOMP] = dest[i][GCOMP];
288 rgba[i][BCOMP] = dest[i][BCOMP];
289 rgba[i][ACOMP] = dest[i][ACOMP];
290 }
291 else if (t == 255) {
292 /* no-op */
293 }
294 else {
295 GLint s = 255 - t;
296 GLint r = (rgba[i][RCOMP] * t + dest[i][RCOMP] * s) >> 8;
297 GLint g = (rgba[i][GCOMP] * t + dest[i][GCOMP] * s) >> 8;
298 GLint b = (rgba[i][BCOMP] * t + dest[i][BCOMP] * s) >> 8;
299 GLint a = (rgba[i][ACOMP] * t + dest[i][ACOMP] * s) >> 8;
300 ASSERT(r <= 255);
301 ASSERT(g <= 255);
302 ASSERT(b <= 255);
303 ASSERT(a <= 255);
304 rgba[i][RCOMP] = (GLubyte) r;
305 rgba[i][GCOMP] = (GLubyte) g;
306 rgba[i][BCOMP] = (GLubyte) b;
307 rgba[i][ACOMP] = (GLubyte) a;
308 }
309 }
310 }
311 }
312
313
314
315 /*
316 * Add src and dest.
317 */
318 static void blend_add( GLcontext *ctx, GLuint n, const GLubyte mask[],
319 GLubyte rgba[][4], CONST GLubyte dest[][4] )
320 {
321 GLuint i;
322 ASSERT(ctx->Color.BlendEquation==GL_FUNC_ADD_EXT);
323 ASSERT(ctx->Color.BlendSrcRGB==GL_ONE);
324 ASSERT(ctx->Color.BlendDstRGB==GL_ONE);
325 (void) ctx;
326
327 for (i=0;i<n;i++) {
328 if (mask[i]) {
329 GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
330 GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
331 GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
332 GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
333 rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
334 rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
335 rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
336 rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
337 }
338 }
339 }
340
341
342
343 /*
344 * Blend min function (for GL_EXT_blend_minmax)
345 */
346 static void blend_min( GLcontext *ctx, GLuint n, const GLubyte mask[],
347 GLubyte rgba[][4], CONST GLubyte dest[][4] )
348 {
349 GLuint i;
350 ASSERT(ctx->Color.BlendEquation==GL_MIN_EXT);
351 (void) ctx;
352
353 for (i=0;i<n;i++) {
354 if (mask[i]) {
355 rgba[i][RCOMP] = (GLubyte) MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
356 rgba[i][GCOMP] = (GLubyte) MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
357 rgba[i][BCOMP] = (GLubyte) MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
358 rgba[i][ACOMP] = (GLubyte) MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
359 }
360 }
361 }
362
363
364
365 /*
366 * Blend max function (for GL_EXT_blend_minmax)
367 */
368 static void blend_max( GLcontext *ctx, GLuint n, const GLubyte mask[],
369 GLubyte rgba[][4], CONST GLubyte dest[][4] )
370 {
371 GLuint i;
372 ASSERT(ctx->Color.BlendEquation==GL_MAX_EXT);
373 (void) ctx;
374
375 for (i=0;i<n;i++) {
376 if (mask[i]) {
377 rgba[i][RCOMP] = (GLubyte) MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
378 rgba[i][GCOMP] = (GLubyte) MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
379 rgba[i][BCOMP] = (GLubyte) MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
380 rgba[i][ACOMP] = (GLubyte) MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
381 }
382 }
383 }
384
385
386
387 /*
388 * Modulate: result = src * dest
389 */
390 static void blend_modulate( GLcontext *ctx, GLuint n, const GLubyte mask[],
391 GLubyte rgba[][4], CONST GLubyte dest[][4] )
392 {
393 GLuint i;
394 (void) ctx;
395
396 for (i=0;i<n;i++) {
397 if (mask[i]) {
398 GLint r = (rgba[i][RCOMP] * dest[i][RCOMP]) >> 8;
399 GLint g = (rgba[i][GCOMP] * dest[i][GCOMP]) >> 8;
400 GLint b = (rgba[i][BCOMP] * dest[i][BCOMP]) >> 8;
401 GLint a = (rgba[i][ACOMP] * dest[i][ACOMP]) >> 8;
402 rgba[i][RCOMP] = (GLubyte) r;
403 rgba[i][GCOMP] = (GLubyte) g;
404 rgba[i][BCOMP] = (GLubyte) b;
405 rgba[i][ACOMP] = (GLubyte) a;
406 }
407 }
408 }
409
410
411
412 /*
413 * General case blend pixels.
414 * Input: n - number of pixels
415 * mask - the usual write mask
416 * In/Out: rgba - the incoming and modified pixels
417 * Input: dest - the pixels from the dest color buffer
418 */
419 static void blend_general( GLcontext *ctx, GLuint n, const GLubyte mask[],
420 GLubyte rgba[][4], CONST GLubyte dest[][4] )
421 {
422 GLfloat rscale = 1.0F / 255.0F;
423 GLfloat gscale = 1.0F / 255.0F;
424 GLfloat bscale = 1.0F / 255.0F;
425 GLfloat ascale = 1.0F / 255.0F;
426 GLuint i;
427
428 for (i=0;i<n;i++) {
429 if (mask[i]) {
430 GLint Rs, Gs, Bs, As; /* Source colors */
431 GLint Rd, Gd, Bd, Ad; /* Dest colors */
432 GLfloat sR, sG, sB, sA; /* Source scaling */
433 GLfloat dR, dG, dB, dA; /* Dest scaling */
434 GLfloat r, g, b, a;
435
436 /* Source Color */
437 Rs = rgba[i][RCOMP];
438 Gs = rgba[i][GCOMP];
439 Bs = rgba[i][BCOMP];
440 As = rgba[i][ACOMP];
441
442 /* Frame buffer color */
443 Rd = dest[i][RCOMP];
444 Gd = dest[i][GCOMP];
445 Bd = dest[i][BCOMP];
446 Ad = dest[i][ACOMP];
447
448 /* Source RGB factor */
449 switch (ctx->Color.BlendSrcRGB) {
450 case GL_ZERO:
451 sR = sG = sB = 0.0F;
452 break;
453 case GL_ONE:
454 sR = sG = sB = 1.0F;
455 break;
456 case GL_DST_COLOR:
457 sR = (GLfloat) Rd * rscale;
458 sG = (GLfloat) Gd * gscale;
459 sB = (GLfloat) Bd * bscale;
460 break;
461 case GL_ONE_MINUS_DST_COLOR:
462 sR = 1.0F - (GLfloat) Rd * rscale;
463 sG = 1.0F - (GLfloat) Gd * gscale;
464 sB = 1.0F - (GLfloat) Bd * bscale;
465 break;
466 case GL_SRC_ALPHA:
467 sR = sG = sB = (GLfloat) As * ascale;
468 break;
469 case GL_ONE_MINUS_SRC_ALPHA:
470 sR = sG = sB = (GLfloat) 1.0F - (GLfloat) As * ascale;
471 break;
472 case GL_DST_ALPHA:
473 sR = sG = sB = (GLfloat) Ad * ascale;
474 break;
475 case GL_ONE_MINUS_DST_ALPHA:
476 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
477 break;
478 case GL_SRC_ALPHA_SATURATE:
479 if (As < 1.0F - (GLfloat) Ad * ascale) {
480 sR = sG = sB = (GLfloat) As * ascale;
481 }
482 else {
483 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
484 }
485 break;
486 case GL_CONSTANT_COLOR:
487 sR = ctx->Color.BlendColor[0];
488 sG = ctx->Color.BlendColor[1];
489 sB = ctx->Color.BlendColor[2];
490 break;
491 case GL_ONE_MINUS_CONSTANT_COLOR:
492 sR = 1.0F - ctx->Color.BlendColor[0];
493 sG = 1.0F - ctx->Color.BlendColor[1];
494 sB = 1.0F - ctx->Color.BlendColor[2];
495 break;
496 case GL_CONSTANT_ALPHA:
497 sR = sG = sB = ctx->Color.BlendColor[3];
498 break;
499 case GL_ONE_MINUS_CONSTANT_ALPHA:
500 sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
501 break;
502 default:
503 /* this should never happen */
504 gl_problem(ctx, "Bad blend source RGB factor in do_blend");
505 return;
506 }
507
508 /* Source Alpha factor */
509 switch (ctx->Color.BlendSrcA) {
510 case GL_ZERO:
511 sA = 0.0F;
512 break;
513 case GL_ONE:
514 sA = 1.0F;
515 break;
516 case GL_DST_COLOR:
517 sA = (GLfloat) Ad * ascale;
518 break;
519 case GL_ONE_MINUS_DST_COLOR:
520 sA = 1.0F - (GLfloat) Ad * ascale;
521 break;
522 case GL_SRC_ALPHA:
523 sA = (GLfloat) As * ascale;
524 break;
525 case GL_ONE_MINUS_SRC_ALPHA:
526 sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
527 break;
528 case GL_DST_ALPHA:
529 sA =(GLfloat) Ad * ascale;
530 break;
531 case GL_ONE_MINUS_DST_ALPHA:
532 sA = 1.0F - (GLfloat) Ad * ascale;
533 break;
534 case GL_SRC_ALPHA_SATURATE:
535 sA = 1.0;
536 break;
537 case GL_CONSTANT_COLOR:
538 sA = ctx->Color.BlendColor[3];
539 break;
540 case GL_ONE_MINUS_CONSTANT_COLOR:
541 sA = 1.0F - ctx->Color.BlendColor[3];
542 break;
543 case GL_CONSTANT_ALPHA:
544 sA = ctx->Color.BlendColor[3];
545 break;
546 case GL_ONE_MINUS_CONSTANT_ALPHA:
547 sA = 1.0F - ctx->Color.BlendColor[3];
548 break;
549 default:
550 /* this should never happen */
551 sA = 0.0F;
552 gl_problem(ctx, "Bad blend source A factor in do_blend");
553 }
554
555 /* Dest RGB factor */
556 switch (ctx->Color.BlendDstRGB) {
557 case GL_ZERO:
558 dR = dG = dB = 0.0F;
559 break;
560 case GL_ONE:
561 dR = dG = dB = 1.0F;
562 break;
563 case GL_SRC_COLOR:
564 dR = (GLfloat) Rs * rscale;
565 dG = (GLfloat) Gs * gscale;
566 dB = (GLfloat) Bs * bscale;
567 break;
568 case GL_ONE_MINUS_SRC_COLOR:
569 dR = 1.0F - (GLfloat) Rs * rscale;
570 dG = 1.0F - (GLfloat) Gs * gscale;
571 dB = 1.0F - (GLfloat) Bs * bscale;
572 break;
573 case GL_SRC_ALPHA:
574 dR = dG = dB = (GLfloat) As * ascale;
575 break;
576 case GL_ONE_MINUS_SRC_ALPHA:
577 dR = dG = dB = (GLfloat) 1.0F - (GLfloat) As * ascale;
578 break;
579 case GL_DST_ALPHA:
580 dR = dG = dB = (GLfloat) Ad * ascale;
581 break;
582 case GL_ONE_MINUS_DST_ALPHA:
583 dR = dG = dB = 1.0F - (GLfloat) Ad * ascale;
584 break;
585 case GL_CONSTANT_COLOR:
586 dR = ctx->Color.BlendColor[0];
587 dG = ctx->Color.BlendColor[1];
588 dB = ctx->Color.BlendColor[2];
589 break;
590 case GL_ONE_MINUS_CONSTANT_COLOR:
591 dR = 1.0F - ctx->Color.BlendColor[0];
592 dG = 1.0F - ctx->Color.BlendColor[1];
593 dB = 1.0F - ctx->Color.BlendColor[2];
594 break;
595 case GL_CONSTANT_ALPHA:
596 dR = dG = dB = ctx->Color.BlendColor[3];
597 break;
598 case GL_ONE_MINUS_CONSTANT_ALPHA:
599 dR = dG = dB = 1.0F - ctx->Color.BlendColor[3] * ascale;
600 break;
601 default:
602 /* this should never happen */
603 dR = dG = dB = 0.0F;
604 gl_problem(ctx, "Bad blend dest RGB factor in do_blend");
605 }
606
607 /* Dest Alpha factor */
608 switch (ctx->Color.BlendDstA) {
609 case GL_ZERO:
610 dA = 0.0F;
611 break;
612 case GL_ONE:
613 dA = 1.0F;
614 break;
615 case GL_SRC_COLOR:
616 dA = (GLfloat) As * ascale;
617 break;
618 case GL_ONE_MINUS_SRC_COLOR:
619 dA = 1.0F - (GLfloat) As * ascale;
620 break;
621 case GL_SRC_ALPHA:
622 dA = (GLfloat) As * ascale;
623 break;
624 case GL_ONE_MINUS_SRC_ALPHA:
625 dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
626 break;
627 case GL_DST_ALPHA:
628 dA = (GLfloat) Ad * ascale;
629 break;
630 case GL_ONE_MINUS_DST_ALPHA:
631 dA = 1.0F - (GLfloat) Ad * ascale;
632 break;
633 case GL_CONSTANT_COLOR:
634 dA = ctx->Color.BlendColor[3];
635 break;
636 case GL_ONE_MINUS_CONSTANT_COLOR:
637 dA = 1.0F - ctx->Color.BlendColor[3];
638 break;
639 case GL_CONSTANT_ALPHA:
640 dA = ctx->Color.BlendColor[3];
641 break;
642 case GL_ONE_MINUS_CONSTANT_ALPHA:
643 dA = 1.0F - ctx->Color.BlendColor[3] * ascale;
644 break;
645 default:
646 /* this should never happen */
647 dA = 0.0F;
648 gl_problem(ctx, "Bad blend dest A factor in do_blend");
649 return;
650 }
651
652 /* Due to round-off problems we have to clamp against zero. */
653 /* Optimization: we don't have to do this for all src & dst factors */
654 if (dA < 0.0F) dA = 0.0F;
655 if (dR < 0.0F) dR = 0.0F;
656 if (dG < 0.0F) dG = 0.0F;
657 if (dB < 0.0F) dB = 0.0F;
658 if (sA < 0.0F) sA = 0.0F;
659 if (sR < 0.0F) sR = 0.0F;
660 if (sG < 0.0F) sG = 0.0F;
661 if (sB < 0.0F) sB = 0.0F;
662
663 ASSERT( sR <= 1.0 );
664 ASSERT( sG <= 1.0 );
665 ASSERT( sB <= 1.0 );
666 ASSERT( sA <= 1.0 );
667 ASSERT( dR <= 1.0 );
668 ASSERT( dG <= 1.0 );
669 ASSERT( dB <= 1.0 );
670 ASSERT( dA <= 1.0 );
671
672 /* compute blended color */
673 if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) {
674 r = Rs * sR + Rd * dR;
675 g = Gs * sG + Gd * dG;
676 b = Bs * sB + Bd * dB;
677 a = As * sA + Ad * dA;
678 }
679 else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) {
680 r = Rs * sR - Rd * dR;
681 g = Gs * sG - Gd * dG;
682 b = Bs * sB - Bd * dB;
683 a = As * sA - Ad * dA;
684 }
685 else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) {
686 r = Rd * dR - Rs * sR;
687 g = Gd * dG - Gs * sG;
688 b = Bd * dB - Bs * sB;
689 a = Ad * dA - As * sA;
690 }
691 else {
692 /* should never get here */
693 r = g = b = a = 0.0F; /* silence uninitialized var warning */
694 gl_problem(ctx, "unexpected BlendEquation in blend_general()");
695 }
696
697 /* final clamping */
698 rgba[i][RCOMP] = (GLubyte) (GLint) CLAMP( r, 0.0F, 255.0F );
699 rgba[i][GCOMP] = (GLubyte) (GLint) CLAMP( g, 0.0F, 255.0F );
700 rgba[i][BCOMP] = (GLubyte) (GLint) CLAMP( b, 0.0F, 255.0F );
701 rgba[i][ACOMP] = (GLubyte) (GLint) CLAMP( a, 0.0F, 255.0F );
702 }
703 }
704 }
705
706
707
708 #if defined(USE_MMX_ASM)
709 #include "X86/mmx.h"
710 #include "X86/common_x86asm.h"
711 #endif
712
713
714 /*
715 * Analyze current blending parameters to pick fastest blending function.
716 * Result: the ctx->Color.BlendFunc pointer is updated.
717 */
718 static void set_blend_function( GLcontext *ctx )
719 {
720 const GLenum eq = ctx->Color.BlendEquation;
721 const GLenum srcRGB = ctx->Color.BlendSrcRGB;
722 const GLenum dstRGB = ctx->Color.BlendDstRGB;
723 const GLenum srcA = ctx->Color.BlendSrcA;
724 const GLenum dstA = ctx->Color.BlendDstA;
725
726 #if defined(USE_MMX_ASM)
727 /* Hmm. A table here would have 12^4 == way too many entries.
728 * Provide a hook for MMX instead.
729 */
730 if (gl_x86_cpu_features & GL_CPU_MMX) {
731 gl_mmx_set_blend_function (ctx);
732 } else
733 #endif
734 if (srcRGB != srcA || dstRGB != dstA) {
735 ctx->Color.BlendFunc = blend_general;
736 }
737 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_SRC_ALPHA
738 && dstRGB==GL_ONE_MINUS_SRC_ALPHA) {
739 ctx->Color.BlendFunc = blend_transparency;
740 }
741 else if (eq==GL_FUNC_ADD_EXT && srcRGB==GL_ONE && dstRGB==GL_ONE) {
742 ctx->Color.BlendFunc = blend_add;
743 }
744 else if (((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_REVERSE_SUBTRACT_EXT)
745 && (srcRGB==GL_ZERO && dstRGB==GL_SRC_COLOR))
746 ||
747 ((eq==GL_FUNC_ADD_EXT || eq==GL_FUNC_SUBTRACT_EXT)
748 && (srcRGB==GL_DST_COLOR && dstRGB==GL_ZERO))) {
749 ctx->Color.BlendFunc = blend_modulate;
750 }
751 else if (eq==GL_MIN_EXT) {
752 ctx->Color.BlendFunc = blend_min;
753 }
754 else if (eq==GL_MAX_EXT) {
755 ctx->Color.BlendFunc = blend_max;
756 }
757 else {
758 ctx->Color.BlendFunc = blend_general;
759 }
760 }
761
762
763
764 /*
765 * Apply the blending operator to a span of pixels.
766 * Input: n - number of pixels in span
767 * x, y - location of leftmost pixel in span in window coords.
768 * mask - boolean mask indicating which pixels to blend.
769 * In/Out: rgba - pixel values
770 */
771 void gl_blend_span( GLcontext *ctx, GLuint n, GLint x, GLint y,
772 GLubyte rgba[][4], const GLubyte mask[] )
773 {
774 GLubyte dest[MAX_WIDTH][4];
775
776 /* Check if device driver can do the work */
777 if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
778 return;
779 }
780
781 /* Read span of current frame buffer pixels */
782 gl_read_rgba_span( ctx, n, x, y, dest );
783
784 if (!ctx->Color.BlendFunc)
785 set_blend_function(ctx);
786
787 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest );
788 }
789
790
791
792
793
794 /*
795 * Apply the blending operator to an array of pixels.
796 * Input: n - number of pixels in span
797 * x, y - array of pixel locations
798 * mask - boolean mask indicating which pixels to blend.
799 * In/Out: rgba - pixel values
800 */
801 void gl_blend_pixels( GLcontext *ctx,
802 GLuint n, const GLint x[], const GLint y[],
803 GLubyte rgba[][4], const GLubyte mask[] )
804 {
805 GLubyte dest[PB_SIZE][4];
806
807 /* Check if device driver can do the work */
808 if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) {
809 return;
810 }
811
812 /* Read pixels from current color buffer */
813 (*ctx->Driver.ReadRGBAPixels)( ctx, n, x, y, dest, mask );
814 if (ctx->RasterMask & ALPHABUF_BIT) {
815 gl_read_alpha_pixels( ctx, n, x, y, dest, mask );
816 }
817
818 if (!ctx->Color.BlendFunc)
819 set_blend_function(ctx);
820
821 (*ctx->Color.BlendFunc)( ctx, n, mask, rgba, (const GLubyte (*)[4])dest );
822 }