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