1 /* $Id: blend.c,v 1.10 1998/01/27 03:42:40 brianp Exp $ */
2
3 /*
4 * Mesa 3-D graphics library
5 * Version: 2.6
6 * Copyright (C) 1995-1997 Brian Paul
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23
24 /*
25 * $Log: blend.c,v $
26 * Revision 1.10 1998/01/27 03:42:40 brianp
27 * optimized more blending modes (Kai Schuetz)
28 *
29 * Revision 1.9 1997/07/24 01:24:45 brianp
30 * changed precompiled header symbol from PCH to PC_HEADER
31 *
32 * Revision 1.8 1997/05/28 03:23:48 brianp
33 * added precompiled header (PCH) support
34 *
35 * Revision 1.7 1997/04/20 19:51:57 brianp
36 * replaced abort() with gl_problem()
37 *
38 * Revision 1.6 1997/02/15 18:27:56 brianp
39 * fixed a few error messages
40 *
41 * Revision 1.5 1997/01/28 22:17:19 brianp
42 * moved logic op blending into logic.c
43 *
44 * Revision 1.4 1997/01/04 00:13:11 brianp
45 * was using ! instead of ~ to invert pixel bits (ugh!)
46 *
47 * Revision 1.3 1996/09/19 00:53:31 brianp
48 * added missing returns after some gl_error() calls
49 *
50 * Revision 1.2 1996/09/15 14:18:10 brianp
51 * now use GLframebuffer and GLvisual
52 *
53 * Revision 1.1 1996/09/13 01:38:16 brianp
54 * Initial revision
55 *
56 */
57
58
59 #ifdef PC_HEADER
60 #include "all.h"
61 #else
62 #include <assert.h>
63 #include <stdlib.h>
64 #include "alphabuf.h"
65 #include "blend.h"
66 #include "context.h"
67 #include "dlist.h"
68 #include "macros.h"
69 #include "pb.h"
70 #include "span.h"
71 #include "types.h"
72 #endif
73
74
75
gl_BlendFunc(GLcontext * ctx,GLenum sfactor,GLenum dfactor)76 void gl_BlendFunc( GLcontext* ctx, GLenum sfactor, GLenum dfactor )
77 {
78 if (INSIDE_BEGIN_END(ctx)) {
79 gl_error( ctx, GL_INVALID_OPERATION, "glBlendFunc" );
80 return;
81 }
82
83 switch (sfactor) {
84 case GL_ZERO:
85 case GL_ONE:
86 case GL_DST_COLOR:
87 case GL_ONE_MINUS_DST_COLOR:
88 case GL_SRC_ALPHA:
89 case GL_ONE_MINUS_SRC_ALPHA:
90 case GL_DST_ALPHA:
91 case GL_ONE_MINUS_DST_ALPHA:
92 case GL_SRC_ALPHA_SATURATE:
93 ctx->Color.BlendSrc = sfactor;
94 break;
95 default:
96 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(sfactor)" );
97 return;
98 }
99
100 switch (dfactor) {
101 case GL_ZERO:
102 case GL_ONE:
103 case GL_SRC_COLOR:
104 case GL_ONE_MINUS_SRC_COLOR:
105 case GL_SRC_ALPHA:
106 case GL_ONE_MINUS_SRC_ALPHA:
107 case GL_DST_ALPHA:
108 case GL_ONE_MINUS_DST_ALPHA:
109 ctx->Color.BlendDst = dfactor;
110 break;
111 default:
112 gl_error( ctx, GL_INVALID_ENUM, "glBlendFunc(dfactor)" );
113 }
114
115 ctx->NewState |= NEW_RASTER_OPS;
116 }
117
118
119
120 /*
121 * Do the real work of gl_blend_span() and gl_blend_pixels().
122 * Input: n - number of pixels
123 * mask - the usual write mask
124 * In/Out: red, green, blue, alpha - the incoming and modified pixels
125 * Input: rdest, gdest, bdest, adest - the pixels from the dest color buffer
126 */
do_blend(GLcontext * ctx,GLuint n,const GLubyte mask[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[],const GLubyte rdest[],const GLubyte gdest[],const GLubyte bdest[],const GLubyte adest[])127 static void do_blend( GLcontext* ctx, GLuint n, const GLubyte mask[],
128 GLubyte red[], GLubyte green[],
129 GLubyte blue[], GLubyte alpha[],
130 const GLubyte rdest[], const GLubyte gdest[],
131 const GLubyte bdest[], const GLubyte adest[] )
132 {
133 GLuint i;
134
135 if (ctx->Color.BlendSrc==GL_SRC_ALPHA
136 && ctx->Color.BlendDst==GL_ONE_MINUS_SRC_ALPHA) {
137 /* Alpha blending */
138 GLfloat ascale = 256.0f * ctx->Visual->InvAlphaScale;
139 GLint rmax = (GLint) ctx->Visual->RedScale;
140 GLint gmax = (GLint) ctx->Visual->GreenScale;
141 GLint bmax = (GLint) ctx->Visual->BlueScale;
142 GLint amax = (GLint) ctx->Visual->AlphaScale;
143 for (i=0;i<n;i++) {
144 if (mask[i]) {
145 GLint r, g, b, a;
146 GLint t = (GLint) ( alpha[i] * ascale ); /* t in [0,256] */
147 GLint s = 256 - t;
148 r = (red[i] * t + rdest[i] * s) >> 8;
149 g = (green[i] * t + gdest[i] * s) >> 8;
150 b = (blue[i] * t + bdest[i] * s) >> 8;
151 a = (alpha[i] * t + adest[i] * s) >> 8;
152
153 /* kai: I think the following clamping is not needed: */
154
155 red[i] = MIN2( r, rmax );
156 green[i] = MIN2( g, gmax );
157 blue[i] = MIN2( b, bmax );
158 alpha[i] = MIN2( a, amax );
159 }
160 }
161 }
162 else {
163
164 /* clipped sum */
165 if (ctx->Color.BlendSrc==GL_ONE
166 && ctx->Color.BlendDst==GL_ONE) {
167 GLint rmax = (GLint) ctx->Visual->RedScale;
168 GLint gmax = (GLint) ctx->Visual->GreenScale;
169 GLint bmax = (GLint) ctx->Visual->BlueScale;
170 GLint amax = (GLint) ctx->Visual->AlphaScale;
171 for (i=0; i < n; i++) {
172 if (mask[i]) {
173 red[i] = MIN2(rmax, red[i] + rdest[i]);
174 green[i] = MIN2(gmax, green[i] + gdest[i]);
175 blue[i] = MIN2(bmax, blue[i] + bdest[i]);
176 alpha[i] = MIN2(amax, alpha[i] + adest[i]);
177 }
178 }
179 }
180
181 /* modulation */
182 else if ((ctx->Color.BlendSrc==GL_ZERO &&
183 ctx->Color.BlendDst==GL_SRC_COLOR)
184 ||
185 (ctx->Color.BlendSrc==GL_DST_COLOR &&
186 ctx->Color.BlendDst==GL_ZERO)) {
187 if (ctx->Visual->EightBitColor) {
188 for (i=0; i < n; i++) {
189 if (mask[i]) {
190 red[i] = (red[i] * rdest[i]) / 255;
191 green[i] = (green[i] * gdest[i]) / 255;
192 blue[i] = (blue[i] * bdest[i]) / 255;
193 alpha[i] = (alpha[i] * adest[i]) / 255;
194 }
195 }
196 }
197 else {
198 GLint rmax = (GLint) ctx->Visual->RedScale;
199 GLint gmax = (GLint) ctx->Visual->GreenScale;
200 GLint bmax = (GLint) ctx->Visual->BlueScale;
201 GLint amax = (GLint) ctx->Visual->AlphaScale;
202 for (i=0; i < n; i++) {
203 if (mask[i]) {
204 red[i] = (red[i] * rdest[i]) / rmax;
205 green[i] = (green[i] * gdest[i]) / gmax;
206 blue[i] = (blue[i] * bdest[i]) / bmax;
207 alpha[i] = (alpha[i] * adest[i]) / amax;
208 }
209 }
210 }
211 }else{
212
213 /* General cases: */
214
215 if (ctx->Visual->EightBitColor) {
216 for (i=0;i<n;i++) {
217 if (mask[i]) {
218 GLint Rs, Gs, Bs, As; /* Source colors */
219 GLint Rd, Gd, Bd, Ad; /* Dest colors */
220 GLint Rss, Gss, Bss, Ass; /* Source colors scaled */
221 GLint Rds, Gds, Bds, Ads; /* Dest colors scaled */
222
223 /* Source Color */
224 Rs = red[i];
225 Gs = green[i];
226 Bs = blue[i];
227 As = alpha[i];
228
229 /* Frame buffer color */
230 Rd = rdest[i];
231 Gd = gdest[i];
232 Bd = bdest[i];
233 Ad = adest[i];
234
235 /* Source scaling */
236 switch (ctx->Color.BlendSrc) {
237 case GL_ZERO:
238 Rss = Gss = Bss = Ass = 0;
239 break;
240 case GL_ONE:
241 Rss = Rs * 255;
242 Gss = Gs * 255;
243 Bss = Bs * 255;
244 Ass = As * 255;
245 break;
246 case GL_DST_COLOR:
247 Rss = Rs * Rd;
248 Gss = Gs * Gd;
249 Bss = Bs * Bd;
250 Ass = As * Ad;
251 break;
252 case GL_ONE_MINUS_DST_COLOR:
253 Rss = Rs * (255 - Rd);
254 Gss = Gs * (255 - Gd);
255 Bss = Bs * (255 - Bd);
256 Ass = As * (255 - Ad);
257 break;
258 case GL_SRC_ALPHA:
259 Rss = Rs * As;
260 Gss = Gs * As;
261 Bss = Bs * As;
262 Ass = As * As;
263 break;
264 case GL_ONE_MINUS_SRC_ALPHA:
265 Rss = Rs * (255 - As);
266 Gss = Gs * (255 - As);
267 Bss = Bs * (255 - As);
268 Ass = As * (255 - As);
269 break;
270 case GL_DST_ALPHA:
271 Rss = Rs * Ad;
272 Gss = Gs * Ad;
273 Bss = Bs * Ad;
274 Ass = As * Ad;
275 break;
276 case GL_ONE_MINUS_DST_ALPHA:
277 Rss = Rs * (255 - Ad);
278 Gss = Gs * (255 - Ad);
279 Bss = Bs * (255 - Ad);
280 Ass = As * (255 - Ad);
281 break;
282 case GL_SRC_ALPHA_SATURATE:
283 {
284 GLint sA = MIN2(As, 255 - Ad);
285 Rss = Rs * sA;
286 Gss = Gs * sA;
287 Bss = Bs * sA;
288 Ass = As * 255;
289 break;
290 }
291 default:
292 /* this should never happen */
293 gl_problem(ctx, "Bad blend source factor in do_blend");
294 }
295
296 /* Dest scaling */
297 switch (ctx->Color.BlendDst) {
298 case GL_ZERO:
299 Rds = Gds = Bds = Ads = 0;
300 break;
301 case GL_ONE:
302 Rds = Rd * 255;
303 Gds = Gd * 255;
304 Bds = Bd * 255;
305 Ads = Ad * 255;
306 break;
307 case GL_SRC_COLOR:
308 Rds = Rd * Rs;
309 Gds = Gd * Gs;
310 Bds = Bd * Bs;
311 Ads = Ad * As;
312 break;
313 case GL_ONE_MINUS_SRC_COLOR:
314 Rds = Rs * (255 - Rs);
315 Gds = Gs * (255 - Gs);
316 Bds = Bs * (255 - Bs);
317 Ads = As * (255 - As);
318 break;
319 case GL_SRC_ALPHA:
320 Rds = Rd * As;
321 Gds = Gd * As;
322 Bds = Bd * As;
323 Ads = Ad * As;
324 break;
325 case GL_ONE_MINUS_SRC_ALPHA:
326 Rds = Rd * (255 - As);
327 Gds = Gd * (255 - As);
328 Bds = Bd * (255 - As);
329 Ads = Ad * (255 - As);
330 break;
331 case GL_DST_ALPHA:
332 Rds = Rd * Ad;
333 Gds = Gd * Ad;
334 Bds = Bd * Ad;
335 Ads = Ad * Ad;
336 break;
337 case GL_ONE_MINUS_DST_ALPHA:
338 Rds = Rd * (255 - Ad);
339 Gds = Gd * (255 - Ad);
340 Bds = Bd * (255 - Ad);
341 Ads = Ad * (255 - Ad);
342 break;
343 default:
344 /* this should never happen */
345 gl_problem(ctx, "Bad blend dest factor in do_blend");
346 }
347
348 /* compute blended color */
349 red[i] = MIN2((Rss + Rds) / 255, 255);
350 green[i] = MIN2((Gss + Gds) / 255, 255);
351 blue[i] = MIN2((Bss + Bds) / 255, 255);
352 alpha[i] = MIN2((Ass + Ads) / 255, 255);
353 }
354 }
355 }else{ /* !EightBitColor */
356 GLfloat rmax = ctx->Visual->RedScale;
357 GLfloat gmax = ctx->Visual->GreenScale;
358 GLfloat bmax = ctx->Visual->BlueScale;
359 GLfloat amax = ctx->Visual->AlphaScale;
360 GLfloat rscale = 1.0f / rmax;
361 GLfloat gscale = 1.0f / gmax;
362 GLfloat bscale = 1.0f / bmax;
363 GLfloat ascale = 1.0f / amax;
364
365 for (i=0;i<n;i++) {
366 if (mask[i]) {
367 GLint Rs, Gs, Bs, As; /* Source colors */
368 GLint Rd, Gd, Bd, Ad; /* Dest colors */
369 GLfloat sR, sG, sB, sA; /* Source scaling */
370 GLfloat dR, dG, dB, dA; /* Dest scaling */
371 GLfloat r, g, b, a;
372
373 /* Source Color */
374 Rs = red[i];
375 Gs = green[i];
376 Bs = blue[i];
377 As = alpha[i];
378
379 /* Frame buffer color */
380 Rd = rdest[i];
381 Gd = gdest[i];
382 Bd = bdest[i];
383 Ad = adest[i];
384
385 /* Source scaling */
386 switch (ctx->Color.BlendSrc) {
387 case GL_ZERO:
388 sR = sG = sB = sA = 0.0F;
389 break;
390 case GL_ONE:
391 sR = sG = sB = sA = 1.0F;
392 break;
393 case GL_DST_COLOR:
394 sR = (GLfloat) Rd * rscale;
395 sG = (GLfloat) Gd * gscale;
396 sB = (GLfloat) Bd * bscale;
397 sA = (GLfloat) Ad * ascale;
398 break;
399 case GL_ONE_MINUS_DST_COLOR:
400 sR = 1.0F - (GLfloat) Rd * rscale;
401 sG = 1.0F - (GLfloat) Gd * gscale;
402 sB = 1.0F - (GLfloat) Bd * bscale;
403 sA = 1.0F - (GLfloat) Ad * ascale;
404 break;
405 case GL_SRC_ALPHA:
406 sR = sG = sB = sA = (GLfloat) As * ascale;
407 break;
408 case GL_ONE_MINUS_SRC_ALPHA:
409 sR = sG = sB = sA = (GLfloat) 1.0F - (GLfloat) As * ascale;
410 break;
411 case GL_DST_ALPHA:
412 sR = sG = sB = sA =(GLfloat) Ad * ascale;
413 break;
414 case GL_ONE_MINUS_DST_ALPHA:
415 sR = sG = sB = sA = 1.0F - (GLfloat) Ad * ascale;
416 break;
417 case GL_SRC_ALPHA_SATURATE:
418 if (As < 1.0F - (GLfloat) Ad * ascale) {
419 sR = sG = sB = (GLfloat) As * ascale;
420 }
421 else {
422 sR = sG = sB = 1.0F - (GLfloat) Ad * ascale;
423 }
424 sA = 1.0;
425 break;
426 default:
427 /* this should never happen */
428 gl_problem(ctx, "Bad blend source factor in do_blend");
429 }
430
431 /* Dest scaling */
432 switch (ctx->Color.BlendDst) {
433 case GL_ZERO:
434 dR = dG = dB = dA = 0.0F;
435 break;
436 case GL_ONE:
437 dR = dG = dB = dA = 1.0F;
438 break;
439 case GL_SRC_COLOR:
440 dR = (GLfloat) Rs * rscale;
441 dG = (GLfloat) Gs * gscale;
442 dB = (GLfloat) Bs * bscale;
443 dA = (GLfloat) As * ascale;
444 break;
445 case GL_ONE_MINUS_SRC_COLOR:
446 dR = 1.0F - (GLfloat) Rs * rscale;
447 dG = 1.0F - (GLfloat) Gs * gscale;
448 dB = 1.0F - (GLfloat) Bs * bscale;
449 dA = 1.0F - (GLfloat) As * ascale;
450 break;
451 case GL_SRC_ALPHA:
452 dR = dG = dB = dA = (GLfloat) As * ascale;
453 break;
454 case GL_ONE_MINUS_SRC_ALPHA:
455 dR = dG = dB = dA = (GLfloat) 1.0F - (GLfloat) As * ascale;
456 break;
457 case GL_DST_ALPHA:
458 dR = dG = dB = dA = (GLfloat) Ad * ascale;
459 break;
460 case GL_ONE_MINUS_DST_ALPHA:
461 dR = dG = dB = dA = 1.0F - (GLfloat) Ad * ascale;
462 break;
463 default:
464 /* this should never happen */
465 gl_problem(ctx, "Bad blend dest factor in do_blend");
466 }
467
468 #ifdef DEBUG
469 assert( sR>= 0.0 && sR<=1.0 );
470 assert( sG>= 0.0 && sG<=1.0 );
471 assert( sB>= 0.0 && sB<=1.0 );
472 assert( sA>= 0.0 && sA<=1.0 );
473 assert( dR>= 0.0 && dR<=1.0 );
474 assert( dG>= 0.0 && dG<=1.0 );
475 assert( dB>= 0.0 && dB<=1.0 );
476 assert( dA>= 0.0 && dA<=1.0 );
477 #endif
478
479 /* compute blended color */
480 r = Rs * sR + Rd * dR;
481 g = Gs * sG + Gd * dG;
482 b = Bs * sB + Bd * dB;
483 a = As * sA + Ad * dA;
484 red[i] = (GLint) CLAMP( r, 0.0F, rmax );
485 green[i] = (GLint) CLAMP( g, 0.0F, gmax );
486 blue[i] = (GLint) CLAMP( b, 0.0F, bmax );
487 alpha[i] = (GLint) CLAMP( a, 0.0F, amax );
488 }
489 }
490 }
491 }
492 }
493
494 }
495
496
497
498
499
500 /*
501 * Apply the blending operator to a span of pixels.
502 * Input: n - number of pixels in span
503 * x, y - location of leftmost pixel in span in window coords.
504 * mask - boolean mask indicating which pixels to blend.
505 * In/Out: red, green, blue, alpha - pixel values
506 */
gl_blend_span(GLcontext * ctx,GLuint n,GLint x,GLint y,GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[],GLubyte mask[])507 void gl_blend_span( GLcontext* ctx, GLuint n, GLint x, GLint y,
508 GLubyte red[], GLubyte green[],
509 GLubyte blue[], GLubyte alpha[],
510 GLubyte mask[] )
511 {
512 GLubyte rdest[MAX_WIDTH], gdest[MAX_WIDTH];
513 GLubyte bdest[MAX_WIDTH], adest[MAX_WIDTH];
514
515 /* Read span of current frame buffer pixels */
516 gl_read_color_span( ctx, n, x, y, rdest, gdest, bdest, adest );
517
518 do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest );
519 }
520
521
522
523
524
525 /*
526 * Apply the blending operator to an array of pixels.
527 * Input: n - number of pixels in span
528 * x, y - array of pixel locations
529 * mask - boolean mask indicating which pixels to blend.
530 * In/Out: red, green, blue, alpha - array of pixel values
531 */
gl_blend_pixels(GLcontext * ctx,GLuint n,const GLint x[],const GLint y[],GLubyte red[],GLubyte green[],GLubyte blue[],GLubyte alpha[],GLubyte mask[])532 void gl_blend_pixels( GLcontext* ctx,
533 GLuint n, const GLint x[], const GLint y[],
534 GLubyte red[], GLubyte green[],
535 GLubyte blue[], GLubyte alpha[],
536 GLubyte mask[] )
537 {
538 GLubyte rdest[PB_SIZE], gdest[PB_SIZE], bdest[PB_SIZE], adest[PB_SIZE];
539
540 /* Read pixels from current color buffer */
541 (*ctx->Driver.ReadColorPixels)( ctx, n, x, y, rdest, gdest, bdest, adest, mask );
542 if (ctx->RasterMask & ALPHABUF_BIT) {
543 gl_read_alpha_pixels( ctx, n, x, y, adest, mask );
544 }
545
546 do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest );
547 }
548