Delphipage - la reference en Delphi
Accueil - Astuces - Composants - Programmes - Tutoriaux - Livres - Liens
 Sources
- Astuces
- Composants
- Programmes
- Tutoriaux
 Rechercher
- Delphipage
- Ngscan
 Ressources
- Lexique Delphi
- Livres
- News
- Patchs Delphi
 Liens
- Borland France
- CodeGear
- Les meilleurs sites


Tutoriaux - Introduction à SDL

Présentation 

SDL (pour Simple Direct Media Layer) est une librairie multimédia gratuite fonctionnant sur plusieurs plateformes (Windows, Linux, MacOSX, BeOS, …). Elle fournit toute une panoplie de fonctions permettant de jouer des sons, gérer le clavier, la 2D, la 3D, … La programmation de jeux multi plateformes s’en trouve donc facilitée.

Afin de pouvoir l’utiliser sous Delphi, nous allons utiliser Jedi-SDL .
Le tutorial a été réalisé avec Delphi 6 Personal Edition mais il devrait certainement fonctionner sur d’autres versions de Delphi.


Installation

Télécharger la dernière version de Jedi-SDL.
Cette archive ZIP contient un fichier ZIP nommé "Jedi-sdl.zip". Décompresser ce dernier dans "c:\".
Vous devez donc obtenir l’arborescence suivante :



Aller dans le répertoire "RunTimes\Win32" et décompresser les fichiers :
  • SDL-1.2.4-win32
  • SDL_image-1.2.2-win32
  • SDL_mixer-1.2.4-win32
  • SDL_net-1.2.4-win32
  • SDL_ttf-2.0.5-win32
  • Smpeg

Copier les DLL obtenues dans le répertoire system32 ("c:\windows\system32").Suivant ce qu’utilise votre programme, vous devrez les distribuer en partie ou en totalité avec votre application. Il faut ensuite paramètrer Delphi pour que celui-ci retrouve les unités Jedi-SDL. Dans le menu "Outils" puis "Options d’environnement", onglet "Bibliothèques", ajouter les chemins de bibliothéque :
  • C:\JEDI-SDL\SDL\Pas
  • C:\JEDI-SDL\SDL_Image\Pas
  • C:\JEDI-SDL\SDL_Mixer\Pas
  • C:\JEDI-SDL\SDL_Net\Pas
  • C:\JEDI-SDL\SDL_Sound\Pas
  • C:\JEDI-SDL\SDL_ttf\Pas
  • C:\JEDI-SDL\SDLMonoFonts\Pas
  • C:\JEDI-SDL\SDLSpriteEngine\Pas
  • C:\JEDI-SDL\SFont\Pas
  • C:\JEDI-SDL\smpeg\Pas




Premier programme

Dans le menu "Fichier" de Delphi, choisir "Nouveau" puis "Autre …" et choisir "Application console".



Le premier programme ne fera qu’initialiser une fenêtre SDL.

program tut01;

uses SDL;

Var screen: PSDL_surface;

Begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1)) then //Initialisation SDL
begin

exit;
end;
SDL_WM_SetCaption('Premier Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,16,SDL_HWSURFACE); //Attributs de la fenetres
SDL_ShowCursor(0); //Cache la souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

La ligne "SDL_Init(SDL_INIT_VIDEO)" permet d’initialiser la librairie en fonction de ce que nous allons utiliser.
Les autres valeurs usuelles sont :

Paramètre
 Description
SDL_INIT_AUDIO Pour la gestion sonore.
SDL_INIT_VIDEO Pour la gestion graphique.
SDL_INIT_CDROM Pour l’accès au cdrom.
SDL_INIT_TIMER Pour utiliser des timers.
SDL_INIT_EVERYTHING Pour tout initialiser.

Ces fonctions sont à combiner avec des "or".
Par exemple, si nous voulons des fonctions sonores et des fonctions graphiques, nous aurons la fonction "SDL_Init(SDL_INIT_VIDEO or SDL_INIT_AUDIO)". La fonction retourne "-1" s’il y a un problème d’initialisation.

La ligne "SDL_SetVideoMode(640, 480, 16, SDL_SWSURFACE) permet de définir le mode vidéo à utiliser. Le premier paramètre défini la largeur de la fenêtre, le second la hauteur. Le troisieme concerne le nombre de bits/pixel. Si il est égal à 0, alors c’est la valeur courante qui est utilisée. Le dernier paramètre correspond à diverses options que l’on peut combiner avec des "or".

Paramètre
 Description
SDL_SWSURFACE Crée la surface en mémoire centrale.
SDL_HWSURFACE Crée la surface en mémoire vidéo.
SDL_HWPALETTE Donne à SDL un accès exclusif à la palette de couleurs.
SDL_FULLSCREEN Passe en mode plein ecran.
SDL_OPENGL Crée une surface utilisable pour OpenGL.
SDL_RESIZABLE Crée une fenêtre redimensionnable.
SDL_NOFRAME Crée une fenêtre sans barre de titre.

Ainsi pour ne pas être en mode fenêtré mais plein écran, la ligne serait :

screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE or SDL_FULLSCREEN);

