#include "ofShader.h"


char *textFileRead(char *fn);		// some memory allocation happens here
									// be careful...  please don't call load shader 
									// repeatedly !!!!! (you have been warned)



static GLint getUniformLocation(GLuint program, const GLchar *name){
    int loc;
	loc = glGetUniformLocation(program, name);
	printf("name: %s : %i \n",name,loc ); 
	 if (loc == -1)
        printf("No such uniform named \"%s\"\n", name);
	return loc;
}

//---------------------------------------------------------------
void ofShader::loadShader(char * fragmentName, char * vertexName){
	
	
	bLoaded = false;	
	
	if (GLEE_ARB_shader_objects){
		
		// ---------------------------------- (a) load in the shaders
		char *vs = NULL,*fs = NULL;
		vs = textFileRead(vertexName);
		fs = textFileRead(fragmentName);
		GLint compileStatus = 0;
		
		
		vertexShader 	= glCreateShader(GL_VERTEX_SHADER);
		fragmentShader 	= glCreateShader(GL_FRAGMENT_SHADER);
		
		
		int length = strlen(vs);
		glShaderSourceARB(vertexShader, 1, (const char**)&vs, &length);
		length = strlen(fs);
		glShaderSourceARB(fragmentShader, 1, (const char**)&fs, &length);
		
		
		// ----------------------------------- (b) compile the shaders
		// try to compile "vertex shader"
		glCompileShaderARB(vertexShader);
		
		glGetObjectParameterivARB( vertexShader, GL_COMPILE_STATUS, &compileStatus );
		
		//--------------------- if we didn't compile, 
		//--------------------- tell the user why:
		
		if (compileStatus == 0){
			char infobuffer[1000];
			int infobufferlen = 0;
			glGetInfoLogARB(vertexShader, 999, &infobufferlen, infobuffer);
			if (infobufferlen != 0){
				infobuffer[infobufferlen] = 0;
				printf("--------------");
				printf("error compiling:\n\n");
				printf("vertexShader reports: %s \n", infobuffer);
				printf("--------------");
				return;
			}
		}
		// ------------------------------------
		// try to compile "fragment shader"
		glCompileShaderARB(fragmentShader);
		
		glGetObjectParameterivARB( fragmentShader, GL_COMPILE_STATUS, &compileStatus );
		
		//--------------------- if we didn't compile, 
		//--------------------- tell the user why:
		
		if (compileStatus == 0){
			char infobuffer[1000];
			int infobufferlen = 0;
			glGetInfoLogARB(fragmentShader, 999, &infobufferlen, infobuffer);
			if (infobufferlen != 0){
				infobuffer[infobufferlen] = 0;
				printf("--------------");
				printf("error compiling:\n\n");
				printf("fragmentShader reports: %s \n", infobuffer);
				printf("--------------");
				return;
			}
		}
		
		// ----------------------------------- (c) link the shaders
		shader = glCreateProgramObjectARB();
		glAttachObjectARB(shader,vertexShader);
		glAttachObjectARB(shader,fragmentShader);
		glLinkProgramARB(shader);
		
		glUseProgramObjectARB(shader);
		
		glUniform3f(getUniformLocation(shader, "BrickColor"), 1.0, 0.3, 0.2);
		glUniform3f(getUniformLocation(shader, "MortarColor"), 0.85, 0.86, 0.84);
		glUniform2f(getUniformLocation(shader, "BrickSize"), 30.0, 30.0);
		glUniform2f(getUniformLocation(shader, "BrickPct"), 0.90, 0.85);
		glUniform3f(getUniformLocation(shader, "LightPosition"), 500.0, 500.0, 3.0);
		
		
		bLoaded = true;
			
	} else {
	
		printf("sorry, it looks like you can't run 'ARB_shader_objects' \n please check the capabilites of your graphics card (http://www.ozone3d.net/gpu_caps_viewer/) \n");
	
	}


}
		
//---------------------------------------------------------------
void ofShader::loadShader(char * shaderName){
	bLoaded = false;
	char fragmentName[1024];
	char vertexName[1024];
	sprintf(fragmentName, "%s.frag", shaderName);
	sprintf(vertexName, "%s.vert", shaderName);
	loadShader(fragmentName, vertexName);
}



//---------------------------------------------------------------
void ofShader::unload(){
	
	if (vertexShader){
		glDetachObjectARB(shader,vertexShader);
		glDeleteObjectARB(vertexShader);
		vertexShader = NULL;
	}
	
	if (fragmentShader){
		glDetachObjectARB(shader,fragmentShader);
		glDeleteObjectARB(fragmentShader);
		fragmentShader = NULL;
	}
	
	if (shader){
		glDeleteObjectARB(shader);
		shader = NULL;
	}
	
}

//---------------------------------------------------------------

void ofShader::setShaderActive(bool bActive){
	if (GLEE_ARB_shader_objects && bLoaded == true){
		if (bActive == true){
			glUseProgramObjectARB(shader);
		} else {
			glUseProgramObjectARB(0);
		}
	}

}

//---------------------------------------------------------------
void ofShader::setUniformVariable (char * name, float value){
	if (bLoaded == true){
		glUniform1fARB(glGetUniformLocationARB(shader, name), value);
	}
}


//---------------------------------------------------------
// below is from: www.lighthouse3d.com
// you may use these functions freely. they are provided as is, and no warranties, either implicit, or explicit are given
//---------------------------------------------------------

char *textFileRead(char *fn) {

	FILE *fp;
	char *content 	= 	NULL;
	int count		=	0;

	if (fn != NULL) {
		fp = fopen(fn,"rt");
		if (fp != NULL) {
		
		      
      fseek(fp, 0, SEEK_END);
      count = ftell(fp);
      rewind(fp);

			if (count > 0) {
				content = (char *)malloc(sizeof(char) * (count+1));
				count = fread(content,sizeof(char),count,fp);
				content[count] = '\0';
			}
			fclose(fp);
		}
	}
	
	return content;
}
