SDL

Példaprogramok

Egy egyszerű példaprogram

Most, hogy mindent előkészítettünk készítsünk végre egy olyan programot, ami valamilyen szemmel látható módon alkalmazza az SDL szolgáltatásait. Kezdjük a videó alrendszer használatával és az eseménykezeléssel, mivel ezek a domináns csoportok. Egy általános grafikus SDL alkalmazás a kezdetek kezdetén. A következő:

#include #include"SDL.h" intmain() { SDL_Surface*sdl_surface; SDL_Eventsdl_event; boolmain_loop_exit = false; /*Ide jön az inicializálás!*/ sdl_surface=SDL_SetVideoMode(640,480,16,SDL_SWSURFACE); if(sdl_surface == NULL) { std::cerr << "SDL_Surfacehiba:" << SDL_GetError(); exit(1); } while(!main_loop_exit) { while(SDL_PollEvent(&sdl_event)) { switch(sdl_event.type) { case SDL_KEYDOWN: main_loop_exit = true; break; default: break; } } } SDL_Quit(); return 0; }

módon nézhet ki. Amint láthatjuk már egy alap SDL program is több sorra rúghat. Nem zárom ki, hogy kevesebb sorból is ki lehet jönni. Lássuk sorban mit is csinál az előző kódrészlet. Láthatjuk, hogy deklaráltunk egy SDL_Surface típusú mutatót. Ez a mutató fog mutatni egy videó felületre, amit az SDL_SetVideoMode eljárással alakíthatunk ki. Ez az eljárás rendre a következő paramétereket várja: képernyő szélessége, magassága, bitek száma pixelenként és flagek. Ha gond van akkor NULL mutatóval tér vissza.

Aparaméterek közül a flagek szorulnak némi magyarázatra. Ezek közül is több létezik. Az SDL_SWSURFACE alapján a rendszer a videó felületet a rendszer memória területén foglalja le, SDL_HWSURFACE esetén pedig a videómemóriában. Ha teljes képernyőn szeretnénk látni az adott felbontást, akkor használjuk az SDL_FULLSCREEN flaget. Ezeket a flageket természetesen a vagy („|”) művelettel össze tudjuk kapcsolni, például:

SDL_SetVideoMode(640,480,16,SDL_SWSURFACE | SDL_FULLSCREEN)

A másik fontos dolog az eseménykezelés. A videószolgáltatás szemléltetése kényelmesebb így, hiszen ha a kódot enélkül futtatnánk, akkor a videófelületből nem láthatnánk semmit sem, csupán egy felvillanó ablakot, vagy teljes képernyős mód esetén egy villanást. Az SDL minden eseményt egy eseménysorban tárol. Az ebben a sorban tárolt eseményeket az SDL_PollEvent eljárással nyerhetjük ki.

Az SDL_Event típus egy unió típus. Innen az eseménytípusától függően kinyerhetjük a számunkra értékes adatokat, többek között, hogy milyen az adott esemény(billentyűleütés vagy felengedés, egérgomb, egér mozgatása stb.) . Az előző kódrészletben az SDL_KEYDOWN eseményre hivatkozunk. Használhatjuk még az SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, szintén eléggé magukért beszélő elnevezéseket is.

Tehát alapból az eseménykezeléshez deklarálnunk kell egy SDL_Event változót, valamit ki kell nyernünk ebbe a változóba az eseménysorból, az éppen soron lévő eseményt az SDL_PollEvent eljárással. Innen pedig a típustól függően lekezelhetjük a felhasználó interakcióit. Később még több példát is láthatunk erre. Most főként a kényelem miatt vezettük csak be az eseménykezelést. A programunk most bármely billentyű megnyomására kilép.

Példaprogram: színátmenet

Térjünk vissza a videószolgáltatáshoz. Most hogy már van egy felületünk a soron következő dolog, hogy meg is tudjunk jeleníteni valamit. Lássunk hogyan nézhet ki egy pixelt megjelenítő rutin.

voidpixel(SDL_Surface* surface, intx, inty, Uint16color) { Uint16 *p = (Uint16*) surface -> pixels + y * surface -> pitch / 2 + x; *p = color; }

A p mutatóban az x és y koordinátákból kiszámolt pixel memóriában elfoglalt helyét kapjuk meg. Ez most a 16 bites színmélység speciális esete. Más bit értékek esetén ügyeljünk a mutatók típusára! A surface -> pixels tag mutat a tényleges videófelületre, ahová aszínértékeket írhatjuk be. Ehhez adjuk hozzá a klasszikus módon kiszámított pixel helyét. A szín (color) érték kiszámításához az SDL_MapRGB függvényt hívjuk segítségül. Ezzel az eljárással keverhetünk ki a piros, zöld, kék értékekből, az adott felület típusától függően színértékeket. Például állítsuk elő az sdl_surface felülethez illő sárga színértéket:

Uint16 sarga = SDL_MapRGB(sdl_surface -> format, 0xff, 0xff, 0x00)

Így a (10,10) koordinátában már ki tudunk rajzolni egy sárga képpontot:

pixel(sdl_surface,10,10,sarga);

Azonban egy videófelületre nem lehet csak úgy „firkálni”! A felületet le kell zárnunk, addig amíg a módosítás történik. Ez több szálú programozás esetén hasznos dolog, hiszen gondoljuk csak el mi történne ha egyszerre több programszál egy idõben kezdene kirajzolni egy adott felületre. Az SDL_LockSurface eljárás segít nekünk. Lássunk egy konkrét példát, mely amár ismertetett pixel eljárást alkalmazza.

