Compositor: Speedup movie (un)distortion operation
[blender.git] / source / blender / compositor / operations / COM_MovieDistortionOperation.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  *              Jeroen Bakker
20  *              Monique Dewanchand
21  *              Sergey Sharybin
22  */
23
24 #include "COM_MovieDistortionOperation.h"
25
26 extern "C" {
27 #  include "BKE_tracking.h"
28 #  include "BKE_movieclip.h"
29 #  include "BLI_linklist.h"
30 }
31
32
33 MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperation()
34 {
35         this->addInputSocket(COM_DT_COLOR);
36         this->addOutputSocket(COM_DT_COLOR);
37         this->setResolutionInputSocketIndex(0);
38         this->m_inputOperation = NULL;
39         this->m_movieClip = NULL;
40         this->m_apply = distortion;
41 }
42
43 void MovieDistortionOperation::initExecution()
44 {
45         this->m_inputOperation = this->getInputSocketReader(0);
46         if (this->m_movieClip) {
47                 MovieTracking *tracking = &this->m_movieClip->tracking;
48                 MovieClipUser clipUser = {0};
49                 int calibration_width, calibration_height;
50
51                 BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber);
52                 BKE_movieclip_get_size(this->m_movieClip,
53                                        &clipUser,
54                                        &calibration_width,
55                                        &calibration_height);
56
57                 float delta[2];
58                 rcti full_frame;
59                 full_frame.xmin = full_frame.ymin = 0;
60                 full_frame.xmax = this->m_width;
61                 full_frame.ymax = this->m_height;
62                 BKE_tracking_max_distortion_delta_across_bound(tracking,
63                                                                &full_frame,
64                                                                !this->m_apply,
65                                                                delta);
66
67                 /* 5 is just in case we didn't hit real max of distortion in
68                  * BKE_tracking_max_undistortion_delta_across_bound
69                  */
70                 m_margin[0] = delta[0] + 5;
71                 m_margin[1] = delta[1] + 5;
72
73                 this->m_distortion = BKE_tracking_distortion_new(tracking,
74                                                                  calibration_width,
75                                                                  calibration_height);
76                 this->m_calibration_width = calibration_width;
77                 this->m_calibration_height = calibration_height;
78                 this->m_pixel_aspect = tracking->camera.pixel_aspect;
79         }
80         else {
81                 m_margin[0] = m_margin[1] = 0;
82                 this->m_distortion = NULL;
83         }
84 }
85
86 void MovieDistortionOperation::deinitExecution()
87 {
88         this->m_inputOperation = NULL;
89         this->m_movieClip = NULL;
90         if (this->m_distortion != NULL) {
91                 BKE_tracking_distortion_free(this->m_distortion);
92         }
93 }
94
95 void MovieDistortionOperation::executePixelSampled(float output[4],
96                                                    float x,
97                                                    float y,
98                                                    PixelSampler /*sampler*/)
99 {
100         if (this->m_distortion != NULL) {
101                 /* float overscan = 0.0f; */
102                 const float pixel_aspect = this->m_pixel_aspect;
103                 const float w = (float)this->m_width /* / (1 + overscan) */;
104                 const float h = (float)this->m_height /* / (1 + overscan) */;
105                 const float aspx = w / (float)this->m_calibration_width;
106                 const float aspy = h / (float)this->m_calibration_height;
107                 float in[2];
108                 float out[2];
109
110                 in[0] = (x /* - 0.5 * overscan * w */) / aspx;
111                 in[1] = (y /* - 0.5 * overscan * h */) / aspy / pixel_aspect;
112
113                 if (this->m_apply) {
114                         BKE_tracking_distortion_undistort_v2(this->m_distortion, in, out);
115                 }
116                 else {
117                         BKE_tracking_distortion_distort_v2(this->m_distortion, in, out);
118                 }
119
120                 float u = out[0] * aspx /* + 0.5 * overscan * w */,
121                       v = (out[1] * aspy /* + 0.5 * overscan * h */) * pixel_aspect;
122
123                 this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR);
124         }
125         else {
126                 this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR);
127         }
128 }
129
130 bool MovieDistortionOperation::determineDependingAreaOfInterest(
131         rcti *input,
132         ReadBufferOperation *readOperation,
133         rcti *output)
134 {
135         rcti newInput;
136         newInput.xmin = input->xmin - m_margin[0];
137         newInput.ymin = input->ymin - m_margin[1];
138         newInput.xmax = input->xmax + m_margin[0];
139         newInput.ymax = input->ymax + m_margin[1];
140         return NodeOperation::determineDependingAreaOfInterest(&newInput,
141                                                                readOperation,
142                                                                output);
143 }