FAQ SDLConsultez toutes les FAQ

Nombre d'auteurs : 6, nombre de questions : 67, création le 10 mai 2013 

 
OuvrirSommaire2D

SDL étant basée sur des (parfois vieilles) API 2D, des opérations telles que l'alpha-blending, les rotations ou n'importe quelle transformation ne peut être accélérée par le matériel. Vous pouvez bien sûr les effectuer « à la main » avec le CPU, mais ce sera très lent.

Une bibliothèque réglant tous ces problèmes existe, il s'agit de SGE. Elle permet :

  • des opérations sur les pixels (alpha-blending par exemple) ;
  • du clipping ;
  • de dessiner des lignes, cercles et autres figures (avec antialiasing et alpha-blending) ;
  • d'effectuer des rotations et mises à l'échelle de surfaces ;
  • de fournir des classes de sprites ;
  • de gérer les polices TrueType pour l'affichage de texte ;
  • de gérer des collisions basiques ;
  • etc.

SGE est libre (sous licence LGPL), et devrait tourner sur à peu près n'importe quelle plateforme supportant SDL (testé sous Windows, Linux et FreeBSD).

Une autre bibliothèque, SDL_gfx, permet de gérer également des transformations, primitives, zooms et filtres d'images de manière optimisée. Elle fournit les fonctions suivantes (inclure <SDL/SDL_rotozoom.h>) :

rotation suivie d'un zoom :

 
Sélectionnez
SDL_Surface *rotozoomSurface(SDL_Surface * src, double angle, double zoom, int smooth);

une variante permet de faire un zoom différent par rapport à chaque axe :

 
Sélectionnez
SDL_Surface *rotozoomSurfaceXY(SDL_Surface * src, double angle, double zoomx, double zoomy, int smooth);

puisque la taille va changer, vous pourrez récupérer la taille dans la structure SDL_Surface, mais aussi au préalable avec ces fonctions :

 
Sélectionnez
void rotozoomSurfaceSize(int width, int height, double angle, double zoom, int *dstwidth, int *dstheight);
void rotozoomSurfaceSizeXY(int width, int height, double angle, double zoomx, double zoomy, int *dstwidth, int *dstheight);

Quelques remarques

  • Ces fonctions créent de nouvelles surfaces, donc il faut faire attention à la gestion de la mémoire.
  • Ce sont des opérations relativement lourdes, donc cela ne serait pas envisageable dans un programme qui nécessite ces traitementsà chaque frame. Cela sert pour les rares fois où le programme a besoin d'une rotation ou d'un zoom
  • Les angles sont donnés en degrés et non en radians.

Enfin, il existe aussi des fonctions qui ne font que les zooms :

 
Sélectionnez
SDL_Surface *zoomSurface(SDL_Surface * src, double zoomx, double zoomy, int smooth);
void zoomSurfaceSize(int width, int height, double zoomx, double zoomy, int *dstwidth, int *dstheight);
Créé le 16 mars 2006  par Laurent Gomila, CSoldier, fearyourself

Lien : Site officiel de SGE
Lien : Site officiel de SDL_gfx

SDL propose une fonction permettant de récupérer toute sorte d'informations utiles sur le matériel :

 
Sélectionnez
const SDL_VideoInfo* SDL_GetVideoInfo()

Elle retourne un pointeur sur une structure de type SDL_VideoInfo contenant quelques membres donnant des informations sur le système vidéo, comme, entre autres :

 
Sélectionnez
const SDL_VideoInfo* VideoInfo;

/* Récupération des informations sur le hardware vidéo */
VideoInfo = SDL_GetVideoInfo();

printf("Surfaces hardware disponibles -> %i", VideoInfo->hw_available);
printf("Gestionnaire de fenêtre disponible -> %i", VideoInfo->wm_available);
printf("Support de l'accélération du blit hardware -> %i", VideoInfo->blit_hw);
printf("Support de l'accélération du remplissage des couleurs hardware -> %i", VideoInfo->blit_fill);
printf("Mémoire vidéo totale sur la carte graphique (en Ko) -> %i", VideoInfo->video_mem);
printf("Nombre d'octets par pixels utilisés par la carte graphique -> %i", VideoInfo->vfmt->BytesPerPixel);
/* ... */

Pour une liste exhaustive, voir l'habituelle documentation officielle.

Créé le 16 mars 2006  par Fiquet

Pour faire des transformations de base (couleur et alpha), on peut accéder directement aux pixels grâce au membre pixels de la structure SDL_Surface qui est un pointeur sur les données de pixels.

