GLUT de A à Z

Tony BAYART

GLUT (OpenGL Utility Toolkit) est une bibliothèque portable permettant de s'affranchir du système d'exploitation dans la réalisation d'une application OpenGL. Créée par Mark Kilgard et portée sur différents systèmes, GLUT est très pratique pour concevoir des petits programmes de tests, des démonstrations et même des jeux. L'intérêt de GLUT réside avant tout dans sa gestion du fenêtrage évitant ainsi au développeur d'avoir à écrire cette partie fortement dépendante du système sur lequel s'exécute le programme. Au delà du fenêtrage et de la gestion des périphériques de saisie (clavier, souris), GLUT possède également d'autres fonctionnalités intéressantes que nous allons découvrir ensemble à travers cet article.

- Titre : GLUT de A à Z

- Auteur : Tony BAYART

- Parution :

- Licence : Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur. La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.

Sommaire

- I. Introduction

- II. Déroulement d'un programme GLUT

- II-A. Initialisation de GLUT

- II-B. Paramétrage de la fenêtre

- II-C. Création de la fenêtre

- II-D. Initialiser les procédures

- II-E. Boucle principale de GLUT

- III. Le fenêtrage

- IV. Les événements

- V. Les procédures "Callback"

- VI. Récupération des états

- VII. Rendu d'objets géométriques

- VIII. Les polices de caractères

- IX. Les menus

- X. Le recouvrement (overlay)

I - Introduction

GLUT est une bibliothèque relativement complète mais un grand nombre de ses utilisateurs n'en connaissent qu'une petite partie. Pour vous donner un aperçu des capacités de GLUT, voici un résumé de ses fonctionnalités :

- Fenêtrage multiple pour le rendu OpenGL

- Gestion des événements par procédure de rappel (callback)

- Traitement des périphériques de saisie

- Routine d'attente et timers

- Possibilité de créer des menus pop-up en cascade

- Outils de génération d'objets basiques en 3D

- Gestion de polices de caractères

- Gestion de fenêtrage de type overlay

Afin de les exploiter au mieux, nous allons les étudier en détail tout au long de cet article.

II - Déroulement d'un programme GLUT

Pour créer un programme basé sur GLUT, il faut initialiser et renseigner certains paramètres avant que le programme ne puisse fonctionner. Il y a des étapes obligatoires et d'autres facultatives.

Les étapes de création d'un programme GLUT

1. Initialisation de GLUT

2. Paramétrage de la fenêtre

3. Création de la fenêtre

4. Initialisation des procédures de rappel

5. Boucle principale de GLUT

Voyons en détails comment procéder à l'exécution de ces différentes étapes.

II-A - Initialisation de GLUT

L'utilisation de GLUT passe avant tout par l'initialisation de la bibliothèque. Initialiser GLUT se fait obligatoirement en appelant la fonction glutInit dont le prototype void glutInit(int *argcp, char **argv); nous indique que la fonction attend 2 paramètres :

1. un pointeur vers argc

2. le pointeur argv

Ces paramètres sont les mêmes que ceux du main à la différence près que le main reçoit un int argc et que glutInit attend un pointeur vers cet entier. Un main standard se déclare de la manière suivante :

Main standard

int main(int argc, char** argv)

Au cas où vous ne le sauriez pas, argc et argv définissent les paramètres de la ligne de commande d'appel du programme. argc contient le nombre de paramètres en comptant le nom du programme. argv contient les paramètres sous forme de chaines de caractères, dont le nom du programme en première position.

Utilisation de glutInit

// le programme principal
int main(int argc, char** argv)
{
// initialisation de glut
glutInit(&argc, argv);
}

Vous vous demandez certainement ce que va faire glutInit de ces paramètres ? La documentation de glutInit contient la liste des options utilisables dans la ligne de commande ainsi que leur effet.

II-B - Paramétrage de la fenêtre

Une fois l'initialisation de GLUT effectuée, il est possible d'initialiser la position et la taille de la fenêtre avant de la créer. La position est paramétrable en appelant glutInitWindowPosition et en lui passant en paramètres les coordonnées en X et en Y de la fenêtre.

Positionnement de la fenêtre

// position de la prochaine fenetre
glutInitWindowPosition(150, 100);

Dans cet exemple, nous demandons à GLUT de positionner la fenêtre à 150 pixels du bord et 100 pixel du haut.

La fonction glutInitWindowSize n'attend que les dimensions en largeur et en hauteur de la fenêtre que vous allez créer. Ainsi demander à GLUT une fenêtre de 640 pixels de large sur 480 pixels de haut se fera de la manière suivante :

