Suivez-nous sur X

|
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
ALL
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
0,
A,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z
|
|
A propos d'Obligement
|
|
David Brunet
|
|
|
|
Comparatif : raylib contre SDL
(Article écrit par Ramon Santamaria et extrait de GitHub - décembre 2023)
|
|
Au cours des dernières années, on m'a posé plusieurs questions sur la comparaison entre les bibliothèques
raylib et SDL.
Malheureusement, mon expérience avec SDL était assez limitée et je ne pouvais donc pas
fournir une bonne comparaison. Au cours des deux dernières années, j'ai découvert SDL et je l'ai utilisé
pour enseigner à l'université. Je pense donc pouvoir désormais fournir une bonne comparaison entre les deux.
J'espère que cela aidera les futurs utilisateurs à mieux comprendre les composants internes et les fonctionnalités
de ces deux bibliothèques.
1. Introduction
La première fois que j'ai découvert la bibliothèque SDL, c'était en 2004. À cette époque, je connaissais très
peu de choses en programmation et je n'avais aucune idée du développement de jeux vidéo ; ma première
expérience avec la bibliothèque n'a pas été bonne. Je ne comprenais pas la plupart des concepts exposés ni
comment les différentes parties de la bibliothèque étaient connectées, les conventions de dénomination SDL
me déroutaient et la documentation était écrasante ; la configuration de la construction était vraiment
pénible, je me souviens avoir eu du mal avec les dépendances du compilateur et des liens, ressentant
beaucoup de frustration. Depuis ce moment, j'ai développé une certaine appréhension pour la bibliothèque SDL.
Huit ans plus tard, après avoir travaillé dans l'industrie du développement de jeux AAA et avoir également sorti
plusieurs jeux XNA, j'ai commencé à travailler comme enseignant. J'ai dû enseigner
les bases de la programmation de jeux vidéo à de jeunes étudiants en art et, à ce moment-là, je n'envisageais guère d'utiliser
SDL en raison de mon expérience passée... j'ai plutôt décidé de créer ma propre bibliothèque : raylib.
Je travaille sur raylib depuis neuf ans maintenant et il y a quelques années, j'ai commencé à enseigner le
développement de moteurs de jeux personnalisés à l'université. Par hasard, j'ai dû enseigner SDL. Je dois
dire que mon expérience cette fois a été bien meilleure que la première fois, en fait, j'ai pu apprécier
cette incroyable bibliothèque et j'en ai beaucoup appris.
Voici ma comparaison personnelle entre raylib et SDL. J'ai fait de mon mieux pour garder cette comparaison
aussi objective que possible, mais notez que ma connaissance des composants internes de SDL et de ses
décisions de conception est plus limitée que celle de raylib ; il se peut qu'il me manque des informations
importantes ou que je sois confus sur certaines parties.
N'hésitez pas à commenter
avec des informations supplémentaires ou des améliorations requises.
Remarque : je concentre cette analyse sur la bibliothèque SDL 2.0, il s'agissait d'un changement
majeur par rapport aux versions précédentes, offrant plus de possibilités d'accélération matérielle 3D,
mais brisant la compatibilité ascendante. La licence a également été modifiée de GNU LGPL à zlib.
2. Comparaison de conception de bibliothèque
SDL est similaire à raylib à bien des égards, les deux sont écrits en langage C et offrent des fonctionnalités
similaires, mais SDL se situe à un niveau un peu inférieur, offrant plus de contrôle sur les options de
configuration de la plate-forme/des systèmes, tandis que raylib fournit des fonctionnalités de plus haut niveau.
En termes de gestion de plate-forme, les deux bibliothèques gèrent plusieurs plates-formes : Windows, Linux,
macOS, FreeBSD, Android, Raspberry Pi, HTML5, Haiku... SDL gère officiellement la plate-forme iOS alors que
raylib ne le fait pas, mais, dans tous les cas, les deux bibliothèques ont été portées sur des plates-formes
supplémentaires par la communauté. SDL a été adapté pour plusieurs SDK de console (sous NDA) et raylib a
été porté sur plusieurs SDK de console faits maison
[NDTrad : au niveau Amiga, SDL2 est disponible sur AmigaOS 4
et MorphOS, alors que raylib dispose d'une version native AROS x86, qui lui, ne dispose pas de SDL2, seulement
de SDL1].
raylib s'appuie sur la bibliothèque GLFW
pour le fenêtrage et la gestion des entrées sur les plates-formes
de bureau et implémente des solutions de fenêtrage/entrée personnalisées pour d'autres plates-formes comme
Android et Raspberry Pi (y compris le mode sans tête natif). En fait, la
bibliothèque principale SDL offre
les mêmes fonctionnalités que GLFW (et bien d'autres).
Les principales différences proviennent de la structure de la bibliothèque, des conventions internes et de
l'API fournie.
Structure de la bibliothèque
SDL se compose d'une bibliothèque principale axée sur les
fonctionnalités de la plate-forme/du système et
de quelques bibliothèques satellites censées être utiles mais facultatives. Les utilisateurs peuvent choisir
lesquels utiliser en fonction des besoins de leurs projets.
Bibliothèque SDL :
- SDL (SDL2.dll) : fonctionnalités de la plate-forme/du
système SDL (gestion des fenêtres/rendu, entrées,
gestion des périphériques audio, entrées/sorties de fichiers, chronomètres...).
Bibliothèques satellites SDL :
- SDL_image (SDL2_image.dll) : chargement des fichiers image.
- SDL_ttf (SDL2_ttf.dll) : chargement des polices
et rendu du texte (vers l'image).
- SDL_Mixer (SDL2_mixer.dll) : chargement et
lecture des fichiers audio.
- SDL_net (SDL2_net.dll) : fonctionnalité réseau.
raylib est contenu dans une seule bibliothèque (raylib.dll|libSraylib.a) et les fonctionnalités
souhaitées peuvent être sélectionnées avec certains indicateurs de compilation, à l'exclusion de
certains modules internes ou parties de code. En interne, raylib est divisé en un petit nombre de
modules (fichiers ".c" séparés), pour la plupart autonomes, offrant différentes fonctionnalités :
- Module principal (rcore.c) :
fonctionnalités de base du système raylib (gestion des fenêtres/périphériques
graphiques, entrées, gestion des fichiers, chronomètre...).
- Module rlgl (rlgl.h) :
couche d'abstraction OpenGL, inclut un système de rendu par lots. Il s'agit d'une
bibliothèque portable contenant uniquement un en-tête de fichier unique.
- Module de formes (rshapes.c) :
dessin de formes 2D de base (ligne, rectangle, cercle, poly...).
- Module de textures (rtextures.h) :
chargement de fichiers image, génération et manipulation d'images,
chargement et dessin de texture 2D.
- Module de texte (rtext.c) :
chargement de polices, génération d'atlas de polices, fonctionnalité
de texte, dessin de texte.
- Module de modèles (rmodels.c) :
chargement de modèles et matériaux 3D, génération de maillages 3D,
dessin de modèles.
- Module audio (raudio.c) :
gestion des périphériques audio, chargement et lecture des fichiers audio.
Remarque : SDL est distribué par défaut sous forme de bibliothèques dynamiques tandis que raylib
est destiné à être lié statiquement (libraylib.a), pour éviter les dépendances externes.
SDL et raylib dépendent de plusieurs bibliothèques externes pour certaines fonctionnalités (généralement le
chargement de formats de fichiers). SDL s'appuie généralement sur les bibliothèques officielles de chargement
de formats de fichiers, tandis que raylib s'appuie principalement sur des bibliothèques autonomes d'en-tête
de fichier unique intégrées à la base de code raylib.
SDL_image exigeait les bibliothèques suivantes : libpng (+zlib), libtiff, libjpeg, libwebpet. Et SDL_Mixer
exigeaient libFLAC, libmikmod, libogg, libvorbis... mais il semble que les dernières versions de SDL
(2022) aient ajouté la gestion de plusieurs bibliothèques d'en-tête de fichier unique uniquement en option
(stb_image, dr_flac, stb_vorbis...), cela peut être sélectionné au moment de la construction.
SDL nécessite un système de construction plus complexe pour gérer les nombreux fichiers de code source
de la bibliothèque et les multiples bibliothèques externes. Voici une liste des bibliothèques dynamiques SDL
et leurs dépendances possibles :
- SDL2.dll.
- SDL2_image.dll pourrait en outre exiger libpng16-16.dll, libtiff-5.dll, libjpeg-9.dll, libwebp-4.dll,zlib1.dll.
- SDL2_ttf.dll pourrait en outre exiger libfreetype-6.dll,zlib1.dll.
- SDL2_mixer.dll pourrait en outre nécessiter libFLAC-8.dll, libmodplug-1.dll, libogg-0.dll, libopus-0.dll,
libvorbis-0.dll, libvorbisfile-3.dll,libmpg123-0.dll.
- SDL2_net.dll.
Remarque : toutes les bibliothèques externes peuvent être compilées directement dans les DLL SDL pour
éviter les exigences supplémentaires en matière de DLL. En fait, comme indiqué, la dernière version de
SDL2_Mixer
gère les alternatives à en-tête de fichier unique uniquement pour le chargement de plusieurs formats de
fichiers au lieu des formats officiels, elle peut être configurée par le système de construction.
Les programmes raylib nécessitent raylib.dll, une compilation dynamique ou un lien avec libraylib.a,
une compilation statique. Par défaut, toutes les fonctionnalités requises sont compilées dans ce fichier
unique. En fait, toutes les fonctionnalités requises sont compilées en seulement
huit unités de compilation (huit fichiers ".c").
Le code source SDL est réparti sur plus de 700 fichiers de code, très bien organisés par systèmes, plates-formes
et arrière-plans logiciels gérés tandis que le code source de raylib se compose d'un petit nombre de fichiers
de code longs (2000 à 7000 lignes de code chacun), au moment d'écrire ces lignes, raylib se compose de huit fichiers ".c"
individuels ainsi que de quelques bibliothèques portables supplémentaires (environ 30 fichiers ".h").
En termes d'utilisation des bibliothèques, les bibliothèques SDL doivent être incluses séparément, en fonction
des besoins de l'utilisateur.
#include "SDL.h" // Bibliothèque de base SDL (fonctionnalité fenêtre/rendu, saisie, chronomètre...)
#include "SDL_opengl.h" // Fonctionnalité SDL OpenGL (si nécessaire, au lieu du moteur de rendu interne)
#include "SDL_image.h" // Fonctionnalité de chargement d'image (dans SDL_Surface)
#include "SDL_ttf.h" // Chargement et rastérisation des données de police (dans l'image)
#include "SDL_mixer.h" // Gestion des périphériques audio et chargement des fichiers audio
|
raylib est livré avec une seule en-tête fournissant toutes les fonctionnalités (l'API interne est divisée
en sections).
#include "raylib.h" // inclusion de raylib (expose toutes les fonctionnalités de chaque module)
|
Certains des modules de bas niveau inclus dans raylib (utilisés par d'autres modules de niveau supérieur)
sont également disponibles pour les utilisateurs nécessitant des fonctionnalités avancées, par exemple
rlgl.h et raymath.h, les modules peuvent être inclus ou également utilisés comme bibliothèques autonomes.
Plus de détails sur l'architecture de la bibliothèque raylib peuvent être trouvés sur le
wiki de raylib.
Conventions internes
- Préfixes de dénomination : SDL préfixe généralement toutes les fonctions avec "SDL_" (par exemple
SDL_CreateWindow()) alors que raylib n'utilise pas de préfixes sur ses fonctions (c'est-à-dire InitWindow()),
en fait, cette décision de conception a été motivée par mon expérience précédente avec les bibliothèques
XNA/WinBGI, la dénomination sans préfixe était plus claire pour mes étudiants. Il convient de noter que
SDL_image utilise le préfixe "IMG_" (par exemple IMG_Load()), SDL_ttf utilise le préfixe "TTF_" (par exemple
TTF_OpenFont()) et SDL_Mixer utilise le préfixe "Mix_" (par exemple Mix_FreeChunk()). Le module interne
de raylib rlgl est le seul à utiliser le préfixe "rl" sur toutes ses fonctions (par exemple rlLoadRenderBatch()),
motivé par la convention OpenGL. Outre le choix des différents préfixes, les deux bibliothèques utilisent la
convention TitleCase de dénomination pour leurs fonctions et leurs structures.
- Pointeurs : SDL utilise principalement des pointeurs vers des structures opaques pour la plupart
de ses types de données (par exemple SDL_Surface), tandis que raylib utilise des structures transparentes
simples qui masquent la complexité des pointeurs si nécessaire. La plupart des fonctions SDL reçoivent/renvoyent
ces pointeurs en tant que paramètres de fonction afin que les données soient transmises par référence,
raylib utilise à la place l'approche "passage par valeur" pour la plupart des fonctions, toutes les structures
raylib ont été conçues pour être aussi petites que possible, généralement moins de
64 octets.
- Codes d'erreur : les fonctions SDL renvoient généralement des codes d'erreur pour vérifier si la
fonction a fonctionné comme prévu, raylib évite généralement cette approche (utilisée uniquement sur certaines
fonctions d'accès aux fichiers). Par défaut, la plupart des fonctions raylib ont un mécanisme de secours
(renvoie un objet par défaut valide) et génèrent des messages LOG_INFO/LOG_WARNING/LOG_ERROR sur la console.
- Rétrocompatibilité : SDL fait attention à la rétrocompatibilité, les fonctions anciennes ou
obsolètes restent dans la bibliothèque et les nouvelles utilisent des signatures différentes lorsqu'elles
sont ajoutées. raylib ne se soucie pas de la rétrocompatibilité ; si une fonction doit être repensée ou
supprimée, c'est le cas. Chaque nouvelle version de raylib répertorie les modifications importantes lors
de sa sortie, mais notez qu'il ne s'agit généralement que de quelques-unes d'entre elles.
3. Comparaison des fonctionnalités
Les deux bibliothèques peuvent être utilisées pour le développement de jeux vidéo et d'applications
graphiques. Il s'agit ici d'une comparaison de l'ensemble des fonctionnalités fournies par les deux :
- Gestion des formats de fichiers.
- Système de fenêtre et de rendu.
- Système d'entrée.
- Dessin de formes.
- Chargement et dessin d'images et de textures.
- Chargement de polices et dessin de texte.
- Chargement et dessin de modèles.
- Système audio.
- Système de réseau.
3.1 Gestion des formats de fichiers
Commençons probablement par la fonctionnalité la moins importante pour les développeurs professionnels, à
savoir la gestion des formats de fichiers d'entrée pour charger les données dans les structures internes fournies.
Les deux bibliothèques gèrent les formats de fichiers les plus courants pour les images, les polices et
l'audio. SDL permet d'utiliser les bibliothèques officielles pour charger les différents formats de
fichiers (c'est-à-dire que les fichiers PNG sont chargés à l'aide de libpng) tandis que raylib utilise
des bibliothèques alternatives à en-tête de fichier unique uniquement pour charger tous les formats de
fichiers gérés (c'est-à-dire stb_image pour les images).
Voici la liste des formats de fichiers gérés :
Type |
SDL |
raylib |
Images |
BMP, TGA, GIF, JPEG, PNG, QOI, PNM, LBM, PCX, SVG, TIFF, WEBP, XCF, XPM, XV |
BMP, TGA, GIF, JPEG, PNG, QOI, PSD, PIC, HDR, DDS, PKM, KTX, PVR, ASTC |
Audio |
WAV, OGG, MP3, FLAC, MOD, XM, S3M, IT, VOC, AIFF... |
WAV, OGG, MP3, FLAC, MOD, XM |
Polices |
TTF, TTC, CFF, WOFF, OTF... |
TTF, OTF, FNT, (images d'atlas de polices) |
Modèles 3D |
- |
OBJ, IQM, GLTF, GLB, VOX |
Quelques points à noter :
- raylib gère le chargement de plusieurs formats de fichiers compressés par la puce graphique, mais pas
la décompression des données pixel, les données sont chargées compressées pour être déplacées directement
vers une texture de la puce graphique.
- SDL utilise FreeType2
pour la rastérisation des polices. Il s'agit d'une bibliothèque standard de
l'industrie qui fournit de très bons résultats de rastérisation, gérant plusieurs astuces comme ClearType.
raylib utilise à la place la bibliothèque stb_truetype, bien plus petite que FreeType2 et avec une
qualité de rastérisation des polices inférieure.
- raylib gère le chargement de modèles/matériaux/animations 3D pour plusieurs formats 3D, cette
fonctionnalité n'est pas fournie par SDL.
3.2 Système de fenêtre et de rendu
Bibliothèque SDL (SDL2) vs module principal raylib
(rcore).
La bibliothèque principale SDL propose plus de 750 fonctions
tandis que le module principal raylib en propose environ
180.
Remarque : ces chiffres incluent la fonctionnalité du système d'entrée, qui est commentée plus
en détail dans le point suivant.
La bibliothèque SDL et le module principal raylib fournissent tous deux des fonctions permettant de gérer
Windows, le périphérique graphique et les entrées. SDL implémente toutes les fonctionnalités directement à
l'aide des bibliothèques système tandis que raylib s'appuie sur la bibliothèque GLFW pour les plates-formes
de bureau (Windows, Linux, macOS...) et implémente des solutions personnalisées pour Android et Raspberry Pi
(mode natif).
SDL fournit un système de rendu puissant pour dessiner sur la fenêtre, SDL_Renderer qui peut être accéléré
matériellement (généralement OpenGL sous Linux et Direct3D sous Windows) avec un repli logiciel si nécessaire.
Mais pour les fonctionnalités avancées d'OpenGL telles que les nuanceurs, c'est à l'utilisateur de les gérer.
En fait, il est recommandé d'éviter SDL_Renderer et de demander un contenu OpenGL manuellement ; pour cette
tâche, une autre bibliothèque doit être utilisée : SDL_opengl.h. SDL_Renderer ajoute des capacités de rendu
par lots sur SDL 2.0.10.
raylib ne gère pas le rendu logiciel et utilise les fonctionnalités modernes d'OpenGL par défaut, il initialise OpenGL 3.3 Core
ou OpenGL ES 2.0 selon la plate-forme mais, il gère également OpenGL 1.1, 2.1 et 4.3 si vous le souhaitez,
grâce au module rlgl,
une couche d'abstraction qui attribue un mode immédiat pseudo-OpenGL 1.1 vers d'autres
versions d'OpenGL. rlgl inclut un système de traitement par lots du rendu qui accumule les appels de
dessin pour émettre un seul dessin lorsque cela est nécessaire, le système de traitement par lots est
initialisé par défaut avec InitWindow() mais il peut être géré manuellement à l'aide de certains appels
de fonctions rlgl (destinés aux utilisateurs avancés).
raylib propose une API pour le chargement (LoadShader()) et l'utilisation (BeginShaderMode()/EndShaderMode())
de nuanceurs GLSL.
Quelques structures de données de base fournies par les deux bibliothèques :
SDL |
raylib |
SDL_Rect |
Rectangle |
SDL_Color |
Color |
SDL_Texture |
Texture2D |
SDL_Surface |
Image |
Ici, il s'agit d'une comparaison de certaines fonctions SDL par rapport à celles équivalentes dans
raylib, gardez à l'esprit que l'API SDL est plus grande que celle de raylib.
Fonctionnalités |
SDL |
raylib |
Initialisation de la fenêtre/du moteur de rendu |
SDL_Init()
SDL_CreateWindow()
SDL_CreateRenderer()
SDL_CreateSoftwareRenderer()
SDL_CreateWindowAndRenderer()
SDL_GL_CreateContext()
|
InitWindow() |
Moteur de rendu : Effacer (Clear) |
SDL_SetRenderDrawColor()
SDL_RenderClear() |
ClearBackground() |
Moteur de rendu : dessin des formes de base |
SDL_RenderDrawPoint()
SDL_RenderFillRect()
SDL_RenderDrawRect()
SDL_RenderDrawLine() |
DrawPixel(),DrawCircle()
DrawRectangle()
DrawRectangleLines()
DrawLine() |
Moteur de rendu : dessin d'une texture |
SDL_RenderCopy()
SDL_RenderCopyEx() |
DrawTexture()
DrawTextureEx()
DrawTexturePro() |
Moteur de rendu : Mélange (Blending) |
SDL_SetRenderDrawBlendMode() |
BeginBlendMode()/EndBlendMode() |
Moteur de rendu : Présent (Present) |
SDL_RenderPresent()
SDL_GL_SwapWindow() |
EndDrawing() |
Désinitialisation de la fenêtre/du moteur de rendu |
SDL_DestroyRenderer()
SDL_GL_DeleteContext()
SDL_DestroyWindow()
SDL_Quit() |
CloseWindow() |
Chronomètre (Timing) |
SDL_Delay() |
WaitTime() |
Enregistrement (Logging) |
SDL_GetError()
SDL_Log() |
TraceLog() |
Exemple 01a. SDL : initialisation/désinitialisation de la fenêtre et du moteur de rendu
// Initialisation de l'état global interne de SDL
// Note : SDL permet d'initialiser uniquement les sous-systèmes souhaités
SDL_Init (SDL_INIT_EVERYTHING);
// Fenêtre d'initialisation
SDL_Window *window = SDL_CreateWindow("Welcome to SDL!", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, flags
// Initialisation du moteur de rendu
SDL_Renderer *renderer = SDL_CreateRenderer(state.window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
SDL_SetRenderDrawColor(renderer, 100, 149, 237, 255); // Default clear color: Cornflower blue
// Boucle d'application
while (!closeWindow)
{
// Traiter les événements d'entrée
// Dessiner
}
// Désinitialise le moteur de rendu et la fenêtre
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(window);
// Désinitialise l'état global interne du SDL
SDL_Quit();
|
Notez que SDL_Renderer n'est pas destiné aux fonctionnalités OpenGL modernes (3D, nuanceurs, fonctionnalités
graphiques avancées...), un contexte OpenGL doit être créé manuellement pour ce cas.
Exemple 01b. SDL : initialisation/désinitialisation de la fenêtre et du moteur de rendu (OpenGL moderne)
// Fonctionnalité OpenGL requise
#include "SDL_opengl.h"
// Initialise l'état global interne du SDL
SDL_Init (SDL_INIT_EVERYTHING);
// Fenêtre d'initialisation
SDL_Window *window = SDL_CreateWindow("Bienvenue dans SDL OpenGL!", 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
// Initialisation du contexte OpenGL
SDL_GLContext glcontext = SDL_GL_CreateContext(window);
// Boucle d'application
while (!closeWindow)
{
// Traiter les événements d'entrée
// Dessinez en utilisant OpenGL
// Note : C'est à l'utilisateur de charger les extensions requises et de gérer l'état OpenGL et le dessin
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT);
SDL_GL_SwapWindow(window);
}
// Désinitialise le contexte et la fenêtre OpenGL
SDL_GL_DeleteContext(glcontext);
// Désinitialise l'état global interne du SDL
SDL_Quit();
|
Exemple 01c. raylib : initialisation/désinitialisation de la fenêtre et du moteur de rendu (OpenGL moderne)
// Initialisation de l'état global interne de raylib et création de la fenêtre
InitWindow(SCREEN_WIDTH, SCREEN_HEIGHT, "Bienvenue dans raylib!");
// Boucle d'application...
while (!WindowShouldClose())
{
// Dessine
BeginDrawing();
ClearBackground(BLACK);
// Les événements d'entrée sont traités en interne par défaut
EndDrawing();
}
// Désinitialise l'état global interne de raylib et la fenêtre
CloseWindow();
|
3.3 Système d'entrée
SDL propose plus de 100 fonctions
pour gérer plusieurs périphériques d'entrée tandis que raylib en propose
environ 45.
SDL fournit un mécanisme pour interroger les événements d'entrée et fournir ces données "brutes"
directement à l'utilisateur. raylib interroge à la place les entrées en interne par défaut lors
de l'appel EndDrawing() (les utilisateurs avancés peuvent effectuer l'interrogation eux-mêmes en
appelant PollInputEvents()) et remplit les tampons internes avec les données de résultat pour fournir
des fonctions de haut niveau permettant de vérifier l'état des entrées (c'est-à-dire IsKeyPressed(),
IsGamepadButtonDown()...).
Les deux bibliothèques gèrent les systèmes de saisie standard : clavier, souris, manette de jeu,
événements tactiles et gestes. SDL inclut également des fonctionnalités permettant de gérer les
capteurs et les commandes haptiques.
Quelques points à noter :
- La gestion de la manette de jeu SDL est exceptionnelle. Elle offre un contrôle très précis des données
de la manette de jeu et gère les attributions de manette de jeu pour plusieurs appareils. En fait, GLFW utilise
les mêmes données SDL_GameControllerDB, elles
sont donc également utilisées en interne par raylib pour identifier de nombreux contrôleurs de manette de jeu.
Fonctionnalités |
SDL |
raylib |
Interrogation des événements d'entrée |
SDL_PollEvents()
SDL_PumpEvents() |
PollInputEvents() (appelée par EndDrawing()) |
Entrées clavier |
SDL_PollEvent() (vérifie event.type)
SDL_GetKeyboardState() |
IsKeyPressed()
IsKeyDown()
GetKeyPressed() |
Entrées souris |
SDL_PollEvent() (vérifie event.type)
SDL_GetMouseState() |
IsMouseButtonPressed()
IsMouseButtonDown()
GetMousePosition() |
Entrées manette de jeu |
SDL_PollEvents() (vérifie event.type)
SDL_NumJoysticks()
SDL_JoystickOpen()
SDL_JoystickClose() |
IsGamepadAvailable()
IsGamepadButtonPressed()
IsGamepadButtonDown()
GetGamepadAxisMovement() |
Constantes d'entrée (exemple) |
SDL_SCANCODE_ESCAPE
SDL_SCANCODE_UP
SDL_SCANCODE_DOWN
SDL_SCANCODE_LEFT
SDL_SCANCODE_RIGHT
SDL_SCANCODE_SPACE |
KEY_ESCAPE
KEY_UP
KEY_DOWN
KEY_LEFT
KEY_RIGHT
KEY_SPACE |
Exemple 02a. SDL : gestion des entrées
// Initialisation de l'entrée manette
// Vérifiez SDL_NumJoysticks() et SDL_JoystickOpen()
if (SDL_NumJoysticks() < 1) SDL_Log( "ATTENTION: aucune manette connectée!\n");
else
{
SDL_Joystick *gamepad = SDL_JoystickOpen(0);
if (SDL_Joystick * gamepad == NULL) SDL_Log("Alerte : Impossible ouvrir manette! Erreur SDL: %s\n", SDL_GetError());
}
// Événements d'entrée d'interrogation
SDL_Event event = { 0 };
SDL_PollEvent(&event);
// Tous les événements d'entrée peuvent être traités après le commutateur d'interrogation switch(event.type)
{
case SDL_QUIT: closeWindow = true; break;
// Les événements de fenêtre sont également interrogés (minimisé, maximisé, fermé...)
case SDL_WINDOWEVENT: break;
// événements clavier
case SDL_KEYDOWN:
{
if (event.key.keysym.sym == SDLK_ESCAPE) closeWindow = true;
} break;
// Vérification des événements souris
case SDL_MOUSEBUTTONDOWN: break;
case SDL_MOUSEBUTTONUP: break;
case SDL_MOUSEWHEEL: break;
case SDL_MOUSEMOTION:
{
mousePosition.x = event.motion.x;
mousePosition.y = event.motion.y;
} break;
// Vérification des événements manette
case SDL_JOYAXISMOTION:
{
// mouvement sur manette 0
if (event.jaxis.which == 0)
{
// mouvement axe X
if (event.jaxis.axis == 0)
{
//...
}
// mouvement axe Y
else if (event.jaxis.axis == 1)
{
//...
}
}
} break;
default: break;
}
|
Exemple 02b. raylib : gestion des entrées
// L'interrogation des entrées est effectuée par défaut par EndDrawing() et les états sont gérés en interne (UP, DOWN)
// Vérification si une touche a été enfoncée (UP->DOWN)
if (IsKeyPressed(KEY_ENTER)) currentScreen = SCREEN_GAMEPLAY;
// Vérification si une touche est enfoncée (DOWN)
if (IsKeyDown(KEY_LEFT)) player.position.x -= player.speed.x;
else if (IsKeyDown(KEY_RIGHT)) player.position.x += player.speed.x;
// Vérification si le bouton de la souris a été enfoncé et obtient la position de la souris
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)
{
Vector2 mousePosition = GetMousePosition();
}
// Vérification si le bouton de la manette est enfoncé
if (IsGamepadButtonPressed(GAMEPAD_BUTTON_LEFT_FACE_RIGHT)) { }
// Récupération du mouvement de l'axe de la manette
float axisValue = GetGamepadAxisMovement(0, GAMEPAD_AXIS_RIGHT_TRIGGER);
|
3.4 Dessin de formes
Bibliothèque SDL (SDL2) vs module de formes raylib
(rshapes).
Remarque : SDL fournit ces fonctions dans le cadre de la bibliothèque principale tandis que raylib
fournit cette fonctionnalité contenue dans le module rshapes.
SDL propose plusieurs fonctions pour restituer des points,
des lignes et des rectangles tandis que raylib fournit environ
40 fonctions pour restituer plusieurs types de formes dont Circle, Ellipsis, Ring, Triangle
et plus encore.
SDL nécessite de définir la couleur de mélange et de rendu à l'aide des fonctions SDL_SetRenderDrawBlendMode()
et SDL_SetRenderDrawColor(). raylib utilise un mode de mélange par défaut avec alpha et toutes les
fonctions Draw*() attendent un dernier paramètre Color pour la coloration/teinture par défaut.
raylib définit également des couleurs personnalisées pour plus de commodité (RED, BLUE, DARKGREEN, RAYWHITE...).
Fonctionnalités |
SDL |
raylib |
Dessin de points |
SDL_RenderDrawPoint*() |
DrawPixel() |
Dessin de ligne |
SDL_RenderDrawLine*() |
DrawLine*() |
Dessin de rectangle |
SDL_RenderFillRect*()
SDL_RenderDrawRect*() |
DrawRectangle*()
DrawRectangleLines*() |
Formes arbitraires |
SDL_RenderGeometry() |
DrawTriangle*()
DrawPoly*() |
Exemple 03a. SDL : dessiner une forme de rectangle
// Définition du mélange et la couleur pour le dessin des formes
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); // RED
// Dessin d'un rectangle rouge à la position (10, 10) de taille (200, 180)
SDL_Rect rec = { 10, 10, width, height };
SDL_RenderFillRect(renderer, &rec);
|
Exemple 03b. raylib : dessin d'une forme rectangulaire
// Dessin d'un rectangle rouge à la position (10, 10) de taille (200, 180)
DrawRectangle(10, 10, 200, 180, RED );
|
3.5 Chargement et dessin d'images et de textures
Bibliothèque SDL (SDL_Image) vs module de
textures raylib (rtextures)
SDL charge les données d'image dans les structures opaques SDL_Surface tandis que raylib utilise la
structure Image.
Fonctionnalités |
SDL |
raylib |
Initialisation/désinitialisation du système d'images |
IMG_Init()
IMG_Quit() |
pas requis |
Chargement des images |
IMG_Load() |
LoadImage() |
Chargement de la texture à partir de l'image |
SDL_CreateTextureFromSurface() |
LoadTexture()
LoadTextureFromImage() |
Déchargement de l'image et de la texture |
SDL_FreeSurface()
SDL_DestroyTexture() |
UnloadImage()
UnloadTexture() |
Dessin d'une texture |
SDL_RenderCopy()
SDL_RenderCopyEx() |
DrawTexture()
DrawTextureEx()
DrawTexturePro() |
Mise à jour des données de texture |
SDL_UpdateTexture() |
UpdateTexture() |
Lecture des données des pixels de texture |
DL_RenderReadPixels() |
LoadImageFromTexture() |
Une différence avec SDL est que raylib fournit plusieurs fonctions pour la génération et la manipulation
d'images. Par exemple, il comprend des fonctions pour générer des images (gradient, checked, white noise,
cellular) ainsi que les opérations sur les images (format, resize, rotate, crop, colorize).
SDL gère le rendu logiciel, raylib n'a pas cette option mais il propose plusieurs fonctions pour dessiner
sur des images, il s'agit en fait de capacités de rendu logiciel 2D, comme le dessin de texte.
Les deux bibliothèques gèrent plusieurs formats de pixels (SDL
et raylib).
Exemple 04a. SDL : chargement d'image/texture
// Fonctionnalité de chargement d'image requise
#include "SDL_image.h"
// Initialisation du système d'images
IMG_Init(IMG_INIT_PNG);
// Charge l'image et charge la texture à partir de celle-ci,
// notez que les types renvoyés sont en fait des pointeurs opaques
SDL_Surface *image = IMG_Load("sample.png");
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, image);
SDL_FreeSurface(surface); // L'image peut être déchargée une fois chargée dans la texture
// Les propriétés de texture doivent être interrogées en raison des pointeurs opaques
int format, access, width, height;
SDL_QueryTexture(texture, &format, &access, &width, &height);
|
Exemple 04b. raylib : chargement d'image/texture (option longue)
// Charge l'image et charge la texture à partir de cette image,
// notez que les types renvoyés sont des structures transparentes
Image image = LoadImage("sample.png");
Texture2D texture = LoadTextureFromImage(image);
UnloadImage(image); // L'image peut être déchargée une fois chargée dans la texture
// Les données de texture sont directement accessibles : texture.width, texture.height, texture.format
|
Exemple 04c. raylib : chargement d'image/texture (option courte)
// La texture peut être directement chargée à partir du fichier image,
// en fait, le processus interne est le même que celui de l'exemple précédent
Texture2D texture = LoadTexture("sample.png");
|
Gestion du rendu vers texture
Les deux bibliothèques gèrent le rendu hors ligne des textures, SDL permet de créer des textures spécifiques
SDL_Texture tandis que raylib fournit la structure RenderTexture.
Fonctionnalités |
SDL |
raylib |
Structure de données |
SDL_Texture |
RenderTexture |
Chargement de la texture de rendu |
SDL_CreateTexture |
LoadRenderTexture() |
Déchargement de la texture de rendu |
SDL_DestroyTexture() |
UnloadRenderTexture() |
Activation de la texture de rendu (pour le dessin) |
SDL_SetRenderTarget() |
BeginTextureMode()
EndTextureMode() |
Exemple 04d. SDL : chargement et dessin pour restituer la texture
// Initialisation de la texture pour le rendu hors ligne
SDL_Texture *texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_TARGET, 1024, 1024);
// Activation de la texture de rendu pour le dessin
SDL_SetRenderTarget(renderer, texture );
// Dessin d'un point dans la texture (définition du mélange et de la couleur)
SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(renderer, 255, 0, 255, 255);
SDL_RenderDrawPoint(renderer, 123, 456);
// Activation de la fenêtre pour continuer à dessiner
SDL_SetRenderTarget(renderer, NULL );
|
Exemple 04e. raylib : chargement et dessin pour le rendu de la texture
// Chargement de la texture de rendu pour le rendu hors ligne
// Remarque : par défaut, un tampon de couleur RVBA 32 bits et un tampon de rendu de profondeur sont créés.
RenderTexture target = LoadRenderTexture(1024, 1024);
// Activation de la texture de rendu pour le dessin
BeginTextureMode(target);
// Dessin d'un point dans la texture
DrawPixel(123, 456, MAGENTA);
// Activation de la fenêtre pour continuer à dessiner
EndTextureMode();
|
3.6 Chargement de polices et dessin de texte
Bibliothèque SDL (SDL_ttf) vs module de texte
raylib (rtext)
SDL utilise FreeType2 et Harfbuzz en interne, deux puissantes bibliothèques offrant des options de
rastérisation de texte de haute qualité, raylib s'appuie plutôt sur stb_truetype, une bibliothèque pour la
rastérisation des polices, avec des résultats de moindre qualité.
L'approche de rendu de texte de SDL et de raylib est un peu différente et SDL_ttf propose plusieurs
fonctions pratiques (TTF_RenderText*()) pour restituer le texte dans SDL_Surface
qui pourra ensuite être utilisé sur le dessin SDL. Le module rtext de raylib utilise les fonctionnalités de
rtextures et de rlgl ; il gère la génération automatique d'atlas de polices et le dessin de texte à l'aide
du système de traitement par lots interne rlgl.
Le module raylib rtext fournit également plusieurs fonctions pour gérer les points de code et le texte
UTF-8 ainsi que certaines fonctions de gestion de chaînes à usage général pour plus de commodité.
raylib inclut une police par défaut intégrée, initialisée à InitWindow(), afin que les utilisateurs puissent
appeler DrawText() par défaut, sans se soucier du chargement préalable d'une police.
Exemple 05a. SDL : chargement de polices et dessin de texte
// Fonctionnalité de chargement de police requise
#include <SDL_ttf.h>
// Initialise le système de polices
TTF_Init();
// Chargement de la police à partir du fichier
TTF_Font *font = TTF_OpenFont("arial.ttf", 24);
// Restitution du texte dans une surface en utilisant la police et la couleur fournies
SDL_Color color = { 255, 255, 255 };
SDL_Surface *surface = TTF_RenderText_Solid(font, "Bienvenue dans SDL", color);
// Création d'une texture à partir de la surface
SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer, surface);
// Dessin d'une texture (contenant du texte)
int texWidth = 0, texHeight = 0;
SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight);
SDL_Rect dstrect = { 0, 0, texWidth, texHeight };
SDL_RenderCopy(renderer, texture, NULL, &dstrect);
SDL_RenderPresent(renderer);
// Déchargement de la texture (contenant du texte)
SDL_DestroyTexture(texture);
SDL_FreeSurface(surface);
// Déchargement de la police et ferme le système de polices
TTF_CloseFont(font);
TTF_Quit();
|
Exemple 05b. raylib : dessin de texte (police interne par défaut)
// Dessin du texte sur l'écran à la position (100, 200), hauteur 20 pixels, couleur ROUGE
DrawText("Bienvenue dans raylib", 100, 200, 20, RED);
|
Exemple 05c. raylib : chargement de police et dessin de texte (police personnalisée)
// Chargement de la police à partir du fichier
// Remarque : raylib génère automatiquement un atlas de polices avec certains paramètres par défaut :
// 32 pixels de hauteur (taille), 95 caractères, 4 pixels de remplissage
// LoadFontEx() est également fourni pour un contrôle plus fin de la taille de la police et
// les points de code requis
Font font = LoadFont("arial.ttf");
// Dessin du texte à l'écran en utilisant la police chargée, le système de traitement par lots interne
// rend ce processus très efficace
DrawTextEx(font, "Bienvenue dans raylib", (Vector2){ 10.0f, 10.0f }, 20, 1, RED);
// Déchargement de la police
UnloadFont(font);
|
3.7 Chargement et dessin de modèles 3D
Rien dans SDL vs module de modèles raylib (rmodels)
raylib fournit un module axé sur le rendu 3D. Il s'agit d'une fonctionnalité de haut niveau non
incluse dans SDL.
Ce module comprend des fonctions pour dessiner des formes 3D de base (cube, sphère, cône...), des
fonctions pour générer des modèles 3D (cube, cylindre, champ de hauteur...), des fonctions pour charger
des modèles/matériaux/animations à partir de fichiers 3D (.obj, .iqm, .gltf, .vox) et quelques fonctions
pour vérifier les collisions 3D de base (Ray, BoundingBox).
3.8 Système audio
bibliothèque SDL (SDL2 et
SDL_Mixer) vs module audio raylib
(raudio)
Les deux bibliothèques offrent des fonctionnalités similaires, elles permettent de charger et de lire
des données audio statiques et dynamiques (lecture en continu) et de gérer le périphérique audio.
La bibliothèque principale SDL fournit la fonctionnalité de gestion des périphériques audio (initialisée
par SDL_Init() ou SDL_InitSubSystem()) alors que SDL_Mixer fournit des fonctionnalités de chargement
et de lecture de plusieurs formats de fichiers audio.
Le module audio de raylib contient des fonctionnalités de gestion de périphériques ainsi que le chargement
et la lecture de fichiers audio. Pour la gestion des périphériques audio, il s'appuie sur la bibliothèque
d'en-tête de fichier unique miniaudio, qui gère plusieurs
arrière-plans logiciels audio et certaines fonctionnalités avancées.
SDL gère les effets audio tandis que raylib a ajouté une première approche expérimentale des effets en
temps réel à partir de sa version 4.2.
Fonctionnalités |
SDL |
raylib |
Initialisation du système audio |
Mix_Init()
Mix_OpenAudio() |
InitAudioDevice() |
Fermeture du système audio |
Mix_CloseAudio()
Mix_Quit()SDL_Texture |
CloseAudioDevice() |
Chargement/déchargement du son |
Mix_LoadWAV()
Mix_FreeChunk() |
LoadSound()
UnloadSound() |
Chargement/déchargement de la musique |
Mix_LoadMUS()
Mix_FreeMusic() |
LoadMusicStream()
UnloadMusicStream() |
Joue un son |
Mix_PlayChannel() |
PlaySound() |
Joue une musique |
Mix_PlayMusic() |
PlayMusicStream()
UpdateMusicStream() |
Structure de données sonores |
Mix_Chunk |
Sound |
Structure de données musicales |
Mix_Music |
Music |
Exemple 06a. SDL : chargement et lecture audio
#include "SDL_mixer.h" // Gestion des périphériques audio et chargement des fichiers audio requis
// Initialisation du système audio
Mix_Init(MIX_INIT_OGG);
Mix_OpenAudio(44100, MIX_DEFAULT_FORMAT, 2, 2048);
// Chargement du fichier son (données audio complètes chargées en mémoire)
Mix_Chunk *sound = Mix_LoadWAV("Assets/sound.wav");
// Chargement du fichier musical (un seul morceau de données, destiné à la lecture en continu)
Mix_Music *music = Mix_LoadMUS("Assets/music.ogg");
// Joue le fichier son une fois
Mix_PlayChannel(-1, sound, 0);
// Commence à jouer de la musique en continu
Mix_PlayMusic(music, -1);
// Décharge les données sonores et musicales
Mix_FreeMusic(music);
Mix_FreeChunk(sound);
// Ferme le système audio
Mix_CloseAudio();
Mix_Quit();
|
Exemple 06b. raylib : chargement et lecture audio
// Initialisation du périphérique audio (configuration par défaut : 44100 Hz, deux canaux)
InitAudioDevice();
// Chargement du fichier son (données audio complètes chargées en mémoire)
Sound sound = LoadSound("Assets/sound.wav");
// Chargement du fichier musical (un seul morceau de données, destiné à la lecture en continu)
Music music = LoadMusicStream("Assets/music.ogg");
// Joue un fichier son une fois
PlaySound(sound);
// Commence à jouer de la musique en continu
PlayMusicStream(music);
// Remplissage des tampons du flux de musique s'ils sont déjà traités (doit être appelé par l'utilisateur)
UpdateMusicStream(music);
// Déchargement des données sonores et musicales
UnloadMusic(music);
UnloadSound(sound);
// Fermeture du périphérique audio
CloseAudioDevice();
|
3.9 Système de réseau
Bibliothèque SDL (SDL_net.dll) vs rien
SDL inclut un module pour la mise en réseau alors que raylib ne gère pas la mise en réseau.
Il convient de mentionner qu'à un moment donné, le module rnet était disponible mais il était bogué
et non maintenu, il a donc finalement été supprimé.
4. Conclusions
SDL offre un contrôle plus fin de la plate-forme que raylib. raylib fournit des fonctionnalités de niveau
supérieur et prend plusieurs décisions pour l'utilisateur afin de simplifier l'utilisation de l'API.
SDL existe depuis plus de 25 ans et il s'agit d'une bibliothèque éprouvée, utilisée dans de nombreux produits
professionnels. raylib a environ 9 ans et a été créé à l'origine pour l'éducation. Aujourd'hui encore, la
plupart de ses utilisateurs sont des étudiants et des passionnés.
Heureusement, à l'avenir, cet article aidera les utilisateurs à décider laquelle des deux bibliothèques
correspond le mieux aux besoins de leurs produits.
Merci d'avoir lu et n'hésitez pas à commenter
ce comparatif avec des informations supplémentaires ou des améliorations. :)
|