8.3.4 Écrire sdlopengl_app.cpp

Implémentons tout ça dans sdlopengl_app.cpp :

1
2
3
4
5
6
7
#include "sdlopengl_app.h"

using namespace std;

const Uint32 TIME_MAX = 10;

const float DTFACTOR = 0.01;

Comme avant on se définit des constantes pour gérer le temps.

Constructeur et destructeur :

1
2
3
4
5
6
7
SDLOpenGl_app::SDLOpenGl_app(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	this->initSDLOpenGl(width, height, near, far, angle, titre, icon);
}

SDLOpenGl_app::~SDLOpenGl_app(){
	SDL_Quit();
}

La fonction principale :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
void SDLOpenGl_app::executer(){      //fonction principale de SDL_Application
	SDL_Event event;
	p_isRun = true;
	while(p_isRun){
		p_start_time = SDL_GetTicks();
		while(SDL_PollEvent(&event)){
			if(event.key.keysym.sym == SDLK_ESCAPE || event.type == SDL_QUIT){p_isRun = false;}
			getEvent(&event);
		}
		getSDL_Event(event);
		
		//pour que la profondeur continue a être respecté
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();          //on commence les calculs avec la matrice identité
		update(p_timeForOneFrame*DTFACTOR);   //on gère les événements
		camera.see(); //on regarde avec la caméra
		draw();               //on affiche tout
		glFlush();                    //fait le
		SDL_GL_SwapBuffers();       //double buffering
		p_ellapsed_time = SDL_GetTicks() - p_start_time;
		if(p_ellapsed_time < p_timeForOneFrame){SDL_Delay(p_timeForOneFrame - p_ellapsed_time);}
	}
}

On renvoie la taille de la fenêtre :

1
Vecteur SDLOpenGl_app::getFenetre(){return p_fenetre;}

On s'occupe de la caméra :

1
2
3
4
5
6
7
void SDLOpenGl_app::setCamera(const Camera & cam){
	camera = cam; //la puissance des opérateurs
}

void SDLOpenGl_app::setCamera(const Vecteur & pos, double theta, double phi, double rouli){
	camera.setAll(pos, theta, phi, rouli);
}

Le déplacement de la caméra :

1
2
3
void SDLOpenGl_app::moveCamera(const Vecteur & dv){
	camera.move(dv);
}

Rotation et initialisation de rotation de la caméra :

1
2
3
4
5
6
7
void SDLOpenGl_app::rotationCamera(double dteta, double dPhi, double dRouli){
	camera.rotation(dteta, dPhi, dRouli);
}

void SDLOpenGl_app::setRotationCamera(double theta, double phi, double rouli){
	camera.setAngles(theta, phi, rouli);
}

La perspective :

1
2
3
4
5
6
7
void SDLOpenGl_app::setPerspective(double angle, double width, double height, double near, double far){
	gluPerspective(angle, (double)width/height, near, far);
}

void SDLOpenGl_app::setPerspective(double angle, double aspect, double near, double far){
	gluPerspective(angle, aspect, near, far);
}

La répétition des touches :

1
2
3
void SDLOpenGl_app::keyRepeat(int delay, int interval){
	SDL_EnableKeyRepeat(delay, interval);
}

On initialise la position maximal d'un objet dans l'application :

1
2
3
void SDLOpenGl_app::setPosMax(const Vecteur & posMax){
	p_posMax = posMax;
}

Les seteurs habituels :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
void SDLOpenGl_app::setSize(int width, int height){
	if(width > 0 && height > 0){
		SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
	}
}

void SDLOpenGl_app::setIcon(SDL_Surface* icon){//défini l'icone de l'application
	if(icon != NULL){SDL_WM_SetIcon(icon, NULL);}
}

void SDLOpenGl_app::setIcon(const std::string & nom_icon){
	if(nom_icon != ""){
		SDL_Surface* ic = IMG_Load(nom_icon.c_str());
		if(ic != NULL){SDL_WM_SetIcon(ic, NULL);}
		SDL_FreeSurface(ic);
	}
}

void SDLOpenGl_app::setTitre(const std::string & titre){//défini le titre de l'application
	SDL_WM_SetCaption(titre.c_str(), NULL);
}

void SDLOpenGl_app::setAll(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	this->initSDLOpenGl(width, height, near, far, angle, titre, icon);
}

