Manipuler les surfaces

Surface

L'écran : ma première surface

Vous n'avez pour le moment qu'une fenêtre à fond noir. On veut dessiner à l'intérieur de cette fenêtre, et le seul outil donné par la SDL est le rectangle. Un rectangle est une surface, et pour créer différentes formes, il faudra assembler des rectangles.
La première surface que nous allons créer est l'écran, chaque surface sera mémorisée dans des variables de type SDL_Surface. C'est une structure créée par la SDL. Donc pour créer la surface écran, il suffit de placer cette ligne de code :

SDL_Surface *ecran = NULL;

On la crée en pointeur, car l'espace mémoire utilisé par l'écran risque de changer au cours du temps, c'est donc une variable allouée dynamiquement. La fonction SDL_SetVideoMode renvoie une valeur. Cette valeur est un pointeur sur la surface de l'écran, on va donc pouvoir le récupérer dans notre variable ecran, par cette ligne de commande :

ecran = SDL_SetVideoMode(…);

Notre pointeur peut valoir :
Null : le SDL_SetVideoMode n'a pas réussi à charger le mode vidéo demandé. Cela arrive si vous demandez une trop grande résolution ou un trop grand nombre de couleurs que ne supporte pas votre ordinateur. Vous pouvez récupérer l'erreur via la fonction SDL_GetError().
Une autre valeur : La SDL a pu allouer la surface en mémoire, donc tout est bon !
On peut donc gérer les erreurs quant-à l'allocation en mémoire de l'écran. Essayez de créer un programme qui gère ces erreurs.
Nous l'avons fait de cette manière :

int main(int argc, char * argv[]) {
SDL_Surface *ecran = NULL; //Le pointeur qui va stocker la surface de l'écran
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE); //On tente d'ouvrir une fenêtre
if(ecran==NULL) { //Si l'ouverture a échoué, on écrit l'erreur et on arrête
fprintf(stderr, "Impossible de charger le mode vidéo : %s\n", SDL_GetError());
exit(EXIT_FAILURE);
}
SDL_WM_SetCaption("Ma fenêtre SDL", NULL);
pause();
SDL_Quit();
return EXIT_SUCCESS:
}

Colorer l'écran

Vous avez deux façons de colorer une surface, soit en chargeant une image, soit en la remplissant par une couleur unie. Nous ne nous intéresseront qu'à la deuxième méthode dans ce tutoriel.
La fonction qui permet de colorer une surface avec une couleur unie s'appelle :

SDL_FillRect()

FillRect signifiant littéralement "Remplir Rectangle" en anglais. Elle prend 3 paramètres :
-un pointeur sur la surface dans laquelle on doit dessiner (par exemple ecran).
-la partie de la surface qui doit être remplie. Si vous voulez remplir toute la surface (et c'est ce qu'on veut faire), envoyez NULL.
-la couleur à utiliser
Pour résumer :

SDL_FillRect(surface, NULL, couleur);

Le plus compliqué à gérer sera la couleur à choisir pour remplir la surface. Pour choisir la couleur, nous allons nous servir de la fonction SDL_MapRGB() qui prend 4 paramètres :
-le format des couleurs. Ce format dépend du nombre de bits/pixel que vous avez demandé avec SDL_SetVideoMode. Vous pouvez le récupérer, il est stocké dans la sous-variable ecran->format
-la quantité de rouge de la couleur
-la quantité de vert de la couleur
-la quantité de bleu de la couleur
Sur un ordinateur, toutes les couleurs sont constituées de 3 couleurs de base : le rouge, le vert et le bleu. Chaque quantité peut varier de 0 (pas de couleur) à 255 (toute la couleur). Par exemple :

SDL_MapRGB(ecran->format, 255, 0, 0); //Vous aurez du rouge, il n'y a ni vert ni bleu
SDL_MapRGB(ecran->format, 0, 0, 255); //Vous aurez du bleu
SDL_MapRGB(ecran->format, 255, 255, 255); //Vous aurez du blanc, qui est la somme des 3 couleurs. Pour le noir, il faudra mettre 0, 0, 0.
Petite astuce pour connaître facilement les doses des couleurs que vous souhaitez : lancez paint, allez (sur Windows XP/Vista) dans le menu "Couleurs/Modifier les couleurs", cliquez sur le bouton "Définir les couleurs personnalisées" ou (sur Windows 7) cliquez sur "Modifier les couleurs". Là, choisissez la couleur qui vous intéresse :

