//////////////////////////////////////////////////////////////////////
// shader.h: place your shader classes here
//////////////////////////////////////////////////////////////////////

#include "shader.hpp"

#include <stdlib.h>
#include <stdio.h>
#include <iostream>
#include <fstream>

using namespace std;

//////////////////////////////////////////////
// ShaderHolder class 
//////////////////////////////////////////////

void ShaderHolder::init() {

		
			static const char *emptyVertex = {
					"varying vec2 Tex_coord;"\
					"void main(void) "\
					"{"\
					"   gl_Position = ftransform();"\
					"   gl_TexCoord[0] = gl_MultiTexCoord0;"\
					"}"	
			};

			// *** BlurX

			static const char *blurxVertex = {
					"varying vec2 pos0;"\
					"varying vec2 pos1;"\
					"varying vec2 pos2;"\
					"varying vec2 pos3;"\
					"varying vec2 pos4;"\
					"uniform float xoff;"\
					"void main(void) "\
					"{"\
					"   vec2 DX = vec2(xoff,0.0);"\
					"   vec2 DX2 = vec2(2.0*xoff,0.0);"\
		            "   pos0 = gl_MultiTexCoord0.st-DX2;"\
					"   pos1 = gl_MultiTexCoord0.st-DX;"\
					"   pos2 = gl_MultiTexCoord0.st;"\
					"   pos3 = gl_MultiTexCoord0.st+DX;"\
					"   pos4 = gl_MultiTexCoord0.st+DX2;"\
					"   gl_Position = ftransform();"\
					"}"	
			};

			// *** BlurY

			static const char *bluryVertex = {
					"varying vec2 pos0;"\
					"varying vec2 pos1;"\
					"varying vec2 pos2;"\
					"varying vec2 pos3;"\
					"varying vec2 pos4;"\
					"uniform float yoff;"\
					"void main(void) "\
					"{"\
					"   vec2 DX = vec2(0.0, yoff);"\
					"   vec2 DX2 = vec2(0.0, 2.0*yoff);"\
		            "   pos0 = gl_MultiTexCoord0.st-DX2;"\
					"   pos1 = gl_MultiTexCoord0.st-DX;"\
					"   pos2 = gl_MultiTexCoord0.st;"\
					"   pos3 = gl_MultiTexCoord0.st+DX;"\
					"   pos4 = gl_MultiTexCoord0.st+DX2;"\
					"   gl_Position = ftransform();"\
					"}"	
			};

			// *** BlurFragment

			static const char *blurFragment = {
              "uniform sampler2D tex;"\
			  "varying vec2 pos0;"\
			  "varying vec2 pos1;"\
			  "varying vec2 pos2;"\
			  "varying vec2 pos3;"\
			  "varying vec2 pos4;"\
              "uniform float alpha;"\
              "void main()"\
              "{"\

              "   vec4 col = vec4(0,0,0,0);"\
              "   col+=texture2D(tex, pos0)*0.1;"\
              "   col+=texture2D(tex, pos1)*0.25;"\
              "   col+=texture2D(tex, pos2)*0.5;"\
              "   col+=texture2D(tex, pos3)*0.25;"\
              "   col+=texture2D(tex, pos4)*0.1;"\
              "   gl_FragColor = col*alpha;"\
              "}"
			};

			static const char *blur2Fragment = {
              "uniform sampler2D tex;"\
			  "varying vec2 pos0;"\
			  "varying vec2 pos1;"\
			  "varying vec2 pos2;"\
			  "varying vec2 pos3;"\
			  "varying vec2 pos4;"\
              "uniform float alpha;"\
              "void main()"\
              "{"\
              "   vec4 col = vec4(0,0,0,0);"\
              "   col+=texture2D(tex, pos0)*0.1;"\
              "   col+=texture2D(tex, pos1)*0.2;"\
              "   col+=texture2D(tex, pos2)*0.4;"\
              "   col+=texture2D(tex, pos3)*0.2;"\
              "   col+=texture2D(tex, pos4)*0.1;"\
              "   gl_FragColor = col*alpha;"\
              "}"
			};

			// *** glow combine

			static const char *glowcVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"   gl_Position = ftransform();"\
				"}"
			};


			static const char *glowcFragment = {
				"uniform sampler2D texunit0;"\
				"uniform sampler2D texunit1;"\
				"uniform float glow_amount;"\
				"varying vec2 coord;"\
				"void main()"\
				"{"\
				"	vec4 norm = texture2D(texunit0, coord);"\
				"	vec4 glow = texture2D(texunit1, coord)*glow_amount;"\
				"	gl_FragColor = norm+glow;"\
				"}"
			};

            // *** displacement

			static const char *displaceVertex = {
				"varying vec2 coord;"\
				"varying vec2 coord2;"\
				"void main(void) "\
				"{"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"   coord2 = gl_MultiTexCoord1.xy;"\
				"   gl_Position = ftransform();"\
				"}"
			};

            static const char *displaceFragment = {
                "uniform sampler2D texunit0;"\
                "uniform sampler2D texunit1;"\
                "uniform float displace_amount;"\
                "uniform float alpha;"\
                "varying vec2 coord;"\
                "varying vec2 coord2;"\
                "void main()"\
                "{"\
                "   vec2 offs = texture2D(texunit1, coord2).xy;"\
                "   vec4 col = texture2D(texunit0, coord+offs*displace_amount);"\
                "   col *= alpha; "\
                "   gl_FragColor = col;"\
                "}"
            };

            // *** invert

			static const char *invertVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"   gl_Position = ftransform();"\
				"}"
			};

            static const char *invertFragment = {
                "uniform sampler2D texunit0;"\
                "uniform float invert_amount ;"\
                "uniform float alpha;"\
                "varying vec2 coord;"\
                "void main()"\
                "{"\
                "   vec4 col = texture2D(texunit0, coord);"\
                "   col.x = col.x * (1.0-invert_amount) + (1.0-col.x) * invert_amount; "\
                "   col.y = col.y * (1.0-invert_amount) + (1.0-col.y) * invert_amount; "\
                "   col.z = col.z * (1.0-invert_amount) + (1.0-col.z) * invert_amount; "\
                "   col *= alpha; "\
                "   gl_FragColor = col;"\
                "}"
            };


			// *** darken 

			static const char *darkenVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   gl_Position = ftransform();"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"}"
			};

			static const char *darkenFragment = {
				"uniform sampler2D tex;"\
				"uniform float alpha;"\
				"varying vec2 coord;"\
				"void main()		"\
				"{"\
				"   vec4 c = texture2D(tex, coord); "\
				"	gl_FragColor = c*c*alpha; "\
				"}"
			};

			// *** blackwhite

			static const char *bwVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   gl_Position = ftransform();"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"}"
			};

			static const char *bwFragment = {
				"uniform sampler2D tex;"\
				"uniform float threshold;"\
				"varying vec2 coord;"\
				"void main()		"\
				"{"\
				"   vec4 c = texture2D(tex, coord); "\
				"   if( (c.x+c.y+c.z)/3.0 < threshold ) "\
				"	 gl_FragColor = vec4(0,0,0,1); "\
				"	else "\
				"	 gl_FragColor = vec4(1,1,1,1); "\
				"}"
			};

			// *** edge detetion stuff

			// http://en.wikipedia.org/wiki/Sobel
			// tätä voi optata siirtämällä positiot vertexshaderille
			const char *edgeFragment = {
				"	uniform sampler2D tex;"\
				"	const float off = 1.0 / 512.0;"\
				"	void main()"\
				"	{"\
				/* naapurimatriisi */
				"	vec4 s00 = texture2D(tex, gl_TexCoord[0].xy + vec2(-off, -off));"\
				"	vec4 s01 = texture2D(tex, gl_TexCoord[0].xy + vec2( 0, -off));"\
				"	vec4 s02 = texture2D(tex, gl_TexCoord[0].xy + vec2( off, -off));"\
				"	vec4 s10 = texture2D(tex, gl_TexCoord[0].xy + vec2(-off, 0));"\
				"	vec4 s12 = texture2D(tex, gl_TexCoord[0].xy + vec2( off, 0));"\
				"	vec4 s20 = texture2D(tex, gl_TexCoord[0].xy + vec2(-off, off));"\
				"	vec4 s21 = texture2D(tex, gl_TexCoord[0].xy + vec2( 0, off));"\
				"	vec4 s22 = texture2D(tex, gl_TexCoord[0].xy + vec2( off, off));"\
				/* sobel filtteriarvoja */
				"	vec4 sobelX = s00 + 2.0 * s10 + s20 - s02 - 2.0 * s12 - s22;"\
				"	vec4 sobelY = s00 + 2.0 * s01 + s02 - s20 - 2.0 * s21 - s22;"\
				"	vec4 edgeSqr = vec4(sobelX * sobelX +  sobelY * sobelY);"\
				/* grayscale */
				"	float val = (edgeSqr.x+edgeSqr.y+edgeSqr.z)/1.0;"\
				"	gl_FragColor = vec4(val,val,val,0);"
				/* alpha ?? */
				"}"

			};

			//lighting

			static const char *lightpointFragment = {
				"varying vec4 diffuse,ambientGlobal, ambient;"\
				"varying vec3 normal,lightDir,halfVector;"\
				"varying vec4 epos;"\
				"varying float dist;"\
				"varying vec2 coord;"\
				"uniform sampler2D tex;"\
				"vec4 light0 ()"\
				" {"\
				" vec4 color;"\
				" vec3 L = normalize(gl_LightSource[0].position.xyz - epos.xyz); "\
				" vec3 E = normalize(-epos.xyz);"\
				" vec3 R = normalize(-reflect(L,normal)); "\
				" float dist = length(L);"\
				" float atten = 1.0 / (gl_LightSource[0].constantAttenuation +"\
				"               gl_LightSource[0].linearAttenuation * dist +"\
				"               gl_LightSource[0].quadraticAttenuation * dist * dist);"\
				" vec4 Iamb = gl_LightSource[0].ambient*gl_FrontMaterial.ambient;"\
				" vec4 Idiff = (gl_LightSource[0].diffuse * max(dot(normal,L), 0.0))*gl_FrontMaterial.diffuse;"\
				" vec4 Ispec = gl_FrontMaterial.specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);"\
				" "\
				" color = gl_FrontMaterial.emission+Iamb+atten*(gl_FrontMaterial.ambient + Idiff + Ispec);"\
				" return color;"\
				" }"\
				" void main (void)"\
				" {"\
				" gl_FragColor = (light0())*texture2D(tex, coord);"\
				" }"
			};
			
			static const char *lightpointVertex = {
				"varying vec4 diffuse,ambientGlobal,ambient;"\
				"varying vec3 normal,lightDir,halfVector;"\
				"varying vec4 epos;"\
				"varying float dist;"\
				"varying vec2 coord;"\
				"void main()"\
				"{   "\
				"   vec3 aux;"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"   normal = normalize(gl_NormalMatrix * gl_Normal);"\
				/*"   //lightpos&dist"\*/
				"   epos = gl_ModelViewMatrix * gl_Vertex;"\
				"   aux = vec3(gl_LightSource[0].position-epos);"\
				"   lightDir = normalize(aux);"\
				"   dist = length(aux);"\
				/*"   //halfvector"\*/
				"   halfVector = normalize(gl_LightSource[0].halfVector.xyz);"\
				"   diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;"\
				"   ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;"\
				"   ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;"\
				"   gl_Position = ftransform();"\
				"}"
			};



			static const char *lightambientpointFragment = {
				"varying vec4 diffuse,ambientGlobal, ambient;"\
				"varying vec3 normal,lightDir,halfVector;"\
				"varying vec4 epos;"\
				"varying float dist;"\
				"vec4 light0 ()"\
				" {"\
				" vec4 color;"\
				" vec3 L = normalize(gl_LightSource[0].position.xyz - epos.xyz); "\
				" vec3 E = normalize(-epos.xyz);"\
				" vec3 R = normalize(-reflect(L,normal)); "\
				" float dist = length(L);"\
				" float atten = 1.0 / (gl_LightSource[0].constantAttenuation +"\
				"               gl_LightSource[0].linearAttenuation * dist +"\
				"               gl_LightSource[0].quadraticAttenuation * dist * dist);"\
				" vec4 Iamb = gl_LightSource[0].ambient*gl_FrontMaterial.ambient;"\
				" vec4 Idiff = (gl_LightSource[0].diffuse * max(dot(normal,L), 0.0))*gl_FrontMaterial.diffuse;"\
				" vec4 Ispec = gl_FrontMaterial.specular * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);"\
				" "\
				" color = gl_FrontMaterial.emission+Iamb+atten*(gl_FrontMaterial.ambient + Idiff + Ispec);"\
				" return color;"\
				" }"\
				" void main (void)"\
				" {"\
				" gl_FragColor = (light0())*ambientGlobal;"\
				" }"
			};
			
			static const char *lightambientpointVertex = {
				"varying vec4 diffuse,ambientGlobal,ambient;"\
				"varying vec3 normal,lightDir,halfVector;"\
				"varying vec4 epos;"\
				"varying float dist;"\
				"void main()"\
				"{   "\
				"   vec3 aux;"\
				"   normal = normalize(gl_NormalMatrix * gl_Normal);"\
				/*"   //lightpos&dist"\*/
				"   epos = gl_ModelViewMatrix * gl_Vertex;"\
				"   aux = vec3(gl_LightSource[0].position-epos);"\
				"   lightDir = normalize(aux);"\
				"   dist = length(aux);"\
				/*"   //halfvector"\*/
				"   halfVector = normalize(gl_LightSource[0].halfVector.xyz);"\
				"   diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;"\
				"   ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient;"\
				"   ambientGlobal = gl_LightModel.ambient * gl_FrontMaterial.ambient;"\
				"   gl_Position = ftransform();"\
				"}"
			};

			// *** gradient fade from image
			// 

			static const char *gradientfadeVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   gl_Position = ftransform();"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"}"
			};

			static const char *gradientfadeFragment = {
				"uniform sampler2D tex;"\
				"uniform sampler2D gradient;"\
				"uniform float value;"\
				"uniform float value2;"\
				"varying vec2 coord;"\
				"void main()		"\
				"{"\
				"   vec4 actc = texture2D(tex, coord); "\
				"   vec4 gradientcolor = texture2D(gradient, coord); "\
				"   vec4 empty = vec4(1,1,1,0);"\
				"	float liuku = smoothstep(value, value2, gradientcolor.r);"\
				"	gl_FragColor = mix(actc, empty, liuku);"\
				"}"
			};

			// *** depth of field blur 
			// 

			static const char *dofVertex = {
				"varying vec2 coord;"\
				"void main(void) "\
				"{"\
				"   gl_Position = ftransform();"\
				"   coord = gl_MultiTexCoord0.xy;"\
				"}"
			};

			static const char *dofFragment = {
				"uniform sampler2D texunit0;"\
				"uniform sampler2D texunit1;"\
				"uniform sampler2D texunit2;"\
				"uniform float near;"\
				"uniform float focus;"\
				"uniform float far;"\
				"varying vec2 coord;"\
				"void main()"\
				"{"\
				"	float f;"\
				/*flip*/
				"	float depth = 255.0 - texture2D(texunit2, coord).r;"\
				/* cosini / catmull lerppi olis tyylikkäämpi..*/
				"	if(depth < focus)"\
				"	{"\
				"		f = (depth - focus)/(focus - near);"\
				"	} else {"\
				"		f = (depth - focus)/(far - focus);"\
				"	}"\
				/*"		f = f * 0.5 + 0.5; "\*/
				"	vec4 norm = texture2D(texunit0, coord)*(1.0-f);"\
				"	vec4 blurred = texture2D(texunit1, coord)*f;"\
				"	gl_FragColor = norm+blurred;"\
				/*"	gl_FragColor = texture2D(texunit2 , coord);"\*/
				"}"
			};




