replace macros with bli math functions for nodes
[blender.git] / source / blender / nodes / composite / nodes / node_composite_filter.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): none yet.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/nodes/composite/nodes/node_composite_filter.c
29  *  \ingroup cmpnodes
30  */
31
32
33 #include "node_composite_util.h"
34
35 /* **************** FILTER  ******************** */
36 static bNodeSocketTemplate cmp_node_filter_in[]= {
37         {       SOCK_FLOAT, 1, "Fac",                   1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f, PROP_FACTOR},
38         {       SOCK_RGBA, 1, "Image",                  1.0f, 1.0f, 1.0f, 1.0f},
39         {       -1, 0, ""       }
40 };
41 static bNodeSocketTemplate cmp_node_filter_out[]= {
42         {       SOCK_RGBA, 0, "Image"},
43         {       -1, 0, ""       }
44 };
45
46 static void do_filter_edge(CompBuf *out, CompBuf *in, float *filter, float fac)
47 {
48         float *row1, *row2, *row3;
49         float *fp, f1, f2, mfac= 1.0f-fac;
50         int rowlen, x, y, c, pix= in->type;
51         
52         rowlen= in->x;
53         
54         for(y=0; y<in->y; y++) {
55                 /* setup rows */
56                 if(y==0) row1= in->rect;
57                 else row1= in->rect + pix*(y-1)*rowlen;
58                 
59                 row2= in->rect + y*pix*rowlen;
60                 
61                 if(y==in->y-1) row3= row2;
62                 else row3= row2 + pix*rowlen;
63                 
64                 fp= out->rect + pix*y*rowlen;
65                 
66                 if(pix==CB_RGBA) {
67                         copy_v4_v4(fp, row2);
68                         fp+= pix;
69                         
70                         for(x=2; x<rowlen; x++) {
71                                 for(c=0; c<3; c++) {
72                                         f1= filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8];
73                                         f2= filter[0]*row1[0] + filter[3]*row1[4] + filter[6]*row1[8] + filter[1]*row2[0] + filter[4]*row2[4] + filter[7]*row2[8] + filter[2]*row3[0] + filter[5]*row3[4] + filter[8]*row3[8];
74                                         fp[0]= mfac*row2[4] + fac*sqrt(f1*f1 + f2*f2);
75                                         fp++; row1++; row2++; row3++;
76                                 }
77                                 fp[0]= row2[4];
78                                 /* no alpha... will clear it completely */
79                                 fp++; row1++; row2++; row3++;
80                         }
81                         copy_v4_v4(fp, row2+4);
82                 }
83                 else if(pix==CB_VAL) {
84                         fp+= pix;
85                         for(x=2; x<rowlen; x++) {
86                                 f1= filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2];
87                                 f2= filter[0]*row1[0] + filter[3]*row1[1] + filter[6]*row1[2] + filter[1]*row2[0] + filter[4]*row2[1] + filter[7]*row2[2] + filter[2]*row3[0] + filter[5]*row3[1] + filter[8]*row3[2];
88                                 fp[0]= mfac*row2[1] + fac*sqrt(f1*f1 + f2*f2);
89                                 fp++; row1++; row2++; row3++;
90                         }
91                 }
92         }
93 }
94
95 static void do_filter3(CompBuf *out, CompBuf *in, float *filter, float fac)
96 {
97         float *row1, *row2, *row3;
98         float *fp, mfac= 1.0f-fac;
99         int rowlen, x, y, c;
100         int pixlen= in->type;
101         
102         rowlen= in->x;
103         
104         for(y=0; y<in->y; y++) {
105                 /* setup rows */
106                 if(y==0) row1= in->rect;
107                 else row1= in->rect + pixlen*(y-1)*rowlen;
108                 
109                 row2= in->rect + y*pixlen*rowlen;
110                 
111                 if(y==in->y-1) row3= row2;
112                 else row3= row2 + pixlen*rowlen;
113                 
114                 fp= out->rect + pixlen*(y)*rowlen;
115                 
116                 if(pixlen==1) {
117                         fp[0]= row2[0];
118                         fp+= 1;
119                         
120                         for(x=2; x<rowlen; x++) {
121                                 fp[0]= mfac*row2[1] + fac*(filter[0]*row1[0] + filter[1]*row1[1] + filter[2]*row1[2] + filter[3]*row2[0] + filter[4]*row2[1] + filter[5]*row2[2] + filter[6]*row3[0] + filter[7]*row3[1] + filter[8]*row3[2]);
122                                 fp++; row1++; row2++; row3++;
123                         }
124                         fp[0]= row2[1];
125                 }
126                 else if(pixlen==2) {
127                         fp[0]= row2[0];
128                         fp[1]= row2[1];
129                         fp+= 2;
130                         
131                         for(x=2; x<rowlen; x++) {
132                                 for(c=0; c<2; c++) {
133                                         fp[0]= mfac*row2[2] + fac*(filter[0]*row1[0] + filter[1]*row1[2] + filter[2]*row1[4] + filter[3]*row2[0] + filter[4]*row2[2] + filter[5]*row2[4] + filter[6]*row3[0] + filter[7]*row3[2] + filter[8]*row3[4]);
134                                         fp++; row1++; row2++; row3++;
135                                 }
136                         }
137                         fp[0]= row2[2];
138                         fp[1]= row2[3];
139                 }
140                 else if(pixlen==3) {
141                         copy_v3_v3(fp, row2);
142                         fp+= 3;
143                         
144                         for(x=2; x<rowlen; x++) {
145                                 for(c=0; c<3; c++) {
146                                         fp[0]= mfac*row2[3] + fac*(filter[0]*row1[0] + filter[1]*row1[3] + filter[2]*row1[6] + filter[3]*row2[0] + filter[4]*row2[3] + filter[5]*row2[6] + filter[6]*row3[0] + filter[7]*row3[3] + filter[8]*row3[6]);
147                                         fp++; row1++; row2++; row3++;
148                                 }
149                         }
150                         copy_v3_v3(fp, row2+3);
151                 }
152                 else {
153                         copy_v4_v4(fp, row2);
154                         fp+= 4;
155                         
156                         for(x=2; x<rowlen; x++) {
157                                 for(c=0; c<4; c++) {
158                                         fp[0]= mfac*row2[4] + fac*(filter[0]*row1[0] + filter[1]*row1[4] + filter[2]*row1[8] + filter[3]*row2[0] + filter[4]*row2[4] + filter[5]*row2[8] + filter[6]*row3[0] + filter[7]*row3[4] + filter[8]*row3[8]);
159                                         fp++; row1++; row2++; row3++;
160                                 }
161                         }
162                         copy_v4_v4(fp, row2+4);
163                 }
164         }
165 }
166
167
168 static void node_composit_exec_filter(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
169 {
170         static float soft[9]= {1/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 4/16.0f, 2/16.0f, 1/16.0f, 2/16.0f, 1/16.0f};
171         float sharp[9]= {-1,-1,-1,-1,9,-1,-1,-1,-1};
172         float laplace[9]= {-1/8.0f, -1/8.0f, -1/8.0f, -1/8.0f, 1.0f, -1/8.0f, -1/8.0f, -1/8.0f, -1/8.0f};
173         float sobel[9]= {1,2,1,0,0,0,-1,-2,-1};
174         float prewitt[9]= {1,1,1,0,0,0,-1,-1,-1};
175         float kirsch[9]= {5,5,5,-3,-3,-3,-2,-2,-2};
176         float shadow[9]= {1,2,1,0,1,0,-1,-2,-1};
177         
178         if(out[0]->hasoutput==0) return;
179         
180         /* stack order in: Image */
181         /* stack order out: Image */
182         
183         if(in[1]->data) {
184                 /* make output size of first available input image */
185                 CompBuf *cbuf= in[1]->data;
186                 CompBuf *stackbuf= alloc_compbuf(cbuf->x, cbuf->y, cbuf->type, 1); /* allocs */
187                 
188                 /* warning note: xof and yof are applied in pixelprocessor, but should be copied otherwise? */
189                 stackbuf->xof= cbuf->xof;
190                 stackbuf->yof= cbuf->yof;
191                 
192                 switch(node->custom1) {
193                         case CMP_FILT_SOFT:
194                                 do_filter3(stackbuf, cbuf, soft, in[0]->vec[0]);
195                                 break;
196                         case CMP_FILT_SHARP:
197                                 do_filter3(stackbuf, cbuf, sharp, in[0]->vec[0]);
198                                 break;
199                         case CMP_FILT_LAPLACE:
200                                 do_filter3(stackbuf, cbuf, laplace, in[0]->vec[0]);
201                                 break;
202                         case CMP_FILT_SOBEL:
203                                 do_filter_edge(stackbuf, cbuf, sobel, in[0]->vec[0]);
204                                 break;
205                         case CMP_FILT_PREWITT:
206                                 do_filter_edge(stackbuf, cbuf, prewitt, in[0]->vec[0]);
207                                 break;
208                         case CMP_FILT_KIRSCH:
209                                 do_filter_edge(stackbuf, cbuf, kirsch, in[0]->vec[0]);
210                                 break;
211                         case CMP_FILT_SHADOW:
212                                 do_filter3(stackbuf, cbuf, shadow, in[0]->vec[0]);
213                                 break;
214                 }
215                         
216                 out[0]->data= stackbuf;
217                 
218                 generate_preview(data, node, out[0]->data);
219         }
220 }
221
222
223 void register_node_type_cmp_filter(ListBase *lb)
224 {
225         static bNodeType ntype;
226
227         node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW|NODE_OPTIONS);
228         node_type_socket_templates(&ntype, cmp_node_filter_in, cmp_node_filter_out);
229         node_type_size(&ntype, 80, 40, 120);
230         node_type_label(&ntype, node_filter_label);
231         node_type_exec(&ntype, node_composit_exec_filter);
232
233         nodeRegisterType(lb, &ntype);
234 }
235
236
237