Gestion des surfaces avec la SDL

Publié le 15 mars 2012 par Lolokai @lolokai

Introduction

Dans cet article nous allons voir comment créer une classe statique permettant de manipuler les surfaces dans SDL. Une surface est une zone de la mémoire graphique qui peut être dessinée à l’écran. On pourrait simplifier en disant qu’une surface est un élément graphique de notre application. Dans notre classe nous utiliserons aussi une extension SDL permettant de charger des images, appelé SDL_image. Le but de cette classe sera de rassembler tous les outils offerts par la SDL dans un même emplacement.

Installation SDL_image

Nous allons commencer par installer notre extension, SDL_image.

Téléchargement
Le fichier se trouve sur cette page: SDL_image.
Il faudra prendre l’archive SDL_Image-devel-1.2.12-VC.zip qui se trouve dans la section Binary > Windows. Cette page propose quelques informations bien utiles sur l’extension, n’hésitez pas à la lire.

Installation
Dans l’archive que vous venez de télécharger, il y a 2 dossier, un include et un lib.

Le contenu dossier include doit être décompressé dans le dossier SDL situé dans le dossier include de MinGW (par défaut dans C:/MinGW/include/SDL/).

Le dossier lib contient deux sous-dossiers x64 et x86, il vaut mieux prendre le contenu du dossier x86 pour des soucis de compatibilité. Décompresser ce contenu dans le dossier lib de MinGW (par défaut dans C:/MinGW/lib/).

Liaison dans Eclipse
Il faut maintenant lier la librairie SDL_image à votre projet. Ouvrez Eclipse allez dans Project > Properties dans la liste de droite choisissez C/C++ General > Paths and Symbols puis dans l’onglet Libraries. Ajoutez comme suit.

Toutes les extensions SDL sont à ajouter de la même manière.

Modèle de classe

Avant de créé la classe nous devons réfléchir à son contenu. Nous savons que la SDL propose des fonctions permettant de manipuler des surfaces comme par exemple, pour créer une surface (SDL_CreateRGB), coller (SDL_BlitSurface) et beaucoup d’autres. Certaines de ces fonctions nécessitent de faire des opérations avant de pouvoir les utiliser. Ce serait donc une bonne chose de placer toute cette logique dans notre classe, ce qui éviterais la répétition de code, qui engendrerais une maintenance plus difficile. Cependant notre classe sera différente des autres classes, elle ne représentera pas un objet comme le ferais un classe Personnage ou Arme. Elle ne sera qu’une structure qui contiendra nos différentes méthodes.

Aussi en C++, il n’existe pas vraiment de classe statique comme en PHP par exemple. Ce sont ses méthodes qui seront statiques.

Création de la classe

Nous devons maintenant créer une nouvelle classe, nous allons pour cela utiliser le Wizard d’Eclipse. Allez dans File > New > Class.

Si la case « Namespace » est cochez, décochez là on en aura pas besoin ici.

Ce qui nous intéresse ici, c’est le champ Class Name, donnez la comme valeur Surface.

Par défaut, Eclipse place le fichier en-tête (.h) et le fichier source (.cpp) à la racine de votre projet. Vous pouvez les placer dans un dossier, selon votre organisation.

Cliquez sur Finish pour terminer. Vous devez vous retrouver avec deux fichiers comme suit:

Surface.h

#ifndef SURFACE_H_
#define SURFACE_H_

class Surface {
public:
Surface();
virtual ~Surface();
};

#endif /* SURFACE_H_ */

Surface.cpp

#include "Surface.h"

Surface::Surface() {
// TODO Auto-generated constructor stub

}

Surface::~Surface() {
// TODO Auto-generated destructor stub
}

Il ne faut pas oubliez l’inclusion des 2 librairies que nous allons utiliser dans cette classe.

#include <SDL/SDL.h>
#include <SDL/SDL_image.h>
#include <iostream.h> //Utile pour le débogage.

Voilà notre classe est maintenant créée, il nous faut maintenant ajouter les méthodes statiques utiles à notre application.

Note: Je commenterais chaque ligne du code, même la plus simple, pour être sûr que vous comprendrais chaque opération.

Chargement de fichier