//"	float liuku = smoothstep(value, value2, gradientcolor.r);"

	dmsMsg("ShaderHolder::init() : Initializing shaders\n");

	blurx = new Shader();
	blurx->init("blurx", blurFragment, blurxVertex);

	blury = new Shader();
	blury->init("blury", blurFragment, bluryVertex);

	blur2x = new Shader();
	blur2x->init("blur2x", blur2Fragment, blurxVertex);

	blur2y = new Shader();
	blur2y->init("blur2y", blur2Fragment, bluryVertex);

	darken = new Shader();
	darken->init("darken",darkenFragment, darkenVertex);

	glowc = new Shader();
	glowc->init("glowc", glowcFragment, glowcVertex);

	edge = new Shader();
	edge->init("lap", edgeFragment, emptyVertex);

	displace = new Shader();
	displace->init("displace", displaceFragment, displaceVertex);

	invert = new Shader();
	invert->init("invert", invertFragment, invertVertex);

    blackwhite = new Shader();
	blackwhite->init("blackwhite", bwFragment, bwVertex);

//	lightdir = new Shader();
//	lightdir->init("lightdir", lightFragment, lightVertex);

	lightpoint = new Shader();
	lightpoint->init("lightpoint", lightpointFragment, lightpointVertex);

	lightambientpoint = new Shader();
	lightambientpoint->init("lightambientpoint", lightambientpointFragment, lightambientpointVertex);

	gradientfade = new Shader();
	gradientfade->init("gradientfade", gradientfadeFragment, gradientfadeVertex);

	dof = new Shader();
	dof->init("depthoffield", dofFragment, dofVertex);

	// varmistetana ettei ole sheideriä aktiivisena
	this->unbind();

	init_ok = true;

	dmsMsg("ShaderHolder::init() : Shaders created\n");
}