Image Paint

Les composantes de la couleur sont affichées en bas à droite. Ici, ce bleu-vert sélectionné se crée à l'aide de 17 de rouge, 206 de vert et 112 de bleu.

Coloration de l'écran :
Pour stocker une couleur que vous pourrez réutiliser, vous pouvez faire comme ceci :

Uint32 bleuVert=SDL_MapRGB(ecran->format, 17, 206, 112);

Ici la couleur sera stockée dans la variable bleuVert.

Mais pour colorer l'écran ou une surface, il n'est pas nécessaire de passer par une variable où stocker la couleur, bien au contraire, il est plus simple de faire comme ceci :

SDL_FillRect(ecran, NULL, SDL_MapRGB(ecran->format, 17, 206, 112));


Mise à jour de l'écran :
Si vous avez essayé la fonction précédente, vous avez pu remarquer que l'écran est toujours noir. En effet, la fonction SDL_FillRect colore bien l'écran, mais elle ne le fait que dans la mémoire. Il faut donc demander à l'ordinateur de mettre à jour l'écran avec les nouvelles données. Pour cela il existe une fonction : SDL_Flip.

SDL_Flip(ecran); //Mise à jour de l'écran

En résumé, voici un main qui vous fera apparaître une fenêtre avec un fond bleu/vert :
int main(int argc, char * argv[]) {
SDL_Surface *ecran = NULL;
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode (640, 480, 32, SDL_HWSURFACE);
SDL_WM_SetCaption ("Ma fenêtre SDL", NULL);
// Coloration de la surface ecran en bleu/vert
SDL_FillRect (ecran, NULL, SDL_MapRGB (ecran->format, 17, 206, 112));
SDL_Flip (ecran); // Mise à jour de l'écran avec sa nouvelle couleur
pause ();
SDL_Quit ();
return EXIT_SUCCESS;
}

Créer une nouvelle surface

Pour le moment, vous n'avez qu'une seul surface : l'écran. On va pouvoir dessiner dessus, c'est-à-dire coller de nouvelles surfaces par dessus (tant mieux en même temps, vous imaginez avoir appris tout ça pour colorer une fenêtre ?). Tout d'abord, on va créer une nouvelle variable SDL_Surface.

SDL_Surface *rectangle=Null;

Pour créer une nouvelle surface, nous n'allons pas utiliser la même fonction que celle de l'écran. Effectivement, nous n'allons pas créer une nouvelle fenêtre à chaque fois que l'on voudra créer une surface, c'est pourquoi nous allons utiliser la fonction

SDL_CreateRGBSurface.

Cette fonction prend en compte beaucoup de paramètres mais nous n'en utiliserons que quelques uns.
Regardons de plus près les plus intéressants, c'est-à-dire les 4 premiers paramètres :
-Une liste d'options. Vous avez le choix entre :
SDL_HWSURFACE : la surface sera chargée en mémoire vidéo. Il y a moins d'espace dans cette mémoire que dans la mémoire système (quoi que, avec les cartes 3D qu'on sort de nos jours c'est plus forcément vrai …), mais cette mémoire est plus optimisée et accélérée.
SDL_SWSURFACE : la surface sera chargée en mémoire système, où il y a plus de place, mais cela obligera votre processeur à faire plus de calculs. En chargeant en mémoire vidéo, c'est la carte 3D qui fait la plupart des calculs.
-La largeur de la surface (en pixels)
-La hauteur de la surface (en pixels)
-Le nombre de couleurs (en bits/pixels)
-Une suite d'autres paramètres qui ne nous intéresseront pas. Nous mettrons des 0 pour chacun des 4 paramètres supplémentaires. Donc pour allouer une partie de la mémoire pour un rectangle de largeur 220 pixels et une hauteur de 180 pixels, voici comment faire :

