GLUT, quoi qu'est-ce ? Et bien c'est une librairie pour OpenGL (GL utility
toolkit) destinée à faciliter la vie du programmeur. Non, elle
ne vous fait pas la bouffe ni ne vous torche à votre place, mais elle
sait quand même créer une fenêtre dans n'importe quel environnement
de n'importe quel OS et bien plus, comme vous le verrez bientôt. Elle
a été en fait désignée pour permettre une portabilité
à 100% du code. Hé oui ! Vous avez bien lu ! 100% ! Ca veut
dire quel que soit l'OS, tous vos programmes OpenGL seront parfaitement
compilables sans aucune modifications à apporter ! C'est-y pas génial,
ca ?
Mais alors pourquoi j'ai pas commencé par faire un tutorial glut ? Ben
d'abord par ce que j'ai appris sans, et qu'ensuite je trouve plus pratique de
développer sans glut pour ce qui est du débugage et des test,
parce qu'on a beaucoup plus d'options et de trucs comme ça. Mine de rien,
ca permet quand même d'appréhender les réactions de chaque
machine à OpenGL, de voir les différences entres les cartes 3D
etc... Mais glut a lui aussi plein d'avantages : d'abord on peut faire de tout
petits programmes tous cons qui tiennent en quelques lignes et peuvent faire
des effets excellent, et puis glut ne se contente pas de gérer le
graphisme : on peut aussi grâce à glut gérer la souris,
le clavier... C'est vraiment excellent !
Après cette brève introduction,
passons à la partie code. Je vais moins commenter le code que dans le
tutorial sur OpenGL pour win, parce que les remarque sont les mêmes. Donc
je vous conseille de lire rapidement le tutorial sus-cité (surtout la
2e partie) afin de saisir les 2 ou 3 concepts de base avant d'aborder celui-ci.
Et si vous avez déjà réussi à utiliser OpenGL avec
windows, alors ce tutorial-ci sera une partie de plaisir. Dans les #include,
on uniquement glut.h. Remarquez qu'ici il n'y a pas de windows.h : c'est un
code tout à fait portable. Il n'y a pas non plus gl.h ou glu.h mais ceux-ci
sont déjà inclus par glut.h normalement. Mais tout dépend
des compilateurs et des systèmes : certains permettent d'inclure les
3, d'autres se contentent de glut.h. Mais pas de panique : toutes les fonctions
gl et glu sonnt accessibles dès lors que vous incluez glut.h.
#include <gl/glut.h>
La différence entre les différentes plateformes se fera en fait
au moment de la compilation : sous windows, vous incluerez glut32.lib, opengl32.lib
et glu32.lib dans vos liens, tandis que sous Unix vous ferez "cc prog.c
-o Prog -lX11 -lglut -lGL etc..."
Sous Visual C++, vous n'aurez donc plus à créer un Win32 Apllication
Project, avec WinMain et tout le toutim, mais juste un Win32Console Application
Project, c'est-à-dire un prog 32 bits qui sait utiliser les dll de win.
Et bien passons maintenant au main()
(ahhh, enfin un main normal !), qui va d'ailleurs être plutôt dans
le genre
int main( int argc, char *argv[ ], char *envp[
] )
Si vous n'avez jamais vu cette syntaxe, sachez qu'elle est tout à fait
conforme au C ANSI, et qu'elle permet juste de récupérer les arguments
de ligne de commande et les variables d'environnement.
Commencons par remplir ce main() avec
les fonctions d'initialistation de glut :
int WindowName; |
|
int main( int argc, char *argv[ ], char *envp[
] )
|
{ |
|
|
glutInit(&argc, argv); |
glutInitDisplayMode(GLUT_RGBA
| GLUT_DOUBLE | GLUT_DEPTH); |
glutInitWindowSize(640,480); |
//Optionnel |
WindowName = glutCreateWindow("Ma
première fenêtre OpenGL !"); |
glutFullScreen(); |
//Optionnel |
|
return 0; |
|
} |
|
glutInit() a besoin des arguments
de ligne de commande, donc on lui donne.
- On transmet à
glutInitDisplayMode()
les options qu'on veut : ici, j'ai choisi un mode RGBA (32 bits), un double-buffering,
et un Z-buffer à titre d'exemple.
glutInitWindowSize() et glutInitWindowPos()
sont des fonctions qui permettent de spécifier la taille et la postition
des fenêtres qui vont être créées.
- Enfin, on crée notre fenêtre, en transmettant juste le titre,
en on récupère un nom unique pour cette fenêtre, qui servira
à la redimensionner, la fermer... Donc mieux vaut l'enregistrer en
tant que variable globale.
Et là, vous pouvez d'ores et déjà lancer votre programme
: ça crée une fenêtre OpenGL en plein écran et tout
et tout... et ca la ferme aussitôt ! Hé oui, on a pas encore vu
comment gérer les évènements comme on le faisait avec WM_PAINT
et toutes ces autres conneries. Et ben on va le faire maintenant : vous vous
rapellez qu'à réception du message WM_SIZE ,
on appelait notre fonction Reshape() ,
qui remettait les paramètres OpenGL aux goûts de la fenêtre.
Et ben là, c'est tout pareil : y'a juste à écrire dans
le main() après les quelques
initialisations
glutReshapeFunc(Reshape);
Avec notre fonction Reshape() définie
de la sorte :
void Reshape(int width, int height) |
{ |
|
|
glViewport(0,0,width,height); |
|
glMatrixMode(GL_PROJECTION); |
|
glLoadIdentity(); |
|
gluPerspective(
45,
float(width)/float(height),
0.1,
100
); |
//Pour les explications, lire le tutorial
sur OGL et win |
|
glMatrixMode(GL_MODELVIEW); |
//Optionnel |
} |
|
Et de même, on appelait Draw()
à réception du message WM_PAINT .
Ici, c'est la même chose que pour Reshape()
: on crée notre fonction Draw()
qui va contenir toutes les fonctions de dessin, et on initialise glut avec
glutDisplayFunc(Draw);
A titre d'exemple, la fonction Draw()
peut être quelque chose dans ce genre (référez-vous au tutorial
OGL+Windows 2e partie pour toutes les explications sur InitGL() ,
Draw() et
Reshape() ) :
void Draw() |
{ |
|
} |
glClear
(
GL_COLOR_BUFFER_BIT |
GL_DEPTH_BUFFER_BIT
); |
//Efface le frame buffer et le Z-buffer |
glMatrixMode(GL_MODELVIEW); |
//Choisit la matrice MODELVIEW |
glLoadIdentity(); |
//Réinitialise la matrice |
gluLookAt(0,0,-10,0,0,0,0,1,0);
|
glBegin(GL_TRIANGLES); |
glVertex2i(0,1);
glVertex2i(-1,0);
glVertex2i(1,0);
|
glEnd(); |
//Pour les explications,
lire le tutorial sur OGL et win |
glutSwapBuffers();
|
//Attention : pas SwapBuffers(DC)
! |
glutPostRedisplay();
|
//Demande de recalculer la scène |
|
Remarquez que cette fonction diffère de la version "sans glut"
par glutSwapBuffers() . Donc si vous
voyez SwapBuffers(DC) dans les prochains
tuts, ne vous étonnez pas et remplacez-le par glutSwapBuffers() .
Attention également à glutPostRedisplay()
: en effet, Draw() n'est appelée
que lorsque glut pense que la fenêtre doit être rafraîchie
(donc lorqu'on change de fenêtre, lorsqu'elle est réduite...).
Pour demander à glut de refaire le rendu, il faut donc appeler glutPostRedisplay() ,
sinon votre fenêtre ne sera pas rafraîchie régulièrement.
Ensuite, après avoir initialisé glut, vous pouvez initialiser
OpenGL lui-même en vous faisant une petite fonction InitGL contenant tous
les trucs nécessaires : glEnable(GL_DEPTH_TEST) ,
glEnable(GL_LIGHTING) etc... Cela ne vous
dit peut-être rien pour l'instant, mais vous en aurez besoin plus tard.
Enfin, lancez le gestionnaire glut, qui se chargera de lancer les fonctions
Draw() et Reshape()
aux moments voulus, grâce à glutMainLoop() .
Pour résumer, voici la fonction main()
complète :
int main( int argc, char *argv[ ], char *envp[
] )
|
{ |
|
|
glutInit(&argc, argv); |
glutInitDisplayMode(GLUT_RGBA
| GLUT_DOUBLE | GLUT_DEPTH); |
glutInitWindowSize(640,480); |
//Optionnel |
WindowName = glutCreateWindow("Ma
première fenêtre OpenGL !"); |
glutFullScreen(); |
//Optionnel |
|
glutReshapeFunc(Reshape); |
glutDisplayFunc(Draw);
|
InitGL();
|
|
glutMainLoop(); |
|
return 0; |
|
} |
|
Ici notre fonction InitGL() ne contient
absolument rien, mais nous nous en servirons plus tard. Notez que glutMainLoop()
ne s'arrête jamais : on est obligé de sortir du programme par un
exit() , ou de fermer la fenêtre
manuellement.
Le programme présenté ici donnera quelque chose de ce genre (là
c'est sans fullscreen) :
Et voilà, c'est fini ! Vous pouvez maintenant garder cet exemple comme
un canevas sur lequel vous n'aurez plus qu'à tisser votre code (c'est
beau, non ?). Dans les prochains tutorials, je ferais toujours référence
à Draw() , InitGL()
et Reshape() , donc vous devrez être
censés savoir ce que c'est. En plus, ces fonctions se retrouvent également
dans la partie "sans glut" : comme ça je n'aurais pas à
expliquer les choses de 2 façons différentes.
Antoche | |