2 * Copyright 2011, Blender Foundation.
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.
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.
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.
23 #include "COM_ScreenLensDistortionOperation.h"
25 #include "BLI_utildefines.h"
30 ScreenLensDistortionOperation::ScreenLensDistortionOperation() : NodeOperation()
32 this->addInputSocket(COM_DT_COLOR);
33 this->addInputSocket(COM_DT_VALUE);
34 this->addInputSocket(COM_DT_VALUE);
35 this->addOutputSocket(COM_DT_COLOR);
36 this->setComplex(true);
37 this->m_inputProgram = NULL;
38 this->m_valuesAvailable = false;
39 this->m_dispersion = 0.0f;
40 this->m_distortion = 0.0f;
42 void ScreenLensDistortionOperation::initExecution()
44 this->m_inputProgram = this->getInputSocketReader(0);
46 this->m_cx = 0.5f * (float)getWidth();
47 this->m_cy = 0.5f * (float)getHeight();
51 void *ScreenLensDistortionOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers)
53 void *buffer = this->m_inputProgram->initializeTileData(NULL, memoryBuffers);
54 updateDispersionAndDistortion(memoryBuffers);
58 void ScreenLensDistortionOperation::executePixel(float *outputColor, int x, int y, MemoryBuffer *inputBuffers[], void *data)
60 const float height = this->getHeight();
61 const float width = this->getWidth();
62 MemoryBuffer *buffer = (MemoryBuffer *)data;
64 int dr = 0, dg = 0, db = 0;
65 float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
66 float tc[4] = {0, 0, 0, 0};
67 const float v = this->m_sc * ((y + 0.5f) - this->m_cy) / this->m_cy;
68 const float u = this->m_sc * ((x + 0.5f) - this->m_cx) / this->m_cx;
69 const float uv_dot = u * u + v * v;
70 int sta = 0, mid = 0, end = 0;
72 if ((t = 1.f - this->m_kr4 * uv_dot) >= 0.f) {
73 d = 1.f / (1.f + sqrtf(t));
74 ln[0] = (u * d + 0.5f) * width - 0.5f, ln[1] = (v * d + 0.5f) * height - 0.5f;
77 if ((t = 1.f - this->m_kg4 * uv_dot) >= 0.f) {
78 d = 1.f / (1.f + sqrtf(t));
79 ln[2] = (u * d + 0.5f) * width - 0.5f, ln[3] = (v * d + 0.5f) * height - 0.5f;
82 if ((t = 1.f - this->m_kb4 * uv_dot) >= 0.f) {
83 d = 1.f / (1.f + sqrtf(t));
84 ln[4] = (u * d + 0.5f) * width - 0.5f, ln[5] = (v * d + 0.5f) * height - 0.5f;
88 if (sta && mid && end) {
89 float jit = this->m_data->jit;
94 const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
95 const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
96 const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
97 const float sd = 1.f / (float)ds;
99 for (z = 0; z < ds; ++z) {
100 const float tz = ((float)z + (jit ? BLI_frand() : 0.5f)) * sd;
101 t = 1.0f - (this->m_kr4 + tz * this->m_drg) * uv_dot;
102 d = 1.0f / (1.f + sqrtf(t));
103 const float nx = (u * d + 0.5f) * width - 0.5f;
104 const float ny = (v * d + 0.5f) * height - 0.5f;
105 buffer->readCubic(color, nx, ny);
106 tc[0] += (1.f - tz) * color[0], tc[1] += tz * color[1];
112 const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
113 const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
114 const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
115 const float sd = 1.f / (float)ds;
117 for (z = 0; z < ds; ++z) {
118 const float tz = ((float)z + (jit ? BLI_frand() : 0.5f)) * sd;
119 t = 1.f - (this->m_kg4 + tz * this->m_dgb) * uv_dot;
120 d = 1.f / (1.f + sqrtf(t));
121 const float nx = (u * d + 0.5f) * width - 0.5f;
122 const float ny = (v * d + 0.5f) * height - 0.5f;
123 buffer->readCubic(color, nx, ny);
124 tc[1] += (1.f - tz) * color[1], tc[2] += tz * color[2];
129 if (dr) outputColor[0] = 2.0f * tc[0] / (float)dr;
130 if (dg) outputColor[1] = 2.0f * tc[1] / (float)dg;
131 if (db) outputColor[2] = 2.0f * tc[2] / (float)db;
134 outputColor[3] = 1.0f;
137 outputColor[0] = 0.0f;
138 outputColor[1] = 0.0f;
139 outputColor[2] = 0.0f;
140 outputColor[3] = 0.0f;
144 void ScreenLensDistortionOperation::deinitExecution()
147 this->m_inputProgram = NULL;
150 void ScreenLensDistortionOperation::determineUV(float result[4], float x, float y, float distortion, float dispersion)
152 if (!this->m_valuesAvailable) {
153 updateVariables(distortion, dispersion);
155 determineUV(result, x, y);
158 void ScreenLensDistortionOperation::determineUV(float result[4], float x, float y) const
160 const float height = this->getHeight();
161 const float width = this->getWidth();
163 float d, t, ln[6] = {0, 0, 0, 0, 0, 0};
164 const float v = this->m_sc * ((y + 0.5f) - this->m_cy) / this->m_cy;
165 const float u = this->m_sc * ((x + 0.5f) - this->m_cx) / this->m_cx;
166 const float uv_dot = u * u + v * v;
168 if ((t = 1.f - this->m_kr4 * uv_dot) >= 0.f) {
169 d = 1.f / (1.f + sqrtf(t));
170 ln[0] = (u * d + 0.5f) * width - 0.5f, ln[1] = (v * d + 0.5f) * height - 0.5f;
172 if ((t = 1.f - this->m_kg4 * uv_dot) >= 0.f) {
173 d = 1.f / (1.f + sqrtf(t));
174 ln[2] = (u * d + 0.5f) * width - 0.5f, ln[3] = (v * d + 0.5f) * height - 0.5f;
176 if ((t = 1.f - this->m_kb4 * uv_dot) >= 0.f) {
177 d = 1.f / (1.f + sqrtf(t));
178 ln[4] = (u * d + 0.5f) * width - 0.5f, ln[5] = (v * d + 0.5f) * height - 0.5f;
181 float jit = this->m_data->jit;
185 const int dx = ln[2] - ln[0], dy = ln[3] - ln[1];
186 const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
187 const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
188 const float sd = 1.f / (float)ds;
191 const float tz = ((float)z + (1.0f)) * sd;
192 t = 1.0f - (this->m_kr4 + tz * this->m_drg) * uv_dot;
193 d = 1.0f / (1.f + sqrtf(t));
194 const float nx = (u * d + 0.5f) * width - 0.5f;
195 const float ny = (v * d + 0.5f) * height - 0.5f;
201 const int dx = ln[4] - ln[2], dy = ln[5] - ln[3];
202 const float dsf = sqrtf((float)dx * dx + dy * dy) + 1.f;
203 const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf);
204 const float sd = 1.f / (float)ds;
207 const float tz = ((float)z + (1.0f)) * sd;
208 t = 1.f - (this->m_kg4 + tz * this->m_dgb) * uv_dot;
209 d = 1.f / (1.f + sqrtf(t));
210 const float nx = (u * d + 0.5f) * width - 0.5f;
211 const float ny = (v * d + 0.5f) * height - 0.5f;
217 bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
220 newInputValue.xmin = 0;
221 newInputValue.ymin = 0;
222 newInputValue.xmax = 2;
223 newInputValue.ymax = 2;
225 NodeOperation *operation = getInputOperation(1);
226 if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
230 operation = getInputOperation(2);
231 if (operation->determineDependingAreaOfInterest(&newInputValue, readOperation, output) ) {
237 #define UPDATE_INPUT \
238 newInput.xmin = MIN3(newInput.xmin, coords[0], coords[2]); \
239 newInput.ymin = MIN3(newInput.ymin, coords[1], coords[3]); \
240 newInput.xmax = MAX3(newInput.xmax, coords[0], coords[2]); \
241 newInput.ymax = MAX3(newInput.ymax, coords[1], coords[3]);
246 if (m_valuesAvailable) {
247 determineUV(coords, input->xmin, input->ymin);
248 newInput.xmin = coords[0];
249 newInput.ymin = coords[1];
250 newInput.xmax = coords[0];
251 newInput.ymax = coords[1];
253 determineUV(coords, input->xmin, input->ymax);
255 determineUV(coords, input->xmax, input->ymax);
257 determineUV(coords, input->xmax, input->ymin);
259 margin = (ABS(this->m_distortion) + this->m_dispersion) * MARGIN;
263 determineUV(coords, input->xmin, input->ymin, 1.0f, 1.0f);
264 newInput.xmin = coords[0];
265 newInput.ymin = coords[1];
266 newInput.xmax = coords[0];
267 newInput.ymax = coords[1];
269 determineUV(coords, input->xmin, input->ymin, -1.0f, 1.0f);
272 determineUV(coords, input->xmin, input->ymax, -1.0f, 1.0f);
274 determineUV(coords, input->xmin, input->ymax, 1.0f, 1.0f);
277 determineUV(coords, input->xmax, input->ymax, -1.0f, 1.0f);
279 determineUV(coords, input->xmax, input->ymax, 1.0f, 1.0f);
282 determineUV(coords, input->xmax, input->ymin, -1.0f, 1.0f);
284 determineUV(coords, input->xmax, input->ymin, 1.0f, 1.0f);
290 newInput.xmin -= margin;
291 newInput.ymin -= margin;
292 newInput.xmax += margin;
293 newInput.ymax += margin;
295 operation = getInputOperation(0);
296 if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
302 void ScreenLensDistortionOperation::updateVariables(float distortion, float dispersion)
304 this->m_kg = MAX2(MIN2(distortion, 1.f), -0.999f);
305 // smaller dispersion range for somewhat more control
306 const float d = 0.25f * MAX2(MIN2(dispersion, 1.f), 0.f);
307 this->m_kr = MAX2(MIN2((this->m_kg + d), 1.0f), -0.999f);
308 this->m_kb = MAX2(MIN2((this->m_kg - d), 1.0f), -0.999f);
309 this->m_maxk = MAX3(this->m_kr, this->m_kg, this->m_kb);
310 this->m_sc = (this->m_data->fit && (this->m_maxk > 0.f)) ? (1.f / (1.f + 2.f * this->m_maxk)) : (1.f / (1.f + this->m_maxk));
311 this->m_drg = 4.f * (this->m_kg - this->m_kr);
312 this->m_dgb = 4.f * (this->m_kb - this->m_kg);
314 this->m_kr4 = this->m_kr * 4.0f;
315 this->m_kg4 = this->m_kg * 4.0f;
316 this->m_kb4 = this->m_kb * 4.0f;
319 void ScreenLensDistortionOperation::updateDispersionAndDistortion(MemoryBuffer **inputBuffers)
321 if (this->m_valuesAvailable) return;
324 if (!this->m_valuesAvailable) {
326 this->getInputSocketReader(1)->read(result, 0, 0, COM_PS_NEAREST, inputBuffers);
327 this->m_distortion = result[0];
328 this->getInputSocketReader(2)->read(result, 0, 0, COM_PS_NEAREST, inputBuffers);
329 this->m_dispersion = result[0];
330 updateVariables(this->m_distortion, this->m_dispersion);
331 this->m_valuesAvailable = true;