FAQ OpenGL
FAQ OpenGL Consultez toutes les FAQ
Nombre d'auteurs : 9, nombre de questions : 74, dernière mise à jour : 24 juin 2021
- Qu'est-ce que GLUT ?
- Où trouver GLUT ?
- Comment se passer de la console sous Windows ?
- Comment texturer les primitives créées avec GLUT ?
- Pourquoi ma fonction GLUT ne fonctionne-t-elle pas ?
- Comment récupérer les extensions OpenGL avec GLUT ?
- Comment afficher du texte avec GLUT dans une perspective orthogonale ?
- Comment connaître les fontes que l'on peut utiliser avec glutBitmapCharacter ?
- Comment connaître la taille d'un caractère affiché par glutBitmapCharacter ?
- Comment gérer un évènement ?
- Comment gérer le clavier ?
- Comment gérer la souris ?
- Comment gérer l'affichage ?
- Comment savoir si la souris a quitté la fenêtre ?
- Comment savoir si la fenêtre est visible ou non ?
- Comment mettre en place un timer ?
- Comment faire exécuter du code lorsque le processus ne fait rien ?
GLUT (GL Utility Toolkit) est une bibliothèque portable apportant principalement la gestion du fenêtrage à OpenGL. La version originale de GLUT a été créée par Mark Kilgard puis portée sous Win32 (Windows 95, 98, Me, NT, 2000, XP) par Nate Robins.
De nombreux tutoriels et exemples trouvables sur Internet utilisent GLUT, c'est la bibliothèque la plus répandue. Malheureusement aujourd'hui, GLUT n'est plus mis à jour et la dernière version (3.7.6) date du 8 novembre 2001. De plus, elle souffre de quelques bogues et la licence est restrictive. Il est conseillé d'utiliser FreeGLUT. (voir aussi ).
Le FTP de GLUT [ftp://ftp.sgi.com/sgi/opengl/glut/index.html] contient de nombreux fichiers utiles :
- les dernières versions pour différentes plateformes, binaires et fichiers de développement ;
- les versions précédentes ;
- le code source de GLUT ;
- des FAQ ;
- la documentation de référence (HTML, PS, PDF).
FreeGLUT, une version open source de GLUT possédant une licence beaucoup moins restrictive, est disponible sur le site de FreeGlut.
Par défaut sous Windows, une console s'affiche lors de l'exécution de votre application, en plus de la fenêtre de rendu.
Il est très simple de s'en passer : il faut créer un projet « Application Windows » et non « Application Console ». Attention toutefois à bien changer le point d'entrée : il s'agira de WinMain et non plus de main.
Si vous souhaitez tout de même conserver main comme point d'entrée (pour des raisons de portabilité par exemple), certains EDI permettent de modifier celui-ci. Par exemple sous Visual Studio, il faut ajouter l'option « /ENTRY:mainCRTStartup » dans la ligne de commande de l'éditeur de liens.
GLUT permet de créer des formes de base via ses fonctions glutSolidCone, glutSolidCube… mais ces formes ne possèdent pas de coordonnées de textures, si bien qu'il est impossible de les texturer correctement.
Il n'y a aucun moyen de forcer GLUT à ajouter des coordonnées de texture, ainsi il vaudra mieux passer par les fonctions de GLU pour générer ces formes (gluCylinder, gluSphere…). Leur génération est toutefois plus compliquée, puisqu'il faut passer par les quadriques. Plus d'informations sur l'utilisation des quadriques ici :
https://nehe.developpez.com/tutoriel/18-quadriques/.
Pour activer la génération de coordonnées de texture, il suffit d'intercaler un petit appel à gluQuadricTexture avec GL_TRUE en paramètre.
Comme dans beaucoup de fonctions GLUT, il faut avoir une fenêtre valide pour pouvoir l'appeler. Vérifiez donc que votre programme ouvre d'abord une fenêtre correctement avant tout autre appel GLUT.
Une ouverture de base se fait comme ceci :
int
main
(
int
argc, char
**
argv)
{
/* On utilisera le mode RGB, un double tampon et le tampon Z */
glutInit
(&
argc,argv);
/* On voudra une fenêtre 640x480 */
glutInitDisplayMode
(
GLUT_RGB |
GLUT_DOUBLE |
GLUT_DEPTH);
glutInitWindowSize
(
640
,480
);
glutCreateWindow
(
"
OpenGL - Glut
"
);
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
Sous OpenGL, la technique est d'appeler glGetString et parcourir la chaîne de caractères renvoyée.
Mais avec GLUT, on peut utiliser plus simplement la fonction suivante pour déterminer si une extension est supportée :
int
glutExtensionSupported(char
*
extension);
Où extension est la chaîne de caractères associée à l'extension (par exemple « GL_ARB_texture_compression »).
Pour afficher du texte avec GLUT, la fonction à utiliser est glutBitmapCharacter. Mais cette fonction ne marchera pas toute seule, il faut utiliser glRasterPos2f pour initialiser correctement la position d'écriture.
Voici un exemple :
void
render_string
(
float
x, float
y, float
z, void
*
font, const
char
*
s)
{
glDisable
(
GL_TEXTURE_2D);
glDisable
(
GL_DEPTH_TEST);
glRasterPos2f
(
x, y);
while
(*
s)
{
glutBitmapCharacter
(
font, *
s);
s++
;
}
}
Les deux glDisable permettent d'être sûr d'avoir le texte affiché dans la couleur souhaitée.
Pour connaître ce qu'il faut passer au paramètre font, lisez l'entrée de la FAQ https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_font.
Il faut regarder dans vos fichiers d'inclusion GLUT les lignes suivantes :
/* Bitmap font constants (use these in GLUT program). */
#define GLUT_BITMAP_9_BY_15 ((void*)2)
#define GLUT_BITMAP_8_BY_13 ((void*)3)
#define GLUT_BITMAP_TIMES_ROMAN_10 ((void*)4)
#define GLUT_BITMAP_TIMES_ROMAN_24 ((void*)5)
#define GLUT_BITMAP_HELVETICA_10 ((void*)6)
#define GLUT_BITMAP_HELVETICA_12 ((void*)7)
#define GLUT_BITMAP_HELVETICA_18 ((void*)8)
En principe celles-ci ne bougeront pas, donc vous pouvez vous en servir. Mais il y en aura peut-être d'autres…
On utilise la fonction suivante :
int
glutBitmapWidth
(
void
*
font, int
character);
Le paramètre font est le même que celui passé à glutBitmapCharacter (voir https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_font).
Sous GLUT, tout se fait avec des fonctions de rappel (callbacks). Ce sont des fonctions qui seront appelées lorsque la gestion d'un évènement est nécessaire.
Avant de lancer la boucle avec glutMainLoop(), on définira donc les fonctions qui vont gérer le clavier, la souris, l'affichage, etc.
Voir par exemple :
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_evt_clavier
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_evt_souris
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_evt_affichage
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_evt_souris_fenetre
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_etat_fenetre
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_timer
- https://jeux.developpez.com/faq/opengl/?page=glut#GLUT_idle
Pour gérer le clavier, on peut utiliser quatre fonctions qui se divisent en deux groupes :
- les fonctions pour les touches normales ;
- les fonctions pour les touches spéciales.
Par exemple, les lettres de l'alphabet sont des touches normales. Par contre, les touches F1 à F12 sont des touches spéciales.
Voici les deux fonctions qui permettent de gérer l'appui d'une touche sur un clavier :
void
glutKeyboardFunc
(
void
(*
func)(
unsigned
char
key, int
x, int
y));
void
glutSpecialFunc
(
void
(*
func)(
int
key, int
x, int
y));
Ensuite, on peut gérer le fait qu'un utilisateur relâche une touche en utilisant les deux autres fonctions suivantes :
void
glutKeyboardUpFunc
(
void
(*
func)(
unsigned
char
key, int
x, int
y));
void
glutSpecialUpFunc
(
void
(*
func)(
int
key, int
x, int
y));
Exemple :
void
AppuiTouche
(
int
key, int
x, int
y)
{
if
(
key ==
GLUT_KEY_F1)
{
/* La touche F1 est appuyée */
}
}
void
RelachementTouche
(
int
key, int
x, int
y)
{
if
(
key ==
GLUT_KEY_F1)
{
/* La touche F1 est relâchée */
}
}
int
main
(
)
{
/* Initialisation de la fenêtre ... */
/* Enregistrement de nos fonctions de gestion des touches spéciales */
glutSpecialFunc
(&
AppuiTouche);
glutSpecialUpFunc
(&
RelachementTouche);
/* Lancement de la boucle principale */
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
Il y a trois fonctions pour la gestion de la souris :
void
glutMouseFunc
(
void
(*
func)(
int
button, int
state, int
x, int
y));
void
glutMotionFunc
(
void
(*
func)(
int
x, int
y));
void
glutPassiveMotionFunc
(
void
(*
func)(
int
x, int
y));
La fonction glutMouseFunc permet de savoir si un bouton de la souris a été appuyé. Le premier paramètre renseigne le bouton qui a été appuyé, voici les possibilités :
#define GLUT_LEFT_BUTTON 0
#define GLUT_MIDDLE_BUTTON 1
#define GLUT_RIGHT_BUTTON 2
Ensuite l'état est le fait d'appuyer un bouton ou le relâcher. En effet, cette fonction est appelée deux fois pour un clic souris (une fois pour l'appui du bouton et une fois pour le relâchement).
#define GLUT_DOWN 0
#define GLUT_UP 1
La fonction glutMotionFunc génère des évènements lorsque la souris bouge et qu'un bouton est appuyé. Elle donnera la nouvelle position de la souris, mais pour connaître quel bouton est appuyé, il faudra utiliser en même temps une fonction callback définie par glutMouseFunc.
Enfin, la fonction glutPassiveMotionFunc permet de générer des évènements lorsque la souris bouge et lorsqu'aucun bouton n'est appuyé. De nouveau, c'est la nouvelle position qui sera passée à la fonction callback.
void
BoutonSouris
(
int
button, int
state, int
x, int
y)
{
/* Gestion du bouton appuyé "button" et éventuellement de la position du curseur "x, y" */
}
void
MouvementSouris
(
int
x, int
y)
{
/* Gestion de la position du curseur "x, y" */
}
int
main
(
)
{
/* Initialisation de la fenêtre ... */
/* Enregistrement de notre fonction de gestion des boutons souris */
glutMouseFunc
(&
BoutonSouris);
/* Enregistrement de notre fonction de gestion des mouvements souris */
glutPassiveMotionFunc
(&
MouvementSouris);
/* Lancement de la boucle principale */
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
On utilise deux fonctions. Une pour l'affichage qui s'appelle glutDisplayFunc, et une autre pour le redimensionnement de la fenêtre (et donc les changements à prendre en compte pour l'affichage), glutReshapeFunc.
void glutDisplayFunc(void (*func)(void)); void glutReshapeFunc(void (*func)(int width, int height));
Exemple :
void
Affichage
(
)
{
/* Affichage de la scène */
}
void
Redimensionnement
(
int
width, int
height)
{
/* width et height sont les nouvelles dimensions de la fenêtre */
}
int
main
(
)
{
/* Initialisation de la fenêtre ... */
/* Enregistrement de notre fonction d'affichage */
glutDisplayFunc
(&
Affichage);
/* Enregistrement de notre fonction d'affichage */
glutReshapeFunc
(&
Redimensionnement);
/* Lancement de la boucle principale */
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
Pour gérer les moments où la souris quitte la fenêtre ou revient dans celle-ci, on utilise la fonction suivante :
void
glutEntryFunc
(
void
(*
func)(
int
state));
Et le paramètre state peut prendre les valeurs suivantes :
#define GLUT_LEFT 0
#define GLUT_ENTERED 1
Attention : certains systèmes d'exploitation ne gèrent pas correctement cette fonction.
Exemple :
void
SourisFenetre
(
int
state)
{
if
(
state ==
GLUT_ENTERED)
{
/* La souris vient d'entrer sur la fenêtre */
}
else
{
/* La souris vient de sortir de la fenêtre */
}
}
int
main
(
)
{
/* Initialisation de la fenêtre ... */
/* Enregistrement de notre fonction de gestion de la souris par rapport à la fenêtre */
glutEntryFunc
(&
SourisFenetre);
/* Lancement de la boucle principale */
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
Pour gérer le changement de visibilité de la fenêtre, on utilise la fonction suivante :
void
glutWindowStatusFunc
(
void
(*
func)(
int
state));
Le paramètre state peut valoir :
/* Fenêtre entièrement cachée */
#define GLUT_HIDDEN 0
/* Fenêtre entièrement visible */
#define GLUT_FULLY_RETAINED 1
/* Fenêtre partiellement visible */
#define GLUT_PARTIALLY_RETAINED 2
/* Fenêtre entièrement cachée mais visible (la barre de la fenêtre) */
#define GLUT_FULLY_COVERED 3
Pour définir un timer, on utilise la fonction suivante :
void
glutTimerFunc
(
unsigned
int
millis, void
(*
func)(
int
value), int
value);
- millis représente le nombre de millisecondes avant que la fonction ne soit appelée ;
- value est la valeur passée à la fonction func lors de l'appel. Ceci permet d'avoir plusieurs temporisateurs qui tournent en même temps.
Exemple :
void
FonctionTimer
(
int
value)
{
switch
(
Value)
{
case
0
:
/* Le délai du premier timer est écoulé */
break
;
case
1
:
/* Le délai du second timer est écoulé */
break
;
}
}
int
main
(
)
{
/* Initialisation de la fenêtre ... */
/* Enregistrement de nos timers */
glutTimerFunc
(
10
, &
FonctionTimer, 0
);
glutTimerFunc
(
50
, &
FonctionTimer, 1
);
/* Lancement de la boucle principale */
glutMainLoop
(
);
return
EXIT_SUCCESS;
}
GLUT permet de gérer beaucoup de choses en même temps. Mais lorsque le gestionnaire n'a rien à faire, il permet d'exécuter du code avec ce callback :
void
glutIdleFunc
(
void
(*
func)(
void
));