#include "LiftGammaGain.H"
#include <math.h>

static int clamp_255( int in ) {
	int out;
	if ( in < 0 ) {
		return 0;
	}
	if ( in > 255 ) {
		return 255;
	}
	return in;
}

static int f_to_i( float in ) {
	return (int)( in * 255 );
}
static float i_to_f( int in ) {
	return (float)in / 255.0;
}

LiftGammaGain::LiftGammaGain()
{
	for ( unsigned int i = 0; i < 256; i++ ) {
		m_red[i] = i;
		m_green[i] = i;
		m_blue[i] = i;
	}
	m_lift[0] = m_lift[1] = m_lift[2] = 1.0;
	m_gamma[0] = m_gamma[1] = m_gamma[2] = 1.0;
	m_gain[0] = m_gain[1] = m_gain[2] = 1.0;
}
LiftGammaGain::~LiftGammaGain()
{
}
static float red( float* a ) {
	return a[0];
}
static float green( float* a ) {
	return a[1];
}
static float blue( float* a ) {
	return a[2];
}
void LiftGammaGain::lift( float r, float g, float b )
{
	m_lift[0] = r;
	m_lift[1] = g;
	m_lift[2] = b;
	calc_luts();
}
void LiftGammaGain::gamma( float r, float g, float b )
{
	m_gamma[0] = r;
	m_gamma[1] = g;
	m_gamma[2] = b;
	calc_luts();
}
void LiftGammaGain::gain( float r, float g, float b )
{
	m_gain[0] = r;
	m_gain[1] = g;
	m_gain[2] = b;
	calc_luts();
}

void LiftGammaGain::calc_luts()
{
	// r goes from 0.0 to 1.0
	float gain, lift, gamma;
	bool m_constant_green = false;
	if ( m_constant_green ) {
		for ( unsigned int i = 0; i < 256; i++ ) {
			/* Red */
			/* Cyan => Rv */
			/* Magenta => R^ B^ */
			gamma = 1.0 / ( 1.0 - ( green( m_gamma ) - red( m_gamma ) ) );
			gain = 1.0 - (green( m_gain ) - red( m_gain ));
			lift = red( m_lift ) - green( m_lift );
			m_red[i] = clamp_255(f_to_i(  pow( (( i_to_f(i) * gain ) + lift ), gamma ) ) );

			/* Blue */
			/* Magenta => R^ B^ */
			/* Yellow => Bv */
			gamma = 1.0 / ( 1.0 - ( green( m_gamma ) - blue( m_gamma ) ) );
			gain = 1.0 - (green( m_gain ) - blue( m_gain ));
			lift = blue( m_lift ) - green( m_lift );
			m_blue[i] = clamp_255(f_to_i(  pow( (( i_to_f(i) * gain ) + lift ), gamma ) ) );
		}
	} else {
		for ( unsigned int i = 0; i < 256; i++ ) {
			/* Red */
			/* Cyan => Rv */
			/* Magenta => R^ B^ */
			gamma = 1.0 / red( m_gamma );
			gain = red( m_gain );
			lift = red( m_lift ) - 1.0;
			m_red[i] = clamp_255(f_to_i(  pow( (( i_to_f(i) * gain ) + lift ), gamma ) ) );

			/* Blue */
			/* Magenta => R^ B^ */
			/* Yellow => Bv */
			gamma = 1.0 / blue( m_gamma );
			gain = blue( m_gain );
			lift = blue( m_lift ) - 1.0;
			m_blue[i] = clamp_255(f_to_i(  pow( (( i_to_f(i) * gain ) + lift ), gamma ) ) );

			gamma = 1.0 / green( m_gamma );
			gain = green( m_gain );
			lift = green( m_lift ) - 1.0;
			m_green[i] = clamp_255(f_to_i(  pow( (( i_to_f(i) * gain ) + lift ), gamma ) ) );
		}
	}

}


