TER Simulateur de billard

Transcription

TER Simulateur de billard
TER∗
Simulateur de billard
Philippe Kappel
15 mai 2003
∗
Travail d’Étude et de Recherche
2
Table des matières
1 Présentation du projet
5
1.1
Le sujet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
1.2
Ce qui a été fait . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
2 Réalisation du billard
7
2.1
Remarques sur la portabilité
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
2.2
Répartition du code source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.3
Un en-tête commun : billard.h . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
2.4
Le mouvement : anim.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
2.5
Dessiner une image complète : dessin.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
2.6
Initialiser les données partagées : init.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.7
Créer des listes constantes : listes.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
2.8
Objet principal : main.c . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3 Création de l’exécutable
15
3.1
Compilation des textures
. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.2
Compilation du code source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
3.3
Exécution du programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
4 Conclusion
17
A Copies d’écran
19
B Textures utilisées
21
3
4
Chapitre 1
Présentation du projet
1.1
Le sujet
Le but de ce TER∗ est la réalisation d’un simulateur de billard. Il faudra donc s’attacher à mettre au point une
simulation physique réaliste des billes, prenant en compte les rebonds, les effets donnés, ainsi que la configuration
de la table. La simulation devra rester interactive et être utilisable à travers la vue subjective du joueur. Il est
envisageable d’introduire un concurrent géré de manière réaliste par l’ordinateur si la simulation est bien maı̂trisée.
1.2
Ce qui a été fait
Toute la partie graphique du projet est achevée. Elle utilise les fonctions de
la librairie OpenGL† . Pour de meilleures performances, tous les objets — excepté
les ombres — sont affichés grâce à des listes d’instructions graphiques. Ce choix
est justifié plus en détail dans le chapitre suivant.
La partie animation n’est pas totalement achevée. Faute de temps, seuls les
deux trous du milieu sont actifs, les quatre autres ne sont pas gérés. Ce détail mis
à part, le reste de l’animation est achevé. Les billes sont ralenties par le frottement
du tapis, avec également une perte d’énergie plus importante lors des collisions.
Chaque bille a sa matrice de rotation.
La partie interactivité est assez simple, mais suffisante pour jouer au billard.
Le joueur dispose d’une queue qui apparaı̂t lorsque les billes sont arrêtées. En bougeant la souris, sans clic, il
déplace la queue, et c’est le contact de la queue avec la bille blanche qui déclenche l’action. En laissant le bouton
gauche appuyé, les mouvements de la souris déplacent la caméra autour de la table. Ce déplacement est possible à
n’importe quel moment — billes arrêtées ou en pleine action.
Les images des textures sont incluses dans l’exécutable lui-même. L’idée était de supprimer tout fichier annexe
nécessaire à l’exécution. Le programme make_images a été conçu dans ce but : générer des fichiers à compiler
avec le code source — ici un billard. Pour plus d’informations sur make_images, voir la section “Compilation des
textures”.
∗ Travail
† Open
d’Étude et de Recherche
Graphics Library : librairie ouverte du graphisme
5
6
Chapitre 2
Réalisation du billard
2.1
Remarques sur la portabilité
Tout le code source est écrit en langage C. La base du programme est essentiellement mathématique. L’affichage
graphique se sert des fonctions de la librairie OpenGL∗ , et la gestion des événements utilisateur — fenêtre, clavier,
souris — est réalisée grâce à l’interface portable GLUT† .
Dans le cas de Windows, les librairies opengl32.dll, glu32.dll et glut32.dll
sont nécessaires. Par défaut, Windows ne contient pas glut32.dll, il faut donc
rajouter ce fichier, disponible sur le site officiel de OpenGL∗ : www.opengl.org.
Dans le cas de Linux, la plupart des distributions — Mandrake, Debian. . . —
fournissent toutes les librairies nécessaires, mais une recompilation du noyau est
indispensable pour adapter le système au processeur graphique, et ainsi bénéficier
de l’accélération 3D.
Certaines possibilités offertes par OpenGL∗ n’ont pas été implémentées suivant
la même philosophie dans les différents drivers graphiques : un rendu correct sur une carte ne le sera pas forcément
sur une autre. Pour assurer un résultat le plus “constant” possible, certaines fonctions ont été évitées, ou remplacées
par d’autres — les fonctions glColorMaterial ont été remplacées par les fonctions glMaterial. L’exécutable a
été testé avec succès sur les configurations suivantes :
Processeur graphique
Système d’exploitation
Drivers installés
Accélération matérielle
Matrox MGA
GeForce 2 MX 400
ATI Radeon 7500
Matrox G550
GeForce 4 Ti 4200
ATI Radeon 9700 Pro
ATI Radeon 9700 Pro
Windows 2000
Windows XP
Linux Debian
Windows XP
Windows XP
Windows XP
Windows 2000
Windows XP
Microsoft
Matrox
Mesa 3D
ATI
Matrox
nVidia
ATI
ATI
non
non
inexploitée
oui
oui
oui
oui
oui
(Ce tableau est classé par fluidité croissante lors de l’exécution. Totalement subjective, elle dépend également du processeur central)
∗ Open
† Open
Graphics Library : librairie ouverte du graphisme
Graphics Library Utility Toolkit : boı̂te à outils des utilitaires de la librairie ouverte du graphisme
7
2.2
Répartition du code source
Pour plus de clarté, le code source a été réparti dans plusieurs fichiers. Le schéma suivant présente toutes
les fonctions non-statiques du code source, elles constituent les interfaces des objets. Les flèches représentent les
inclusions effectuées par le préprocesseur lors de la compilation :
6 2chiers écrits à la main
4 2chiers générés par make_images
#include
<math.h>
<glut.h>
"textures.h"
Constantes partagées
Variables partagées
numéros
des textures
tailles des
images
déclaration de
creer_textures()
déclaration des
tableaux RGBA*
textures.h
images.h
Interfaces des objets
billard.h
#include
<billard.h>
#include
<billard.h>
#include
<billard.h>
#include
<billard.h>
#include
<billard.h>
...
...
...
...
...
rotation(...)
avancer()
dessiner_tout()
init()
creer_listes()
main()
anim.c
dessin.c
init.c
listes.c
main.c
#include
"images.h"
"textures.h"
creer_textures()
textures.c
tableaux
contenant
les niveaux
RGBA* des
images
images.o
Le code source de make_images a lui-même été écrit en C. Le but premier
de ce programme était de générer les fichiers images.o et images.h à partir de
fichiers *.bmp. Ainsi, le programmeur peut accéder directement aux tailles et aux
niveaux RGBA∗ de ses images, simplement en incluant l’en-tête images.h.
La prise en charge des textures OpenGL† n’est venue que plus tard. L’unique
fonction creer_textures() de textures.c utilise l’en-tête images.h pour charger les textures en mémoire vidéo. Le nouvel en-tête textures.h fournit au programmeur l’accès à la fonction creer_textures() et aux numéros des textures
générés par cette fonction.
Si le programmeur ne s’intéresse qu’aux images, il peut effacer les fichiers de
textures, et inclure l’en-tête images.h. Dans notre cas — le simulateur de billard — nous ne nous intéressons
qu’aux textures, c’est pourquoi le fichier images.h n’est pas inclus dans billard.h.
2.3
Un en-tête commun : billard.h
L’en-tête billard.h est inclus dans tous les fichiers C écrits
√ à la main.
√ Il inclut√lui-même les en-têtes math.h
et glut.h, définit les constantes générales — PI = π, R2 = 2, R3 = 3, R5 = 5 . . . — déclare les variables
partagées — positions, vitesses, matrices de rotation. . . — ainsi que les interfaces de tous les objets — fonctions
non-statiques de tous les fichiers C.
Pour plus de détail sur les interfaces, voir les sections suivantes, dédiées aux objets et à leurs interfaces.
∗ Red
Green Blue Alpha : rouge vert bleu alpha
Graphics Library : librairie ouverte du graphisme
† Open
8
LARGEUR_tapis
x
2*LARGEUR_tapis
(0, –1, 0)
z
DALLE_tapis
Extrait du fichier billard.h :
20
21
22
23
24
25
// Mesures (l’unité est le rayon d’une bille) :
#define
DALLE_tapis 5
#define LARGEUR_tapis 20
// sert pour la texture et l’éclairage du tapis (doit ^
etre au moins égale à 2)
// demi-largeur du tapis (2*LARGEUR_tapis doit ^
etre multiple de DALLE_tapis)
#define
// sert uniquement pour appliquer la texture du bois
DALLE_bois
10
Du moment que les commentaires sont respectés, ces mesures peuvent être modifiées sans problème.
2.4
Le mouvement : anim.c
L’interface de ce fichier est composée de deux fonctions : rotation(...) et avancer().
La fonction rotation(...) n’est pas à proprement parler une fonction d’interface. En effet, pendant tout le déroulement du jeu, elle n’est jamais appelée
par un objet externe. Elle est par contre très sollicitée à l’intérieur de l’objet —
utilisée par la fonction avancer() — comme s’il s’agissait d’une fonction statique.
Pourquoi alors avoir rendu publique une telle fonction ? La raison est simple. Lors
de l’initialisation, les boules sont tournées aléatoirement par la fonction init() de
l’objet init.c, et c’est uniquement à ce moment là que la fonction rotation(...)
est appelée depuis l’extérieur.
Je vous rassure tout de suite, cette fonction est la seule qui présente ce genre
d’ambiguı̈té au niveau objet. C’est aussi la seule fonction publique à paramètres.
Spécification : void rotation(float matrice[4][4], float angle, float x, float z)
Description : matrice est la matrice de rotation de la bille que l’on souhaite tourner d’un angle angle, et dont
l’axe de rotation est déterminé par x et z.
La fonction avancer() est la véritable interface de l’objet anim.c. Son rôle est de faire avancer toutes les
billes, tout en gérant leurs collisions. Pour cela, elle commence par déclarer une variable locale float devoir=1
qui représente le devoir à accomplir. On peut voir ce 1 comme une représentation de 100% du potentiel de chaque
vecteur vitesse. L’idée est la suivante : en même temps que les billes avancent, elles consomment le potentiel de
leur vecteur vitesse par l’intermédiaire de la variable devoir, qui diminue jusqu’à atteindre 0. À ce moment précis,
le devoir est accompli, et la fonction avancer() peut enfin se quitter.
Pourquoi avoir utilisé une telle philosophie ?
Chaque bille a son vecteur vitesse — en deux dimentions x et z. Par des calculs issus de résolution d’équations, la
fonction avancer() détermine précisément jusqu’où elle est capable de faire avancer l’ensemble des billes sans qu’il
y ait de collision, tout en restant dans la limite du devoir restant. Si la plus proche collision arrive au bout de 30%,
alors toutes les billes n’avanceront que de 30%, et le devoir diminuera de 30%. La collision est générée en modifiant
les vecteurs vitesse concernés — voir l’exemple page suivante. Lorsque ce rebond est effectué, l’accomplissement
du devoir se poursuit. . . jusqu’à ce que aucune collision ne survienne — dans la limite du devoir restant — dans
quel cas le devoir passe à 0, faisant avancer les billes en conséquence.
9
Exemple :
la bille n◦ 1 et la bille n◦ 2 se rencontrent.
Comme nous l’avons vu précédemment, le devoir s’accomplit jusqu’à atteindre le point de collision. Les vecteurs
−
→
− −
→1 , →
→2 sont calculés d’après l’axe formé par la collision. Ces vecteurs représentent les vecteurs vitesse des
t2 et −
n
t1 , n
deux billes, mais exprimés dans une autre base.
bille n°2
bille n°1
t2
n1
n2
t1
e la
axe idsion
l
l
co
→1 et −
→2 ne sont pas concernées par la collision. Par conséquent, le principe d’inertie
Les composantes normales −
n
n
fait que ces composantes ne subissent aucune modification.
→
−
→
−
Les composantes tangentielles t1 et t2 sont, au contraire, totalement incapables de rester passives face à la
→
−
collision. La même énergie qui a poussé les billes a se rencontrer va les faire s’éloigner : la composante t1 est
→
−
◦
◦
transférée sur la bille n 2, et la composante t2 est transférée sur la bille n 1.
bille n°2
bille n°1
n1
e la
axe idsion
l
l
co
t1
n2
t2
Au final, ce sont évidemment les vrais vecteurs vitesse — exprimés en coordonnées cartésiennes (x, z) — qui
sont modifiés.
À chaque fois que la fonction avancer() fait avancer les billes, elle les fait
tourner en conséquence, en multipliant comme il le faut la matrice de rotation
déclarée dans billard.h, et initialisée dans init.c grâce à la fonction init().
En plus de toute cette gestion, la fonction avancer() s’occupe de ralentir la
progression des billes grâce aux forces de frottement qui diminuent avec la vitesse
des billes. Chaque collision retire à elle seule une partie d’énergie plus importante
que le simple frottement sur le tapis.
C’est aussi la fonction avancer() qui fait rentrer les billes dans les trous.
Chaque bille a une variable globale positionnée à 1 — valeur par défaut — si elle
est visible, et à 0 si elle ne l’est pas. Lorsqu’une bille doit tomber dans un trou,
la fonction avancer() fait passer la valeur de la variable à 0.
Vous vous dites peut-être que la fonction avancer() sait vraiment faire plein de choses, même trop de choses !
En réalité, tout ceci n’est qu’une apparence, et n’est vrai qu’au niveau “interface”, car au niveau “programmation”
du code source, la fonction avancer() se sert très souvent de fonctions statiques. De cette façon, le fichier anim.c
est plus facile à comprendre.
10
2.5
Dessiner une image complète : dessin.c
Au moment d’appeler la fonction dessiner_tout(), l’objet principal — le seul à utiliser GLUT∗ — a déjà
modifié la matrice courante pour tenir compte de la vue demandée par l’utilisateur. Il ne reste plus qu’à tout
dessiner — d’où le nom de cette fonction — autour du point (0, 0, 0) qui est le centre du billard.
Voici l’algorithme général de la fonction dessiner_tout() :
Étape
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
Type d’opération
Liste
Fonction
Liste
Liste
Liste
-
Description de l’opération
Positionner les deux lampes au-dessus de la table
Dessiner le tapis
Dessiner les ombres (test de profondeur désactivé)
Dessiner le meuble
Empiler matrice
Translation
Empiler matrice
Rotation (par multiplication de matrice)
Dessiner une bille sans reflet spéculaire
Dépiler matrice
Dessiner un “chapeau” de bille uniquement spéculaire
Dépiler matrice
Les étapes 5 à 12 sont répétées autant de fois qu’il y a de billes sur la table.
Liste “bille speculaire” totalement
transparente, ne sert qu’à dessiner
les re3ets des lampes
Liste “bille diffuse” totalement
opaque, sur laquelle est appliquée
la texture
Pour chaque bille, la fonction statique chargée de dessiner les ombres projette
l’ombre d’un carré sur le tapis. Il en résulte deux quadrilatères — un quadrilatère
par source de lumière — plus ou moins étirés, en fonction de leur position par rapport aux lampes. Chaque quadrilatère est affiché avec la texture d’ombre. Chaque
texel de cette texture a ses composantes rouge, verte, et bleue à 0. Seule la composante alpha varie, formant un dégradé circulaire — voir la page des textures.
Avant d’effectuer le rendu des ombres, le test de profondeur est désactivé, car
l’ombre est située à la même altitude y que le tapis. Une fois les ombres dessinées,
le test de profondeur est réactivé.
Dans ce billard, les sources de lumière sont les seuls objets de l’espace que
OpenGL† n’oublie pas. Une fois paramétrées, on peut voir leur effet dans tous les prochains objets dessinés.
Cependant, comme le billard peut tourner et se déplacer — pour simuler les mouvements de caméra — les lampes
doivent se déplacer de la même façon. Il faut donc les repositionner à chaque image de l’animation, ceci afin que
leurs coordonnées tiennent compte de l’état de la matrice courante.
∗ Open
† Open
Graphics Library Utility Toolkit : boı̂te à outils des utilitaires de la librairie ouverte du graphisme
Graphics Library : librairie ouverte du graphisme
11
2.6
Initialiser les données partagées : init.c
Cet objet est de loin l’objet le plus simple de tout le code source. Son interface init() est appelée une seule
fois, au moment où le billard commence son exécution, avant que la première image ne soit affichée.
Cette fonction “allume” les lampes à la bonne intensité, active les possibités OpenGL∗ dont se sert le billard,
définit la taille des “taches” qui simuleront les reflets spéculaires des lampes, charge les textures dans la mémoire
vidéo, remplit des zones de mémoire virtuelle avec des instructions graphiques élémentaires constantes :
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
static const float lumiere_diffuse
[3] = {.6, .5, .4} ;
static const float lumiere_speculaire[3] = {.6, .5, .4} ;
glLightfv(GL_LIGHT0,
glLightfv(GL_LIGHT0,
glLightfv(GL_LIGHT1,
glLightfv(GL_LIGHT1,
GL_DIFFUSE ,
GL_SPECULAR,
GL_DIFFUSE ,
GL_SPECULAR,
glEnable(GL_CULL_FACE )
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING )
glEnable(GL_LIGHT0
)
glEnable(GL_LIGHT1
)
lumiere_diffuse
)
lumiere_speculaire)
lumiere_diffuse
)
lumiere_speculaire)
;
;
;
;
;
;
;
;
;
glMateriali(GL_FRONT, GL_SHININESS, 100) ;
creer_textures() ;
creer_listes () ;
Ensuite, la fonction init() tourne les billes aléatoirement, de telle sorte que chaque nouvelle exécution du
billard affichera des rotations différentes. Elle positionne les billes en triangle, et finalement colore le tapis en vert.
2.7
Créer des listes constantes : listes.c
Une liste OpenGL est un emplacement de la mémoire virtuelle contenant des
instructions élémentaires destinées à être envoyées rapidement au processeur graphique. Le but de la plupart des fonctions OpenGL∗ — glVertex, glMaterial,
glTexCoord. . . — est de rajouter une ou plusieurs instructions élémentaires à la
liste courante.
Lorsqu’on sait que chaque image d’une animation telle que ce billard est le
résultat de millions d’instructions élémentaires, on se rend mieux compte du gaspillage phénoménal au niveau du processeur central, qui doit sans cesse recréer —
avec toute la trigonométrie et les milliers d’appels de fonctions nécessaires — ces
instructions élémentaires, dont plus de 99% reviennent constamment identiques.
Tout ce gaspillage de temps peut être évité en créant une fois pour toutes ces instructions constantes, et en les
stockant dans des listes réutilisables à volonté.
L’objet listes.c a été conçu uniquement pour allouer et remplir cinq listes lors de l’initialisation du billard.
Pourtant, les tailles des fichiers parlent d’elles-mêmes :
33.4
9.6
4.4
2.9
2.2
1.2
ko
ko
ko
ko
ko
ko
listes.c
anim.c
dessin.c
main.c
init.c
billard.h
La fonction creer_listes() est appelée par la fonction init() de l’objet init.c pour préparer les listes
d’instructions. Ensuite, l’objet listes.c n’est plus utilisé lors de l’exécution.
∗ Open
Graphics Library : librairie ouverte du graphisme
12
2.8
Objet principal : main.c
Ceci est l’objet principal, qui démarre l’exécution et réagit aux actions de
l’utilisateur. Cet objet est le seul à utiliser la librairie GLUT∗ , les autres objets
se contentent des fonctions OpenGL† pour le dessin, voire du C pour le calcul de
l’animation.
L’interface de cet objet est composée d’une seule fonction : main(). Son rôle est
très simple : elle fournit à GLUT∗ l’adresse des fonctions rattachées à l’affichage,
au clavier, aux déplacements et aux clics de la souris, initialise tout le billard en
appelant simplement la fonction init() de l’objet init.c — elle-même faisant
référence aux fonctions creer_textures() et creer_listes() — pour finalement
rentrer dans la boucle infinie de la fonction glutMainLoop().
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
∗ Open
† Open
glutCreateWindow("Billard") ;
glutDisplayFunc
(display )
glutKeyboardFunc
(keyboard)
glutMouseFunc
(mouse
)
glutMotionFunc
(motion )
glutPassiveMotionFunc(passive )
glutReshapeFunc
(reshape )
;
;
;
;
;
;
glutFullScreen() ;
glutSetCursor(GLUT_CURSOR_NONE) ;
init() ;
glutMainLoop() ;
Graphics Library Utility Toolkit : boı̂te à outils des utilitaires de la librairie ouverte du graphisme
Graphics Library : librairie ouverte du graphisme
13
14
Chapitre 3
Création de l’exécutable
3.1
Compilation des textures
Voici le contenu du dossier make_images :
billes0.bmp
billes1.bmp
billes2.bmp
billes3.bmp
billes4.bmp
billes5.bmp
billes6.bmp
billes7.bmp
billes8.bmp
billes9.bmp
billes10.bmp
billes11.bmp
billes12.bmp
billes13.bmp
billes14.bmp
billes15.bmp
bois.bmp
make_images.bat
make_images.c
ombre.bmp
tapis.bmp
Pour compiler les textures, il suffit de cliquer sur le fichier make_images.bat, dont voici le script :
@echo off
gcc make_images.c -o make_images -O3 -s -Wall
make_images.exe billes 3 16 bois 3 1 tapis 3 1 ombre 1 1
del make_images.exe
pause
make_images.exe ira chercher automatiquement les fichiers *.bmp dans le dossier courant, et créera les fichiers
images.o, images.h, textures.c et textures.h dans ce même dossier. Pour cela, il a besoin d’une suite de triplets
d’arguments (t, p, n) où :
– t est le nom du tableau que l’on souhaite utiliser en C.
– p est le nombre de plans (1=Alpha ou 3=RGB∗ ) que l’on souhaite convertir en RGBA† .
– n est le nombre de versions de l’image.
Les tableaux générés par make_images.exe sont globaux et constants. Ils seront donc écrits dans la région CODE de l’exécutable obtenu, donc dans la région
CODE des processus qui en découlent.
Les pages de cette région sont marquées en “lecture seule” par le système
d’exploitation, ce qui est un gage de sécurité — au cas où une erreur du code
engendrerait une écriture dans une image, la MMU‡ détecterait immédiatement
l’incohérence entre les droits de la page et l’action demandée. Elle en avertirait
le système d’exploitation, qui générerait un signal SIGSEGV, ce qui terminerait
immédiatement l’exécution du programme — si l’action du signal SIGSEGV n’a
pas été redéfinie, ce qui est le cas ici.
∗ Red
Green Blue : rouge vert bleu
Green Blue Alpha : rouge vert bleu alpha
‡ Memory Management Unit : unité de gestion de la mémoire
† Red
15
3.2
Compilation du code source
Voici le contenu du dossier racine :
make_images
anim.c
Billard.bat
billard.h
dessin.c
init.c
listes.c
main.c
Pour compiler le code source complet, et obtenir l’exécutable Billard.exe, il
suffit de cliquer sur le fichier Billard.bat, dont voici le script :
@echo off
gcc *.c make_images/images.o make_images/textures.c -o Billard -O3 -s
-Wall -mwindows -lm -lopengl32 -lglu32 -lglut32
pause
L’option -s sert à effacer la table des symboles de Billard.exe, car elle n’est
plus d’aucune utilisé lors de l’exécution. Cette opération peut être réalisée après
compilation, grâce à l’utilitaire strip.
L’option -mwindows sert à ce que Billard.exe n’ouvre pas de fenêtre MS-DOS∗ lors de son exécution. Cette
option ne doit pas être utilisée sous UNIX† , car il n’y a pas de fenêtre MS-DOS∗ sous UNIX† .
3.3
Exécution du programme
Lorsque l’interaction a été créée, le but était de la concevoir la plus simple et la plus intuitive possible. Dans la
première version de ce jeu, le déplacement de caméra ne modifiait pas la distance par rapport au centre du billard.
Pour corriger ce défaut, il était possible de “zoomer” en appuyant sur la touche [Shift]. Cette manipulation en
deux temps — déplacer puis zoomer — a été remplacée par une manipulation “tout-en-un” beaucoup plus simple.
Désormais, le rapprochement et l’éloignement est intégré au déplacement de caméra.
Environ dix personnes ont essayé ce jeu, et elles ont toutes été conquises par sa jouabilité réaliste et très intuitive.
Manipuler la souris :
Il faut frapper la boule blanche à l’aide de la queue. Celle-ci apparaı̂t uniquement lorsque toutes les billes sont arrêtées. Dès lors, les mouvements de la
souris sont répercutées sur la queue. Pour tirer, il suffit simplement d’avancer la
queue jusqu’à ce qu’elle touche la bille blanche. C’est le contact avec celle-ci qui
va la faire partir en respectant la force de frappe et l’angle formé par la queue au
moment de la frappe.
À tout moment, l’utilisateur peut déplacer la caméra en appuyant sur le bouton
gauche de la souris pendant qu’il la déplace. Un curseur en forme de croix apparaı̂t
pendant que le bouton est cliqué. De cette façon, l’utilisateur sait toujours où se
trouve la souris pendant le déplacement, évitant ainsi d’être bloqué sans le savoir par le bord de l’écran.
Touches de raccourci :
– [R] : colore le tapis en rouge
– [V] : colore le tapis en vert (par défaut)
– [B] : colore le tapis en bleu
– [espace] : vue de dessus
– [0] à [9] : définit le nombre d’avancements par image (la valeur par défaut est 5)
– Autre touche : quitter le jeu
∗ Microsoft
† Uniplexed
– Disk Operating System : système d’exploitation à disque
Information and Computing System : système d’information et de calcul uniplexé
16
Chapitre 4
Conclusion
Il y a 4 ans, je commençais tout juste à voir des articles sur internet parlant des cartes graphiques et de leurs
possibilités en dessin 3D. Je n’imaginais pas qu’un jour, je saurais utiliser ces possibilités. Ce billard est mon pemier
vrai programme se servant de la librairie OpenGL∗ .
Ce qui a été le plus long dans la réalisation de ce projet était sans aucun
doute l’apprentissage d’OpenGL∗ , savoir ce qui est exécuté par le processeur graphique, ce qui est exécuté par le processeur central, le moment où sont réalisées
les entrées/sorties avec la carte graphique. . . sans oublier la philosophie de la librairie elle-même. Tout ceci m’a demandé de réaliser une énorme quantité de
petits programmes de test, de rechercher sur internet les spécifications des fonctions OpenGL, et des exemples pour leur utilisation. La plupart des tutoriels ne
rentrent pas dans le détail, et les quelques-uns qui le font se contredisent souvent.
Ils fournissent rarement des exemples, et lorsqu’ils le font, ces exemples sont souvent faux, incomplets, ou ne compilent pas pour différentes raisons — l’exemple
le plus fréquent est qu’ils n’utilisent pas les fonctions OpenGL dans le bon ordre — ce qui, évidemment, ne donne
pas le résultat attendu lors de l’exécution. . . si toutefois la compilation réussit.
Tout ce temps de recherche et de test a duré plus de deux mois, pendant lesquels j’ai posé des questions à Alain
Daurat de l’option IGG† , et à Dominique Gerber pendant ses TP de LIG‡ .
Je remercie également Olivier Genevaux et Dominique Gerber — encore lui — pour avoir résolu un problème
technique dans mon code source. Le problème en question était l’utilisation de ColorMaterial, qui ne donne pas
le même résultat avec les drivers ATI et les drivers nVidia, Matrox. . . Sans cette journée de recherche, le billard
n’aurait jamais pu être exécuté correctement sur un ordinateur équipé d’une carte graphique ATI.
Je remercie également Woo Hyun Lee — étudiant en maı̂trise de mathématiques discrètes — pour sa brève
introduction au langage LATEX qui m’a servi à présenter ce rapport. Depuis quelques mois, ce sont les tutoriels, les
FAQ§ et mes nombreux tests personnels qui me font progresser dans ce formidable langage de mise en page. Je
remercie Alain Daurat et Vincent Lœchner pour avoir répondu à mes questions concernant LATEX. Ce rapport
a été compilé sous Windows XP avec MiKTEX 2.2.
∗ Open
Graphics Library : librairie ouverte du graphisme
Géométrique et Graphique
‡ Logiciels et Interfaces Graphiques
§ Frequently Asked Questions : questions fréquemment posées
† Informatique
17
18
Annexe A
Copies d’écran
19
20
Annexe B
Textures utilisées
64 × 64
billes[0]
64 × 64
billes[1]
64 × 64
billes[2]
64 × 64
billes[3]
64 × 64
billes[4]
64 × 64
billes[5]
64 × 64
billes[6]
64 × 64
billes[7]
64 × 64
billes[8]
64 × 64
billes[9]
64 × 64
billes[10]
64 × 64
billes[11]
64 × 64
billes[12]
64 × 64
billes[13]
64 × 64
billes[14]
64 × 64
bois
32 × 32
ombre
64 × 64
tapis
64 × 64
billes[15]
21