Aller au menu - Aller au contenu

[Plan du site] Vous êtes ici --- > Le Site du Zéro > Les tutoriels > Officiels > Programmation > Apprenez à programmer en C ! > [Pratique] Création de jeux 2D en SDL > Afficher des images > Lecture du tutoriel

Afficher des images

Avatar
Auteur : M@teo21
Difficulté : Amateur (2 / 5)
Note : 19 / 20 (26 votes)
Visualisations : 247 903

Plus d'informations Plus d'informations
Dans notre premier chapitre de "vraie" pratique de la SDL, nous avons appris à charger la SDL, ouvrir une fenêtre et gérer les surfaces.

Or, pour le moment nous n'avons appris qu'à créer des surfaces unies, c'est-à-dire ayant la même couleur. Les surfaces unies ça va un moment, mais ce serait délicat de faire un jeu avec juste des carrés de couleur :p
Dans ce chapitre, nous allons justement apprendre à charger des images dans des surfaces, que ce soit des BMP, des PNG, des GIF, des JPG ou que sais-je encore ^^
Sommaire du chapitre :
Icône du chapitre
Chapitre précédent Sommaire Chapitre suivant

Charger une image BMP

Allons bon o_O
Pourquoi est-ce qu'on ne va apprendre qu'à charger des images BMP ici ?


En fait, la SDL est une librairie très simple. Elle ne propose à la base que le chargement d'images de type Bitmap (extension ".bmp"). Ne paniquez pas pour autant, car grâce à une extension de la SDL (la librairie SDL_Image) nous verrons qu'il est possible de charger de nombreux autres types.

Pour commencer déjà, nous allons nous contenter de ce que la SDL offre à la base. Nous allons donc étudier le chargement de BMP.


Le format BMP



Un BMP (abréviation de Bitmap) est un format d'image.
Les images que vous voyez sur votre ordinateur sont stockées dans des fichiers. Il existe plusieurs formats d'images, c'est-à-dire plusieurs façons de coder l'image dans un fichier. Selon le format, l'image prend plus ou moins d'espace disque et est de plus ou moins bonne qualité.

Le Bitmap est un format non compressé (contrairement aux JPG, PNG, GIF etc.)
Concrètement, cela signifie les choses suivantes :


Bref, il y a des avantages et des défauts.
Pour la SDL, l'avantage c'est que ce type de fichier est simple et rapide à lire. Si vous avez souvent besoin de charger des images au cours de l'exécution de votre programme, il vaut mieux utiliser des BMP : certes le fichier est plus gros, mais il se chargera plus vite qu'un GIF par exemple.


Charger un bitmap




Téléchargement du pack d'images



Nous allons travailler avec plusieurs images dans ce chapitre. Si vous voulez faire les tests en même temps que vous lisez (et vous devriez !), je vous recommande fortement de télécharger ce pack qui contient toutes les images dont on va avoir besoin :



Placez toutes les images dans le dossier de votre projet.
Nous allons commencer par travailler avec le fichier lac_en_montagne.bmp. C'est une scène 3D d'exemple livrée avec le logiciel de modélisation Vue d'Esprit (c'était à l'époque où j'espérais me découvrir un talent artistique, mais ça fait belle lurette que j'ai abandonné :p )



Charger l'image dans une surface



Nous allons utiliser une fonction qui va charger l'image BMP et la mettre dans une surface.
Cette fonction a pour nom SDL_LoadBMP. Vous allez voir c'est ridicule tellement c'est simple :p

Code : C
1
maSurface = SDL_LoadBMP("image.bmp");


La fonction SDL_LoadBMP remplace 2 fonctions que vous connaissez :


Pourquoi est-ce que ça remplace ces 2 fonctions ? C'est très simple :



Codons sans plus tarder :D

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *imageDeFond = NULL;
    SDL_Rect positionFond;

    positionFond.x = 0;
    positionFond.y = 0;

    SDL_Init(SDL_INIT_VIDEO);

    ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Chargement d'images en SDL", NULL);

    /* Chargement d'une image Bitmap dans une surface */
    imageDeFond = SDL_LoadBMP("lac_en_montagne.bmp");
    /* On blitte par-dessus l'écran */
    SDL_BlitSurface(imageDeFond, NULL, ecran, &positionFond);

    SDL_Flip(ecran);
    pause();

    SDL_FreeSurface(imageDeFond); /* On libère la surface */
    SDL_Quit();

    return EXIT_SUCCESS;
}


