Mis à jour le mercredi 30 octobre 2013
  • Facile
Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Introduction du cours

Bonjour à tous. :D

Bienvenue dans ce mini-tuto où vous allez apprendre à faire des rotations sur des surfaces grâce à... SDL_gfx. :o

Bon, commençons...

C'est quoi SDL_gfx ?

SDL_gfx est une bibliothèque qui nécessite que la SDL soit installée.
Vous en avez sûrement déjà entendu parler dans les cours de M@teo21, je pense au chapitre SDL_image ou SDL_ttf.

SDL_gfx sert à faire des rotations mais aussi des figures géométriques, filtrer des images, gérer le temps de rafraîchissement de l'écran, etc...
Mais nous, ce qui nous intéresse, c'est la rotation, alors au boulot ! :pirate:

Installation de SDL_gfx

Téléchargement

Tout d'abord, il faut télécharger le fichier zip de SDL_gfx ici(merci à transfear pour le lien).

Quand vous arriverez sur la page, cliquez sur "Click here" dans le paragraphe "Setting Up SDL_gfx in Visual Studio .NET 2003".

C'est téléchargé ? Bon maintenant, il faut décompresser ce zip.

Voici comment faire :

Faites un clic droit sur le fichier et cliquez sur "Extraire tout...", ensuite laissez-vous guider par l'assistant d'extraction qui va vous décompresser ça en moins de deux.

Maintenant que vous avez décompressé le fichier, allez dans le dossier issu de la décompression.

Dans le dossier lib se trouvent les fichiers sdlgfx.dll et sdlgfx.lib.
Dans le dossier include se trouvent les fichiers d'en-tête ou headers (*.h).

Nous aurons besoin de ces fichiers pour l'installation...

Installation sous Code::Blocks

Je vous rappelle les fichiers dont nous avons besoin :

  • sdlgfx.dll : placez ce fichier dans le dossier de votre projet ;

  • sdlgfx.lib : ce fichier va dans le dossier "C:\Program Files\CodeBlocks\mingw32\lib" ;

  • et les headers (*.h) : ils vont dans le dossier "C:\Program Files\CodeBlocks\mingw32\include\SDL".

OK ! Les fichiers sont bien placés !

Maintenant il faut... configurer votre projet pour utiliser SDL_gfx.

Créez d'abord votre projet si ce n'est pas déjà fait, en configurant comme pour un projet SDL normal. Si vous ne vous souvenez plus comment faire, rendez-vous ici.

Puis sous Code::Blocks, allez dans le menu "Projects", "Build options".
Dans l'onglet "Linker", cliquez sur le bouton "Add" et indiquez où se trouve le fichier "sdlgfx.lib".
Si on vous demande "Keep as a relative path ?", répondez Non.

C'est bon, l'installation sous Code::Blocks est terminée.

Installation sous Visual Studio

Pour Visual, voici la démarche :magicien: :

  • Allez dans le dossier de Visual (chez moi : "C:\Program Files\Microsoft Visual Studio 9.0").

  • Ensuite allez dans le dossier VC.

  • Mettez sdlgfx.lib dans le dossier lib.

  • Allez dans le dossier include et mettez les headers (*.h) dans le dossier SDL.

  • Et évidemment, sdlgfx.dll dans le dossier de votre projet. ;)

Pour configurer Visual pour SDL_gfx, cliquez sur le menu "Projet", puis sur "Propriété nom du projet", puis allez dans "Editeur de liens", puis sur "Entrée" et dans dépendances supplémentaire mettez sdlgfx.lib en plus des autres .lib.

Voilà vous avez SDL_gfx pour Visual Studio. :)

( merci Dark Patate )

( merci Dark Patate )

Faire une rotation

On entre maintenant dans la partie la plus intéressante. :)

Tout d'abord, le main.c devrait ressembler à ça :

#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
 
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL;
    SDL_Event event;
    int continuer = 1;
 
    SDL_Init(SDL_INIT_VIDEO);
 
    ecran = SDL_SetVideoMode(500, 500, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Faire des rotations avec SDL_gfx", NULL);
 
    while(continuer)
    {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
                break;
        }
 
        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
        SDL_Flip(ecran);
    }
 
    SDL_FreeSurface(ecran);    
    SDL_Quit();
 
    return EXIT_SUCCESS;
}

La première chose à faire c'est d'inclure le fichier header :

#include <SDL/SDL_rotozoom.h>

Mais il me semble que j'ai copié 5 fichiers header ? Non ?