La fonction suivante sert à modifier le pixel (x, y) d'une SDL_Surface (tiré de la doc officielle) :

 
Sélectionnez
void SetPixel(SDL_Surface* Surface, int x, int y, Uint32 pixel)
{
    /* p est l'adresse du pixel que l'on veut modifier */
    Uint8 *p = (Uint8*)Surface->pixels + y * Surface->pitch + x * bpp;

    switch(Surface->format->BytesPerPixel)
    {
    case 1:
        *p = pixel;
        break;

    case 2:
        *(Uint16*)p = pixel;
        break;

    case 3:
        if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
        {
            p[0] = (pixel >> 16) & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = pixel & 0xff;
        }

        else
        {
            p[0] = pixel & 0xff;
            p[1] = (pixel >> 8) & 0xff;
            p[2] = (pixel >> 16) & 0xff;
        }
        break;

    case 4:
        *(Uint32 *)p = pixel;
        break;
    }
}
Créé le 16 mars 2006  par Fiquet

La plupart des fonctions de SDL qui utilisent les couleurs demandent un code couleur de type Uint32 qui correspond à un pixel. Cependant, ce type étant peu parlant et interprété différemment selon le format de pixel des surfaces, il existe la fonction SDL_MapRGB qui retourne un Uint32 correspondant au format, d'après les valeurs RGB passées dans les trois derniers paramètres. Le premier paramètre correspond au format de pixel de la surface, qui peut être renseigné grâce au membre format de SDL_Suface :

 
Sélectionnez
/* Dessine un rectangle bleu (0, 0, 255) de 30 * 10 pixels sur la surface */
SDL_Rect Rect;
Rect.x = 0;
Rect.y = 0;
Rect.w = 30;
Rect.h = 10;

SDL_FillRect(mySurf, &Rect, SDL_MapRGB(mySurf->format, 0, 0, 255));

Pour des pixels utilisant le canal alpha, on peut utiliser la fonction :

 
Sélectionnez
Uint32 SDL_MapRGBA(SDL_PixelFormat* fmt, Uint8 r, Uint8 g, Uint8 b, Uint8 a)

qui a le même fonctionnement que SDLMapRGB, avec un paramètre de plus pour le canal alpha.

Pour faire l'inverse, c'est-à-dire récupérer chaque canal de couleur depuis un Uint32, il existe la fonction :

 
Sélectionnez
void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat* fmt, Uint8* r, Uint8* g, Uint8* b, Uint8* a)

qui fournit les valeurs dans les paramètres correspondants. Il faut aussi renseigner la fonction avec le format de pixel.

 
Sélectionnez
Uint8 r, g, b;

/* Récupère la valeur RGB du premier pixel (0, 0) d'une surface */
SDL_GetRGB((Uint8)Surf->pixels, Surf->format, &r, &g, &b);

printf("Couleur : rouge = %i, vert = %i, bleu = %i", r, g, b);
Créé le 16 mars 2006  par Fiquet

Grâce à une bibliothèque presque indispensable avec SDL : SDL_image, que l'on peut télécharger sur le site officiel.

Cette bibliothèque permet de lire les formats suivants : BMP, GIF, JPG, TIF, PNG, TGA et d'autres encore.

On peut ouvrir indifféremment n'importe quel type d'image simplement en appelant la fonction suivante :

 
Sélectionnez
SDL_Surface* IMG_Load(const char *file)

qui retourne la bonne surface.

Cependant, cette bibliothèque permet seulement l'ouverture des fichiers, pas la sauvegarde.

Créé le 16 mars 2006  par Fiquet

Parfois, on ne veut pas afficher une certaine couleur d'une surface, et garder le fond transparent. Pour dessiner un objet non-rectangle par exemple, ou comportant des « trous » (sprite, personnage, arbre…). On peut pour cela définir une couleur de transparence pour la surface avec la fonction suivante :

 
Sélectionnez
int SDL_SetColorKey(SDL_Surface* surface, Uint32 flag, Uint32 key)

