#include "SceneOpenGL.h" // Permet d'éviter la ré-écriture du namespace glm:: using namespace glm; // Constructeur de Destucteur SceneOpenGL::SceneOpenGL(std::string titreFenetre, int largeurFenetre, int hauteurFenetre) : m_titreFenetre(titreFenetre), m_largeurFenetre(largeurFenetre), m_hauteurFenetre(hauteurFenetre), m_fenetre(0), m_contexteOpenGL(0), m_input(), m_texturLoader( "Textures/" ), m_shader( "Shaders/texture.vert", "Shaders/texture.frag" ), m_shLight( "Shaders/light.vert", "Shaders/light.frag" ), m_shGris( "Shaders/texture.vert", "Shaders/gris.frag" ) { } SceneOpenGL::~SceneOpenGL() { SDL_GL_DeleteContext(m_contexteOpenGL); SDL_DestroyWindow(m_fenetre); SDL_Quit(); } // Méthodes bool SceneOpenGL::initialiserFenetre() { // Initialisation de la SDL if(SDL_Init(SDL_INIT_VIDEO) < 0) { std::cout << "Erreur lors de l'initialisation de la SDL : " << SDL_GetError() << std::endl; SDL_Quit(); return false; } #ifdef __APPLE__ // Version d'OpenGL SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 2); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); // Récupération du Bundle CFURLRef URLBundle = CFBundleCopyResourcesDirectoryURL(CFBundleGetMainBundle()); char *cheminResources = new char[PATH_MAX]; // Changement du 'Working Directory' if(CFURLGetFileSystemRepresentation(URLBundle, 1, (UInt8*)cheminResources, PATH_MAX)) chdir(cheminResources); // Libération de la mémoire delete[] cheminResources; CFRelease(URLBundle); #else // Version d'OpenGL SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); #endif // Création de la fenêtre uint32_t flag( SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL ); m_fenetre = SDL_CreateWindow(m_titreFenetre.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_largeurFenetre, m_hauteurFenetre, flag); if(m_fenetre == 0) { std::cout << "Erreur lors de la creation de la fenetre : " << SDL_GetError() << std::endl; SDL_Quit(); return false; } // Paramètres des évènements m_input.setWindow( m_fenetre ); m_input.capturerPointeur( true ); m_input.setMoveKeys( SDL_SCANCODE_W, SDL_SCANCODE_S, SDL_SCANCODE_D, SDL_SCANCODE_A ); // Création du contexte OpenGL m_contexteOpenGL = SDL_GL_CreateContext(m_fenetre); if(m_contexteOpenGL == 0) { std::cout << SDL_GetError() << std::endl; SDL_DestroyWindow(m_fenetre); SDL_Quit(); return false; } return true; } bool SceneOpenGL::initGL() { #ifdef WIN32 // On initialise GLEW GLenum initialisationGLEW( glewInit() ); // Si l'initialisation a échoué : if(initialisationGLEW != GLEW_OK) { // On affiche l'erreur grâce à la fonction : glewGetErrorString(GLenum code) std::cout << "Erreur d'initialisation de GLEW : " << glewGetErrorString(initialisationGLEW) << std::endl; // On quitte la SDL SDL_GL_DeleteContext(m_contexteOpenGL); SDL_DestroyWindow(m_fenetre); SDL_Quit(); return false; } #endif // Paramètres OpenGL avancés glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); // Tout s'est bien passé, on retourne true return true; } void SceneOpenGL::bouclePrincipale() { // Variables temps unsigned int frameRate (1000 / 50); Uint32 debutBoucle(0), finBoucle(0), tempsEcoule(0); // Frame Buffer FrameBuffer frameBuffer(512, 512); frameBuffer.charger(); m_texturLoader.addTextur("FBO_Tele", frameBuffer.getColorBuffer(0)); // Shaders m_shader.charger(); m_shLight.charger(); m_shGris.charger(); Shader* shTarget(0x0); // Matrices (première passe) mat4 projectionFBO; projectionFBO = perspective(70.0, (double)frameBuffer.getLargeur() / frameBuffer.getHauteur(), 1.0, 100.0); // Matrices (seconde passe) mat4 projection, projection30, projection70, plat; mat4 view, unicite(1.0); const float format( (float) m_largeurFenetre / m_hauteurFenetre ); projection70 = perspective(70.0, (double)format, 0.1, 100.0); projection30 = perspective(30.0, (double)format, 0.1, 100.0); const float plat_extY( 30.0 ); const float plat_extX( plat_extY * format ); plat = ortho(-plat_extX, plat_extX, -plat_extY, plat_extY, 0.1f, 100.0f); // Vecteurs uint16_t nbLight(3); vec3 posLight[nbLight]; posLight[0] = vec3( 10.0, 3.0, 0.0 ); posLight[2] = vec3( 30.0, 3.5, 0.0 ); float posLightV[nbLight*3]; // Caméra mobile Camera camera(vec3(0, 1.78, 0), vec3(0, 1.78, -1), vec3(0, 1, 0), 0.5, 0.5); vec3 eyePos; m_input.afficherPointeur(false); m_input.capturerPointeur(true); // Objet Caisse OBJ metal; metal.charger("3DModels/kube.obj", m_texturLoader.take("caisse_basic")); mat4 model_metal(1.0); OBJ plan; plan.charger( "3DModels/plan.obj", m_texturLoader.take("pierres"), 50.0, 20.0); mat4 model_plan(1.0); model_plan = translate(model_plan, vec3(2.5,0.0,0.0)); OBJ tele; tele.charger( "3DModels/plan.obj", m_texturLoader.take("FBO_Tele"), 2.5 ); mat4 model_tele(1.0); model_tele = translate( model_tele, vec3(16.56,3.2,-0.5) ); model_tele = rotate(model_tele, 90.0f, vec3(0, 0, 1)); OBJ caisse; caisse.charger("3DModels/kube.obj", m_texturLoader.take("chantier")); mat4 model_caisseA(1.0),model_caisseB(1.0),model_caisseC(1.0); model_caisseA = translate( model_caisseA, vec3(-6.56,1.0,-0.5) ); model_caisseB = translate( model_caisseB, vec3(6.56,1.0,4.5) ); model_caisseC = translate( model_caisseC, vec3(3.5,1.0,3.5) ); OBJ weapon; weapon.charger( "3DModels/MPX.obj", m_texturLoader.take("chantier"), 0.2 ); mat4 model_weapon(1.0); Mosaic sword; sword.charger( "2DModels/sword_iron.bmp" ); mat4 model_sword(1.0); float angle = 0.0; float theta, theta_old = 0.0; float phi, phi_old = 0.0; bool rangee(true), rangement(false), veutRanger(false); bool veutViser(false); bool veutTemporiser(false); bool veutLight(false), lightDone(false), lightState(false); bool veutOverLight(false), overLightDone(false); GLint overLightState(false); // Boucle principale while(!m_input.terminer()) { // On définit le temps de début de boucle debutBoucle = SDL_GetTicks(); // Gestion des évènements m_input.updateEvenements(); camera.setVol( m_input.getTouche( SDL_SCANCODE_LSHIFT ) ); if (m_input.getTouche(SDL_SCANCODE_ESCAPE)) break; if (m_input.getTouche(SDL_SCANCODE_KP_3)) nbLight = 3; if (m_input.getTouche(SDL_SCANCODE_KP_2)) nbLight = 2; if (m_input.getTouche(SDL_SCANCODE_KP_1)) nbLight = 1; if (m_input.getTouche(SDL_SCANCODE_KP_0)) nbLight = 0; camera.deplacer(m_input); veutRanger = m_input.getTouche(SDL_SCANCODE_E) || m_input.getBoutonPad(1); if ( !rangement && veutRanger ) { rangement = true; rangee = !rangee; if ( rangee ) camera.setVitesse(0.5f); else camera.setVitesse(0.2f); } else if ( !veutRanger ) rangement = false; veutTemporiser = m_input.getTouche( SDL_SCANCODE_SPACE ) || m_input.getBoutonPad(2); veutViser = m_input.getBoutonSouris(3) || m_input.getBoutonPad(4); veutLight = m_input.getTouche( SDL_SCANCODE_LCTRL ) || m_input.getBoutonPad(3); if ( !lightDone && veutLight ) { lightDone = true; lightState = !lightState; } else if ( !veutLight ) lightDone = false; veutOverLight = m_input.getTouche( SDL_SCANCODE_Q ) || m_input.getBoutonPad(0); if ( !overLightDone && veutOverLight ) { overLightDone = true; overLightState = !overLightState; } else if ( !veutOverLight ) overLightDone = false; /* ***** Première Passe ***** */ // Verrouillage du Frame Buffer glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer.getID()); // Nettoyage de l'écran glClearColor(0.2, 0.2, 0.25, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Redimensionnement de la zone d'affichage glViewport(0, 0, frameBuffer.getLargeur(), frameBuffer.getHauteur()); // Placement de la caméra view = lookAt(vec3(0, 0, 3), vec3(0, 0, 0), vec3(0, 1, 0)); // Gestion de la rotation de la caisse if ( veutTemporiser ) angle = 0.05f; else angle = 2.0f; // Activation du shader glUseProgram( m_shGris.getProgramID() ); // Affichage de la caisse model_metal = rotate(model_metal, angle, vec3(0, 1, 0)); metal.afficher(projectionFBO*view*model_metal, model_metal, &m_shGris); // Désactivation du shader glUseProgram( 0 ); // Déverrouillage du Frame Buffer glBindFramebuffer(GL_FRAMEBUFFER, 0); /* ***** Seconde Passe ***** */ // Nettoyage de l'écran glClearColor(0.0, 0.0, 0.0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Redimensionnement de la zone d'affichage glViewport(0, 0, m_largeurFenetre, m_hauteurFenetre); // Gestion de la caméra camera.lookAt(view); if ( veutViser ) projection = projection30; else if ( m_input.getTouche( SDL_SCANCODE_X ) ) projection = plat; else projection = projection70; // Gestion de la lumière posLight[1] = camera.getPos() + vec3(0.0, 1.2, 0.0); posLight[2] = rotateY( posLight[2], angle ); uint16_t j; for ( uint16_t i(0); igetProgramID() ); if ( lightState ) { glUniform3f(glGetUniformLocation(m_shLight.getProgramID(), "eyePos"), eyePos.x, eyePos.y, eyePos.z); glUniform3fv(glGetUniformLocation(m_shLight.getProgramID(), "posLight"), nbLight, posLightV); glUniform1i(glGetUniformLocation(m_shLight.getProgramID(), "overLight"), overLightState); glUniform1i(glGetUniformLocation(m_shLight.getProgramID(), "nbLight"), (int)nbLight); } // Afficher le plan plan.afficher(projection * view * model_plan, model_plan, shTarget); // Afficher la télé tele.afficher(projection * view * model_tele, model_tele, shTarget); // Affichage de la caisse model_caisseA = rotate(model_caisseA, angle, vec3(0, 1, 0)); weapon.afficher(projection * view * model_caisseA, model_caisseA, shTarget); caisse.afficher(projection * view * model_caisseB, model_caisseB, shTarget); caisse.afficher(projection * view * model_caisseC, model_caisseC, shTarget); // Affichage de l'arme if ( rangee ) { theta = camera.getTheta() + 180; phi = 90; } else { theta = camera.getTheta(); phi = camera.getPhi(); } theta_old = theta_old*3 + theta; theta_old /= 4; phi_old = phi_old*3 - phi; phi_old /= 4; model_weapon = translate( unicite, camera.getPos() ); model_weapon = rotate(model_weapon, theta_old, vec3(0, 1, 0)); model_weapon = rotate(model_weapon, phi_old, vec3(1, 0, 0) ); if ( veutViser ) model_weapon = translate( model_weapon, vec3(0,-0.5,1.0) ); else model_weapon = translate( model_weapon, vec3(-0.5,-0.7,1.0) ); glClear(GL_DEPTH_BUFFER_BIT); // L'arme s'affiche au premier plan quoi qu'il arrive weapon.afficher(projection * view * model_weapon, model_weapon, shTarget); // Affichage de l'épée sword.afficher(projection * view * model_sword, model_sword, shTarget); // Désactivation du shader shTarget = 0x0; glUseProgram( 0 ); // Actualisation de la fenêtre SDL_GL_SwapWindow(m_fenetre); // Calcul du temps écoulé finBoucle = SDL_GetTicks(); tempsEcoule = finBoucle - debutBoucle; // Si nécessaire, on met en pause le programme if(tempsEcoule < frameRate) SDL_Delay(frameRate - tempsEcoule); } }