#include "PAppSdlOpenGl3.h" using namespace std; ///constante qui permet que le dt ne soit pas trop grand const float DTFACTOR = 0.01; ///////////////////////////////////////////////////////// // // // Fonctions publiques de la classe PAppSdlOpenGl3 // // // ///////////////////////////////////////////////////////// ///Constructeur par défaut de PAppSdlOpenGl3 PAppSdlOpenGl3::PAppSdlOpenGl3(const std::string& titreFenetre, int largeurFenetre, int hauteurFenetre){ this->initialisationPAppSdlOpenGl3(titreFenetre, largeurFenetre, hauteurFenetre); } ///Constructeur de copier de PAppSdlOpenGl3 /** @param other : PAppSdlOpenGl3 à copier */ PAppSdlOpenGl3::PAppSdlOpenGl3(const PAppSdlOpenGl3 & other){ } ///Destructeur de PAppSdlOpenGl3 PAppSdlOpenGl3::~PAppSdlOpenGl3(){ #ifdef USE_NEW_MATRICE_C freePMat4fGl3(p_matModelview); freePMat4fGl3(p_matProjection); #endif SDL_Quit(); } ///fonction qui permet d'exécuter l'application /** @return 0 si l'exécution s'est bien passée, false sinon */ int PAppSdlOpenGl3::executer(){ if(!p_isOpenGlSdlInit) return 1; p_isRun = true; while(p_isRun){ p_start_time = SDL_GetTicks(); this->clearKeyStatesNoRepeat(); while(SDL_PollEvent(&p_evenements)){ this->updateWithEvent(&p_evenements); this->getEvent(&p_evenements); } // Nettoyage de l'écran glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //on suppose que tout à bien fonctionne comme prévus et que le temps de calcul était égale à this->timeForOneFrame (en même temps on s'arange pour que se soit le cas) this->update(p_timeForOneFrame*DTFACTOR); //on gère les évenements // Ré-initialisation de la matrice et placecement de la caméra #ifdef USE_NEW_MATRICE_C loadIdentityPMat4fGl3(p_matModelview); #else p_matModelview.loadIdentity(); #endif p_cameraGL.see(p_matModelview); this->draw3d(); //on affiche tout SDL_GL_SwapWindow(p_fenetre); //on fait le double buffering p_ellapsed_time = SDL_GetTicks() - p_start_time; if(p_ellapsed_time < p_timeForOneFrame){SDL_Delay(p_timeForOneFrame - p_ellapsed_time);} } return 0; } /////////////////////////////////////////////////////////////////// // // // Fonctions protégées de la classe PAppSdlOpenGl3 // // // /////////////////////////////////////////////////////////////////// void PAppSdlOpenGl3::updateWithEvent(SDL_Event* event){ } ///fonction qui permet de rajouter une touche à gérer durant l'execution de l'application /** @param action : nom de l'action à effectuer avec cette touche ("forward", "up", "down", "left", "right", "quit"...) @param key : touche sdl associée à cette action (flèche du haut : SDLK_UP, fléche du bas : SDLK_DOWN ...) @param initValue : valeur par défaut de cette touche (true : enfoncée ou false : relachée) */ void PAppSdlOpenGl3::addKeyEventRepeat(const std::string & action, SDL_Keycode key, bool initValue){ p_keyconfRepeat[action] = key; p_keystatesRepeat[p_keyconfRepeat[action]] = initValue; } ///fonction qui permet de rajouter une touche à gérer durant l'execution de l'application (empèche la répatition de la touche tant qu'elle n'est pas relâchée /** @param action : nom de l'action à effectuer avec cette touche ("forward", "up", "down", "left", "right", "quit"...) @param key : touche sdl associée à cette action (flèche du haut : SDLK_UP, fléche du bas : SDLK_DOWN ...) @param initValue : valeur par défaut de cette touche (true : enfoncée ou false : relachée) */ void PAppSdlOpenGl3::addKeyEventNoRepeat(const std::string & action, SDL_Keycode key, bool initValue){ p_keyconfNoRepeat[action] = key; p_keystatesNoRepeat[p_keyconfNoRepeat[action]] = initValue; } ///fonction qui met tous les keystatesNoRepeat à false void PAppSdlOpenGl3::clearKeyStatesNoRepeat(){ for(KeyStates::iterator it = p_keystatesNoRepeat.begin(); it != p_keystatesNoRepeat.end(); it++){ it->second = false; } } ///fonction qui arrète l'application void PAppSdlOpenGl3::stop(){p_isRun = false;} ///fonction qui permet d'envoyer la matrice de projection de l'application au shader /** @param idMatProjection : numéro d'identification de la matrice de projection à donner */ void PAppSdlOpenGl3::sendMatProjectionToShader(GLint idMatProjection){ #ifdef USE_NEW_MATRICE_C glUniformMatrix4fv(idMatProjection, 1, GL_TRUE, p_matProjection->mat); #else glUniformMatrix4fv(idMatProjection, 1, GL_TRUE, p_matProjection.getValue()); #endif } ///fonction qui permet d'envoyer la matrice modelView de l'application au shader /** @param idMatModelView : numéro d'identification de la matrice modelView à donner */ void PAppSdlOpenGl3::sendMatModelViewToShader(GLint idMatModelView){ #ifdef USE_NEW_MATRICE_C glUniformMatrix4fv(idMatModelView, 1, GL_TRUE, p_matModelview->mat); #else glUniformMatrix4fv(idMatModelView, 1, GL_TRUE, p_matModelview.getValue()); #endif } ///fonction qui fait une sauvegarde de la matrice modelView void PAppSdlOpenGl3::pushMatModelView(){ #ifdef USE_NEW_MATRICE_C pushPMat4fGl3(p_matModelview); #else p_matModelview.push(); #endif } ///fonction qui fait une restauration de la matrice modelView void PAppSdlOpenGl3::popMatModelView(){ #ifdef USE_NEW_MATRICE_C popPMat4fGl3(p_matModelview); #else p_matModelview.pop(); #endif } ///fonction qui transforme la matrice modelView en matrice identité void PAppSdlOpenGl3::loadIdentityMV(){ #ifdef USE_NEW_MATRICE_C loadIdentityPMat4fGl3(p_matModelview); #else p_matModelview.loadIdentity(); #endif } ///fonction qui translate la matrice modelView /** @param x : translation en x * @param y : translation en y * @param z : translation en z */ void PAppSdlOpenGl3::translateMV(float x, float y, float z){ #ifdef USE_NEW_MATRICE_C translatePMat4fGl3(p_matModelview, x, y, z); #else p_matModelview.translated(x, y, z); #endif } ///fonction qui change l'échelle de la matrice modelView /** @param x : échelle en x * @param y : échelle en y * @param z : échelle en z */ void PAppSdlOpenGl3::scaleMV(float x, float y, float z){ #ifdef USE_NEW_MATRICE_C scalePMat4fGl3(p_matModelview, x, y, z); #else p_matModelview.scale(x, y, z); #endif } ///fonction qui fait tourner la matrice modelView avec un angle en radian /** @param angleRad : angle de rotation (en radian) * @param x : composante x de l'axe de rotation * @param y : composante y de l'axe de rotation * @param z : composante z de l'axe de rotation */ void PAppSdlOpenGl3::rotateMVRad(float angleRad, float x, float y, float z){ #ifdef USE_NEW_MATRICE_C rotatePMat4fGl3Rad(p_matModelview, angleRad, x, y, z); #else p_matModelview.rotateRad(angleRad, x, y, z); #endif } ///fonction qui fait tourner la matrice modelView avec un angle en degré /** @param angleDeg : angle de rotation (en degrée) * @param x : composante x de l'axe de rotation * @param y : composante y de l'axe de rotation * @param z : composante z de l'axe de rotation */ void PAppSdlOpenGl3::rotateMVDeg(float angleDeg, float x, float y, float z){ #ifdef USE_NEW_MATRICE_C rotatePMat4fGl3Rad(p_matModelview, angleDeg, x, y, z); #else p_matModelview.rotateDeg(angleDeg, x, y, z); #endif } ///fonction qui dit si Sdl et OpenGl ont bien été initialisées /** @return true si Sdl et OpenGl ont bien été initialisées, false sinon */ bool PAppSdlOpenGl3::isOpenGlSdlInit() const{return p_isOpenGlSdlInit;} ///définit le nombre de frames par secondes à afficher (n'est pas forcément un nombre entier) /** @param framePerSecond : nombre de frames par secondes à afficher */ void PAppSdlOpenGl3::setFPS(Uint32 framePerSecond){ //le facteur 1000 vient du fait que le temps donnée par SDL_getTicks est en millisecondes p_timeForOneFrame = 1000.0/framePerSecond; } ///fonction qui renvoie le ratio de la fenêtre /** @return ratio de la fenêtre */ float PAppSdlOpenGl3::getRatio() const{ return p_largeurFenetre / p_hauteurFenetre; } ///fonction qui initialise a perspective avec un angle en radian /** @param angleDeg : angle de vue en degrée (70°) * @param near : position la plus prés de la caméra à afficher * @param far : position la plus loin de la caméra à afficher */ void PAppSdlOpenGl3::setPerpectiveDeg(float angleDeg, float near, float far){ #ifdef USE_NEW_MATRICE_C perspectivePMat4fGl3Deg(p_matProjection, angleDeg, getRatio(), near, far); #else p_matProjection.perspectiveDeg(angleDeg, getRatio(), near, far); #endif } ///fonction qui initialise a perspective avec un angle en radian /** @param angleRad : angle de vue en radian * @param near : position la plus prés de la caméra à afficher * @param far : position la plus loin de la caméra à afficher */ void PAppSdlOpenGl3::setPerpectiveRad(float angleRad, float near, float far){ #ifdef USE_NEW_MATRICE_C perspectivePMat4fGl3Rad(p_matProjection, angleRad, getRatio(), near, far); #else p_matProjection.perspectiveRad(angleRad, getRatio(), near, far); #endif } ///fonction qui permet d'empècher le démarage de l'application (par exemple lors d'un problème d'initialisation) void PAppSdlOpenGl3::dontRun(){ p_isOpenGlSdlInit = false; } ///fonction qui affiche la matrice de projection et la matrice modelView de l'application void PAppSdlOpenGl3::printMatPMV(){ #ifdef USE_NEW_MATRICE_C cout << "Matrice ModelView :" << endl; printPtMat4f(p_matModelview->mat); cout << "Matrice de projection :" << endl; printPtMat4f(p_matProjection->mat); #else cout << "Matrice ModelView :" << endl; cout << p_matModelview << endl; cout << "Matrice de projection :" << endl; cout << p_matProjection << endl; #endif } /////////////////////////////////////////////////////// // // // Fonctions private de la classe PAppSdlOpenGl3 // // // /////////////////////////////////////////////////////// ///Fonction d'initialisation de la classe PAppSdlOpenGl3 /** @param titreFenetre : titre de la fenêtre * @param largeurFenetre : largeur de la fenêtre * @param hauteurFenetre : hauteur de la fenêtre */ void PAppSdlOpenGl3::initialisationPAppSdlOpenGl3(const std::string& titreFenetre, int largeurFenetre, int hauteurFenetre){ p_titreFenetre = titreFenetre; p_largeurFenetre = largeurFenetre; p_hauteurFenetre = hauteurFenetre; if(SDL_Init(SDL_INIT_VIDEO) < 0){ // Initialisation de la SDL std::cout << "Erreur lors de l'initialisation de la SDL : " << SDL_GetError() << std::endl; p_isOpenGlSdlInit = false; // SDL_Quit(); //on quitte dans le destructeur return; }else{ std::cout << "Mode vidéo de SDL initialisé." << std::endl; } // Version d'OpenGL SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1); // Double Buffer SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); // Création de la fenêtre p_fenetre = SDL_CreateWindow(p_titreFenetre.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, p_largeurFenetre, p_hauteurFenetre, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL); if(p_fenetre == NULL){ std::cerr << "Imposible de créer la fenêtre : " << SDL_GetError() << std::endl; p_isOpenGlSdlInit = false; dontRun(); // SDL_Quit(); return; }else{ std::cout << "Création de la fénêtre." << std::endl; } p_contexteOpenGL = SDL_GL_CreateContext(p_fenetre); //on dit qu'il faut faire un test de profondeur (pour l'affichage 3D) glEnable(GL_DEPTH_TEST); p_isOpenGlSdlInit = true; #ifdef USE_NEW_MATRICE_C p_matModelview = createPMat4fGl3(); p_matProjection = createPMat4fGl3(); loadIdentityPMat4fGl3(p_matModelview); loadIdentityPMat4fGl3(p_matProjection); #else p_matModelview.loadIdentity(); p_matProjection.loadIdentity(); #endif setFPS(30.0); p_cameraGL.setWindowID(p_fenetre); } ///fonction qui récupère les différents évenements (appuis des touches) /** @param event : évenement de la lib sdl */ void PAppSdlOpenGl3::getEvent(SDL_Event* event){ //on test d'abord les touches qui peuvent se répéter for (KeyStates::iterator it = p_keystatesRepeat.begin();it != p_keystatesRepeat.end();it++){ //est-ce que la touche responsable de l'événement est celle du keystate ? if (event->key.keysym.sym == it->first){ it->second = (event->motion.type == SDL_KEYDOWN); //true si enfoncé, false si relâché break; //la touche responsable de l'événement a été utilisée, on quitte le for } } //maintenant les touches qui ne se répètent pas for (KeyStates::iterator it = p_keystatesNoRepeat.begin();it != p_keystatesNoRepeat.end();it++){ //est-ce que la touche responsable de l'événement est celle du keystate ? if (event->key.keysym.sym == it->first){ it->second = (event->motion.type == SDL_KEYUP); //true si enfoncé, false si relâché break; //la touche responsable de l'événement a été utilisée, on quitte le for } } }