En mettant le flag SDL_SRCCOLORKEY au paramètre flag. Le paramètre key correspond à la couleur à définir comme couleur transparente (voir http://jeux.developpez.com/faq/sdl/?page=2d#2D_definir_rgb).

 
Sélectionnez
/* Ouverture d'un BMP, un personnage par exemple */
SDL_Surface* Perso = SDL_LoadBMP("perso.bmp");

/* Autour du perso, on a par exemple mis une horrible couleur magenta :) qu'on ne va jamais utiliser (255, 0, 255) */
SDL_SetColorKey(Perso, SDL_SRCCOLORKEY, SDL_MapRGB(Perso->format, 255, 0, 255));
Créé le 16 mars 2006  par Fiquet

Avec la fonction :

 
Sélectionnez
int SDL_SetAlpha(SDL_Surface* surface, Uint32 flag, Uint8 alpha)

qui prend en premier paramètre la surface sur laquelle il faut appliquer de l'alpha, en second paramètre un flag à renseigner (la plupart du temps avec SDL_SRCALPHA), et en dernier paramètre une valeur entre 0 et 255, où 0 = le plus transparent et 255 = le plus opaque. Les minima et maxima sont aussi définis par les macros SDL_ALPHA_TRANSPARENT et SDL_ALPHA_OPAQUE.

 
Sélectionnez
/* Création d'une surface de 400 sur 300 (pour un menu transparent par exemple) */
MenuSurf = SDL_CreateRGBSurface(SDL_HWSURFACE, 400, 300, 32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff);

/* On donne un joli effet de transparence */
SDL_SetAlpha(MenuSurf, SDL_SRCALPHA, 180);

/* On dessine notre beau menu sur l'écran avec de la transparence */
SDL_BlitSurface(MenuSurf, NULL, MainScreen, &PosRect);
Créé le 16 mars 2006  par Fiquet

Si votre programme tourne normalement sur votre PC, mais trop (ou pas assez) vite lorsque vous l'essayez sur un autre, c'est sûrement que vous n'avez pas géré la fréquence d'affichage. En effet, si l'on ne précise rien et qu'on fait nos opérations en boucle, le programme tournera simplement à la vitesse maximale possible, qui dépend du processeur et d'autres choses encore.

Pour pallier ce problème, on peut utiliser simplement un timer, c'est-à-dire afficher seulement à une fréquence donnée.

Ce code dessine seulement à 20 fps (images par seconde) par exemple :

 
Sélectionnez
unsigned int checkTime = SDL_GetTicks();
const unsigned int fps = 20;

if(SDL_GetTicks() > (checkTime + 1000 / fps) )
{
    /* Code à exécuter 20 fois / seconde ... */

    /* On remet à jour le temps à contrôler */
    checkTime = SDL_GetTicks();
}
Créé le 16 mars 2006  par Fiquet

On parle de surface software lorsque celle-ci est chargée dans la mémoire vive (RAM) du PC et de mémoire hardware lorsque celle-ci est chargée en mémoire vidéo (RAM de la carte graphique).

Créé le 16 mars 2006  par Fiquet

Cela dépend de ce que l'on veut faire.

Le principal avantage des surfaces en mémoire vidéo (hardware) c'est que pour l'affichage (le blitting) ce sera beaucoup plus rapide. En effet, la surface sera gérée par la carte graphique et pourra donc être envoyée beaucoup plus vite à l'écran. L'inconvénient c'est que l'on doit accéder à la carte graphique à chaque traitement de l'image.

L'avantage des surfaces en mémoire système (software) c'est que le processeur y accède très rapidement, il sera donc plus facile de la lire, la modifier, la filtrer, etc.

Une chose importante à savoir est que pour activer le double buffering (voir http://jeux.developpez.com/faq/sdl/?page=2d#2D_double_buffering), il faudra mettre la surface de l'écran en mémoire vidéo.

Créé le 16 mars 2006  par Fiquet

Le double buffering est une fonction intéressante que l'on peut choisir d'activer lors de la création de la fenêtre. En mode double buffer (littéralement « double tampon »), le dessin ne se fera pas directement sur l'écran, mais sur un tampon qui n'est pas affiché. Lorsqu'on a tout dessiné, on inverse les deux tampons et c'est le nouveau qui est affiché en un coup, alors que l'on dessinera sur le second. L'avantage est double : d'une part le dessin se fait en un coup et paraît moins saccadé, d'autre part, on gagne en performances, car pendant que le premier tampon est affiché à l'écran, on peut déjà commencer à dessiner la prochaine frame sur le second.

Pour activer le double buffering il faut mettre le flag SDL_DOUBLEBUF dans la fonction SDL_SetVideoMode(). Pour que l'on soit réellement en double buffering, il faut aussi que la surface de l'écran soit en mémoire vidéo (voir http://jeux.developpez.com/faq/sdl/?page=2d#2D_choix_surface) avec le flag SDL_HWSURFACE dans la fonction SDL_SetVideoMode(), sinon on aura sans s'en apercevoir du simple buffering et un appel à SDL_Flip() sera équivalent à un simple appel à SDL_UpdateRect().

Créé le 16 mars 2006  par Fiquet

En plus de la fonction SDL_LoadBMP() pour charger des images, SDL propose la fonction suivante :

 
Sélectionnez
int SDL_SaveBMP(SDL_Surface* surface, const char* file)

qui permet d'enregistrer dans un fichier au format BMP la surface passée dans le premier paramètre, sur le chemin passé en second paramètre.
Pour faire une capture de tout l'écran, il suffit d'appeler cette fonction sur la surface de l'écran, celle créée grâce à SDL_SetVideoMode().

Créé le 16 mars 2006  par Fiquet
 
Sélectionnez
SDL_Surface* SDL_DisplayFormat(SDL_Surface* surface)

Cette fonction prend en entrée une surface quelconque, et renvoie une (autre) surface ayant le même format que la surface vidéo.

L'intérêt réside dans la vitesse de l'exécution de la fonction SDL_BlitSurface. En effet, pour qu'une surface puisse être collée sur une autre, il faut que toutes deux aient le même format de pixel.
Si lors de l'appel à SDL_BlitSurface, les deux surfaces n'ont pas le même format, SDL_BlitSurface effectue la conversion pour vous (en appelant SDL_ConvertSurface). Mais cela prend (énormément) de temps. Or si l'on doit coller une surface à l'écran beaucoup de fois, mieux vaut changer son format dès le départ.

 
Sélectionnez
SDL_Surface* tmp;
SDL_Surface* mon_image_au_format_ecran;

/* On charge l'image */
tmp = IMG_Load("mon_image.png");

/* On vérifie qu'elle a bien été chargée */
if (tmp == NULL)
{
    /* Erreur */
}

/* On change son format afin qu'il soit le même que celui de l'écran */
mon_image_au_format_ecran = SDL_DisplayFormat(tmp);

/* On revérifie que tout est correct */
if (mon_image_au_format_ecran == NULL)
{
    /* Erreur */
}

/* On supprime l'image temporaire */
SDL_FreeSurface(tmp);

Remarque : il faut bien évidemment que la fonction SDL_SetVideoMode ait été appelée auparavant.

Si les images possèdent un canal de transparence alpha, il faut utiliser SDL_DisplayFormatAlpha. Voir http://jeux.developpez.com/faq/sdl/?page=2d#2D_displayformat_alpha.

Créé le 16 mars 2006  par elekis

On ne peut pas, pour cela il faut utiliser la fonction complémentaire :

 
Sélectionnez
SDL_Surface *SDL_DisplayFormatAlpha(SDL_Surface *surface)

Elle fonctionne sur le même principe, à savoir :

 
Sélectionnez
SDL_Surface* temp = 0;
SDL_Surface* mon_image_finale = 0;

/* On charge une image qui contient de la transparence */
temp = IMG_Load("mon_image.png");
if(temp == 0)
    return 0; /* erreur lors du chargement de l'image */

mon_image_finale = SDL_DisplayFormatAlpha(temp);
if(mon_image_finale == 0)
{
    SDL_FreeSurface(temp);
    return 0; /* erreur lors du changement de format */
}

SDL_FreeSurface(temp);
Créé le 16 mars 2006  par elekis

Lorsqu'on utilise un double tampon pour l'affichage, le programme dessine la prochaine image en même temps que la carte graphique affiche l'image précédente.

Supposons que la carte graphique affiche le tampon A et que le code de rendu travaille sur le tampon B.

SDL_Flip permet de dire à la carte graphique que le code de rendu sur le tampon B est fini et qu'elle peut à présent l'afficher.

Ainsi, le code de rendu qui va suivre va écrire sur le tampon A pendant que la carte graphique affiche l'image qui se trouve dans le tampon B.

Le prochain SDL_Flip fera que la carte graphique affichera tampon A pendant que le code de rendu travaille sur le tampon B.

Créé le 3 mai 2007  par fearyourself

Lorsqu'un code SDL est écrit, il possède généralement une boucle globale qui inclut une boucle évènementielle, ceci permet de bien définir l'emplacement de l'appel à SDL_Flip :

Boucle générale d'un programme SDL
Sélectionnez
        while( jeuencours ) {
          while( SDL_PollEvent(&event) ) {
             case SDL_QUIT :
                jeuencours = 0;
                break;
             default:
          }
 
          /* Code de rendu */
 
          ..... Pas de SDL_Flip ....
 
          /* Un seul SDL_Flip */
          SDL_Flip(ecran);
        }

Remarque : il ne faut pas voir SDL_Flip comme une solution pour afficher le dernier Blit qui vient d'être fait. Il faut un et un seul appel par code de rendu.

Créé le 3 mai 2007  par fearyourself
  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2006-2012 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.