diff options
Diffstat (limited to 'source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp')
-rw-r--r-- | source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp new file mode 100644 index 00000000000..4a4ac6c6833 --- /dev/null +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp @@ -0,0 +1,164 @@ +/* + * Copyright 2011, Blender Foundation. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Contributor: + * Jeroen Bakker + * Monique Dewanchand + */ + +#include "COM_ScreenLensDistortionOperation.h" +#include "BLI_math.h" +#include "BLI_utildefines.h" +extern "C" { + #include "BLI_rand.h" +} + +ScreenLensDistortionOperation::ScreenLensDistortionOperation(): NodeOperation() { + this->addInputSocket(COM_DT_COLOR); + this->addOutputSocket(COM_DT_COLOR); + this->setComplex(true); + this->inputProgram = NULL; +} +void ScreenLensDistortionOperation::initExecution() { + this->inputProgram = this->getInputSocketReader(0); + kg = MAX2(MIN2(this->distortion, 1.f), -0.999f); + // smaller dispersion range for somewhat more control + const float d = 0.25f*MAX2(MIN2(this->dispersion, 1.f), 0.f); + kr = MAX2(MIN2((kg+d), 1.f), -0.999f); + kb = MAX2(MIN2((kg-d), 1.f), -0.999f); + maxk = MAX3(kr, kg, kb); + sc = (this->data->fit && (maxk > 0.f)) ? (1.f/(1.f + 2.f*maxk)) : (1.f/(1.f + maxk)); + drg = 4.f*(kg - kr); + dgb = 4.f*(kb - kg); + + kr4 = kr*4; + kg4 = kg*4.f; + kb4 *= kb*4.f; + cx = 0.5f*(float)getWidth(); + cy = 0.5f*(float)getHeight(); + +} + +void* ScreenLensDistortionOperation::initializeTileData(rcti *rect, MemoryBuffer **memoryBuffers) { + void* buffer = inputProgram->initializeTileData(NULL, memoryBuffers); + return buffer; +} + +void ScreenLensDistortionOperation::executePixel(float* outputColor, int x, int y, MemoryBuffer *inputBuffers[], void* data) { + const float height = this->getHeight(); + const float width = this->getWidth(); + MemoryBuffer* buffer = (MemoryBuffer*)data; + + int dr = 0, dg = 0, db = 0; + float d, t, ln[6] = {0, 0, 0, 0, 0, 0}; + float tc[4] = {0, 0, 0, 0}; + const float v = sc*((y + 0.5f) - cy)/cy; + const float u = sc*((x + 0.5f) - cx)/cx; + int sta = 0, mid = 0, end = 0; + + if ((t = 1.f - kr4*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[0] = (u*d + 0.5f)*width - 0.5f, ln[1] = (v*d + 0.5f)*height - 0.5f; + sta = 1; + } + if ((t = 1.f - kg4*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[2] = (u*d + 0.5f)*width - 0.5f, ln[3] = (v*d + 0.5f)*height - 0.5f; + mid = 1; + } + if ((t = 1.f - kb4*(u*u + v*v)) >= 0.f) { + d = 1.f/(1.f + sqrtf(t)); + ln[4] = (u*d + 0.5f)*width - 0.5f, ln[5] = (v*d + 0.5f)*height - 0.5f; + end = 1; + } + + if (sta && mid && end) { + float jit = this->data->jit; + float z; + float color[4]; + { + // RG + const int dx = ln[2] - ln[0], dy = ln[3] - ln[1]; + const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; + const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); + const float sd = 1.f/(float)ds; + + for (z=0; z<ds; ++z) { + const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd; + t = 1.f - (kr4 + tz*drg)*(u*u + v*v); + d = 1.f / (1.f + sqrtf(t)); + const float nx = (u*d + 0.5f)*getWidth() - 0.5f; + const float ny = (v*d + 0.5f)*getHeight() - 0.5f; + buffer->readCubic(color, nx, ny); + tc[0] += (1.f-tz)*color[0], tc[1] += tz*color[1]; + dr++, dg++; + } + } + { + // GB + const int dx = ln[4] - ln[2], dy = ln[5] - ln[3]; + const float dsf = sqrtf(dx*dx + dy*dy) + 1.f; + const int ds = (int)(jit ? ((dsf < 4.f) ? 2.f : sqrtf(dsf)) : dsf); + const float sd = 1.f/(float)ds; + + for (z=0; z<ds; ++z) { + const float tz = ((float)z + (jit ? BLI_frand() : 0.5f))*sd; + t = 1.f - (kg4 + tz*dgb)*(u*u + v*v); + d = 1.f / (1.f + sqrtf(t)); + const float nx = (u*d + 0.5f)*getWidth() - 0.5f; + const float ny = (v*d + 0.5f)*getHeight() - 0.5f; + buffer->readCubic(color, nx, ny); + tc[1] += (1.f-tz)*color[1], tc[2] += tz*color[2]; + dg++, db++; + } + + } + if (dr) outputColor[0] = 2.f*tc[0] / (float)dr; + if (dg) outputColor[1] = 2.f*tc[1] / (float)dg; + if (db) outputColor[2] = 2.f*tc[2] / (float)db; + + /* set alpha */ + outputColor[3]= 1.0f; + } else { + outputColor[0]= 0.0f; + outputColor[1]= 0.0f; + outputColor[2]= 0.0f; + outputColor[3]= 0.0f; + } +} + +void ScreenLensDistortionOperation::deinitExecution() { + this->inputProgram = NULL; +} + +void ScreenLensDistortionOperation::determineUV(float result[2], float x, float y) const { + const float v = sc*((y + 0.5f) - cy)/cy; + const float u = sc*((x + 0.5f) - cx)/cx; + const float t = ABS(MIN3(kr, kg, kb)*4); + float d = 1.f/(1.f + sqrtf(t)); + result[0] = (u*d + 0.5f)*getWidth() - 0.5f; + result[1] = (v*d + 0.5f)*getHeight() - 0.5f; +} + +bool ScreenLensDistortionOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { + rcti newInput; + newInput.xmin = 0; + newInput.ymin = 0; + newInput.ymax = inputProgram->getHeight(); + newInput.xmax = inputProgram->getWidth(); + return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output); +} |