La fonction virtuelle de tout à l'heure (ne fait rien par défaut mais on doit l'implémenter car elle est virtuelle et pas virtuelle pure) :

1
void SDLOpenGl_app::getSDL_Event(SDL_Event & event){}

La gestion des évènements :

1
2
3
4
5
6
7
8
void SDLOpenGl_app::addKeyEvent(const std::string & action, SDLKey key, bool initValue){
	p_keyconf[action] = key;
	p_keystates[p_keyconf[action]] = initValue;
}

bool SDLOpenGl_app::keyEventMade(const std::string & action){
	return p_keystates[p_keyconf[action]];
}

Arrêt de l'application :

1
2
3
void SDLOpenGl_app::stop(){
	p_isRun = false;
}

On initialise SDL et OpenGl :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
void SDLOpenGl_app::initSDLOpenGl(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	static bool initSDL = false;
	if(!initSDL){
		SDL_Init(SDL_INIT_VIDEO);
		atexit(SDL_Quit);//stop() sera appelé quand on fera exit(0);
		SDL_WM_SetCaption(titre.c_str(), NULL);
		SDL_SetVideoMode(width, height, 32, SDL_OPENGL);
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		gluPerspective(angle, (double)width/height, near, far);
		glEnable(GL_DEPTH_TEST);
		p_fenetre.setXYZ(width, height, 0);
		setIcon(icon);          //icon de l'application
		initSDL = true;
		p_timeForOneFrame = 1000/30;
	}
}

C'est quoi atexit(SDL_Quit); ?

C'est pour arrêter SDL et OpenGl si on fait exit(0), si on arrête le programme prématurément.

Récupération des évènements :

1
2
3
4
5
6
7
8
void SDLOpenGl_app::getEvent(SDL_Event* event){
	for (KeyStates::iterator it = p_keystates.begin();it != p_keystates.end();it++){
		if (event->key.keysym.sym == it->first){
			it->second = (event->motion.type == SDL_KEYDOWN);
			break;
		}
	}
}

Et voilà, une classe de plus.

Et comme il se doit, un autre petit résumé de ce que l'on a fait :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
#include "sdlopengl_app.h"

using namespace std;

///temps permit pour faire un cycle
const Uint32 TIME_MAX = 10;
///constante qui permet que le dt ne soit pas trop grand
const float DTFACTOR = 0.01;

///Constructeur de la classe SDLOpenGl_app
/**	@param width : largeur de la fenêtre de l’application
	@param height : hauteur de la fenêtre de l’application
	@param near : distance la plus petite entre un point et la caméra (si le point est plus près il ne sera pas affiché
	@param far : distance la plus grande entre un point et la caméra (si le point est plus loin il ne sera pas affiché
	@param angle : angle d'ouverture de la caméra, angle de vue de la caméra
	@param titre : nom de la fenêtre (dans la barre en haut de la fenêtre)
	@param icon : nom de l'icone de l'application
	ce constructeur est aussi le constructeur par défaut car tout les paramètres ont des valeurs par défaut
*/
SDLOpenGl_app::SDLOpenGl_app(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	this->initSDLOpenGl(width, height, near, far, angle, titre, icon);
}

///destructeur de l'application
SDLOpenGl_app::~SDLOpenGl_app(){
	SDL_Quit();
}

///fonction qui lance l'application
void SDLOpenGl_app::executer(){      //fonction principale de SDL_Application
	SDL_Event event;
	p_isRun = true;
	while(p_isRun){
		p_start_time = SDL_GetTicks();
		while(SDL_PollEvent(&event)){
			if(event.key.keysym.sym == SDLK_ESCAPE || event.type == SDL_QUIT){p_isRun = false;}
			getEvent(&event);
		}
		getSDL_Event(event);
		
		//pour que la profondeur continue a être respecté
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		glMatrixMode(GL_MODELVIEW);
		glLoadIdentity();          //on commence les calculs avec la matrice identité
		update(p_timeForOneFrame*DTFACTOR);   //on gère les événements
		camera.see(); //on regarde avec la caméra
		draw();               //on affiche tout
		glFlush();                    //fait le
		SDL_GL_SwapBuffers();       //double buffering
		p_ellapsed_time = SDL_GetTicks() - p_start_time;
		if(p_ellapsed_time < p_timeForOneFrame){SDL_Delay(p_timeForOneFrame - p_ellapsed_time);}
	}
}

