Programmer en C avec SDL2.0 sous Ubuntu


SDL (Simple DirectMedia Layer) est une librairie libre qui permet de créer des applications multimédias et notamment des jeux en deux dimensions. Cette librairie est écrite en C, elle fonctionne avec les systèmes d'exploitation Linux, Windows et Mac OS. Elle peut être utilisée avec divers langages de programmation (C, C++, C#, Python...) et permet d'avoir accès à l'audio, au clavier, à la souris, au joystick et à la carte graphique (via OpenGL.
À la date d'écriture de ces lignes (novembre 2020) la dernière version de SDL est la version 2.0

Dans ce qui suit, on utilise la librairie SDL 2.0 avec le système d'exploitation Ubuntu 18.04 et le compilateur gcc version 7.5.0 utilisé ici avec le langage C.

Pour tester l'installation et l'utilisation de SDL 2.0 sous Ubuntu 18.04, on suit ici la démarche suivante :
1) On installe SDL 2.0;
2) On utilise SDL 2.0 avec le langage C et le compilateur gcc;
3) On solutionne les éventuels messages d'erreurs;
4) On utilise la bibliothèque graphique complémentaire SDL2_gfx_primitives.

1) Installer SDL2 sous Ubuntu 18.04

On commence par saisir, dans le Terminal de commandes, la commande suivante qui affiche la liste des paquets installés:
dpkg-query -l

Si les paquets suivants apparaissent dans la liste, c'est que la librairie SDL2 est déjà installée dans sa version runtime et dans sa version de développement (fichier libsdl2-dev).

ii libsdl-image1. 1.2.12-8ubun amd64 Image loading library for Simple
ii libsdl1.2debia 1.2.15+dfsg2 amd64 Simple DirectMedia Layer
ii libsdl2-2.0-0: 2.0.8+dfsg1- amd64 Simple DirectMedia Layer
ii libsdl2-dev:am 2.0.8+dfsg1- amd64 Simple DirectMedia Layer developm
ii libsdl2-mixer- 2.0.2+dfsg1- amd64 Mixer library for Simple DirectMe
ii libsdl2-mixer- 2.0.2+dfsg1- amd64 Mixer library for Simple DirectMe
ii libsdl2-ttf-2. 2.0.14+dfsg1 amd64 TrueType Font library for Simple
ii libsdl2-ttf-de 2.0.14+dfsg1 amd64 TrueType Font library for Simple

Si ces paquets n'apparaissent pas dans la liste, notamment le paquet libsdl2-dev qui est nécessaire pour pouvoir programmer des applications avec SDL 2.0, il faut procéder à l'installation de SDL 2.0 version de dévelioppement (paquet libsdl2-dev).

Pour cela, on saisit les commandes suivantes dans le Terminal de commande :
sudo apt-get update
sudo apt-get install libsdl2-dev

La seconde commande installe et configure automatiquement tout ce qui est nécessaire pour pouvoir ensuite créer des programmes utilisant SDL 2.0.

Une fois la librairie SDL 2.0 installée, on peut prendre connaissance des principaux répertoires qu'elle utilise, à l'aide des commandes suivantes:
locate libsdl2-dev
locate SDL2/SDL.h
locate libSDL2.a

La première commande permet de localiser les paquets installés, la seconde permet de localiser les fichiers d'en-tête (.h) et la troisième permet de localiser les librairies (statique .a et dynamique .so).

2) Utiliser SDL avec le langage C et le compilateur gcc