J'ai donc créé un pointeur vers une surface (imageDeFond) ainsi que les coordonnées correspondantes (positionFond).
La surface est créée en mémoire et remplie par la fonction SDL_LoadBMP.
On la blitte ensuite sur la surface ecran et c'est tout ! Admirez le résultat :

Image utilisateur


C'est aussi simple que cela :)



Donner une icône à son application



Maintenant que nous savons charger des images, nous pouvons voir comment donner une icône à notre programme. L'icône sera affichée en haut à gauche de la fenêtre (et aussi dans la barre des tâches). Pour le moment on a une icône par défaut.

Mais, les icônes des programmes ne sont pas des .ico normalement ?


Non pas forcément ! D'ailleurs les .ico n'existent que sous Windows, sur les autres OS on n'en trouve pas !
La SDL réconcilie tout le monde en utilisant un truc bien à elle : une surface !
Eh oui, l'icône d'un programme SDL n'est rien d'autre qu'une bête surface ^^

Votre icône doit normalement être de taille 16x16 pixels.
Toutefois, sous Windows il faut que l'icône soit de taille 32x32 pixels sinon elle sera déformée. Ne vous en faites pas, la SDL "réduira" les dimensions de l'image pour qu'elle rentre dans 16x16 pixels (vous imaginez pas le temps que j'ai mis pour comprendre ça ^^ )


Pour ajouter l'icône à la fenêtre, on utilise la fonction SDL_WM_SetIcon
Cette fonction prend 2 paramètres : la surface qui contient l'image à afficher ainsi que des informations sur la transparence (NULL si on ne veut pas de transparence).

La gestion de la transparence d'une icône est un peu compliquée (il faut dire un à un quels sont les pixels transparents), nous ne l'étudierons donc pas.


On va combiner 2 fonctions en une :

Code : C
1
SDL_WM_SetIcon(SDL_LoadBMP("sdl_icone.bmp"), NULL);


L'image est chargée en mémoire par SDL_LoadBMP et l'adresse de la surface est directement envoyée à SDL_WM_SetIcon.

La fonction SDL_WM_SetIcon doit être appelée avant que la fenêtre ne soit ouverte, c'est-à-dire qu'elle doit se trouver avant SDL_SetVideoMode dans votre code source.


Voici le code source complet (j'ai juste ajouté le SDL_WM_SetIcon par rapport à la dernière fois) :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *imageDeFond = NULL;
    SDL_Rect positionFond;

    positionFond.x = 0;
    positionFond.y = 0;

    SDL_Init(SDL_INIT_VIDEO);

    /* Chargement de l'icône AVANT SDL_SetVideoMode */
    SDL_WM_SetIcon(SDL_LoadBMP("sdl_icone.bmp"), NULL);

    ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Chargement d'images en SDL", NULL);

    imageDeFond = SDL_LoadBMP("lac_en_montagne.bmp");
    SDL_BlitSurface(imageDeFond, NULL, ecran, &positionFond);

    SDL_Flip(ecran);
    pause();

    SDL_FreeSurface(imageDeFond);
    SDL_Quit();

    return EXIT_SUCCESS;
}


Résultat, l'icône est chargée :D

Image utilisateur



Gestion de la transparence

Le problème de la transparence



Nous avons chargé une jolie image bitmap tout à l'heure dans notre fenêtre.
Supposons que l'on veuille blitter une image par-dessus. Ca vous arrivera très fréquemment, car dans un jeu en général le personnage que l'on déplace est un bitmap, et il se déplace sur une image de fond.

On va blitter l'image de Zozor (la mascotte du Site du Zér0 !) sur la scène :

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *imageDeFond = NULL, *zozor = NULL;
    SDL_Rect positionFond, positionZozor;

    positionFond.x = 0;
    positionFond.y = 0;
    positionZozor.x = 500;
    positionZozor.y = 260;

    SDL_Init(SDL_INIT_VIDEO);

    SDL_WM_SetIcon(SDL_LoadBMP("sdl_icone.bmp"), NULL);

    ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Chargement d'images en SDL", NULL);

    imageDeFond = SDL_LoadBMP("lac_en_montagne.bmp");
    SDL_BlitSurface(imageDeFond, NULL, ecran, &positionFond);

    /* Chargement et blittage de zozor sur la scène */
    zozor = SDL_LoadBMP("zozor.bmp");
    SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);

    SDL_Flip(ecran);
    pause();

    SDL_FreeSurface(imageDeFond);
    SDL_FreeSurface(zozor);
    SDL_Quit();

    return EXIT_SUCCESS;
}


