doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_colorSpill.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, Xavier Thomas
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30
31 #include "../CMP_util.h"
32
33 #define avg(a,b) ((a+b)/2)
34
35 /* ******************* Color Spill Supression ********************************* */
36 static bNodeSocketType cmp_node_color_spill_in[]={
37    {SOCK_RGBA,1,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
38    {SOCK_VALUE, 1, "Fac",       1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
39         {-1,0,""}
40 };
41
42 static bNodeSocketType cmp_node_color_spill_out[]={
43         {SOCK_RGBA,0,"Image", 0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
44         {-1,0,""}
45 };
46
47 static void do_simple_spillmap_red(bNode *node, float* out, float *in)
48 {
49    NodeColorspill *ncs;
50         ncs=node->storage;
51         out[0]=in[0]-( ncs->limscale * in[ncs->limchan] );
52 }
53
54 static void do_simple_spillmap_red_fac(bNode *node, float* out, float *in, float *fac)
55 {
56    NodeColorspill *ncs;
57    ncs=node->storage;
58
59    out[0] = *fac * (in[0]-( ncs->limscale * in[ncs->limchan]));
60 }
61
62 static void do_simple_spillmap_green(bNode *node, float* out, float *in)
63 {
64         NodeColorspill *ncs;
65         ncs=node->storage;
66         out[0]=in[1]-( ncs->limscale * in[ncs->limchan] );
67 }
68
69 static void do_simple_spillmap_green_fac(bNode *node, float* out, float *in, float *fac)
70 {
71    NodeColorspill *ncs;
72    ncs=node->storage;
73
74    out[0] = *fac * (in[1]-( ncs->limscale * in[ncs->limchan]));
75 }
76
77 static void do_simple_spillmap_blue(bNode *node, float* out, float *in)
78 {
79         NodeColorspill *ncs;
80         ncs=node->storage;
81         out[0]=in[2]-( ncs->limscale * in[ncs->limchan] );
82 }
83
84 static void do_simple_spillmap_blue_fac(bNode *node, float* out, float *in, float *fac)
85 {
86    NodeColorspill *ncs;
87    ncs=node->storage;
88
89    out[0] = *fac * (in[2]-( ncs->limscale * in[ncs->limchan]));
90 }
91
92 static void do_average_spillmap_red(bNode *node, float* out, float *in)
93 {
94         NodeColorspill *ncs;
95         ncs=node->storage;
96         out[0]=in[0]-(ncs->limscale * avg(in[1], in[2]) );
97 }
98
99 static void do_average_spillmap_red_fac(bNode *node, float* out, float *in, float *fac)
100 {
101    NodeColorspill *ncs;
102    ncs=node->storage;
103
104    out[0] = *fac * (in[0]-(ncs->limscale * avg(in[1], in[2]) ));
105 }
106
107 static void do_average_spillmap_green(bNode *node, float* out, float *in)
108 {
109         NodeColorspill *ncs;
110         ncs=node->storage;
111         out[0]=in[1]-(ncs->limscale * avg(in[0], in[2]) );
112 }
113
114 static void do_average_spillmap_green_fac(bNode *node, float* out, float *in, float *fac)
115 {
116    NodeColorspill *ncs;
117    ncs=node->storage;
118
119    out[0] = *fac * (in[0]-(ncs->limscale * avg(in[0], in[2]) ));
120 }
121
122 static void do_average_spillmap_blue(bNode *node, float* out, float *in)
123 {
124         NodeColorspill *ncs;
125         ncs=node->storage;
126         out[0]=in[2]-(ncs->limscale * avg(in[0], in[1]) );
127 }
128
129 static void do_average_spillmap_blue_fac(bNode *node, float* out, float *in, float *fac)
130 {
131    NodeColorspill *ncs;
132    ncs=node->storage;
133
134    out[0] = *fac * (in[0]-(ncs->limscale * avg(in[0], in[1]) ));
135 }
136
137 static void do_apply_spillmap_red(bNode *node, float* out, float *in, float *map)
138 {       
139         NodeColorspill *ncs;
140         ncs=node->storage;
141         if(map[0]>0) {
142                 out[0]=in[0]-(ncs->uspillr*map[0]);
143                 out[1]=in[1]+(ncs->uspillg*map[0]);
144                 out[2]=in[2]+(ncs->uspillb*map[0]);
145         }
146         else {
147                 out[0]=in[0];
148                 out[1]=in[1];
149                 out[2]=in[2];
150         }
151 }
152
153 static void do_apply_spillmap_green(bNode *node, float* out, float *in, float *map)
154 {
155         NodeColorspill *ncs;
156         ncs=node->storage;
157         if(map[0]>0) {
158                 out[0]=in[0]+(ncs->uspillr*map[0]);
159                 out[1]=in[1]-(ncs->uspillg*map[0]);
160                 out[2]=in[2]+(ncs->uspillb*map[0]);
161    }
162         else {
163                 out[0]=in[0];
164                 out[1]=in[1];
165                 out[2]=in[2];
166         }
167 }
168
169 static void do_apply_spillmap_blue(bNode *node, float* out, float *in, float *map)
170 {
171         NodeColorspill *ncs;
172         ncs=node->storage;
173         if(map[0]>0) {
174                 out[0]=in[0]+(ncs->uspillr*map[0]);
175                 out[1]=in[1]+(ncs->uspillg*map[0]);
176                 out[2]=in[2]-(ncs->uspillb*map[0]);
177    }
178         else {
179                 out[0]=in[0];
180                 out[1]=in[1];
181                 out[2]=in[2];
182         }
183 }
184
185 static void node_composit_exec_color_spill(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
186 {
187         /*
188         Originally based on the information from the book "The Art and Science of Digital Composition" and 
189         discussions from vfxtalk.com.*/
190    CompBuf *cbuf;
191    CompBuf *mask;
192         CompBuf *rgbbuf;
193         CompBuf *spillmap;
194         NodeColorspill *ncs;
195         ncs=node->storage;
196
197    /* early out for missing connections */
198    if(out[0]->hasoutput==0 ) return;
199    if(in[0]->hasinput==0) return;
200    if(in[0]->data==NULL) return;
201         
202    cbuf=typecheck_compbuf(in[0]->data, CB_RGBA);
203    mask=typecheck_compbuf(in[1]->data, CB_VAL);
204         spillmap=alloc_compbuf(cbuf->x, cbuf->y, CB_VAL, 1);
205         rgbbuf=dupalloc_compbuf(cbuf);
206
207         switch(node->custom1)
208         {
209         case 1:  /*red spill*/
210                 {
211                         switch(node->custom2)
212                         {
213          case 0: /* simple limit */
214             {
215                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
216                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_red, CB_RGBA);
217                } else {
218                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_red_fac, CB_RGBA,  CB_VAL);
219                }
220                                         break;
221                                 }
222          case 1: /* average limit */
223             {
224                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
225                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_red, CB_RGBA);
226                } else {
227                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_red_fac, CB_RGBA,  CB_VAL);
228                }
229                                         break;
230                                 }
231                         }
232                         if(ncs->unspill==0) {
233                                 ncs->uspillr=1.0f;
234                                 ncs->uspillg=0.0f;
235                                 ncs->uspillb=0.0f;
236                         }
237                         composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_red, CB_RGBA, CB_VAL);
238                         break;
239                 }
240         case 2: /*green spill*/
241                 {
242                         switch(node->custom2)
243                         {
244          case 0: /* simple limit */
245             {
246                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
247                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_green, CB_RGBA);
248                } else {
249                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_green_fac, CB_RGBA,  CB_VAL);
250                }
251                break;
252             }
253          case 1: /* average limit */
254             {
255                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
256                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_green, CB_RGBA);
257                } else {
258                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_green_fac, CB_RGBA,  CB_VAL);
259                }
260                break;
261             }
262                         }
263                         if(ncs->unspill==0) {
264                                 ncs->uspillr=0.0f;
265                                 ncs->uspillg=1.0f;
266                                 ncs->uspillb=0.0f;
267          }
268                         composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_green, CB_RGBA, CB_VAL);
269                         break;
270                 }
271         case 3: /*blue spill*/
272                 {
273                         switch(node->custom2)
274                         {
275          case 0: /* simple limit */
276             {
277                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
278                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_simple_spillmap_blue, CB_RGBA);
279                } else {
280                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_simple_spillmap_blue_fac, CB_RGBA,  CB_VAL);
281                }
282                break;
283             }
284          case 1: /* average limit */
285             {
286                if ((in[1]->data==NULL) && (in[1]->vec[0] >= 1.f)) {
287                   composit1_pixel_processor(node, spillmap, cbuf, in[0]->vec, do_average_spillmap_blue, CB_RGBA);
288                } else {
289                   composit2_pixel_processor(node, spillmap, cbuf, in[0]->vec, in[1]->data, in[1]->vec, do_average_spillmap_blue_fac, CB_RGBA,  CB_VAL);
290                }
291                break;
292             }
293                         }
294                         if(ncs->unspill==0) {
295                                 ncs->uspillr=0.0f;
296                                 ncs->uspillg=0.0f;
297                                 ncs->uspillb=1.0f;
298                         }
299                         composit2_pixel_processor(node, rgbbuf, cbuf, in[0]->vec, spillmap, NULL, do_apply_spillmap_blue, CB_RGBA, CB_VAL);
300                         break;
301                 }
302         default:
303                 break;
304         }
305
306         out[0]->data=rgbbuf;
307
308         if(cbuf!=in[0]->data)
309                 free_compbuf(cbuf);
310    
311    free_compbuf(spillmap);
312 }
313
314 static void node_composit_init_color_spill(bNode *node)
315 {
316    NodeColorspill *ncs= MEM_callocN(sizeof(NodeColorspill), "node colorspill");
317    node->storage=ncs;
318    node->custom1= 2; /* green channel */
319    node->custom2= 0; /* simple limit algo*/
320    ncs->limchan= 0;  /* limit by red */
321    ncs->limscale= 1.0f; /* limit scaling factor */
322    ncs->unspill=0;   /* do not use unspill */
323 }
324
325 void register_node_type_cmp_color_spill(ListBase *lb)
326 {
327         static bNodeType ntype;
328         
329         node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, NODE_OPTIONS,
330                                    cmp_node_color_spill_in, cmp_node_color_spill_out);
331         node_type_size(&ntype, 140, 80, 200);
332         node_type_init(&ntype, node_composit_init_color_spill);
333         node_type_storage(&ntype, "NodeColorspill", node_free_standard_storage, node_copy_standard_storage);
334         node_type_exec(&ntype, node_composit_exec_color_spill);
335         
336         nodeRegisterType(lb, &ntype);
337 }