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