///fonction qui renvoie la taille de la fenêtre
/** @return taille de la fenêtre
*/
Vecteur SDLOpenGl_app::getFenetre(){return p_fenetre;}

///fonction qui initialise la caméra de l'application avec une autre caméra passée en paramètres
/**	@param camera : Camera qui sera la caméra de l'application
*/
void SDLOpenGl_app::setCamera(const Camera & cam){
	camera = cam;
}

///fonction qui initialise la caméra de l'application avec ses caractéristiques
/**	@param pos : position de la caméra de l'application
	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void SDLOpenGl_app::setCamera(const Vecteur & pos, double theta, double phi, double rouli){
	camera.setAll(pos, theta, phi, rouli);
}

///Déplace la caméra en incrémentant sa position d'un Vecteur dv
/**	@param dv : Vecteur de déplacement de la caméra
*/
void SDLOpenGl_app::moveCamera(const Vecteur & dv){
	camera.move(dv);
}

///fonction qui fait pivoter la caméra suivant les angles donnés
/**	@param dteta : variation de l'angle théta
	@param dPhi : variation de l'angle phi
	@param dRouli : variation de l'angle de rouli
*/
void SDLOpenGl_app::rotationCamera(double dteta, double dPhi, double dRouli){
	camera.rotation(dteta, dPhi, dRouli);
}

///initialise une visée à la caméra avec des angles
/**	@param theta : angle polaire avec l'axe des abscisses (en polaire si phi = M_PI/2)
	@param phi : angle de la composante verticale en coordonnées sphériques
	@param rouli : représente le rouli de la caméra, si elle est penchée sur la droite ou la gauche
*/
void SDLOpenGl_app::setRotationCamera(double theta, double phi, double rouli){
	camera.setAngles(theta, phi, rouli);
}

///initialise les réglages de la caméra
/**	@param angle : angle d'ouverture de la caméra, angle de vue de la caméra
	@param width : largeur de la fenêtre de l’application
	@param height : hauteur de la fenêtre de l’application
	@param near : distance la plus petite entre un point et la caméra (si le point est plus près il ne sera pas affiché
	@param far : distance la plus grande entre un point et la caméra (si le point est plus loin il ne sera pas affiché
*/
void SDLOpenGl_app::setPerspective(double angle, double width, double height, double near, double far){
	gluPerspective(angle, (double)width/height, near, far);
}

///initialise les réglages de la caméra
/**	@param angle : angle d'ouverture de la caméra, angle de vue de la caméra
	@param aspect : aspect (width / height) de la fenêtre de l’application
	@param near : distance la plus petite entre un point et la caméra (si le point est plus près il ne sera pas affiché
	@param far : distance la plus grande entre un point et la caméra (si le point est plus loin il ne sera pas affiché
*/
void SDLOpenGl_app::setPerspective(double angle, double aspect, double near, double far){
	gluPerspective(angle, aspect, near, far);
}

///permet d'activer et de régler la répétition automatique des touches
/**	@param delay : délais d'attente avant de répéter la touche
	@param interval : intervalle de temps pendant lequel on répète la touche
*/
void SDLOpenGl_app::keyRepeat(int delay, int interval){
	SDL_EnableKeyRepeat(delay, interval);
}

///fonction qui récupère les différents événements (appuis des touches)
/**	@param event : événement de la lib sel
*/
void SDLOpenGl_app::getEvent(SDL_Event* event){
	for (KeyStates::iterator it = p_keystates.begin();it != p_keystates.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
		}
	}
}

///définis la position maximale d'un objet dans l'application
/**	@param posMax : position maximale d'un objet dans l'application
*/
void SDLOpenGl_app::setPosMax(const Vecteur & posMax){
	p_posMax = posMax;
}

///fonction qui initialise le nombre de fps que l'on veut
/**	@param fps : nombre de fps que l'on veut
*/
void SDLOpenGl_app::setFPS(unsigned int fps){
	p_timeForOneFrame = 1000/fps;
}

