#include "PAppTestSdlGl3.h"
#include "sdlglutils.h"

const float VITESSE_ROTATION_CUBE(0.3);
const float VITESSE_CAMERA(3.0);



/////////////////////////////////////////////////////////
//                                                     //
//   Fonctions publiques de la classe PAppTestSdlGl3   //
//                                                     //
/////////////////////////////////////////////////////////


///Constructeur par défaut de PAppTestSdlGl3
PAppTestSdlGl3::PAppTestSdlGl3(const std::string& titreFenetre, int largeurFenetre, int hauteurFenetre)
	:PAppSdlOpenGl3(titreFenetre, largeurFenetre, hauteurFenetre)
{
	initialisationPAppTestSdlGl3();
}

///Destructeur de PAppTestSdlGl3
PAppTestSdlGl3::~PAppTestSdlGl3(){
	delete[] p_vertices;
	delete[] p_indices;
	delete[] p_textCoordBleu;
	delete[] p_textCoordVert;
	delete[] p_textCoordRouge;
	glDeleteProgram(p_programTest);
}

///fonction qui met à jour l'application
/**	@param dt : intervalle de temps entre deux calcul
*/
void PAppTestSdlGl3::update(float dt){
	if(keyEventMadeNoRepeat("close")){stop();}
	
	if(keyEventMadeRepeat("forward")) p_cameraGL.moveVisee(VITESSE_CAMERA*dt);
	else if(keyEventMadeRepeat("backward")) p_cameraGL.moveVisee(-VITESSE_CAMERA*dt);
	
	if(keyEventMadeRepeat("right")) p_cameraGL.moveGauche(-VITESSE_CAMERA*dt);
	else if(keyEventMadeRepeat("left")) p_cameraGL.moveGauche(VITESSE_CAMERA*dt);
	
	if(keyEventMadeRepeat("turnRight")) p_cameraGL.turnRight(VITESSE_ROTATION_CUBE*dt);
	else if(keyEventMadeRepeat("turnLeft")) p_cameraGL.turnLeft(VITESSE_ROTATION_CUBE*dt);
	
	if(keyEventMadeRepeat("turnUp")) p_cameraGL.turnUp(VITESSE_ROTATION_CUBE*dt);
	else if(keyEventMadeRepeat("turnDown")) p_cameraGL.turnDown(VITESSE_ROTATION_CUBE*dt);
}

///fonction qui affiche toute la scène 3D
void PAppTestSdlGl3::draw3d(){
	// Activation du shader et des tableaux Vertex Attrib (0 pour les vertices, 1 pour les couleurs, 2 pour les textures)
	glEnableVertexAttribArray(0);  //les coordonnées
	glEnableVertexAttribArray(1);  //les coordonnées de textures
	glUseProgram(p_programTest);
	glBindTexture(GL_TEXTURE_2D, p_texture);
	//on envoie les matrices de projection et modelview
	sendMatProjectionToShader(p_idMatriceProjection);
	sendMatModelViewToShader(p_idMatriceModelView);
	
	drawTexturedCube3D();
	glBindTexture(GL_TEXTURE_2D, 0);
	glUseProgram(0);
	glDisableVertexAttribArray(1);  //on désactive les textures
	glDisableVertexAttribArray(0);  //on désactive les vertices
}

///////////////////////////////////////////////////////
//                                                   //
//   Fonctions private de la classe PAppTestSdlGl3   //
//                                                   //
///////////////////////////////////////////////////////

///fonction uqi affiche un cube texturé en 3D
void PAppTestSdlGl3::drawTexturedCube3D(){
	glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, p_vertices);
	
	/* ***** Première face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordRouge);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, p_indices);

	/* ***** Deuxième face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordVert);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &p_indices[6]);

	/* ***** Troisième face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordBleu);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &p_indices[12]);

	/* ***** Quatrième face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordRouge);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &p_indices[18]);

	/* ***** Cinquième face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordVert);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &p_indices[24]);

	/* ***** Sixième face ***** */
	glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, p_textCoordBleu);
	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, &p_indices[30]);
}

///Fonction d'initialisation de la classe PAppTestSdlGl3
void PAppTestSdlGl3::initialisationPAppTestSdlGl3(){
	initialisationTouches();
	initilisationCamera();
	initialisationProgrammeShader();
	initialisationTexture();
	initialisationVertices();
	initialisationColors();
	initialisationTextureCoodonnees();
	initialisationIndex();
}

///fonction qui initialise les touches
void PAppTestSdlGl3::initialisationTouches(){
	addKeyEventRepeat("turnRight", SDLK_RIGHT);
	addKeyEventRepeat("turnLeft", SDLK_LEFT);
	addKeyEventRepeat("turnUp", SDLK_UP);
	addKeyEventRepeat("turnDown", SDLK_DOWN);
	
	addKeyEventNoRepeat("close", SDLK_ESCAPE);
	
	addKeyEventRepeat("forward", SDLK_z);
	addKeyEventRepeat("backward", SDLK_s);
	addKeyEventRepeat("right", SDLK_d);
	addKeyEventRepeat("left", SDLK_q);
}

