xref: /reactos/dll/opengl/mesa/blend.c (revision 5f2bebf7)
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