#include "GPUcomputing.h"

void prepareGPUcomputationTexture( unsigned int sizeX, unsigned int sizeY, unsigned int chanelCount, Texture<float> &dstFBOtexture)
{
	dstFBOtexture.internalData.sizeX = sizeX;
	dstFBOtexture.internalData.sizeY = sizeY;
	dstFBOtexture.internalData.type=GL_FLOAT;

	//THIS IS IMPORTANT!!!!
	dstFBOtexture.textureParams.clear();
	dstFBOtexture.textureParams.push_back( TextureParam(GL_TEXTURE_WRAP_S, GL_REPEAT) );
	dstFBOtexture.textureParams.push_back( TextureParam(GL_TEXTURE_WRAP_T, GL_REPEAT) );
	dstFBOtexture.textureParams.push_back( TextureParam(GL_TEXTURE_MAG_FILTER, GL_NEAREST) );
	dstFBOtexture.textureParams.push_back( TextureParam(GL_TEXTURE_MIN_FILTER, GL_NEAREST) );
	//--------------------

	switch ( chanelCount )
	{
	case 1:
		dstFBOtexture.internalFormat=GL_R16F;
		dstFBOtexture.internalData.format=GL_R;
	break;
	case 2:
		dstFBOtexture.internalFormat=GL_RG16F;
		dstFBOtexture.internalData.format=GL_RG;
	break;
	case 3:
		dstFBOtexture.internalFormat=GL_RGB16F;
		dstFBOtexture.internalData.format=GL_RGB;
	break;
	case 4:
		dstFBOtexture.internalFormat=GL_RGBA16F;
		dstFBOtexture.internalData.format=GL_RGBA;
	break;
	default:
		assert(!" Unsuported texture chanell count!");
	break;
	}
		
}

CGprogram loadShaderComputingVS( ShaderManager& dstShaderManager )
{
	bool ok =dstShaderManager.insertVertexShaderDirect( GPU_COMPUTING_VERTEX_PROGRAM, GPU_COMPUTING_VERTEX_PROGRAM_ENTRY, GPU_COMPUTING_VERTEX_PROGRAM );
	assert( ok && !" Something is wrong - GPU_COMPUTING_VERTEX_PROGRAM already exist or is corrupted!" );

	return dstShaderManager.getShader( GPU_COMPUTING_VERTEX_PROGRAM );
}

ShaderComputing::ShaderComputing( CGprogram vertexShader, ShaderComposer fragmentShaderComposer ) : fragmentShaderComposer( fragmentShaderComposer )
{
	this->vertexShader= vertexShader;

}

void ShaderComputing::run( FBO  &fbo, FragmentData &fragmentData)
{
	//TODO PERFOORMANCE: to much viewport switching may cause slow down maybe ???

	fbo.bind();
	//glDisable(GL_DEPTH_TEST);
 //  glEnable(GL_BLEND);
 //  glBlendFunc(GL_ONE, GL_ONE);
 //  int TODO = glGetError();

	//Bind shaders
	cgGLBindProgram( this->vertexShader );
	cgGLBindProgram( this->fragmentShaderComposer.getShader());

	for (int i=0; i < fragmentData.paramContainer.size(); ++i )
	{
		//fragmentShaderComposer.setParam( fragmentData.paramContainer[i].paramName, &fragmentData.paramContainer[i].values[0] );
		fragmentShaderComposer.setParamSmart( fragmentData.paramContainer[i].paramName, &fragmentData.paramContainer[i].values[0] );
	}


	for ( int i=0; i < fragmentData.textureContainer.size(); ++i )
	{
		selectTextureUnit(i);
		glBindTexture( GL_TEXTURE_2D, fragmentData.textureContainer[i] );
	}

	int viewport[4];
    glGetIntegerv(GL_VIEWPORT, viewport);
	glViewport(0, 0, fbo.getFrameSizeX() , fbo.getFrameSizeY() );

	glClear(GL_DEPTH_BUFFER_BIT);

		glBegin(GL_QUADS);
			glTexCoord2f(0,0);			glVertex3f(-1.0, -1.0,0);
			glTexCoord2f(1.0,0);		glVertex3f(1.0,	-1.0,0);
			glTexCoord2f(1.0,1.0);		glVertex3f(1.0,	1.0,0);
			glTexCoord2f(0,1.0);		glVertex3f(-1.0, 1.0,0);
		glEnd();

	glFlush();

	//deactive all texture units	(except the 1st one which is traditionaly enabled)
	for ( int i=1; i< fragmentData.textureContainer.size() ; ++i)
	{
		selectTextureUnit(i);
		//glBindTexture( GL_TEXTURE_2D, 0);
		glDisable(GL_TEXTURE_2D);
	}

	//load viewport settings
	glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);// Obnovení viewportu
	glEnable(GL_DEPTH_TEST);

	fbo.unbind();
}