860aeed29d7996f5d178faef2789b820956e7b70
[blender-staging.git] / source / blender / render / intern / source / pixelblending.c
1 /*
2  * pixelblending.c
3  *
4  * Functions to blend pixels with or without alpha, in various formats
5  * nzc - June 2000
6  *
7  * $Id$
8  *
9  * ***** BEGIN GPL LICENSE BLOCK *****
10  *
11  * This program is free software; you can redistribute it and/or
12  * modify it under the terms of the GNU General Public License
13  * as published by the Free Software Foundation; either version 2
14  * of the License, or (at your option) any later version.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * Contributor(s): Full recode, 2004-2006 Blender Foundation
29  *
30  * ***** END GPL LICENSE BLOCK *****
31  */
32
33 #include <math.h>
34
35 /* global includes */
36 #include "BLI_arithb.h"
37 #include "BLI_rand.h"
38
39 /* own includes */
40 #include "render_types.h"
41 #include "renderpipeline.h"
42 #include "pixelblending.h"
43 #include "gammaCorrectionTables.h"
44
45 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
46 /* defined in pipeline.c, is hardcopy of active dynamic allocated Render */
47 /* only to be used here in this file, it's for speed */
48 extern struct Render R;
49 /* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ */
50
51
52 /* ------------------------------------------------------------------------- */
53 /* Debug/behaviour defines                                                   */
54 /* if defined: alpha blending with floats clips colour, as with shorts       */
55 /* #define RE_FLOAT_COLOUR_CLIPPING  */
56 /* if defined: alpha values are clipped                                      */
57 /* For now, we just keep alpha clipping. We run into thresholding and        */
58 /* blending difficulties otherwise. Be careful here.                         */
59 #define RE_ALPHA_CLIPPING
60
61
62
63 /* Threshold for a 'full' pixel: pixels with alpha above this level are      */
64 /* considered opaque This is the decimal value for 0xFFF0 / 0xFFFF           */
65 #define RE_FULL_COLOUR_FLOAT 0.9998
66 /* Threshold for an 'empty' pixel: pixels with alpha above this level are    */
67 /* considered completely transparent. This is the decimal value              */
68 /* for 0x000F / 0xFFFF                                                       */
69 #define RE_EMPTY_COLOUR_FLOAT 0.0002
70
71
72 /* ------------------------------------------------------------------------- */
73
74 void addAlphaOverFloat(float *dest, float *source)
75 {
76     /* d = s + (1-alpha_s)d*/
77     float c;
78     float mul;
79     
80         mul= 1.0 - source[3];
81
82         c= (mul*dest[0]) + source[0];
83        dest[0]= c;
84    
85         c= (mul*dest[1]) + source[1];
86        dest[1]= c;
87
88         c= (mul*dest[2]) + source[2];
89        dest[2]= c;
90
91         c= (mul*dest[3]) + source[3];
92        dest[3]= c;
93
94 }
95
96
97 /* ------------------------------------------------------------------------- */
98
99 void addAlphaUnderFloat(float *dest, float *source)
100 {
101     float c;
102     float mul;
103     
104     if( (-RE_EMPTY_COLOUR_FLOAT < dest[3])
105         && (dest[3] <  RE_EMPTY_COLOUR_FLOAT) ) {       
106         dest[0] = source[0];
107         dest[1] = source[1];
108         dest[2] = source[2];
109         dest[3] = source[3];
110         return;
111     }
112
113         mul= 1.0 - dest[3];
114
115         c= (mul*source[0]) + dest[0];
116        dest[0]= c;
117    
118         c= (mul*source[1]) + dest[1];
119        dest[1]= c;
120
121         c= (mul*source[2]) + dest[2];
122        dest[2]= c;
123
124         c= (mul*source[3]) + dest[3];
125        dest[3]= c;
126
127
128
129
130 /* ------------------------------------------------------------------------- */
131 void addalphaAddfacFloat(float *dest, float *source, char addfac)
132 {
133     float m; /* weiging factor of destination */
134     float c; /* intermediate colour           */
135
136     /* Addfac is a number between 0 and 1: rescale */
137     /* final target is to diminish the influence of dest when addfac rises */
138     m = 1.0 - ( source[3] * ((255.0 - addfac) / 255.0));
139
140     /* blend colours*/
141     c= (m * dest[0]) + source[0];
142 #ifdef RE_FLOAT_COLOUR_CLIPPING
143     if(c >= RE_FULL_COLOUR_FLOAT) dest[0] = RE_FULL_COLOUR_FLOAT; 
144     else 
145 #endif
146         dest[0]= c;
147    
148     c= (m * dest[1]) + source[1];
149 #ifdef RE_FLOAT_COLOUR_CLIPPING
150     if(c >= RE_FULL_COLOUR_FLOAT) dest[1] = RE_FULL_COLOUR_FLOAT; 
151     else 
152 #endif
153         dest[1]= c;
154     
155     c= (m * dest[2]) + source[2];
156 #ifdef RE_FLOAT_COLOUR_CLIPPING
157     if(c >= RE_FULL_COLOUR_FLOAT) dest[2] = RE_FULL_COLOUR_FLOAT; 
158     else 
159 #endif
160         dest[2]= c;
161
162         c= (m * dest[3]) + source[3];
163 #ifdef RE_ALPHA_CLIPPING
164         if(c >= RE_FULL_COLOUR_FLOAT) dest[3] = RE_FULL_COLOUR_FLOAT; 
165         else 
166 #endif
167        dest[3]= c;
168
169 }
170
171
172 /* ------------------------------------------------------------------------- */
173
174 /* filtered adding to scanlines */
175 void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w)
176 {
177         /* calc the value of mask */
178         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
179         float *rb1, *rb2, *rb3;
180         float val, r, g, b, al;
181         unsigned int a, maskand, maskshift;
182         int j;
183         
184         r= col[0];
185         g= col[1];
186         b= col[2];
187         al= col[3];
188         
189         rb2= rowbuf-4;
190         rb3= rb2-4*row_w;
191         rb1= rb2+4*row_w;
192         
193         maskand= (mask & 255);
194         maskshift= (mask >>8);
195         
196         for(j=2; j>=0; j--) {
197                 
198                 a= j;
199                 
200                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
201                 if(val!=0.0) {
202                         rb1[0]+= val*r;
203                         rb1[1]+= val*g;
204                         rb1[2]+= val*b;
205                         rb1[3]+= val*al;
206                 }
207                 a+=3;
208                 
209                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
210                 if(val!=0.0) {
211                         rb2[0]+= val*r;
212                         rb2[1]+= val*g;
213                         rb2[2]+= val*b;
214                         rb2[3]+= val*al;
215                 }
216                 a+=3;
217                 
218                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
219                 if(val!=0.0) {
220                         rb3[0]+= val*r;
221                         rb3[1]+= val*g;
222                         rb3[2]+= val*b;
223                         rb3[3]+= val*al;
224                 }
225                 
226                 rb1+= 4;
227                 rb2+= 4;
228                 rb3+= 4;
229         }
230 }
231
232 /* ------------------------------------------------------------------------- */
233 void addalphaAddFloat(float *dest, float *source)
234 {
235
236         /* Makes me wonder whether this is required... */
237         if( dest[3] < RE_EMPTY_COLOUR_FLOAT) {
238                 dest[0] = source[0];
239                 dest[1] = source[1];
240                 dest[2] = source[2];
241                 dest[3] = source[3];
242                 return;
243         }
244
245         /* no clipping! */
246         dest[0] = dest[0]+source[0];
247         dest[1] = dest[1]+source[1];
248         dest[2] = dest[2]+source[2];
249         dest[3] = dest[3]+source[3];
250
251 }
252
253
254 /* ------------------------------------------------------------------------- */
255
256 /* ------------------------------------------------------------------------- */
257 /* Colour buffer related:                                                    */
258 /* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value            */
259 /* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd.         */
260 /* This is the standard transformation, more elaborate tools are for later.  */
261 /* ------------------------------------------------------------------------- */
262 void std_floatcol_to_charcol( float *buf, char *target)
263 {
264         float col[3];
265         
266         float dither_value;
267         
268         dither_value = ((BLI_frand()-0.5)*R.r.dither_intensity)/256.0; 
269         
270         /* alpha */
271         if((buf[3]+dither_value)<=0.0) target[3]= 0;
272         else if((buf[3]+dither_value)>1.0) target[3]= 255;
273         else target[3]= 255.0*(buf[3]+dither_value);
274         
275         if(R.r.postgamma==1.0) {
276                 /* r */
277                 col[0]= R.r.postmul*buf[0] + R.r.postadd + dither_value;
278                 /* g */
279                 col[1]= R.r.postmul*buf[1] + R.r.postadd + dither_value;
280                 /* b */
281                 col[2]= R.r.postmul*buf[2] + R.r.postadd + dither_value;
282         }
283         else {
284                 /* putting the postmul within the pow() gives an
285                 * easier control for the user, values from 1.0-2.0
286                 * are relevant then
287                 */
288                 
289                 /* r */
290                 col[0]= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd + dither_value;
291                 /* g */
292                 col[1]= pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd + dither_value;
293                 /* b */
294                 col[2]= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd + dither_value;
295         }
296         
297         if(R.r.posthue!=0.0 || R.r.postsat!=1.0) {
298                 float hsv[3];
299                 
300                 rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
301                 hsv[0]+= R.r.posthue;
302                 if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
303                 hsv[1]*= R.r.postsat;
304                 if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
305                 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
306         }
307         
308         if(col[0]<=0.0) target[0]= 0;
309         else if(col[0]>1.0) target[0]= 255;
310         else target[0]= 255.0*col[0];
311         
312         if(col[1]<=0.0) target[1]= 0;
313         else if(col[1]>1.0) target[1]= 255;
314         else target[1]= 255.0*col[1];
315         
316         if(col[2]<=0.0) target[2]= 0;
317         else if(col[2]>1.0) target[2]= 255;
318         else target[2]= 255.0*col[2];
319 }
320
321 /* ----------------------------------------------------------------------------
322
323 Colour buffer related:
324
325 The colour buffer is a buffer of a single screen line. It contains        
326 four fields of type RE_COLBUFTYPE per pixel.
327
328 We can do several post-process steps. I would prefer to move them outside
329 the render module later on, but it's ok to leave it here for now. For the
330 time being, we have:
331 - post-process function
332     Does some operations with the colours.
333 - Multiply with some factor
334 - Add constant offset
335 - Apply extra gamma correction (seems weird...)
336 - key-alpha correction
337     Key alpha means 'un-applying' the alpha. For fully covered pixels, this
338         operation has no effect.
339
340 - XXX WARNING! Added the inverse render gamma here, so this cannot be used external
341         without setting Osa or Gamma flags off (ton)
342
343 ---------------------------------------------------------------------------- */
344 /* used external! */
345 void transferColourBufferToOutput( float *buf, int y)
346 {
347     /* Copy the contents of AColourBuffer3 to R.rectot + y * R.rectx */
348     int x = 0;
349 //    char *target = (char*) (R.rectot + (y * R.rectx));
350         
351         /* Copy the first <R.rectx> pixels. We can do some more clipping on    */
352         /* the z buffer, I think.                                                 */
353         while (x < R.rectx) {
354                 
355                 
356                 /* invert gamma corrected additions */
357                 if(R.do_gamma) {
358                         buf[0] = invGammaCorrect(buf[0]);
359                         buf[1] = invGammaCorrect(buf[1]);
360                         buf[2] = invGammaCorrect(buf[2]);
361                 }                       
362                 
363 //              std_floatcol_to_charcol(buf, target);
364                 
365                 /*
366                  Key-alpha mode:
367                  Need to un-apply alpha if alpha is non-full. For full alpha,
368                  the operation doesn't have effect. Do this after the post-
369                  processing, so we can still use the benefits of that.
370                  
371                  */
372                 
373                 if (R.r.alphamode == R_ALPHAKEY) {  
374 //                      applyKeyAlphaCharCol(target);
375                 }                               
376                 
377 //        target+=4;
378         buf+=4;
379         x++;
380     }
381 }
382
383
384 /* eof pixelblending.c */
385
386