Sous SDL, les sprites, les images et l’écran sont gérés à l’aide de surfaces dont les variables sont de type "PSDL_Surface".


Charger une image

Par défaut, l’unité SDL ne permet de charger que des fichiers BMP via la fonction "SDL_LOADBMP".
Nous allons donc utiliser l’unité SDL_Image permettant de chargé d’autre type de fichier (PCX, JPG, GIF, PNG, …).

program tut02;

uses SDL,SDL_Image;

Var screen,image: PSDL_surface;

Begin
if ((SDL_Init(SDL_INIT_VIDEO )=-1)) then //Initialisation SDL
begin

exit;
end;
SDL_WM_SetCaption('Second Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
SDL_BlitSurface(image,nil,screen,nil); //Copie image sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

Pour charger le fichier JPG, on passé par une surface nommé image. Ensuite on effectue une copie de la surface image vers la surface screen (et donc vers l’écran) à l’aide de la fonction "SDL_BlitSurface".

"SDL_BlitSurface" permet de faire des copies rapides d’une surface vers une autre.
La syntaxe de cette fonction est la suivante :


SDL_BlitSurface(source,rect_source,destination,rect_destination) ;

"Source" et "destination" sont des surfaces de type "PSDL_surface".
"rect_source" et "rect_destination" sont des variables de type "TSDL_Rect" qui permettent de définir la zone rectangulaire à copier.
Si ces valeurs sont égales à "nil", la surface toute entière est copiée.

Pour optimiser la fonction "BlitSurface", nous pourrions utiliser la fonction "SDL_DisplayFormat" sur la surface après le chargement de celle-ci.
Une variable de type "TSDL_Rect" se décompose comme ceci :


Paramètre
 Description
TSDL_Rect.X Position X du coin supérieur gauche.
TSDL_Rect.Y Position Y du coin supérieur gauche.
TSDL_Rect.H Hauteur du bloc à copier.
TSDL_Rect.W Largeur du bloc à copier.

Dans la zone de destination, seules les valeurs .X et .Y sont utilisées
Ainsi, si nous voulons uniquement copier un bloc de 300 pixels sur 50, le programme serait le suivant :

program tut02;

uses SDL,SDL_Image;

Var screen,image: PSDL_surface;
rect1,rect2 : TSDL_rect;

Begin
if ((SDL_Init(SDL_INIT_VIDEO)=-1)) then //Initialisation SDL
begin
exit;
end;
SDL_WM_SetCaption('Second Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,DL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
rect1.x:=0; //X coin superieur gauche
rect1.y:=0; //Y coin superieur gauche
rect1.w:=640; //Largeur
rect1.h:=480; //Hauteur
rect2.x:=0; //X coin superieur gauche
rect2.y:=0; //Y coin superieur gauche
SDL_BlitSurface(image,@rect1,screen,@rect2); //Copie image sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.


Les sprites

Sous SDL, les sprites sont gérés aussi par de surfaces.

program tut03;

uses SDL,SDL_Image;

Var screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect; begin

if ((SDL_Init(SDL_INIT_VIDEO)=-1)) then //Initialisation SDL
begin
exit;
end;
SDL_WM_SetCaption('Troisieme Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen,nil); //Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
SDL_Delay(5000); //On attend 5s
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

Nous remarquons que ceci ressemble fortement à tout ce que nous avons pu faire jusqu’ici.
Seule petite nouveauté, la ligne suivante :

SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL, SDL_MapRGB(sprite.format,255,255,55));

Elle permet de définir la transparence du sprite. En effet, l’arrière-plan du sprite est blanc (valeur RGB : 255,255,255) et cette ligne permet de définir cette couleur comme couleur de transparence.

Pour plus de renseignements sur cette fonction, consultez la documentation officielle de l’API de SDL.



Gestion du clavier

Dans cet exemple, nous allons faire bouger notre petit avion lorsque l’on se sert des flèches du clavier.
Volontairement, cet exemple n’est pas optimisé afin de bien comprendre le fonctionnement.

program tut04;

uses
SDL,SDL_Image;


Var
screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;


begin

if ((SDL_Init(SDL_INIT_VIDEO)=-1)) then //Initialisation SDL
begin
exit;
end;
SDL_WM_SetCaption('Quatrieme Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen, nil); //Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
Repeat
while (SDL_PollEvent(@Event) > 0) do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (keys[SDLK_UP]=SDL_PRESSED) and (rect1.y>0) then //si fleche haut
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //efface le sprite
dec(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect( screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_DOWN]=SDL_PRESSED) and (rect1.y<385) then //si fleche bas
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface le sprite
inc(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_LEFT]=SDL_PRESSED) and (rect1.x>0) then //Si fleche gauche
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface le sprite
dec(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_RIGHT]=SDL_PRESSED) and (rect1.x<490) then //Si fleche droite
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface le sprite
inc(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED); //Si appui sur espace
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

La boucle WHILE permet d’intercepter les événements. Ensuite, on récupère l’état du clavier et en fonction des touches pressées (SDLK_UP, SDLK_DOWN, SDLK_LEFT, SDLK_RIGHT) , on bouge l’avion en conséquence.


Musique

SDL permet de jouer des modules (.mod, .xm, .s3m) en musique de fond.
Pour cet exemple, il vous faudra un fichier .mod (vous pouvez en trouver pas mal sur le web, http://dir.yahoo.com/Entertainment/Music/Computer_Generated/MOD/).

program tut05;

uses
SDL, SDL_Image, SDL_Mixer, smpeg;


Var
screen,image,sprite: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;
music: PMix_Music;


begin

if ((SDL_Init(SDL_INIT_VIDEO OR SDL_INIT_AUDIO)=-1)) then
//Initialisation SDL
begin
exit;
end;
if (Mix_OpenAudio(22040, AUDIO_U8, 1, 512) < 0) then // initialise le systeme sonore a 22kb/8bits
begin
exit;
end;
SDL_WM_SetCaption('Cinquieme Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32,SDL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen, nil); //Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
SDL_ShowCursor(0); //Cache la souris
music := Mix_LoadMUS( PChar( 'mamusique.mod' ) ); //Charge le module .mod
Repeat
while (SDL_PollEvent(@Event) > 0) do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (keys[SDLK_UP]=SDL_PRESSED) and (rect1.y>0) then //Si fleche haut
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface le sprite
dec(rect1.y);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_DOWN]=SDL_PRESSED) and (rect1.y<385) then //Si fleche bas
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface le sprite
inc(rect1.y);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_LEFT]=SDL_PRESSED) and (rect1.x>0) then //Si fleche gauche
begin
SDL_BlitSurface(image,@rect1,screen,@rect1); //Efface le sprite
dec(rect1.x);
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (keys[SDLK_RIGHT]=SDL_PRESSED) and (rect1.x<490) then //si fleche droite
begin
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface le sprite
inc(rect1.x);
SDL_BlitSurface(sprite,nil,screen,@rect1); //Copie sprite sur ecran
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
end;
if (not (Mix_PlayingMusic=1)) then //Si la musique est arretée, on la joue (permet de la jouer en boucle)
begin
Mix_PlayMusic(music,0);
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED); //Si appui sur espace
Mix_CloseAudio();
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

