3. diel - SDĽ - Základy vykresľovanie
V dnešnom diele sa dozvieme niečo o vykresľovanie pomocou knižnice SDL. Povieme si základné pojmy a potom vykreslíme obdĺžnik, s ktorým budeme posúvať po obrazovke.
SDL_Rect
Predtým, než sa vrhneme na vykresľovanie, spomeniem štruktúru SDL_Rect. Už z názvu vyplýva, že reprezentuje obdĺžnik. Má len štyri atribúty, ktoré sú x a y (určenie pozície ľavého horného rohu), a ďalej w a h, ktoré určujú šírku a výšku obdĺžnika. SDL_Rect sa používa často na určenie zdrojového alebo cieľového obdĺžnika vykresľovanie. Vždy, keď nechceme vykresliť farbou celé okno, použijeme SDL_Rect.
SDL_Renderer, SDL_Texture a SDL_Surface
Jedná sa o tri štruktúry, ktoré sú svojim významom veľmi podobné, ale nie sú zhodné. Pretože budeme potrebovať všetky tri, každú si popíšeme.
SDL_Renderer
je štruktúra, ktorá sa stará o samotnej
vykresľovanie. Spravidla je zviazaná s určitým SDL_Window
, do
ktorého vykresľuje (môže byť zviazaný aj s SDL_Surface
). S
SDL_Renderer
sú spojené funkcie vykresľujúca jednotlivé
elementy (SDL_RenderDrawPoint, SDL_RenderDrawLine,
SDL_RenderDrawRect), ale aj funkcie, ktoré obsah kopírujú
(SDL_RenderCopy). Najprv budeme využívať funkcie, ktoré
vykresľujú len určité elementy, v ďalšom diele sa pozrieme na funkcie,
ktoré obraz kopírujú. Vlastne sa jedná o sprostredkovateľa, skrze ktorého
budeme vykresľovať.
SDL_Texture je štruktúra, ktorá ukladá obraz - informácie o jednotlivých pixeloch. Je hardwarovo špecifická a je uložená v pamäti grafickej karty. Tu sa dostávame k hardvérovo-akcelerovanému vykresľovanie. Samotné operácie, ktoré s ňou môžeme robiť, sú značne obmedzené, užíva sa predovšetkým ako zdroj pre ďalšie vykresľovanie. Do textúry môžeme napríklad uložiť obrázok pozadia. Pri každom vykreslenie potom prvý skopírujeme túto textúru do výsledného obrazu, a až potom začneme vykresľovať jednotlivé prvky scény.
SDL_Surface má podobnú funkciu ako SDL_Texture
, ale v
tomto prípade sa jedná o štruktúru softvérovú. Je uložená v RAM pamäti
a môžeme s ňou viac pracovať. V premenných xay má uložené svoje rozmery,
ukazovateľ pixels
potom obsahuje adresu samotných pixelov.
Odporúčam ale pixely neupravovať ručne. Vo väčšine prípadov to ani nie
je nutné. SDL poskytuje viacero funkcií, ktoré nám
dovoľujú s SDL_Surface
manipulovať. Medzi najdôležitejšie by
som zaradil SDL_FillRect, ktorá vykreslí obdĺžnik. Ďalšou veľmi
dôležitou funkciou je SDL_BlitSurface, ktorá skopíruje údaje z
jednej SDL_Surface
do druhej. Posledný zaujímavou funkciou,
ktorú by som spomenul, je SDL_SetColorKey.
Tá nastaví farbu, ktorá sa nebude vykresľovať. Väčšina obrázkov
(pozadia, postavy - stretneme sa s nimi neskôr) má určitú farbu pozadia. Ak
túto farbu vo funkcii nastavíme, nebude sa vykresľovať. Napríklad
nasledujúci obrázok má červenú farbu pozadia (získané tu).
Spojitosť medzi SDL_Surface, SDL_Texture a SDL_Renderer
Hoci každá štruktúra slúži na iný účel, istá spojitosť medzi nimi je. Povedzme si o pár funkciách, ktoré budeme potrebovať.
Z SDL_Surface
môžeme vytvoriť SDL_Texture
pomocou funkcie SDL_CreateTextureFromSurface, ktorá prevedie
SDL_Surface
na SDL_Texture
. Tým dostaneme obraz,
ktorý bol v SDL_Surface
do pamäte grafickej karty, ktorá s ním
môže pracovať rýchlejšie. Využíva sa toho v prípadoch, keď vykresľujú
niečo zložité, ale už to nepotrebujeme prekresľovať. Najprv vytvoríme
SDL_Surface
, kde všetko vykreslíme, a potom to prevedieme do
SDL_Texture
.
Môžeme tiež vytvoriť SDL_Renderer
, ktorý bude naviazaný na
určitý SDL_Surface
. Využijeme na to funkciu
SDL_CreateSoftwareRenderer, ktorá SDL_Renderer
vytvorí. Všetky operácie sa potom budú vykonávať na
SDL_Surface
, ktorú sme odovzdali v parametri. Ak budeme chcieť,
aby bol SDL_Renderer
naviazaný na určitý
SDL_Texture
, využijeme funkcie SDL_SetRendererTarget. V
túto chvíľu bude SDL_Renderer
vykresľovať na
SDL_Texture
. Nesmieme ale zabudnúť, že SDL_Renderer
musí byť vytvorený s FLAG SDL_RENDERER_TARGETTEXTURE
.
Zároveň stojí za pozornosť, že SDL_RenderCopy
prijíma ako
parameter SDL_Texture
. Z toho vyplýva, že nie je možné
vykresľovať na obrazovku z SDL_Surface
. Ak budeme potrebovať,
aby sa SDL_Surface
vykreslila na obrazovku, musíme z nej vytvoriť
SDL_Texture
a následne vykresliť cez
SDL_Renderer
.
Posledná vec, ktorú spomeniem, je možnosť získať
SDL_Surface
zo SDL_Window
. Potom akákoľvek úprava
vykonaná na tento SDL_Surface
bude vykonaná aj na obrazovke.
Jediná vec, na ktorú nesmieme zabudnúť, je zavolať funkciu
SDL_UpdateWindowSurface. Tá zobrazuje všetky zmeny, ktoré sme
vykonali. Prečo vlastne máme dva spôsoby vykresľovanie? Štruktúra
SDL_Surface
je softvérová. Všetky operácie vykonáva procesor.
Na rozdiel od toho SDL_Renderer
a SDL_Texture
sú
štruktúry hardwarovo závislé a operácie prebiehajú v grafickej karte. To
znamená, že sú rýchlejšie a efektívnejšie. Preto by sme mali používať
hlavne hardvérovo-akcelerovanej funkcie, ktoré tak nezaťažujú procesor a
sú na grafickej karte vykonané rýchlejšie.
Zobrazenie vykreslenie
Posledná časť teórie, ktorú budeme potrebovať, je funkcia pre
zobrazenie vykreslenie. Obraz nemôže byť zároveň zobrazený a meniť sa -
nemôžeme do neho vykresľovať. Obraz je preto v grafickej karte uložený
dvakrát. Jeden je ten, ktorý sa zobrazuje, a druhý ten, na ktorý
vykresľuje. Táto technika sa nazýva double buffering. Obrazy sa môžu radiť
aj do fronty (triple buffering), ale SDL pre to podporu nemá. Nie je však
ťažké túto techniku naimplementovať. O tieto priestory sa stará sám
SDL_Renderer
. Ona spomínaná funkcia je
SDL_RenderPresent. Tá urobí iba to, že skopíruje obraz, ktorý
sme menili, a vloží ho na miesto obrazu, ktorý je zobrazený na obrazovke.
Potom môžeme ďalej meniť prvý obraz, bez toho aby sme narušovali
zobrazovanie aktuálneho obrazu. Ak budeme chcieť docieliť vyššiu
efektivitu, môžeme vytvoriť SDL_Renderer
s FLAG
SDL_RENDERER_PRESENTVSYNC
, ktorý bude synchronizovať zmienenú
operáciu tak, aby zodpovedala obnovovaciu frekvenciu monitora (spravidla
60Hz).
Vykreslenie obdĺžnika
Najprv budeme potrebovať obdĺžnik, ktorý budeme vykresľovať. Vytvoríme
si teda SDL_Rect
a nastavíme jeho premenné na ľubovoľnú
veľkosť. Potom vytvoríme nový SDL_Renderer
pre okno. Tieto dve
operácie vykonáme ešte pred vstupom do hlavnej slučky, inak by sme ich
vytvárali v každom priechode a by bolo zbytočné ..
SDL_Rect* rect = new SDL_Rect; rect->x = rect->y = rect->w = rect->h = 100; SDL_Renderer* renderer = SDL_CreateRenderer(MainWindow,-1,0);
Zo vstupu budeme zachytávať stisk klávesov. Pre začiatok nám bude
stačiť reagovať iba na šípky. Šípkou nahor obdĺžnik posunieme hore a
obdobne pre ostatné smery. Ak sa jednalo o stlačenie klávesy, bude táto
štruktúra uložená v atribúte key
, v nej sa pozrieme do
informácií o klávesoch (keysym
) a konkrétne nás bude
zaujímať kód klávesy (sym
). V ňom sú uložené hodnoty z SDL_Keycode. My budeme reagovať
iba v prípade, keď sa jednalo o šípky (SDLK_RIGHT
,
SDLK_LEFT
, SDLK_UP
, SDLK_DOWN
).
Výsledný kód pre vstup bude vyzerať nasledovne:
while (SDL_PollEvent(event)) //načtení události z fronty { if (event->type == SDL_QUIT) //manipulace s událostí End = true; //ukončení aplikace else if (event->type == SDL_KEYDOWN) //reagování na stisk klávesy { switch (event->key.keysym.sym) { case SDLK_RIGHT: rect->x += 1; break; case SDLK_LEFT: rect->x -= 1; break; case SDLK_UP: rect->y -= 1; break; case SDLK_DOWN: rect->y += 1; break; } } }
Nakoniec ešte obdĺžnik vykreslíme. Najprv nastavíme farbu, akú budeme
obdĺžnik vykresľovať. Ja si zvolil červenú. Farbu nastavíme funkcií
SDL_SetRenderDrawColor. Druhý až štvrtý parameter slúži na
nastavenie farby klasicky vo formáte RGB, posledný je alfa kanál - teda
transparentnosť. Všetky tieto parametre prijímajú hodnotu 0 až 255.
Obdĺžnik vykreslíme funkcií SDL_RenderFillRect. Nakoniec musíme
aktualizovať obraz, preto použijeme funkciu SDL_RenderPresent
. To
je všetko, teraz program spustíme.
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRect(renderer, rect); SDL_RenderPresent(renderer);
Prečo nám obdĺžnik nemizne? Pretože vždy vykreslíme nový obdĺžnik,
do už existujúceho obrazu. Ak chceme docieliť to, aby nám obdĺžnik zmizol,
budeme musieť celú obrazovku prekresliť. V tomto prípade však nevyužijeme
funkciu SDL_RenderFillRect
, ale SDL_RenderClear, ktorá
přemaluje celú plochu. Preto opäť nastavíme farbu
(SDL_SetRenderDrawColor
). Zvolíme napríklad na modrú a potom
zavoláme SDL_RenderClear
. Konečný kód pre vykreslenie je
nasledovný:
SDL_SetRenderDrawColor(renderer, 0, 0, 255, 255); SDL_RenderClear(renderer); SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRect(renderer, rect); SDL_RenderPresent(renderer);
Obdĺžnik mizne a pozadia máme modrej. Presne ako sme chceli.
To je pre tento diel všetko. Nabudúce sa pozrieme na prácu s obrázkami, prácu s textúrami a kopírovanie blokov pamäte.
Stiahnuť
Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkamiStiahnuté 1062x (3.34 MB)