doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_levels.c
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2006 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): Bob Holcomb.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "../CMP_util.h"
31
32
33 /* **************** LEVELS ******************** */
34 static bNodeSocketType cmp_node_view_levels_in[]= {
35         {       SOCK_RGBA, 1, "Image", 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
36         {       -1, 0, ""       }
37 };
38
39 static bNodeSocketType cmp_node_view_levels_out[]={
40         {SOCK_VALUE, 0,"Mean",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
41         {SOCK_VALUE, 0,"Std Dev",0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
42         {-1,0,""}
43 };
44
45 static void rgb_tobw(float r, float g, float b, float* out)
46 {
47         *out= r*0.35f + g*0.45f + b*0.2f;
48 }
49
50 static void fill_bins(bNode* node, CompBuf* in, int* bins, int colorcor)
51 {
52         float value[4];
53         int ivalue=0;
54         int x,y;
55
56         /*fill bins */
57         for(y=0; y<in->y; y++) {
58                 for(x=0; x<in->x; x++) {
59
60                         /* get the pixel */
61                         qd_getPixel(in, x, y, value);
62
63                         if(value[3] > 0.0) { /* don't count transparent pixels */
64                                 switch(node->custom1) {
65                                         case 1: { /* all colors */
66                                                 if(colorcor)
67                                                         linearrgb_to_srgb_v3_v3(&value[0],&value[0]);
68                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
69                                                 value[0]=value[0]*255; /* scale to 0-255 range */
70                                                 ivalue=(int)value[0];
71                                                 break;
72                                         }
73                                         case 2: { /* red channel */
74                                                 if(colorcor)
75                                                         value[0]=linearrgb_to_srgb(value[0]);
76                                                 value[0]=value[0]*255; /* scale to 0-255 range */
77                                                 ivalue=(int)value[0];
78                                                 break;
79                                         }
80                                         case 3:  { /* green channel */
81                                                 if(colorcor)
82                                                         value[1]=linearrgb_to_srgb(value[1]);
83                                                 value[1]=value[1]*255; /* scale to 0-255 range */
84                                                 ivalue=(int)value[1];
85                                                 break;
86                                         }
87                                         case 4: /*blue channel */
88                                         {
89                                                 if(colorcor)
90                                                         value[2]=linearrgb_to_srgb(value[2]);
91                                                 value[2]=value[2]*255; /* scale to 0-255 range */
92                                                 ivalue=(int)value[2];
93                                                 break;
94                                         }
95                                         case 5: /* luminence */
96                                         {
97                                                 if(colorcor)
98                                                         linearrgb_to_srgb_v3_v3(&value[0],&value[0]);
99                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
100                                                 value[0]=value[0]*255; /* scale to 0-255 range */
101                                                 ivalue=(int)value[0];
102                                                 break;
103                                         }
104                                 } /*end switch */
105
106                                 /*clip*/
107                                 if(ivalue<0) ivalue=0;
108                                 if(ivalue>255) ivalue=255;
109
110                                 /*put in the correct bin*/
111                                 bins[ivalue]+=1;
112                         } /*end if alpha */
113                 }
114         }       
115 }
116
117 static float brightness_mean(bNode* node, CompBuf* in)
118 {
119         float sum=0.0;
120         int numPixels=0.0;
121         int x,y;
122         float value[4];
123
124         for(x=0; x< in->x; x++) {
125                 for(y=0; y < in->y; y++) {
126                         
127                         /* get the pixel */
128                         qd_getPixel(in, x, y, value);
129
130                         if(value[3] > 0.0) { /* don't count transparent pixels */
131                                 numPixels++;
132                                 switch(node->custom1)
133                                 {
134                                 case 1:
135                                         {
136                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
137                                                 sum+=value[0];
138                                                 break;
139                                         }
140                                 case 2:
141                                         {
142                                                 sum+=value[0];
143                                                 break;
144                                         }
145                                 case 3:
146                                         {
147                                                 sum+=value[1];
148                                                 break;
149                                         }
150                                 case 4:
151                                         {
152                                                 sum+=value[2];
153                                                 break;
154                                         }
155                                 case 5:
156                                         {
157                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
158                                                 sum+=value[0];
159                                                 break;
160                                         }
161                                 }
162                         }
163                 }
164         }
165
166         return sum/numPixels;
167 }
168
169 static float brightness_standard_deviation(bNode* node, CompBuf* in, float mean)
170 {
171         float sum=0.0;
172         int numPixels=0.0;
173         int x,y;
174         float value[4];
175
176         for(x=0; x< in->x; x++) {
177                 for(y=0; y < in->y; y++) {
178                         
179                         /* get the pixel */
180                         qd_getPixel(in, x, y, value);
181
182                         if(value[3] > 0.0) { /* don't count transparent pixels */
183                                 numPixels++;
184                                 switch(node->custom1)
185                                 {
186                                 case 1:
187                                         {
188                                                 rgb_tobw(value[0],value[1],value[2], &value[0]);
189                                                 sum+=(value[0]-mean)*(value[0]-mean);
190                                                 break;
191                                         }
192                                 case 2:
193                                         {
194                                                 sum+=value[0];
195                                                 sum+=(value[0]-mean)*(value[0]-mean);
196                                                 break;
197                                         }
198                                 case 3:
199                                         {
200                                                 sum+=value[1];
201                                                 sum+=(value[1]-mean)*(value[1]-mean);
202                                                 break;
203                                         }
204                                 case 4:
205                                         {
206                                                 sum+=value[2];
207                                                 sum+=(value[2]-mean)*(value[2]-mean);
208                                                 break;
209                                         }
210                                 case 5:
211                                         {
212                                                 rgb_to_yuv(value[0],value[1],value[2], &value[0], &value[1], &value[2]);
213                                                 sum+=(value[0]-mean)*(value[0]-mean);
214                                                 break;
215                                         }
216                                 }
217                         }
218                 }
219         }
220
221
222         return sqrt(sum/(float)(numPixels-1));
223 }
224
225 static void draw_histogram(bNode *node, CompBuf *out, int* bins)
226 {
227         int x,y;
228         float color[4]; 
229         float value;
230         int max;
231
232         /* find max value */
233         max=0;
234         for(x=0; x<256; x++) {
235                 if(bins[x]>max) max=bins[x];
236         }
237
238         /*draw histogram in buffer */
239         for(x=0; x<out->x; x++) {
240                 for(y=0;y<out->y; y++) {
241
242                         /* get normalized value (0..255) */
243                         value=((float)bins[x]/(float)max)*255.0; 
244
245                         if(y < (int)value) { /*if the y value is below the height of the bar for this line then draw with the color */
246                                 switch (node->custom1) {
247                                         case 1: { /* draw in black */
248                                                 color[0]=0.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
249                                                 break;
250                                         }
251                                         case 2: { /* draw in red */
252                                                 color[0]=1.0; color[1]=0.0; color[2]=0.0; color[3]=1.0;
253                                                 break;
254                                         }
255                                         case 3: { /* draw in green */
256                                                 color[0]=0.0; color[1]=1.0; color[2]=0.0; color[3]=1.0;
257                                                 break;
258                                         }
259                                         case 4: { /* draw in blue */
260                                                 color[0]=0.0; color[1]=0.0; color[2]=1.0; color[3]=1.0;
261                                                 break;
262                                         }
263                                         case 5: { /* draw in white */
264                                                 color[0]=1.0; color[1]=1.0; color[2]=1.0; color[3]=1.0;
265                                                 break;
266                                         }
267                                 }
268                         }
269                         else{
270                                 color[0]=0.8; color[1]=0.8; color[2]=0.8; color[3]=1.0;
271                         }
272
273                         /* set the color */
274                         qd_setPixel(out, x, y, color);
275                 }
276         }
277 }
278
279 static void node_composit_exec_view_levels(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
280 {
281         CompBuf* cbuf;
282         CompBuf* histogram;
283         RenderData *rd=data;
284         float mean, std_dev;
285         int bins[256];
286         int x;
287
288         if(in[0]->hasinput==0)  return;
289         if(in[0]->data==NULL) return;
290
291         histogram=alloc_compbuf(256, 256, CB_RGBA, 1);  
292         cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);   
293                 
294         /*initalize bins*/
295         for(x=0; x<256; x++) {
296                 bins[x]=0;
297         }
298         
299         /*fill bins */
300         fill_bins(node, in[0]->data, bins, rd->color_mgt_flag & R_COLOR_MANAGEMENT);
301
302         /* draw the histogram chart */
303         draw_histogram(node, histogram, bins);
304
305         /* calculate the average brightness and contrast */
306         mean=brightness_mean(node, in[0]->data);
307         std_dev=brightness_standard_deviation(node, in[0]->data, mean);
308
309         /*  Printf debuging ;) 
310         printf("Mean: %f\n", mean);
311         printf("Std Dev: %f\n", std_dev);
312         */
313
314         if(out[0]->hasoutput)
315                         out[0]->vec[0]= mean;
316         if(out[1]->hasoutput)
317                         out[1]->vec[0]= std_dev;
318
319         generate_preview(data, node, histogram);
320
321         if(cbuf!=in[0]->data)
322                 free_compbuf(cbuf);
323         free_compbuf(histogram);
324 }
325
326 static void node_composit_init_view_levels(bNode* node)
327 {
328    node->custom1=1; /*All channels*/
329 }
330
331 void register_node_type_cmp_view_levels(ListBase *lb)
332 {
333         static bNodeType ntype;
334
335         node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_OPTIONS|NODE_PREVIEW,
336                 cmp_node_view_levels_in, cmp_node_view_levels_out);
337         node_type_size(&ntype, 140, 100, 320);
338         node_type_init(&ntype, node_composit_init_view_levels);
339         node_type_storage(&ntype, "ImageUser", NULL, NULL);
340         node_type_exec(&ntype, node_composit_exec_view_levels);
341
342         nodeRegisterType(lb, &ntype);
343 }
344
345