Taille de la fenêtre

// dimensions de la prochaine fenetre
glutInitWindowSize(640, 480);

Appeler glutInitWindowPosition et glutInitWindowSize est facultatif. Par défaut, la taille d'une fenêtre GLUT est de 300 pixels de large et 300 pixels de haut. La position par défaut est, quand à elle, laissée à l'appréciation du système.

Avant de créer une fenêtre, il faut définir le format d'affichage de celle-ci. C'est le rôle attribué à la fonction glutInitDisplayMode qui prend en paramètre une combinaison de drapeaux définissant les propriétés du contexte OpenGL de la fenêtre qui sera créée. Cette fonction est importante car elle permet de demander un double buffer, un Z buffer ou encore un stencil buffer. Pour avoir un simple affichage il suffit d'appeler glutInitDisplayMode de la manière suivante :

Affichage simple en mode RGBA

// format d'affichage de la prochaine fenetre
glutInitDisplayMode(GLUT_RGBA);

Par défaut, l'affichage d'une fenêtre sera paramétré comme si l'appel précédent avait été fait. Si vous appelez glutInitDisplayMode de la manière suivante :

Affichage avec un double buffer en mode RGBA avec tampon de profondeur

// format d'affichage de la prochaine fenetre
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);

Toutes les fenêtres qui seront créées après cet appel auront un double buffer et un Z buffer. Jusqu'à ce que vous fassiez à nouveau appel à glutInitDisplayMode, ces paramètres perdureront.

Vous aurez remarqué que les paramètres utilisés dans l'appel de la fonction ne forment qu'un et qu'il s'agit d'une combinaison par un ou binaire de plusieurs options. En effet, comme je vous le disais précédemment, glutInitDisplayMode n'attend qu'un seul et unique paramètre issu d'une combinaison de drapeaux. Voici une liste des drapeaux utilisables et leur utilité :

- GLUT_RGBA est le mode de couleurs par défaut. Il spécifie un affichage en 24 bits "true-colors" (soit 16 millions de couleurs).

- GLUT_RGB est un synonyme de GLUT_RGBA.

- GLUT_INDEX permet d'avoir un affichage "palettisé" et donc limité à 256 couleurs. Je vous déconseille fortement son utilisation. GLUT_INDEX est prioritaire sur GLUT_RGBA si les deux sont utilisés.

- GLUT_SINGLE sert à demander un affichage avec un simple buffer. Le mode d'affichage par défaut est constitué d'un simple buffer.

- GLUT_DOUBLE sert à spécifier un affichage en double buffer. GLUT_DOUBLE est prioritaire à GLUT_SINGLE sir les deux sont utilisés simultanément.

- GLUT_ACCUM permet d'avoir des buffers d'accumulations à disposition.

- GLUT_ALPHA demande à ce qu'une couche alpha (transparence) fasse partie de l'affichage. Attention, la couche alpha ne sert pas à rendre la fenêtre transparente mais à conserver une information pour traiter des pixels transparents à l'affichage (un verre, un vitrail, de la fumée...).

- GLUT_DEPTH sert à obtenir un buffer de profondeur pour le tri des pixels selon leur éloignement.

- GLUT_STENCIL permet d'avoir un stencil buffer (pochoir). Parmis les possibilités offertes par le stencil buffer il y a les ombres volumétriques, le fondu entre 2 affichages, le calcul de complexité d'affichage...

- GLUT_MULTISAMPLE demande à ce que l'affichage bénéficie du multisampling. Le multisampling est une extension OpenGL permettant de lisser l'affichage afin de diminuer les effets d'escalier. Le résultat du multisampling est connu sous le terme antialiasing (anticrénelage en français).

- GLUT_STEREO sert à avoir un affichage dit en stéréo. La particularité d'un affichage en stéréo c'est l'obtention de 2 images issues d'un seul rendu. Les deux images étant chacune destinées à un oeil, l'affichage stéréo est essentiellement destiné à un affichage multi-écran tel que des lunettes spéciales.

- GLUT_LUMINANCE est une option permettant d'avoir un affichage en niveaux de gris.

Certaines de ces options (GLUT_STEREO entre autres) sont rarement supportées par les cartes vidéo grand public et nécessitent une carte vidéo spécifique voire professionnelle.

II-C - Création de la fenêtre

