void TimeNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { SetValueOperation *operation = new SetValueOperation(); bNode *node = this->getbNode(); /* stack order output: fac */ float fac = 0.0f; const int framenumber = context.getFramenumber(); if (framenumber < node->custom1) { fac = 0.0f; } else if (framenumber > node->custom2) { fac = 1.0f; } else if (node->custom1 < node->custom2) { fac = (context.getFramenumber() - node->custom1) / (float)(node->custom2 - node->custom1); } curvemapping_initialize((CurveMapping *)node->storage); fac = curvemapping_evaluateF((CurveMapping *)node->storage, 0, fac); operation->setValue(clamp_f(fac, 0.0f, 1.0f)); converter.addOperation(operation); converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket()); }
void TimeNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { SetValueOperation *operation = new SetValueOperation(); this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket()); bNode *node = this->getbNode(); /* stack order output: fac */ float fac = 0.0f; const int framenumber = context->getFramenumber(); if (framenumber < node->custom1) { fac = 0.0f; } else if (framenumber > node->custom2) { fac = 1.0f; } else if (node->custom1 < node->custom2) { fac = (context->getFramenumber() - node->custom1) / (float)(node->custom2 - node->custom1); } curvemapping_initialize((CurveMapping *)node->storage); fac = curvemapping_evaluateF((CurveMapping *)node->storage, 0, fac); operation->setValue(CLAMPIS(fac, 0.0f, 1.0f)); graph->addOperation(operation); }
void GlareNode::convertToOperations(NodeConverter &converter, const CompositorContext & /*context*/) const { bNode *node = this->getbNode(); NodeGlare *glare = (NodeGlare *)node->storage; GlareBaseOperation *glareoperation = NULL; switch (glare->type) { default: case 3: glareoperation = new GlareGhostOperation(); break; case 2: // streaks glareoperation = new GlareStreaksOperation(); break; case 1: // fog glow glareoperation = new GlareFogGlowOperation(); break; case 0: // simple star glareoperation = new GlareSimpleStarOperation(); break; } BLI_assert(glareoperation); glareoperation->setGlareSettings(glare); GlareThresholdOperation *thresholdOperation = new GlareThresholdOperation(); thresholdOperation->setGlareSettings(glare); SetValueOperation *mixvalueoperation = new SetValueOperation(); mixvalueoperation->setValue(0.5f + glare->mix * 0.5f); MixGlareOperation *mixoperation = new MixGlareOperation(); mixoperation->setResolutionInputSocketIndex(1); mixoperation->getInputSocket(2)->setResizeMode(COM_SC_FIT); converter.addOperation(glareoperation); converter.addOperation(thresholdOperation); converter.addOperation(mixvalueoperation); converter.addOperation(mixoperation); converter.mapInputSocket(getInputSocket(0), thresholdOperation->getInputSocket(0)); converter.addLink(thresholdOperation->getOutputSocket(), glareoperation->getInputSocket(0)); converter.addLink(mixvalueoperation->getOutputSocket(), mixoperation->getInputSocket(0)); converter.mapInputSocket(getInputSocket(0), mixoperation->getInputSocket(1)); converter.addLink(glareoperation->getOutputSocket(), mixoperation->getInputSocket(2)); converter.mapOutputSocket(getOutputSocket(), mixoperation->getOutputSocket()); }
void EllipseMaskNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { EllipseMaskOperation *operation; operation = new EllipseMaskOperation(); operation->setData((NodeEllipseMask *)this->getbNode()->storage); InputSocket *inputSocket = this->getInputSocket(0); OutputSocket *outputSocket = this->getOutputSocket(0); if (inputSocket->isConnected()) { inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph); outputSocket->relinkConnections(operation->getOutputSocket()); } else { /* Value operation to produce original transparent image */ SetValueOperation *valueOperation = new SetValueOperation(); valueOperation->setValue(0.0f); graph->addOperation(valueOperation); /* Scale that image up to render resolution */ const RenderData *rd = context->getRenderData(); ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); scaleOperation->setIsAspect(false); scaleOperation->setIsCrop(false); scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * rd->size / 100.0f); scaleOperation->setNewHeight(rd->ysch * rd->size / 100.0f); addLink(graph, valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); addLink(graph, scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); outputSocket->relinkConnections(operation->getOutputSocket(0)); scaleOperation->getInputSocket(0)->getConnection()->setIgnoreResizeCheck(true); graph->addOperation(scaleOperation); } this->getInputSocket(1)->relinkConnections(operation->getInputSocket(1), 1, graph); operation->setMaskType(this->getbNode()->custom1); graph->addOperation(operation); }
void SocketProxyNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { OutputSocket *outputsocket = this->getOutputSocket(0); InputSocket *inputsocket = this->getInputSocket(0); if (outputsocket->isConnected()) { if (inputsocket->isConnected()) { SocketProxyOperation *operation = new SocketProxyOperation(this->getOutputSocket()->getDataType()); inputsocket->relinkConnections(operation->getInputSocket(0)); outputsocket->relinkConnections(operation->getOutputSocket(0)); graph->addOperation(operation); } else { /* If input is not connected, add a constant value operation instead */ switch (outputsocket->getDataType()) { case COM_DT_VALUE: { SetValueOperation *operation = new SetValueOperation(); bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)inputsocket->getbNodeSocket()->default_value; operation->setValue(dval->value); outputsocket->relinkConnections(operation->getOutputSocket(0)); graph->addOperation(operation); break; } case COM_DT_COLOR: { SetColorOperation *operation = new SetColorOperation(); bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)inputsocket->getbNodeSocket()->default_value; operation->setChannels(dval->value); outputsocket->relinkConnections(operation->getOutputSocket(0)); graph->addOperation(operation); break; } case COM_DT_VECTOR: { SetVectorOperation *operation = new SetVectorOperation(); bNodeSocketValueVector *dval = (bNodeSocketValueVector *)inputsocket->getbNodeSocket()->default_value; operation->setVector(dval->value); outputsocket->relinkConnections(operation->getOutputSocket(0)); graph->addOperation(operation); break; } } } } }
void NodeOperationBuilder::add_input_constant_value(NodeOperationInput *input, NodeInput *node_input) { switch (input->getDataType()) { case COM_DT_VALUE: { float value; if (node_input && node_input->getbNodeSocket()) value = node_input->getEditorValueFloat(); else value = 0.0f; SetValueOperation *op = new SetValueOperation(); op->setValue(value); addOperation(op); addLink(op->getOutputSocket(), input); break; } case COM_DT_COLOR: { float value[4]; if (node_input && node_input->getbNodeSocket()) node_input->getEditorValueColor(value); else zero_v4(value); SetColorOperation *op = new SetColorOperation(); op->setChannels(value); addOperation(op); addLink(op->getOutputSocket(), input); break; } case COM_DT_VECTOR: { float value[3]; if (node_input && node_input->getbNodeSocket()) node_input->getEditorValueVector(value); else zero_v3(value); SetVectorOperation *op = new SetVectorOperation(); op->setVector(value); addOperation(op); addLink(op->getOutputSocket(), input); break; } } }
void BoxMaskNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { NodeInput *inputSocket = this->getInputSocket(0); NodeOutput *outputSocket = this->getOutputSocket(0); BoxMaskOperation *operation; operation = new BoxMaskOperation(); operation->setData((NodeBoxMask *)this->getbNode()->storage); operation->setMaskType(this->getbNode()->custom1); converter.addOperation(operation); if (inputSocket->isLinked()) { converter.mapInputSocket(inputSocket, operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket()); } else { /* Value operation to produce original transparent image */ SetValueOperation *valueOperation = new SetValueOperation(); valueOperation->setValue(0.0f); converter.addOperation(valueOperation); /* Scale that image up to render resolution */ const RenderData *rd = context.getRenderData(); ScaleFixedSizeOperation *scaleOperation = new ScaleFixedSizeOperation(); scaleOperation->setIsAspect(false); scaleOperation->setIsCrop(false); scaleOperation->setOffset(0.0f, 0.0f); scaleOperation->setNewWidth(rd->xsch * rd->size / 100.0f); scaleOperation->setNewHeight(rd->ysch * rd->size / 100.0f); scaleOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); converter.addOperation(scaleOperation); converter.addLink(valueOperation->getOutputSocket(0), scaleOperation->getInputSocket(0)); converter.addLink(scaleOperation->getOutputSocket(0), operation->getInputSocket(0)); converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0)); } converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); }
void BlurNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const { bNode *editorNode = this->getbNode(); NodeBlurData *data = (NodeBlurData *)editorNode->storage; NodeInput *inputSizeSocket = this->getInputSocket(1); bool connectedSizeSocket = inputSizeSocket->isLinked(); const float size = this->getInputSocket(1)->getEditorValueFloat(); CompositorQuality quality = context.getQuality(); NodeOperation *input_operation = NULL, *output_operation = NULL; if (data->filtertype == R_FILTER_FAST_GAUSS) { FastGaussianBlurOperation *operationfgb = new FastGaussianBlurOperation(); operationfgb->setData(data); converter.addOperation(operationfgb); converter.mapInputSocket(getInputSocket(1), operationfgb->getInputSocket(1)); input_operation = operationfgb; output_operation = operationfgb; } else if (editorNode->custom1 & CMP_NODEFLAG_BLUR_VARIABLE_SIZE) { MathAddOperation *clamp = new MathAddOperation(); SetValueOperation *zero = new SetValueOperation(); zero->setValue(0.0f); clamp->setUseClamp(true); converter.addOperation(clamp); converter.addOperation(zero); converter.mapInputSocket(getInputSocket(1), clamp->getInputSocket(0)); converter.addLink(zero->getOutputSocket(), clamp->getInputSocket(1)); GaussianAlphaXBlurOperation *operationx = new GaussianAlphaXBlurOperation(); operationx->setData(data); operationx->setQuality(quality); operationx->setSize(1.0f); operationx->setFalloff(PROP_SMOOTH); operationx->setSubtract(false); converter.addOperation(operationx); converter.addLink(clamp->getOutputSocket(), operationx->getInputSocket(0)); GaussianAlphaYBlurOperation *operationy = new GaussianAlphaYBlurOperation(); operationy->setData(data); operationy->setQuality(quality); operationy->setSize(1.0f); operationy->setFalloff(PROP_SMOOTH); operationy->setSubtract(false); converter.addOperation(operationy); converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); GaussianBlurReferenceOperation *operation = new GaussianBlurReferenceOperation(); operation->setData(data); operation->setQuality(quality); converter.addOperation(operation); converter.addLink(operationy->getOutputSocket(), operation->getInputSocket(1)); output_operation = operation; input_operation = operation; } else if (!data->bokeh) { GaussianXBlurOperation *operationx = new GaussianXBlurOperation(); operationx->setData(data); operationx->setQuality(quality); converter.addOperation(operationx); converter.mapInputSocket(getInputSocket(1), operationx->getInputSocket(1)); GaussianYBlurOperation *operationy = new GaussianYBlurOperation(); operationy->setData(data); operationy->setQuality(quality); converter.addOperation(operationy); converter.mapInputSocket(getInputSocket(1), operationy->getInputSocket(1)); converter.addLink(operationx->getOutputSocket(), operationy->getInputSocket(0)); if (!connectedSizeSocket) { operationx->setSize(size); operationy->setSize(size); } input_operation = operationx; output_operation = operationy; } else { GaussianBokehBlurOperation *operation = new GaussianBokehBlurOperation(); operation->setData(data); operation->setQuality(quality); converter.addOperation(operation); converter.mapInputSocket(getInputSocket(1), operation->getInputSocket(1)); if (!connectedSizeSocket) { operation->setSize(size); } input_operation = operation; output_operation = operation; } if (data->gamma) { GammaCorrectOperation *correct = new GammaCorrectOperation(); GammaUncorrectOperation *inverse = new GammaUncorrectOperation(); converter.addOperation(correct); converter.addOperation(inverse); converter.mapInputSocket(getInputSocket(0), correct->getInputSocket(0)); converter.addLink(correct->getOutputSocket(), input_operation->getInputSocket(0)); converter.addLink(output_operation->getOutputSocket(), inverse->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(), inverse->getOutputSocket()); converter.addPreview(inverse->getOutputSocket()); } else { converter.mapInputSocket(getInputSocket(0), input_operation->getInputSocket(0)); converter.mapOutputSocket(getOutputSocket(), output_operation->getOutputSocket()); converter.addPreview(output_operation->getOutputSocket()); } }
void Converter::convertResolution(NodeOperationBuilder &builder, NodeOperationOutput *fromSocket, NodeOperationInput *toSocket) { InputResizeMode mode = toSocket->getResizeMode(); NodeOperation *toOperation = &toSocket->getOperation(); const float toWidth = toOperation->getWidth(); const float toHeight = toOperation->getHeight(); NodeOperation *fromOperation = &fromSocket->getOperation(); const float fromWidth = fromOperation->getWidth(); const float fromHeight = fromOperation->getHeight(); bool doCenter = false; bool doScale = false; float addX = (toWidth - fromWidth) / 2.0f; float addY = (toHeight - fromHeight) / 2.0f; float scaleX = 0; float scaleY = 0; switch (mode) { case COM_SC_NO_RESIZE: break; case COM_SC_CENTER: doCenter = true; break; case COM_SC_FIT_WIDTH: doCenter = true; doScale = true; scaleX = scaleY = toWidth / fromWidth; break; case COM_SC_FIT_HEIGHT: doCenter = true; doScale = true; scaleX = scaleY = toHeight / fromHeight; break; case COM_SC_FIT: doCenter = true; doScale = true; scaleX = toWidth / fromWidth; scaleY = toHeight / fromHeight; if (scaleX < scaleY) { scaleX = scaleY; } else { scaleY = scaleX; } break; case COM_SC_STRETCH: doCenter = true; doScale = true; scaleX = toWidth / fromWidth; scaleY = toHeight / fromHeight; break; } if (doCenter) { NodeOperation *first = NULL; ScaleOperation *scaleOperation = NULL; if (doScale) { scaleOperation = new ScaleOperation(); scaleOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); scaleOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); first = scaleOperation; SetValueOperation *sxop = new SetValueOperation(); sxop->setValue(scaleX); builder.addLink(sxop->getOutputSocket(), scaleOperation->getInputSocket(1)); SetValueOperation *syop = new SetValueOperation(); syop->setValue(scaleY); builder.addLink(syop->getOutputSocket(), scaleOperation->getInputSocket(2)); builder.addOperation(sxop); builder.addOperation(syop); unsigned int resolution[2] = {fromOperation->getWidth(), fromOperation->getHeight()}; scaleOperation->setResolution(resolution); sxop->setResolution(resolution); syop->setResolution(resolution); builder.addOperation(scaleOperation); } TranslateOperation *translateOperation = new TranslateOperation(); translateOperation->getInputSocket(1)->setResizeMode(COM_SC_NO_RESIZE); translateOperation->getInputSocket(2)->setResizeMode(COM_SC_NO_RESIZE); if (!first) first = translateOperation; SetValueOperation *xop = new SetValueOperation(); xop->setValue(addX); builder.addLink(xop->getOutputSocket(), translateOperation->getInputSocket(1)); SetValueOperation *yop = new SetValueOperation(); yop->setValue(addY); builder.addLink(yop->getOutputSocket(), translateOperation->getInputSocket(2)); builder.addOperation(xop); builder.addOperation(yop); unsigned int resolution[2] = {toOperation->getWidth(), toOperation->getHeight()}; translateOperation->setResolution(resolution); xop->setResolution(resolution); yop->setResolution(resolution); builder.addOperation(translateOperation); if (doScale) { translateOperation->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); builder.addLink(scaleOperation->getOutputSocket(), translateOperation->getInputSocket(0)); } /* remove previous link and replace */ builder.removeInputLink(toSocket); first->getInputSocket(0)->setResizeMode(COM_SC_NO_RESIZE); toSocket->setResizeMode(COM_SC_NO_RESIZE); builder.addLink(fromSocket, first->getInputSocket(0)); builder.addLink(translateOperation->getOutputSocket(), toSocket); } }
void MovieClipNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { OutputSocket *outputMovieClip = this->getOutputSocket(0); OutputSocket *alphaMovieClip = this->getOutputSocket(1); OutputSocket *offsetXMovieClip = this->getOutputSocket(2); OutputSocket *offsetYMovieClip = this->getOutputSocket(3); OutputSocket *scaleMovieClip = this->getOutputSocket(4); OutputSocket *angleMovieClip = this->getOutputSocket(5); bNode *editorNode = this->getbNode(); MovieClip *movieClip = (MovieClip *)editorNode->id; MovieClipUser *movieClipUser = (MovieClipUser *)editorNode->storage; bool cacheFrame = !context->isRendering(); ImBuf *ibuf = NULL; if (movieClip) { if (cacheFrame) ibuf = BKE_movieclip_get_ibuf(movieClip, movieClipUser); else ibuf = BKE_movieclip_get_ibuf_flag(movieClip, movieClipUser, movieClip->flag, MOVIECLIP_CACHE_SKIP); } // always connect the output image MovieClipOperation *operation = new MovieClipOperation(); addPreviewOperation(graph, context, operation->getOutputSocket()); if (outputMovieClip->isConnected()) { outputMovieClip->relinkConnections(operation->getOutputSocket()); } operation->setMovieClip(movieClip); operation->setMovieClipUser(movieClipUser); operation->setFramenumber(context->getFramenumber()); operation->setCacheFrame(cacheFrame); graph->addOperation(operation); if (alphaMovieClip->isConnected()) { MovieClipAlphaOperation *alphaOperation = new MovieClipAlphaOperation(); alphaOperation->setMovieClip(movieClip); alphaOperation->setMovieClipUser(movieClipUser); alphaOperation->setFramenumber(context->getFramenumber()); alphaOperation->setCacheFrame(cacheFrame); alphaMovieClip->relinkConnections(alphaOperation->getOutputSocket()); graph->addOperation(alphaOperation); } MovieTrackingStabilization *stab = &movieClip->tracking.stabilization; float loc[2], scale, angle; loc[0] = 0.0f; loc[1] = 0.0f; scale = 1.0f; angle = 0.0f; if (ibuf) { if (stab->flag & TRACKING_2D_STABILIZATION) { int clip_framenr = BKE_movieclip_remap_scene_to_clip_frame(movieClip, context->getFramenumber()); BKE_tracking_stabilization_data_get(&movieClip->tracking, clip_framenr, ibuf->x, ibuf->y, loc, &scale, &angle); } } if (offsetXMovieClip->isConnected()) { SetValueOperation *operationSetValue = new SetValueOperation(); operationSetValue->setValue(loc[0]); offsetXMovieClip->relinkConnections(operationSetValue->getOutputSocket()); graph->addOperation(operationSetValue); } if (offsetYMovieClip->isConnected()) { SetValueOperation *operationSetValue = new SetValueOperation(); operationSetValue->setValue(loc[1]); offsetYMovieClip->relinkConnections(operationSetValue->getOutputSocket()); graph->addOperation(operationSetValue); } if (scaleMovieClip->isConnected()) { SetValueOperation *operationSetValue = new SetValueOperation(); operationSetValue->setValue(scale); scaleMovieClip->relinkConnections(operationSetValue->getOutputSocket()); graph->addOperation(operationSetValue); } if (angleMovieClip->isConnected()) { SetValueOperation *operationSetValue = new SetValueOperation(); operationSetValue->setValue(angle); angleMovieClip->relinkConnections(operationSetValue->getOutputSocket()); graph->addOperation(operationSetValue); } if (ibuf) { IMB_freeImBuf(ibuf); } }
void KeyingNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context) { InputSocket *inputImage = this->getInputSocket(0); InputSocket *inputScreen = this->getInputSocket(1); InputSocket *inputGarbageMatte = this->getInputSocket(2); InputSocket *inputCoreMatte = this->getInputSocket(3); OutputSocket *outputImage = this->getOutputSocket(0); OutputSocket *outputMatte = this->getOutputSocket(1); OutputSocket *outputEdges = this->getOutputSocket(2); OutputSocket *postprocessedMatte = NULL, *postprocessedImage = NULL, *originalImage = NULL, *edgesMatte = NULL; bNode *editorNode = this->getbNode(); NodeKeyingData *keying_data = (NodeKeyingData *) editorNode->storage; /* keying operation */ KeyingOperation *keyingOperation = new KeyingOperation(); keyingOperation->setScreenBalance(keying_data->screen_balance); inputScreen->relinkConnections(keyingOperation->getInputSocket(1), 1, graph); if (keying_data->blur_pre) { /* chroma preblur operation for input of keying operation */ OutputSocket *preBluredImage = setupPreBlur(graph, inputImage, keying_data->blur_pre, &originalImage); addLink(graph, preBluredImage, keyingOperation->getInputSocket(0)); } else { inputImage->relinkConnections(keyingOperation->getInputSocket(0), 0, graph); originalImage = keyingOperation->getInputSocket(0)->getConnection()->getFromSocket(); } graph->addOperation(keyingOperation); postprocessedMatte = keyingOperation->getOutputSocket(); /* black / white clipping */ if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) { postprocessedMatte = setupClip(graph, postprocessedMatte, keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance, keying_data->clip_black, keying_data->clip_white, false); } /* output edge matte */ if (outputEdges->isConnected()) { edgesMatte = setupClip(graph, postprocessedMatte, keying_data->edge_kernel_radius, keying_data->edge_kernel_tolerance, keying_data->clip_black, keying_data->clip_white, true); } /* apply garbage matte */ if (inputGarbageMatte->isConnected()) { SetValueOperation *valueOperation = new SetValueOperation(); MathSubtractOperation *subtractOperation = new MathSubtractOperation(); MathMinimumOperation *minOperation = new MathMinimumOperation(); valueOperation->setValue(1.0f); addLink(graph, valueOperation->getOutputSocket(), subtractOperation->getInputSocket(0)); inputGarbageMatte->relinkConnections(subtractOperation->getInputSocket(1), 0, graph); addLink(graph, subtractOperation->getOutputSocket(), minOperation->getInputSocket(0)); addLink(graph, postprocessedMatte, minOperation->getInputSocket(1)); postprocessedMatte = minOperation->getOutputSocket(); graph->addOperation(valueOperation); graph->addOperation(subtractOperation); graph->addOperation(minOperation); } /* apply core matte */ if (inputCoreMatte->isConnected()) { MathMaximumOperation *maxOperation = new MathMaximumOperation(); inputCoreMatte->relinkConnections(maxOperation->getInputSocket(0), 0, graph); addLink(graph, postprocessedMatte, maxOperation->getInputSocket(1)); postprocessedMatte = maxOperation->getOutputSocket(); graph->addOperation(maxOperation); } /* apply blur on matte if needed */ if (keying_data->blur_post) postprocessedMatte = setupPostBlur(graph, postprocessedMatte, keying_data->blur_post); /* matte dilate/erode */ if (keying_data->dilate_distance != 0) { postprocessedMatte = setupDilateErode(graph, postprocessedMatte, keying_data->dilate_distance); } /* matte feather */ if (keying_data->feather_distance != 0) { postprocessedMatte = setupFeather(graph, context, postprocessedMatte, keying_data->feather_falloff, keying_data->feather_distance); } /* set alpha channel to output image */ SetAlphaOperation *alphaOperation = new SetAlphaOperation(); addLink(graph, originalImage, alphaOperation->getInputSocket(0)); addLink(graph, postprocessedMatte, alphaOperation->getInputSocket(1)); postprocessedImage = alphaOperation->getOutputSocket(); /* despill output image */ if (keying_data->despill_factor > 0.0f) { postprocessedImage = setupDespill(graph, postprocessedImage, keyingOperation->getInputSocket(1)->getConnection()->getFromSocket(), keying_data->despill_factor, keying_data->despill_balance); } /* connect result to output sockets */ outputImage->relinkConnections(postprocessedImage); outputMatte->relinkConnections(postprocessedMatte); if (edgesMatte) outputEdges->relinkConnections(edgesMatte); graph->addOperation(alphaOperation); }