Sommaire Index Rechercher Liens A Propos
[LinuxFocus Image]
[Navegation Bar]
Nouvelles Archives

Programmation avec GLUT : la Gestion des Fenêtres

par Miguel Angel Sepúlveda


Introduction

Gestion des fenêtres

Utilisation de sous-fenêtres

Le Clavier

Afficher du Texte

Conclusion

Introduction

Cet article continue notre série sur GLUT (GL Utility Toolkit), la librairie-boite à outils- pour OpenGL écrite par Mark Kilgard. Comme nous l'avons dit dans notre précédent article (Fenêtres et Animations) GLUT est une librairie très intéressante et très utile pour tous les développeurs OpenGL car elle permet d'écrire du code portable. GLUT cache au développeur tous les détails embêtant du gestionnaire de fenêtres et de l'interface graphique .

GLUT est divisé en plusieurs ensembles de fonctions. Dans cet article nous détaillerons l'ensemble de gestion de fenêtres (et de sous-fenêtres). Comme son nom l'indique, elle prend en charge les tâches liées aux fenêtres utilisées par votre application OpenGL : créer, détruire, iconifier une fenêtre ; mise en avant/arrière plan, cacher, déplacer ; fixer les titres, la position, etc...

Le sous-ensemble de Gestion de Fenêtre ( Windows Management Sub-Api)

Voici une liste exhaustive des fonctions supportées par la gestion de fenêtre de GLUT (pour ce qui est de la version 3.6) :

int glutCreateWindow(char *name) Crée une nouvelle fenêtre principale
int glutCreateSubWindow(int win,
   int x, int y, int width, int height)
Crée une sous-fenêtre
void glutSetWindow(int winId) Fait de la fenêtre ayant l'identificacteur winId la fenêtre courante
int glutGetWindow(void) Demande l'identificateur de la fenêtre courante
void glutDestroyWindow(int winId) Détruit la fenêtre identifiée par winID
void glutPostRedisplay(void) Informe le gestionnaire d'évènements de GLUT que la fenêtre courante doit être réaffichée
void glutSwapBuffers(void) Effectue le changement de buffer.
void glutPositionWindow(int x, int y) Demande le changement de position de la fenêtre
void glutReshapeWindow(int width, int height) Demande le changement de dimension de la fenêtre
void glutFullScreen() Demande la mise en pleine écran
void glutPopWindow(void)
void glutPushWindow(void)
met à l'avant plan ou à l'arrière plan la fenêtre active
void glutShowWindow(void)
void glutHideWindow(void)
void glutIconifyWindow(void)
Montre, cache, iconifie la fenêtre courante
void glutSetWindowTitle(char *name)
void glutSetIconTitle(char *name)
Fixe le titre de la fenêtre

Utilisation des sous-fenêtres

L'utilisation de la plupart des fonctions ci-dessus est très simple. Certaines furent détaillées dans notre précédent article : glutPosRedisaply, glutCreateWindow, glutPositionWindow, glutSwapBuffers,... etc. Les nouvelles sont très simples à utiliser et la description précédente dit l'essentiel de ce qu'elles font, par exemple : glutSetIconTitle, glutFullScreen,... etc. Cependant l'utilisation n'en n'est pas si simple, c'est pourquoi nous avons décidé de vous donner un exemple simple et de commenter les détails de son implémentation.

Voici le code source d'une petite démo OpenGL-GLUT (../../common/March1998/example1.c, ../../common/March1998/Makefile). Son but est de vous montrer : (a) comment gérer les sous-fenêtres, (b) comment utiliser le clavier pour interagir avec votre application OpenGL,(c) comment afficher du texte dans une fenêtre OpenGL.

(s'il vous plaît, imprimez ou ayez le code source de ../../common/March1998/example1.c sous la main pendant que nous poursuivons l'explication.)

[Snapshot of example1 running]

D'abord regardons la fonction main(). Cette application commence comme toutes les applications GLUT par la phase d'initialisation : parcours des arguments de la ligne de commande, choix du mode d'affichage, enfin placement et dimensionnement de la fenêtre initiale. Comme notre application va manipuler plus d'une fenêtre il est nécessaire de stocker l'entier d'identification de fenêtre retourné par la fonction glutCreateWindow. La variable winIdMain est une référence à cette fenêtre. Il nous faut maintenant fixer les fonctions appelées en réponse à des événements associés à la fenêtre winIdMain (appelées fonctions callback) ; Plusieurs fonctions callback sont définies et agissent toutes sur la fenêtre principale : une fonction pour l'affichage (mainDisplay) qui dessine la scène, une fonction de retaillage (mainReshape) qui gère toute transformation du cadre de la fenêtre principale - par exemple un redimensionnement, keyboard qui gère les actions venant du clavier, et idle qui est appelé quant il n'y a aucun autre événement à traiter et dont on se sert pour la gestion des animations (cf. Fenêtres et animations pour une description plus détaillée du rôle de idle) ;

