Programmer en C++
SDL2 - Texte avec SDL2_ttf

1. Paramétrage du linker



Lors de la création du premier projet avec SDL2 nous avions du ajouter dans le linker, et dans cet ordre trois librairies "libmingw32, libSDL2main, et libSDL2". Rappelez vous la procédure de l'installation de ces librairies :
• 1) Clic droit sur le nom du projet.
• 2) Dans le menu qui apparait, cliquez sur "Build options ...".
• 3) Dans la fenêtre qui s'ouvre "Project build options", vérifiez que le nom du projet est sélectionné (donc pas simplement Debug ou Release, mais tout).
• 4) Ajoutez à la suite des trois librairies précédentes, la librairies libSDL2_ttf

Nous pouvons maintenant commencer à écrire le code qui nous permettra d'écrire dans la fenêtre.

2. Du code pour écrire du texte

L'utilisation des différentes fonction appartenant à SDL2_ttf nécessite l'ajout d'un en-tête particulier :

#include <SDL_ttf.h>

Tout de suite après l'initialisation de SDL2, nous initialisons SDL2_ttf avec :

TTF_Init();

La fonction retourne 0 si l'initialisation s'est bien déroulée, et -1 sinon.
A la fin du programme, il faudra penser à refermer SDL2_ttf. C'est le rôle de la fonction suivante :

TTF_Quit();

Cette fonction doit être placée avant SDL_Quit.

Revenons maintenant à l'instant qui suit l'initialisation. Pour écrire du texte, il nous faut au préalable une police de caractère. Celles-ci sont disponibles au format "ttf".
Où les trouver ?
On en trouve facilement sur internet, mais sachez aussi que Windows en possède un choix relativement important dans le dossier "C:\Windows\Fonts".
Le plus simple est de placer le fichier de cette police à l'emplacement du programme. Supposons qu'il se nomme "arial.ttf", le chargement de cette police se fera alors en écrivant :

TTF_Font *pFont = TTF_OpenFont("arial.ttf", 25);

La fonction TTF_OpenFont reçoit le nom de la police en premier argument, puis la taille de cette police en second. Si la taille fournie excède les tailles de police disponible, alors ce sera la taille de police la plus grande qui sera prise par défaut. La fonction retourne un pointeur sur cette police.

Ensuite nous allons définir une couleur d'écriture de cette façon :

SDL_Color couleur = {255, 255, 0};     // du jaune ici

A partir de maintenant nous allons voir que placer du texte dans une fenêtre, ressemble beaucoup au placement d'une image. Le texte va être placé dans une "surface", puis transféré dans une "texture". Il sera ensuite transmis au rendu avant que la fenêtre ne soit actualisée.
Le transfert du texte vers une surface se fait comme ceci :

SDL_Surface *pSurfTxt = TTF_RenderText_Blended(pFont, "Bonjour !", couleur);

Nous reviendrons sur cette fonction un peu plus loin.
Maintenant que notre texte est passé dans une "surface", nous pouvons libérer la mémoire de notre police en écrivant :

TTF_CloseFont(pFont);

La suite se fait donc comme avec une image (on supposera "pRendu" être le pointeur désignant le rendu) :

SDL_Texture *pTextureTxt = SDL_CreateTextureFromSurface(pRendu, pSurfTxt);

Le transfert du texte de la "surface" à une "texture" nous permet maintenant de libérer la mémoire utilisée par la "surface" avec :

SDL_FreeSurface(pSurfTxt);

Comme avec une image on aura donc aussi le transfert vers le rendu avec :

SDL_RenderCopy(pRendu, pTextureTxt, nullptr, nullptr);


Je ne vais pas revenir sur la suite qui a déjà été traité pour l'affichage d'images (actualisation de la fenêtre, libération de la mémoire de texture, puis de rendu). Au besoin revoir les chapîtres précédents.

Comme on peut s'y attendre le texte apparait probalement déformé (trop étiré dans le sens horizontal, ou vertical, et de plus envahit totalement la fenêtre).

