c283512e4612bac9b9f5dbdcba0fefddd46681fe
[blender.git] / source / blender / nodes / composite / nodes / node_composite_displace.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_displace.c
29  *  \ingroup cmpnodes
30  */
31
32
33 #include "node_composite_util.h"
34
35
36 /* **************** Displace  ******************** */
37
38 static bNodeSocketTemplate cmp_node_displace_in[] = {
39         {       SOCK_RGBA, 1, N_("Image"),                      1.0f, 1.0f, 1.0f, 1.0f},
40         {       SOCK_VECTOR, 1, N_("Vector"),                   1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_TRANSLATION},
41         {       SOCK_FLOAT, 1, N_("X Scale"),                           0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_FACTOR},
42         {       SOCK_FLOAT, 1, N_("Y Scale"),                           0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f, PROP_FACTOR},
43         {       -1, 0, ""       }
44 };
45 static bNodeSocketTemplate cmp_node_displace_out[] = {
46         {       SOCK_RGBA, 0, N_("Image")},
47         {       -1, 0, ""       }
48 };
49
50 #ifdef WITH_COMPOSITOR_LEGACY
51
52 /* minimum distance (in pixels) a pixel has to be displaced
53  * in order to take effect */
54 #define DISPLACE_EPSILON        0.01f
55
56 static void do_displace(bNode *node, CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *UNUSED(veccol), CompBuf *xbuf,  CompBuf *ybuf, float *xscale, float *yscale)
57 {
58         ImBuf *ibuf;
59         int x, y;
60         float p_dx, p_dy;       /* main displacement in pixel space */
61         float d_dx, d_dy;
62         float dxt, dyt;
63         float u, v;
64         float xs, ys;
65         float vec[3], vecdx[3], vecdy[3];
66         float col[3];
67         
68         ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0);
69         ibuf->rect_float= cbuf->rect;
70         
71         for (y=0; y < stackbuf->y; y++) {
72                 for (x=0; x < stackbuf->x; x++) {
73                         /* calc pixel coordinates */
74                         qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof, vec);
75                         
76                         if (xbuf)
77                                 qd_getPixel(xbuf, x-xbuf->xof, y-xbuf->yof, &xs);
78                         else
79                                 xs = xscale[0];
80                         
81                         if (ybuf)
82                                 qd_getPixel(ybuf, x-ybuf->xof, y-ybuf->yof, &ys);
83                         else
84                                 ys = yscale[0];
85
86                         /* clamp x and y displacement to triple image resolution - 
87                          * to prevent hangs from huge values mistakenly plugged in eg. z buffers */
88                         CLAMP(xs, -stackbuf->x*4, stackbuf->x*4);
89                         CLAMP(ys, -stackbuf->y*4, stackbuf->y*4);
90                         
91                         p_dx = vec[0] * xs;
92                         p_dy = vec[1] * ys;
93                         
94                         /* if no displacement, then just copy this pixel */
95                         if (fabsf(p_dx) < DISPLACE_EPSILON && fabsf(p_dy) < DISPLACE_EPSILON) {
96                                 qd_getPixel(cbuf, x-cbuf->xof, y-cbuf->yof, col);
97                                 qd_setPixel(stackbuf, x, y, col);
98                                 continue;
99                         }
100                         
101                         /* displaced pixel in uv coords, for image sampling */
102                         u = (x - cbuf->xof - p_dx + 0.5f) / (float)stackbuf->x;
103                         v = (y - cbuf->yof - p_dy + 0.5f) / (float)stackbuf->y;
104                         
105                         
106                         /* calc derivatives */
107                         qd_getPixel(vecbuf, x-vecbuf->xof+1, y-vecbuf->yof, vecdx);
108                         qd_getPixel(vecbuf, x-vecbuf->xof, y-vecbuf->yof+1, vecdy);
109                         d_dx = vecdx[0] * xs;
110                         d_dy = vecdy[1] * ys;
111
112                         /* clamp derivatives to minimum displacement distance in UV space */
113                         dxt = p_dx - d_dx;
114                         dyt = p_dy - d_dy;
115
116                         dxt = signf(dxt)*maxf(fabsf(dxt), DISPLACE_EPSILON)/(float)stackbuf->x;
117                         dyt = signf(dyt)*maxf(fabsf(dyt), DISPLACE_EPSILON)/(float)stackbuf->y;
118                         
119                         ibuf_sample(ibuf, u, v, dxt, dyt, col);
120                         qd_setPixel(stackbuf, x, y, col);
121                         
122                         if (node->exec & NODE_BREAK) break;
123                 }
124                 
125                 if (node->exec & NODE_BREAK) break;
126         }
127         IMB_freeImBuf(ibuf);
128         
129         
130 /* simple method for reference, linear interpolation */
131 #if 0
132         int x, y;
133         float dx, dy;
134         float u, v;
135         float vec[3];
136         float col[3];
137         
138         for (y=0; y < stackbuf->y; y++) {
139                 for (x=0; x < stackbuf->x; x++) {
140                         qd_getPixel(vecbuf, x, y, vec);
141                         
142                         dx = vec[0] * (xscale[0]);
143                         dy = vec[1] * (yscale[0]);
144                         
145                         u = (x - dx + 0.5f) / (float)stackbuf->x;
146                         v = (y - dy + 0.5f) / (float)stackbuf->y;
147                         
148                         qd_getPixelLerp(cbuf, u*cbuf->x - 0.5f, v*cbuf->y - 0.5f, col);
149                         qd_setPixel(stackbuf, x, y, col);
150                 }
151         }
152 #endif
153 }
154
155
156 static void node_composit_exec_displace(void *UNUSED(data), bNode *node, bNodeStack **in, bNodeStack **out)
157 {
158         if (out[0]->hasoutput==0)
159                 return;
160         
161         if (in[0]->data && in[1]->data) {
162                 CompBuf *cbuf= in[0]->data;
163                 CompBuf *vecbuf= in[1]->data;
164                 CompBuf *xbuf= in[2]->data;
165                 CompBuf *ybuf= in[3]->data;
166                 CompBuf *stackbuf;
167                 
168                 cbuf= typecheck_compbuf(cbuf, CB_RGBA);
169                 vecbuf= typecheck_compbuf(vecbuf, CB_VEC3);
170                 xbuf= typecheck_compbuf(xbuf, CB_VAL);
171                 ybuf= typecheck_compbuf(ybuf, CB_VAL);
172                 
173                 stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
174
175                 do_displace(node, stackbuf, cbuf, vecbuf, in[1]->vec, xbuf, ybuf, in[2]->vec, in[3]->vec);
176                 
177                 out[0]->data= stackbuf;
178                 
179                 
180                 if (cbuf!=in[0]->data)
181                         free_compbuf(cbuf);
182                 if (vecbuf!=in[1]->data)
183                         free_compbuf(vecbuf);
184         }
185 }
186
187 #endif  /* WITH_COMPOSITOR_LEGACY */
188
189 void register_node_type_cmp_displace(bNodeTreeType *ttype)
190 {
191         static bNodeType ntype;
192
193         node_type_base(ttype, &ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, NODE_OPTIONS);
194         node_type_socket_templates(&ntype, cmp_node_displace_in, cmp_node_displace_out);
195         node_type_size(&ntype, 140, 100, 320);
196 #ifdef WITH_COMPOSITOR_LEGACY
197         node_type_exec(&ntype, node_composit_exec_displace);
198 #endif
199
200         nodeRegisterType(ttype, &ntype);
201 }