rename remaining class members with m_ prefix.
[blender.git] / source / blender / compositor / nodes / COM_KeyingNode.cpp
1 /*
2  * Copyright 2012, 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  *              Sergey Sharybin
22  */
23
24 #include "COM_KeyingNode.h"
25
26 #include "COM_ExecutionSystem.h"
27
28 #include "COM_KeyingOperation.h"
29 #include "COM_KeyingBlurOperation.h"
30 #include "COM_KeyingDespillOperation.h"
31 #include "COM_KeyingClipOperation.h"
32
33 #include "COM_SeparateChannelOperation.h"
34 #include "COM_CombineChannelsOperation.h"
35 #include "COM_ConvertRGBToYCCOperation.h"
36 #include "COM_ConvertYCCToRGBOperation.h"
37 #include "COM_SetValueOperation.h"
38
39 #include "COM_DilateErodeOperation.h"
40
41 #include "COM_SetAlphaOperation.h"
42
43 #include "COM_GaussianAlphaXBlurOperation.h"
44 #include "COM_GaussianAlphaYBlurOperation.h"
45
46 KeyingNode::KeyingNode(bNode *editorNode) : Node(editorNode)
47 {
48         /* pass */
49 }
50
51 OutputSocket *KeyingNode::setupPreBlur(ExecutionSystem *graph, InputSocket *inputImage, int size, OutputSocket **originalImage)
52 {
53         ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation();
54         convertRGBToYCCOperation->setMode(0);  /* ITU 601 */
55
56         inputImage->relinkConnections(convertRGBToYCCOperation->getInputSocket(0), 0, graph);
57         graph->addOperation(convertRGBToYCCOperation);
58
59         CombineChannelsOperation *combineOperation = new CombineChannelsOperation();
60         graph->addOperation(combineOperation);
61
62         for (int channel = 0; channel < 4; channel++) {
63                 SeparateChannelOperation *separateOperation = new SeparateChannelOperation();
64                 separateOperation->setChannel(channel);
65                 addLink(graph, convertRGBToYCCOperation->getOutputSocket(0), separateOperation->getInputSocket(0));
66                 graph->addOperation(separateOperation);
67
68                 if (channel == 0 || channel == 3) {
69                         addLink(graph, separateOperation->getOutputSocket(0), combineOperation->getInputSocket(channel));
70                 }
71                 else {
72                         KeyingBlurOperation *blurXOperation = new KeyingBlurOperation();
73                         KeyingBlurOperation *blurYOperation = new KeyingBlurOperation();
74
75                         blurXOperation->setSize(size);
76                         blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X);
77
78                         blurYOperation->setSize(size);
79                         blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y);
80
81                         addLink(graph, separateOperation->getOutputSocket(), blurXOperation->getInputSocket(0));
82                         addLink(graph, blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0));
83                         addLink(graph, blurYOperation->getOutputSocket(0), combineOperation->getInputSocket(channel));
84
85                         graph->addOperation(blurXOperation);
86                         graph->addOperation(blurYOperation);
87                 }
88         }
89
90         ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation();
91         convertYCCToRGBOperation->setMode(0);  /* ITU 601 */
92         addLink(graph, combineOperation->getOutputSocket(0), convertYCCToRGBOperation->getInputSocket(0));
93         graph->addOperation(convertYCCToRGBOperation);
94
95         *originalImage = convertRGBToYCCOperation->getInputSocket(0)->getConnection()->getFromSocket();
96
97         return convertYCCToRGBOperation->getOutputSocket(0);
98 }
99
100 OutputSocket *KeyingNode::setupPostBlur(ExecutionSystem *graph, OutputSocket *postBlurInput, int size)
101 {
102         KeyingBlurOperation *blurXOperation = new KeyingBlurOperation();
103         KeyingBlurOperation *blurYOperation = new KeyingBlurOperation();
104
105         blurXOperation->setSize(size);
106         blurXOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_X);
107
108         blurYOperation->setSize(size);
109         blurYOperation->setAxis(KeyingBlurOperation::BLUR_AXIS_Y);
110
111         addLink(graph, postBlurInput, blurXOperation->getInputSocket(0));
112         addLink(graph, blurXOperation->getOutputSocket(), blurYOperation->getInputSocket(0));
113
114         graph->addOperation(blurXOperation);
115         graph->addOperation(blurYOperation);
116
117         return blurYOperation->getOutputSocket();
118 }
119
120 OutputSocket *KeyingNode::setupDilateErode(ExecutionSystem *graph, OutputSocket *dilateErodeInput, int distance)
121 {
122         DilateDistanceOperation *dilateErodeOperation;
123
124         if (distance > 0) {
125                 dilateErodeOperation = new DilateDistanceOperation();
126                 dilateErodeOperation->setDistance(distance);
127         }
128         else {
129                 dilateErodeOperation = new ErodeDistanceOperation();
130                 dilateErodeOperation->setDistance(-distance);
131         }
132
133         addLink(graph, dilateErodeInput, dilateErodeOperation->getInputSocket(0));
134
135         graph->addOperation(dilateErodeOperation);
136
137         return dilateErodeOperation->getOutputSocket(0);
138 }
139
140 OutputSocket *KeyingNode::setupFeather(ExecutionSystem *graph, CompositorContext *context,
141                                        OutputSocket *featherInput, int falloff, int distance)
142 {
143         /* this uses a modified gaussian blur function otherwise its far too slow */
144         CompositorQuality quality = context->getQuality();
145
146         /* initialize node data */
147         NodeBlurData *data = (NodeBlurData *)&this->m_alpha_blur;
148         memset(data, 0, sizeof(*data));
149         data->filtertype = R_FILTER_GAUSS;
150
151         if (distance > 0) {
152                 data->sizex = data->sizey = distance;
153         }
154         else {
155                 data->sizex = data->sizey = -distance;
156         }
157
158         GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation();
159         operationx->setData(data);
160         operationx->setQuality(quality);
161         operationx->setSize(1.0f);
162         operationx->setSubtract(distance < 0);
163         operationx->setFalloff(falloff);
164         graph->addOperation(operationx);
165
166         GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation();
167         operationy->setData(data);
168         operationy->setQuality(quality);
169         operationy->setSize(1.0f);
170         operationy->setSubtract(distance < 0);
171         operationy->setFalloff(falloff);
172         graph->addOperation(operationy);
173
174         addLink(graph, featherInput, operationx->getInputSocket(0));
175         addLink(graph, operationx->getOutputSocket(), operationy->getInputSocket(0));
176
177         return operationy->getOutputSocket();
178 }
179
180 OutputSocket *KeyingNode::setupDespill(ExecutionSystem *graph, OutputSocket *despillInput, OutputSocket *inputScreen, float factor)
181 {
182         KeyingDespillOperation *despillOperation = new KeyingDespillOperation();
183
184         despillOperation->setDespillFactor(factor);
185
186         addLink(graph, despillInput, despillOperation->getInputSocket(0));
187         addLink(graph, inputScreen, despillOperation->getInputSocket(1));
188
189         graph->addOperation(despillOperation);
190
191         return despillOperation->getOutputSocket(0);
192 }
193
194 OutputSocket *KeyingNode::setupClip(ExecutionSystem *graph, OutputSocket *clipInput, int kernelRadius, float kernelTolerance,
195                                     float clipBlack, float clipWhite, bool edgeMatte)
196 {
197         KeyingClipOperation *clipOperation = new KeyingClipOperation();
198
199         clipOperation->setKernelRadius(kernelRadius);
200         clipOperation->setKernelTolerance(kernelTolerance);
201
202         clipOperation->setClipBlack(clipBlack);
203         clipOperation->setClipWhite(clipWhite);
204         clipOperation->setIsEdgeMatte(edgeMatte);
205
206         addLink(graph, clipInput, clipOperation->getInputSocket(0));
207
208         graph->addOperation(clipOperation);
209
210         return clipOperation->getOutputSocket(0);
211 }
212
213 void KeyingNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
214 {
215         InputSocket *inputImage = this->getInputSocket(0);
216         InputSocket *inputScreen = this->getInputSocket(1);
217         InputSocket *inputGarbageMatte = this->getInputSocket(2);
218         InputSocket *inputCoreMatte = this->getInputSocket(3);
219         OutputSocket *outputImage = this->getOutputSocket(0);
220         OutputSocket *outputMatte = this->getOutputSocket(1);
221         OutputSocket *outputEdges = this->getOutputSocket(2);
222         OutputSocket *postprocessedMatte = NULL, *postprocessedImage = NULL, *originalImage = NULL, *edgesMatte = NULL;
223
224         bNode *editorNode = this->getbNode();
225         NodeKeyingData *keying_data = (NodeKeyingData *) editorNode->storage;
226
227         /* keying operation */
228         KeyingOperation *keyingOperation = new KeyingOperation();
229
230         keyingOperation->setScreenBalance(keying_data->screen_balance);
231
232         inputScreen->relinkConnections(keyingOperation->getInputSocket(1), 1, graph);
233         inputGarbageMatte->relinkConnections(keyingOperation->getInputSocket(2), 2, graph);
234         inputCoreMatte->relinkConnections(keyingOperation->getInputSocket(3), 3, graph);
235
236         if (keying_data->blur_pre) {
237                 /* chroma preblur operation for input of keying operation  */
238                 OutputSocket *preBluredImage = setupPreBlur(graph, inputImage, keying_data->blur_pre, &originalImage);
239                 addLink(graph, preBluredImage, keyingOperation->getInputSocket(0));
240         }
241         else {
242                 inputImage->relinkConnections(keyingOperation->getInputSocket(0), 0, graph);
243                 originalImage = keyingOperation->getInputSocket(0)->getConnection()->getFromSocket();
244         }
245
246         graph->addOperation(keyingOperation);
247
248         postprocessedMatte = keyingOperation->getOutputSocket();
249
250         if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) {
251                 postprocessedMatte = setupClip(graph, postprocessedMatte,
252                                                keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance,
253                                                keying_data->clip_black, keying_data->clip_white, false);
254         }
255
256         if (outputEdges->isConnected()) {
257                 edgesMatte = setupClip(graph, postprocessedMatte,
258                                        keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance,
259                                        keying_data->clip_black, keying_data->clip_white, true);
260         }
261
262         /* apply blur on matte if needed */
263         if (keying_data->blur_post)
264                 postprocessedMatte = setupPostBlur(graph, postprocessedMatte, keying_data->blur_post);
265
266         /* matte dilate/erode */
267         if (keying_data->dilate_distance != 0) {
268                 postprocessedMatte = setupDilateErode(graph, postprocessedMatte, keying_data->dilate_distance);
269         }
270
271         /* matte feather */
272         if (keying_data->feather_distance != 0) {
273                 postprocessedMatte = setupFeather(graph, context, postprocessedMatte, keying_data->feather_falloff,
274                                                   keying_data->feather_distance);
275         }
276
277         /* set alpha channel to output image */
278         SetAlphaOperation *alphaOperation = new SetAlphaOperation();
279         addLink(graph, originalImage, alphaOperation->getInputSocket(0));
280         addLink(graph, postprocessedMatte, alphaOperation->getInputSocket(1));
281
282         postprocessedImage = alphaOperation->getOutputSocket();
283
284         /* despill output image */
285         if (keying_data->despill_factor > 0.0f) {
286                 postprocessedImage = setupDespill(graph, postprocessedImage,
287                                                   keyingOperation->getInputSocket(1)->getConnection()->getFromSocket(),
288                                                   keying_data->despill_factor);
289         }
290
291         /* connect result to output sockets */
292         outputImage->relinkConnections(postprocessedImage);
293         outputMatte->relinkConnections(postprocessedMatte);
294
295         if (edgesMatte)
296                 outputEdges->relinkConnections(edgesMatte);
297
298         graph->addOperation(alphaOperation);
299 }