Uporaba večpredstavnih knjižnic SDL
SDL (Simple DirectMedia Layer) je večpredstavna knjižnica, podobna DirectX, vendar jo je bistveno enostavneje uporabljati.
SDL podpira naslednje operacijske sisteme: Linux, Windows, BeOS, MacOS Classic, MacOS X, FreeBSD, OpenBSD, BSD/OS, Solaris, IRIX, in QNX. Knjižnica SDL je izvirno napisana v programskem jeziku C/C++. Obstaja pa povezava z drugimi programskimi jeziki, med drugim: ada, eiffel, java, lua, ML, perl, PHP, pike, python in ruby. Če obvladamo osnove programskega jezika C, SDL ponuja preprosto in zabavno izdelovanje večpredstavnih uporabniških programov in igric.
Namestitev (Linux)
Najnovejša različica knjižnic SDL je na spletni strani http://www.libsdl.org/download-1.2.php. Na voljo so izdaje, ki podpirajo različne operacijske sisteme in arhitekture računalnikov.
Prenesite paket z izvirno kodo SDL-1.2.6.tar.gz in vpišite naslednje zaporedje ukazov v lupini:
# tar xzvf SDL-1.2.6.tar.gz
# ./configure ; make ; make install
SDL in programski jezik C/C++
Za dostop do funkcij SDL v programskem jeziku C/C++ v izvirno kodo vključujemo datoteko SDL.h (predprocesorski ukaz #include).
Inicializacijo knjižnic izvedemo s funkcijo SDL_Init, ki določa, katere namenske sklope funkcij bomo uporabili v kodi. Možno je upravljanje različnih naprav: zaslona, zvočne kartice, cd-roma, igralne palice, miške in tipkovnice.
V spodnjem zgledu izvajamo inicializacijo zaslona in zvoka:
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
printf ("Napaka: ne morem inicializirati SDL: %s\n", SDL_GetError());
exit(1);
}
Pri zaključevanju programa funkcija atexit() kliče funkcijo SDL_Quit. Ta funkcija na novo nastavi vse video načine in briše prejšnje nastavitve knjižnic SDL.
V nadaljevanju bomo podali opis osnovnih pojmov in funkcij ter zglede rabe knjižnic SDL v programskem jeziku C/C++.
Površine
Knjižnice SDL uporabljajo pojem površin (surfaces) za predstavitev področij grafičnega pomnilnika. Površina je, na primer, zaslon ali slika BMP. Površine SDL so deklarirane kot kazalec na "grafično" strukturo SDL_Surface.
Preden začnemo risati, s funkcijo SDL_SetVideoMode pripravimo površino za risanje (zaslon). Funkcija jemlje naslednje parametre: širino in višino grafične ločljivosti, bitno globino (bitdepth) in grafične možnosti.
Na voljo so naslednje grafične možnosti:
Delo s površinami
SDL ponuja precejšnji nabor funkcij za delo z zaslonom in površinami. Podali bomo nekaj osnovnih:
Funkcija SDL_LoadBMP naloži površino, podano z imenom datoteke BMP, kot lasten argument. Vrnjena vrednost funkcije je kazalec na strukturo SDL_Surface, ki bo enolično predstavljal naloženo datoteko BMP v drugih funkcijah za delo s površinami.
SDL_Surface *p_znakec;
p_znakec = SDL_LoadBMP("znakec.bmp");
Površino je mogoče shraniti z uporabo funkcije SDL_SaveBMP.
int SDL_SaveBMP(SDL_Surface *surface, const char *file);
Funkcija jemlje dva argumenta: kazalec na površino in ime datoteke BMP, v katero bo površina shranjena. Funkcija vrne vrednost 0, če je bilo shranjevanje uspešno, oziroma -1, če se je zgodila napaka.
Za risanje (kopiranje) površine na drugo površino uporabljamo funkcijo SDL_BlitSurface.
SDL_BlitSurface(p_slika, NULL, zaslon, &koordinate);
Prvi argument funkcije predstavlja površino, ki bo izrisana na površini, določeni s tretjim argumentom funkcije. Položaj kopirane površine na ciljni površini predstavlja četrti argument funkcije, ki je kazalec na strukturo SDL_Rect. Dejanski položaj določata člena x in y te strukture:
typedef struct{
Sint16 x, y;
Uint16 w, h;
} SDL_Rect;
V programskem zgledu, ki ga bomo podali v nadaljevanju, uporabljamo funkcijo RisiSlikoNaZaslon za izrisovanje površin na zaslonu.
// Funkcija riše sliko na zaslon
void RisiSlikoNaZaslon(SDL_Surface *p_slika, int n_x_poz, int n_y_poz, SDL_Surface* &zaslon)
{
SDL_Rect koordinate;
koordinate.x = n_x_poz;
koordinate.y = n_y_poz;
SDL_FillRect(zaslon, NULL, 2000);
SDL_BlitSurface(p_slika, NULL, zaslon, &koordinate);
SDL_Flip(zaslon);
}
Funkcija SDL_FillRect() izpolni zaslon z modro barvo (vrednost 1000). Funkcijo SDL_Flip() uporabljamo za sinhronizacijo podatkov risane površine z zaslonom.
Obdelava dogodkov
Obdelava dogodkov (event handling) omogoča uporabniškemu programu sprejemanje uporabniških vhodnih podatkov iz tipkovnice, miške ali igralne palice.
Dogodke inicializiramo s klicem funkcije SDL_Init.
SDL_Init(SDL_INIT_VIDEO);
SDL shranjuje vse dogodke, ki čakajo na obdelavo, v dogodkovno vrsto (event queue). Branje dogodkov iz dogodkovne vrste izvajamo ob pomoči funkcije SDL_PollEvent. Funkcija jemlje kot argument kazalec na strukturo SDL_Event.
Podali bomo enostaven zgled obdelave dogodkov. Ob pritisku na tipko Esc se bo sprožil dogodek, ki bo povzročil konec programa:
Najprej deklariramo dogodek test_dogodka s pomočjo strukture SDL_Event:
SDL_Event test_dogodka;
Dogodek test_dogodka nastopa kot argument v funkciji SDL_PollEvent. Ta funkcija je hkrati argument while zanke, v kateri preverjamo tip novo nastalega dogodka:
while ((SDL_PollEvent(&test_dogodka))) {
if (test_dogodka.type == SDL_KEYDOWN)
if (test_dogodka.key.keysym.sym == SDLK_ESCAPE) // Konec programa
exit(1);
}
Tip dogodka je določen s členom type strukture SDL_Event. V naslednji vrstici preverjamo, ali je prišlo do pritiska ene od tipk na tipkovnici:
if (test_dogodka.type == SDL_KEYDOWN)
Temu sledi določanje pritisnjene tipke:
if (test_dogodka.key.keysym.sym == SDLK_ESCAPE)
Tipko Esc (Escape) predstavlja konstanta SDLK_ESCAPE.
Podobno bi preverjali pritisk drugih tipk, na primer:
puščica gor
SDLK_UP
puščica dol
SDLK_DOWN
puščica levo
SDLK_LEFT
puščica desno
SDLK_RIGHT
tipka q
SDLK_q
tipka r
SDLK_r
Na miški poznamo naslednje tipe dogodkov: SDL_MOUSEMOTION (premik miške) in SDL_MOUSEBUTTONDOWN/UP (pritisk tipke na miški).
Tipi dogodkov na igralni palici so: SDL_JOYAXISMOTION, SDL_JOYAXISMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN/UP.
Zgled rabe knjižnic SDL
Podali bomo program, ki bo omogočal premikanje slike na zaslonu z usmerjevalnimi tipkami (puščice). Hkrati bo možno premeščati sliko na poljubno mesto s pritiskom na levo tipko miške. V ta namen potrebujemo poljubno sliko BMP, veliko 30 × 30 pikslov. Ker je barvna podlaga modre barve, izberite barvo slike, ki bo vidna na taki podlagi. Sliko shranite pod imenom znakec.bmp v isto mapo kakor program.
// Datoteka SDL_zgled.c
// Zgled rabe knjižnic SDL
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
// Definiramo, za koliko se premakne slika
// na zaslonu ob pritisku na tipko
#define PREMIK 20
// Deklaracija površin
SDL_Surface *p_zaslon; // Zaslon
SDL_Surface *p_znakec; // Slika
// Funkcija riše sliko na zaslon
void RisiSlikoNaZaslon(SDL_Surface *p_slika, int n_x_poz, int n_y_poz, SDL_Surface* &zaslon)
{
SDL_Rect koordinate;
koordinate.x = n_x_poz;
koordinate.y = n_y_poz;
SDL_FillRect(zaslon, NULL, 2000);
SDL_BlitSurface(p_slika, NULL, zaslon, &koordinate);
SDL_Flip(zaslon);
}
/*** Glavni program ***/
int main()
{
SDL_Event event;
// Začetni položaj na zaslonu
int n_x = 200;
int n_y = 200;
// Začetno stanje tipk
bool b_tipka_dol = false;
bool b_dol = false;
bool b_gor = false;
bool b_levo = false;
bool b_desno = false;
// Inicializacija knjižnic SDL
if (SDL_Init(SDL_INIT_AUDIO | SDL_INIT_VIDEO) < 0) {
printf ("Napaka: ne morem inicializirati SDL: %s\n", SDL_GetError());
exit(1);
}
atexit(SDL_Quit);
// Priprava površine za risanje (zaslona)
p_zaslon = SDL_SetVideoMode(800, 600, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
// Preverjanje
if (p_zaslon == NULL) {
printf("Ne morem inicializirati video signala na ločljivost 640 x 480: %s\n", SDL_GetError());
exit(1);
}
// Kazalec na površino SDL povežemo z datoteko BMP
p_znakec = SDL_LoadBMP("znakec.bmp");
// Rišemo sliko na zaslon
RisiSlikoNaZaslon(p_znakec, n_x, n_y, p_zaslon);
// Preverjamo, ali so dogodki v dogodkovni vrsti
while(true) {
while ((SDL_PollEvent(&event)) || (b_tipka_dol)) {
// Preverjamo, ali so bile tipke pritisnjene
if (event.type == SDL_KEYDOWN) {
b_tipka_dol = true;
switch (event.key.keysym.sym) {
case SDLK_UP:
n_y -= PREMIK;
b_gor = true;
break;
case SDLK_DOWN:
n_y += PREMIK;
b_dol = true;
break;
case SDLK_RIGHT:
n_x += PREMIK;
b_desno = true;
break;
case SDLK_LEFT:
n_x -= PREMIK;
b_levo = true;
break;
case SDLK_ESCAPE:
exit(1);
break;
}
// Preverjamo, ali so bile tipke sproščene
} else if (event.type == SDL_KEYUP) {
b_tipka_dol = b_gor = b_dol = b_desno = b_levo = false;
break;
// Preverjamo pritisk tipke na miški
} else if (event.type == SDL_MOUSEBUTTONDOWN) {
RisiSlikoNaZaslon(p_znakec, event.button.x, event.button.y, p_zaslon);
n_x = event.button.x;
n_y = event.button.y;
}
// Premikamo in rišemo sliko, dokler je tipka pritisnjena
if (b_gor)
n_y -= PREMIK;
else if (b_dol)
n_y += PREMIK;
else if (b_desno)
n_x += PREMIK;
else if (b_levo)
n_x -= PREMIK;
if (b_tipka_dol)
RisiSlikoNaZaslon(p_znakec, n_x, n_y, p_zaslon);
}
}
return 0;
}
Program prevedemo in poženemo z naslednjim zaporedjem ukazov v lupini:
# g++ -c `sdl-config --cflags` SDL_zgled.c
# g++ -o SDL_zgled SDL_zgled.o `sdl-config --libs` -lSDL_image
# ./SDL_zgled
Ukazovanje cd-romu
Za konec še posladek. Knjižnice SDL omogočajo analizo in predvajanje zvočnih zapisov na cd-romu, neposredno iz programskega jezika C/C++.
Sledi zgled, ki bo prikazal vsebino cd-roma in nato predvajal posamezne skladbe:
// Datoteka: cdrom.c
// SDL knjižnice: primer upravljanja naprave CD-ROM
#include <stdio.h>
#include <stdlib.h>
#include <SDL/SDL.h>
int main ()
{
SDL_CD *cdrom; // Deklariramo napravo CD-ROM
CDstatus status;
int n_st, n_m, n_s, n_f;
// Najprej inicializiramo SDL za upravljanje naprave CR-ROM
if (SDL_Init(SDL_INIT_CDROM) < 0 ) {
fprintf(stderr, "Napaka pri inicializaciji SDL: %s\n",SDL_GetError());
exit(1);
}
// Izhod
atexit(SDL_Quit);
// Odpri privzeto napravo CD-ROM
cdrom = SDL_CDOpen(0);
// Preveri, ali je bilo odpiranje uspešno
if (cdrom == NULL) {
fprintf(stderr, "Ne morem odpreti privzete naprave CD-ROM: %s\n",
SDL_GetError());
exit(2);
}
// Status naprave CR-ROM
SDL_CDStatus(cdrom);
printf("Skladbe: %d\n", cdrom->numtracks);
for (n_st = 0; n_st < cdrom->numtracks; ++n_st) {
FRAMES_TO_MSF(cdrom->track[n_st].length, &n_m, &n_s, &n_f);
if (n_m > 0)
++n_m;
printf("\tSkladba (index %d) %d: %d:%2.2d\n", n_st,
cdrom->track[n_st].id, n_m, n_s);
}
// Predvajaj celotni CD
//if (CD_INDRIVE(SDL_CDStatus(cdrom)) )
// SDL_CDPlayTracks(cdrom, 0, 0, 0, 0);
// Predvajaj zadnjo skladbo
//if (CD_INDRIVE(SDL_CDStatus(cdrom)) ) {
// SDL_CDPlayTracks(cdrom, cdrom->numtracks-1, 0, 0, 0);
//}
// Predvajaj 10 s prve skladbe
if ( CD_INDRIVE(SDL_CDStatus(cdrom)) )
SDL_CDPlayTracks(cdrom, 0, 0, 0, CD_FPS * 10);
}
Program prevedemo in poženemo z naslednjim zaporedjem ukazov v lupini:
# g++ -c `sdl-config --cflags` cdrom.c
# g++ -o cdrom cdrom.o `sdl-config --libs` -lSDL_image
# ./cdrom
Še več podatkov o uporabi knjižnic SDL najdete na spletni strani http://www.libsdl.org/index.php.