diff options
Diffstat (limited to 'source/blender/render/intern/source/pixelblending.c')
-rw-r--r-- | source/blender/render/intern/source/pixelblending.c | 919 |
1 files changed, 919 insertions, 0 deletions
diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c new file mode 100644 index 00000000000..4fa3703d865 --- /dev/null +++ b/source/blender/render/intern/source/pixelblending.c @@ -0,0 +1,919 @@ +/* + * pixelblending.c + * + * Functions to blend pixels with or without alpha, in various formats + * nzc - June 2000 + * + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +#include <math.h> + +/* global includes */ +#include "render.h" +#include "render_intern.h" + +/* local includes */ +#include "vanillaRenderPipe_types.h" + +/* own includes */ +#include "pixelblending_types.h" +#include "pixelblending.h" +#include "gammaCorrectionTables.h" + +/* externals */ + +/* ------------------------------------------------------------------------- */ +/* Debug/behaviour defines */ +/* if defined: alpha blending with floats clips colour, as with shorts */ +/* #define RE_FLOAT_COLOUR_CLIPPING */ +/* if defined: alpha values are clipped */ +/* For now, we just keep alpha clipping. We run into thresholding and */ +/* blending difficulties otherwise. Be careful here. */ +#define RE_ALPHA_CLIPPING + +/* functions --------------------------------------------------------------- */ + +/* + One things about key-alpha is that simply dividing by the alpha will + sometimes cause 'overflows' in that the pixel colours will be shot + way over full colour. This should be caught, and subsequently, the + operation will end up modifying the alpha as well. + + Actually, when the starting colour is premul, it shouldn't overflow + ever. Strange thing is that colours keep overflowing... + +*/ +void applyKeyAlphaCharCol(char* target) { + + if ((!(target[3] == 0)) + || (target[3] == 255)) { + /* else: nothing to do */ + /* check whether div-ing is enough */ + float cf[4]; + cf[0] = target[0]/target[3]; + cf[1] = target[1]/target[3]; + cf[2] = target[2]/target[3]; + if ((cf[0] <= 1.0) && (cf[1] <= 1.0) && (cf[2] <= 1.0)) { + /* all colours remain properly scaled? */ + /* scale to alpha */ + cf[0] = (float) target[0] * (255.0/ (float)target[3]); + cf[1] = (float) target[1] * (255.0/ (float)target[3]); + cf[2] = (float) target[2] * (255.0/ (float)target[3]); + + /* Clipping is important. */ + target[0] = (cf[0] > 255.0 ? 255 : (char) cf[0]); + target[1] = (cf[1] > 255.0 ? 255 : (char) cf[1]); + target[2] = (cf[2] > 255.0 ? 255 : (char) cf[2]); + + } else { + /* shouldn't happen! we were premul, remember? */ +/* should go to error handler: printf("Non-premul colour detected\n"); */ + } + } + +} /* end of void applyKeyAlphaCharCol(char* target) */ + +/* ------------------------------------------------------------------------- */ + +void addAddSampColF(float *sampvec, float *source, int mask, int osaNr, + char addfac) +{ + int a; + + for(a=0; a < osaNr; a++) { + if(mask & (1<<a)) addalphaAddfacFloat(sampvec, source, addfac); + sampvec+= 4; + } +} /* end of void addAddSampColF(float, float, int, int) */ + +/* ------------------------------------------------------------------------- */ + +void addOverSampColF(float *sampvec, float *source, int mask, int osaNr) +{ + int a; + + for(a=0; a < osaNr; a++) { + if(mask & (1<<a)) addAlphaOverFloat(sampvec, source); + sampvec+= 4; + } +} /* end of void addOverSampColF(float, float, int, int) */ + +/* ------------------------------------------------------------------------- */ + +int addUnderSampColF(float *sampvec, float *source, int mask, int osaNr) +{ + int a, retval = osaNr; + + for(a=0; a < osaNr; a++) { + if(mask & (1<<a)) addAlphaUnderFloat(sampvec, source); + if(sampvec[3] > RE_FULL_COLOUR_FLOAT) retval--; + sampvec+= 4; + } + return retval; +} /* end of int addToSampColF(float, float, int, int) */ + +/* ------------------------------------------------------------------------- */ + +int addToSampCol(unsigned short *sampcol, unsigned short *shortcol, int mask, int osaNr) +{ + int a, retval = osaNr; + + for(a=0; a < osaNr; a++) { + if(mask & (1<<a)) addAlphaUnderShort(sampcol, shortcol); + if(sampcol[3]>0xFFF0) retval--; + sampcol+= 4; + } + return retval; +} /* end of int addToSampCol(unsigned short, uhost, int, int) */ + +/* ------------------------------------------------------------------------- */ + +int addtosampcol(unsigned short *sampcol, unsigned short *shortcol, int mask) +{ + int a, retval = R.osa; + + for(a=0; a < R.osa; a++) { + if(mask & (1<<a)) addAlphaUnderShort(sampcol, shortcol); + if(sampcol[3]>0xFFF0) retval--; + sampcol+= 4; + } + return retval; +} /* end of int addtosampcol(unsigned short *sampcol, unsigned short *shortcol, int mask) */ + +/* ------------------------------------------------------------------------- */ + +void addAlphaOverShort(unsigned short *doel, unsigned short *bron) /* vult bron over doel in met alpha van bron */ +{ + unsigned int c; + unsigned int mul; + + if( doel[3]==0 || bron[3]>=0xFFF0) { /* is getest, scheelt veel */ + *((unsigned int *)doel)= *((unsigned int *)bron); + *((unsigned int *)(doel+2))= *((unsigned int *)(bron+2)); + return; + } + + mul= 0xFFFF-bron[3]; + + c= ((mul*doel[0])>>16)+bron[0]; + if(c>=0xFFF0) doel[0]=0xFFF0; + else doel[0]= c; + c= ((mul*doel[1])>>16)+bron[1]; + if(c>=0xFFF0) doel[1]=0xFFF0; + else doel[1]= c; + c= ((mul*doel[2])>>16)+bron[2]; + if(c>=0xFFF0) doel[2]=0xFFF0; + else doel[2]= c; + c= ((mul*doel[3])>>16)+bron[3]; + if(c>=0xFFF0) doel[3]=0xFFF0; + else doel[3]= c; + +} /* end of void addAlphaOverShort(unsigned short *doel, unsigned short *bron) */ + +/* ------------------------------------------------------------------------- */ + +void addAlphaUnderShort(unsigned short *doel, unsigned short *bron) /* vult bron onder doel in met alpha van doel */ +{ + unsigned int c; + unsigned int mul; + + if(doel[3]>=0xFFF0) return; + if( doel[3]==0 ) { /* is getest, scheelt veel */ + *((unsigned int *)doel)= *((unsigned int *)bron); + *((unsigned int *)(doel+2))= *((unsigned int *)(bron+2)); + return; + } + + mul= 0xFFFF-doel[3]; + + c= ((mul*bron[0])>>16)+doel[0]; + if(c>=0xFFF0) doel[0]=0xFFF0; + else doel[0]= c; + c= ((mul*bron[1])>>16)+doel[1]; + if(c>=0xFFF0) doel[1]=0xFFF0; + else doel[1]= c; + c= ((mul*bron[2])>>16)+doel[2]; + if(c>=0xFFF0) doel[2]=0xFFF0; + else doel[2]= c; + c= ((mul*bron[3])>>16)+doel[3]; + if(c>=0xFFF0) doel[3]=0xFFF0; + else doel[3]= c; + +} /* end of void addAlphaUnderShort(unsigned short *doel, unsigned short *bron) */ + +/* ------------------------------------------------------------------------- */ + +void addAlphaOverFloat(float *dest, float *source) +{ + /* d = s + (1-alpha_s)d*/ + float c; + float mul; + + /* I may want to disable this clipping */ +#ifdef RE_FLOAT_COLOUR_CLIPPING + if( /* (-RE_FULL_COLOUR_FLOAT < source[3]) */ +/* && */ (source[3] > RE_FULL_COLOUR_FLOAT) ) { /* is getest, scheelt veel */ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } +#endif + + mul= 1.0 - source[3]; + + c= (mul*dest[0]) + source[0]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[0] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[0]= c; + + c= (mul*dest[1]) + source[1]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[1] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[1]= c; + + c= (mul*dest[2]) + source[2]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[2] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[2]= c; + + c= (mul*dest[3]) + source[3]; +#ifdef RE_ALPHA_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[3] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[3]= c; + +} /* end of void addAlphaOverFloat(float *doel, float *bron) */ + + + +/* ------------------------------------------------------------------------- */ + +void addAlphaUnderFloat(float *dest, float *source) +{ + float c; + float mul; + + /* I may want to disable this clipping */ +#ifdef RE_FLOAT_COLOUR_CLIPPING + if( dest[3] >= RE_FULL_COLOUR_FLOAT) return; +#endif + if( (-RE_EMPTY_COLOUR_FLOAT < dest[3]) + && (dest[3] < RE_EMPTY_COLOUR_FLOAT) ) { /* is getest, scheelt veel */ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } + + mul= 1.0 - dest[3]; + + c= (mul*source[0]) + dest[0]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[0] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[0]= c; + + c= (mul*source[1]) + dest[1]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[1] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[1]= c; + + c= (mul*source[2]) + dest[2]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[2] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[2]= c; + + c= (mul*source[3]) + dest[3]; +#ifdef RE_ALPHA_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[3] = RE_UNITY_COLOUR_FLOAT; + else +#endif + dest[3]= c; + +} /* end of void addAlphaUnderFloat(float *doel, float *bron) */ + +/* ------------------------------------------------------------------------- */ + +void cpShortColV2CharColV(unsigned short *source, char *dest) +{ + dest[0] = source[0]>>8; + dest[1] = source[1]>>8; + dest[2] = source[2]>>8; + dest[3] = source[3]>>8; +} /* end of void cpShortColV2CharColV(unsigned short *source, char *dest) */ +/* ------------------------------------------------------------------------- */ + +void cpCharColV2ShortColV(char *source, unsigned short *dest) +{ + dest[0] = source[0]<<8; + dest[1] = source[1]<<8; + dest[2] = source[2]<<8; + dest[3] = source[3]<<8; +} /* end of void cpShortColV2CharColV(char *source, unsigned short *dest) */ + +/* ------------------------------------------------------------------------- */ + +void cpIntColV2CharColV(unsigned int *source, char *dest) +{ + dest[0] = source[0]>>24; + dest[1] = source[1]>>24; + dest[2] = source[2]>>24; + dest[3] = source[3]>>24; +} /* end of void cpIntColV2CharColV(unsigned int *source, char *dest) */ + +/* ------------------------------------------------------------------------- */ + +void cpCharColV2FloatColV(char *source, float *dest) +{ + /* What about endianness? Might be caught at this level :) */ + dest[0] = source[0]/255.0; + dest[1] = source[1]/255.0; + dest[2] = source[2]/255.0; + dest[3] = source[3]/255.0; +} /* end of void cpCharColV2FloatColV(char *source, float *dest) */ +/* ------------------------------------------------------------------------- */ + +void cpShortColV2FloatColV(unsigned short *source, float *dest) +{ + dest[0] = source[0]/65535.0; + dest[1] = source[1]/65535.0; + dest[2] = source[2]/65535.0; + dest[3] = source[3]/65535.0; +} /* end of void cpShortColV2FloatColV(char *source, float *dest) */ + +/* ------------------------------------------------------------------------- */ + +void cpFloatColV2CharColV(float* source, char *dest) +{ + /* can't this be done more efficient? hope the conversions are correct... */ + if (source[0] < 0.0) dest[0] = 0; + else if (source[0] > 1.0) dest[0] = 255; + else dest[0] = (char) (source[0] * 255.0); + + if (source[1] < 0.0) dest[1] = 0; + else if (source[1] > 1.0) dest[1] = 255; + else dest[1] = (char) (source[1] * 255.0); + + if (source[2] < 0.0) dest[2] = 0; + else if (source[2] > 1.0) dest[2] = 255; + else dest[2] = (char) (source[2] * 255.0); + + if (source[3] < 0.0) dest[3] = 0; + else if (source[3] > 1.0) dest[3] = 255; + else dest[3] = (char) (source[3] * 255.0); + +} /* end of void cpFloatColV2CharColV(float* source, char *dest) */ + +/* ------------------------------------------------------------------------- */ + +void cpShortColV(unsigned short *source, unsigned short *dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; +} /* end of void cpShortColV(unsigned short *source, unsigned short *dest) */ + +/* ------------------------------------------------------------------------- */ +void cpFloatColV(float *source, float *dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; +} /* end of void cpFloatColV(float *source, float *dest) */ + +/* ------------------------------------------------------------------------- */ + +void cpCharColV(char *source, char *dest) +{ + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; +} /* end of void cpCharColV(char *source, char *dest) */ + +/* ------------------------------------------------------------------------- */ +void addalphaAddfacFloat(float *dest, float *source, char addfac) + /* doel= bron over doel */ +{ + float m; /* weiging factor of destination */ + float c; /* intermediate colour */ + + /* 1. copy source straight away if dest has zero alpha */ + /* 2. copy dest straight away if dest has full alpha */ + /* I am not sure whether (2) is correct. It seems to */ + /* me that this should not happen if float colours */ + /* aren't clipped at 1.0 . */ + /* I'll keep the code, but disabled.... */ + if ( (dest[3] < RE_EMPTY_COLOUR_FLOAT) + /* || source[3] > RE_FULL_COLOUR_FLOAT */ ) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } + + /* Addfac is a number between 0 and 1: rescale */ + /* final target is to diminish the influence of dest when addfac rises */ + m = 1.0 - ( source[3] * ((255.0 - addfac) / 255.0)); + + /* blend colours*/ + c= (m * dest[0]) + source[0]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[0] = RE_FULL_COLOUR_FLOAT; + else +#endif + dest[0]= c; + + c= (m * dest[1]) + source[1]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[1] = RE_FULL_COLOUR_FLOAT; + else +#endif + dest[1]= c; + + c= (m * dest[2]) + source[2]; +#ifdef RE_FLOAT_COLOUR_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[2] = RE_FULL_COLOUR_FLOAT; + else +#endif + dest[2]= c; + + c= dest[3] + source[3]; +#ifdef RE_ALPHA_CLIPPING + if(c >= RE_FULL_COLOUR_FLOAT) dest[3] = RE_FULL_COLOUR_FLOAT; + else +#endif + dest[3]= c; + +} /* end of void addalphaAddfacFloat(unsigned short *doel, unsigned short *bron, char addfac_help) */ + +/* ------------------------------------------------------------------------- */ + +void addalphaAddfacShort(unsigned short *doel, unsigned short *bron, char addfac) + /* doel= bron over doel */ +{ + float m; /* weiging factor of destination */ + float c; /* intermediate colour */ + + /* 1. copy bron straight away if doel has zero alpha */ + if( doel[3] == 0) { + *((unsigned int *)doel) = *((unsigned int *)bron); + *((unsigned int *)(doel+2)) = *((unsigned int *)(bron+2)); + return; + } + + /* Addfac is a number between 0 and 1: rescale */ + /* final target is to diminish the influence of dest when addfac rises */ + m = 1.0 - ( bron[3] * ((255.0 - addfac) / 255.0)); + + /* blend colours*/ + c = (m * doel[0]) + bron[0]; + if( c > 65535.0 ) doel[0]=65535; + else doel[0] = floor(c); + c = (m * doel[1]) + bron[1]; + if( c > 65535.0 ) doel[1]=65535; + else doel[1] = floor(c); + c = (m * doel[2]) + bron[2]; + if( c > 65535.0 ) doel[2]=65535; + else doel[2] = floor(c); + + c = doel[3] + bron[3]; + if(c > 65535.0) doel[3] = 65535; + else doel[3]= floor(c); + +} /* end of void addalphaAddfacShort(unsigned short *doel, unsigned short *bron, char addfac_help) */ + +/* ------------------------------------------------------------------------- */ + +void addHaloToHaloShort(unsigned short *d, unsigned short *s) +{ + /* float m; */ /* weiging factor of destination */ + float c[4]; /* intermediate colour */ + float rescale = 1.0; + + /* 1. copy <s> straight away if <d> has zero alpha */ + if( d[3] == 0) { + *((unsigned int *) d) = *((unsigned int *) s); + *((unsigned int *)(d + 2)) = *((unsigned int *)(s + 2)); + return; + } + + /* 2. halo blending */ + /* no blending, just add */ + c[0] = s[0] + d[0]; + c[1] = s[1] + d[1]; + c[2] = s[2] + d[2]; + c[3] = s[3] + d[3]; + /* One thing that may happen is that this pixel is over-saturated with light - */ + /* i.e. too much light comes out, and the pixel is clipped. Currently, this */ + /* leads to artifacts such as overproportional undersampling of background */ + /* colours. */ + /* Compensating for over-saturation: */ + /* - increase alpha */ + /* - increase alpha and rescale colours */ + + /* let's try alpha increase and clipping */ + + /* calculate how much rescaling we need */ + if( c[0] > 65535.0 ) { + rescale *= c[0] /65535.0; + d[0] = 65535; + } else d[0] = floor(c[0]); + if( c[1] > 65535.0 ) { + rescale *= c[1] /65535.0; + d[1] = 65535; + } else d[1] = floor(c[1]); + if( c[2] > 65535.0 ) { + rescale *= c[2] /65535.0; + d[2] = 65535; + } else d[2] = floor(c[2]); + + /* a bit too hefty I think */ + c[3] *= rescale; + + if( c[3] > 65535.0 ) d[3] = 65535; else d[3]= floor(c[3]); + +} /* end of void addHaloToHaloShort(unsigned short *dest, unsigned short *source, char addfac) */ + +/* ------------------------------------------------------------------------- */ + +void sampleShortColV2ShortColV(unsigned short *sample, unsigned short *dest, int osaNr) +{ + unsigned int intcol[4] = {0}; + unsigned short *scol = sample; + int a = 0; + + for(a=0; a < osaNr; a++, scol+=4) { + intcol[0]+= scol[0]; intcol[1]+= scol[1]; + intcol[2]+= scol[2]; intcol[3]+= scol[3]; + } + + /* Now normalise the integrated colour. It is guaranteed */ + /* to be correctly bounded. */ + dest[0]= intcol[0]/osaNr; + dest[1]= intcol[1]/osaNr; + dest[2]= intcol[2]/osaNr; + dest[3]= intcol[3]/osaNr; + +} /* end of void sampleShortColVToShortColV(unsigned short *sample, unsigned short *dest) */ + + +/* ------------------------------------------------------------------------- */ + +void sampleFloatColV2FloatColV(float *sample, float *dest, int osaNr) +{ + float intcol[4] = {0}; + float *scol = sample; + int a = 0; + + if (doGamma()) { + /* use a LUT and interpolation to do the gamma correction */ + for(a=0; a < osaNr; a++, scol+=4) { + intcol[0] += gammaCorrect(scol[0]); + intcol[1] += gammaCorrect(scol[1]); + intcol[2] += gammaCorrect(scol[2]); + intcol[3] += scol[3]; + } + + /* renormalise */ + intcol[0] /= osaNr; + intcol[1] /= osaNr; + intcol[2] /= osaNr; + intcol[3] /= osaNr; + + /* back to pixel values */ + dest[0] = invGammaCorrect(intcol[0]); + dest[1] = invGammaCorrect(intcol[1]); + dest[2] = invGammaCorrect(intcol[2]); + dest[3] = intcol[3]; + } else { + /* no gamma */ + for(a=0; a < osaNr; a++, scol+=4) { + intcol[0] += scol[0]; intcol[1] += scol[1]; + intcol[2] += scol[2]; intcol[3] += scol[3]; + } + + dest[0]= intcol[0]/osaNr; + dest[1]= intcol[1]/osaNr; + dest[2]= intcol[2]/osaNr; + dest[3]= intcol[3]/osaNr; + } + +} /* end void sampleFloatColVToFloatColV(unsigned short *, unsigned short *) */ + +/* ------------------------------------------------------------------------- */ +/* The following functions are 'old' blending functions: */ + +/* ------------------------------------------------------------------------- */ +void keyalpha(char *doel) /* maakt premul 255 */ +{ + int c; + short div; + div= doel[3]; + if (!div) + { + doel[0] = (doel[0] ? 255 : 0); + doel[1] = (doel[1] ? 255 : 0); + doel[2] = (doel[2] ? 255 : 0); + } else + { + c= (doel[0]<<8)/div; + if(c>255) doel[0]=255; + else doel[0]= c; + c= (doel[1]<<8)/div; + if(c>255) doel[1]=255; + else doel[1]= c; + c= (doel[2]<<8)/div; + if(c>255) doel[2]=255; + else doel[2]= c; + } +} + +/* ------------------------------------------------------------------------- */ +/* vult bron onder doel in met alpha van doel*/ +void addalphaUnder(char *doel, char *bron) +{ + int c; + int mul; + + if(doel[3]==255) return; + if( doel[3]==0) { /* is getest, scheelt */ + *((unsigned int *)doel)= *((unsigned int *)bron); + return; + } + + mul= 255-doel[3]; + + c= doel[0]+ ((mul*bron[0])/255); + if(c>255) doel[0]=255; + else doel[0]= c; + c= doel[1]+ ((mul*bron[1])/255); + if(c>255) doel[1]=255; + else doel[1]= c; + c= doel[2]+ ((mul*bron[2])/255); + if(c>255) doel[2]=255; + else doel[2]= c; + + c= doel[3]+ ((mul*bron[3])/255); + if(c>255) doel[3]=255; + else doel[3]= c; + + /* doel[0]= MAX2(doel[0], bron[0]); */ +} + +/* ------------------------------------------------------------------------- */ +/* gamma-gecorr: vult bron onder doel in met alpha van doel */ +void addalphaUnderGamma(char *doel, char *bron) +{ + unsigned int tot; + int c, doe, bro; + int mul; + + /* hier doel[3]==0 of doel==255 afvangen gebeurt al in skylus */ + mul= 256-doel[3]; + + doe= igamtab1[(int)doel[0]]; + bro= igamtab1[(int)bron[0]]; + tot= (doe+ ((mul*bro)>>8)); + if(tot>65535) tot=65535; + doel[0]= *((gamtab+tot)) >>8; + + doe= igamtab1[(int)doel[1]]; + bro= igamtab1[(int)bron[1]]; + tot= (doe+ ((mul*bro)>>8)); + if(tot>65535) tot=65535; + doel[1]= *((gamtab+tot)) >>8; + + doe= igamtab1[(int)doel[2]]; + bro= igamtab1[(int)bron[2]]; + tot= (doe+ ((mul*bro)>>8)); + if(tot>65535) tot=65535; + doel[2]= *((gamtab+tot)) >>8; + + c= doel[3]+ ((mul*bron[3])/255); + if(c>255) doel[3]=255; + else doel[3]= c; + /* doel[0]= MAX2(doel[0], bron[0]); */ +} + +/* ------------------------------------------------------------------------- */ +/* doel= bron over doel */ +void addalphaOver(char *doel, char *bron) +{ + int c; + int mul; + + if(bron[3]==0) return; + if( bron[3]==255) { /* is getest, scheelt */ + *((unsigned int *)doel)= *((unsigned int *)bron); + return; + } + + mul= 255-bron[3]; + + c= ((mul*doel[0])/255)+bron[0]; + if(c>255) doel[0]=255; + else doel[0]= c; + c= ((mul*doel[1])/255)+bron[1]; + if(c>255) doel[1]=255; + else doel[1]= c; + c= ((mul*doel[2])/255)+bron[2]; + if(c>255) doel[2]=255; + else doel[2]= c; + c= ((mul*doel[3])/255)+bron[3]; + if(c>255) doel[3]=255; + else doel[3]= c; +} + +/* ------------------------------------------------------------------------- */ +void addalphaAdd(char *doel, char *bron) /* telt bron bij doel */ +{ + int c; + + if( doel[3]==0 || bron[3]==255) { /* is getest, scheelt veel */ + *((unsigned int *)doel)= *((unsigned int *)bron); + return; + } + c= doel[0]+bron[0]; + if(c>255) doel[0]=255; + else doel[0]= c; + c= doel[1]+bron[1]; + if(c>255) doel[1]=255; + else doel[1]= c; + c= doel[2]+bron[2]; + if(c>255) doel[2]=255; + else doel[2]= c; + c= doel[3]+bron[3]; + if(c>255) doel[3]=255; + else doel[3]= c; +} +/* ------------------------------------------------------------------------- */ +void addalphaAddshort(unsigned short *doel, unsigned short *bron) /* telt bron bij doel */ +{ + int c; + + if( doel[3]==0) { + *((unsigned int *)doel)= *((unsigned int *)bron); + *((unsigned int *)(doel+2))= *((unsigned int *)(bron+2)); + return; + } + c= doel[0]+bron[0]; + if(c>65535) doel[0]=65535; + else doel[0]= c; + c= doel[1]+bron[1]; + if(c>65535) doel[1]=65535; + else doel[1]= c; + c= doel[2]+bron[2]; + if(c>65535) doel[2]=65535; + else doel[2]= c; + c= doel[3]+bron[3]; + if(c>65535) doel[3]=65535; + else doel[3]= c; +} + +/* ------------------------------------------------------------------------- */ +void addalphaAddFloat(float *dest, float *source) +{ + + /* Makes me wonder whether this is required... */ + if( dest[3] < RE_EMPTY_COLOUR_FLOAT) { + dest[0] = source[0]; + dest[1] = source[1]; + dest[2] = source[2]; + dest[3] = source[3]; + return; + } + + /* no clipping! */ + dest[0] = dest[0]+source[0]; + dest[1] = dest[1]+source[1]; + dest[2] = dest[2]+source[2]; + dest[3] = dest[3]+source[3]; + +} + +/* ALPHADDFAC: + * + * Z= X alphaover Y: + * Zrgb= (1-Xa)*Yrgb + Xrgb + * + * Om ook de add te doen moet (1-Xa) moduleren met 1 via fac + * (1-fac)*(1-Xa) + fac <=> + * 1-Xa-fac+fac*Xa+fac <=> + * Xa*(fac-1)+1 + */ + + +/* ------------------------------------------------------------------------- */ +/* doel= bron over doel */ +void RE_addalphaAddfac(char *doel, char *bron, char addfac) +{ + + int c, mul; + + if( doel[3]==0) { + *((unsigned int *)doel)= *((unsigned int *)bron); + return; + } + + mul= 255 - (bron[3]*(255-addfac))/255; + + c= ((mul*doel[0])/255)+bron[0]; + if(c>255) doel[0]=255; + else doel[0]= c; + c= ((mul*doel[1])/255)+bron[1]; + if(c>255) doel[1]=255; + else doel[1]= c; + c= ((mul*doel[2])/255)+bron[2]; + if(c>255) doel[2]=255; + else doel[2]= c; + + /* c= ((mul*doel[3])/255)+bron[3]; */ + c= doel[3]+bron[3]; + if(c>255) doel[3]=255; + else doel[3]= c; +} + +/* ------------------------------------------------------------------------- */ +/* doel= bron over doel */ +void addalphaAddfacshort(unsigned short *doel, + unsigned short *bron, + short addfac) +{ + int c, mul; + + if( doel[3]==0) { + *((unsigned int *)doel)= *((unsigned int *)bron); + *((unsigned int *)(doel+2))= *((unsigned int *)(bron+2)); + return; + } + + mul= 0xFFFF - (bron[0]*(255-addfac))/255; + + c= ((mul*doel[0])>>16)+bron[0]; + if(c>=0xFFF0) doel[0]=0xFFF0; + else doel[0]= c; + c= ((mul*doel[1])>>16)+bron[1]; + if(c>=0xFFF0) doel[1]=0xFFF0; + else doel[1]= c; + c= ((mul*doel[2])>>16)+bron[2]; + if(c>=0xFFF0) doel[2]=0xFFF0; + else doel[2]= c; + c= ((mul*doel[3])>>16)+bron[3]; + if(c>=0xFFF0) doel[3]=0xFFF0; + else doel[3]= c; + +} + +/* ------------------------------------------------------------------------- */ + +/* eof pixelblending.c */ + + |