La première chose importante à savoir est que dans GLUT, il ne peut y avoir qu'une seule fonction callback idle. La fonction idle est globale et commune à toutes les fenêtres de l'application. Aussi prenez cela en compte lorsque vous concevez votre fonction idle, elle doit effectuer le rafraîchissement de toutes les fenêtres et sous-fenêtres de votre application.

Ensuite dans le code viens la création de la sous-fenêtre (winIDSub). Pour créer une sous-fenêtre, vous devez fournir l'ID de la fenêtre de plus haut niveau , ici winIDMain, les coordonnées x et y de la sous-fenêtre par rapport à la fenêtre parente, et la hauteur et la largeur désirée pour cette sous-fenêtre. Après la création de la sous-fenêtre GLUT retourne une référence sur cette fenêtre à notre programme, nous pouvons maintenant fixer les fonctions callback de winIDSub. Dans notre exemple nous définissons deux fonctions callback : une pour l'affichage (subDisplay) et une pour les modifications sur le cadre (subReshape).

Quand GLUT ouvre une sous-fenêtre il lui fournit un environnement OpenGL complet. Il y a donc une baisse des performances induite par l'utilisation de sous-fenêtres car le driver de la carte vidéo doit rafraîchir la zone mémoire pour chaque fenêtre en plusieurs passes. Grâce à des environnements OpenGL indépendant, chaque fenêtre peut avoir son propre système de coordonnées par exemple. Dans ../../common/March1998/example1.c le système de coordonnées est défini dans mainDisplay() et subDisplay() respectivement. Regardez ces deux fonctions, elles sont assez simples et si vous avez suivis notre article de janvier sur OpenGL (" rendu de polygones " ) vous n'aurez pas de mal à les comprendre.

La fonction mainDisaplay() dessine un triangle avec des arêtes Rouges, Bleues et Vertes. OpenGL calcul par interpolation la couleur de chaque point de la surface. Avant de dessiner le triangle nous avons ajouté un ordre glRotate, qui fait tourner le triangle autour de l'axe Z (perpendiculaire à l'écran), l'angle de rotation (spin) est incrémenté doucement dans la fonction idle pour donner l'illusion de rotation.

La fonction d'affichage associée à winIDSub est elle aussi très simple. Tout d'abord elle remplit le fond en gris, ensuite elle dessine un contour vert sur le cadre de la sous-fenêtre, enfin elle inscrit du texte. Plus tard nous expliqueront comment se fait le dessin de texte sous GLUT. Pour le moment notez juste que glRastePos2f(x,y) fixe la position à laquelle le texte sera affiché et que les coordonnées x,y sont données relativement au système de coordonnées de la sous-fenêtre (défini dans subReshape() ).

La sous-fenêtre agit comme une zone de texte pour les données venant de l'animation. Cette une application un peu bête, nous aurions pu afficher la zone de texte sur la fenêtre principale et obtenir le même résultat (en plus performant). Dans certaines circonstances cependant il est préférable d'ouvrir une sous-fenêtre pour la zone de texte. Par exemple lorsque l'animation est en 3D avec des jeux de lumières et des effets atmosphériques, et que vous ne voulez pas voir votre zone de texte déformée par la perspective, l'éclairage, les ombres, le brouillard etc. Dans ce cas une sous-fenêtre est un bon choix car complètement isolé de l'animation 3D.

Il y a une différence cruciale entre une fonction de retaillage pour une fenêtre principale et pour une sous-fenêtre. Quand un événement de retaillage est intercepté, seul la fonction callback de retaillage de la fenêtre principale est appelée, dans notre exemple mainReshape(). Nous devons appeler les fonctions subReshape() dans le code de la fonction mainReshape(). Cela est normal car la taille et la position des sous-fenêtres ne sont connues que relativement à celles de la fenêtre principale. C'est pourquoi si vous regardez maintenant le code de notre fonction mainReshape() vous verrez que tout d'abord nous fixons la matrice de projection pour la fenêtre principale, et qu'ensuite nous basculons sur la fenêtre winIDSub et appelons la fonction subReshape() avec les paramètres de largeur et de hauteur déduits de ceux de winIDMain.

