Three features;
[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 mul;
78     
79         mul= 1.0 - source[3];
80
81         dest[0]= (mul*dest[0]) + source[0];
82         dest[1]= (mul*dest[1]) + source[1];
83         dest[2]= (mul*dest[2]) + source[2];
84         dest[3]= (mul*dest[3]) + source[3];
85
86 }
87
88
89 /* ------------------------------------------------------------------------- */
90
91 void addAlphaUnderFloat(float *dest, float *source)
92 {
93     float mul;
94     
95     if( (-RE_EMPTY_COLOUR_FLOAT < dest[3])
96         && (dest[3] <  RE_EMPTY_COLOUR_FLOAT) ) {       
97         dest[0] = source[0];
98         dest[1] = source[1];
99         dest[2] = source[2];
100         dest[3] = source[3];
101         return;
102     }
103
104         mul= 1.0 - dest[3];
105
106         dest[0]+= (mul*source[0]);
107         dest[1]+= (mul*source[1]);
108         dest[2]+= (mul*source[2]);
109         dest[3]+= (mul*source[3]);
110
111
112
113 /* ------------------------------------------------------------------------- */
114 void addalphaAddfacFloat(float *dest, float *source, char addfac)
115 {
116     float m; /* weiging factor of destination */
117     float c; /* intermediate colour           */
118
119     /* Addfac is a number between 0 and 1: rescale */
120     /* final target is to diminish the influence of dest when addfac rises */
121     m = 1.0 - ( source[3] * ((255.0 - addfac) / 255.0));
122
123     /* blend colours*/
124     c= (m * dest[0]) + source[0];
125 #ifdef RE_FLOAT_COLOUR_CLIPPING
126     if(c >= RE_FULL_COLOUR_FLOAT) dest[0] = RE_FULL_COLOUR_FLOAT; 
127     else 
128 #endif
129         dest[0]= c;
130    
131     c= (m * dest[1]) + source[1];
132 #ifdef RE_FLOAT_COLOUR_CLIPPING
133     if(c >= RE_FULL_COLOUR_FLOAT) dest[1] = RE_FULL_COLOUR_FLOAT; 
134     else 
135 #endif
136         dest[1]= c;
137     
138     c= (m * dest[2]) + source[2];
139 #ifdef RE_FLOAT_COLOUR_CLIPPING
140     if(c >= RE_FULL_COLOUR_FLOAT) dest[2] = RE_FULL_COLOUR_FLOAT; 
141     else 
142 #endif
143         dest[2]= c;
144
145         c= (m * dest[3]) + source[3];
146 #ifdef RE_ALPHA_CLIPPING
147         if(c >= RE_FULL_COLOUR_FLOAT) dest[3] = RE_FULL_COLOUR_FLOAT; 
148         else 
149 #endif
150        dest[3]= c;
151
152 }
153
154
155 /* ------------------------------------------------------------------------- */
156
157 /* filtered adding to scanlines */
158 void add_filt_fmask(unsigned int mask, float *col, float *rowbuf, int row_w)
159 {
160         /* calc the value of mask */
161         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
162         float *rb1, *rb2, *rb3;
163         float val, r, g, b, al;
164         unsigned int a, maskand, maskshift;
165         int j;
166         
167         r= col[0];
168         g= col[1];
169         b= col[2];
170         al= col[3];
171         
172         rb2= rowbuf-4;
173         rb3= rb2-4*row_w;
174         rb1= rb2+4*row_w;
175         
176         maskand= (mask & 255);
177         maskshift= (mask >>8);
178         
179         for(j=2; j>=0; j--) {
180                 
181                 a= j;
182                 
183                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
184                 if(val!=0.0) {
185                         rb1[0]+= val*r;
186                         rb1[1]+= val*g;
187                         rb1[2]+= val*b;
188                         rb1[3]+= val*al;
189                 }
190                 a+=3;
191                 
192                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
193                 if(val!=0.0) {
194                         rb2[0]+= val*r;
195                         rb2[1]+= val*g;
196                         rb2[2]+= val*b;
197                         rb2[3]+= val*al;
198                 }
199                 a+=3;
200                 
201                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
202                 if(val!=0.0) {
203                         rb3[0]+= val*r;
204                         rb3[1]+= val*g;
205                         rb3[2]+= val*b;
206                         rb3[3]+= val*al;
207                 }
208                 
209                 rb1+= 4;
210                 rb2+= 4;
211                 rb3+= 4;
212         }
213 }
214
215 /* filtered adding to scanlines */
216 void add_filt_fmask_alphaunder(unsigned int mask, float *col, float *rowbuf, int row_w)
217 {
218         /* calc the value of mask */
219         float **fmask1= R.samples->fmask1, **fmask2=R.samples->fmask2;
220         float *rb1, *rb2, *rb3;
221         float val, r, g, b, al, acol[4];
222         unsigned int a, maskand, maskshift;
223         int j;
224         
225         r= col[0];
226         g= col[1];
227         b= col[2];
228         al= col[3];
229         
230         rb2= rowbuf-4;
231         rb3= rb2-4*row_w;
232         rb1= rb2+4*row_w;
233         
234         maskand= (mask & 255);
235         maskshift= (mask >>8);
236         
237         for(j=2; j>=0; j--) {
238                 
239                 a= j;
240                 
241                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
242                 if(val!=0.0) {
243                         acol[0]= val*r;
244                         acol[1]= val*g;
245                         acol[2]= val*b;
246                         acol[3]= val*al;
247                         addAlphaUnderFloat(rb1, acol);
248                 }
249                 a+=3;
250                 
251                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
252                 if(val!=0.0) {
253                         acol[0]= val*r;
254                         acol[1]= val*g;
255                         acol[2]= val*b;
256                         acol[3]= val*al;
257                         addAlphaUnderFloat(rb2, acol);
258                 }
259                 a+=3;
260                 
261                 val= *(fmask1[a] +maskand) + *(fmask2[a] +maskshift);
262                 if(val!=0.0) {
263                         acol[0]= val*r;
264                         acol[1]= val*g;
265                         acol[2]= val*b;
266                         acol[3]= val*al;
267                         addAlphaUnderFloat(rb3, acol);
268                 }
269                 
270                 rb1+= 4;
271                 rb2+= 4;
272                 rb3+= 4;
273         }
274 }
275
276
277 /* ------------------------------------------------------------------------- */
278 void addalphaAddFloat(float *dest, float *source)
279 {
280
281         /* Makes me wonder whether this is required... */
282         if( dest[3] < RE_EMPTY_COLOUR_FLOAT) {
283                 dest[0] = source[0];
284                 dest[1] = source[1];
285                 dest[2] = source[2];
286                 dest[3] = source[3];
287                 return;
288         }
289
290         /* no clipping! */
291         dest[0] = dest[0]+source[0];
292         dest[1] = dest[1]+source[1];
293         dest[2] = dest[2]+source[2];
294         dest[3] = dest[3]+source[3];
295
296 }
297
298
299 /* ------------------------------------------------------------------------- */
300
301 /* ------------------------------------------------------------------------- */
302 /* Colour buffer related:                                                    */
303 /* This transforms the 4 inputvalues RE_COLBUFTYPE to a new value            */
304 /* It expects the values R.r.postigamma, R.r.postmul and R.r.postadd.         */
305 /* This is the standard transformation, more elaborate tools are for later.  */
306 /* ------------------------------------------------------------------------- */
307 void std_floatcol_to_charcol( float *buf, char *target)
308 {
309         float col[3];
310         
311         float dither_value;
312         
313         dither_value = ((BLI_frand()-0.5)*R.r.dither_intensity)/256.0; 
314         
315         /* alpha */
316         if((buf[3]+dither_value)<=0.0) target[3]= 0;
317         else if((buf[3]+dither_value)>1.0) target[3]= 255;
318         else target[3]= 255.0*(buf[3]+dither_value);
319         
320         if(R.r.postgamma==1.0) {
321                 /* r */
322                 col[0]= R.r.postmul*buf[0] + R.r.postadd + dither_value;
323                 /* g */
324                 col[1]= R.r.postmul*buf[1] + R.r.postadd + dither_value;
325                 /* b */
326                 col[2]= R.r.postmul*buf[2] + R.r.postadd + dither_value;
327         }
328         else {
329                 /* putting the postmul within the pow() gives an
330                 * easier control for the user, values from 1.0-2.0
331                 * are relevant then
332                 */
333                 
334                 /* r */
335                 col[0]= pow(R.r.postmul*buf[0], R.r.postigamma) + R.r.postadd + dither_value;
336                 /* g */
337                 col[1]= pow( R.r.postmul*buf[1], R.r.postigamma) + R.r.postadd + dither_value;
338                 /* b */
339                 col[2]= pow(R.r.postmul*buf[2], R.r.postigamma) + R.r.postadd + dither_value;
340         }
341         
342         if(R.r.posthue!=0.0 || R.r.postsat!=1.0) {
343                 float hsv[3];
344                 
345                 rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
346                 hsv[0]+= R.r.posthue;
347                 if(hsv[0]>1.0) hsv[0]-=1.0; else if(hsv[0]<0.0) hsv[0]+= 1.0;
348                 hsv[1]*= R.r.postsat;
349                 if(hsv[1]>1.0) hsv[1]= 1.0; else if(hsv[1]<0.0) hsv[1]= 0.0;
350                 hsv_to_rgb(hsv[0], hsv[1], hsv[2], col, col+1, col+2);
351         }
352         
353         if(col[0]<=0.0) target[0]= 0;
354         else if(col[0]>1.0) target[0]= 255;
355         else target[0]= 255.0*col[0];
356         
357         if(col[1]<=0.0) target[1]= 0;
358         else if(col[1]>1.0) target[1]= 255;
359         else target[1]= 255.0*col[1];
360         
361         if(col[2]<=0.0) target[2]= 0;
362         else if(col[2]>1.0) target[2]= 255;
363         else target[2]= 255.0*col[2];
364 }
365
366 /* ----------------------------------------------------------------------------
367
368 Colour buffer related:
369
370 The colour buffer is a buffer of a single screen line. It contains        
371 four fields of type RE_COLBUFTYPE per pixel.
372
373 We can do several post-process steps. I would prefer to move them outside
374 the render module later on, but it's ok to leave it here for now. For the
375 time being, we have:
376 - post-process function
377     Does some operations with the colours.
378 - Multiply with some factor
379 - Add constant offset
380 - Apply extra gamma correction (seems weird...)
381 - key-alpha correction
382     Key alpha means 'un-applying' the alpha. For fully covered pixels, this
383         operation has no effect.
384
385 - XXX WARNING! Added the inverse render gamma here, so this cannot be used external
386         without setting Osa or Gamma flags off (ton)
387
388 ---------------------------------------------------------------------------- */
389 /* used external! */
390 void transferColourBufferToOutput( float *buf, int y)
391 {
392     /* Copy the contents of AColourBuffer3 to R.rectot + y * R.rectx */
393     int x = 0;
394 //    char *target = (char*) (R.rectot + (y * R.rectx));
395         
396         /* Copy the first <R.rectx> pixels. We can do some more clipping on    */
397         /* the z buffer, I think.                                                 */
398         while (x < R.rectx) {
399                 
400                 
401                 /* invert gamma corrected additions */
402                 if(R.do_gamma) {
403                         buf[0] = invGammaCorrect(buf[0]);
404                         buf[1] = invGammaCorrect(buf[1]);
405                         buf[2] = invGammaCorrect(buf[2]);
406                 }                       
407                 
408 //              std_floatcol_to_charcol(buf, target);
409                 
410                 /*
411                  Key-alpha mode:
412                  Need to un-apply alpha if alpha is non-full. For full alpha,
413                  the operation doesn't have effect. Do this after the post-
414                  processing, so we can still use the benefits of that.
415                  
416                  */
417                 
418                 if (R.r.alphamode == R_ALPHAKEY) {  
419 //                      applyKeyAlphaCharCol(target);
420                 }                               
421                 
422 //        target+=4;
423         buf+=4;
424         x++;
425     }
426 }
427
428
429 /* eof pixelblending.c */
430
431