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í.

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_RenderDraw­Point, SDL_RenderDraw­Line, SDL_RenderDraw­Rect), 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).

Postava s pozadím - SDL

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_CreateTex­tureFromSurfa­ce, 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_CreateSof­twareRenderer, 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_SetRenderer­Target. 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_UpdateWin­dowSurface. 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_RenderPre­sent. 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_SetRender­DrawColor. 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_RenderFillRec­t. 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);
Vykresleni bez pozadí - SDL

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);
Vykreslení obdelníku - SDL

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ínkami

Staženo 1014x (3.34 MB)

 

Předchozí článek
SDL - Vytvoření okna a vstup od uživatele
Všechny články v sekci
SDL
Přeskočit článek
(nedoporučujeme)
SDL - Práce s obrázky
Článek pro vás napsal Patrik Valkovič
Avatar
Uživatelské hodnocení:
6 hlasů
Věnuji se programování v C++ a C#. Kromě toho také programuji v PHP (Nette) a JavaScriptu (NodeJS).
Aktivity