14. diel - SDĽ - RWops, vlákna a ďalšie
V dnešnom diele sa bližšie pozrieme na veci, ktoré sa mi nepodarilo vložiť do predchádzajúcich článkov. Tento diel bude rozdielny od predchádzajúcich v tom, že nebude tak podrobný. Hlavným dôvodom je použitie informácií, ktoré dnes budem zmieňovať. Vo väčšine programov nebudeme potrebovať joystick ani ovládač a rovnako tak nebudeme vytvárať vlastný zdroj dát. Získate ale základné povedomie o týchto možnostiach.
SDL_RWops
SDL_RWops je štruktúra, ktorá je prostredníkom pre vstupno
výstupné operácie. Interne všetky funkcie, ktoré pracujú s dátami,
vytvárajú SDL_RWops
. Štandardne nebudeme potrebovať vytvárať
vlastné SDL_RWops
, SDL má funkcie pre jeho vytvorenie zo súboru
alebo z pamäte. Definícia štruktúry je nasledujúca.
/* RWops Types */ #define SDL_RWOPS_UNKNOWN #define SDL_RWOPS_WINFILE #define SDL_RWOPS_STDFILE #define SDL_RWOPS_JNIFILE #define SDL_RWOPS_MEMORY #define SDL_RWOPS_MEMORY_RO typedef struct SDL_RWops { Uint32 type; Sint64 (SDLCALL * size) (struct SDL_RWops * context); Sint64 (SDLCALL * seek) (struct SDL_RWops * context, Sint64 offset, int whence); size_t (SDLCALL * read) (struct SDL_RWops * context, void *ptr, size_t size, size_t maxnum); size_t (SDLCALL * write) (struct SDL_RWops * context, const void *ptr, size_t size, size_t num); int (SDLCALL * close) (struct SDL_RWops * context); union { struct stdio; struct mem; struct { void *data1; void *data2; } unknown; } hidden; } SDL_RWops;
Typ môže byť jedna z hodnôt, ktoré sú vypísané nad definíciou
štruktúry. Ako som spomenul, jedná sa o rôzne druhy súborov a pamäti.
Prvým typom je SDL_RWOPS_UNKNOWN
, ktorý by sme mali použiť pre
všetky nami vytvorené SDL_RWops
. S vytváraním
SDL_RWops
sa bežne nestretneme, spravidla len pri získavaní dát
z "exotických" zdrojov, ako je sieť alebo naša trieda. Ako vytvoriť vlastné
SDL_RWops
si ukážeme ďalej.
Ďalej má štruktúra definovaných 5 Callback, ktoré volajú rutiny pre
získavanie dát. Tieto Callback získavajú v parametri samotnú inštanciu
SDL_Rwops
, s ktorou môžeme pracovať. Funkcie by mali byť
nadefinované tak, že vracia -1 pri chybe alebo v prípade, keď daná funkcia
nedáva zmysel. Takým príkladom môže byť nekonečný zdroj náhodných
hodnôt (ukážka ďalej). Pravdepodobne do takého streamu nebudeme chcieť
zapisovať, teda nastavenie pozície čítanie, veľkosť a zápis nedávajú
zmysel. Tieto Callback sa nevolajú priamo, ale pomocou makier, ktoré SDL
definuje (SDL_RWseize, SDL_RWseek, SDL_RWread,
SDL_RWwrite, SDL_RWclose). Nasledujúce dva zápisy sú
totožné.
RW_Read(RWInstance,data,sizeof(MyStruc),10); RWInstance->read(RWInstance,data,sizeof(MyStruc),10);
Prvým Callback je size
, ktorý vracia veľkosť streamu.
Ďalším je seek
, ktorý nastaví aktuálnu pozíciu, od ktorej sa
bude čítať. Tretím parametrom funkcie je whence
, ktorý
bližšie určuje, odkiaľ sa bude kurzor presúvať. Môže nadobúdať hodnoty
RW_SEEK_SET
pre začiatok, RW_SEEK_CUR
pre aktuálnu
pozíciu a SDL_SEEK_END
pre koniec. Funkcia vracia aktuálnu
pozíciu vo streamu. Uvediem pár ukážok pre lepšiu predstavu.
SDL_RWseek(instance, 10, SDL_SEEK_SET); //10 bajtů od začátku SDL_RWseek(instance,10,SDLK_SEEK_CUR); // 10 bajtů od aktuální pozice SDL_RWseek(instance,-10,SDL_SEEK_END); // 10 bajtů před koncem SDL_RWseek(instance,0,SDL_SEEK_CUR); //vrátí aktuální pozici SDL_RWtell(instance); //ekvivalentní k předchozímu případu
write
a read
sú takmer totožné. Prvý parameter
je inštancia SDL_RWops
, druhým parametrom ukazovateľ na dáta, z
ktorých zapisovať / čítať. Tretím parametrom je veľkosť jedného objektu
a posledným počet objektov, ktoré čítame. Obe funkcie vracia počet
objektov, ktoré prečítali / zapísali. Hodnotu je potreba overiť, pretože
funkcia môže zapísať / prečítať menej objektov, než sme požadovali.
Posledný callback je close
. Ten by mal uvoľniť všetky dáta,
ktoré SDL_RWops
používala, a tiež samotné
SDL_RWops
funkcií SDL_FreeRW. Rovnako ako ostatné
funkcie, vracia -1 pri neúspechu. Podľa dokumentácie napriek tomu nemôžeme
považovať štruktúru za validné a nemala by byť ďalej používaná. Ako sa
v takejto situácii zachovať, už dokumentácia neuvádza.
Vo väčšine prípadov budeme potrebovať štruktúru alebo triedu, ktorá
nám uchová informácie. Pre vlastné SDL_RWops
máme pripravené
dva ukazovatele typu void. Získame je pomocou hidden.unknown.data1
a hidden.unknown.data2
. Zvyšok štruktúr v Unionu
hidden
slúži pre interné účely SDL a okrem prostredníctvom
Callback by sme vs nimi nemali vôbec pracovať.
Vlastné SDL_RWops
V programe navrhneme SDL_RWops
, ktorý bude vracať nekonečný
prúd náhodne generovaných hodnôt. V tejto situácii nedáva väčšina
funkcií zmysel, preto write
, seek
, aj
size
budú vracať hodnotu -1. Nebudeme potrebovať žiadne dáta,
v callback close
len uvoľníme SDL_RWops
inštanciu a
vrátime 0. Všetko sa bude odohrávať v callback read. Telo funkcie je
nasledovné:
size_t read(SDL_RWops* instance, void* ReadTo, size_t OneObjectSize, size_t ObjectsToRead) { Uint64 BytesToRead = OneObjectSize * ObjectsToRead; //kolik bytů přečíst Uint8* Begin = (Uint8*)ReadTo; //odkud začít číst Uint8* End = Begin + BytesToRead; //kde ukončit čtení while (Begin != End) { *Begin = rand(); //vložení náhodné hodnoty Begin += sizeof(Uint8); } return ObjectsToRead; };
Teraz len štruktúre nastavíme type
na
SDL_RWOPS_UNKNOWN
a máme hotovo. Kompletné riešenia a použitia
je v priloženom projektu.
Vlákna
SDL poskytuje všetky operácie, ktoré pre prácu s vláknami potrebujeme. Ako bolo spomenuté už niekoľkokrát, práca s viacerými vláknami by potrebovala celý vlastný seriál, preto uvediem len základné príkazy. V projektoch viac vlákien používať nebudeme.
Pre manipuláciu s vláknami obsahuje SDL funkcie SDL_CreateThread pre vytvorenie, SDL_DetachThread pre označenie vlákna bežiaceho na pozadí a funkcií SDL_WaitThread počkáme na vykonanie vlákna.
SDL tiež obsahuje funkcie pre zamykanie, prácu so semaformi a mutexy. Všetky dostupné funkcie nájdeme v dokumentácii. Pre tých, ktorým tieto pojmy nič nehovoria - jedná sa o prostriedky na synchronizáciu vlákien medzi sebou.
Ďalej SDL obsahuje funkcie pre atomické operácie. Ich zoznam je opäť
uvedený v dokumentácii. Atomická operácie prebehne ako jeden celok.
Napríklad pri sčítaní dvoch čísel v jednom vlákne
(SDL_AtomicAdd
) sa nám nestane, že by iné vlákno zmenilo jednu
z hodnôt uprostred sčítanie a výsledok by bol nevalidný.
Pre bližšie porozumenie vláknam odporučím články na ITNetwork ( Java alebo C #) poprípade preklad v PDF od Jakuba Kottnauera, ktorý sa problémom zaoberá hlbšie (aj keď stále na povrchu). Pre začiatok nie je dôležité, v ktorom jazyku s vláknami pracujete. Dôležité je pochopiť princípy, ktoré sa vlákien týkajú.
Ovládač a joystick
S ovládačom sa spája udalosti SDL_ControllerAxisEvent (pohyb) a SDL_ControllerButtonEvent (stlačenie tlačidiel). U joysticku je situácia trochu komplikovanejšia, obsahuje udalosti SDL_JoyAxisEvent (pohyb), SDL_JoyBallEvent (trackball), SDL_JoyButtonEvent (stlačenie tlačidla) a SDL_JoyHatEvent (zmena pozície hlavy). Rovnako ako u myši a klávesnice, SDL poskytuje aj informácie o aktuálnom stave ovládače i joysticku. Pretože ani jednu z vyššie uvedených udalostí nebudeme v potrebovať, nebudem ich ani bližšie popisovať.
Záver
Dnešným dielom sme dopracovali väčšinu funkcionality, ktorú SDL poskytuje. Pomaly sa vrhneme na vytváranie hry. Posledný podtriedy, ktorá nám v SDL chýba, je zvuk. Na ten sa zameriame od budúceho dielu.
V priloženom projektu je tentoraz ukázané, ako vytvoriť vlastné
SDL_RWops
a čítať z neho dáta.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 919x (9.17 MB)