4f34d7fb150415714bd9e3492644f096bcbedfe9
[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  */
22
23 #include "COM_MovieDistortionOperation.h"
24
25 extern "C" {
26 #  include "BKE_tracking.h"
27 #  include "BKE_movieclip.h"
28 #  include "BLI_linklist.h"
29 }
30
31
32 static vector<DistortionCache *> s_cache;
33
34 void deintializeDistortionCache(void) 
35 {
36         while (s_cache.size() > 0) {
37                 DistortionCache * cache = s_cache.back();
38                 s_cache.pop_back();
39                 delete cache;
40         }
41 }
42
43 MovieDistortionOperation::MovieDistortionOperation(bool distortion) : NodeOperation()
44 {
45         this->addInputSocket(COM_DT_COLOR);
46         this->addOutputSocket(COM_DT_COLOR);
47         this->setResolutionInputSocketIndex(0);
48         this->m_inputOperation = NULL;
49         this->m_movieClip = NULL;
50         this->m_cache = NULL;
51         this->m_distortion = distortion;
52 }
53
54 void MovieDistortionOperation::initExecution()
55 {
56         this->m_inputOperation = this->getInputSocketReader(0);
57         if (this->m_movieClip) {
58                 MovieClipUser clipUser = {0};
59                 int calibration_width, calibration_height;
60
61                 BKE_movieclip_user_set_frame(&clipUser, this->m_framenumber);
62                 BKE_movieclip_get_size(this->m_movieClip, &clipUser, &calibration_width, &calibration_height);
63
64                 for (unsigned int i = 0; i < s_cache.size(); i++) {
65                         DistortionCache *c = (DistortionCache *)s_cache[i];
66                         if (c->isCacheFor(this->m_movieClip, this->m_width, this->m_height,
67                                           calibration_width, calibration_height, this->m_distortion))
68                         {
69                                 this->m_cache = c;
70                                 this->m_cache->updateLastUsage();
71                                 this->m_cache->getMargin(this->m_margin);
72                                 return;
73                         }
74                 }
75
76                 float delta[2];
77                 rcti full_frame;
78                 full_frame.xmin = full_frame.ymin = 0;
79                 full_frame.xmax = this->m_width;
80                 full_frame.ymax = this->m_height;
81                 BKE_tracking_max_distortion_delta_across_bound(
82                         &this->m_movieClip->tracking, &full_frame,
83                         !this->m_distortion, delta);
84
85                 /* 5 is just in case we didn't hit real max of distortion in
86                  * BKE_tracking_max_undistortion_delta_across_bound
87                  */
88                 m_margin[0] = delta[0] + 5;
89                 m_margin[1] = delta[1] + 5;
90
91                 DistortionCache *newC = new DistortionCache(this->m_movieClip,
92                                                             this->m_width, this->m_height,
93                                                             calibration_width, calibration_height,
94                                                             this->m_distortion,
95                                                             this->m_margin);
96                 s_cache.push_back(newC);
97                 this->m_cache = newC;
98         }
99         else {
100                 this->m_cache = NULL;
101                 m_margin[0] = m_margin[1] = 0;
102         }
103 }
104
105 void MovieDistortionOperation::deinitExecution()
106 {
107         this->m_inputOperation = NULL;
108         this->m_movieClip = NULL;
109         while (s_cache.size() > COM_DISTORTIONCACHE_MAXSIZE) {
110                 double minTime = PIL_check_seconds_timer();
111                 vector<DistortionCache*>::iterator minTimeIterator = s_cache.begin();
112                 for (vector<DistortionCache*>::iterator it = s_cache.begin(); it < s_cache.end(); it ++) {
113                         DistortionCache * cache = *it;
114                         if (cache->getTimeLastUsage() < minTime) {
115                                 minTime = cache->getTimeLastUsage();
116                                 minTimeIterator = it;
117                         }
118                 }
119                 s_cache.erase(minTimeIterator);
120         }
121 }
122
123
124 void MovieDistortionOperation::executePixelSampled(float output[4], float x, float y, PixelSampler /*sampler*/)
125 {
126         
127         if (this->m_cache != NULL) {
128                 float u, v;
129                 this->m_cache->getUV(&this->m_movieClip->tracking, x, y, &u, &v);
130                 this->m_inputOperation->readSampled(output, u, v, COM_PS_BILINEAR);
131         }
132         else {
133                 this->m_inputOperation->readSampled(output, x, y, COM_PS_BILINEAR);
134         }
135 }
136
137 bool MovieDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
138 {
139         rcti newInput;
140         newInput.xmin = input->xmin - m_margin[0];
141         newInput.ymin = input->ymin - m_margin[1];
142         newInput.xmax = input->xmax + m_margin[0];
143         newInput.ymax = input->ymax + m_margin[1];
144         return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
145 }