On a juste rajouté une surface pour y stocker Zozor, que l'on blitte ensuite à un endroit sur la scène.
Le résultat est le suivant :

Image utilisateur


C'est moche hein ? :D

Bah oui, c'est parce que t'as mis un fond bleu tout moche sur l'image de Zozor !


Parce que vous croyez qu'avec un fond noir ou un fond marron derrière Zozor ça aurait été plus joli ? :-°
Ben non, le problème ici c'est que notre image est forcément rectangulaire, donc si on la colle sur la scène on voit son fond et ça fait moche.

Heureusement, la SDL gère la transparence !


Rendre une image transparente



Etape 1 : préparer l'image



Pour commencer, il faut préparer l'image que vous voulez blitter sur la scène.
Les BMP ne sont pas des images gérant la transparence, contrairement aux GIF et PNG. Il va donc falloir utiliser une astuce.

Il faut mettre la même couleur de fond sur toute l'image. Celle-ci sera rendue transparente par la SDL au moment du blit. Observez à quoi ressemble mon zozor.bmp de plus près :

Image utilisateur


J'ai mis un fond bleu uni exprès. Notez que j'ai choisi le bleu au hasard, j'aurais très bien pu mettre un fond vert ou rouge par exemple. Ce qui compte, c'est que cette couleur soit unique et unie. J'ai choisi le bleu parce qu'il n'y en avait pas dans l'image de zozor. Si j'avais choisi le vert, j'aurais pris le risque que l'herbe que machouille Zozor (en bas à gauche de l'image) soit rendue transparente.

A vous donc de vous débrouiller avec votre logiciel de dessin (Paint, Photoshop, chacun ses goûts :D ) pour donner un fond uni à votre image.


Etape 2 : indiquer la couleur transparente



Pour indiquer à la SDL quelle est la couleur qui doit être rendue transparente, vous devez utiliser la fonction SDL_SetColorKey. Cette fonction doit être appelée avant de blitter l'image.
Voici comment je m'en sers pour rendre le bleu derrière Zozor transparent :

Code : C
1
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));


Il y a 3 paramètres :



En résumé, on charge d'abord l'image avec SDL_LoadBMP, on indique la couleur transparente avec SDL_SetColorKey, puis on peut blitter avec SDL_BlitSurface :

Code : C
1
2
3
4
5
6
/* On charge l'image : */
zozor = SDL_LoadBMP("zozor.bmp");
/* On rend le bleu derrière Zozor transparent : */
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));
/* On blitte l'image maintenant transparente sur le fond : */
SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);


Résultat, Zozor est parfaitement intégré à la scène !

Image utilisateur


Ca, c'est LA technique de base que vous réutiliserez tout le temps dans vos futurs programmes. Apprenez à bien manier la transparence car c'est fondamental si on veut avoir un jeu un minimum réaliste ^^


La transparence Alpha



C'est un autre type de transparence.
Jusqu'ici, on se contentait de définir UNE couleur de transparence (par exemple le bleu). Cette couleur n'apparaissait pas une fois l'image blittée.

La transparence Alpha c'est autre chose. Elle permet de réaliser un "mélange" entre une image et le fond. C'est une sorte de fondu.

La transparence Alpha d'une surface peut être activée par la fonction SDL_SetAlpha :

Code : C
1
SDL_SetAlpha(zozor, SDL_SRCALPHA, 128);


Il y a là encore 3 paramètres :



Plus le nombre Alpha est petit, plus l'image est transparente et fondue.

Voici par exemple un code qui met une transparence alpha de 128 à notre Zozor :

Code : C
1
2
3
4
5
zozor = SDL_LoadBMP("zozor.bmp");
SDL_SetColorKey(zozor, SDL_SRCCOLORKEY, SDL_MapRGB(zozor->format, 0, 0, 255));
/* Transparence Alpha moyenne (128) : */
SDL_SetAlpha(zozor, SDL_SRCALPHA, 128);
SDL_BlitSurface(zozor, NULL, ecran, &positionZozor);


Vous noterez que j'ai conservé la transparence de SDL_SetColorKey. Les 2 types de transparence sont en effet combinables.


Ce tableau vous montre à quoi ressemble Zozor selon la valeur de Alpha :