void ShaderHolder::deinit() {

	if(!init_ok) return;

	blurx->deinit();
	delete blurx;

	blury->deinit();
	delete blury;

	darken->deinit();
	delete darken;

	glowc->deinit();
	delete glowc;

	edge->deinit();
	delete edge;

	blackwhite->deinit();
	delete blackwhite;

	lightpoint->deinit();
	delete lightpoint;

	lightambientpoint->deinit();
	delete lightambientpoint;

	gradientfade->deinit();
	delete gradientfade;

	invert->deinit();
	delete invert;
	
	dof->deinit();
	delete dof;

	dmsMsg("ShaderHolder::deinit() : Shaders released\n");
}

//////////////////////////////////////////////
// Shader class 
//////////////////////////////////////////////
void Shader::init(const char *name_, const char *frag, const char *vert) {

	this->name = name_;

	vertex = glCreateShaderObjectARB(GL_VERTEX_SHADER_ARB);
	glShaderSourceARB(this->vertex, 1, &vert,NULL);
	glCompileShaderARB(this->vertex);
	debugShader(vertex, name_);

	fragment = glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
	glShaderSourceARB(this->fragment, 1, &frag,NULL);
	glCompileShaderARB(this->fragment);
	debugShader(fragment, name_);

	program = glCreateProgramObjectARB();
	glAttachObjectARB(this->program,vertex);
	glAttachObjectARB(this->program,fragment);
	glLinkProgramARB(this->program);
	debugShader(this->program, name_);

	glUseProgramObjectARB(program);
}

