#include "UiRender.h"

UiRender::UiRender( Context &context, CGprogram vertexShader, CGprogram fragmentShader ):Render(context),vertexShader(vertexShader), fragmentShader(fragmentShader)
{
	//POZNAMKA: musi zvenku dostat shader ktery pouziva prate tyto parametry 
	this->vertexShader.insertParam("modelMatrix", MATRIX4X4_FLOAT);
	this->fragmentShader.insertParam("falloff", ARRAY_FLOAT1);
	this->fragmentShader.insertParam("spotType", ARRAY_FLOAT1);
	this->fragmentShader.insertParam("directional", ARRAY_FLOAT1);
	this->fragmentShader.insertParam("fillLight", ARRAY_FLOAT1);
	this->fragmentShader.insertParam("radiance", ARRAY_FLOAT3);
	this->fragmentShader.insertParam("lightPosition", ARRAY_FLOAT3);
	this->fragmentShader.insertParam("lightDirection", ARRAY_FLOAT3);
	this->fragmentShader.insertParam("eyePosition", FLOAT3);
	this->fragmentShader.insertParam("lightCount", FLOAT1);
	this->fragmentShader.insertParam("Pa", FLOAT3);		//ambient
	this->fragmentShader.insertParam("Pd", FLOAT3);		//diffuse
	this->fragmentShader.insertParam("Ps", FLOAT3);		//speculat
	this->fragmentShader.insertParam("exponent", FLOAT1);
	this->fragmentShader.insertParam("useTexture", FLOAT1);
	this->fragmentShader.insertParam("scale", FLOAT1);	//tonemapping param
	this->fragmentShader.insertParam("invGamma", FLOAT1); //tonemapping param
}

void UiRender::renderLights( vector<DTITLight*> &lights, const vector< CTriCol* >& lightColors )
{
	//WARNING: this function doest use shaders -> shaders have to be deactivated
	//cgGLBindProgram( NULL ); //context Null pointer warning!

	assert ( lights.size() == lightColors.size() );

	this->bind();

	for ( int i=0; i < lights.size(); ++i )
	{
		renderDTITLight( lights[i], lightColors[i] );
	}
}

void UiRender::renderLights( vector<DTITLight*> &lights, const CTriCol* color )
{
	//WARNING: this function doest use shaders -> shaders have to be deactivated
	//cgGLBindProgram( NULL ); //context Null pointer warning!

	this->bind();

	for ( int i=0; i < lights.size(); ++i )
	{
		renderDTITLight( lights[i], color );
	}
}

void UiRender::renderModels( vector<DTITLight*> &lights, vector<Model*> &models, float scale, float gamma )
{
	glPushMatrix();
	this->bind();	//bind + sets viewMatrix
	
	//Bind shaders
	cgGLBindProgram( this->vertexShader.getShader() );
	cgGLBindProgram( this->fragmentShader.getShader());

	this->fragmentShader.setParam("eyePosition", this->cameraPos);

	//tone mapping data
	float invGamma = 1.0/gamma;
	this->fragmentShader.setParam("scale", &scale );
	this->fragmentShader.setParam("invGamma", &invGamma );


	float tmp[3];

	for (int i=0; i< lights.size(); ++i)
	{
		switch (lights[i]->subtype)
		{
			case SPOT_PHONG:
			{
				this->fragmentShader.setArrayParamOnIndex("spotType", i, &SPOT_BASIC);
				this->fragmentShader.setArrayParamOnIndex("fillLight", i, &NO_FILL_LIGHT);
			}
			break;

			case DIRECTIONAL_PHONG:
				//fall through ( will be rendered like Rectangle light for now )

			case RECTANGLE_PHONG:
			{
				//until Rectangle light shader not implemented use OmniLight
				this->fragmentShader.setArrayParamOnIndex("spotType", i, &NO_SPOT);
				this->fragmentShader.setArrayParamOnIndex("fillLight", i, &NO_FILL_LIGHT);
			}
			break;

			case OMNI_PHONG:
			{
				this->fragmentShader.setArrayParamOnIndex("spotType", i, &NO_SPOT);
				this->fragmentShader.setArrayParamOnIndex("fillLight", i, &NO_FILL_LIGHT);
			}
			break;

			
			tmp[0] = lights[i]->color[0] * lights[i]->intensity;
			tmp[1] = lights[i]->color[1] * lights[i]->intensity;
			tmp[2] = lights[i]->color[2] * lights[i]->intensity;
			this->fragmentShader.setArrayParamOnIndex("radiance",i , tmp);

			tmp[0]=lights[i]->direction.x();
			tmp[1]=lights[i]->direction.y();
			tmp[2]=lights[i]->direction.z();
			this->fragmentShader.setArrayParamOnIndex("lightDirection",i , tmp);

			this->fragmentShader.setArrayParamOnIndex("falloff", i, &lights[i]->attenuation );
			this->fragmentShader.setArrayParamOnIndex("directional", i, &lights[i]->directionalExp);

			tmp[0]=lights[i]->position.x();
			tmp[1]=lights[i]->position.y();
			tmp[2]=lights[i]->position.z();
			this->fragmentShader.setArrayParamOnIndex("lightPosition",i , tmp);
		}
	}

	float lightCount = lights.size();
	this->fragmentShader.setParam("lightCount", &lightCount );

	for (int i=0; i<models.size(); ++i)
	{
		glPushMatrix();
			
		
		Matrix4X4<float> modelMatrix;
		models[i]->getModelMatrix(modelMatrix);

		this->vertexShader.setMatrixParam("modelMatrix", modelMatrix.getPtr());

		glMatrixMode(GL_MODELVIEW);			
		glMultMatrixf( modelMatrix.getPtr() );


		for (int n=0; n<models[i]->meshes.size(); ++n)
		{
			if (models[i]->meshes[n].material!=NULL)
			{
				assert(models[i]->meshes[n].material->getMaterialType()== PHONG);

				PhongMaterial *material= (PhongMaterial*) models[i]->meshes[n].material;

				this->fragmentShader.setParam("Pa", material->ambient);
				this->fragmentShader.setParam("Pd", material->diffuse);
				this->fragmentShader.setParam("Ps", material->specular);
				this->fragmentShader.setParam("exponent", &material->specular_exp ); 
			}
			else
			{
				float def[]={0,0,0};
				float defS=32;
					
				this->fragmentShader.setParam("Pd", def);
				this->fragmentShader.setParam("Ps", def);
				this->fragmentShader.setParam("exponent", &defS);
			}
				
			//use texture
			float useTexture[1];
			if ( models[i]->meshes[n].textures.empty() )	//no tex coord availible
			{
				useTexture[0]=0.0; //dont use texture
			}
			else
			{
				useTexture[0]=1.0; //use texture
			}

			this->fragmentShader.setParam("useTexture", useTexture);
			VBOmanager::renderVBO(models[i]->meshes[n].vbo_data, models[i]->meshes[n].textures );

		}

		glPopMatrix();
	}
	glPopMatrix();
}

void UiRender::beginFrame(const Camera<float>& camera)
{
	this->cameraPos[0]=camera.pos.x();
	this->cameraPos[1]=camera.pos.y();
	this->cameraPos[2]=camera.pos.z();

	Render::beginFrame(camera);
}