AlphaAperçu
255
(entièrement opaque)
Image utilisateur
190
Image utilisateur
128
(transparence moyenne)
Image utilisateur
75
Image utilisateur
0
(entièrement transparente)
Image utilisateur


La transparence Alpha 128 (transparence moyenne) est une valeur spéciale qui est optimisée par la SDL. Ce type de transparence est plus rapide à calculer pour votre ordinateur que les autres. C'est peut être bon à savoir si vous utilisez beaucoup de transparence Alpha dans votre programme.



Charger plus de formats d'image avec SDL_Image

La SDL ne gère que les Bitmaps (BMP) comme on l'a vu.
A priori, ce n'est pas un très gros problème parce que la lecture des BMP est rapide pour la SDL, mais il faut reconnaître qu'aujourd'hui on est plutôt habitué à utiliser d'autres formats. En particulier, nous sommes habitués aux formats d'images "compressés" comme le PNG, le GIF et le JPEG. Ca tombe bien, il existe justement une librairie SDL_Image qui gère tous les formats suivants :


Il est possible de rajouter des extensions à la SDL. Ce sont des librairies qui ont besoin de la SDL pour fonctionner. On peut voir ça comme des add-ons. SDL_Image est l'une d'entre elles.


Installer SDL_image sous Windows




Téléchargement



Il y a une page spéciale sur le site de la SDL qui référence les librairies utilisant la SDL. Cette page s'intitule Libraries, vous trouverez un lien dans le menu de gauche.
Vous pourrez voir qu'il y a pas mal de librairies disponibles. Celles-ci ne proviennent pas des auteurs de la SDL généralement, ce sont plutôt des utilisateurs de la SDL qui proposent leurs librairies.
Certaines sont très bonnes et méritent le détour, d'autres sont moins bonnes et encore buggées. Il faut arriver à faire le tri ;)

Cherchez SDL_Image dans la liste...
Bon allez, je suis de bonne humeur : voici un lien direct vers la page de téléchargement de SDL_Image pour vous aider :p

Téléchargez la version de SDL_Image qui vous correspond dans la section Binary (ne prenez PAS la source, on n'en a pas besoin !)
Si vous êtes sous Windows téléchargez SDL_image-devel-1.2.4-VC6.zip même si vous n'utilisez pas Visual C++ !


Installation



Dans ce zip vous trouverez :


Ensuite, vous devez modifier les options de votre projet pour "linker" avec le fichier SDL_image.lib.

Si vous êtes sous Code::Blocks par exemple, allez dans le menu Projects / Build options. Dans l'onglet Linker, cliquez sur le bouton "Add" et indiquez où se trouve le fichier SDL_image.lib
Si on vous demande "Keep as a relative path ?", répondez ce que vous voulez ça ne changera rien dans l'immédiat. Je recommande de répondre "Non" personnellement :p

Ensuite, vous n'avez plus qu'à inclure le header SDL_image.h dans votre code source comme ceci :

Code : C
1
#include <SDL/SDL_image.h>


Et voilà, la librairie SDL_image devrait maintenant fonctionner (à condition que vous ayez bien fait exactement tout ce que j'ai indiqué bien sûr ;) )

Si vous êtes sous Dev-C++ ou Visual Studio, la manipulation est quasiment la même. Si vous avez réussi à installer la SDL, vous n'aurez aucun problème pour installer SDL_image ;)


Installer SDL_image sous Mac OS X



Si vous utilisez Mac OS X, téléchargez le fichier .dmg sur le site de la SDL.

Copiez le fichier SDL_image.framework dans Macintosh HD/Library/Frameworks.
Copiez ensuite le fichier SDL_image.h dans SDL.framework/Headers.

Créez un nouveau projet de type "SDL Application" et faites "Add / Existing Frameworks".

XCode SDL_image


Là, sélectionnez le fichier SDL_image.framework que vous venez de télécharger. C'est tout ! :)

Petite exception pour vous, il faudra inclure le fichier .h dans votre code comme ceci :
#include "SDL_image.h"
... au lieu d'utiliser des chevrons < >. Remplacez donc la ligne d'include de SDL_image dans le gros code qui va suivre par celle que je viens de vous donner.


Charger les images



En fait, installer SDL_image est 100 fois plus compliqué que de l'utiliser, c'est vous dire la complexité du truc :lol:

Il y a UNE fonction à connaître : IMG_Load.
Elle prend un paramètre : le nom du fichier à ouvrir.

Ce qui est génial, c'est que cette fonction est capable d'ouvrir tous les types de fichiers que gère SDL_image (GIF, PNG, JPG, mais aussi BMP, TIF...). Elle détectera toute seule le type du fichier en fonction de son extension.

Comme SDL_image peut aussi ouvrir les BMP, vous pouvez même oublier la fonction SDL_LoadBMP maintenant et n'utiliser plus que IMG_Load pour le chargement de n'importe quelle image.


Autre bon point : si l'image que vous chargez gère la transparence (comme c'est le cas des PNG et des GIF), alors SDL_image activera automatiquement la transparence pour cette image ! Cela vous évite donc d'avoir à appeler SDL_SetColorKey :)

Voici le code source complet qui charge sapin.png et l'affiche.
Notez bien que j'inclue SDL/SDL_image.h et que je ne fais pas appel à SDL_SetColorKey car mon PNG est transparent.
Vous allez voir que j'utilise IMG_Load partout dans ce code en remplacement de SDL_LoadBMP.

Code : C
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_image.h> /* Inclusion du header de SDL_image */
 
void pause();
 
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *imageDeFond = NULL, *sapin = NULL;
    SDL_Rect positionFond, positionSapin;
 
    positionFond.x = 0;
    positionFond.y = 0;
    positionSapin.x = 500;
    positionSapin.y = 260;
 
    SDL_Init(SDL_INIT_VIDEO);
 
    SDL_WM_SetIcon(IMG_Load("sdl_icone.bmp"), NULL);
 
    ecran = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Chargement d'images en SDL", NULL);
 
    imageDeFond = IMG_Load("lac_en_montagne.bmp");
    SDL_BlitSurface(imageDeFond, NULL, ecran, &positionFond);
 
    /* Chargement d'un PNG avec IMG_Load
    Celui-ci est automatiquement rendu transparent car les informations de
    transparence sont codées à l'intérieur du fichier PNG */
    sapin = IMG_Load("sapin.png");
    SDL_BlitSurface(sapin, NULL, ecran, &positionSapin);
 
    SDL_Flip(ecran);
    pause();
 
    SDL_FreeSurface(imageDeFond);
    SDL_FreeSurface(sapin);
    SDL_Quit();
 
    return EXIT_SUCCESS;
}
 
