This is blend.c in view mode; [Download] [Up]
/* $Id: blend.c,v 1.3 1996/09/19 00:53:31 brianp Exp $ */ /* * Mesa 3-D graphics library * Version: 2.0 * Copyright (C) 1995-1996 Brian Paul * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* * $Log: blend.c,v $ * Revision 1.3 1996/09/19 00:53:31 brianp * added missing returns after some gl_error() calls * * Revision 1.2 1996/09/15 14:18:10 brianp * now use GLframebuffer and GLvisual * * Revision 1.1 1996/09/13 01:38:16 brianp * Initial revision * */ #ifdef DEBUG # include <assert.h> #endif #include <stdlib.h> #include "alphabuf.h" #include "blend.h" #include "context.h" #include "dlist.h" #include "macros.h" #include "pb.h" #include "span.h" #include "types.h" void gl_BlendFunc( GLcontext* ctx, GLenum sfactor, GLenum dfactor ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glBlendFunction" ); return; } switch (sfactor) { case GL_ZERO: case GL_ONE: case GL_DST_COLOR: case GL_ONE_MINUS_DST_COLOR: case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: case GL_DST_ALPHA: case GL_ONE_MINUS_DST_ALPHA: case GL_SRC_ALPHA_SATURATE: case GL_CONSTANT_COLOR: case GL_ONE_MINUS_CONSTANT_COLOR: case GL_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA: ctx->Color.BlendSrc = sfactor; break; default: gl_error( ctx, GL_INVALID_ENUM, "glBlendFunction" ); return; } switch (dfactor) { case GL_ZERO: case GL_ONE: case GL_SRC_COLOR: case GL_ONE_MINUS_SRC_COLOR: case GL_SRC_ALPHA: case GL_ONE_MINUS_SRC_ALPHA: case GL_DST_ALPHA: case GL_ONE_MINUS_DST_ALPHA: case GL_CONSTANT_COLOR: case GL_ONE_MINUS_CONSTANT_COLOR: case GL_CONSTANT_ALPHA: case GL_ONE_MINUS_CONSTANT_ALPHA: ctx->Color.BlendDst = dfactor; break; default: gl_error( ctx, GL_INVALID_ENUM, "glBlendFunction" ); } ctx->NewState |= NEW_RASTER_OPS; } /* This is really an extension function! */ void gl_BlendEquation( GLcontext* ctx, GLenum mode ) { if (INSIDE_BEGIN_END(ctx)) { gl_error( ctx, GL_INVALID_OPERATION, "glBlendEquation" ); return; } switch (mode) { case GL_MIN_EXT: case GL_MAX_EXT: case GL_LOGIC_OP: case GL_FUNC_ADD_EXT: case GL_FUNC_SUBTRACT_EXT: case GL_FUNC_REVERSE_SUBTRACT_EXT: ctx->Color.BlendEquation = mode; break; default: gl_error( ctx, GL_INVALID_ENUM, "glBlendEquation" ); return; } ctx->NewState |= NEW_RASTER_OPS; } void gl_BlendColor( GLcontext* ctx, GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha ) { ctx->Color.BlendColor[0] = CLAMP( red, 0.0, 1.0 ); ctx->Color.BlendColor[1] = CLAMP( green, 0.0, 1.0 ); ctx->Color.BlendColor[2] = CLAMP( blue, 0.0, 1.0 ); ctx->Color.BlendColor[3] = CLAMP( alpha, 0.0, 1.0 ); } /* * Do the real work of gl_blend_span() and gl_blend_pixels(). * Input: n - number of pixels * mask - the usual write mask * In/Out: red, green, blue, alpha - the incoming and modified pixels * Input: rdest, gdest, bdest, adest - the pixels from the dest color buffer */ static void 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[] ) { GLuint i; /* Common cases: */ if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT && ctx->Color.BlendSrc==GL_SRC_ALPHA && ctx->Color.BlendDst==GL_ONE_MINUS_SRC_ALPHA) { /* Alpha blending */ GLfloat ascale = 256.0f * ctx->Visual->InvAlphaScale; GLint rmax = (GLint) ctx->Visual->RedScale; GLint gmax = (GLint) ctx->Visual->GreenScale; GLint bmax = (GLint) ctx->Visual->BlueScale; GLint amax = (GLint) ctx->Visual->AlphaScale; for (i=0;i<n;i++) { if (mask[i]) { GLint r, g, b, a; GLint t = (GLint) ( alpha[i] * ascale ); /* t in [0,256] */ GLint s = 256 - t; r = (red[i] * t + rdest[i] * s) >> 8; g = (green[i] * t + gdest[i] * s) >> 8; b = (blue[i] * t + bdest[i] * s) >> 8; a = (alpha[i] * t + adest[i] * s) >> 8; red[i] = MIN2( r, rmax ); green[i] = MIN2( g, gmax ); blue[i] = MIN2( b, bmax ); alpha[i] = MIN2( a, amax ); } } } else if (ctx->Color.BlendEquation==GL_LOGIC_OP && ctx->Color.LogicOp==GL_XOR) { /* XOR drawing */ for (i=0;i<n;i++) { if (mask[i]) { red[i] ^= rdest[i]; green[i] ^= gdest[i]; blue[i] ^= bdest[i]; alpha[i] ^= adest[i]; } } } /* General cases: */ else if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT || ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT || ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) { GLfloat rmax = ctx->Visual->RedScale; GLfloat gmax = ctx->Visual->GreenScale; GLfloat bmax = ctx->Visual->BlueScale; GLfloat amax = ctx->Visual->AlphaScale; GLfloat rscale = 1.0f / rmax; GLfloat gscale = 1.0f / gmax; GLfloat bscale = 1.0f / bmax; GLfloat ascale = 1.0f / amax; for (i=0;i<n;i++) { if (mask[i]) { GLint Rs, Gs, Bs, As; /* Source colors */ GLint Rd, Gd, Bd, Ad; /* Dest colors */ GLfloat sR, sG, sB, sA; /* Source scaling */ GLfloat dR, dG, dB, dA; /* Dest scaling */ GLfloat r, g, b, a; /* Source Color */ Rs = red[i]; Gs = green[i]; Bs = blue[i]; As = alpha[i]; /* Frame buffer color */ Rd = rdest[i]; Gd = gdest[i]; Bd = bdest[i]; Ad = adest[i]; /* Source scaling */ switch (ctx->Color.BlendSrc) { case GL_ZERO: sR = sG = sB = sA = 0.0F; break; case GL_ONE: sR = sG = sB = sA = 1.0F; break; case GL_DST_COLOR: sR = (GLfloat) Rd * rscale; sG = (GLfloat) Gd * gscale; sB = (GLfloat) Bd * bscale; sA = (GLfloat) Ad * ascale; break; case GL_ONE_MINUS_DST_COLOR: sR = 1.0F - (GLfloat) Rd * rscale; sG = 1.0F - (GLfloat) Gd * gscale; sB = 1.0F - (GLfloat) Bd * bscale; sA = 1.0F - (GLfloat) Ad * ascale; break; case GL_SRC_ALPHA: sR = sG = sB = sA = (GLfloat) As * ascale; break; case GL_ONE_MINUS_SRC_ALPHA: sR = sG = sB = sA = (GLfloat) 1.0F - (GLfloat) As * ascale; break; case GL_DST_ALPHA: sR = sG = sB = sA =(GLfloat) Ad * ascale; break; case GL_ONE_MINUS_DST_ALPHA: sR = sG = sB = sA = 1.0F - (GLfloat) Ad * ascale; break; case GL_SRC_ALPHA_SATURATE: if (As < 1.0F - (GLfloat) Ad * ascale) { sR = sG = sB = (GLfloat) As * ascale; } else { sR = sG = sB = 1.0F - (GLfloat) Ad * ascale; } sA = 1.0; break; case GL_CONSTANT_COLOR: sR = ctx->Color.BlendColor[0]; sG = ctx->Color.BlendColor[1]; sB = ctx->Color.BlendColor[2]; sA = ctx->Color.BlendColor[3]; break; case GL_ONE_MINUS_CONSTANT_COLOR: sR = 1.0F - ctx->Color.BlendColor[0]; sG = 1.0F - ctx->Color.BlendColor[1]; sB = 1.0F - ctx->Color.BlendColor[2]; sA = 1.0F - ctx->Color.BlendColor[3]; break; case GL_CONSTANT_ALPHA: sR = sG = sB = sA = ctx->Color.BlendColor[3]; break; case GL_ONE_MINUS_CONSTANT_ALPHA: sR = sG = sB = sA = 1.0F - ctx->Color.BlendColor[3]; break; default: /* this should never happen */ abort(); } /* Dest scaling */ switch (ctx->Color.BlendDst) { case GL_ZERO: dR = dG = dB = dA = 0.0F; break; case GL_ONE: dR = dG = dB = dA = 1.0F; break; case GL_SRC_COLOR: dR = (GLfloat) Rs * rscale; dG = (GLfloat) Gs * gscale; dB = (GLfloat) Bs * bscale; dA = (GLfloat) As * ascale; break; case GL_ONE_MINUS_SRC_COLOR: dR = 1.0F - (GLfloat) Rs * rscale; dG = 1.0F - (GLfloat) Gs * gscale; dB = 1.0F - (GLfloat) Bs * bscale; dA = 1.0F - (GLfloat) As * ascale; break; case GL_SRC_ALPHA: dR = dG = dB = dA = (GLfloat) As * ascale; break; case GL_ONE_MINUS_SRC_ALPHA: dR = dG = dB = dA = (GLfloat) 1.0F - (GLfloat) As * ascale; break; case GL_DST_ALPHA: dR = dG = dB = dA = (GLfloat) Ad * ascale; break; case GL_ONE_MINUS_DST_ALPHA: dR = dG = dB = dA = 1.0F - (GLfloat) Ad * ascale; break; case GL_CONSTANT_COLOR: dR = ctx->Color.BlendColor[0]; dG = ctx->Color.BlendColor[1]; dB = ctx->Color.BlendColor[2]; dA = ctx->Color.BlendColor[3]; break; case GL_ONE_MINUS_CONSTANT_COLOR: dR = 1.0F - ctx->Color.BlendColor[0]; dG = 1.0F - ctx->Color.BlendColor[1]; dB = 1.0F - ctx->Color.BlendColor[2]; dA = 1.0F - ctx->Color.BlendColor[3]; break; case GL_CONSTANT_ALPHA: dR = dG = dB = dA = ctx->Color.BlendColor[3]; break; case GL_ONE_MINUS_CONSTANT_ALPHA: dR = dG = dB = dA = 1.0F - ctx->Color.BlendColor[3] * ascale; break; default: /* this should never happen */ abort(); } #ifdef DEBUG assert( sR>= 0.0 && sR<=1.0 ); assert( sG>= 0.0 && sG<=1.0 ); assert( sB>= 0.0 && sB<=1.0 ); assert( sA>= 0.0 && sA<=1.0 ); assert( dR>= 0.0 && dR<=1.0 ); assert( dG>= 0.0 && dG<=1.0 ); assert( dB>= 0.0 && dB<=1.0 ); assert( dA>= 0.0 && dA<=1.0 ); #endif /* compute blended color */ if (ctx->Color.BlendEquation==GL_FUNC_ADD_EXT) { r = Rs * sR + Rd * dR; g = Gs * sG + Gd * dG; b = Bs * sB + Bd * dB; a = As * sA + Ad * dA; } else if (ctx->Color.BlendEquation==GL_FUNC_SUBTRACT_EXT) { r = Rs * sR - Rd * dR; g = Gs * sG - Gd * dG; b = Bs * sB - Bd * dB; a = As * sA - Ad * dA; } else if (ctx->Color.BlendEquation==GL_FUNC_REVERSE_SUBTRACT_EXT) { r = Rd * dR - Rs * sR; g = Gd * dG - Gs * sG; b = Bd * dB - Bs * sB; a = Ad * dA - As * sA; } red[i] = (GLint) CLAMP( r, 0.0F, rmax ); green[i] = (GLint) CLAMP( g, 0.0F, gmax ); blue[i] = (GLint) CLAMP( b, 0.0F, bmax ); alpha[i] = (GLint) CLAMP( a, 0.0F, amax ); } } } else if (ctx->Color.BlendEquation==GL_LOGIC_OP) { /* EXTENSION */ switch (ctx->Color.LogicOp) { case GL_CLEAR: for (i=0;i<n;i++) { if (mask[i]) { red[i] = green[i] = blue[i] = alpha[i] = 0; } } break; case GL_SET: { GLubyte r = (GLint) ctx->Visual->RedScale; GLubyte g = (GLint) ctx->Visual->GreenScale; GLubyte b = (GLint) ctx->Visual->BlueScale; GLubyte a = (GLint) ctx->Visual->AlphaScale; for (i=0;i<n;i++) { if (mask[i]) { red[i] = r; green[i] = g; blue[i] = b; alpha[i] = a; } } } break; case GL_COPY: /* do nothing */ break; case GL_COPY_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !red[i]; green[i] = !green[i]; blue[i] = !blue[i]; alpha[i] = !alpha[i]; } } break; case GL_NOOP: for (i=0;i<n;i++) { if (mask[i]) { red[i] = rdest[i]; green[i] = gdest[i]; blue[i] = bdest[i]; alpha[i] = adest[i]; } } break; case GL_INVERT: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !rdest[i]; green[i] = !gdest[i]; blue[i] = !bdest[i]; alpha[i] = !adest[i]; } } break; case GL_AND: for (i=0;i<n;i++) { if (mask[i]) { red[i] &= rdest[i]; green[i] &= gdest[i]; blue[i] &= bdest[i]; alpha[i] &= adest[i]; } } break; case GL_NAND: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !(red[i] & rdest[i]); green[i] = !(green[i] & gdest[i]); blue[i] = !(blue[i] & bdest[i]); alpha[i] = !(alpha[i] & adest[i]); } } break; case GL_OR: for (i=0;i<n;i++) { if (mask[i]) { red[i] |= rdest[i]; green[i] |= gdest[i]; blue[i] |= bdest[i]; alpha[i] |= adest[i]; } } break; case GL_NOR: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !(red[i] | rdest[i]); green[i] = !(green[i] | gdest[i]); blue[i] = !(blue[i] | bdest[i]); alpha[i] = !(alpha[i] | adest[i]); } } break; case GL_XOR: for (i=0;i<n;i++) { if (mask[i]) { red[i] ^= rdest[i]; green[i] ^= gdest[i]; blue[i] ^= bdest[i]; alpha[i] ^= adest[i]; } } break; case GL_EQUIV: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !(red[i] ^ rdest[i]); green[i] = !(green[i] ^ gdest[i]); blue[i] = !(blue[i] ^ bdest[i]); alpha[i] = !(alpha[i] ^ adest[i]); } } break; case GL_AND_REVERSE: for (i=0;i<n;i++) { if (mask[i]) { red[i] = red[i] & !rdest[i]; green[i] = green[i] & !gdest[i]; blue[i] = blue[i] & !bdest[i]; alpha[i] = alpha[i] & !adest[i]; } } break; case GL_AND_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !red[i] & rdest[i]; green[i] = !green[i] & gdest[i]; blue[i] = !blue[i] & bdest[i]; alpha[i] = !alpha[i] & adest[i]; } } break; case GL_OR_REVERSE: for (i=0;i<n;i++) { if (mask[i]) { red[i] = red[i] | !rdest[i]; green[i] = green[i] | !gdest[i]; blue[i] = blue[i] | !bdest[i]; alpha[i] = alpha[i] | !adest[i]; } } break; case GL_OR_INVERTED: for (i=0;i<n;i++) { if (mask[i]) { red[i] = !red[i] | rdest[i]; green[i] = !green[i] | gdest[i]; blue[i] = !blue[i] | bdest[i]; alpha[i] = !alpha[i] | adest[i]; } } break; default: ; /* nothing */ } } else if (ctx->Color.BlendEquation==GL_MIN_EXT) { /* EXTENSION */ for (i=0;i<n;i++) { if (mask[i]) { red[i] = MIN2( red[i], rdest[i] ); green[i] = MIN2( green[i], gdest[i] ); blue[i] = MIN2( blue[i], bdest[i] ); alpha[i] = MIN2( alpha[i], adest[i] ); } } } else if (ctx->Color.BlendEquation==GL_MAX_EXT) { /* EXTENSION */ for (i=0;i<n;i++) { if (mask[i]) { red[i] = MAX2( red[i], rdest[i] ); green[i] = MAX2( green[i], gdest[i] ); blue[i] = MAX2( blue[i], bdest[i] ); alpha[i] = MAX2( alpha[i], adest[i] ); } } } } /* * Apply the blending operator to a span of pixels. * Input: n - number of pixels in span * x, y - location of leftmost pixel in span in window coords. * mask - boolean mask indicating which pixels to blend. * In/Out: red, green, blue, alpha - pixel values */ void gl_blend_span( GLcontext* ctx, GLuint n, GLint x, GLint y, GLubyte red[], GLubyte green[], GLubyte blue[], GLubyte alpha[], GLubyte mask[] ) { GLubyte rdest[MAX_WIDTH], gdest[MAX_WIDTH]; GLubyte bdest[MAX_WIDTH], adest[MAX_WIDTH]; /* Check if device driver can do the work */ if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) { return; } /* Read span of current frame buffer pixels */ gl_read_color_span( ctx, n, x, y, rdest, gdest, bdest, adest ); do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest ); } /* * Apply the blending operator to an array of pixels. * Input: n - number of pixels in span * x, y - array of pixel locations * mask - boolean mask indicating which pixels to blend. * In/Out: red, green, blue, alpha - array of pixel values */ void gl_blend_pixels( GLcontext* ctx, GLuint n, const GLint x[], const GLint y[], GLubyte red[], GLubyte green[], GLubyte blue[], GLubyte alpha[], GLubyte mask[] ) { GLubyte rdest[PB_SIZE], gdest[PB_SIZE], bdest[PB_SIZE], adest[PB_SIZE]; /* Check if device driver can do the work */ if (ctx->Color.BlendEquation==GL_LOGIC_OP && !ctx->Color.SWLogicOpEnabled) { return; } /* Read pixels from current color buffer */ (*ctx->Driver.ReadColorPixels)( ctx, n, x, y, rdest, gdest, bdest, adest, mask ); if (ctx->RasterMask & ALPHABUF_BIT) { gl_read_alpha_pixels( ctx, n, x, y, adest, mask ); } do_blend( ctx, n, mask, red, green, blue, alpha, rdest, gdest, bdest, adest ); }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.