Lekce 3 - SDL - Základy vykreslování
V minulé lekci, SDL - Vytvoření okna a vstup od uživatele, jsme se zabývali správou oken, událostmi a jak na ně správně reagovat.
V dnešním díle se dozvíme něco o vykreslování pomocí knihovny SDL. Řekneme si základní pojmy a poté vykreslíme obdélník, se kterým budeme posouvat po obrazovce.
SDL_Rect
Předtím, než se vrhneme na vykreslování, zmíním strukturu SDL_Rect. Již z názvu vyplývá, že reprezentuje obdélník. Má jen čtyři atributy, které jsou x a y (určení pozice levého horního rohu), a dále w a h, které určují šířku a výšku obdélníku. SDL_Rect se používá často k určení zdrojového nebo cílového obdélníku vykreslování. Vždy, když nechceme vykreslit barvou celé okno, použijeme SDL_Rect.
SDL_Renderer, SDL_Texture a SDL_Surface
Jedná se o tři struktury, které jsou svým významem velmi podobné, ale nejsou shodné. Protože budeme potřebovat všechny tři, každou si popíšeme.
SDL_Renderer
je struktura, která se stará o samotné
vykreslování. Zpravidla je svázaná s určitým SDL_Window
, do
kterého vykresluje (může být svázán i s SDL_Surface
). S
SDL_Renderer
jsou spojeny funkce vykreslující jednotlivé
elementy (SDL_RenderDrawPoint,
SDL_RenderDrawLine,
SDL_RenderDrawRect),
ale také funkce, které obsah kopírují (SDL_RenderCopy).
Nejprve budeme využívat funkce, které vykreslují pouze určité elementy, v
dalším díle se podíváme na funkce, které obraz kopírují. Vlastně se
jedná o prostředníka, skrze kterého budeme vykreslovat.
SDL_Texture je struktura, která ukládá obraz - informace o jednotlivých pixelech. Je hardwarově specifická a je uložena v paměti grafické karty. Zde se dostáváme k hardwarově-akcelerovanému vykreslování. Samotné operace, které s ní můžeme dělat, jsou značně omezené, užívá se především jako zdroj pro další vykreslování. Do textury můžeme například uložit obrázek pozadí. Při každém vykreslení poté první zkopírujeme tuto texturu do výsledného obrazu, a teprve poté začneme vykreslovat jednotlivé prvky scény.
SDL_Surface má
podobnou funkci jako SDL_Texture
, ale v tomto případě se jedná
o strukturu softwarovou. Je uložena v RAM paměti a můžeme s ní více
pracovat. V proměnných x a y má uložené své rozměry, ukazatel
pixels
poté obsahuje adresu samotných pixelů. Doporučuji ale
pixely neupravovat ručně. Ve většině případů to ani není nutné. SDL
poskytuje několik funkcí,
které nám dovolují s SDL_Surface
manipulovat. Mezi
nejdůležitější bych zařadil SDL_FillRect,
která vykreslí obdélník. Další velmi důležitou funkcí je SDL_BlitSurface,
která zkopíruje data z jedné SDL_Surface
do druhé. Poslední
zajímavou funkcí, kterou bych zmínil, je SDL_SetColorKey.
Ta nastaví barvu, která se nebude vykreslovat. Většina obrázků (pozadí,
postavy – setkáme se s nimi později) má určitou barvu pozadí. Pokud tuto
barvu ve funkci nastavíme, nebude se vykreslovat. Například následující
obrázek má červenou barvu pozadí (získáno zde).

