#include "PAppSdlOpenGl3.h" ///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(){ 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)){ // if(p_evenements.key.keysym.sym == SDLK_ESCAPE || p_evenements.type == SDL_QUIT){p_isRun = false;} //apparement ça génère des bugs donc on oublie 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 p_matModelview.loadIdentity(); 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 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){ p_matProjection.perspectiveDeg(angleDeg, getRatio(), near, far); } ///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){ p_matProjection.perspectiveRad(angleRad, getRatio(), near, far); } ///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; } /////////////////////////////////////////////////////// // // // 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; p_matModelview.loadIdentity(); p_matProjection.loadIdentity(); 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 } } }