On écrit le programme source suivant. Ce programme affiche simplement une fenêtre vide de 300x200 pixels, coin haut gauche placé en (100,100) et remplie de noir puis se met en scrutation infinie des évènements susceptibles de se produire (clic ou appuie d'une touche clavier par exemple). Le programme se termine dès que l'évènement "clic sur le bouton de fermeture de la fenêtre" se produit.

/* essai.c
compilation: gcc -Wall essai.c -o essai $(sdl2-config --cflags --libs)
exécution: ./essai
*/
#include <stdio.h>
#include <SDL2/SDL.h>
int main() {
SDL_Window *mafenetre; //fenêtre du programme
SDL_Event event; // structure pour gérer les évènements clavier, souris, joystick
int fin=0;
if (SDL_VideoInit(NULL) < 0) { exit(1); }// SDL_VideoInit renvoie 0 en cas de succes
mafenetre = SDL_CreateWindow("Essai",100,100,300,200, SDL_WINDOW_SHOWN);
while (!fin ) { //boucle principale
if ( SDL_PollEvent(&event) ) { // scrute sans cesse les évènements et renvoie 1
switch (event.type) {
case SDL_QUIT: //à l'évènement de fermeture de la fenêtre
fin=1;
break;
}}}
SDL_DestroyWindow(mafenetre);
SDL_Quit();
exit(0);
}

Code source: essai.c

On compile ce programme avec la commande suivante puis on l'exécute avec la commande ./essai, avec le Terminal de commandes ouvert dans le répertoire du programme.
gcc -Wall essai.c -o essai $(sdl2-config --cflags --libs)
./essai

01

En résumé :

Pour créer directement un exécutable essai
gcc -Wall essai.c -o essai $(sdl2-config --cflags --libs)

Pour créer un fichier objet essai.o
gcc -Wall -c essai.c $(sdl2-config --cflags)

Pour linker un fichier objet essai.o et créer un exécutable essai
gcc essai.o $(sdl2-config --libs) -o essai

Pour lancer un exécutable essai
./essai

Remarque

La partie $(sdl2-config --cflags --libs) permet de passer des infomations nécessaires au compilateur.

On peut tester les différentes options disponibles pour sdl2-config, en saisissant les commandes suivantes dans le Terminal de commandes.

1) sdl2-config --version
affiche le numéro de version de SDL
Exemple
$ sdl2-config --version
2.0.8

2) sdl2-config --prefix (ou sdl2-config --exec-prefix)
Affiche l'emplacement de l'installation de SDL. Si elle utilisée, cette option doit apparaître avant les options --cflags, --libs et --static-libs.
Exemple
$ sdl2-config --prefix
/usr
$ sdl2-config --exec-prefix
/usr

3) sdl2-config --cflags
Affiche les indications nécessaires au compilateur pour pouvoir compiler un programme utilisant SDL.
Exemple
$ sdl2-config --cflags
-I/usr/include/SDL2 -D_REENTRANT

4) sdl2-config --libs
Affiche les indications nécessaires au compilateur pour pouvoir linker un programme utilisant SDL.
Exemple
$ sdl2-config --libs
-lSDL2

5) sdl2-config --static-libs
Affiche l'ensemble des indications pouvant être passées au compilateur pour pouvoir linker un programme utilisant SDL
Exemple
$ sdl2-config --static-libs
-lSDL2 -Wl,--no-undefined -lm -ldl -lasound -lm -ldl -lpthread -lpulse-simple -lpulse -lsndio -lX11 -lXext -lXcursor
-lXinerama -lXi -lXrandr -lXss -lXxf86vm -lwayland-egl -lwayland-client -lwayland-cursor -lxkbcommon -lpthread -lrt

3) Solutionner les éventuels messages d'erreurs

Lors de la compilation, il peut arriver que gcc retourne un message d'erreur indiquant qu'il ne peut pas trouver un fichier d'en-tête donné.: Par exemple, le message suivant indique gcc ne peut pas trouver le fichier d'en-tête SDL2/SDL_mixer.h
In file included from main.c:1:0:
main.h:4:10: fatal error: SDL2/SDL_mixer.h: Aucun fichier ou dossier de ce type
#include <SDL2/SDL_mixer.h>

Le message suivant indique gcc ne peut pas trouver le fichier d'en-tête SDL_gfxPrimitives.h
/media/ubuntu/data/SDL$ gcc -Wall test.c -o test $(sdl2-config --cflags --libs)
test.c:10:10: fatal error: SDL2/SDL2_gfxPrimitives.h: Aucun fichier ou dossier de ce type
#include <SDL2/SDL2_gfxPrimitives.h>