void pause()
{
    int continuer = 1;
    SDL_Event event;
 
    while (continuer)
    {
        SDL_WaitEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
        }
    }
}


Résultat :

Image utilisateur


Quand même bien pratique cette petite librairie :D

Q.C.M.

Quelle fonction permet d'ajouter une icône à la fenêtre ?
Qu'est-ce que la transparence Alpha ?
Pourquoi peut-on parfois se passer de la fonction SDL_SetColorKey si on charge une image GIF ou PNG avec SDL_image ?
Quel est le seul format d'image que permet de lire la librairie SDL à la base ?

Statistiques de réponses au QCM


Vous êtes maintenant capables d'afficher de nombreux type d'images dans vos programmes SDL, et, surtout, de rendre ces images transparentes.
Avec ces fonctions pourtant très simples de la SDL, vous allez pouvoir réaliser à peu près tous les programmes que vous voulez.

Mais avant ça, il va falloir étudier un chapitre très important de la SDL : les évènements. Cela vous permettra de gérer le clavier, la souris et le joystick, rien de moins que ça ! :)
Au lieu d'avoir un programme "passif" comme maintenant où vous vous contentez de regarder votre fenêtre, vous allez pouvoir contrôler un personnage au clavier, cliquer dans la fenêtre etc. :D
Chapitre précédent Sommaire Chapitre suivant
Retour en haut Retour en haut


Créé : le 29/07/2005 à 00:29:36
Modifié : le 24/11/2008 à 16:17:12
Avancement : 100%
Licence : Copie non autorisée

43 commentaires

Changer de design | En savoir plus | Plan du site | Politique d'accessibilité | Règles | RSS tutoriels | RSS news
Édité par Simple IT SARL : Nous contacter | Notre blog | Revue de presse | Publicité

Y'a plus rien à lire, faut remonter maintenant !

Hébergement web - Correction de tutoriels - Créer un site
Vous souhaitez apparaître ici ? Contactez-nous.

Nombre de connectés 100 Zéros connectés | Requêtes SQL 8 requêtes | Temps de génération de la page : Total (SQL) 0.1412s (0.071s)