|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Présentation SDL2 (Simple DirectMedia Layer version 2) est une bibliothèque logicielle libre utilisée pour créer des applications multimédias en deux dimensions (jeux, démos,...). Son succès est dû à sa portabilité sur la plupart des plates-formes et à sa facilité d'implémentation dans de nombreux langages, dont le langage C (ce qui nous intéresse ici). Tout cela a fini par susciter mon intérêt et en découvrant la facilité de son implémentation en langage C, je me suis mis à développer une démo "oldschool" (JUST FOR FUN, sortie en 2022) : www.morphos-storage.net/?find=just-for-fun. Puis un petit jeu, réadaptation du célèbre Pong (MorPhONG, sorti en 2023) : www.morphos-storage.net/?find=MorPhONG. Aujourd'hui, ce tutoriel est là pour vous introduire un cas simple d'utilisation de SDL2 : l'animation d'une image dans une fenêtre (un joli morpho bleu qui papillonne). Ceci sur MorphOS, mais le programme peut tout aussi bien être recompilé sur d'autres plates-formes comme AmigaOS 4 (histoire de voir un joli morpho bleu papillonner sur AmigaOS 4 ^^). Et tant qu'à faire, en langage C afin de profiter des meilleures performances du système. La présentation est volontairement la plus détaillée possible. Avec des rudiments en programmation (variables, fonctions, if, while) et sans maîtriser le langage C, vous devriez en comprendre le principe tant son approche est simple. En espérant susciter d'autres intérêts et au final, pourquoi pas, motiver le développement de nouveaux jeux et démos sur nos "Amiga NG". ;) Prérequis Disposer de la dernière version de MorphOS : www.morphos-team.net/downloads. Afin de disposer du langage C et de son compilateur GCC, télécharger et installer la dernière version du SDK de MorphOS (Software Development Kit ou trousse de développement logiciel) : www.morphos-team.net/downloads. Puis télécharger et installer la dernière version de SDL2 sur MorphOS : www.morphos-storage.net/?find=SDL_2. Lors de l'installation, pour vos développements avec SDL2, attention à bien cocher l'option "Yes i have SDK installed" pour la question "Do you want SDK Files? (you need last SDK installed)". Fichiers du programme étudié
Image bitmap (BMP) Afin d'avoir tout de suite une idée du résultat, n'hésitez pas à lancer le programme exécutable "Butterfly" (pour le quitter : touche "Échap" ou un clic sur la croix de la fenêtre). Venons-en maintenant à l'explication détaillée du code source, de la première ligne à la dernière ligne. Attention : le langage C est sensible à la casse, il fait la différence entre les minuscules et les majuscules. Inclusion du fichier d'en-tête "SDL.h" de la bibliothèque SDL2
Ce fichier d'en-tête contient les déclarations et les définitions nécessaires pour utiliser les fonctionnalités de SDL2 dans notre programme. Déclaration des constantes et des variables globales à tout le programme
Ces lignes déclarent les constantes MAXW à la valeur 800 et MAXH à la valeur 600 qui seront utilisées pour la taille de notre fenêtre (en pixels).
Ces lignes déclarent des pointeurs (nom de variable commençant par *) vers des objets SDL2.
Cette fonction sera appelée pour quitter proprement le programme. Elle n'a pas besoin de paramètres (parenthèses vides) et ne renvoie rien (void). Son code est entre accolades {}.
Chacune de ces lignes "if" teste si l'objet en question (texture_butterfly, butterfly, renderer, window) est défini et dans ce cas le détruit avec la fonction SDL2 correspondante (SDL_DestroyTexture, SDL_FreeSurface, SDL_DestroyRenderer, SDL_DestroyWindow). Ceci afin de libérer proprement les ressources allouées à ces objets (et éviter les fuites de mémoire).
Cette fonction nettoie et libère toutes les ressources utilisées par la bibliothèque SDL2 (celles allouées lors de son initialisation).
Cette fonction quitte définitivement le programme en renvoyant le code retour 0 (pas d'erreur). Définition de la fonction "gestion_evenements"
Cette fonction sera appelée pour gérer les évènements éventuellement survenus (frappe de la touche "Échap", fermeture de la fenêtre,...). Elle n'a pas besoin de paramètres (parenthèses vides) et ne renvoie rien (void). Son code est entre accolades {}.
Cette ligne déclare la variable locale "event" de type SDL_Event. Dans SDL2, les évènements sont représentés par des structures de données de type SDL_Event.
Tous les évènements survenus (clavier, souris,...) sont en attente dans la file d'attente des évènements de SDL2. La fonction "SDL_PollEvent(&event)" vérifie s'il y a un évènement en attente dans cette file, dans ce cas renvoie 1 sinon 0. La fonction copie également cet évènement dans la structure "event" passée en paramètre entre parenthèses (le & est obligatoire pour pouvoir récupérer en retour la modification de "event"). Cette boucle "while" permet donc d'appeler la fonction SDL_PollEvent tant qu'il y a un évènement dans la file d'attente, et pour chaque "event" récupéré de le traiter (grâce au traitement du "while" qui suit, entre accolades).
La structure "switch" permet de comparer une variable à plusieurs valeurs (cas/case) et pour chacune de réaliser un traitement spécifique (on pourrait le faire avec des "if"). Ici, la variable comparée est "event.type" contenant le type de l'évènement à traiter.
Dans le cas où le type de l'évènement est la frappe d'une touche (case SDL_KEYDOWN), si la touche est la touche "Échap" (if (event.key.keysym.sym == SDLK_ESCAPE)) alors la fonction "fin" est appelée pour quitter le programme. Enfin, le "break" permet de sortir du "switch" (car cas traité).
Dans le cas où le type de l'évènement est un évènement sur la fenêtre (case SDL_WINDOWEVENT), si l'évènement est la fermeture de la fenêtre (if (event.window.event == SDL_WINDOWEVENT_CLOSE)) alors la fonction "fin" est aussi appelée pour quitter le programme. Enfin, le "break" permet de sortir du "switch" (car cas traité). D'autres évènements peuvent survenir (autres touches, autres clics,...), mais ceux-ci ne sont donc pas traités. Définition de la fonction "main"
Cette fonction est la fonction principale du programme. Lors du lancement de celui-ci, c'est la première appelée. Son code est entre accolades {}. Ses paramètres définis entre parenthèses (int argc, char *argv[]) permettent de gérer les arguments éventuellement transmis au programme lors de son lancement. "argc" contient le nombre d'arguments transmis (entier, type "int") et "argv" la liste des arguments transmis (tableau pointant sur des chaînes de caractères, type "char"). Mais ceux-ci ne seront pas exploités dans notre programme (car lancé sans arguments). Elle renvoie un entier ("int" devant "main"), le code retour de la fonction "exit" servant à quitter le programme (revoir la fonction "fin" ci-dessus).
Cette ligne déclare des variables locales de type entier non signé (unsigned int), donc positives.
Cette ligne déclare des variables locales de type entier signé (int), donc positives ou négatives.
Cette fonction initialise la bibliothèque SDL2 pour utiliser la vidéo (SDL_INIT_VIDEO) afin de créer des fenêtres et effectuer leurs rendus graphiques. Il pourrait y avoir d'autres paramètres, par exemple pour utiliser l'audio.
Cette fonction crée notre fenêtre "window" (pointeur de fenêtre déclaré plus haut) avec les paramètres entre parenthèses.
Cette fonction crée le moteur de rendu "renderer" (pointeur de renderer déclaré plus haut) pour notre fenêtre "window" avec les paramètres entre parenthèses.
Ce renderer sera donc utilisé pour effectuer le rendu des graphiques dans notre fenêtre.
Cette fonction définit la couleur de dessin de notre renderer : noire (0, 0, 0) et sans transparence (SDL_ALPHA_OPAQUE). La fonction "SDL_RenderClear(renderer);" (plus bas) effacera donc le renderer en noir, d'où le fond noir de la fenêtre. Cette fonction est juste là pour vous introduire cette fonctionnalité. On aurait pu s'en passer car la couleur de dessin d'un renderer est déjà par défaut le noir.
Cette fonction charge l'image bitmap (BMP) du fichier "Butterfly.bmp" en objet surface "butterfly" (pointeur de surface déclaré plus haut).
Cette fonction crée la texture "texture_butterfly" pour notre renderer (pointeur de texture déclaré plus haut), cela à partir des données de la surface "butterfly" (de notre image). Pour rappel : une texture est une structure de données utilisée pour stocker des données d'image afin de pouvoir les exploiter dans le rendu/renderer de la fenêtre.
Cette ligne crée la structure "srcrect_butterfly" de type SDL_Rect. Celle-ci contient les valeurs du rectangle de notre image d'origine (en pixels).
Ce "while" est une boucle infinie (1 correspond à "vrai"). C'est elle qui gère le renderer et donc l'animation de l'image dans la fenêtre. Elle n'est quittée que par la frappe de la touche "Échap" ou par la fermeture de la fenêtre. Son code est entre accolades {}. Le principe de ce genre de traitement est toujours le même avec SDL2, pour chaque cycle :
Notre fonction qui gère les évènements éventuellement survenus (frappe de la touche "Échap", fermeture de la fenêtre,...), voir plus haut.
Cette fonction efface le contenu actuel du renderer, en le remplissant avec la couleur de fond actuellement définie (le noir défini plus haut par la fonction SDL_SetRenderDrawColor).
Incrémente la position horizontale "x" de notre image de la valeur "sens_x" (initialisée plus haut à la valeur de la variable "vitesse").
Incrémente la position verticale "y" de notre image de la valeur "sens_y" (initialisée plus haut à la valeur de la variable "vitesse"). Notre papillon se déplacera donc en diagonale, d'autant plus rapidement que la valeur de "vitesse/sens_x/sens_y" est grande.
Si la position horizontale "x" de notre image est inférieure à 0 ou supérieure à "MAXW" (largeur maximale de la fenêtre), alors le sens de déplacement horizontal de notre image change (sens_x = -sens_x : valeur opposée de "sens_x").
Si la position verticale "y" de notre image est inférieure à 0 ou supérieure à "MAXH-butterfly_h" (hauteur maximale de la fenêtre moins la hauteur de notre image papillon), alors le sens de déplacement vertical de notre image change (sens_y = -sens_y : valeur opposée de "sens_y"). Notre papillon rebondira donc sur les bords de la fenêtre (droit/0 et gauche/MAXW, haut/0 et bas/MAXH-butterfly_h), sans sortir de celle-ci.
Augmente la largeur actuelle de notre image papillon "butterfly_l" de la valeur "battements".
Si la largeur actuelle de notre image papillon "butterfly_l" est inférieure à 0 ou supérieure à "butterfly_w" (largeur maximale de notre image papillon), alors le sens du battement d'ailes change (battements = -battements : valeur opposée de "battements"). Notre papillon battra donc des ailes, d'autant plus vite que la valeur de "battements" est grande.
Cette ligne crée la structure "dstrect_butterfly" de type SDL_Rect. Celle-ci contient les valeurs du rectangle de notre image résultat (en pixels), déterminées à partir de celles qu'on vient de calculer.
La position (horizontale et verticale) est toujours déterminée par rapport au coin supérieur gauche de l'image (et non son centre).
Cette fonction copie sur notre "renderer" le rectangle résultat "dstrect_butterfly" (image transformée), dont les données sont issues de notre texture "texture_butterfly" et sélectionnées par le rectangle de départ "srcrect_butterfly" (correspondant à notre image d'origine). Dans notre programme, le rectangle de départ "srcrect_butterfly" prend toute la texture (car on veut toute l'image), mais on pourrait en prendre qu'une partie. Toutes les transformations entre source et destination sont possibles, permettant tous types d'animations. Pour le même cycle, on pourrait copier sur le renderer d'autres textures transformées, voire dessiner d'autres éléments (lignes, cercles,...). Tous les rendus graphiques sont donc possibles.
Enfin, cette fonction met à jour l'affichage de la fenêtre avec tout ce qui a été rendu sur le renderer. Fin du code source. Compilation et exécution du programme Une fois le fichier du code source enregistré (avec le nom "Butterfly.c"), il faut le compiler pour obtenir son fichier exécutable. Il faudra également le recompiler après chaque modification du code source. Pour cela, ouvrir un terminal Shell et aller dans le répertoire contenant ce fichier (à l'aide de la commande de changement de répertoire "cd"). Pour rappel : le fichier de l'image utilisée "Butterfly.bmp" doit être présent dans ce même répertoire (vérifier avec la commande "dir"). Puis taper la commande suivante pour le compiler :
Pour lancer le programme, il suffit de taper le nom de son fichier exécutable "Butterfly", ou de double-cliquer sur son icône dans le dossier concerné de l'interface graphique. Et vous devriez voir apparaître la fenêtre avec notre joli morpho bleu qui papillonne à l'écran. :) L'Amiga a sa Boing Ball, MorphOS a maintenant son Flying Morpho ! ^^ Le résultat final (image réduite) L'animation doit être fluide. Si elle est saccadée, relancer le programme après avoir décoché l'option "Affichage amélioré" ("Enhanced display" en anglais) en éditant votre écran dans les préférences de MorphOS. Code source complet Pour conclure le tout, voici le code source complet du programme :
|