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 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 */ 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 */ 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 */ 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