Remarquez que la clause "USES" a changée par rapport à l’exemple précédent.

Le code source est suffisamment commenté pour ne pas avoir à détailler le fonctionnement.
Pour jouer le module, on initialise le système sonore, on charge le fichier musical et on le joue en boucle. 


Les Timers

SDL permet de gérer le temps ainsi que des timers.
Ces timers permettent de faire des appels répétitifs à des fonctions. Dans cet exemple nous allons gérer l’animation du sprite grâce à des timers.

program tut06;

uses
SDL, SDL_Image, SDL_Mixer, smpeg;


Var
screen,image,sprite,tux: PSDL_surface;
rect1 : TSDL_rect;
event: TSDL_Event;
keys: PKeyStateArr;
music: PMix_Music;
sens: boolean;
bouge : function (timer:Uint32; param:pointer) : Uint32;
time : Uint32;
timer : PSDL_TimerID;


function
affichespr(interval : UInt32; param : Pointer) : Uint32; //Fontion qui gere le deplacement du sprite
begin // interval et param sont des parametres definis par SDL
SDL_BlitSurface(image,@rect1,screen, @rect1); //Efface le sprite
if sens=false then
begin
inc(rect1.y,10); // pas de deplacement
if rect1.y>=374 then sens:=not(sens); //Hauteur fenetre(480)-(hauteur du sprite(95)+ pas de deplacement(10))
end
else
begin
dec(rect1.y,10);
if rect1.y<=10 then sens:=not(sens);
end;
SDL_BlitSurface(sprite,nil,screen, @rect1); //Copie sprite sur ecran
SDL_UpdateRect( screen,0,0,0,0); //Actualise l'ecran
affichespr:=interval; //LIGNE IMPORTANTE SINON LE TIMER NE FONCTIONNE PAS
end;
begin
if ((SDL_Init(SDL_INIT_VIDEO OR SDL_INIT_AUDIO or SDL_INIT_TIMER)=-1)) then //Initialisation SDL
begin
exit;
end;
if (Mix_OpenAudio(22040,AUDIO_U8,1,512) < 0) then
begin
exit;
end;
sens:=false;
SDL_WM_SetCaption('Mon Programme',nil); //Titre de la fenetre
screen:=SDL_SetVideoMode(640,480,32, SDL_HWSURFACE); //Attributs de la fenetres
image:=IMG_Load(PCHAR('test.jpg')); //Charge un JPG dans une surface
sprite:=IMG_Load(PCHAR('avion.bmp')); //Charge le sprite dans une surface
sprite:=SDL_DisplayFormat(sprite);
SDL_BlitSurface(image,nil,screen,nil); //Copie image sur ecran
rect1.x:=300;
rect1.y:=240;
rect1.w:=150;
rect1.h:=95;
SDL_SetColorKey(sprite,SDL_SRCCOLORKEY OR SDL_RLEACCEL,SDL_MapRGB(sprite.format,255,255,255));
SDL_ShowCursor(0); //Cache la souris
music:=Mix_LoadMUS( PChar('ma_musique.mod'));
SDL_UpdateRect(screen,0,0,0,0); //Actualise l'ecran
time:=20; //Periodicite du timer
bouge:=affichespr; //Fonction appelée par le timer
timer:=SDL_AddTimer(time,@bouge,nil); //Initialise un timer
Repeat
while (SDL_PollEvent(@Event) > 0) do
begin
case Event.type_ of
SDL_QuitEv:
begin
Exit;
end;
end;
end;
keys:=PKeyStateArr(SDL_GetKeyState(nil));
if (not(Mix_PlayingMusic=1)) then
begin
Mix_PlayMusic(music,0);
end;
Until (keys[SDLK_SPACE]=SDL_PRESSED); //Si appui sur espace
SDL_RemoveTimer(timer); //Detruit le timer
Mix_CloseAudio();
SDL_ShowCursor(1); //Affichage souris
SDL_Quit; //On quitte
end.