C’est dans cette méthode que notre extension SDL_image sera utilisé. La SDL fourni une fonction SDL_LoadBMP qui permet de charger des images. Mais comme son nom le présuppose, elle ne permet que de charger des images au format BMP. L’extension SDL_image permet de débloquer cette situation en permettant le chargement d’images dans les formats les plus connu comme le PNG, JPG, GIF,.. avec une seule fonction IMG_Load. Cette méthode fournira aussi une version optimisée de la surface. Optimisé veut dire que la surface aura le même format de pixel et de couleur que le framebuffer, ce qui améliorera ainsi la vitesse de collage.
La méthode comporte aussi une ligne de débogage (SDL_GetError) qu’il faudra supprimer, lorsque le projet sera en production.

Ajout du prototype dans Surface.h

static SDL_Surface* chargeImage(const char* file);

Ajout du code dans Surface.cpp

SDL_Surface* Surface::chargeImage(const char* file) {

//Surface qui contiendra l'image chargé
SDL_Surface* surfaceBasique = NULL;

//Surface qui contiendra l'image optimisé
SDL_Surface* surfaceOptimise = NULL;

//Charge l'image
surfaceBasique = IMG_Load(file);

//Test si chargement réussit
if(surfaceBasique != NULL) {

//Copie une version optimisé de l'image chargé
surfaceOptimise = SDL_DisplayFormat(surfaceBasique);

//Supprime l'image basique, pour libéré la mémoire
SDL_FreeSurface(surfaceBasique);
}
//Image n'a pas pu être chargé
else {
cout << "Erreur :" << SDL_GetError() << endl;
}

//Retourne la surface optimisé
return surfaceOptimise;
}

Collage de surface simple

Cette méthode permet de coller une surface sur une autre, de la source vers la destination, selon des coordonnées X et Y. Dans notre prototype, la destination est égale à NULL. Bien sûr on ne peut pas coller une source sur rien. Cette notation permet en fait, que lorsque la destination est à NULL, on colle directement sur la surface vidéo. Les coordonnées permettent de définir l’emplacement où la source sera collé sur la surface de destination.

Surface.h

static void collage(SDL_Surface* source, SDL_Surface* destination = NULL, int destinationX, int destinationY);

Surface.cpp

void Surface::collage(SDL_Surface* source, SDL_Surface* destination, int destinationX, int destinationY) {

//Si la source est null == Erreur
if(source == NULL) {
cout << "La source est vide, impossible de Blitter" << endl;
return;
}

//Si la destination est null
if(destination == NULL) {

//Utilise la surface de la fenêtre
destination = SDL_GetVideoSurface();
}

//Zone destination
SDL_Rect destinationRect;
destinationRect.x = destinationX;
destinationRect.y = destinationY;

//Applique une surface
SDL_BlitSurface(source, NULL, destination, &amp;amp;amp;destinationRect);
}

Collage de surface avancé

Le collage avancé effectue les mêmes opérations que le collage simple, mais elle permet de ne coller qu’une seule partie de la surface source sur la surface de destination.

Surface.h

static void collage(SDL_Surface* source, SDL_Surface* destination = NULL, int destinationX, int destinationY, int sourceX, int sourceY, int sourceH, int sourceW);

Surface.cpp

void Surface::collage(SDL_Surface* source, SDL_Surface* destination, int destinationX, int destinationY, int sourceX, int sourceY, int sourceH, int sourceW) {

//Si la source est null == Erreur
if(source == NULL) {
cout << "La source est vide, impossible de coller" << endl;
return;
}

//Si la destination est null
if(destination == NULL) {

//Utilise la surface de la fenêtre
destination = SDL_GetVideoSurface();
}

//Zone source
SDL_Rect sourceRect;
sourceRect.x = sourceX;
sourceRect.y = sourceY;
sourceRect.h = sourceH;
sourceRect.w = sourceW;

//Zone destination
SDL_Rect destinationRect;
destinationRect.x = destinationX;
destinationRect.y = destinationY;

//Applique une surface
SDL_BlitSurface(source, &amp;amp;amp;sourceRect, destination, &amp;amp;amp;destinationRect);
}

Conclusion

Vous avez maintenant une classe statique fonctionnelle, prête à être utiliser dans vos projets. Elle permet d’effectuer les actions les plus courantes avec les Surfaces. Les méthodes présentées ici peuvent améliorer pour mieux servir vos besoins.

Et vous, quelle méthode auriez-vous rajouter dans cette classe ? Gérez-vous SDL avec un autre IDE ?