1cea8e842191569eaa67ccb77c1fe71fbeb3f4bd
[blender.git] / source / blender / compositor / operations / COM_MapUVOperation.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  *              Dalai Felinto
20  */
21
22 #include "COM_MapUVOperation.h"
23 #include "BLI_math.h"
24
25 MapUVOperation::MapUVOperation() : NodeOperation()
26 {
27         this->addInputSocket(COM_DT_COLOR, COM_SC_NO_RESIZE);
28         this->addInputSocket(COM_DT_VECTOR);
29         this->addOutputSocket(COM_DT_COLOR);
30         this->m_alpha = 0.0f;
31         this->setComplex(true);
32
33         this->m_inputUVProgram = NULL;
34         this->m_inputColorProgram = NULL;
35 }
36
37 void MapUVOperation::initExecution()
38 {
39         this->m_inputColorProgram = this->getInputSocketReader(0);
40         this->m_inputUVProgram = this->getInputSocketReader(1);
41 }
42
43 void MapUVOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
44 {
45         float inputUV[4];
46         float uv_a[4], uv_b[4];
47         float u, v;
48
49         float dx, dy;
50         float uv_l, uv_r;
51         float uv_u, uv_d;
52
53         this->m_inputUVProgram->read(inputUV, x, y, sampler);
54         if (inputUV[2] == 0.f) {
55                 zero_v4(output);
56                 return;
57         }
58         /* adaptive sampling, red (U) channel */
59         this->m_inputUVProgram->read(uv_a, x - 1, y, COM_PS_NEAREST);
60         this->m_inputUVProgram->read(uv_b, x + 1, y, COM_PS_NEAREST);
61         uv_l = uv_a[2] != 0.f ? fabsf(inputUV[0] - uv_a[0]) : 0.f;
62         uv_r = uv_b[2] != 0.f ? fabsf(inputUV[0] - uv_b[0]) : 0.f;
63
64         dx = 0.5f * (uv_l + uv_r);
65
66         /* adaptive sampling, green (V) channel */
67         this->m_inputUVProgram->read(uv_a, x, y - 1, COM_PS_NEAREST);
68         this->m_inputUVProgram->read(uv_b, x, y + 1, COM_PS_NEAREST);
69         uv_u = uv_a[2] != 0.f ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
70         uv_d = uv_b[2] != 0.f ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
71
72         dy = 0.5f * (uv_u + uv_d);
73
74 #if 0
75         /* more adaptive sampling, red and green (UV) channels */
76         this->m_inputUVProgram->read(uv_a, x - 1, y - 1, COM_PS_NEAREST);
77         this->m_inputUVProgram->read(uv_b, x - 1, y + 1, COM_PS_NEAREST);
78         uv_l = uv_a[2] != 0.f ? fabsf(inputUV[0] - uv_a[0]) : 0.f;
79         uv_r = uv_b[2] != 0.f ? fabsf(inputUV[0] - uv_b[0]) : 0.f;
80         uv_u = uv_a[2] != 0.f ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
81         uv_d = uv_b[2] != 0.f ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
82
83         dx += 0.25f * (uv_l + uv_r);
84         dy += 0.25f * (uv_u + uv_d);
85
86         this->m_inputUVProgram->read(uv_a, x + 1, y - 1, COM_PS_NEAREST);
87         this->m_inputUVProgram->read(uv_b, x + 1, y + 1, COM_PS_NEAREST);
88         uv_l = uv_a[2] != 0.f ? fabsf(inputUV[0] - uv_a[0]) : 0.f;
89         uv_r = uv_b[2] != 0.f ? fabsf(inputUV[0] - uv_b[0]) : 0.f;
90         uv_u = uv_a[2] != 0.f ? fabsf(inputUV[1] - uv_a[1]) : 0.f;
91         uv_d = uv_b[2] != 0.f ? fabsf(inputUV[1] - uv_b[1]) : 0.f;
92
93         dx += 0.25f * (uv_l + uv_r);
94         dy += 0.25f * (uv_u + uv_d);
95 #endif
96
97         /* UV to alpha threshold */
98         const float threshold = this->m_alpha * 0.05f;
99         float alpha = 1.0f - threshold * (dx + dy);
100         if (alpha < 0.f) alpha = 0.f;
101         else alpha *= inputUV[2];
102
103 #if 0
104         /* should use mipmap */
105         dx = min(dx, 0.2f);
106         dy = min(dy, 0.2f);
107 #endif
108
109         /* EWA filtering */
110         u = inputUV[0] * this->m_inputColorProgram->getWidth();
111         v = inputUV[1] * this->m_inputColorProgram->getHeight();
112
113         this->m_inputColorProgram->read(output, u, v, dx, dy, COM_PS_NEAREST);
114
115         /* "premul" */
116         if (alpha < 1.0f) {
117                 mul_v4_fl(output, alpha);
118         }
119 }
120
121 void MapUVOperation::deinitExecution()
122 {
123         this->m_inputUVProgram = NULL;
124         this->m_inputColorProgram = NULL;
125 }
126
127 bool MapUVOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
128 {
129         rcti colorInput;
130         rcti uvInput;
131         NodeOperation *operation = NULL;
132
133         /* the uv buffer only needs a 3x3 buffer. The image needs whole buffer */
134
135         operation = getInputOperation(0);
136         colorInput.xmax = operation->getWidth();
137         colorInput.xmin = 0;
138         colorInput.ymax = operation->getHeight();
139         colorInput.ymin = 0;
140         if (operation->determineDependingAreaOfInterest(&colorInput, readOperation, output)) {
141                 return true;
142         }
143
144         operation = getInputOperation(1);
145         uvInput.xmax = input->xmax + 1;
146         uvInput.xmin = input->xmin - 1;
147         uvInput.ymax = input->ymax + 1;
148         uvInput.ymin = input->ymin - 1;
149         if (operation->determineDependingAreaOfInterest(&uvInput, readOperation, output)) {
150                 return true;
151         }
152
153         return false;
154 }
155