compositor - EWA filter was blurring too much by default, this caused the displace...
[blender.git] / source / blender / compositor / operations / COM_DisplaceOperation.cpp
1 /*
2  * Copyright 2011, Blender Foundation.
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  * Contributor:
19  *              Dalai Felinto
20  */
21
22 #include "COM_DisplaceOperation.h"
23 #include "BLI_math.h"
24 #include "BLI_utildefines.h"
25
26 DisplaceOperation::DisplaceOperation() : NodeOperation()
27 {
28         this->addInputSocket(COM_DT_COLOR);
29         this->addInputSocket(COM_DT_VECTOR);
30         this->addInputSocket(COM_DT_VALUE);
31         this->addInputSocket(COM_DT_VALUE);
32         this->addOutputSocket(COM_DT_COLOR);
33         this->setComplex(true);
34
35         this->m_inputColorProgram = NULL;
36         this->m_inputVectorProgram = NULL;
37         this->m_inputScaleXProgram = NULL;
38         this->m_inputScaleYProgram = NULL;
39 }
40
41 void DisplaceOperation::initExecution()
42 {
43         this->m_inputColorProgram = this->getInputSocketReader(0);
44         this->m_inputVectorProgram = this->getInputSocketReader(1);
45         this->m_inputScaleXProgram = this->getInputSocketReader(2);
46         this->m_inputScaleYProgram = this->getInputSocketReader(3);
47
48         this->m_width_x4 = this->getWidth() * 4;
49         this->m_height_x4 = this->getHeight() * 4;
50 }
51
52
53 /* minimum distance (in pixels) a pixel has to be displaced
54  * in order to take effect */
55 #define DISPLACE_EPSILON    0.01f
56
57 void DisplaceOperation::executePixel(float output[4], int x, int y, void *data)
58 {
59         float inVector[4];
60         float inScale[4];
61
62         float p_dx, p_dy;   /* main displacement in pixel space */
63         float d_dx, d_dy;
64         float dxt, dyt;
65         float u, v;
66
67         this->m_inputScaleXProgram->read(inScale, x, y, COM_PS_NEAREST);
68         float xs = inScale[0];
69         this->m_inputScaleYProgram->read(inScale, x, y, COM_PS_NEAREST);
70         float ys = inScale[0];
71
72         /* clamp x and y displacement to triple image resolution - 
73          * to prevent hangs from huge values mistakenly plugged in eg. z buffers */
74         CLAMP(xs, -this->m_width_x4, this->m_width_x4);
75         CLAMP(ys, -this->m_height_x4, this->m_height_x4);
76
77         this->m_inputVectorProgram->read(inVector, x, y, COM_PS_NEAREST);
78         p_dx = inVector[0] * xs;
79         p_dy = inVector[1] * ys;
80
81         /* displaced pixel in uv coords, for image sampling */
82         u = x - p_dx + 0.5f;
83         v = y - p_dy + 0.5f;
84
85         /* calc derivatives */
86         this->m_inputVectorProgram->read(inVector, x + 1, y, COM_PS_NEAREST);
87         d_dx = inVector[0] * xs;
88         this->m_inputVectorProgram->read(inVector, x, y + 1, COM_PS_NEAREST);
89         d_dy = inVector[1] * ys;
90
91         /* clamp derivatives to minimum displacement distance in UV space */
92         dxt = p_dx - d_dx;
93         dyt = p_dy - d_dy;
94
95         dxt = signf(dxt) * maxf(fabsf(dxt), DISPLACE_EPSILON) / this->getWidth();
96         dyt = signf(dyt) * maxf(fabsf(dyt), DISPLACE_EPSILON) / this->getHeight();
97
98         /* EWA filtering (without nearest it gets blurry with NO distortion) */
99         this->m_inputColorProgram->read(output, u, v, dxt, dyt, COM_PS_NEAREST);
100 }
101
102 void DisplaceOperation::deinitExecution()
103 {
104         this->m_inputColorProgram = NULL;
105         this->m_inputVectorProgram = NULL;
106         this->m_inputScaleXProgram = NULL;
107         this->m_inputScaleYProgram = NULL;
108 }
109
110 bool DisplaceOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
111 {
112         rcti colorInput;
113         rcti vectorInput;
114         NodeOperation *operation = NULL;
115
116         /* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */
117         /* image */
118         operation = getInputOperation(0);
119         colorInput.xmax = operation->getWidth();
120         colorInput.xmin = 0;
121         colorInput.ymax = operation->getHeight();
122         colorInput.ymin = 0;
123         if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
124                 return true;
125         }
126
127         /* vector */
128         operation = getInputOperation(1);
129         vectorInput.xmax = input->xmax + 2;
130         vectorInput.xmin = input->xmin;
131         vectorInput.ymax = input->ymax + 2;
132         vectorInput.ymin = input->ymin;
133         if (operation->determineDependingAreaOfInterest(&vectorInput, readOperation, output)) {
134                 return true;
135         }
136
137         /* scale x */
138         operation = getInputOperation(2);
139         if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
140                 return true;
141         }
142
143         /* scale y */
144         operation = getInputOperation(3);
145         if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
146                 return true;
147         }
148
149         return false;
150 }
151