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é 1030x (9.17 MB)