Spojitost mezi SDL_Surface, SDL_Texture a SDL_Renderer
Ačkoliv každá struktura slouží k jinému účelu, jistá spojitost mezi nimi je. Řekněme si o pár funkcích, které budeme potřebovat.
Z SDL_Surface
můžeme vytvořit SDL_Texture
pomocí funkce SDL_CreateTextureFromSurface,
která převede SDL_Surface
na SDL_Texture
. Tím
dostaneme obraz, který byl v SDL_Surface
do paměti grafické
karty, která s ním může pracovat rychleji. Využívá se toho v případech,
kdy vykreslujeme něco složitého, ale už to nepotřebujeme překreslovat.
Nejprve vytvoříme SDL_Surface
, kde vše vykreslíme, a poté to
převedeme do SDL_Texture
.
Můžeme také vytvořit SDL_Renderer
, který bude navázaný na
určitý SDL_Surface
. Využijeme k tomu funkci SDL_CreateSoftwareRenderer,
která SDL_Renderer
vytvoří. Všechny operace se poté budou
provádět na SDL_Surface
, kterou jsme předali v parametru. Pokud
budeme chtít, aby byl SDL_Renderer
navázaný na určitý
SDL_Texture
, využijeme funkce SDL_SetRendererTarget.
V tuto chvíli bude SDL_Renderer
vykreslovat na
SDL_Texture
. Nesmíme ale zapomenout, že SDL_Renderer
musí být vytvořen s flagem SDL_RENDERER_TARGETTEXTURE
.
Zároveň stojí za pozornost, že SDL_RenderCopy
přijímá
jako parametr SDL_Texture
. Z toho plyne, že není možné
vykreslovat na obrazovku z SDL_Surface
. Pokud budeme potřebovat,
aby se SDL_Surface
vykreslila na obrazovku, musíme z ní vytvořit
SDL_Texture
a následně vykreslit přes
SDL_Renderer
.
Poslední věc, kterou zmíním, je možnost získat SDL_Surface
ze SDL_Window
. Poté jakákoliv úprava provedená na tento
SDL_Surface
bude provedena také na obrazovce. Jediná věc, na
kterou nesmíme zapomenout, je zavolat funkci SDL_UpdateWindowSurface.
Ta zobrazí všechny změny, které jsme provedli. Proč vlastně máme dva
způsoby vykreslování? Struktura SDL_Surface
je softwarová.
Všechny operace provádí procesor. Na rozdíl od toho
SDL_Renderer
a SDL_Texture
jsou struktury hardwarově
závislé a operace probíhají v grafické kartě. To znamená, že jsou
rychlejší a efektivnější. Proto bychom měli používat hlavně
hardwarově-akcelerované funkce, které tak nezatěžují procesor a jsou na
grafické kartě provedeny rychleji.
Zobrazení vykreslení
Poslední část teorie, kterou budeme potřebovat, je funkce pro zobrazení
vykreslení. Obraz nemůže být zároveň zobrazen a měnit se – nemůžeme
do něj vykreslovat. Obraz je proto v grafické kartě uložen dvakrát. Jeden
je ten, který se zobrazuje, a druhý ten, na který vykreslujeme. Tato technika
se nazývá double buffering. Obrazy se můžou řadit i do fronty (triple
buffering), ale SDL pro to podporu nemá. Není ovšem těžké tuto techniku
naimplementovat. O tyto prostory se stará sám SDL_Renderer
. Ona
zmiňovaná funkce je SDL_RenderPresent.
Ta udělá pouze to, že zkopíruje obraz, který jsme měnili, a vloží jej na
místo obrazu, který je zobrazen na obrazovce. Poté můžeme dál měnit
první obraz, aniž bychom narušovali zobrazování aktuálního obrazu. Pokud
budeme chtít docílit vyšší efektivity, můžeme vytvořit
SDL_Renderer
s flagem SDL_RENDERER_PRESENTVSYNC
,
který bude synchronizovat zmíněnou operaci tak, aby odpovídala obnovovací
frekvenci monitoru (zpravidla 60Hz).
Vykreslení obdélníku
Nejprve budeme potřebovat obdélník, který budeme vykreslovat. Vytvoříme
si tedy SDL_Rect
a nastavíme jeho proměnné na libovolnou
velikost. Poté vytvoříme nový SDL_Renderer
pro okno. Tyto dvě
operace provedeme ještě před vstupem do hlavní smyčky, jinak bychom je
vytvářeli v každém průchodu a by bylo zbytečné..
SDL_Rect* rect = new SDL_Rect; rect->x = rect->y = rect->w = rect->h = 100; SDL_Renderer* renderer = SDL_CreateRenderer(MainWindow,-1,0);
Ze vstupu budeme zachytávat stisk kláves. Pro začátek nám bude stačit
reagovat pouze na šipky. Šipkou nahoru obdélník posuneme nahoru a obdobně
pro ostatní směry. Jestliže se jednalo o stisk klávesy, bude tato struktura
uložena v atributu key
, v ní se podíváme do informací o
klávesách (keysym
) a konkrétně nás bude zajímat kód klávesy
(sym
). V něm jsou uloženy hodnoty z SDL_Keycode. My budeme reagovat
pouze v případě, kdy se jednalo o šipky (SDLK_RIGHT
,
SDLK_LEFT
, SDLK_UP
, SDLK_DOWN
).
Výsledný kód pro vstup bude vypadat následovně:
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; } } }
Nakonec ještě obdélník vykreslíme. Nejprve nastavíme barvu, jakou
budeme obdélník vykreslovat. Já si zvolil červenou. Barvu nastavíme funkcí
SDL_SetRenderDrawColor.
Druhý až čtvrtý parametr slouží k nastavení barvy klasicky ve formátu
RGB, poslední je alfa kanál – tedy průhlednost. Všechny tyto parametry
přijímají hodnotu 0 až 255. Obdélník vykreslíme funkcí SDL_RenderFillRect.
Nakonec musíme aktualizovat obraz, proto použijeme funkci
SDL_RenderPresent
. To je vše, nyní program spustíme.
SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255); SDL_RenderFillRect(renderer, rect); SDL_RenderPresent(renderer);

Proč nám obdélník nemizí? Protože vždy vykreslíme nový obdélník,
do již existujícího obrazu. Pokud chceme docílit toho, aby nám obdélník
zmizel, budeme muset celou obrazovku překreslit. V tomto případě ovšem
nevyužijeme funkci SDL_RenderFillRect
, ale SDL_RenderClear,
která přemaluje celou plochu. Proto opět nastavíme barvu
(SDL_SetRenderDrawColor
). Zvolíme například na modrou a poté
zavoláme SDL_RenderClear
. Konečný kód pro vykreslení je
následovný:
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élník mizí a pozadí máme modré. Přesně jak jsme chtěli.
To je pro tento díl vše.
Příště, v lekci SDL - Práce s obrázky, se podíváme na práci s obrázky, práci s texturami a kopírování bloků paměti.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkamiStaženo 1106x (3.34 MB)