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, puis 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
static
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 pixel avec la fonction glutBitmapHeight.
La hauteur de la fenêtre peut être récupérée en pixel 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ées 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é 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, qu'il faut déclarer.
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 tranformation 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 freeglu 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 4 vertices et les 4 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.