#include "ShaderComposer.h"


ParamInfo::ParamInfo(paramType type)
{
	this->type=type;
	this->value=NULL;
}

ShaderComposer::ShaderComposer(CGprogram shader)
{
	this->shader=shader;
}

void ShaderComposer::setShader(CGprogram shader)
{
	this->shader=shader;
}

ShaderComposer::ShaderComposer(void)
{
	this->shader= NULL;
}

ShaderComposer::~ShaderComposer(void)
{
}

CGprogram ShaderComposer::getShader(void)
{
	return this->shader;
}


void ShaderComposer::insertParam(const string& name, paramType type)
{
	ParamInfo param(type);

	this->params.insert(make_pair(name,param));
}
bool ShaderComposer::setMatrixParam(const string& name, const float* values)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		assert(!" problem v shaderu");
		return false;
	}

	CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );

	switch (it->second.type)
	{
	case MATRIX4X4_FLOAT:
		cgGLSetMatrixParameterfc(cgParam,values);


	//old version ( ignore )
	//	cgGLSetMatrixParameterfr(cgParam,values);	// Matrix4X4<float> is ROW MAJOR (D3D matrix layout) which is the reason why I use this method ( CG SPEC: "cgSetMatrixParameterfr sets the value of a given matrix parameter from an array of floats laid out in row-major order." )
		break;
	default:
		assert(!" Unsuported cg data type");
		return false;
	}

	return true;
}

bool ShaderComposer::setMatrixParamColumn(const string& name, const float* values)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		assert(!" problem v shaderu");
		return false;
	}

	CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );

	switch (it->second.type)
	{
	case MATRIX4X4_FLOAT:
		cgGLSetMatrixParameterfc(cgParam,values);
		break;
	default:
		assert(!" Unsuported cg data type");
		return false;
	}

	return true;
}

bool ShaderComposer::setArrayParam(const string& name, const float* values)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		assert(!" problem v shaderu");
		return false;
	}


	CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );
	

	switch (it->second.type)
	{
		
	case ARRAY_FLOAT1:
		cgGLSetParameterArray1f(cgParam, 0, 0, values);	//CG: Passing a value of 0 for numberOfElements tells the functions to set all the values starting at index startIndex up to the last valid index of the array,
		break;
	case ARRAY_FLOAT2:
		cgGLSetParameterArray2f(cgParam, 0, 0, values);
		break;
		
	case ARRAY_FLOAT3:
		cgGLSetParameterArray3f(cgParam, 0, 0,values);

		break;
	case ARRAY_FLOAT4:
		cgGLSetParameterArray4f(cgParam, 0, 0, values);
		break;

	default:
		assert(!" Unsuported cg data type");
	break;
	}

	it->second.value=NULL; //primo nacitane parametry ukazuji na NULL aby je bylo mozne rozeznat ve funkci loadParamFromPtr a nenacitat je znovu
	return true;
}
bool ShaderComposer::setArrayParamOnIndex(const string& name, unsigned int idx, const float* values)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		assert(!" problem v shaderu");
		return false;
	}


	CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );
	CGparameter cgIdx= cgGetArrayParameter(cgParam, idx);

	switch (it->second.type)
	{
		
	case ARRAY_FLOAT1:
		cgGLSetParameter1fv(cgIdx, values);	//CG: Passing a value of 0 for numberOfElements tells the functions to set all the values starting at index startIndex up to the last valid index of the array,
		break;
	case ARRAY_FLOAT2:
		cgGLSetParameter2fv(cgIdx, values);
		break;
		
	case ARRAY_FLOAT3:
		cgGLSetParameter3fv(cgIdx, values);
		break;
	case ARRAY_FLOAT4:
		cgGLSetParameter4fv(cgIdx, values);
		break;

	default:
		assert(!" Unsuported cg data type");
	break;
	}

	it->second.value=NULL; //primo nacitane parametry ukazuji na NULL aby je bylo mozne rozeznat ve funkci loadParamFromPtr a nenacitat je znovu
	return true;
}


bool ShaderComposer::setParamSmart( const string& name, const float* values)
{
	map<string, ParamInfo>::iterator it =this->params.find( name );

	if (it == this->params.end() )
	{
		return false;	//parameter with given name was not found
	}
	else
	{
		/*
		FLOAT1,
	FLOAT2,
	FLOAT3,
	FLOAT4,
	FLOAT4x4,

	ARRAY_FLOAT1,
	ARRAY_FLOAT2,
	ARRAY_FLOAT3,
	ARRAY_FLOAT4,

	MATRIX4X4_FLOAT
	*/
		switch ( it->second.type )
		{
		case FLOAT1:
			//fall throught!!!
		case FLOAT2:
			//fall throught!!!
		case FLOAT3:
			//fall throught!!!
		case FLOAT4:
			this->setParam( name, values);
			break;

		case ARRAY_FLOAT1:
			//fall throught!!!
		case ARRAY_FLOAT2:
			//fall throught!!!
		case ARRAY_FLOAT3:
			//fall throught!!!
		case ARRAY_FLOAT4:
			this->setArrayParam( name, values );
			break;

		case MATRIX4X4_FLOAT:
			this->setMatrixParam( name, values );
			break;

		default:
			assert( "unsuported cg type" );
			return false;
			break;
		}
	}

	return true;
}

bool ShaderComposer::setParam(const string& name, const float* value)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		return false;
	}

	CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );

	switch (it->second.type)
	{
	case FLOAT1:
		cgGLSetParameter1fv(cgParam, value);
		break;
	case FLOAT2:
		cgGLSetParameter2fv(cgParam, value);
		break;
	case FLOAT3:
		cgGLSetParameter3fv(cgParam, value);
		break;
	case FLOAT4:
		cgGLSetParameter4fv(cgParam, value);
		break;
	case FLOAT4x4:
		cgGLSetMatrixParameterfr(cgParam, value);
		break;
	default:
		assert(!" Unsuported cg data type");
		break;
	}

	it->second.value=NULL; //primo nacitane parametry ukazuji na NULL aby je bylo mozne rozeznat ve funkci loadParamFromPtr a nenacitat je znovu
	return true;
}
bool ShaderComposer::setParamPtr(const string& name, const float* value)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	map<string, ParamInfo>::iterator it=this->params.find(name);

	if (it==this->params.end())
	{
		return false;
	}

	it->second.value=value;
	return true;
}

void ShaderComposer::loadParamFromPtr(void)
{
	assert( shader && "CGprogram ukazuje na NULL!!!");

	for (map<string, ParamInfo>::iterator it=this->params.begin(); it!=this->params.end(); ++it)
	{
		if (it->second.value==NULL)
		{
			continue;
		}

		CGparameter cgParam=cgGetNamedParameter(this->shader, it->first.c_str() );

		switch (it->second.type)
		{
		case FLOAT1:
			cgGLSetParameter1fv(cgParam, it->second.value);
			break;
		case FLOAT2:
			cgGLSetParameter2fv(cgParam, it->second.value);
			break;
		case FLOAT3:
			cgGLSetParameter3fv(cgParam, it->second.value);
			break;
		case FLOAT4:
			cgGLSetParameter4fv(cgParam, it->second.value);
			break;
		case FLOAT4x4:
			cgGLSetMatrixParameterfc(cgParam, it->second.value);
			break;
		default:
			assert(!" Unsuported cg data type");
			break;
		}
	}
}

