diff options
Diffstat (limited to 'source/blender/compositor/operations/COM_MapUVOperation.cpp')
-rw-r--r-- | source/blender/compositor/operations/COM_MapUVOperation.cpp | 153 |
1 files changed, 153 insertions, 0 deletions
diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cpp new file mode 100644 index 00000000000..ef0c9004a7d --- /dev/null +++ b/source/blender/compositor/operations/COM_MapUVOperation.cpp @@ -0,0 +1,153 @@ +/* + * 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: + * Dalai Felinto + */ + +#include "COM_MapUVOperation.h" +#include "BLI_math.h" + +MapUVOperation::MapUVOperation(): NodeOperation() { + this->addInputSocket(COM_DT_COLOR); + this->addInputSocket(COM_DT_VECTOR); + this->addOutputSocket(COM_DT_COLOR); + this->alpha = 0.f; + this->setComplex(true); + + this->inputUVProgram = NULL; + this->inputColorProgram = NULL; +} + +void MapUVOperation::initExecution() { + this->inputColorProgram = this->getInputSocketReader(0); + this->inputUVProgram = this->getInputSocketReader(1); +} + +void MapUVOperation::executePixel(float* color, float x, float y, PixelSampler sampler, MemoryBuffer *inputBuffers[]) { + float inputUV[4]; + float uv_a[4], uv_b[4]; + float u,v; + + float dx, dy; + float uv_l, uv_r; + float uv_u, uv_d; + + this->inputUVProgram->read(inputUV, x, y, sampler, inputBuffers); + if (inputUV[2] == 0.f) { + color[0] = 0.f; + color[1] = 0.f; + color[2] = 0.f; + color[3] = 0.f; + return; + } + /* adaptive sampling, red (U) channel */ + this->inputUVProgram->read(uv_a, x-1, y, COM_PS_NEAREST, inputBuffers); + this->inputUVProgram->read(uv_b, x+1, y, COM_PS_NEAREST, inputBuffers); + uv_l= uv_a[2]!=0.f? fabs(inputUV[0] - uv_a[0]) : 0.f; + uv_r= uv_b[2]!=0.f? fabs(inputUV[0] - uv_b[0]) : 0.f; + + dx= 0.5f * (uv_l + uv_r); + + /* adaptive sampling, green (V) channel */ + this->inputUVProgram->read(uv_a, x, y-1, COM_PS_NEAREST, inputBuffers); + this->inputUVProgram->read(uv_b, x, y+1, COM_PS_NEAREST, inputBuffers); + uv_u= uv_a[2]!=0.f? fabs(inputUV[1] - uv_a[1]) : 0.f; + uv_d= uv_b[2]!=0.f? fabs(inputUV[1] - uv_b[1]) : 0.f; + + dy= 0.5f * (uv_u + uv_d); + + /* more adaptive sampling, red and green (UV) channels */ + this->inputUVProgram->read(uv_a, x-1, y-1, COM_PS_NEAREST, inputBuffers); + this->inputUVProgram->read(uv_b, x-1, y+1, COM_PS_NEAREST, inputBuffers); + uv_l= uv_a[2]!=0.f? fabsf(inputUV[0] - uv_a[0]) : 0.f; + uv_r= uv_b[2]!=0.f? fabsf(inputUV[0] - uv_b[0]) : 0.f; + uv_u= uv_a[2]!=0.f? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d= uv_b[2]!=0.f? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dx+= 0.25f * (uv_l + uv_r); + dy+= 0.25f * (uv_u + uv_d); + + this->inputUVProgram->read(uv_a, x+1, y-1, COM_PS_NEAREST, inputBuffers); + this->inputUVProgram->read(uv_b, x+1, y+1, COM_PS_NEAREST, inputBuffers); + uv_l= uv_a[2]!=0.f? fabsf(inputUV[0] - uv_a[0]) : 0.f; + uv_r= uv_b[2]!=0.f? fabsf(inputUV[0] - uv_b[0]) : 0.f; + uv_u= uv_a[2]!=0.f? fabsf(inputUV[1] - uv_a[1]) : 0.f; + uv_d= uv_b[2]!=0.f? fabsf(inputUV[1] - uv_b[1]) : 0.f; + + dx+= 0.25f * (uv_l + uv_r); + dy+= 0.25f * (uv_u + uv_d); + + /* UV to alpha threshold */ + const float threshold = this->alpha * 0.05f; + float alpha = 1.0f - threshold * (dx + dy); + if (alpha < 0.f) alpha= 0.f; + else alpha *= inputUV[2]; + + /* should use mipmap */ + dx= min(dx, 0.2f); + dy= min(dy, 0.2f); + + + /* EWA filtering */ + u = inputUV[0] * inputColorProgram->getWidth(); + v = inputUV[1] * inputColorProgram->getHeight(); + + this->inputColorProgram->read(color, u, v, dx, dy, inputBuffers); + + /* "premul" */ + if(alpha < 1.0f) { + color[0]*= alpha; + color[1]*= alpha; + color[2]*= alpha; + color[3]*= alpha; + } +} + +void MapUVOperation::deinitExecution() { + this->inputUVProgram = NULL; + this->inputColorProgram = NULL; +} + +bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output) { + rcti colorInput; + rcti uvInput; + NodeOperation *operation=NULL; + + /* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */ + + operation = getInputOperation(0); + colorInput.xmax = operation->getWidth(); + colorInput.xmin = 0; + colorInput.ymax = operation->getHeight(); + colorInput.ymin = 0; + if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) { + return true; + } + + operation = getInputOperation(1); + uvInput.xmax = input->xmax + 1; + uvInput.xmin = input->xmin - 1; + uvInput.ymax = input->ymax + 1; + uvInput.ymin = input->ymin - 1; + if (operation->determineDependingAreaOfInterest(&uvInput, readOperation, output)) { + return true; + } + + return false; +} + |