Navigation▲
Tutoriel précédent : vos premières fenêtres |
Tutoriel suivant : les événements |
I. Introduction▲
Vous savez créer un projet avec la SDL 2, initialiser la bibliothèque, ouvrir une fenêtre, vous pouvez maintenant remplir le contenu de la fenêtre en affichant un premier sprite.
Un sprite est une image (un tableau contenant des couleurs), pouvant être généré à la volée par le programme, ou plus simplement, chargé à partir d'un fichier et qui sera copié une ou plusieurs fois dans la fenêtre de destination à un emplacement voulu.
II. Méthode SDL 1.2▲
L'affichage des sprites comme cela était fait avec la SDL 1.2 est encore d'actualité dans cette nouvelle version de la bibliothèque. Toutefois, il faut bien comprendre que celle-ci n'est pas accélérée par le matériel et sera donc plus lente à exécuter. En contrepartie, cette méthode est simple à mettre en place et est la base pour la méthode utilisant l'accélération graphique avec la SDL 2.0.
II-A. Type de données utiles▲
Avant de commencer à voir les fonctions dont vous avez besoin pour afficher un sprite sur l'écran, il est nécessaire de connaître les types de données utilisés par ces fonctions.
II-A-1. SDL_Surface▲
SDL_Surface est une structure utilisée pour contenir un ensemble de pixels et les informations nécessaires pour utiliser ces pixels. Voici la liste des champs de la structure :
Type |
Nom |
Description |
SDL_PixelFormat* |
format |
Le format des pixels stockés dans la surface. |
int |
w |
La largeur en pixels de la surface (lecture seule). |
int |
h |
La hauteur en pixels de la surface (lecture seule). |
int |
pitch |
La longueur d'une ligne de pixels en octets (lecture seule). |
void* |
pixels |
Le pointeur sur les pixels de la surface. |
void* |
userdata |
Un pointeur sur des données utilisateur. |
SDL_Rect |
clip_rect |
Un rectangle de découpage des opérations de blits sur cette surface. Vous devez le définir avec la fonction SDL_SetClipRect() (lecture seule). |
int |
refcount |
Un compteur de référence pouvant être incrémenté par l'application. |
D'autres champs sont aussi accessibles, mais ils sont internes au fonctionnement de la SDL. Ainsi, il est déconseillé de tenter de les utiliser tels quels et ne doivent être accédés qu'en utilisant des fonctions mises en place pour cela.
Il en est de même pour les champs indiqués en lecture seule : vous ne devez en aucun cas les modifier.
II-A-2. SDL_Rect▲
SDL_Rect représente un rectangle. Pour cela, quatre champs sont définis :
Type |
Nom |
Description |
int |
x |
La position du coin supérieur gauche du rectangle sur l'axe des X. |
int |
y |
La position du coin supérieur gauche du rectangle sur l'axe des Y. |
int |
w |
La largeur du rectangle. |
int |
h |
La hauteur du rectangle. |
Il est possible de définir un rectangle en spécifiant son coin supérieur gauche et son coin inférieur droit, mais, sachant que les informations de largeur et de hauteur sont très utilisées, il est préférable de ne pas les calculer à chaque utilisation.
II-B. Chargement Sprite▲
Le sprite doit être lu à partir d'un fichier image sur le disque dur (ou à partir d'une zone mémoire). Pour cela, la SDL propose la fonction SDL_LoadBMP() afin de charger le fichier (ou SDL_Load_RW() ou encore SDL_CreateRGBSurfaceFrom() pour lire une zone mémoire).
Comme le nom de la fonction l'indique, elle ne chargera que des fichiers BMP. Pour pouvoir lire d'autres formats (GIF, PNG, JPG…), vous pouvez utiliser la bibliothèque complémentaire à la SDL : SDL_image.
II-B-1. Les paramètres de SDL_LoadBMP()▲
La fonction SDL_LoadBMP() charge une surface à partir d'un fichier BMP, ainsi elle prend en paramètre une chaine de caractères : chemin menant au fichier BMP à charger.
II-B-2. La valeur de retour de SDL_LoadBMP()▲
Lorsque le chargement est réussi, la fonction SDL_LoadBMP() retourne un pointeur sur SDL_SurfaceSDL_Surface, sinon, la fonction retourne NULL. Vous pouvez connaître la raison avec SDL_GetError().
II-C. Affichage du sprite▲
Une fois le sprite chargé et donc que vous avez une SDL_SurfaceSDL_Surface lui correspondant, vous pouvez maintenant copier votre surface à l'écran. Pour cela, vous pouvez utiliser SDL_BlitSurface(), mais cela demande une petite préparation.
II-C-1. Définition de la destination du sprite▲
Vous devez définir l'endroit où votre sprite sera copié en utilisant la structure SDL_RectSDL_Rect :
SDL_Rect dest =
{
640
/
2
-
pSprite->
w/
2
,480
/
2
-
pSprite->
h/
2
, 0
, 0
}
;
Les deux premiers champs de la structure SDL_Rect servent à indiquer où nous voulons copier le sprite (position de son coin supérieur gauche). Les deux derniers champs sont inutiles pour la fonction SDL_BlitSurface().
Ici, nous voulons centrer le sprite dans notre fenêtre de résolution 640 x 480. Pour ce faire, nous calculons le centre de la fenêtre : 640/2 , 480/2. Mais cela ne suffit pas, car le sprite est dessiné en partant de son coin supérieur gauche. Il est donc nécessaire de le décaler afin que son centre corresponde au centre de la fenêtre. Le centre du sprite s'obtient en divisant la largeur et la hauteur par deux (comme pour la fenêtre). Nous pouvons récupérer la largeur et la hauteur de la structure SDL_SurfaceSDL_Surface avec les champs 'w' et 'h' : pSprite->w/2, pSprite->h/2. Connaissant le centre du sprite, il est maintenant possible de nous décaler pour faire correspondre celui-ci avec le centre de l'image : centre_de_l'image - centre_du_sprite. Ce qui donne dans le code : 640/2 - pSprite->w/2,480/2 - pSprite->h/2.
Si vraiment vous n'y arrivez pas, prenez une feuille de papier, dessiner un rectangle assez grand pour votre fenêtre, un carré pour votre sprite et écrivez les positions x et y des points. Cela devrait devenir clair.
En place de « 640 » et « 480 », il serait judicieux de récupérer la taille de la fenêtre avec la fonction SDL_GetWindowSize(). Ainsi, le code resterait correct, quelle que soit la résolution.
II-C-2. Récupération de la surface destination▲
SDL_BlitSurface() nécessite un pointeur sur une instance de SDL_Surface comme destination de son opération de copie. Le sprite doit être affiché dans la fenêtre, mais celle-ci est de type SDL_Window. Il est possible de récupérer la SDL_Surface associée à votre fenêtre (SDL_Window) grâce à la fonction SDL_GetWindowSurface(). Comme nous l'avons vu dans le tutoriel précédent, la structure SDL_Window contient une SDL_Surface représentant les pixels de la fenêtre. Cette surface peut être récupérée comme suit :
SDL_Surface pWinSurf =
SDL_GetWindowSurface
(
pWindow);
II-C-2-a. Les paramètres de SDL_GetWindowSurface()▲
La fonction SDL_GetWindowSurface() n'accepte qu'un seul paramètre, qui est un pointeur sur une SDL_Window, soit, la fenêtre sur laquelle vous voulez dessiner.
II-C-2-b. La valeur de retour de SDL_GetWindowSurface()▲
La fonction retourne un pointeur sur la SDL_Surface associée à la fenêtre passée en argument. Si une erreur se produit, la fonction retournera NULL et vous pourrez récupérer quelques détails supplémentaires avec SDL_GetError().
II-C-3. Copie du sprite dans la fenêtre▲
Vous avez tous les éléments pour copier votre sprite dans la fenêtre :
- la surface source, chargée avec SDL_LoadBMP()Chargement Sprite ;
- la surface de destination récupérée grâce à SDL_GetWindowSurface() ;
- l'emplacement voulu pour le spriteDéfinition de la destination du sprite.
Il suffit d'appeler SDL_BlitSurface() avec les paramètres préparés :
SDL_BlitSurface
(
pSprite,NULL
,SDL_GetWindowSurface
(
pWindow),&
dest);
Vous remarquez que ce sont des pointeurs sur des SDL_Rect qui sont attendus par la fonction. Les variables peuvent donc être modifiées par la fonction et c'est le cas, lorsque vous affichez un sprite qui sort de l'écran. Le SDL_Rect résultant correspondra uniquement à la partie du sprite visible sur l'écran.
Par exemple, si vous essayez d'afficher un sprite qui sort de l'écran par la gauche, donc qui aura une coordonnée en X négative, la fonction vous retournera un X valant zéro et une largeur de sprite diminuée.
II-C-3-a. Les paramètres de SDL_BlitSurface()▲
SDL_BlitSurface() demande quatre paramètres :
- la surface source à copier ;
- la région source (un SDL_RectSDL_Rect représentant le sous-rectangle source à copier). Si ce paramètre est NULL, la globalité du sprite est copiée ;
- la surface destination (où copier la surface source) ;
- l'emplacement destination (même si un SDL_RectSDL_Rect est nécessaire, seuls les deux premiers paramètres, x et y, sont utilisés).
II-C-3-b. La valeur de retour de SDL_BlitSurface()▲
SDL_BlitSurface() retourne un entier valant zéro si aucune erreur ne s'est produite, ou un nombre négatif si un problème est apparu. Dans ce cas, vous pouvez récupérer l'erreur avec SDL_GetError().
II-C-4. Affichage ▲
Arrivé ici, rien ne va apparaître à l'écran. En effet, SDL_BlitSurface() copiera le sprite sur la surface de l'écran, sauf que celle-ci est une zone mémoire et ne correspond pas à l'écran physique. Pour afficher cette surface à l'écran, il suffit d'appeler SDL_UpdateWindowSurface() qui forcera la mise à jour de la fenêtre et prendra donc en compte le changement de la surface :
SDL_UpdateWindowSurface
(
pWindow);
Voilà, vous pouvez maintenant voir le sprite à l'écran.
II-C-4-a. Le paramètres de SDL_UpdateWindowSurface()▲
La fonction prend qu'une instance de SDL_Window de la fenêtre à mettre à jour.
II-C-4-b. La valeur de retour de SDL_UpdateWindowSurface()▲
La fonction retourne zéro si tout se passe correctement ou un entier négatif en cas d'erreur. Vous pouvez appeler SDL_GetError() pour avoir plus d'information sur la source de l'erreur.
II-C-5. Libération des ressources liées au sprite▲
Tout comme pour la fenêtre, une fois que vous n'avez plus besoin du sprite, vous devez libérer la mémoire associée. La fonction pour ce faire est SDL_FreeSurface() :
SDL_FreeSurface
(
pSprite);
II-C-5-a. Le paramètre de SDL_FreeSurface()▲
SDL_FreeSurface() accepte simplement un pointeur sur la SDL_Surface à libérer.
II-C-6. Récapitulatif▲
Voici le code d'affichage d'un sprite :
SDL_Surface*
pSprite =
SDL_LoadBMP
(
"
./data/dvp.bmp
"
);
if
(
pSprite )
{
SDL_Rect dest =
{
640
/
2
-
pSprite->
w/
2
,480
/
2
-
pSprite->
h/
2
, 0
, 0
}
;
SDL_BlitSurface
(
pSprite,NULL
,SDL_GetWindowSurface
(
pWindow),&
dest); // Copie du sprite
SDL_UpdateWindowSurface
(
pWindow); // Mise à jour de la fenêtre pour prendre en compte la copie du sprite
SDL_Delay
(
3000
); /* Attendre trois secondes, que l'utilisateur voit la fenêtre */
SDL_FreeSurface
(
pSprite); // Libération de la ressource occupée par le sprite
}
else
{
fprintf
(
stdout,"
Échec de chargement du sprite (%s)
\n
"
,SDL_GetError
(
));
}
III. Méthode SDL 2.0▲
La version 2 de la bibliothèque apporte une nouvelle façon d'afficher un sprite. Cette nouvelle méthode permet à la bibliothèque d'optimiser le rendu et de le faire s'exécuter sur le GPU. Toutefois, même si elle apporte des nouveautés, les bases sont les mêmes que ce qui a été vu dans la méthode d'affichage avec la SDL 1.2. Ainsi, les structures seront réutilisées, ainsi que la méthode pour charger le sprite.
III-A. Type de données utiles▲
III-A-1. SDL_Renderer▲
La structure SDL_Renderer peut être assimilée à un pinceau. C'est grâce à SDL_Renderer que vous allez pouvoir afficher des éléments dans la fenêtre et cela, en utilisant la carte graphique, si vous le souhaitez.
III-A-2. SDL_Texture▲
La SDL_Texture peut être perçue comme une SDL_SurfaceSDL_Surface, mais placée dans la mémoire de la carte graphique (et donc, utilisable par celle-ci). Vous pouvez la créer à partir d'une SDL_Surface.
Pour rappel, la mémoire CPU (communément appelée mémoire RAM) et la mémoire GPU (appelée VRAM, 'V' pour « Video ») sont deux mémoires distinctes et non partagées. Un élément présent dans l'une des mémoires ne sera pas accessible dans la seconde. Pour rendre accessibles des données d'une mémoire à l'autre, une opération de copie est nécessaire.
III-B. Création d'un SDL_Renderer▲
L'instance de SDL_Renderer peut être créée à partir d'une fenêtre avec la fonction SDL_CreateRenderer() :
SDL_Renderer *
pRenderer =
SDL_CreateRenderer
(
pWindow,-
1
,SDL_RENDERER_ACCELERATED);
III-B-1. Les paramètres de SDL_CreateRenderer()▲
La fonction SDL_CreateRenderer() accepte trois paramètres :
- la fenêtre (SDL_Window) pour laquelle le SDL_Renderer doit être créé ;
- un index spécifiant le SDL_Renderer à initialiser ou -1 pour utiliser le premier supportant les options indiquées ;
- des options sur le SDL_Renderer.
III-B-1-a. Options du SDL_Renderer▲
La SDL 2 propose quatre options lors de la création d'un SDL_Renderer :
SDL_RENDERER_SOFTWARE |
Le SDL_Renderer est purement logiciel (solution de repli). |
SDL_RENDERER_ACCELERATED |
Le SDL_Renderer utilise l'accélération matérielle. |
SDL_RENDERER_PRESENTVSYNC |
Le SDL_Renderer est synchronisé au rafraichissement de la fenêtre. |
SDL_RENDERER_TARGETTEXTURE |
Le SDL_Renderer supporte le rendu vers une texture. |
III-B-2. La valeur de retour de SDL_CreateRenderer()▲
SDL_CreateRenderer() retourne en toute logique un pointeur sur une instance de SDL_Renderer. En cas d'erreur la fonction retourne NULL et des informations sur celle-ci seront disponibles en appelant SDL_GetError().
III-C. Créer la SDL_Texture à partir d'une SDL_Surface▲
La fonction permettant de créer une SDL_Texture à partir d'une SDL_Surface est SDL_CreateTextureFromSurface() :
SDL_Texture*
pTexture =
SDL_CreateTextureFromSurface
(
pRenderer,pSprite);
Une fois la SDL_Texture créée, vous pouvez libérer la SDL_Surface avec SDL_FreeSurface()Libération des ressources liées au sprite. En effet, la fonction copie les données de SDL_Surface.
III-C-1. Les paramètres de SDL_CreateTextureFromSurface()▲
SDL_CreateTextureFromSurface() nécessite deux paramètres :
- le SDL_Renderer pour lequel la texture est créée ;
- la SDL_Surface sur laquelle se baser pour créer la SDL_Texture.
III-C-2. La valeur de retour de SDL_CreateTextureFromSurface()▲
La fonction retourne un pointeur sur la SDL_Texture nouvellement créée. Si une erreur est survenue, un pointeur NULL sera retourné et un message d'erreur explicite pourra être récupéré avec SDL_GetError().
III-D. Récupération de la taille de la texture▲
Pour la copie du sprite, nous avons besoin de la taille de la texture que nous utilisons. Pour récupérer des informations sur cette dernière, nous devons utiliser SDL_QueryTexture(). Son utilisation est la suivante :
Uint32 format;
int
access =
0
;
int
largeur =
0
;
int
hauteur =
0
;
SDL_QueryTexture
(
texture,&
format, &
access, &
largeur, &
hauteur);
La fonction remplira les variables passées en paramètres avec les informations concernant la texture.
Si vous n'avez pas besoin du format et de l'état d'accès de la texture, vous pouvez passer NULL.
III-D-1. Les paramètres de SDL_QueryTexture()▲
La fonction accepte quatre paramètres :
- la texture pour laquelle vous voulez récupérer des informations ;
- le format des pixels de la texture ;
- l'état d'accès de la texture ;
- la largeur ;
- la hauteur.
Le format, l'état d'accès, la largeur et la hauteur sont des pointeurs afin de permettre à la fonction d'écrire les données.
III-D-2. La valeur de retour de SDL_QueryTexture()▲
La fonction retourne zéro en cas de réussite ou une valeur négative en cas d'erreur. SDL_GetError() donnera une description de l'erreur.
III-E. Copie du sprite▲
La copie du sprite en utilisant un SDL_Renderer s'effectue avec SDL_RenderCopy(). De façon similaire à SDL_BlitSurface()Copie du sprite dans la fenêtre, nous avons préparé les éléments suivants :
- le SDL_Renderer à utiliserCréation d'un SDL_Renderer ;
- la SDL_Texture à copierCréer la SDL_Texture à partir d'une SDL_Surface.
Voici son utilisation :
SDL_Rect dest =
{
640
/
2
-
largeur/
2
,480
/
2
-
hauteur/
2
, largeur, hauteur}
;
SDL_RenderCopy
(
pRenderer,pTexture,NULL
,&
dest);
Le calcul de la position du sprite peut paraître compliqué. Une explication est donnée dans la partie pour la SDL 1.2Définition de la destination du sprite.
III-E-1. Les paramètres de SDL_RenderCopy()▲
Cette fonction prend en paramètres :
- le SDL_Renderer (sachant que le SDL_Rendererest créé à partir d'une fenêtre, il affichera le sprite sur celle-ci) ;
- la SDL_Texture à copier ;
- le rectangle source (permettant ainsi de ne copier qu'une sous-partie d'une texture) ;
- le rectangle destination.
SDL_RenderCopy() prend en compte tous les champs du rectangle destination. En effet, les SDL_Renderer sont capables de faire du redimensionnement de sprite à la volée, ainsi, les informations de largeur et de hauteur sont utiles pour spécifier un quelconque redimensionnement.
III-E-2. La valeur de retour de SDL_RenderCopy()▲
La fonction retourne zéro lorsque tout a bien été ou un entier négatif en cas d'erreur. SDL_GetError() donnera une description de l'erreur.
III-F. Affichage▲
Encore une fois, la fenêtre est toujours vide à cette étape. Pour la mettre à jour, il faut utiliser la fonction SDL_RenderPresent() :
SDL_RenderPresent
(
pRenderer);
III-F-1. Le paramètre de SDL_RenderPresent()▲
La fonction prend en paramètre le SDL_Renderer à mettre à jour.
III-G. Libération de la mémoire liée à la SDL_Texture▲
Maintenant que la texture n'est plus nécessaire, il est possible de libérer la mémoire associée à celle-ci. La fonction pour ce faire est SDL_DestroyTexture() :
SDL_DestroyTexture
(
pTexture);
III-G-1. Le paramètre de SDL_DestroyTexture()▲
La fonction prend en paramètre la SDL_Texture à détruire.
III-H. Libération de la mémoire liée au SDL_Renderer▲
Le SDL_Renderer doit lui aussi être désalloué. La fonction pour ce faire est SDL_DestroyRenderer() :
SDL_DestroyRenderer
(
pRenderer);
III-H-1. Le paramètre de SDL_DestroyRenderer()▲
La fonction prend en paramètre le SDL_Renderer à détruire.
III-I. Récapitulatif▲
Voici le code permettant d'afficher un sprite et cela, en utilisant l'accélération graphique disponible dans la SDL 2 :
SDL_Renderer *
pRenderer =
SDL_CreateRenderer
(
pWindow,-
1
,SDL_RENDERER_ACCELERATED); // Création d'un SDL_Renderer utilisant l'accélération matérielle
if
(
pRenderer )
{
SDL_Surface*
pSprite =
SDL_LoadBMP
(
"
./data/dvp.bmp
"
);
if
(
pSprite )
{
SDL_Texture*
pTexture =
SDL_CreateTextureFromSurface
(
pRenderer,pSprite); // Préparation du sprite
if
(
pTexture )
{
SDL_Rect dest =
{
640
/
2
-
pSprite->
w/
2
,480
/
2
-
pSprite->
h/
2
, pSprite->
w, pSprite->
h}
;
SDL_RenderCopy
(
pRenderer,pTexture,NULL
,&
dest); // Copie du sprite grâce au SDL_Renderer
SDL_RenderPresent
(
pRenderer); // Affichage
SDL_Delay
(
3000
); /* Attendre trois secondes, que l'utilisateur voit la fenêtre */
SDL_DestroyTexture
(
pTexture); // Libération de la mémoire associée à la texture
}
else
{
fprintf
(
stdout,"
Échec de création de la texture (%s)
\n
"
,SDL_GetError
(
));
}
SDL_FreeSurface
(
pSprite); // Libération de la ressource occupée par le sprite
}
else
{
fprintf
(
stdout,"
Échec de chargement du sprite (%s)
\n
"
,SDL_GetError
(
));
}
SDL_DestroyRenderer
(
pRenderer); // Libération de la mémoire du SDL_Renderer
}
else
{
fprintf
(
stdout,"
Échec de création du renderer (%s)
\n
"
,SDL_GetError
(
));
}
IV. Nettoyage de l'écran▲
IV-A. SDL 1.X▲
Pour donner une couleur de fond à votre fenêtre, vous pouvez utiliser SDL_FillRect :
Uint32 color =
SDL_MapRGB
(
pWindowSurface->
format,100
,32
,32
);
SDL_FillRect
(
pWindowSurface,NULL
, color);
IV-A-1. Les paramètres de SDL_FillRect()▲
La fonction accepte trois paramètres :
- la surface à colorier ;
- le rectangle dans la surface à colorier ou NULL pour colorier l'intégralité de la surface ;
- la couleur à utiliser.
IV-A-2. La valeur de retour de SDL_FillRect()▲
La fonction retourne zéro ou un entier négatif si une erreur a eu lieu. Vous pouvez utiliser SDL_GetError().
IV-B. SDL 2▲
Avec la nouvelle version de la bibliothèque, le nettoyage de l'écran est un processus en deux étapes :
- la sélection d'une couleur de nettoyage ;
- le nettoyage.
IV-B-1. Sélection de la couleur de nettoyage▲
Pour indiquer la couleur de nettoyage à la bibliothèque, il faut utiliser la fonction SDL_SetRenderDrawColor() :
SDL_SetRenderDrawColor
(
renderer, 255
, 0
, 0
, 255
);
IV-B-1-a. Les paramètres de SDL_SetRenderDrawColor()▲
La fonction accepte cinq paramètres :
- le SDL_Renderer sur lequel appliquer le changement ;
- la valeur pour le canal rouge ;
- la valeur pour le canal vert ;
- la valeur pour le canal bleu ;
- la valeur pour le canal alpha.
IV-B-2. La valeur de retour de SDL_SetRenderDrawColor()▲
La fonction retourne zéro ou un entier négatif si une erreur a eu lieu. Vous pouvez utiliser SDL_GetError().
IV-B-3. Nettoyage▲
La fonction en SDL 2 pour effectuer le nettoyage est SDL_RenderClear :
SDL_RenderClear
(
renderer);
IV-B-3-a. Le paramètre de SDL_RenderClear()▲
La fonction demande simplement le SDL_Renderer à nettoyer.
IV-B-3-b. La valeur de retour de SDL_RenderClear()▲
La fonction retourne zéro ou un entier négatif si une erreur a eu lieu. Vous pouvez utiliser SDL_GetError().
V. Remerciements▲
Merci à Kannagi pour son avis et ses suggestions lors de la réalisation de ce tutoriel.
Merci à ClaudeLELOUP pour sa relecture orthographique.
Navigation▲
Tutoriel précédent : vos premières fenêtres |
Tutoriel suivant : les événements |