Oui c'est vrai. Mais comme je l'ai déjà dit dans la première partie, SDL_gfx ne sert pas qu'à faire des rotations et dans notre cas, nous n'avons besoin que de SDL_rotozoom.h.

Maintenant regardons le prototype de la fonction permettant de faire une rotation :

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

Le premier argument est en fait le nom de la surface à modifier.
Le deuxième est l'angle de rotation.
Le troisième est le zoom à appliquer sur la surface.

Hein ! Mais qu'est-ce que le zoom vient faire ici ?

Eh bien cette fonction permet de faire une rotation mais aussi un zoom.
C'est vrai que ce n'est pas terrible comme fonctionnement, mais il doit sûrement y avoir une raison. Si vous ne voulez pas faire de zoom, mettez 1.0.

Et enfin le quatrième argument sert à lisser la surface tournée, comme ça c'est plus joli. :)
Mettez 1 pour lisser, sinon mettez 0.

Maintenant qu'on a tout expliqué, voilà le code complet :

#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_rotozoom.h>
 
#define TEMPS       30 // Le temps qu'il y a entre chaque augmentation de l'angle.
 
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *image = NULL, *rotation = NULL;
    SDL_Rect rect;
    SDL_Event event;
    double angle = 0;
 
    int continuer = 1;
    int tempsPrecedent = 0, tempsActuel = 0;
 
    SDL_Init(SDL_INIT_VIDEO);
 
    ecran = SDL_SetVideoMode(500, 500, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Faire des rotations avec SDL_gfx", NULL);
 
    image = SDL_LoadBMP("image.bmp");
 
    rect.x =  150;
    rect.y =  150;
 
    while(continuer)
    {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
                break;
        }
 
        tempsActuel = SDL_GetTicks();
        if (tempsActuel - tempsPrecedent > TEMPS)
        {
            angle += 2; //On augmente l'angle pour que l'image tourne sur elle-même.
 
            tempsPrecedent = tempsActuel;
        }
        else
        {
            SDL_Delay(TEMPS - (tempsActuel - tempsPrecedent));
        }
 
 
        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
 
        rotation = rotozoomSurface(image, angle, 1.0, 1); //On transforme la surface image.
 
        SDL_BlitSurface(rotation , NULL, ecran, &rect); //On affiche la rotation de la surface image.
        SDL_FreeSurface(rotation); //On efface la surface rotation car on va la redéfinir dans la prochaine boucle. Si on ne le fait pas, cela crée une fuite de mémoire. 
 
        SDL_Flip(ecran);
    }
 
    SDL_FreeSurface(ecran);
    SDL_FreeSurface(image);
    SDL_Quit();
 
    return EXIT_SUCCESS;
}

Surtout n'oubliez pas d'ajouter une image dans le dossier de votre projet. ;)

Maintenant vous pouvez compiler et lancer votre programme.

Ah oui, j'ai oublié de vous dire : quand nous plaçons notre image, sa taille change à cause de la rotation ce qui la fait bouger.

La surface rotation change de taille ?

Oui, regardez ceci pour comprendre :

erreurRotation1

Ici on a fait une rotation, donc la taille de la surface a changé.

En revanche ici, l'image n'est pas tournée, donc la surface garde sa taille normale :

erreurRotation2

Donc il faut placer notre image en fonction de sa taille.

Voici le code :

#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_rotozoom.h>
 
#define TEMPS       30 // Le temps qu'il y a entre chaque augmentation de l'angle.
 
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *image = NULL, *rotation = NULL;
    SDL_Rect rect;
    SDL_Event event;
    double angle = 0;
 
    int continuer = 1;
    int tempsPrecedent = 0, tempsActuel = 0;
 
    SDL_Init(SDL_INIT_VIDEO);
 
    ecran = SDL_SetVideoMode(500, 500, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Faire des rotations avec SDL_gfx", NULL);
 
    image = SDL_LoadBMP("image.bmp");
 
    while(continuer)
    {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
                break;
        }
 
        tempsActuel = SDL_GetTicks();
        if (tempsActuel - tempsPrecedent > TEMPS)
        {
            angle += 2; //On augmente l'angle pour que l'image tourne sur elle-même.
 
            tempsPrecedent = tempsActuel;
        }
        else
        {
            SDL_Delay(TEMPS - (tempsActuel - tempsPrecedent));
        }
 
        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
 
        rotation = rotozoomSurface(image, angle, 1.0, 1); //On transforme la surface image.
 
        //On positionne l'image en fonction de sa taille.
        rect.x =  200 - rotation->w / 2;
        rect.y =  200 - rotation->h / 2;
 
        SDL_BlitSurface(rotation , NULL, ecran, &rect); //On affiche la rotation de la surface image.
        SDL_FreeSurface(rotation); //On efface rotation car on va la redéfinir dans la prochaine boucle. Si on ne le fait pas, cela crée une fuite de mémoire. 
 
        SDL_Flip(ecran);
    }
 
    SDL_FreeSurface(ecran);
    SDL_FreeSurface(image);
    SDL_Quit();
 
    return EXIT_SUCCESS;
}

