XVII. L'affichage de textes▲
Il y a deux façons d'afficher du texte :
- afficher un bitmap (c'est-à-dire une image) représentant chaque lettre du texte ;
- afficher chaque lettre du texte en 3D avec des vertices.
Si le texte est fixe, il est également possible de créer le texte sous forme d'une image (avec Paint par exemple), et d'appliquer une texture sur un rectangle blanc pour afficher ce texte.
Si on souhaite afficher un texte dynamique, il faut afficher chaque lettre du texte sur un rectangle.
On crée alors une texture contenant la table des caractères et on précise les coordonnées de texture correspondant au caractère à dessiner.
XVII-A. Affichage d'un texte bitmap statique▲
Voici l'image de texture utilisée :
C'est un simple texte rouge sur fond noir créé avec Paint.
Comme pour les autres textures, on la charge et on sauvegarde l'identifiant dans une variable :
' Identifiant de la texture du texte statique
Private
gTextureTexte As
Long
gTextureTexte =
TextureAddFromFile
(
CurrentProject.Path
&
"\texte.bmp"
)
Ensuite, à la fin de la procédure de rendu Render, on crée un rectangle et on lui applique la texture :
' Affichage d'un texte sur un rectangle
' Sauvegarde la matrice
glPushMatrix
' Affecte la texture
glBindTexture GL_TEXTURE_2D, gTextureTexte
' Filtrage de la texture
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
' Dessin d'un rectangle
glColor3VB vbWhite
glBegin GL_QUADS
glTexCoord2d 0
, 0
glVertex2d -
3
, -
0
.5
glTexCoord2d 1
, 0
glVertex2d -
1
, -
0
.5
glTexCoord2d 1
, 1
glVertex2d -
1
, 0
.5
glTexCoord2d 0
, 1
glVertex2d -
3
, 0
.5
glEnd
' N'affecte aucune texture
glBindTexture GL_TEXTURE_2D, 0
' Restaure la matrice
glPopMatrix
Ne pas oublier d'affecter une couleur blanche au rectangle (car on est en mode GL_MODULATE pour l'application des textures).
Le texte est alors affiché sur un rectangle qui est éclairé et qui tourne avec le reste de la scène :
On souhaite afficher un texte d'information qui est éclairé en permanence uniformément.
On va donc déjà désactiver la lumière avant l'affichage du texte,et la réactiver ensuite.
' Désactive la lumière
glDisable GL_LIGHTING
' Active la lumière
glEnable GL_LIGHTING
Ainsi le rectangle est éclairé par la lumière ambiante par défaut.
Si on souhaite rendre le fond noir transparent, il faut :
- charger la texture avec le noir transparent (deuxième paramètre) :
gTextureTexte = TextureAddFromFile(CurrentProject.Path & "\texte.bmp", vbBlack); - activer la gestion de la transparence avant rendu du texte (ou à l'initialisation de la scène si on laisse la transparence activée tout le temps) :
glEnable GL_BLEND
glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA.
' Affichage d'un texte sur un rectangle
' Désactive la lumière
glDisable GL_LIGHTING
' Sauvegarde la matrice
glPushMatrix
' Affecte la texture
glBindTexture GL_TEXTURE_2D, gTextureTexte
' Filtrage de la texture
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
' Active la transparence
glEnable GL_BLEND
glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
' Dessin d'un rectangle
glColor3VB vbWhite
glBegin GL_QUADS
glTexCoord2d 0
, 0
glVertex2d -
3
, -
0
.5
glTexCoord2d 1
, 0
glVertex2d -
1
, -
0
.5
glTexCoord2d 1
, 1
glVertex2d -
1
, 0
.5
glTexCoord2d 0
, 1
glVertex2d -
3
, 0
.5
glEnd
' N'affecte aucune texture
glBindTexture GL_TEXTURE_2D, 0
' Restaure la matrice
glPopMatrix
' Active la lumière
glEnable GL_LIGHTING
' Désactive la transparence
glDisable GL_BLEND
Le texte est maintenant affiché sur un fond transparent :
La méthode avec GL_BLEND est générique, car elle permet de gérer l'affichage translucide.
Pour un affichage totalement transparent, préférez l'utilisation de l'alpha-test (GL_ALPHA_TEST).
On souhaite maintenant afficher un texte d'information à un endroit précis de l'écran.
C'est-à-dire qu'on souhaite que le texte s'affiche par exemple en bas à gauche, et ne se déplace pas lorsqu'on tourne ou redimensionne la scène.
Pour y arriver, on va passer en mode de projection orthonormée le temps de dessiner le texte.
On met en place une projection orthonormée (glOrtho) dont le plan est défini par les coordonnées (-1,-1) et (1,1).
Puis on se place (gluLookAt) au centre un peu en retrait.
On peut alors définir notre rectangle en fonction du plan de projection, (-1,-1) étant le point en bas à gauche :
' Affichage d'un texte statique sur un rectangle
' Passage en matrice de projection
glMatrixMode GL_PROJECTION
' Projection orthonormée
glLoadIdentity
glOrtho -
1
, 1
, -
1
, 1
, 0
, 0
' Retour en matrice de visualisation-modélisation
glMatrixMode GL_MODELVIEW
glLoadIdentity
gluLookAt 0
, 0
, 1
, 0
, 0
, 0
, 0
, 1
, 0
' Désactive la lumière
glDisable GL_LIGHTING
' Sauvegarde la matrice
glPushMatrix
' Affecte la texture
glBindTexture GL_TEXTURE_2D, gTextureTexte
' Filtrage de la texture
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR
glTexParameterf GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR
' Active la transparence
glEnable GL_BLEND
glBlendFunc GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA
' Dessin d'un rectangle en bas à gauche
glColor3VB vbWhite
glBegin GL_QUADS
glTexCoord2d 0
, 0
glVertex2d -
1
, -
1
glTexCoord2d 1
, 0
glVertex2d -
0
.4
, -
1
glTexCoord2d 1
, 1
glVertex2d -
0
.4
, -
0
.8
glTexCoord2d 0
, 1
glVertex2d -
1
, -
0
.8
glEnd
' N'affecte aucune texture
glBindTexture GL_TEXTURE_2D, 0
' Restaure la matrice
glPopMatrix
' Active la lumière
glEnable GL_LIGHTING
' Désactive la transparence
glDisable GL_BLEND
Le texte est dessiné en bas à gauche, et y reste même si on tourne autour de la scène :
Voici donc une méthode assez simple pour afficher un texte statique, qui peut également être utilisée pour afficher un logo par exemple.
XVII-B. Affichage d'un texte bitmap dynamique avec freeGLUT▲
Pour la suite, nous souhaitons afficher le frame rate non plus dans la barre de titre de la fenêtre, mais sur l'image en haut à gauche.
freeGLUT met à notre disposition une fonction très facile à utiliser : glutBitmapString.
Pour positionner le texte, il faut utiliser une fonction glRasterPos* (car la fonction de dessin de texte de freeGLUT utilise la fonction glBitmap).
On conserve notre projection orthonormée : donc pour placer le texte en haut à gauche il faut le placer :
- en X à -1 ;
- en Y à 1 - (la hauteur du texte).
La hauteur du texte peut être récupérée en pixels avec la fonction glutBitmapHeight.
La hauteur de la fenêtre peut être récupérée en pixels avec la fonction glutGet(GLUT_WINDOW_HEIGHT).
Une division nous donnera la taille du texte dans l'unité openGL.
D'après la définition du plan de la projection :
- le bas de la fenêtre est à une ordonnée de -1 ;
- le haut de la fenêtre est à une ordonnée de 1.
Donc on a 1 unité pour une demi-hauteur d'une fenêtre :
glutBitmapHeight(GLUT_BITMAP_TIMES_ROMAN_24) / (glutGet(GLUT_WINDOW_HEIGHT) / 2) est la taille du texte en unités OpenGL
Commençons par retirer le frame rate de la barre de titre.
Après calcul, on le sauvegarde dans une variable.
' Frame rate
Private
gFrameRate As
Double
' Calcul et affichage du frame rate
gDisplayCount =
gDisplayCount +
1
If
gDisplayCount =
100
Then
gFrameRate =
gDisplayCount /
(
glutGet
(
GLUT_ELAPSED_TIME) -
gElapsedTime) *
1000
gDisplayCount =
0
gElapsedTime =
glutGet
(
GLUT_ELAPSED_TIME)
End
If
Et on affiche ce frame rate en haut à gauche, en couleur bleue :
(Ajoutez ce code dans la procédure render.)
' Affichage du frame rate
glColor3VB vbBlue
glRasterPos2d -
1
, 1
-
glutBitmapHeight
(
GLUT_BITMAP_TIMES_ROMAN_24) /
(
glutGet
(
GLUT_WINDOW_HEIGHT) /
2
)
glutBitmapString GLUT_BITMAP_TIMES_ROMAN_24, "Frame rate : "
&
format
(
gFrameRate, "0,0"
)
Au lieu de GLUT_BITMAP_TIMES_ROMAN_24, on peut choisir :
GLUT_BITMAP_9_BY_15, GLUT_BITMAP_8_BY_13 , GLUT_BITMAP_TIMES_ROMAN_10, GLUT_BITMAP_TIMES_ROMAN_24, GLUT_BITMAP_HELVETICA_10, GLUT_BITMAP_HELVETICA_12 ou GLUT_BITMAP_HELVETICA_18.
Pour positionner le texte, on peut également utiliser glutBitmapLength pour obtenir la largeur du texte.
Voici le frame rate affiché sur l'image :
freeGLUT nous offre donc une fonction très simple pour afficher du texte.
XVII-C. Affichage d'un texte bitmap dynamique avec Windows▲
Sous Windows, nous avons à notre disposition la fonction wglUseFontBitmaps.
Cette fonction permet de générer des listes d'affichage contenant les caractères d'une police.
Il faut d'abord créer une police de caractères avec gdi32.
Ensuite l'appel à wglUseFontBitmaps génère les listes d'affichage.
Et enfin on affiche le texte en appelant ces listes avec glCallLists.
Importez le module standard ModOpenGLFontTools
Ce module contient deux fonctions VB de gestion des textes :
- une fonction CreateFontBitmap qui crée les listes ;
- une fonction DrawText qui affiche le texte.
La création d'une police de caractères se fait avec la fonction gdi32 CreateFont.
Il nous suffit maintenant :
- d'ajouter en en-tête du module principal la déclaration de l'identifiant de liste d'affichage :
' Identifiant de la liste pour le texte
Private
gListTexte As
Long
- de créer les listes d'affichage dans la procédure d'initialisation InitScene :
' Création des listes pour le texte
gListTexte =
CreateFontBitmap
(
"Arial"
)
- et enfin d'appeler la fonction DrawText (au lieu de glutBitmapString) pour afficher le texte :
' Affichage du frame rate
glColor3VB vbBlue
glRasterPos2d -
1
, 1
-
20
/
(
glutGet
(
GLUT_WINDOW_HEIGHT) /
2
)
DrawText "Frame rate : "
&
format
(
gFrameRate, "0,0"
), gListTexte
Nous n'avons pas ici de fonction simple à notre disposition pour retrouver la taille du texte.
J'ai mis 20 empiriquement.
XVII-D. Affichage d'un texte 3D dynamique avec Windows▲
Sous Windows, nous avons à notre disposition la fonction wglUseFontOutlines.
Cette fonction permet de générer des listes d'affichage contenant les caractères d'une police sous forme 3D.
C'est-à-dire avec des vertices et même une épaisseur.
Il faut d'abord, comme pour la fonction précédente, créer une police de caractères avec gdi32.
Ensuite l'appel à wglUseFontOutlines génère les listes d'affichage.
Et enfin on affiche le texte en appelant ces listes avec glCallLists.
Importez le module standard ModOpenGLFontTools
Ce module contient une fonction VB de gestion des textes 3D, la fonction CreateFontOutline qui crée les listes.
Il nous suffit maintenant :
- de remplacer l'appel à CreateFontBitmap par un appel à CreateFontOutline :
' Création des listes pour le texte
' On extrude de 0.3 pour donner de la profondeur au texte
gListTexte =
CreateFontOutline
(
"Arial"
, 0
.3
)
- et de modifier le positionnement du texte.
On utilise pour les textes 3D les fonctions de transformation de la matrice de modélisation-visualisation :
' Affichage du frame rate
glColor3VB vbYellow
glPushMatrix
glTranslated -
1
, 1
-
20
/
(
glutGet
(
GLUT_WINDOW_HEIGHT) /
2
), 0
glScaled 0
.2
, 0
.2
, 0
.2
DrawText "Frame rate : "
&
format
(
gFrameRate, "0,0"
), gListTexte
glPopMatrix
On ne voit pas beaucoup de changement, le texte semble toujours en 2D.
C'est normal, car on dessine le texte avec une projection orthonormée.
Pour voir le texte en 3D, il faut l'afficher avant le passage dans cette projection.
' Affichage du frame rate en 3D
glColor3VB vbYellow
glPushMatrix
glTranslated -
3
, 2
, 2
DrawText "Frame rate : "
&
format
(
gFrameRate, "0,0"
), gListTexte
glPopMatrix
Le texte s'affiche alors en 3D, et suit les transformations de la scène :
XVII-E. Affichage d'un texte bitmap dynamique : méthode générique▲
Les techniques que nous venons de voir nécessitent freeGLUT ou Windows.
Comment faire pour dessiner du texte de manière plus générique ?
Il faut générer « à la main » les listes d'affichage.
Pour nous aider, on peut utiliser des outils de création de textures à partir de polices de caractères.
Par exemple : Bitmap Font Builder permet de générer une image contenant une table de caractères.
On obtient une image de ce type :
Et en parallèle on peut extraire la taille de chaque caractère dans un fichier texte.
Il faut ensuite générer une liste par caractère.
Chaque liste est un quad contenant quatre vertices et les quatre coordonnées de la texture qui correspondent au caractère.
La taille du quad et les coordonnées de texture sont fonction de la position du caractère dans la table et de la largeur de ce caractère.
L'idée est de se créer un module réutilisable de gestion des textures pour faire toutes ces opérations.
Si vous avez bien suivi jusqu'ici, vous devriez être capable de programmer un tel module.