rectangle=SDL_CreateRGBSurface(SDL_HWSURFACE, 220, 180, 32, 0, 0, 0, 0);

Puisque cette surface a été allouée dynamiquement, il faudra ne pas oublier de rendre la mémoire à la fin du programme par une simple commande :

SDL_FreeSurface(rectangle);

Cette fonction possède les mêmes caractéristiques que la fonction SDL_Quit(). La surface écran est automatiquement libérée lors de SDL_Quit().
On peut colorer cette nouvelle surface en blanc par exemple. Essayez de le faire seul.
Voici la commande :

SDL_FillRect(rectangle, NULL, SDL_MapRGB(ecran->format, 255,255,255));

Coller la nouvelle surface sur l'écran

Pour coller la nouvelle surface, il va falloir une nouvelle commande : SDL_BlitSurface.
Cette fonction attend 4 paramètres :
-La surface à coller (ici, ça sera rectangle)
-Une information sur la partie de la surface à coller (facultative). Ca ne nous intéresse pas car on veut coller toute la surface. On enverra donc NULL.
-La surface sur laquelle on doit coller, c'est-à-dire ecran dans notre cas.
-Un pointeur sur une variable contenant des coordonnées. Ces coordonnées indiquent où devra être collée notre surface sur l'écran (la position).
Pour les coordonnées, nous allons utiliser une nouvelle structure qui attend plusieurs paramètres, dont 2 qui nous intéressent :
x : l'abscisse
y : l'ordonnées
Il faut savoir que le point de coordonnées (0,0) est situé tout en haut à gauche. Si vous avez ouvert une fenêtre de taille 640x480, alors le point en bas à droite a les coordonnées (640,480).

image fenêtre surface

Vous ne devriez pas avoir trop de mal à comprendre. Donc pour coller la surface rectangle, nous allons créer une variable position de type SDL_Rect de cette façon :

SDL_Rect position;
position.x=0;
position.y=0;
Ici, nous avons mis x et y à 0 dans le but d'afficher la nouvelle surface en haut à gauche de l'écran. Maintenant, il faut mettre la surface sur ecran en la "blittant".

SDL_BlitSurface(rectangle, NULL, ecran, &position);

Voici donc un exemple de code pour obtenir un carré blanc en haut à gauche d'une fenêtre bleue/verte :
int main (int argc, char *argv []) {
SDL_Surface *ecran = NULL, *rectangle = NULL;
SDL_Rect position;
SDL_Init(SDL_INIT_VIDEO);
ecran = SDL_SetVideoMode (640, 480, 32, SDL_HWSURFACE);
rectangle = SDL_CreateRGBSurface (SDL_HWSURFACE, 220, 180, 32, 0, 0, 0, 0); // Allocation de la surface
SDL_WM_SetCaption ("Ma super fenêtre SDL !", NULL);
SDL_FillRect (ecran, NULL, SDL_MapRGB (ecran->format, 17, 206, 112));
position.x = 0; // Les coordonnées de la surface seront (0, 0)
position.y = 0;
SDL_FillRect (rectangle, NULL, SDL_MapRGB (ecran->format, 255, 255, 255)); // Remplissage de la surface avec du blanc
SDL_BlitSurface (rectangle, NULL, ecran, &position); // Collage de la surface sur l'écran
SDL_Flip (ecran); // Mise à jour de l'écran
pause ();
SDL_FreeSurface (rectangle); // Libération de la surface
SDL_Quit ();
return EXIT_SUCCESS;
}

Centrer la surface à l'écran

Vous n'aurez qu'à modifier vos valeurs de x et y. Avec un peu de réflexion, vous devriez y arriver seul :

position.x=(640/2)-(220/2);
position.y=(480/2)-(180*2);

L'abscisse du rectangle sera la moitié de la largeur de l'écran (640/2), mais en plus de ça, il faut retrancher la moitié de la largeur du rectangle (220/2), car sinon, ça sera le point à gauche du rectangle qui sera centré. C'est la même chose pour l'ordonnée avec la hauteur de l'écran et du rectangle. Voici ce que vous devriez obtenir à l'écran :
image surface 2

Créer un site gratuit avec e-monsite - Signaler un contenu illicite sur ce site