Et voilà ! On a réussi à faire notre rotation. Alors, des questions ?

Euh... oui. Dans la fonction rotozoomSurface, est-ce qu'on n'aurait pas pu mettre "image = rotozoomSurface(image, angle, 1.0, 1);" ?

C'est une très bonne question. En fait oui, normalement on aurait pu le faire, mais on ne peut pas à cause du zoom parce que si à chaque fois on refait un zoom sur la même surface, alors l'image va gRANDIR jusqu'à l'infini, voilà pourquoi.
Quand dans la fonction on met 1.0, c'est pour agrandir l'image à sa taille normale. Si on met 0, l'image ne s'affiche pas, car on ne fait pas de zoom.

Un petit exercice

Maintenant on pourrait ajouter un petit gadget dans notre programme pour que vous vous rendiez compte de ce que l'on peut faire d'intéressant avec SDL_gfx.
Par exemple, ça serait bien que l'image bouge avec la souris. Et pour faire encore mieux, on pourrait aussi ajouter un effet de zoom.

Correction :magicien: :

#include <stdlib.h>
#include <stdio.h>
#include <SDL/SDL.h>
#include <SDL/SDL_rotozoom.h>
 
#define TEMPS       30 // Le temps qu'il y a entre chaque augmentation de l'angle.
 
int main(int argc, char *argv[])
{
    SDL_Surface *ecran = NULL, *image = NULL, *rotation = NULL;
    SDL_Rect rect;
    SDL_Event event;
    double angle = 0;
    double zoom = 1;
    int sens = 1;
 
    int continuer = 1;
    int tempsPrecedent = 0, tempsActuel = 0;
 
    SDL_Init(SDL_INIT_VIDEO);
 
    ecran = SDL_SetVideoMode(500, 500, 32, SDL_HWSURFACE);
    SDL_WM_SetCaption("Faire des rotations avec SDL_gfx", NULL);
 
    image = SDL_LoadBMP("image.bmp");
 
    while(continuer)
    {
        SDL_PollEvent(&event);
        switch(event.type)
        {
            case SDL_QUIT:
                continuer = 0;
                break;
        }
 
        tempsActuel = SDL_GetTicks();
        if (tempsActuel - tempsPrecedent > TEMPS)
        {
            angle += 2; //On augmente l'angle pour que l'image tourne sur elle-même.
 
            tempsPrecedent = tempsActuel;
        }
        else
        {
            SDL_Delay(TEMPS - (tempsActuel - tempsPrecedent));
        }
 
        SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 255, 255, 255));
 
        rotation = rotozoomSurface(image, angle, zoom, 0); //On transforme la surface image.
        
        //On repositionne l'image en fonction de sa taille.
        rect.x =  event.button.x - rotation->w / 2;
        rect.y =  event.button.y - rotation->h / 2;
 
        SDL_BlitSurface(rotation , NULL, ecran, &rect); //On affiche la rotation de la surface image.
        SDL_FreeSurface(rotation); //On efface la surface rotation car on va la redéfinir dans la prochaine boucle. Si on ne le fait pas, cela crée une fuite de mémoire. 
 
        if(zoom >= 2){sens = 0;}
        else if(zoom <= 0.5){sens = 1;}
 
        if(sens == 0){zoom -= 0.02;}
        else{zoom += 0.02;}
 
        SDL_Flip(ecran);
    }
 
    SDL_FreeSurface(ecran);
    SDL_FreeSurface(image);
    SDL_Quit();
 
    return EXIT_SUCCESS;
}

Voilà, c'est fini. :D

Maintenant vous savez faire des rotations !
Et donc grâce à cela, vous allez pouvoir réaliser plein de super trucs.

Bonne programmation ! :)

Exemple de certificat de réussite
Exemple de certificat de réussite