=== Node editor ===
[blender.git] / source / blender / nodes / intern / CMP_nodes / CMP_displace.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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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): none yet.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "../CMP_util.h"
31
32
33 /* **************** Displace  ******************** */
34
35 static bNodeSocketType cmp_node_displace_in[]= {
36         {       SOCK_RGBA, 1, "Image",                  0.8f, 0.8f, 0.8f, 1.0f, 0.0f, 1.0f},
37         {       SOCK_VECTOR, 1, "Vector",                       1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
38         {       SOCK_VALUE, 1, "X Scale",                               0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
39         {       SOCK_VALUE, 1, "Y Scale",                               0.0f, 0.0f, 0.0f, 0.0f, -1000.0f, 1000.0f},
40         {       -1, 0, ""       }
41 };
42 static bNodeSocketType cmp_node_displace_out[]= {
43         {       SOCK_RGBA, 0, "Image",                  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
44         {       -1, 0, ""       }
45 };
46
47 static void do_displace(CompBuf *stackbuf, CompBuf *cbuf, CompBuf *vecbuf, float *veccol, float *xscale, float *yscale)
48 {
49         ImBuf *ibuf;
50         int x, y, sx, sy;
51         float dx=0.0, dy=0.0;
52         float dspx, dspy;
53         float uv[2];
54
55         float *out= stackbuf->rect, *vec=vecbuf->rect, *in= cbuf->rect;
56         float *vp, *vpnext, *vpprev;
57         
58         int row = 3*vecbuf->x;
59         
60         /* ibuf needed for sampling */
61         ibuf= IMB_allocImBuf(cbuf->x, cbuf->y, 32, 0, 0);
62         ibuf->rect_float= cbuf->rect;
63         
64         vec = vecbuf->rect;
65         
66         sx= stackbuf->x;
67         sy= stackbuf->y;
68         
69         for(y=0; y<sy; y++) {
70                 for(x= 0; x< sx; x++, out+=4, in+=4, vec+=3) {
71                         
72                         /* the x-xrad stuff is a bit weird, but i seem to need it otherwise 
73                          * my returned pixels are offset weirdly */
74                         vp = compbuf_get_pixel(vecbuf, veccol, x-vecbuf->xrad, y-vecbuf->yrad, vecbuf->xrad, vecbuf->yrad);
75                         
76                         /* find the new displaced co-ords, also correcting for translate offset */
77                         dspx = x - (*xscale * vp[0]);
78                         dspy = y - (*yscale * vp[1]);
79
80                         /* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */
81                         uv[0] = dspx / (float)sx;
82                         uv[1] = dspy / (float)sy;
83                         
84                         if(x>0 && x< vecbuf->x-1 && y>0 && y< vecbuf->y-1)  {
85                                 vpnext = vp+row;
86                                 vpprev = vp-row;
87                         
88                                 /* adaptive sampling, X channel */
89                                 dx= 0.5f*(fabs(vp[0]-vp[-3]) + fabs(vp[0]-vp[3]));
90                                 
91                                 dx+= 0.25f*(fabs(vp[0]-vpprev[-3]) + fabs(vp[0]-vpnext[-3]));
92                                 dx+= 0.25f*(fabs(vp[0]-vpprev[+3]) + fabs(vp[0]-vpnext[+3]));
93                                 
94                                 /* adaptive sampling, Y channel */
95                                 dy= 0.5f*(fabs(vp[1]-vp[-row+1]) + fabs(vp[1]-vp[row+1]));
96                                                  
97                                 dy+= 0.25f*(fabs(vp[1]-vpprev[+1-3]) + fabs(vp[1]-vpnext[+1-3]));
98                                 dy+= 0.25f*(fabs(vp[1]-vpprev[+1+3]) + fabs(vp[1]-vpnext[+1+3]));
99                                 
100                                 /* scaled down to prevent blurriness */
101                                 /* 8: magic number, provides a good level of sharpness without getting too aliased */
102                                 dx /= 8;
103                                 dy /= 8;
104                         }
105
106                         /* should use mipmap */
107                         if(dx > 0.006f) dx= 0.006f;
108                         if(dy > 0.006f) dy= 0.006f;
109                         if ((vp[0]> 0.0) && (dx < 0.004)) dx = 0.004;
110                         if ((vp[1]> 0.0) && (dy < 0.004)) dy = 0.004;
111                         
112
113                         ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
114                 }
115         }
116
117         IMB_freeImBuf(ibuf);    
118 }
119
120
121 static void node_composit_exec_displace(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
122 {
123         if(out[0]->hasoutput==0)
124                 return;
125         
126         if(in[0]->data && in[1]->data) {
127                 CompBuf *cbuf= in[0]->data;
128                 CompBuf *vecbuf= in[1]->data;
129                 CompBuf *stackbuf;
130                 
131                 cbuf= typecheck_compbuf(cbuf, CB_RGBA);
132                 vecbuf= typecheck_compbuf(vecbuf, CB_VEC3);
133                 stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
134
135                 do_displace(stackbuf, cbuf, vecbuf, in[1]->vec, in[2]->vec, in[3]->vec);
136                 
137                 out[0]->data= stackbuf;
138                 
139                 
140                 if(cbuf!=in[0]->data)
141                         free_compbuf(cbuf);
142                 if(vecbuf!=in[1]->data)
143                         free_compbuf(vecbuf);
144         }
145 }
146
147 bNodeType cmp_node_displace= {
148         /* *next,*prev */       NULL, NULL,
149         /* type code   */       CMP_NODE_DISPLACE,
150         /* name        */       "Displace",
151         /* width+range */       140, 100, 320,
152         /* class+opts  */       NODE_CLASS_DISTORT, NODE_OPTIONS,
153         /* input sock  */       cmp_node_displace_in,
154         /* output sock */       cmp_node_displace_out,
155         /* storage     */       "",
156         /* execfunc    */       node_composit_exec_displace, 
157         /* butfunc     */       NULL,
158         /* initfunc    */       NULL,
159         /* freestoragefunc    */        NULL,
160         /* copystoragefunc    */        NULL,
161         /* id          */       NULL
162 };
163