Blender  V2.59
pixelblending.c
Go to the documentation of this file.
00001 /*
00002  * pixelblending.c
00003  *
00004  * Functions to blend pixels with or without alpha, in various formats
00005  * nzc - June 2000
00006  *
00007  * $Id: pixelblending.c 36276 2011-04-21 15:53:30Z campbellbarton $
00008  *
00009  * ***** BEGIN GPL LICENSE BLOCK *****
00010  *
00011  * This program is free software; you can redistribute it and/or
00012  * modify it under the terms of the GNU General Public License
00013  * as published by the Free Software Foundation; either version 2
00014  * of the License, or (at your option) any later version.
00015  *
00016  * This program is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License
00022  * along with this program; if not, write to the Free Software Foundation,
00023  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00024  *
00025  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00026  * All rights reserved.
00027  *
00028  * Contributor(s): Full recode, 2004-2006 Blender Foundation
00029  *
00030  * ***** END GPL LICENSE BLOCK *****
00031  */
00032 
00038 #include <math.h>
00039 #include <string.h>
00040 
00041 /* global includes */
00042 #include "BLI_math.h"
00043 #include "BLI_rand.h"
00044 
00045 /* own includes */
00046 #include "render_types.h"
00047 #include "renderpipeline.h"
00048 #include "pixelblending.h"
00049 #include "gammaCorrectionTables.h"
00050 
00051 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00052 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
00053 /* only to be used here in this file, it's for speed */
00054 extern struct Render R;
00055 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
00056 
00057 
00058 /* ------------------------------------------------------------------------- */
00059 /* Debug/behaviour defines                                                   */
00060 /* if defined: alpha blending with floats clips color, as with shorts       */
00061 /* #define RE_FLOAT_COLOR_CLIPPING  */
00062 /* if defined: alpha values are clipped                                      */
00063 /* For now, we just keep alpha clipping. We run into thresholding and        */
00064 /* blending difficulties otherwise. Be careful here.                         */
00065 #define RE_ALPHA_CLIPPING
00066 
00067 
00068 
00069 /* Threshold for a 'full' pixel: pixels with alpha above this level are      */
00070 /* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF           */
00071 #define RE_FULL_COLOR_FLOAT 0.9998
00072 /* Threshold for an 'empty' pixel: pixels with alpha above this level are    */
00073 /* considered completely transparent. This is the decimal value              */
00074 /* for 0x000F / 0xFFFF                                                       */
00075 #define RE_EMPTY_COLOR_FLOAT 0.0002
00076 
00077 
00078 /* ------------------------------------------------------------------------- */
00079 
00080 void addAlphaOverFloat(float *dest, float *source)
00081 {
00082         /* d = s + (1-alpha_s)d*/
00083         float mul;
00084 
00085         mul= 1.0 - source[3];
00086 
00087         dest[0]= (mul*dest[0]) + source[0];
00088         dest[1]= (mul*dest[1]) + source[1];
00089         dest[2]= (mul*dest[2]) + source[2];
00090         dest[3]= (mul*dest[3]) + source[3];
00091 
00092 }
00093 
00094 
00095 /* ------------------------------------------------------------------------- */
00096 
00097 void addAlphaUnderFloat(float *dest, float *source)
00098 {
00099         float mul;
00100 
00101         mul= 1.0 - dest[3];
00102 
00103         dest[0]+= (mul*source[0]);
00104         dest[1]+= (mul*source[1]);
00105         dest[2]+= (mul*source[2]);
00106         dest[3]+= (mul*source[3]);
00107 } 
00108 
00109 
00110 /* ------------------------------------------------------------------------- */
00111 void addalphaAddfacFloat(float *dest, float *source, char addfac)
00112 {
00113         float m; /* weiging factor of destination */
00114         float c; /* intermediate color           */
00115 
00116         /* Addfac is a number between 0 and 1: rescale */
00117         /* final target is to diminish the influence of dest when addfac rises */
00118         m = 1.0 - ( source[3] * ((255.0 - addfac) / 255.0));
00119 
00120         /* blend colors*/
00121         c= (m * dest[0]) + source[0];
00122 #ifdef RE_FLOAT_COLOR_CLIPPING
00123         if(c >= RE_FULL_COLOR_FLOAT) dest[0] = RE_FULL_COLOR_FLOAT; 
00124         else 
00125 #endif
00126                 dest[0]= c;
00127    
00128         c= (m * dest[1]) + source[1];
00129 #ifdef RE_FLOAT_COLOR_CLIPPING
00130         if(c >= RE_FULL_COLOR_FLOAT) dest[1] = RE_FULL_COLOR_FLOAT; 
00131         else 
00132 #endif
00133                 dest[1]= c;
00134 
00135         c= (m * dest[2]) + source[2];
00136 #ifdef RE_FLOAT_COLOR_CLIPPING
00137         if(c >= RE_FULL_COLOR_FLOAT) dest[2] = RE_FULL_COLOR_FLOAT; 
00138         else 
00139 #endif
00140                 dest[2]= c;
00141 
00142         c= (m * dest[3]) + source[3];
00143 #ifdef RE_ALPHA_CLIPPING
00144         if(c >= RE_FULL_COLOR_FLOAT) dest[3] = RE_FULL_COLOR_FLOAT; 
00145         else 
00146 #endif
00147         dest[3]= c;
00148 
00149 }
00150 
00151 
00152 /* ------------------------------------------------------------------------- */
00153 
00154 /* filtered adding to scanlines */
00155 void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w)
00156 {
00157         /* calc the value of mask */
00158         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
00159         float *rb1, *rb2, *rb3;
00160         float val, r, g, b, al;
00161         unsigned int a, maskand, maskshift;
00162         int j;
00163         
00164         r= col[0];
00165         g= col[1];
00166         b= col[2];
00167         al= col[3];
00168         
00169         rb2= rowbuf-4;
00170         rb3= rb2-4*row_w;
00171         rb1= rb2+4*row_w;
00172         
00173         maskand= (mask & 255);
00174         maskshift= (mask >>8);
00175         
00176         for(j=2; j>=0; j--) {
00177                 
00178                 a= j;
00179                 
00180                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00181                 if(val!=0.0) {
00182                         rb1[0]+= val*r;
00183                         rb1[1]+= val*g;
00184                         rb1[2]+= val*b;
00185                         rb1[3]+= val*al;
00186                 }
00187                 a+=3;
00188                 
00189                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00190                 if(val!=0.0) {
00191                         rb2[0]+= val*r;
00192                         rb2[1]+= val*g;
00193                         rb2[2]+= val*b;
00194                         rb2[3]+= val*al;
00195                 }
00196                 a+=3;
00197                 
00198                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00199                 if(val!=0.0) {
00200                         rb3[0]+= val*r;
00201                         rb3[1]+= val*g;
00202                         rb3[2]+= val*b;
00203                         rb3[3]+= val*al;
00204                 }
00205                 
00206                 rb1+= 4;
00207                 rb2+= 4;
00208                 rb3+= 4;
00209         }
00210 }
00211 
00212 
00213 void mask_array(unsigned int mask, float filt[][3])
00214 {
00215         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
00216         unsigned int maskand= (mask & 255);
00217         unsigned int maskshift= (mask >>8);
00218         int a, j;
00219         
00220         for(j=2; j>=0; j--) {
00221                 
00222                 a= j;
00223                 
00224                 filt[2][2-j]= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00225 
00226                 a+=3;
00227                 
00228                 filt[1][2-j]= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00229                 
00230                 a+=3;
00231                 
00232                 filt[0][2-j]= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00233         }
00234 }
00235 
00236 
00237 /* 
00238 
00239 index ordering, scanline based:
00240 
00241  ---    ---   ---  
00242 | 2,0 | 2,1 | 2,2 |
00243  ---    ---   ---  
00244 | 1,0 | 1,1 | 1,2 |
00245  ---    ---   ---  
00246 | 0,0 | 0,1 | 0,2 |
00247  ---    ---   ---  
00248 */
00249 
00250 void add_filt_fmask_coord(float filt[][3], float *col, float *rowbuf, int row_w, int col_h, int x, int y)
00251 {
00252         float *fpoin[3][3];
00253         float val, r, g, b, al, lfilt[3][3];
00254         
00255         r= col[0];
00256         g= col[1];
00257         b= col[2];
00258         al= col[3];
00259         
00260         memcpy(lfilt, filt, sizeof(lfilt));
00261         
00262         fpoin[0][1]= rowbuf-4*row_w;
00263         fpoin[1][1]= rowbuf;
00264         fpoin[2][1]= rowbuf+4*row_w;
00265         
00266         fpoin[0][0]= fpoin[0][1] - 4;
00267         fpoin[1][0]= fpoin[1][1] - 4;
00268         fpoin[2][0]= fpoin[2][1] - 4;
00269         
00270         fpoin[0][2]= fpoin[0][1] + 4;
00271         fpoin[1][2]= fpoin[1][1] + 4;
00272         fpoin[2][2]= fpoin[2][1] + 4;
00273         
00274         if(y==0) {
00275                 fpoin[0][0]= fpoin[1][0];
00276                 fpoin[0][1]= fpoin[1][1];
00277                 fpoin[0][2]= fpoin[1][2];
00278                 /* filter needs the opposite value yes! */
00279                 lfilt[0][0]= filt[2][0];
00280                 lfilt[0][1]= filt[2][1];
00281                 lfilt[0][2]= filt[2][2];
00282         }
00283         else if(y==col_h-1) {
00284                 fpoin[2][0]= fpoin[1][0];
00285                 fpoin[2][1]= fpoin[1][1];
00286                 fpoin[2][2]= fpoin[1][2];
00287                 
00288                 lfilt[2][0]= filt[0][0];
00289                 lfilt[2][1]= filt[0][1];
00290                 lfilt[2][2]= filt[0][2];
00291         }
00292         
00293         if(x==0) {
00294                 fpoin[2][0]= fpoin[2][1];
00295                 fpoin[1][0]= fpoin[1][1];
00296                 fpoin[0][0]= fpoin[0][1];
00297                 
00298                 lfilt[2][0]= filt[2][2];
00299                 lfilt[1][0]= filt[1][2];
00300                 lfilt[0][0]= filt[0][2];
00301         }
00302         else if(x==row_w-1) {
00303                 fpoin[2][2]= fpoin[2][1];
00304                 fpoin[1][2]= fpoin[1][1];
00305                 fpoin[0][2]= fpoin[0][1];
00306                 
00307                 lfilt[2][2]= filt[2][0];
00308                 lfilt[1][2]= filt[1][0];
00309                 lfilt[0][2]= filt[0][0];
00310         }
00311         
00312         
00313         /* loop unroll */
00314 #define MASKFILT(i, j)  val= lfilt[i][j]; if(val!=0.0f) {float *fp= fpoin[i][j]; fp[0]+= val*r; fp[1]+= val*g; fp[2]+= val*b; fp[3]+= val*al; }
00315         
00316         MASKFILT(0, 0)
00317         MASKFILT(0, 1)
00318         MASKFILT(0, 2)
00319         MASKFILT(1, 0)
00320         MASKFILT(1, 1)
00321         MASKFILT(1, 2)
00322         MASKFILT(2, 0)
00323         MASKFILT(2, 1)
00324         MASKFILT(2, 2)
00325 }
00326 
00327 void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize)
00328 {
00329         /* calc the value of mask */
00330         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
00331         float *rb1, *rb2, *rb3;
00332         float val;
00333         unsigned int a, maskand, maskshift;
00334         int i, j;
00335         
00336         rb2= rowbuf-pixsize;
00337         rb3= rb2-pixsize*row_w;
00338         rb1= rb2+pixsize*row_w;
00339         
00340         maskand= (mask & 255);
00341         maskshift= (mask >>8);
00342         
00343         for(j=2; j>=0; j--) {
00344                 
00345                 a= j;
00346                 
00347                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00348                 if(val!=0.0) {
00349                         for(i= 0; i<pixsize; i++)
00350                                 rb1[i]+= val*in[i];
00351                 }
00352                 a+=3;
00353                 
00354                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00355                 if(val!=0.0) {
00356                         for(i= 0; i<pixsize; i++)
00357                                 rb2[i]+= val*in[i];
00358                 }
00359                 a+=3;
00360                 
00361                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
00362                 if(val!=0.0) {
00363                         for(i= 0; i<pixsize; i++)
00364                                 rb3[i]+= val*in[i];
00365                 }
00366                 
00367                 rb1+= pixsize;
00368                 rb2+= pixsize;
00369                 rb3+= pixsize;
00370         }
00371 }
00372 
00373 /* ------------------------------------------------------------------------- */
00374 void addalphaAddFloat(float *dest, float *source)
00375 {
00376 
00377         /* Makes me wonder whether this is required... */
00378         if( dest[3] < RE_EMPTY_COLOR_FLOAT) {
00379                 dest[0] = source[0];
00380                 dest[1] = source[1];
00381                 dest[2] = source[2];
00382                 dest[3] = source[3];
00383                 return;
00384         }
00385 
00386         /* no clipping! */
00387         dest[0] = dest[0]+source[0];
00388         dest[1] = dest[1]+source[1];
00389         dest[2] = dest[2]+source[2];
00390         dest[3] = dest[3]+source[3];
00391 
00392 }
00393 
00394 
00395 /* ---------------------------------------------------------------------------- */
00396 
00397 
00398 /* eof pixelblending.c */
00399 
00400