///fonction qui initialise la caméra
void PAppTestSdlGl3::initilisationCamera(){
	p_cameraGL.setPosition(-30.0, 0.0, 50.0);
	p_cameraGL.setPhi(M_PI/2.0 + M_PI/4.0);
	p_cameraGL.setTheta(M_PI/7.0);
}

///fonction qui initialise le programme qui utilisera les shaders
void PAppTestSdlGl3::initialisationProgrammeShader(){
	p_programTest = glCreateProgram();
	GLuint fragmentShader = loadShader(GL_FRAGMENT_SHADER, GL_FRAGMENT_SHADER_CUBE);
	GLuint vertexShader = loadShader(GL_VERTEX_SHADER, GL_VERTEX_SHADER_CUBE);
	
	//on attache les shaders au programme
	glAttachShader(p_programTest, fragmentShader);
	glAttachShader(p_programTest, vertexShader);
	//on lie le programme
	int linkingResult = linkGlProgram(p_programTest);
	if(linkingResult == 0){
		glDeleteProgram(p_programTest);
		dontRun();
	}else{
		p_idMatriceModelView = glGetUniformLocation(p_programTest, "modelview");
		p_idMatriceProjection = glGetUniformLocation(p_programTest, "projection");
	}
}

///fonction qui initialise la texture
void PAppTestSdlGl3::initialisationTexture(){
// 	p_texture = loadTexture("../images/Flat_Wood163.JPG");
	if(!loadTextureGl3(p_texture, GL_TEXTURE_CUBE)){
		dontRun();
	}
}

///fonction qui initialise les Vertices
void PAppTestSdlGl3::initialisationVertices(){
	unsigned int tailleTabVertices(8 * 3);
	float arreteCube = 5.0;
	// Vertices
	float vertices[] = {	-arreteCube,	-arreteCube,	-arreteCube,	arreteCube,
				-arreteCube,	-arreteCube,	arreteCube,	arreteCube,
				-arreteCube,	-arreteCube,	arreteCube,	-arreteCube,
				-arreteCube,	-arreteCube,	arreteCube,	arreteCube,
				-arreteCube,	arreteCube,	arreteCube,	arreteCube,
				arreteCube,	-arreteCube,	arreteCube,	arreteCube};
				
	p_vertices = new float[tailleTabVertices];
	for(unsigned int i(0); i < tailleTabVertices; i++) p_vertices[i] = vertices[i];
}

///fonction qui initialise les couleurs
void PAppTestSdlGl3::initialisationColors(){
	
}

///fonction qui initialise les Coordonnées de textures
void PAppTestSdlGl3::initialisationTextureCoodonnees(){
	unsigned int tailleTabTexCoord(8 * 2);
	
	float textureCoordRouge[] = {0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0,	0.0, 0.0,   1.0, 0.0,   1.0, 1.0,   0.0, 1.0};
	float textureCoordVert[] = {1.0, 0.0,   1.0, 0.0,   0.0, 0.0,   0.0, 0.0, 	1.0, 1.0,   1.0, 1.0,   0.0, 1.0,   0.0, 1.0};
	float textureCoordBleu[] = {0.0, 0.0,   1.0, 0.0,   1.0, 0.0,   0.0, 0.0, 	0.0, 1.0,   1.0, 1.0,   1.0, 1.0,   0.0, 1.0};
	
	p_textCoordBleu = new float[tailleTabTexCoord];
	p_textCoordVert = new float[tailleTabTexCoord];
	p_textCoordRouge = new float[tailleTabTexCoord];
	
	for(unsigned int i(0); i < tailleTabTexCoord; i++){
		p_textCoordBleu[i] = textureCoordBleu[i];
		p_textCoordVert[i] = textureCoordVert[i];
		p_textCoordRouge[i] = textureCoordRouge[i];
	}
}

///fonction qui initialise les index des faces à dessiner
void PAppTestSdlGl3::initialisationIndex(){
	unsigned int tailleTabIndices(6 * 2 * 3);
	p_indices = new unsigned int[tailleTabIndices];
	// Indices
	unsigned int indices [] = {	0, 1, 2,   2, 3, 0,   // Face 1
					5, 1, 2,   2, 6, 5,   // Face 2
					0, 1, 5,   5, 4, 0,   // Face 3
					4, 5, 6,   6, 7, 4,   // Face 4
					0, 4, 7,   7, 3, 0,   // Face 5
					7, 6, 2,   2, 3, 7};  // Face 6
					
	for(unsigned int i(0); i < tailleTabIndices; i++) p_indices[i] = indices[i];
}