void Shader::initFromFile(const char *name_, char *fragFile, char *vertFile) {
  
	char fr[10000], vr[10000];

	this->loadFromFile(fragFile, fr);
	this->loadFromFile(vertFile, vr);

    // load vertex program
   if (vertFile!=0)
   if (vr == 0)
   { 
	  
	   memset(vr,' ',10000);
	  char buf[100];
	  sprintf(buf, "error: couldn't load vertex shader! [%s from %s] \n", name_, vertFile);
	  MessageBox(dmsGetHWND(), buf, name_, MB_OK|MB_TOPMOST);     
      dmsMsg("Error: couldn't load vertex shader [%s from %s]\n", name_, vertFile);
   }

  
  // Load fragment program
  if (fragFile!=0)
  if (fr == 0)
  {
	  memset(fr,' ',10000);
      dmsMsg("Error: couldn't load fragment shader [%s from %s]\n", name_, fragFile);
	  char buf[100];
	  sprintf(buf, "Error: couldn't load vertex shader! [%s from %s]\n", name_, fragFile);
	  MessageBox(dmsGetHWND(), buf, name_, MB_OK|MB_TOPMOST);

  }
	init(name_ , fr, vr);
}

bool Shader::loadFromFile(char *filename, char* buffer) {

	std::fstream f;
	f.open(filename, std::ios::in|std::ios::binary);

	if (!f.is_open() || !f.good())
	{
		MessageBox(dmsGetHWND(), filename, "Failed to load file", MB_OK|MB_TOPMOST);
		dmsMsg("ERROR: Failed to load %s\n", filename);
		return false;
	}

	// clear old list
	char chunk_char=' ';
	std::string text;

	while (f.good())
	{
			f.read(&chunk_char, sizeof(char));
			text.append(1,chunk_char);
	}

	strncpy(buffer, text.c_str(), 10000);

	f.close();

	return true;
}

