Objavljeno: 24.10.2005 19:39 | Avtor: Dalibor Kranjčič | Monitor Marec 2004

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:

  • SDL_SWSURFACE - Ustvari video površino v sistemskem pomnilniku.

  • SDL_HWSURFACE - Ustvari video površino v video pomnilniku.

  • SDL_ANYFORMAT - Dovoljuje ustvarjanje površine poljubne bitne globine.

  • SDL_HWPALETE - Omogoča popoln dostop do barvne lestvice video pomnilnika.

  • SDL_DOUBLEBUF - Uporabi dvojno pomnjenje (double buffering) površine. Program najprej ustvari vse risane predmete v dvojnem medpomnilniku, nato pa kopira celotno vsebino v video pomnilnik.

  • SDL_FULLSCREEN - Prikaže celoten zaslon.

  • SDL_OPENGL - Ustvari površino tipa OpenGL.

  • SDL_RESIZABLE - Ustvari okno z možnostjo spreminjanja velikosti.

  • SDL_NOFRAME - Ustvari okno brez okvira.

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.

Naroči se na redna tedenska ali mesečna obvestila o novih prispevkih na naši spletni strani!

Komentirajo lahko le prijavljeni uporabniki

 
  • Polja označena z * je potrebno obvezno izpolniti
  • Pošlji