Remove ifdef-ed code, it's still in SVn anyway.
[blender.git] / source / blender / compositor / operations / COM_PlaneTrackWarpImageOperation.cpp
1 /*
2  * Copyright 2013, 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  *              Sergey Sharybin
20  */
21
22 #include "COM_PlaneTrackWarpImageOperation.h"
23 #include "COM_ReadBufferOperation.h"
24
25 #include "MEM_guardedalloc.h"
26
27 #include "BLI_listbase.h"
28 #include "BLI_math.h"
29 #include "BLI_math_color.h"
30
31 extern "C" {
32         #include "BLI_jitter.h"
33
34         #include "BKE_movieclip.h"
35         #include "BKE_node.h"
36         #include "BKE_tracking.h"
37 }
38
39 BLI_INLINE bool isPointInsideQuad(const float x, const float y, const float corners[4][2])
40 {
41         float point[2];
42
43         point[0] = x;
44         point[1] = y;
45
46         return isect_point_tri_v2(point, corners[0], corners[1], corners[2]) ||
47                isect_point_tri_v2(point, corners[0], corners[2], corners[3]);
48 }
49
50 BLI_INLINE bool resolveUV(const float x, const float y, const float corners[4][2], float uv[2])
51 {
52         float point[2];
53         bool inside;
54
55         inside = isPointInsideQuad(x, y, corners);
56
57         point[0] = x;
58         point[1] = y;
59
60         /* Use reverse bilinear to get UV coordinates within original frame */
61         resolve_quad_uv(uv, point, corners[0], corners[1], corners[2], corners[3]);
62
63         return inside;
64 }
65
66 BLI_INLINE void resolveUVAndDxDy(const float x, const float y, const float corners[4][2],
67                                  float *u_r, float *v_r, float *dx_r, float *dy_r)
68 {
69         float inputUV[2];
70         float uv_a[2], uv_b[2];
71
72         float dx, dy;
73         float uv_l, uv_r;
74         float uv_u, uv_d;
75
76         bool ok1, ok2;
77
78         resolveUV(x, y, corners, inputUV);
79
80         /* adaptive sampling, red (U) channel */
81         ok1 = resolveUV(x - 1, y, corners, uv_a);
82         ok2 = resolveUV(x + 1, y, corners, uv_b);
83         uv_l = ok1 ? fabsf(inputUV[0] - uv_a[0]) : 0.0f;
84         uv_r = ok2 ? fabsf(inputUV[0] - uv_b[0]) : 0.0f;
85
86         dx = 0.5f * (uv_l + uv_r);
87
88         /* adaptive sampling, green (V) channel */
89         ok1 = resolveUV(x, y - 1, corners, uv_a);
90         ok2 = resolveUV(x, y + 1, corners, uv_b);
91         uv_u = ok1 ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
92         uv_d = ok2 ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
93
94         dy = 0.5f * (uv_u + uv_d);
95
96         *dx_r = dx;
97         *dy_r = dy;
98
99         *u_r = inputUV[0];
100         *v_r = inputUV[1];
101 }
102
103 PlaneTrackWarpImageOperation::PlaneTrackWarpImageOperation() : PlaneTrackCommonOperation()
104 {
105         this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
106         this->addOutputSocket(COM_DT_COLOR);
107         this->m_pixelReader = NULL;
108         this->setComplex(true);
109 }
110
111 void PlaneTrackWarpImageOperation::initExecution()
112 {
113         PlaneTrackCommonOperation::initExecution();
114
115         this->m_pixelReader = this->getInputSocketReader(0);
116
117         const int osa = 8;
118         this->m_osa = osa;
119         BLI_jitter_init(this->m_jitter[0], osa);
120 }
121
122 void PlaneTrackWarpImageOperation::deinitExecution()
123 {
124         this->m_pixelReader = NULL;
125 }
126
127 void PlaneTrackWarpImageOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
128 {
129         float color_accum[4];
130
131         zero_v4(color_accum);
132         for (int sample = 0; sample < this->m_osa; sample++) {
133                 float current_x = x + this->m_jitter[sample][0],
134                       current_y = y + this->m_jitter[sample][1];
135                 if (isPointInsideQuad(current_x, current_y, this->m_frameSpaceCorners)) {
136                         float current_color[4];
137                         float u, v, dx, dy;
138
139                         resolveUVAndDxDy(current_x, current_y, this->m_frameSpaceCorners, &u, &v, &dx, &dy);
140
141                         u *= this->m_pixelReader->getWidth();
142                         v *= this->m_pixelReader->getHeight();
143
144                         this->m_pixelReader->read(current_color, u, v, dx, dy, COM_PS_NEAREST);
145                         premul_to_straight_v4(current_color);
146                         add_v4_v4(color_accum, current_color);
147                 }
148         }
149
150         mul_v4_v4fl(output, color_accum, 1.0f / this->m_osa);
151         straight_to_premul_v4(output);
152 }
153
154 bool PlaneTrackWarpImageOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
155 {
156         float frame_space_corners[4][2];
157
158         for (int i = 0; i < 4; i++) {
159                 frame_space_corners[i][0] = this->m_corners[i][0] * this->getWidth();
160                 frame_space_corners[i][1] = this->m_corners[i][1] * this->getHeight();
161         }
162
163         float UVs[4][2];
164
165         /* TODO(sergey): figure out proper way to do this. */
166         resolveUV(input->xmin - 2, input->ymin - 2, frame_space_corners, UVs[0]);
167         resolveUV(input->xmax + 2, input->ymin - 2, frame_space_corners, UVs[1]);
168         resolveUV(input->xmax + 2, input->ymax + 2, frame_space_corners, UVs[2]);
169         resolveUV(input->xmin - 2, input->ymax + 2, frame_space_corners, UVs[3]);
170
171         float min[2], max[2];
172         INIT_MINMAX2(min, max);
173         for (int i = 0; i < 4; i++) {
174                 minmax_v2v2_v2(min, max, UVs[i]);
175         }
176
177         rcti newInput;
178
179         newInput.xmin = min[0] * readOperation->getWidth() - 1;
180         newInput.ymin = min[1] * readOperation->getHeight() - 1;
181         newInput.xmax = max[0] * readOperation->getWidth() + 1;
182         newInput.ymax = max[1] * readOperation->getHeight() + 1;
183
184         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
185 }