
#include "load_shaders.h"

///fonction qui renvoie la chaine de caractère comprenant tout le fichier
/**	@param filename : nom du fichier à lire
 * 	@return chaine de caractère comprenant tout le fichier
*/
char* loadSource(const char *filename){
	char *src = NULL;   /* code source de notre shader */
	FILE *fp = NULL;    /* fichier */
	long size;          /* taille du fichier */
	long i;             /* compteur */
	
	/* on ouvre le fichier */
	fp = fopen(filename, "r");
	/* on verifie si l'ouverture a echoue */
	if(fp == NULL){
		fprintf(stderr, "impossible d'ouvrir le fichier '%s'\n", filename);
		return NULL;
	}
	
	/* on recupere la longueur du fichier */
	fseek(fp, 0, SEEK_END);
	size = ftell(fp);
	
	/* on se replace au debut du fichier */
	rewind(fp);
	
	/* on alloue de la memoire pour y placer notre code source */
	src = malloc(size+1); /* +1 pour le caractere de fin de chaine '\0' */
	if(src == NULL){
		fclose(fp);
		fprintf(stderr, "erreur d'allocation de memoire!\n");
		return NULL;
	}
	
	/* lecture du fichier */
	for(i=0; i<size; i++)
		src[i] = fgetc(fp);
	
	/* on place le dernier caractere a '\0' */
	src[size] = '\0';
	
	fclose(fp);
	
	return src;
}


///fonction qui permet d'initialiser un shader
/**	@param type : type du shader (GL_VERTEX_SHADER pour les vertices (*.vert) ou GL_FRAGMENT_SHADER pour les pixels (*.frag))
 * 	@param filename : nom du fichier à lire
 * 	@return identifiant du shader ou 0 si l'initialisation à échouée.
*/
GLuint loadShader(GLenum type, const char *filename){
	GLuint shader = 0;
	GLsizei logsize = 0;
	GLint compile_status = GL_TRUE;
	char *log = NULL;
	char *src = NULL;
	shader = glCreateShader(type); /* creation d'un shader de type type */
	if(shader == 0){
		fprintf(stderr, "impossible de creer le shader\n");
		return 0;
	}
	src = loadSource(filename);           /* chargement du code source */
	if(src == NULL)	{
		/* theoriquement, la fonction LoadSource a deja affiche un message
		d'erreur, nous nous contenterons de supprimer notre shader
		et de retourner 0 */
		glDeleteShader(shader);
		return 0;
	}
	glShaderSource(shader, 1, (const GLchar**)&src, NULL); /* assignation du code source */
	glCompileShader(shader);                               /* compilation du shader */
	free(src);                                             /* liberation de la memoire du code source */
	src = NULL;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compile_status); /* verification du succes de la compilation */
	if(compile_status != GL_TRUE){      /* erreur a la compilation recuperation du log d'erreur */
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &logsize);  /* on recupere la taille du message d'erreur */
		log = malloc(logsize + 1);                            /* on alloue un espace memoire dans lequel OpenGL ecrira le message */
		if(log == NULL){
			fprintf(stderr, "impossible d'allouer de la memoire !\n");
			return 0;
		}
		memset(log, '\0', logsize + 1);                    /* initialisation du contenu */
		glGetShaderInfoLog(shader, logsize, &logsize, log);
		fprintf(stderr, "impossible de compiler le shader '%s' :\n%s", filename, log);
		free(log);                                         /* ne pas oublier de liberer la memoire et notre shader */
		glDeleteShader(shader);
		return 0;
	}
	return shader;
}

///fonction qui lie un programme avec les shaders qui lui sont attachés
/**	@param programID : id du programme à linker
 * 	@return 1 si le linkage à réussie, 0 sinon
*/
int linkGlProgram(GLuint programID){
	glLinkProgram(programID);
	GLint linkingResult = GL_TRUE;
	glGetProgramiv(programID, GL_COMPILE_STATUS, &linkingResult);
	if(linkingResult != GL_TRUE){                              /* erreur a la compilation récuperation du log d'erreur */
		char *log = NULL;
		GLint logsize;
		glGetShaderiv(programID, GL_INFO_LOG_LENGTH, &logsize);  /* on recupere la taille du message d'erreur */
		log = malloc(logsize + 1);                     /* on alloue un espace memoire dans lequel OpenGL ecrira le message */
		if(log == NULL){
			fprintf(stderr, "impossible d'allouer de la memoire !\n");
			return 0;
		}
		memset(log, '\0', logsize + 1);     /* initialisation du contenu */
		
		glGetProgramInfoLog(programID, logsize, &logsize, log);
		fprintf(stderr, "impossible linker le programme :\n%s", log);
		free(log); /* ne pas oublier de liberer la memoire et notre shader */
		return 0;
	}else return 1;
}