#include #include "SDL.h" void pixel(SDL_Surface* surface, int x, int y, Uint16 color) { ... } int main() { SDL_Surface* sdl_surface; SDL_Event sdl_event; bool main_loop_exit = false; Uint16 color; ... /* Itt inicializálunk */ sdl_surface = SDL_SetVideoMode(255, 255, 16, SDL_SWSURFACE); if (sdl_surface == NULL) { ... } // Lefoglaljuk az írásjogot a felületre. SDL_LockSurface(sdl_surface); for(Uint16 i=0;i<255;i++) { for(Uint16 j=0;j<255;j++) { // Színkeverés és kirajzolás. color = SDL_MapRGB(sdl_surface->format, i, j,255-j); pixel(sdl_surface,i,j,color); } } // A felület frissítése SDL_UpdateRect(sdl_surface, 0,0,255,255); // Elengedjük a felületet. SDL_UnlockSurface(sdl_surface); while (!main_loop_exit) {...} ... return 0; }

A következõ képet fogja kirajzolni:

Kirajzolt kép

Amint látjuk alkalmaztunk egy SDL_UpdateRect nevű eljárást. Ennek segítségével aktivizáljuk az adott felületen a változtatásokat és jelenítjük meg a frissített felületet. Paraméterként a felület nevét, majd a frissítendõ négyzet koordinátáit várja (balfelsõ sarok, jobb alsó sarok). Hogy látványosan elnevezzük az elsõ komolyabb SDL programunkat, ismerjük meg az ablakkezelő rendszer egyik funkcióját:

SDL_WM_SetCaption

Ezen eljárás segítségével képesek vagyunk módosítani az adott alkalmazás ablakának feliratát, valamint ikonnevét. Például:

SDL_WM_SetCaption("SDL Színátmenet", "");

Ezt a sort az sdl_surface inicializálása után érdemes beszúrni a fenti példában.

Rajzolás részletátvitel segítségével

Láthattuk, miképpen lehet képpontokat közvetlenül a képernyõre rajzolni, és nincs is semmi ok, ami miatt ne lehetne ilyen módon akár egy teljes játékot megalkotni. Mégis, nagy adatmennyiség képernyõre küldésére létezik egy sokkal jobb módszer is. A következõ példánk egy teljes felületet tölt be egy fájlból, majd egyetlen SDL-függ- vénnyel a képernyõre rajzolja azt.

Amint láthattad, az SDL_LoadBMP függvénnyel töltöttük a memóriába a bitképet. A függvény vagy egy, a képet tartalmazó SDL_Surface típusú mutatót ad vissza, vagy NULL-t, amennyiben a képet nem sikerült betölteni. A fájl sikeres betöltését követõen, a bitkép egyszerû SDL-felületként kezelhetõ, amit a program képernyõre vagy bármilyen más felületre rajzolhat. A bitképek dinamikusan foglalt memóriát használnak, amit fel kell szabadítani, ha a továbbiakban már nincs rá szükség. Az SDL_FreeSurface függvény felszabadítja a bitkép által lefoglalt memóriaterületet.

Az SDL_BlitSurface függvény feladata az egyik felület másikra vitele, miközben képpont-átalakítást hajt végre az egyes formátumok között, amennyiben szükséges. Ez a függvény négy bemenõ értéket vár: a forrásfelületet (ahonnan a képet másolni kell), egy SDL_Rect szerkezetet, ami a forrásból ténylegesen átvitelre kerülõ téglalap alakú területet határozza meg, a célfelületet (ahová a kép kerül), és egy másik SDL_Rect szerkezetet, amely a célterületet adja meg. Ennek a két területnek azonos szélességûnek és magasságúnak kell lennie (mivel az SDL jelenleg még nem támogatja a torzítást), a területek kezdõ x és y koordinátái azonban különbözhetnek.

#include #include #include int main() { SDL_Surface *screen; SDL_Surface *image; SDL_Rect src,dest; /* Kezdeti kód, az elõzõ példával azonos módon. */ /* A bitkép beolvasása. Az SDL_LoadBMP egy mutatóval tér vissza, mely a képet tartalmazó új felületre mutat. */ image = SDL_LoadBMP("tux.bmp"); if (image == NULL) { printf("Nem tudom betölteni a képet.\n"); return 1; }; /* Az SDL képátvitel (blitting) számára pontosan meg kell adni az átvinni kívánt adat mennyiségét. Ezt az src és dest SDL_Rect szerkezetekkel adjuk meg. A két területnek azonos méretűnek kell lennie. Az SDL jelenleg nem kezel torzításokat. */ src.x = 0; src.y = 0; src.w = image->w; /* Az egész kép másolása */ src.h = image->h; dest.x = 0; dest.y = 0; dest.w = image->w; dest.h = image->h; /* A bitkép kirajzolása a képernyõre. Hicolor módban vagyunk, ezért nem kell foglalkozzunk a színpalettákkal. Képátvitelnél (blitting) nem kell zárolnunk a képernyõt, az SDL elintézi a zárolást. */ SDL_BlitSurface(image,&src,screen,&dest); /* Utasítjuk az SDL-t, hogy frissítse az egész képernyõt. */ SDL_UpdateRect(screen,0,0,0,0); /* Pár másodpercig várunk, hogy a nézõnek legyen ideje ámuldozni. */ SDL_Delay(3000); /* A lefoglalt memória felszabadítása.. */ SDL_FreeSurface(image); return 0; }