Grace à l'utilisation de SDL_Rect nous pouvons positionner le texte là ou nous le voulons. Par contre comment modifier les paramètres "h" (hauteur du texte) et "w" (largeur du texte) pour être certain de respecter les bonnes proportions ?

Heureusement il existe un outil, la fonction :

SDL_QueryTexture(pTextureTxt, NULL, NULL, &txtW, &txtH);

Vous reconnaissez le premier argument : c'est le pointeur sur la texture contenant notre texte à afficher. Nous sautons volontairement les deux arguments suivants pour ne nous intéresser qu'aux deux derniers. Ce sont deux entiers donc nous fournissons les adresses. La fonction retourne la largeur et la hauteur de la zone de texte, respectivement dans txtW et txtH (C'est juste ce que nous avions besoin).

Je vous ai annoncé plus haut que j'allais revenir sur la fonction TTF_RenderText_Blended. Il me semble intéressant en effet de vous montrer qu'il existe d'autre fonctions semblables ayant des effets différents sur l'affichage du texte. La différence est montrée en images :

3. Le code complet

Voici le code qui nous a permis d'afficher "Bonjour !" dans le style "TTF_RenderText_Blended".

#include <iostream>
#include <SDL.h>
#include <SDL_ttf.h>

using namespace std;

int main(int argc, char* argv[])
{
    cout << "Texte avec SDL2_ttf" << endl;

    SDL_Window *pFenetre = 0;
    SDL_Renderer *pRendu = 0;
    SDL_Rect destRect;

    SDL_Init (SDL_INIT_VIDEO);
    pFenetre = SDL_CreateWindow(
            "Texte avec SDL2_ttf", SDL_WINDOWPOS_CENTERED,
            SDL_WINDOWPOS_CENTERED, 300,
            300, SDL_WINDOW_SHOWN);

    if(TTF_Init() == -1)     // Initialisation de SDL2_ttf
    {
        cout << "erreur d'initialisation de la SDL2_ttf" << endl;
    }

    TTF_Font *pFont = TTF_OpenFont("arial.ttf", 25);
    SDL_Color couleur = {255, 255, 0};     // du jaune ici
    SDL_Surface *pSurfTxt = TTF_RenderText_Blended(pFont, "Bonjour !", couleur);
    TTF_CloseFont(pFont);     // On libère la mémoire utilisée par la police
    pRendu = SDL_CreateRenderer(pFenetre, -1, SDL_RENDERER_ACCELERATED);
    // Transfert de l'image de la surface à une texture
    SDL_Texture *pTextureTxt = SDL_CreateTextureFromSurface(pRendu, pSurfTxt);
    // Deux variables qui vont recevoir les dimensions du texte
    int txtW = 0;
    int txtH = 0;
    SDL_QueryTexture(pTextureTxt, NULL, NULL, &txtW, &txtH);
    SDL_FreeSurface(pSurfTxt);     // La mémoire de surface est libérée
    // Positionnement du texte
    destRect.x = 50;
    destRect.y = 50;
    // On utilise les données fournies par SDL_QueryTexture
    destRect.w = txtW;
    destRect.h = txtH;
    // On applique le texte dans la fenêtre
    SDL_RenderCopy(pRendu, pTextureTxt, nullptr, &destRect);
    SDL_DestroyTexture(pTextureTxt);     // La mémoire de texture est libérée

    // Actualisation de la fenêtre
    SDL_RenderPresent(pRendu);

    int attendre = 1;
    SDL_Event evenement;

    // Boucle d'evenements
    while(attendre)
    {
        SDL_WaitEvent(&evenement);
        switch(evenement.type)
        {
            case SDL_QUIT:
                attendre = 0;
                break;
        }
    }

    SDL_DestroyRenderer(pRendu);
    SDL_DestroyWindow(pFenetre);
    SDL_Quit ();

    return EXIT_SUCCESS;
}