Maintenant que
SDL_ttf est chargée et qu'on a une variable
police chargée elle aussi, plus rien ni personne ne nous empêchera d'écrire du texte dans notre fenêtre SDL !
Bien : écrire du texte c'est bien, mais avec quelle fonction ? D'après la doc', pas moins de 12 fonctions sont disponibles !
En fait, il y a trois façons différentes pour
SDL_ttf de dessiner du texte.
- Solid (fig. suivante) : c'est la technique la plus rapide. Le texte sera rapidement écrit dans une SDL_Surface. La surface sera transparente mais n'utilisera qu'un niveau de transparence (on a appris ça il y a quelques chapitres). C'est pratique, mais le texte ne sera pas très joli, pas très « arrondi », surtout s'il est écrit gros. Utilisez cette technique lorsque vous devez souvent changer le texte, par exemple pour afficher le temps qui s'écoule ou le nombre de FPS d'un jeu.
- Shaded (fig. suivante) : cette fois, le texte sera joli. Les lettres seront antialiasées (cela signifie que leurs contours seront adoucis, ce qui est plus agréable à l'œil) et le texte apparaîtra plus lisse. Il y a un défaut, en revanche : le fond doit être d'une couleur unie. Il est impossible de rendre le fond de la SDL_Surface transparente en Shaded.
- Blended (fig. suivante) : c'est la technique la plus puissante, mais elle est lente. En fait, elle met autant de temps que Shaded à créer la SDL_Surface. La seule différence avec Shaded, c'est que vous pouvez blitter le texte sur une image et la transparence sera respectée (contrairement à Shaded qui imposait un fond uni). Attention : le calcul du blit sera plus lent que pour Shaded.



En résumé :
- si vous avez un texte qui change souvent, comme un compte à rebours, utilisez Solid ;
- si votre texte ne change pas très souvent et que vous voulez blitter votre texte sur un fond uni, utilisez Shaded ;
- si votre texte ne change pas très souvent mais que vous voulez blitter sur un fond non uni (comme une image), utilisez Blended.
Voilà, vous devriez déjà être un peu plus familiers avec ces trois types d'écriture de
SDL_ttf.
Je vous avais dit qu'il y avait 12 fonctions en tout.
En effet, pour chacun de ces trois types d'écriture, il y a quatre fonctions. Chaque fonction écrit le texte à l'aide d'un
charset différent, c'est-à-dire d'une palette de caractères différente. Ces quatre fonctions sont :
- Latin1 ;
- UTF8 ;
- Unicode ;
- Unicode Glyph.
L'idéal est d'utiliser l'Unicode car c'est un charset gérant la quasi-totalité des caractères existant sur Terre. Toutefois, utiliser l'Unicode n'est pas toujours forcément simple (un caractère prend plus que la taille d'un
char en mémoire), nous ne verrons donc pas comment l'utiliser ici.
A priori, si votre programme est écrit en français le mode Latin1 suffit amplement, vous pouvez vous contenter de celui-là.
Les trois fonctions utilisant le charset Latin1 sont :
- TTF_RenderText_Solid ;
- TTF_RenderText_Shaded ;
- TTF_RenderText_Blended.
Exemple d'écriture de texte en Blended
Pour spécifier une couleur à
SDL_ttf, on ne va pas utiliser le même type qu'avec la SDL (un
Uint32 créé à l'aide de la fonction
SDL_MapRGB).
Au contraire, nous allons utiliser une structure toute prête de la SDL :
SDL_Color. Cette structure comporte trois sous-variables : la quantité de rouge, de vert et de bleu.
Si vous voulez créer une variable
couleurNoire, vous devrez donc écrire :
Code : C | SDL_Color couleurNoire = {0, 0, 0};
|
Attention à ne pas confondre avec les couleurs qu'utilise habituellement la SDL !
La SDL utilise des Uint32 créés à l'aide de SDL_MapRGB.
SDL_ttf utilise des SDL_Color.
On va écrire un texte en noir dans une SDL_Surface
texte :
Code : C | texte = TTF_RenderText_Blended(police, "Salut les Zér0s !", couleurNoire);
|
Vous voyez dans l'ordre les paramètres à envoyer : la police (de type
TTF_Font), le texte à écrire, et enfin la couleur (de type
SDL_Color).
Le résultat est stocké dans une
SDL_Surface.
SDL_ttf calcule automatiquement la taille nécessaire à donner à la surface en fonction de la taille du texte et du nombre de caractères que vous avez voulu écrire.
Comme toute
SDL_Surface, notre pointeur
texte contient les sous-variables
w et
h indiquant respectivement sa largeur et sa hauteur. C'est donc un bon moyen de connaître les dimensions du texte une fois que celui-ci a été écrit dans la
SDL_Surface. Vous n'aurez qu'à écrire :
Code : C | texte->w /* Donne la largeur */
texte->h /* Donne la hauteur */
|
Code complet d'écriture de texte
Vous savez désormais tout ce qu'il faut connaître sur
SDL_ttf. Voyons pour résumer un code complet d'écriture de texte en mode Blended :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58 | #include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <SDL/SDL_ttf.h>
int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *texte = NULL, *fond = NULL;
SDL_Rect position;
SDL_Event event;
TTF_Font *police = NULL;
SDL_Color couleurNoire = {0, 0, 0};
int continuer = 1;
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("Gestion du texte avec SDL_ttf", NULL);
fond = IMG_Load("moraira.jpg");
/* Chargement de la police */
police = TTF_OpenFont("angelina.ttf", 65);
/* Écriture du texte dans la SDL_Surface texte en mode Blended (optimal) */
texte = TTF_RenderText_Blended(police, "Salut les Zér0s !", couleurNoire);
while (continuer)
{
SDL_WaitEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
position.x = 0;
position.y = 0;
SDL_BlitSurface(fond, NULL, ecran, &position); /* Blit du fond */
position.x = 60;
position.y = 370;
SDL_BlitSurface(texte, NULL, ecran, &position); /* Blit du texte */
SDL_Flip(ecran);
}
TTF_CloseFont(police);
TTF_Quit();
SDL_FreeSurface(texte);
SDL_Quit();
return EXIT_SUCCESS;
}
|
Le résultat vous est présenté sur la fig. suivante.
Si vous voulez changer de mode d'écriture pour tester, il n'y a qu'une ligne à modifier : celle créant la surface (avec l'appel à la fonction
TTF_RenderText_Blended).
La fonction TTF_RenderText_Shaded prend un quatrième paramètre, contrairement aux deux autres. Ce dernier paramètre est la couleur de fond à utiliser. Vous devrez donc créer une autre variable de type SDL_Color pour indiquer une couleur de fond (par exemple le blanc).
Attributs d'écriture du texte
Il est aussi possible de spécifier des attributs d'écriture, comme gras, italique et souligné.
Il faut d'abord que la police soit chargée. Vous devriez donc avoir une variable
police valide. Vous pouvez alors faire appel à la fonction
TTF_SetFontStyle qui va modifier la police pour qu'elle soit en gras, italique ou souligné selon vos désirs.
La fonction prend deux paramètres :
- la police à modifier ;
- une combinaison de flags pour indiquer le style à donner : gras, italique ou souligné.
Pour les flags, vous devez utiliser ces constantes :
- TTF_STYLE_NORMAL : normal ;
- TTF_STYLE_BOLD : gras ;
- TTF_STYLE_ITALIC : italique ;
- TTF_STYLE_UNDERLINE : souligné.
Comme c'est une liste de flags, vous pouvez les combiner à l'aide du symbole
| comme on a appris à le faire.
Testons :
Code : C | /* Chargement de la police */
police = TTF_OpenFont("angelina.ttf", 65);
/* Le texte sera écrit en italique et souligné */
TTF_SetFontStyle(police, TTF_STYLE_ITALIC | TTF_STYLE_UNDERLINE);
/* Écriture du texte en italique et souligné */
texte = TTF_RenderText_Blended(police, "Salut les Zér0s !", couleurNoire);
|
Résultat, le texte est écrit en italique et souligné (fig. suivante).
Pour restaurer une police à son état normal, il suffit de refaire appel à la fonction
TTF_SetFontStyle en utilisant cette fois le flag
TTF_STYLE_NORMAL.
Exercice : le compteur
Cet exercice va cumuler ce que vous avez appris dans ce chapitre et dans le chapitre sur la gestion du temps. Votre mission, si vous l'acceptez, consistera à créer un compteur qui s'incrémentera tous les dixièmes de seconde.
Ce compteur va donc progressivement afficher : 0,
100,
200,
300,
400,
etc. Au bout d'une seconde le nombre 1000 devrait donc s'afficher.
Astuce pour écrire dans une chaîne
Pour réaliser cet exercice, vous aurez besoin de savoir comment écrire dans une chaîne de caractères en mémoire.
En effet, vous devez donner un
char* à
TTF_RenderText mais vous, ce que vous aurez, c'est un nombre (un
int par exemple). Comment convertir un nombre en chaîne de caractères ?
On peut utiliser pour cela la fonction
sprintf.
Elle marche de la même manière que
fprintf, sauf qu'au lieu d'écrire dans un fichier elle écrit dans une chaîne (le « s » de
sprintf signifie « string », c'est-à-dire « chaîne » en anglais).
Le premier paramètre que vous lui donnerez sera donc un pointeur sur un tableau de
char.
Veillez à réserver suffisamment d'espace pour le tableau de char si vous ne voulez pas déborder en mémoire !
Exemple :
Code : C | sprintf(temps, "Temps : %d", compteur);
|
Ici,
temps est un tableau de
char (20 caractères), et
compteur est un
int qui contient le temps.
Après cette instruction, la chaîne
temps contiendra par exemple
"Temps : 500".
À vous de jouer !
Correction
Voici une correction possible de l'exercice :
Code : C 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62 | int main(int argc, char *argv[])
{
SDL_Surface *ecran = NULL, *texte = NULL;
SDL_Rect position;
SDL_Event event;
TTF_Font *police = NULL;
SDL_Color couleurNoire = {0, 0, 0}, couleurBlanche = {255, 255, 255};
int continuer = 1;
int tempsActuel = 0, tempsPrecedent = 0, compteur = 0;
char temps[20] = ""; /* Tableau de char suffisamment grand */
SDL_Init(SDL_INIT_VIDEO);
TTF_Init();
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
SDL_WM_SetCaption("Gestion du texte avec SDL_ttf", NULL);
/* Chargement de la police */
police = TTF_OpenFont("angelina.ttf", 65);
/* Initialisation du temps et du texte */
tempsActuel = SDL_GetTicks();
sprintf(temps, "Temps : %d", compteur);
texte = TTF_RenderText_Shaded(police, temps, couleurNoire, couleurBlanche);
while (continuer)
{
SDL_PollEvent(&event);
switch(event.type)
{
case SDL_QUIT:
continuer = 0;
break;
}
SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
tempsActuel = SDL_GetTicks();
if (tempsActuel - tempsPrecedent >= 100) /* Si 100 ms au moins se sont écoulées */
{
compteur += 100; /* On rajoute 100 ms au compteur */
sprintf(temps, "Temps : %d", compteur); /* On écrit dans la chaîne "temps" le nouveau temps */
SDL_FreeSurface(texte); /* On supprime la surface précédente */
texte = TTF_RenderText_Shaded(police, temps, couleurNoire, couleurBlanche); /* On écrit la chaîne temps dans la SDL_Surface */
tempsPrecedent = tempsActuel; /* On met à jour le tempsPrecedent */
}
position.x = 180;
position.y = 210;
SDL_BlitSurface(texte, NULL, ecran, &position); /* Blit du texte */
SDL_Flip(ecran);
}
TTF_CloseFont(police);
TTF_Quit();
SDL_FreeSurface(texte);
SDL_Quit();
return EXIT_SUCCESS;
}
|
La fig. suivante vous présente le résultat au bout de 13,9 secondes très exactement.
N'hésitez pas à télécharger ce projet si vous souhaitez l'étudier en détail et l'améliorer. Il n'est pas encore parfait : on pourrait par exemple utiliser
SDL_Delay pour éviter d'utiliser 100 % du CPU.
Pour aller plus loin
Si vous voulez améliorer ce petit bout de programme, vous pouvez essayer d'en faire un jeu où il faut cliquer le plus de fois possible dans la fenêtre avec la souris dans un temps imparti. Un compteur s'incrémentera à chaque clic de la souris.
Un compte à rebours doit s'afficher. Lorsqu'il atteint 0, on récapitule le nombre de clics effectués et on demande si on veut faire une nouvelle partie.
Vous pouvez aussi gérer les meilleurs scores en les enregistrant dans un fichier. Cela vous fera travailler à nouveau la gestion des fichiers en C.
Bon courage !