#ifndef DEF_TX_SHADERS
 #define DEF_TX_SHADERS

//------------------------------------------//
//		TKA4 Shaders Setup Graph classes	//
//				10. 11. 2007				//
//------------------------------------------//


//--- Includes
#include "gl_add.h"
#include "TX_Error.h"
//=== Includes 


//--- Defines
#define SV_LIGHT_POS	"LightPos"
#define SV_EYE_POS		"EyePos"
// Material
#define SV_DIFF_COLOR	"DiffColor"
#define SV_AMBI_COLOR	"AmbiColor"
#define SV_SPEC_COLOR	"SpecColor"
#define SV_EMIS_COLOR	"EmisColor"
#define SV_SHINE_COLOR	"ShineColor"
//=== Defines


class txShader {
public :
	txErrorFile  *Log;
	
	GLhandleARB  handle;
	GLhandleARB  vertex;
	GLhandleARB  fragment;
	

	txShader() { vertex=fragment=handle=0; };

	//--- Check OpenGL errors
	bool inline CheckGL () {
		for ( ; ; ) {
			GLenum  glErr = glGetError ();
			if ( glErr == GL_NO_ERROR ) return false;
			*Log+txError(-1, "glError", (char*) gluErrorString (glErr));
		}
		return true;
	}


	//--- Print Info
	void inline PrintInfo ()
	{
		int         logLength     = 0;
		int         charsWritten  = 0;
		GLcharARB*  infoLog;

		glGetObjectParameterivARB (handle, GL_OBJECT_INFO_LOG_LENGTH_ARB, &logLength );
		
		if ( logLength > 0 )
		{
			infoLog = (GLcharARB*) malloc(logLength);

			if ( infoLog == NULL )
				*Log+txError(0, "Shader. Error Loading", "Could not allocate ShaderInfoLog buffer");
							
			glGetInfoLogARB (handle, logLength, &charsWritten, infoLog);

			*Log+txError(0, "Shader. Info", infoLog);
			free   ( infoLog );
		}
	}


	//--- Load Shader
	bool inline LoadShaderProgram (GLhandleARB  h, char * fileName )
	{
		FILE *file = fopen ( fileName, "rb" );
		if ( file == NULL ) {
			*Log+txError(0, "Shader. Error opening", fileName);
		}

		fseek (file, 0, SEEK_END);
		int	size = ftell (file);
		if (size < 1) {
			fclose ( file );
			*Log+txError(0, "Shader. Error loading", fileName);
		}
	
		char *buf = (char *) malloc (size);
		fseek (file, 0, SEEK_SET);
		if ( fread (buf, 1, size, file) != size) {
			fclose (file);
			*Log+txError(0, "Shader. Error loading", fileName);
		}
		fclose (file);

		//--- --- --- 
		glShaderSourceARB ( h, 1, (const char **) &buf, &size );
        glCompileShaderARB (h);
		free(buf);

		if ( !CheckGL() )          
			return false;

		GLint   compileStatus;
		glGetObjectParameterivARB (h, GL_OBJECT_COMPILE_STATUS_ARB, &compileStatus );
		PrintInfo();

		return compileStatus != 0;
	}


	//--- Set Data Variables
	bool inline SetData (const char *name, const float *value, int r)
	{
		glUseProgramObjectARB (handle);
		int loc = glGetUniformLocationARB (handle, name);
		
		if ( loc < 0 ) {
			glUseProgramObjectARB(0);
			return false;
		}

		glUniform4fvARB(loc, r, value);

		glUseProgramObjectARB (0);

		return true;
	}


	bool inline SetUniformFloat ( const char * name, float value )
	{
		glUseProgramObjectARB (handle);

		int loc = glGetUniformLocationARB (handle, name );
		if ( loc < 0 )
			return false;
		glUniform1fARB ( loc, value );

		glUseProgramObjectARB (0);
		return true;
	}


	//--- Enable 
	void inline  Enable() { glUseProgramObjectARB (handle); }


	//--- Disable
	void inline Disable() { glUseProgramObjectARB (0); }


	//--- Init
	void inline Init() {
		//--- Test support
		if ( glewInit () != GLEW_OK )
			*Log+txError(0, "Shader", "glewInit() error");
			
		if ( !GLEW_ARB_shading_language_100 )
			*Log+txError(0, "Shader", "GL_ARB_shading_language_100 not supported" );

		if ( !GLEW_ARB_shader_objects )
    		*Log+txError(0, "Shader", "GL_ARB_shader_objects not supported");
     }
	//--- Load
	void  Load (char *Vname, char *Fname) 
	{
		GLint  linked;
    
		vertex   = glCreateShaderObjectARB ( GL_VERTEX_SHADER_ARB   );
		fragment = glCreateShaderObjectARB ( GL_FRAGMENT_SHADER_ARB );
        handle   = glCreateProgramObjectARB();

		LoadShaderProgram (vertex, Vname);
        LoadShaderProgram (fragment, Fname);
        
		glAttachObjectARB (handle, vertex);
		glAttachObjectARB (handle, fragment);

        glLinkProgramARB (handle);

		CheckGL();
        
		glGetObjectParameterivARB (handle, GL_OBJECT_LINK_STATUS_ARB, &linked);

		if ( !linked )
			*Log+txError(0, "Shader", "not linked");
	}

};


#endif