Possible fix for bug #6922: crash in displace compositor node,
[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, vx, vy, 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                         /* this happens in compbuf_get_pixel, need to make sure the following
77                          * check takes them into account */
78                         vx= x-vecbuf->xof;
79                         vy= y-vecbuf->yof;
80                         
81                         /* find the new displaced co-ords, also correcting for translate offset */
82                         dspx = vx - (*xscale * vp[0]);
83                         dspy = vy - (*yscale * vp[1]);
84
85                         /* convert image space to 0.0-1.0 UV space for sampling, correcting for translate offset */
86                         uv[0] = dspx / (float)sx;
87                         uv[1] = dspy / (float)sy;
88                 
89                         if(vx>0 && vx< vecbuf->x-1 && vy>0 && vy< vecbuf->y-1)  {
90                                 vpnext = vp+row;
91                                 vpprev = vp-row;
92                         
93                                 /* adaptive sampling, X channel */
94                                 dx= 0.5f*(fabs(vp[0]-vp[-3]) + fabs(vp[0]-vp[3]));
95                                 
96                                 dx+= 0.25f*(fabs(vp[0]-vpprev[-3]) + fabs(vp[0]-vpnext[-3]));
97                                 dx+= 0.25f*(fabs(vp[0]-vpprev[+3]) + fabs(vp[0]-vpnext[+3]));
98                                 
99                                 /* adaptive sampling, Y channel */
100                                 dy= 0.5f*(fabs(vp[1]-vp[-row+1]) + fabs(vp[1]-vp[row+1]));
101                                                  
102                                 dy+= 0.25f*(fabs(vp[1]-vpprev[+1-3]) + fabs(vp[1]-vpnext[+1-3]));
103                                 dy+= 0.25f*(fabs(vp[1]-vpprev[+1+3]) + fabs(vp[1]-vpnext[+1+3]));
104                                 
105                                 /* scaled down to prevent blurriness */
106                                 /* 8: magic number, provides a good level of sharpness without getting too aliased */
107                                 dx /= 8;
108                                 dy /= 8;
109                         }
110
111                         /* should use mipmap */
112                         if(dx > 0.006f) dx= 0.006f;
113                         if(dy > 0.006f) dy= 0.006f;
114                         if ((vp[0]> 0.0) && (dx < 0.004)) dx = 0.004;
115                         if ((vp[1]> 0.0) && (dy < 0.004)) dy = 0.004;
116                         
117
118                         ibuf_sample(ibuf, uv[0], uv[1], dx, dy, out);
119                 }
120         }
121
122         IMB_freeImBuf(ibuf);    
123 }
124
125
126 static void node_composit_exec_displace(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
127 {
128         if(out[0]->hasoutput==0)
129                 return;
130         
131         if(in[0]->data && in[1]->data) {
132                 CompBuf *cbuf= in[0]->data;
133                 CompBuf *vecbuf= in[1]->data;
134                 CompBuf *stackbuf;
135                 
136                 cbuf= typecheck_compbuf(cbuf, CB_RGBA);
137                 vecbuf= typecheck_compbuf(vecbuf, CB_VEC3);
138                 stackbuf= alloc_compbuf(cbuf->x, cbuf->y, CB_RGBA, 1); /* allocs */
139
140                 do_displace(stackbuf, cbuf, vecbuf, in[1]->vec, in[2]->vec, in[3]->vec);
141                 
142                 out[0]->data= stackbuf;
143                 
144                 
145                 if(cbuf!=in[0]->data)
146                         free_compbuf(cbuf);
147                 if(vecbuf!=in[1]->data)
148                         free_compbuf(vecbuf);
149         }
150 }
151
152 bNodeType cmp_node_displace= {
153         /* *next,*prev */       NULL, NULL,
154         /* type code   */       CMP_NODE_DISPLACE,
155         /* name        */       "Displace",
156         /* width+range */       140, 100, 320,
157         /* class+opts  */       NODE_CLASS_DISTORT, NODE_OPTIONS,
158         /* input sock  */       cmp_node_displace_in,
159         /* output sock */       cmp_node_displace_out,
160         /* storage     */       "",
161         /* execfunc    */       node_composit_exec_displace, 
162         /* butfunc     */       NULL,
163         /* initfunc    */       NULL,
164         /* freestoragefunc    */        NULL,
165         /* copystoragefunc    */        NULL,
166         /* id          */       NULL
167 };
168