La fonction "affichespr" gère le déplacement du sprite. Nous ajoutons à cette fonction les paramètres ("interval : UInt32; param : Pointer") comme défini dans la documentation SDL. Via "param", nous pouvons passer des paramètres à cette fonction (nous ne nous en servirons pas dans cet exemple). "interval" est une variable qui permet de retourner le prochain intervalle du timer (d’où la ligne "affichespr:=interval;" en fin de fonction).

La fonction "SDL_AddTimer" retourne un identificateur unique pour le timer crée. C’est cet identificateur qui permet supprimer le timer en temps voulu avec la fonction "SDL_RemoveTimer(id)".

A noter, le paramètre "SDL_INIT_TIMER" qui se trouve dans la ligne d’initialisation de SDL.



Introduction à SDL    [ 21-11-2004 ]
 Exemples d'utilisation de SDL en Delphi.
Télécharger :  [114 Ko] [Télécharger sdl.zip]

Auteur : Shogun


Pour aller plus loin...

Ici s’achève cette introduction sur l’utilisation de la bibliothèque SDL en Delphi, via les unités Jedi-SDL. Bien sûr, nous sommes loin d’avoir fait le tour de toutes les possibilités offertes par SDL.

Pour aller plus loin, voici quelques liens intéressants :


Tous droits réservés - Contacts
Haut de la page