IT rekvalifikace s garancí práce. Seniorní programátoři vydělávají až 160 000 Kč/měsíc a rekvalifikace je prvním krokem. Zjisti, jak na to!
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.

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_Controlle­rAxisEvent (pohyb) a SDL_Controller­ButtonEvent (stlačenie tlačidiel). U joysticku je situácia trochu komplikovanejšia, obsahuje udalosti SDL_JoyAxisEvent (pohyb), SDL_JoyBallEvent (trackball), SDL_JoyButtonE­vent (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 podmienkami

Stiahnuté 696x (9.17 MB)

 

Predchádzajúci článok
SDĽ - Vlastné udalosti a filtrovanie
Všetky články v sekcii
SDĽ
Článok pre vás napísal Patrik Valkovič
Avatar
Užívateľské hodnotenie:
Ešte nikto nehodnotil, buď prvý!
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity