bool GaussianAlphaYBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInput;
#if 0 /* until we add size input */
	rcti sizeInput;
	sizeInput.xmin = 0;
	sizeInput.ymin = 0;
	sizeInput.xmax = 5;
	sizeInput.ymax = 5;

	NodeOperation *operation = this->getInputOperation(1);
	if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
		return true;
	}
	else
#endif
	{
		if (this->m_sizeavailable && this->m_gausstab != NULL) {
			newInput.xmax = input->xmax;
			newInput.xmin = input->xmin;
			newInput.ymax = input->ymax + this->m_rad + 1;
			newInput.ymin = input->ymin - this->m_rad - 1;
		}
		else {
			newInput.xmax = this->getWidth();
			newInput.xmin = 0;
			newInput.ymax = this->getHeight();
			newInput.ymin = 0;
		}
		return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
	}
}
void ExecutionGroup::setRenderBorder(float xmin, float xmax, float ymin, float ymax)
{
	NodeOperation *operation = this->getOutputOperation();

	if (operation->isOutputOperation(true)) {
		/* Basically, setting border need to happen for only operations
		 * which operates in render resolution buffers (like compositor
		 * output nodes).
		 *
		 * In this cases adding border will lead to mapping coordinates
		 * from output buffer space to input buffer spaces when executing
		 * operation.
		 *
		 * But nodes like viewer and file output just shall display or
		 * safe the same exact buffer which goes to their input, no need
		 * in any kind of coordinates mapping.
		 */

		bool operationNeedsBorder = !(operation->isViewerOperation() ||
		                              operation->isPreviewOperation() ||
		                              operation->isFileOutputOperation());

		if (operationNeedsBorder) {
			BLI_rcti_init(&this->m_viewerBorder, xmin * this->m_width, xmax * this->m_width,
			              ymin * this->m_height, ymax * this->m_height);
		}
	}
}
void NodeOperationBuilder::add_datatype_conversions()
{
	Links convert_links;
	for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
		const Link &link = *it;
		
		/* proxy operations can skip data type conversion */
		NodeOperation *from_op = &link.from()->getOperation();
		NodeOperation *to_op = &link.to()->getOperation();
		if (!(from_op->useDatatypeConversion() || to_op->useDatatypeConversion()))
			continue;
		
		if (link.from()->getDataType() != link.to()->getDataType())
			convert_links.push_back(link);
	}
	for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
		const Link &link = *it;
		NodeOperation *converter = Converter::convertDataType(link.from(), link.to());
		if (converter) {
			addOperation(converter);
			
			removeInputLink(link.to());
			addLink(link.from(), converter->getInputSocket(0));
			addLink(converter->getOutputSocket(0), link.to());
		}
	}
}
bool GaussianXBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInput;
	
	if (!this->m_sizeavailable) {
		rcti sizeInput;
		sizeInput.xmin = 0;
		sizeInput.ymin = 0;
		sizeInput.xmax = 5;
		sizeInput.ymax = 5;
		NodeOperation *operation = this->getInputOperation(1);
		if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
			return true;
		}
	}
	{
		if (this->m_sizeavailable && this->m_gausstab != NULL) {
			newInput.xmax = input->xmax + this->m_filtersize + 1;
			newInput.xmin = input->xmin - this->m_filtersize - 1;
			newInput.ymax = input->ymax;
			newInput.ymin = input->ymin;
		}
		else {
			newInput.xmax = this->getWidth();
			newInput.xmin = 0;
			newInput.ymax = this->getHeight();
			newInput.ymin = 0;
		}
		return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
	}
}
void ExecutionGroup::initExecution()
{
	if (this->m_chunkExecutionStates != NULL) {
		MEM_freeN(this->m_chunkExecutionStates);
	}
	unsigned int index;
	determineNumberOfChunks();

	this->m_chunkExecutionStates = NULL;
	if (this->m_numberOfChunks != 0) {
		this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN(sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__);
		for (index = 0; index < this->m_numberOfChunks; index++) {
			this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED;
		}
	}


	unsigned int maxNumber = 0;

	for (index = 0; index < this->m_operations.size(); index++) {
		NodeOperation *operation = this->m_operations[index];
		if (operation->isReadBufferOperation()) {
			ReadBufferOperation *readOperation = (ReadBufferOperation *)operation;
			this->m_cachedReadOperations.push_back(readOperation);
			maxNumber = max(maxNumber, readOperation->getOffset());
		}
	}
	maxNumber++;
	this->m_cachedMaxReadBufferOffset = maxNumber;

}
bool NodeOperation::determineDependingAreaOfInterest(rcti *input,
                                                     ReadBufferOperation *readOperation,
                                                     rcti *output)
{
  if (isInputOperation()) {
    BLI_rcti_init(output, input->xmin, input->xmax, input->ymin, input->ymax);
    return false;
  }
  else {
    rcti tempOutput;
    bool first = true;
    for (int i = 0; i < getNumberOfInputSockets(); i++) {
      NodeOperation *inputOperation = this->getInputOperation(i);
      if (inputOperation &&
          inputOperation->determineDependingAreaOfInterest(input, readOperation, &tempOutput)) {
        if (first) {
          output->xmin = tempOutput.xmin;
          output->ymin = tempOutput.ymin;
          output->xmax = tempOutput.xmax;
          output->ymax = tempOutput.ymax;
          first = false;
        }
        else {
          output->xmin = min(output->xmin, tempOutput.xmin);
          output->ymin = min(output->ymin, tempOutput.ymin);
          output->xmax = max(output->xmax, tempOutput.xmax);
          output->ymax = max(output->ymax, tempOutput.ymax);
        }
      }
    }
    return !first;
  }
}
void RenderLayersNode::missingSocketLink(NodeConverter &converter,
                                         NodeOutput *output) const
{
	NodeOperation *operation;
	switch (output->getDataType()) {
		case COM_DT_COLOR:
		{
			const float color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
			SetColorOperation *color_operation = new SetColorOperation();
			color_operation->setChannels(color);
			operation = color_operation;
			break;
		}
		case COM_DT_VECTOR:
		{
			const float vector[3] = {0.0f, 0.0f, 0.0f};
			SetVectorOperation *vector_operation = new SetVectorOperation();
			vector_operation->setVector(vector);
			operation = vector_operation;
			break;
		}
		case COM_DT_VALUE:
		{
			SetValueOperation *value_operation = new SetValueOperation();
			value_operation->setValue(0.0f);
			operation = value_operation;
			break;
		}
	}

	converter.mapOutputSocket(output, operation->getOutputSocket());
	converter.addOperation(operation);
}
bool FastGaussianBlurOperation::determineDependingAreaOfInterest(rcti * /*input*/, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInput;
	rcti sizeInput;
	sizeInput.xmin = 0;
	sizeInput.ymin = 0;
	sizeInput.xmax = 5;
	sizeInput.ymax = 5;

	NodeOperation *operation = this->getInputOperation(1);
	if (operation->determineDependingAreaOfInterest(&sizeInput, readOperation, output)) {
		return true;
	}
	else {
		if (this->m_iirgaus) {
			return false;
		}
		else {
			newInput.xmin = 0;
			newInput.ymin = 0;
			newInput.xmax = this->getWidth();
			newInput.ymax = this->getHeight();
		}
		return NodeOperation::determineDependingAreaOfInterest(&newInput, readOperation, output);
	}
}
void ExecutionGroup::determineResolution(unsigned int resolution[2])
{
	NodeOperation *operation = this->getOutputOperation();
	resolution[0] = operation->getWidth();
	resolution[1] = operation->getHeight();
	this->setResolution(resolution);
	BLI_rcti_init(&this->m_viewerBorder, 0, this->m_width, 0, this->m_height);
}
void ExecutionGroup::setViewerBorder(float xmin, float xmax, float ymin, float ymax)
{
	NodeOperation *operation = this->getOutputOperation();

	if (operation->isViewerOperation() || operation->isPreviewOperation()) {
		BLI_rcti_init(&this->m_viewerBorder, xmin * this->m_width, xmax * this->m_width,
		              ymin * this->m_height, ymax * this->m_height);
	}
}
void ChannelMatteNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
	bNode *node = this->getbNode();
	
	NodeInput *inputSocketImage = this->getInputSocket(0);
	NodeOutput *outputSocketImage = this->getOutputSocket(0);
	NodeOutput *outputSocketMatte = this->getOutputSocket(1);
	
	NodeOperation *convert = NULL;
	/* colorspace */
	switch (node->custom1) {
		case CMP_NODE_CHANNEL_MATTE_CS_RGB:
			break;
		case CMP_NODE_CHANNEL_MATTE_CS_HSV: /* HSV */
			convert = new ConvertRGBToHSVOperation();
			break;
		case CMP_NODE_CHANNEL_MATTE_CS_YUV: /* YUV */
			convert = new ConvertRGBToYUVOperation();
			break;
		case CMP_NODE_CHANNEL_MATTE_CS_YCC: /* YCC */
			convert = new ConvertRGBToYCCOperation();
			((ConvertRGBToYCCOperation *)convert)->setMode(0); /* BLI_YCC_ITU_BT601 */
			break;
		default:
			break;
	}
	
	ChannelMatteOperation *operation = new ChannelMatteOperation();
	/* pass the ui properties to the operation */
	operation->setSettings((NodeChroma *)node->storage, node->custom2);
	converter.addOperation(operation);
	
	SetAlphaOperation *operationAlpha = new SetAlphaOperation();
	converter.addOperation(operationAlpha);
	
	if (convert) {
		converter.addOperation(convert);
		
		converter.mapInputSocket(inputSocketImage, convert->getInputSocket(0));
		converter.addLink(convert->getOutputSocket(), operation->getInputSocket(0));
		converter.addLink(convert->getOutputSocket(), operationAlpha->getInputSocket(0));
	}
	else {
		converter.mapInputSocket(inputSocketImage, operation->getInputSocket(0));
		converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
	}
	
	converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0));
	
	converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
	converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
	
	converter.addPreview(operationAlpha->getOutputSocket());
}
void ExecutionSystemHelper::findOutputNodeOperations(vector<NodeOperation *> *result, vector<NodeOperation *>& operations, bool rendering)
{
	unsigned int index;

	for (index = 0; index < operations.size(); index++) {
		NodeOperation *operation = operations[index];
		if (operation->isOutputOperation(rendering)) {
			result->push_back(operation);
		}
	}
}
MemoryBuffer *ExecutionGroup::allocateOutputBuffer(int /*chunkNumber*/,
                                                   rcti *rect)
{
	// we asume that this method is only called from complex execution groups.
	NodeOperation *operation = this->getOutputOperation();
	if (operation->isWriteBufferOperation()) {
		WriteBufferOperation *writeOperation = (WriteBufferOperation *)operation;
		MemoryBuffer *buffer = new MemoryBuffer(writeOperation->getMemoryProxy(), rect);
		return buffer;
	}
	return NULL;
}
void MuteNode::reconnect(ExecutionSystem *graph, OutputSocket *output)
{
	vector<InputSocket *> &inputsockets = this->getInputSockets();
	for (unsigned int index = 0; index < inputsockets.size(); index++) {
		InputSocket *input = inputsockets[index];
		if (input->getDataType() == output->getDataType()) {
			if (input->isConnected()) {
				output->relinkConnections(input->getConnection()->getFromSocket(), false);
				return;
			}
		}
	}
	
	NodeOperation *operation = NULL;
	switch (output->getDataType()) {
		case COM_DT_VALUE:
		{
			SetValueOperation *valueoperation = new SetValueOperation();
			valueoperation->setValue(0.0f);
			operation = valueoperation;
			break;
		}
		case COM_DT_VECTOR:
		{
			SetVectorOperation *vectoroperation = new SetVectorOperation();
			vectoroperation->setX(0.0f);
			vectoroperation->setY(0.0f);
			vectoroperation->setW(0.0f);
			operation = vectoroperation;
			break;
		}
		case COM_DT_COLOR:
		{
			SetColorOperation *coloroperation = new SetColorOperation();
			coloroperation->setChannel1(0.0f);
			coloroperation->setChannel2(0.0f);
			coloroperation->setChannel3(0.0f);
			coloroperation->setChannel4(0.0f);
			operation = coloroperation;
			break;
		}
	}

	if (operation) {
		output->relinkConnections(operation->getOutputSocket(), false);
		graph->addOperation(operation);
	}

	output->clearConnections();
}
bool AntiAliasOperation::determineDependingAreaOfInterest(
        rcti *input,
        ReadBufferOperation *readOperation,
        rcti *output)
{
	rcti imageInput;
	NodeOperation *operation = getInputOperation(0);
	imageInput.xmax = input->xmax + 1;
	imageInput.xmin = input->xmin - 1;
	imageInput.ymax = input->ymax + 1;
	imageInput.ymin = input->ymin - 1;
	return operation->determineDependingAreaOfInterest(&imageInput,
	                                                   readOperation,
	                                                   output);
}
WriteBufferOperation *OutputSocket::findAttachedWriteBufferOperation() const
{
	unsigned int index;
	for (index = 0; index < this->m_connections.size(); index++) {
		SocketConnection *connection = this->m_connections[index];
		NodeBase *node = connection->getToNode();
		if (node->isOperation()) {
			NodeOperation *operation = (NodeOperation *)node;
			if (operation->isWriteBufferOperation()) {
				return (WriteBufferOperation *)operation;
			}
		}
	}
	return NULL;
}
Exemple #17
0
void DisplaceNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
    NodeOperation *operation;
    if (context->getQuality() == COM_QUALITY_LOW)
        operation = new DisplaceSimpleOperation();
    else
        operation = new DisplaceOperation();

    this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph);
    this->getInputSocket(1)->relinkConnections(operation->getInputSocket(1), 1, graph);
    this->getInputSocket(2)->relinkConnections(operation->getInputSocket(2), 2, graph);
    this->getInputSocket(3)->relinkConnections(operation->getInputSocket(3), 3, graph);
    this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket());

    graph->addOperation(operation);
}
bool DisplaceSimpleOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti colorInput;
	NodeOperation *operation = NULL;

	/* the vector buffer only needs a 2x2 buffer. The image needs whole buffer */
	/* image */
	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;
	}

	/* vector */
	if (operation->determineDependingAreaOfInterest(input, readOperation, output)) {
		return true;
	}

	/* scale x */
	operation = getInputOperation(2);
	if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
		return true;
	}

	/* scale y */
	operation = getInputOperation(3);
	if (operation->determineDependingAreaOfInterest(input, readOperation, output) ) {
		return true;
	}

	return false;
}
void ConvertAlphaNode::convertToOperations(NodeConverter &converter, const CompositorContext &context) const
{
	NodeOperation *operation = NULL;
	bNode *node = this->getbNode();

	/* value hardcoded in rna_nodetree.c */
	if (node->custom1 == 1) {
		operation = new ConvertPremulToStraightOperation();
	}
	else {
		operation = new ConvertStraightToPremulOperation();
	}
	
	converter.addOperation(operation);
	
	converter.mapInputSocket(getInputSocket(0), operation->getInputSocket(0));
	converter.mapOutputSocket(getOutputSocket(0), operation->getOutputSocket());
}
void ConvertAlphaNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
	NodeOperation *operation = NULL;
	bNode *node = this->getbNode();

	/* value hardcoded in rna_nodetree.c */
	if (node->custom1 == 1) {
		operation = new ConvertPremulToStraightOperation();
	}
	else {
		operation = new ConvertStraightToPremulOperation();
	}

	this->getInputSocket(0)->relinkConnections(operation->getInputSocket(0), 0, graph);
	this->getOutputSocket(0)->relinkConnections(operation->getOutputSocket());

	graph->addOperation(operation);
}
bool AntiAliasOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti imageInput;
	if (this->m_buffer) {
		return false;
	}
	else {
		NodeOperation *operation = getInputOperation(0);
		imageInput.xmax = operation->getWidth();
		imageInput.xmin = 0;
		imageInput.ymax = operation->getHeight();
		imageInput.ymin = 0;
		if (operation->determineDependingAreaOfInterest(&imageInput, readOperation, output) ) {
			return true;
		}
	}
	return false;
}
bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest(rcti *input, ReadBufferOperation *readOperation, rcti *output)
{
	rcti newInput;
	rcti bokehInput;

	const float max_dim = max(m_width, m_height);
	const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f;
	int maxBlurScalar = this->m_maxBlur * scalar;

	newInput.xmax = input->xmax + maxBlurScalar + 2;
	newInput.xmin = input->xmin - maxBlurScalar + 2;
	newInput.ymax = input->ymax + maxBlurScalar - 2;
	newInput.ymin = input->ymin - maxBlurScalar - 2;
	bokehInput.xmax = COM_BLUR_BOKEH_PIXELS;
	bokehInput.xmin = 0;
	bokehInput.ymax = COM_BLUR_BOKEH_PIXELS;
	bokehInput.ymin = 0;
	

	NodeOperation *operation = getInputOperation(2);
	if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
		return true;
	}
	operation = getInputOperation(1);
	if (operation->determineDependingAreaOfInterest(&bokehInput, readOperation, output) ) {
		return true;
	}
