/*
 * 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: 
 *		Jeroen Bakker 
 *		Monique Dewanchand
 */

#include "COM_ColorCurveOperation.h"

#ifdef __cplusplus
extern "C" {
#endif
	#include "BKE_colortools.h"
#ifdef __cplusplus
}
#include "MEM_guardedalloc.h"
#endif

ColorCurveOperation::ColorCurveOperation() : CurveBaseOperation()
{
	this->addInputSocket(COM_DT_VALUE);
	this->addInputSocket(COM_DT_COLOR);
	this->addInputSocket(COM_DT_COLOR);
	this->addInputSocket(COM_DT_COLOR);
	this->addOutputSocket(COM_DT_COLOR);

	this->m_inputFacProgram = NULL;
	this->m_inputImageProgram = NULL;
	this->m_inputBlackProgram = NULL;
	this->m_inputWhiteProgram = NULL;

	this->setResolutionInputSocketIndex(1);
}
void ColorCurveOperation::initExecution()
{
	CurveBaseOperation::initExecution();
	this->m_inputFacProgram = this->getInputSocketReader(0);
	this->m_inputImageProgram = this->getInputSocketReader(1);
	this->m_inputBlackProgram = this->getInputSocketReader(2);
	this->m_inputWhiteProgram = this->getInputSocketReader(3);

	curvemapping_premultiply(this->m_curveMapping, 0);

}

void ColorCurveOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
{
	CurveMapping *cumap = this->m_curveMapping;
	
	float fac[4];
	float image[4];

	/* local versions of cumap->black, cumap->white, cumap->bwmul */
	float black[4];
	float white[4];
	float bwmul[3];

	this->m_inputBlackProgram->read(black, x, y, sampler);
	this->m_inputWhiteProgram->read(white, x, y, sampler);

	/* get our own local bwmul value,
	 * since we can't be threadsafe and use cumap->bwmul & friends */
	curvemapping_set_black_white_ex(black, white, bwmul);

	this->m_inputFacProgram->read(fac, x, y, sampler);
	this->m_inputImageProgram->read(image, x, y, sampler);

	if (*fac >= 1.0f) {
		curvemapping_evaluate_premulRGBF_ex(cumap, output, image,
		                                    black, bwmul);
	}
	else if (*fac <= 0.0f) {
		copy_v3_v3(output, image);
	}
	else {
		float col[4];
		curvemapping_evaluate_premulRGBF_ex(cumap, col, image,
		                                    black, bwmul);
		interp_v3_v3v3(output, image, col, *fac);
	}
	output[3] = image[3];
}

void ColorCurveOperation::deinitExecution()
{
	CurveBaseOperation::deinitExecution();
	this->m_inputFacProgram = NULL;
	this->m_inputImageProgram = NULL;
	this->m_inputBlackProgram = NULL;
	this->m_inputWhiteProgram = NULL;
}


// Constant level curve mapping

ConstantLevelColorCurveOperation::ConstantLevelColorCurveOperation() : CurveBaseOperation()
{
	this->addInputSocket(COM_DT_VALUE);
	this->addInputSocket(COM_DT_COLOR);
	this->addOutputSocket(COM_DT_COLOR);

	this->m_inputFacProgram = NULL;
	this->m_inputImageProgram = NULL;

	this->setResolutionInputSocketIndex(1);
}
void ConstantLevelColorCurveOperation::initExecution()
{
	CurveBaseOperation::initExecution();
	this->m_inputFacProgram = this->getInputSocketReader(0);
	this->m_inputImageProgram = this->getInputSocketReader(1);

	curvemapping_premultiply(this->m_curveMapping, 0);

	curvemapping_set_black_white(this->m_curveMapping, this->m_black, this->m_white);
}

void ConstantLevelColorCurveOperation::executePixel(float output[4], float x, float y, PixelSampler sampler)
{
	float fac[4];
	float image[4];

	this->m_inputFacProgram->read(fac, x, y, sampler);
	this->m_inputImageProgram->read(image, x, y, sampler);

	if (*fac >= 1.0f) {
		curvemapping_evaluate_premulRGBF(this->m_curveMapping, output, image);
	}
	else if (*fac <= 0.0f) {
		copy_v3_v3(output, image);
	}
	else {
		float col[4];
		curvemapping_evaluate_premulRGBF(this->m_curveMapping, col, image);
		interp_v3_v3v3(output, image, col, *fac);
	}
	output[3] = image[3];
}

void ConstantLevelColorCurveOperation::deinitExecution()
{
	CurveBaseOperation::deinitExecution();
	this->m_inputFacProgram = NULL;
	this->m_inputImageProgram = NULL;
}