void Shader::deinit() {
		glDeleteShader(vertex);
		glDeleteShader(fragment);
		glDeleteProgram(program);
}

void Shader::bind() {
		glUseProgramObjectARB(this->program);
}

void Shader::unbind() {
		glUseProgramObjectARB(0);
}

////////////////////////////////////////////////////////////////
// PARAMETER PASSING 
////////////////////////////////////////////////////////////////

bool Shader::setUniform1f(char* varname, GLfloat v0)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform1fARB(loc, v0);
    
    return true;
}

bool Shader::setUniform2f(char* varname, GLfloat v0, GLfloat v1)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform2fARB(loc, v0, v1);
    
    return true;
}

bool Shader::setUniform3f(char* varname, GLfloat v0, GLfloat v1, GLfloat v2)
{
    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform3fARB(loc, v0, v1, v2);

    return true;
}

bool Shader::setUniform4f(char* varname, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform4fARB(loc, v0, v1, v2, v3);

    return true;
}

bool Shader::setUniform1i(char* varname, GLint v0)
{ 


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform1iARB(loc, v0);
    
    return true;
}
bool Shader::setUniform2i(char* varname, GLint v0, GLint v1)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform2i(loc, v0, v1);


    return true;
}

bool Shader::setUniform3i(char* varname, GLint v0, GLint v1, GLint v2)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform3i(loc, v0, v1, v2);

    return true;
}
bool Shader::setUniform4i(char* varname, GLint v0, GLint v1, GLint v2, GLint v3)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform4i(loc, v0, v1, v2, v3);

    return true;
}