En ouvrant l'explorateur de fichier dans le répertoire /usr/include/SDL2, on peut vérifier l'absence de ces fichiers.

Pour résoudre ce type de problème, il suffit d'installer les paquets manquants, par exemple:
sudo apt update
sudo apt-get install libsdl2-image-dev
sudo apt-get install libsdl2-mixer-dev
sudo apt-get install libsdl2-ttf-dev
sudo apt-get install libsdl2-gfx-dev

4) Utilisation de la bibliothèque SDL2_gfx_primitives

La bibliothèque SDL2_gfx_primitives fournit à SDL 2.0 des fonctions évoluées de dessin (supplémentaires par rapport aux fonctions de bases) telles que des lignes, des cercles ou des polygones enrichis, comme par exemple les fonctions suivantes (liste non exhaustive).

  • int lineRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int rectangleRGBA(SDL_Renderer * renderer, Sint16 x1, Sint16 y1, Sint16 x2, Sint16 y2, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int pixelRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int circleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int filledCircleRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rad, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int ellipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
  • int filledEllipseRGBA(SDL_Renderer * renderer, Sint16 x, Sint16 y, Sint16 rx, Sint16 ry, Uint8 r, Uint8 g, Uint8 b, Uint8 a)

L'utilisation des fonctions graphiques enrichies de la bibliothèque SDL2_gfxPrimitives nécessite que:
1) le paquet libsdl2-gfx-dev soit installé;
2) l'instruction #include <SDL2_gfxPrimitives.h> soit placée au début du programme source;
3) la compilation soit faite avec la commande suivante qui ajoute l'option -lSDL2_gfx
gcc -Wall test.c -o test $(sdl2-config --cflags --libs) -lSDL2_gfx

Exemple

L'esemble suivant crée une fenêtre de 300x200 pixel dotée d'un fond noir puis affiche dans cette fenêtre une ligne bleue et un cercle rouge. La ligne bleue est dessinée avec les fonctions standard de SDL 2.0 (sans recourir à la bibliothèque SDL2_gfxPrimitives). En revanche le cercle rouge est dessiné par la fonction circleRGBA() qui fait partie de la bibliothèque SDL2_gfxPrimitives.
Si on essaie d'exécuter le programme sans utiliser le paramètre -lSDL2_gfx, nécessaire pour la prise en compte cette bibliothèque, on obtient un message d'erreur lors de la compilation ou de l'édition des liens.

/* test.c
compilation: gcc -Wall test.c -o test $(sdl2-config --cflags --libs) -lSDL2_gfx
exécution: ./test

#include <SDL.h>
#include <SDL2_gfxPrimitives.h>
int main()
{
//initialisation
if (SDL_Init(SDL_INIT_VIDEO) == 0) { SDL_Window window = NULL; SDL_Renderer* renderer = NULL;
if (SDL_CreateWindowAndRenderer(300, 200, 0, &window, &renderer) == 0) { SDL_bool done = SDL_FALSE;
//boucle du programme
while (!done) {
SDL_Event event;
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
SDL_RenderClear(renderer);
SDL_SetRenderDrawColor(renderer, 0, 0, 255, SDL_ALPHA_OPAQUE);
SDL_RenderDrawLine(renderer, 0, 0, 100, 100); // fonction standard de SDL2
circleRGBA(renderer, 100, 100, 50, 255, 0, 0, 255);//fonction de la librairie SDL2_gfxPrimitives
SDL_RenderPresent(renderer);
while (SDL_PollEvent(&event)) {if (event.type == SDL_QUIT) {done = SDL_TRUE;}}
}}
//sortie de la boucle du programme
if (renderer) {SDL_DestroyRenderer(renderer);}
if (window) {SDL_DestroyWindow(window);}
}
SDL_Quit();
return 0;
}

Code source: test.c

02