#ifdef COM_DEFOCUS_SEARCH
	rcti searchInput;
	searchInput.xmax = (input->xmax / InverseSearchRadiusOperation::DIVIDER) + 1;
	searchInput.xmin = (input->xmin / InverseSearchRadiusOperation::DIVIDER) - 1;
	searchInput.ymax = (input->ymax / InverseSearchRadiusOperation::DIVIDER) + 1;
	searchInput.ymin = (input->ymin / InverseSearchRadiusOperation::DIVIDER) - 1;
	operation = getInputOperation(3);
	if (operation->determineDependingAreaOfInterest(&searchInput, readOperation, output) ) {
		return true;
	}
#endif
	operation = getInputOperation(0);
	if (operation->determineDependingAreaOfInterest(&newInput, readOperation, output) ) {
		return true;
	}
	return false;
}
void NodeOperationBuilder::determineResolutions()
{
	/* determine all resolutions of the operations (Width/Height) */
	for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
		NodeOperation *op = *it;
		
		if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) {
			unsigned int resolution[2] = {0, 0};
			unsigned int preferredResolution[2] = {0, 0};
			op->determineResolution(resolution, preferredResolution);
			op->setResolution(resolution);
		}
	}
	
	for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
		NodeOperation *op = *it;
		
		if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) {
			unsigned int resolution[2] = {0, 0};
			unsigned int preferredResolution[2] = {0, 0};
			op->determineResolution(resolution, preferredResolution);
			op->setResolution(resolution);
		}
	}
	
	/* add convert resolution operations when needed */
	{
		Links convert_links;
		for (Links::const_iterator it = m_links.begin(); it != m_links.end(); ++it) {
			const Link &link = *it;
			
			if (link.to()->getResizeMode() != COM_SC_NO_RESIZE) {
				NodeOperation &from_op = link.from()->getOperation();
				NodeOperation &to_op = link.to()->getOperation();
				if (from_op.getWidth() != to_op.getWidth() || from_op.getHeight() != to_op.getHeight())
					convert_links.push_back(link);
			}
		}
		for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) {
			const Link &link = *it;
			Converter::convertResolution(*this, link.from(), link.to());
		}
	}
}
void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
	

	
	

	bNode *editorsnode = getbNode();
	NodeColorBalance *n = (NodeColorBalance *)editorsnode->storage;

	NodeInput *inputSocketImage = this->getInputSocket(0);
	NodeInput *inputSocketKey = this->getInputSocket(1);
	NodeOutput *outputSocketImage = this->getOutputSocket(0);
	NodeOutput *outputSocketMatte = this->getOutputSocket(1);
	
	ConvertRGBToHSVOperation *operationRGBToHSV_Image = new ConvertRGBToHSVOperation();
	ConvertRGBToHSVOperation *operationRGBToHSV_Key = new ConvertRGBToHSVOperation();
	converter.addOperation(operationRGBToHSV_Image);
	converter.addOperation(operationRGBToHSV_Key);
	
	NodeOperation *operation;
	ColorBalanceLGGOperation *operationLGG = new ColorBalanceLGGOperation();
	operationLGG->setGain(n->gain);
	operation = operationLGG;
	converter.addOperation(operation);
	
	SetAlphaOperation *operationAlpha = new SetAlphaOperation();
	converter.addOperation(operationAlpha);
	
	converter.mapInputSocket(inputSocketImage, operationRGBToHSV_Image->getInputSocket(0));
	converter.mapInputSocket(inputSocketKey, operationRGBToHSV_Key->getInputSocket(0));
	converter.addLink(operationRGBToHSV_Image->getOutputSocket(), operation->getInputSocket(0));
	converter.addLink(operationRGBToHSV_Key->getOutputSocket(), operation->getInputSocket(1));
	converter.mapOutputSocket(outputSocketMatte, operation->getOutputSocket(0));
	
	converter.mapInputSocket(inputSocketImage, operationAlpha->getInputSocket(0));
	converter.addLink(operation->getOutputSocket(), operationAlpha->getInputSocket(1));
	converter.mapOutputSocket(outputSocketImage, operationAlpha->getOutputSocket());
	
	converter.addPreview(operationAlpha->getOutputSocket());

}
void ColorBalanceNode::convertToOperations(NodeConverter &converter, const CompositorContext &/*context*/) const
{
	bNode *node = this->getbNode();
	NodeColorBalance *n = (NodeColorBalance *)node->storage;

	NodeInput *inputSocket = this->getInputSocket(0);
	NodeInput *inputImageSocket = this->getInputSocket(1);
	NodeOutput *outputSocket = this->getOutputSocket(0);

	NodeOperation *operation;
	if (node->custom1 == 0) {
		ColorBalanceLGGOperation *operationLGG = new ColorBalanceLGGOperation();

		float lift_lgg[3], gamma_inv[3];
		for (int c = 0; c < 3; c++) {
			lift_lgg[c] = 2.0f - n->lift[c];
			gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
		}

		operationLGG->setGain(n->gain);
		operationLGG->setLift(lift_lgg);
		operationLGG->setGammaInv(gamma_inv);
		operation = operationLGG;
	}
	else {
		ColorBalanceASCCDLOperation *operationCDL = new ColorBalanceASCCDLOperation();

		float offset[3];
		copy_v3_fl(offset, n->offset_basis);
		add_v3_v3(offset, n->offset);

		operationCDL->setOffset(offset);
		operationCDL->setPower(n->power);
		operationCDL->setSlope(n->slope);
		operation = operationCDL;
	}
	converter.addOperation(operation);

	converter.mapInputSocket(inputSocket, operation->getInputSocket(0));
	converter.mapInputSocket(inputImageSocket, operation->getInputSocket(1));
	converter.mapOutputSocket(outputSocket, operation->getOutputSocket(0));
}
void DistanceMatteNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
	InputSocket *inputSocketImage = this->getInputSocket(0);
	InputSocket *inputSocketKey = this->getInputSocket(1);
	OutputSocket *outputSocketImage = this->getOutputSocket(0);
	OutputSocket *outputSocketMatte = this->getOutputSocket(1);

	NodeOperation *operation;
	bNode *editorsnode = getbNode();
	NodeChroma *storage = (NodeChroma *)editorsnode->storage;

	/* work in RGB color space */
	if (storage->channel == 1) {
		operation = new DistanceRGBMatteOperation();
		((DistanceRGBMatteOperation *) operation)->setSettings(storage);

		inputSocketImage->relinkConnections(operation->getInputSocket(0), 0, graph);
		inputSocketKey->relinkConnections(operation->getInputSocket(1), 1, graph);
	}
	/* work in YCbCr color space */
	else {
		operation = new DistanceYCCMatteOperation();
		((DistanceYCCMatteOperation *) operation)->setSettings(storage);

		ConvertRGBToYCCOperation *operationYCCImage = new ConvertRGBToYCCOperation();
		inputSocketImage->relinkConnections(operationYCCImage->getInputSocket(0), 0, graph);
		addLink(graph, operationYCCImage->getOutputSocket(), operation->getInputSocket(0));
		graph->addOperation(operationYCCImage);

		ConvertRGBToYCCOperation *operationYCCMatte = new ConvertRGBToYCCOperation();
		inputSocketKey->relinkConnections(operationYCCMatte->getInputSocket(0), 1, graph);
		addLink(graph, operationYCCMatte->getOutputSocket(), operation->getInputSocket(1));
		graph->addOperation(operationYCCMatte);
	}

	if (outputSocketMatte->isConnected()) {
		outputSocketMatte->relinkConnections(operation->getOutputSocket());
	}

	graph->addOperation(operation);

	SetAlphaOperation *operationAlpha = new SetAlphaOperation();
	addLink(graph, operation->getInputSocket(0)->getConnection()->getFromSocket(), operationAlpha->getInputSocket(0));
	addLink(graph, operation->getOutputSocket(), operationAlpha->getInputSocket(1));

	graph->addOperation(operationAlpha);
	addPreviewOperation(graph, context, operationAlpha->getOutputSocket());

	if (outputSocketImage->isConnected()) {
		outputSocketImage->relinkConnections(operationAlpha->getOutputSocket());
	}
}
void NodeOperationBuilder::add_operation_input_constants()
{
	/* Note: unconnected inputs cached first to avoid modifying
	 *       m_operations while iterating over it
	 */
	typedef std::vector<NodeOperationInput*> Inputs;
	Inputs pending_inputs;
	for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
		NodeOperation *op = *it;
		for (int k = 0; k < op->getNumberOfInputSockets(); ++k) {
			NodeOperationInput *input = op->getInputSocket(k);
			if (!input->isConnected())
				pending_inputs.push_back(input);
		}
	}
	for (Inputs::const_iterator it = pending_inputs.begin(); it != pending_inputs.end(); ++it) {
		NodeOperationInput *input = *it;
		add_input_constant_value(input, find_node_input(m_input_map, input));
	}
}
void NodeOperationBuilder::add_complex_operation_buffers()
{
	/* note: complex ops and get cached here first, since adding operations
	 * will invalidate iterators over the main m_operations
	 */
	Operations complex_ops;
	for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it)
		if ((*it)->isComplex())
			complex_ops.push_back(*it);
	
	for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) {
		NodeOperation *op = *it;
		
		DebugInfo::operation_read_write_buffer(op);
		
		for (int index = 0; index < op->getNumberOfInputSockets(); index++)
			add_input_buffers(op, op->getInputSocket(index));
		
		for (int index = 0; index < op->getNumberOfOutputSockets(); index++)
			add_output_buffers(op, op->getOutputSocket(index));
	}
}
void NodeOperationBuilder::group_operations()
{
	for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) {
		NodeOperation *op = *it;
		
		if (op->isOutputOperation(m_context->isRendering())) {
			ExecutionGroup *group = make_group(op);
			group->setOutputExecutionGroup(true);
		}
		
		/* add new groups for associated memory proxies where needed */
		if (op->isReadBufferOperation()) {
			ReadBufferOperation *read_op = (ReadBufferOperation *)op;
			MemoryProxy *memproxy = read_op->getMemoryProxy();
			
			if (memproxy->getExecutor() == NULL) {
				ExecutionGroup *group = make_group(memproxy->getWriteBufferOperation());
				memproxy->setExecutor(group);
			}
		}
	}
}
void ColorBalanceNode::convertToOperations(ExecutionSystem *graph, CompositorContext *context)
{
	InputSocket *inputSocket = this->getInputSocket(0);
	InputSocket *inputImageSocket = this->getInputSocket(1);
	OutputSocket *outputSocket = this->getOutputSocket(0);
	
	bNode *node = this->getbNode();
	NodeColorBalance *n = (NodeColorBalance *)node->storage;
	NodeOperation *operation;
	if (node->custom1 == 0) {
		ColorBalanceLGGOperation *operationLGG = new ColorBalanceLGGOperation();
		{
			int c;
	
			for (c = 0; c < 3; c++) {
				n->lift_lgg[c] = 2.0f - n->lift[c];
				n->gamma_inv[c] = (n->gamma[c] != 0.0f) ? 1.0f / n->gamma[c] : 1000000.0f;
			}
		}
	
		operationLGG->setGain(n->gain);
		operationLGG->setLift(n->lift_lgg);
		operationLGG->setGammaInv(n->gamma_inv);
		operation = operationLGG;
	}
	else {
		ColorBalanceASCCDLOperation *operationCDL = new ColorBalanceASCCDLOperation();
		operationCDL->setGain(n->gain);
		operationCDL->setLift(n->lift);
		operationCDL->setGamma(n->gamma);
		operation = operationCDL;
	}
	
	inputSocket->relinkConnections(operation->getInputSocket(0), 0, graph);
	inputImageSocket->relinkConnections(operation->getInputSocket(1), 1, graph);
	outputSocket->relinkConnections(operation->getOutputSocket(0));
	graph->addOperation(operation);
}