bool Shader::setUniform1fv(char* varname, GLsizei count, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform1fv(loc, count, value);

    return true;
}
bool Shader::setUniform2fv(char* varname, GLsizei count, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform2fv(loc, count, value);

    return true;
}

bool Shader::setUniform3fv(char* varname, GLsizei count, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform3fv(loc, count, value);

    return true;
}

bool Shader::setUniform4fv(char* varname, GLsizei count, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform4fv(loc, count, value);

    return true;
}

bool Shader::setUniform1iv(char* varname, GLsizei count, GLint *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform1iv(loc, count, value);

    return true;
}

bool Shader::setUniform2iv(char* varname, GLsizei count, GLint *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform2iv(loc, count, value);

    return true;
}

bool Shader::setUniform3iv(char* varname, GLsizei count, GLint *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform3iv(loc, count, value);

    return true;
}

bool Shader::setUniform4iv(char* varname, GLsizei count, GLint *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniform4iv(loc, count, value);

    return true;
}

bool Shader::setUniformMatrix2fv(char* varname, GLsizei count, GLboolean transpose, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniformMatrix2fv(loc, count, transpose, value);

    return true;
}

bool Shader::setUniformMatrix3fv(char* varname, GLsizei count, GLboolean transpose, GLfloat *value)
{


    
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniformMatrix3fv(loc, count, transpose, value);

    return true;
}