Il a été mentionné plus haut que la fonction callback idle() devait mettre à jour la fenêtre principale et toutes les sous-fenêtres d 'une application OpenGL. Dans notre exemple idle() met d'abord à jour les variables de l'animation (time et spin) et ensuite demande à la fenêtre principale et à la sous-fenêtre de se redessiner.

Le Clavier

J'ai ajouté deux touches actives au programme. En appuyant sur la touche « i » vous pouvez activer ou désactiver la zone d'information et avec la touche « q » vous quittez l'application ; Essayez-les :)

A chaque fois que vous tapez sur une touche du clavier, GLUT génère un événement clavier. Ces événements sont gérés par des fonctions callback. En principe chaque fenêtre à ses propres fonctions callback. Quand la souris est à la position (x,y) dans une fenêtre (ou sous-fenêtre) et qu'un événement clavier est lancé, c'est la fonction callback associée à cette fenêtre qui est appelée. Cette fonction prend comme argument le code ASCII (codé sur un unsigned char) associé à cette touche, ainsi que les coordonnées x et y du curseur à ce moment. Dans ../../common/March1998/example2.c il n'y a pas d'utilisation de x et y, mais je suis sûr que vous pouvez imaginer des applications tirant partie de cette possibilité.

Dans notre exemple, seule la fenêtre de plus haut niveau possède une fonction callback. Si vous essayez de presser les touches « i » et « q » alors que le curseur est sur la sous-fenêtre, vous remarquerez que rien ne se passe. Par défaut lorsqu'aucune fonction callback n'a été définie toutes les touches sont ignorées. Gardez cela en tête si plus tard vous utilisez plusieurs fenêtres et désirez avoir une bonne gestion du clavier.

J'ajouterai enfin, que l'appel aux fonctions callback de traitement des évènements claviers peuvent être désactivé en passant NULL à la fonction glutKeyBoardFunc().

Afficher du Texte

Afficher du texte sous OpenGL et GLUT est une vraie merde !. Désolé de dire cela, mais c'est vrai. Je ne sais pas exactement pourquoi les fonctions de gestion du texte ont été autant négligées dans la librairie OpenGL. La vieille librairie GL de Silicon Graphics avait quelques fonctions de haut niveau pour traiter le texte en mode graphique et il y avait une librairie auxiliaire pour changer de fonte. OpenGL ne propose que quelques primitives pour afficher des images 2D, ce qui veut dire que vous devez créer votre propre librairie à base d'image 2D pour chaque caractère, tenir compte du redimensionnement des espaces...vous voyez ce que je veux dire.

GLUT résout partiellement le problème du texte sous OpenGL. Il propose une fonction glutBitmapCharacter qui affiche un seul caractère à l'écran à la position spécifié par glRastePos. J'ai ajouté un couple de fonctions, drawString() et drawStringBig() qui vous rendrons la vie un peu plus facile pour afficher des chaînes.

Conclusion

Ceci conclut notre introduction simple à l'utilisation des sous-fenêtres avec GLUT. Je dois ajouter qu'il est bon de les expérimenter et de les tester sous plusieurs environnements, car malheureusement les sous-fenêtres de GLUT ne sont pas complètement opérationnelles sous tous les environnements. Les utilisateurs de cartes 3Dfx s'apercevrons que les sous-fenêtres ne sont pas opérationnelles à cause de limitations matérielles. J'ai également rencontré de forte baisse de performance lors de l'utilisation de sous-fenêtres sur certaines plates-formes. Par exemple sur mon Linux pour Alpha avec une matrox millenium de 2Mo l'utilisation de sous-fenêtres diminue par deux les performances, probablement parce que le serveur X pour Alpha ne supporte aucune accélération matérielle. D'un autre coté, la même application sous windows 95, avec une ATI RageII 2Mo et les drivers OpenGL de SGI tourne parfaitement.

Comme les développements sous Linux avancent trés vite, il est possible que dans un futur proche la plupart de ces problèmes de performances et d'incompatibilités n'existeront plus. Pour l'instant gardez à l'esprit que cela existe et qu'il vaut mieux utiliser les sous-fenêtres avec précaution.

Bien sûr les utilisateurs expérimentés pourrons toujours contourner l'utilisation de sous-fenêtres en jouant avec la pile des matrices, mais comme nous n'avons pas étudié cela encore, vous m'excuserez de le garder pour plus tard... ;) )


Traduit par Mathieu Veron

Pour en savoir plus:
© 1998 Miguel Angel Sepulveda
Ce site web est maintenu par Miguel A Sepulveda.