1 /* $Id: blend.c,v 1.10 1998/01/27 03:42:40 brianp Exp $ */
4 * Mesa 3-D graphics library
6 * Copyright (C) 1995-1997 Brian Paul
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.
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.
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.
26 * Revision 1.10 1998/01/27 03:42:40 brianp
27 * optimized more blending modes (Kai Schuetz)
29 * Revision 1.9 1997/07/24 01:24:45 brianp
30 * changed precompiled header symbol from PCH to PC_HEADER
32 * Revision 1.8 1997/05/28 03:23:48 brianp
33 * added precompiled header (PCH) support
35 * Revision 1.7 1997/04/20 19:51:57 brianp
36 * replaced abort() with gl_problem()
38 * Revision 1.6 1997/02/15 18:27:56 brianp
39 * fixed a few error messages
41 * Revision 1.5 1997/01/28 22:17:19 brianp
42 * moved logic op blending into logic.c
44 * Revision 1.4 1997/01/04 00:13:11 brianp
45 * was using ! instead of ~ to invert pixel bits (ugh!)
47 * Revision 1.3 1996/09/19 00:53:31 brianp
48 * added missing returns after some gl_error() calls
50 * Revision 1.2 1996/09/15 14:18:10 brianp
51 * now use GLframebuffer and GLvisual
53 * Revision 1.1 1996/09/13 01:38:16 brianp
76 void gl_BlendFunc( GLcontext
* ctx
, GLenum sfactor
, GLenum dfactor
)
78 if (INSIDE_BEGIN_END(ctx
)) {
79 gl_error( ctx
, GL_INVALID_OPERATION
, "glBlendFunc" );
87 case GL_ONE_MINUS_DST_COLOR
:
89 case GL_ONE_MINUS_SRC_ALPHA
:
91 case GL_ONE_MINUS_DST_ALPHA
:
92 case GL_SRC_ALPHA_SATURATE
:
93 ctx
->Color
.BlendSrc
= sfactor
;
96 gl_error( ctx
, GL_INVALID_ENUM
, "glBlendFunc(sfactor)" );
104 case GL_ONE_MINUS_SRC_COLOR
:
106 case GL_ONE_MINUS_SRC_ALPHA
:
108 case GL_ONE_MINUS_DST_ALPHA
:
109 ctx
->Color
.BlendDst
= dfactor
;
112 gl_error( ctx
, GL_INVALID_ENUM
, "glBlendFunc(dfactor)" );
115 ctx
->NewState
|= NEW_RASTER_OPS
;
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
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
[] )
135 if (ctx
->Color
.BlendSrc
==GL_SRC_ALPHA
136 && ctx
->Color
.BlendDst
==GL_ONE_MINUS_SRC_ALPHA
) {
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
;
146 GLint t
= (GLint
) ( alpha
[i
] * ascale
); /* t in [0,256] */
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;
153 /* kai: I think the following clamping is not needed: */
155 red
[i
] = MIN2( r
, rmax
);
156 green
[i
] = MIN2( g
, gmax
);
157 blue
[i
] = MIN2( b
, bmax
);
158 alpha
[i
] = MIN2( a
, amax
);
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
++) {
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
]);
182 else if ((ctx
->Color
.BlendSrc
==GL_ZERO
&&
183 ctx
->Color
.BlendDst
==GL_SRC_COLOR
)
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
++) {
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;
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
++) {
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
;
215 if (ctx
->Visual
->EightBitColor
) {
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 */
229 /* Frame buffer color */
236 switch (ctx
->Color
.BlendSrc
) {
238 Rss
= Gss
= Bss
= Ass
= 0;
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
);
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
);
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
);
282 case GL_SRC_ALPHA_SATURATE
:
284 GLint sA
= MIN2(As
, 255 - Ad
);
292 /* this should never happen */
293 gl_problem(ctx
, "Bad blend source factor in do_blend");
297 switch (ctx
->Color
.BlendDst
) {
299 Rds
= Gds
= Bds
= Ads
= 0;
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
);
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
);
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
);
344 /* this should never happen */
345 gl_problem(ctx
, "Bad blend dest factor in do_blend");
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);
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
;
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 */
379 /* Frame buffer color */
386 switch (ctx
->Color
.BlendSrc
) {
388 sR
= sG
= sB
= sA
= 0.0F
;
391 sR
= sG
= sB
= sA
= 1.0F
;
394 sR
= (GLfloat
) Rd
* rscale
;
395 sG
= (GLfloat
) Gd
* gscale
;
396 sB
= (GLfloat
) Bd
* bscale
;
397 sA
= (GLfloat
) Ad
* ascale
;
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
;
406 sR
= sG
= sB
= sA
= (GLfloat
) As
* ascale
;
408 case GL_ONE_MINUS_SRC_ALPHA
:
409 sR
= sG
= sB
= sA
= (GLfloat
) 1.0F
- (GLfloat
) As
* ascale
;
412 sR
= sG
= sB
= sA
=(GLfloat
) Ad
* ascale
;
414 case GL_ONE_MINUS_DST_ALPHA
:
415 sR
= sG
= sB
= sA
= 1.0F
- (GLfloat
) Ad
* ascale
;
417 case GL_SRC_ALPHA_SATURATE
:
418 if (As
< 1.0F
- (GLfloat
) Ad
* ascale
) {
419 sR
= sG
= sB
= (GLfloat
) As
* ascale
;
422 sR
= sG
= sB
= 1.0F
- (GLfloat
) Ad
* ascale
;
427 /* this should never happen */
428 gl_problem(ctx
, "Bad blend source factor in do_blend");
432 switch (ctx
->Color
.BlendDst
) {
434 dR
= dG
= dB
= dA
= 0.0F
;
437 dR
= dG
= dB
= dA
= 1.0F
;
440 dR
= (GLfloat
) Rs
* rscale
;
441 dG
= (GLfloat
) Gs
* gscale
;
442 dB
= (GLfloat
) Bs
* bscale
;
443 dA
= (GLfloat
) As
* ascale
;
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
;
452 dR
= dG
= dB
= dA
= (GLfloat
) As
* ascale
;
454 case GL_ONE_MINUS_SRC_ALPHA
:
455 dR
= dG
= dB
= dA
= (GLfloat
) 1.0F
- (GLfloat
) As
* ascale
;
458 dR
= dG
= dB
= dA
= (GLfloat
) Ad
* ascale
;
460 case GL_ONE_MINUS_DST_ALPHA
:
461 dR
= dG
= dB
= dA
= 1.0F
- (GLfloat
) Ad
* ascale
;
464 /* this should never happen */
465 gl_problem(ctx
, "Bad blend dest factor in do_blend");
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 );
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
);
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
507 void gl_blend_span( GLcontext
* ctx
, GLuint n
, GLint x
, GLint y
,
508 GLubyte red
[], GLubyte green
[],
509 GLubyte blue
[], GLubyte alpha
[],
512 GLubyte rdest
[MAX_WIDTH
], gdest
[MAX_WIDTH
];
513 GLubyte bdest
[MAX_WIDTH
], adest
[MAX_WIDTH
];
515 /* Read span of current frame buffer pixels */
516 gl_read_color_span( ctx
, n
, x
, y
, rdest
, gdest
, bdest
, adest
);
518 do_blend( ctx
, n
, mask
, red
, green
, blue
, alpha
, rdest
, gdest
, bdest
, adest
);
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
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
[],
538 GLubyte rdest
[PB_SIZE
], gdest
[PB_SIZE
], bdest
[PB_SIZE
], adest
[PB_SIZE
];
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
);
546 do_blend( ctx
, n
, mask
, red
, green
, blue
, alpha
, rdest
, gdest
, bdest
, adest
);