Nous avons vu comment initialiser GLUT et préparer la création de notre fenêtre d'affichage. Passons maintenant à l'étape suivante : la création de fenêtres d'affichage. La fonction glutCreateWindow sert à créer une fenêtre principale.

Création d'une fenêtre principale

// creation d'une fenetre
int nWindowID = glutCreateWindow("Ma première fenetre GLUT");

Nous venons donc de créer une fenêtre intitulée "Ma première fenêtre GLUT". Les propriétés de cette fenêtre sont définies par le dernier appel aux fonctions d'initialisation que nous avons vues dans le chapitre précédent, aussi bien sa taille et sa position que le mode d'affichage employé. Une valeur de retour est également conservée dans nWindowID, ce qui permet de sélectionner la fenêtre par la suite pour modifier certain paramètres dont les procédures de rappel utilisées par GLUT.

II-D - Initialiser les procédures

Vous pouvez créer plusieurs fenêtres au sein d'un même programme GLUT, chaque fenêtre possèdant ses propres procédures de rappel. Mais qu'est-ce qu'une procédure de rappel ? me demanderez-vous. Globalement, une procédure de rappel est une fonction qui suit un prototype prédéfini afin de pouvoir être appelée par un programme exploitant ce prototype. Vous pouvez consulter la définition wikipedia sur les fonctions de rappel si vous souhaitez plus de détails.

Une fenêtre GLUT possède plusieurs procédures de rappel décrites dans la documentation de GLUT. La seule procédure qui doit obligatoirement être renseignée lorsqu'une fenêtre est créée est la procédure d'affichage. En consultant la documentation de glutDisplayFunc, on apprend que le prototype de la procédure de rappel est sous la forme d'une fonction ne prenant aucun paramètre et n'en retournant aucun, comme par exemple :

Fonction d'affichage

// fonction d'affichage appelee par GLUT
void affichage(void)
{
}

Puisque nous voulons que cette fonction s'occupe de l'affichage, il faut l'indiquer à GLUT en lui envoyant l'adresse de cette fonction. Ce qui se fait tout simplement en appelant glutDisplayFunc avec, en paramètre, le nom de la fonction :

Fonction d'affichage

// parametrage de la fonction d'affichage (obligatoire)
glutDisplayFunc(affichage);

Il ne vous reste plus qu'à remplir cette fonction avec des commandes d'affichage OpenGL

II-E - Boucle principale de GLUT

Maintenant que nous avons initialisé GLUT, créé notre fenêtre et paramétré une fonction d'affichage, nous pouvons exécuter la boucle principale de GLUT. La boucle principale s'occupe du traitement des événements tels que le redimensionnement de la fenêtre GLUT, les clics et mouvements de souris, la gestion du clavier, etc... Elle s'occupe également d'appeler les procédures de rappel qui ont été renseignées telle que la fonction affichage que nous avons précédemment transmise. Pour lancer la boucle principale de GLUT, il suffit de faire appel à la fonction glutMainLoop de la manière la plus simple qui soit :

Fonction d'affichage

// boucle principale de GLUT
glutMainLoop();

On ne peux plus simple, n'est-ce pas ?

Dans un programme GLUT, il faut au moins un appel à glutMainLoop. Il faut également savoir que la fonction glutMainLoop ne retourne jamais. Si vous écrivez du code à la suite de l'appel à glutMainLoop, il ne sera donc jamais exécuté.

Pour clore cet aperçu d'un programme GLUT, et avant de rentrer dans les détails de la bibliothèque, je vous laisse admirer ce à quoi ressemble un programme GLUT minimal.

Programme GLUT minimum

#include <stdlib.h>
#include <GL/glut.h>

// fonction d'affichage appelee par GLUT
void affichage(void)
{
}

// le programme principal
int main(int argc, char *argv[])
{
// initialisation de GLUT
glutInit(&argc, argv);

// creation d'une fenetre
glutCreateWindow("Ma fenetre GLUT");

// parametrage de la fonction d'affichage (obligatoire)
glutDisplayFunc(affichage);

// boucle principale de GLUT
glutMainLoop();

// l'execution du programme n'arrivera jamais jusqu'ici
return EXIT_SUCCESS;
}

Ce programme est le strict minimum pour compiler, par contre il est inutilisable en l'état et nécessite certains ajustements que vous apprendrez dans la suite de cet article.

III - Le fenêtrage

IV - Les événements

V - Les procédures "Callback"

VI - Récupération des états

VII - Rendu d'objets géométriques

VIII - Les polices de caractères

IX - Les menus

X - Le recouvrement (overlay)