///fonction qui initialise toute l’application ainsi que SDL et OpenGl
/**	@param width : largeur de la fenêtre de l’application
	@param height : hauteur de la fenêtre de l’application
	@param near : distance la plus petite entre un point et la caméra (si le point est plus près il ne sera pas affiché
	@param far : distance la plus grande entre un point et la caméra (si le point est plus loin il ne sera pas affiché
	@param angle : angle d'ouverture de la caméra, angle de vue de la caméra
	@param titre : nom de la fenêtre (dans la barre en haut de la fenêtre)
	@param icon : nom de l'icone de l'application
*/
void SDLOpenGl_app::initSDLOpenGl(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	static bool initSDL = false;
	if(!initSDL){
		SDL_Init(SDL_INIT_VIDEO);
		atexit(SDL_Quit);//stop() sera appelé quand on fera exit(0);
		SDL_WM_SetCaption(titre.c_str(), NULL);
		SDL_SetVideoMode(width, height, 32, SDL_OPENGL);
		glMatrixMode( GL_PROJECTION );
		glLoadIdentity();
		gluPerspective(angle, (double)width/height, near, far);
		glEnable(GL_DEPTH_TEST);
		p_fenetre.setXYZ(width, height, 0);
		setIcon(icon);          //icone de l'application
		initSDL = true;
		p_timeForOneFrame = 1000/30;
	}
}

///permet de régler la taille de la fenêtre
/**	@param width : largeur de la fenêtre de l’application
	@param height : hauteur de la fenêtre de l’application
*/
void SDLOpenGl_app::setSize(int width, int height){
	if(width > 0 && height > 0){
		SDL_SetVideoMode(width, height, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
	}
}

///permet de donner un icône à l'application
/**	@param icon : icône de l'application sous forme d'image
*/
void SDLOpenGl_app::setIcon(SDL_Surface* icon){//défini l'icone de l'application
	if(icon != NULL){SDL_WM_SetIcon(icon, NULL);}
}

///permet de donner un icône à l'application
/**	@param nom_icon : nom de l'icône de l'application
*/
void SDLOpenGl_app::setIcon(const std::string & nom_icon){
	if(nom_icon != ""){
		SDL_Surface* ic = IMG_Load(nom_icon.c_str());
		if(ic != NULL){SDL_WM_SetIcon(ic, NULL);}
		SDL_FreeSurface(ic);
	}
}

///permet de changer le titre de la fenêtre (ce qui est marqué en haut)
/**	@param titre : texte à écrire à la place du titre de la fenêtre
*/
void SDLOpenGl_app::setTitre(const std::string & titre){//défini le titre de l'application
	SDL_WM_SetCaption(titre.c_str(), NULL);
}

///initialise tout les paramètres de l'application
/**	@param width : largeur de la fenêtre de l’application
	@param height : hauteur de la fenêtre de l’application
	@param near : distance la plus petite entre un point et la caméra (si le point est plus près il ne sera pas affiché
	@param far : distance la plus grande entre un point et la caméra (si le point est plus loin il ne sera pas affiché
	@param angle : angle d'ouverture de la caméra, angle de vue de la caméra
	@param titre : nom de la fenêtre (dans la barre en haut de la fenêtre)
	@param icon : nom de l'icone de l'application
	tout les paramètres ont des valeurs par défaut ce n'est donc pas la peine de tous les rentrer
*/
void SDLOpenGl_app::setAll(double width, double height, double near, double far, double angle, const string & titre, const string & icon){
	this->initSDLOpenGl(width, height, near, far, angle, titre, icon);
}

///fonction virtuelle qui permet a l'utilisateur de récupérer des évènements si il en a besoin
/** @param event : événement de la SDL
*/
void SDLOpenGl_app::getSDL_Event(SDL_Event & event){}

///fonction qui permet de rajouter une touche à gérer durant l’exécution 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 : relâchée) 
*/
void SDLOpenGl_app::addKeyEvent(const std::string & action, SDLKey key, bool initValue){
	p_keyconf[action] = key;
	p_keystates[p_keyconf[action]] = initValue;
}

///fonction qui dit si un événement à tester s'est réalisé ou pas
/**	@param action : nom de l'action à testé ("forward", "up", "down", "left", "right", "quit"...)
	@return true si la touche est pressée, false sinon
*/
bool SDLOpenGl_app::keyEventMade(const std::string & action){
	return p_keystates[p_keyconf[action]];
}

///fonction qui arrête l’exécution de l'application
void SDLOpenGl_app::stop(){
	p_isRun = false;
}

Voilà l'application enfin finie.