bool Shader::setUniformMatrix4fv(char* varname, GLsizei count, GLboolean transpose, GLfloat *value)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
    
    glUniformMatrix4fv(loc, count, transpose, value);

    return true;
}

GLint Shader::GetUniLoc(const GLcharARB *name)
{
	GLint loc;

	loc = glGetUniformLocationARB(this->program, name);
	if (loc == -1) 
	{
        dmsMsg("Error: can't find uniform variable %s from %s\n", name, this->name);

	}
	return loc;
}

void Shader::GetUniformfv(char* name, GLfloat* values)
{
    GLint loc;

	loc = glGetUniformLocationARB(this->program, name);
	if (loc == -1) 
	{
		dmsMsg("Error: can't find uniform variable %s \n", name);
	}
	glGetUniformfvARB(this->program, loc, values);
	
}

void Shader::GetUniformiv(char* name, GLint* values)
{
    GLint loc;

	loc = glGetUniformLocationARB(this->program, name);
	if (loc == -1) 
	{
        dmsMsg("Error: can't find uniform variable %s \n", name);
	}
	
	glGetUniformivARB(this->program, loc, values);

}

bool Shader::setVertexAttrib1f(char *varname, GLfloat v0)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
   glVertexAttrib1f(loc, v0);

   return true;
}

bool Shader::setVertexAttrib2f(char *varname, GLfloat v0, GLfloat v1)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable
   glVertexAttrib2f(loc, v0, v1);
   
   return true;
}

bool Shader::setVertexAttrib3f(char *varname, GLfloat v0, GLfloat v1, GLfloat v2)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable   
    glVertexAttrib3f(loc, v0, v1, v2);
    
    return true;
}

bool Shader::setVertexAttrib4f(char *varname, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3)
{
    GLint loc = GetUniLoc(varname);
    if (loc==-1) return false;  // can't find variable

   glVertexAttrib4f(loc, v0, v1, v2, v3);
   
   return true;
}

////////////////////////////////////////////////////////////
// Debug global
////////////////////////////////////////////////////////////

void debugShader(GLuint obj, const char *name)
{
	int infologLength = 0;
	char infoLog[1024];
 
	if (glIsShader(obj))  {
		glGetShaderInfoLog(obj, 1024, &infologLength, infoLog);
		if(infologLength>0) MessageBox(dmsGetHWND(), infoLog, name, MB_OK|MB_TOPMOST);		
	}  else  {
		glGetProgramInfoLog(obj, 1024, &infologLength, infoLog);

	}	
		
}	

////////////////////////////////////////////////////////////
// ShaderHolder
////////////////////////////////////////////////////////////

void ShaderHolder::unbind() {
		glUseProgramObjectARB(0);
}