Vydělávej až 160.000 Kč měsíčně! Akreditované rekvalifikační kurzy s garancí práce od 0 Kč. Více informací.
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í.

6. diel - SDĽ - Práca s 8bitovou grafikou

V dnešnom diele sa bližšie pozrieme na štruktúru SDL_Surface. Povieme si, ako môžeme pracovať s jednotlivými pixely u 8-bitové grafiky. V ďalšom diele sa potom pozrieme na grafiku 16 a 32-bitovú.

Popis SDL_Surface

struct SDL_Surface
{
    Uint32 flags;               /**< Read-only */
    SDL_PixelFormat *format;    /**< Read-only */
    int w, h;                   /**< Read-only */
    int pitch;                  /**< Read-only */
    void *pixels;               /**< Read-write */

    /** Application data associated with the surface */
    void *userdata;             /**< Read-write */

    /** information needed for surfaces requiring locks */
    int locked;                 /**< Read-only */
    void *lock_data;            /**< Read-only */

    /** clipping information */
    SDL_Rect clip_rect;         /**< Read-only */

    /** info for fast blit mapping to other surfaces */
    struct SDL_BlitMap *map;    /**< Private */

    /** Reference count -- used when freeing surface */
    int refcount;               /**< Read-mostly */
}

Týmto spôsobom je SDL_Surface definovaný. Teraz si jednotlivé atribúty prejdeme a povieme si, čo robia.

flags a map slúži iba k interným účely SDL. format si popíšeme ďalej v článku. Slúži na uchovanie informácií o tom, ako sú pixely v štruktúre uložené, kde sú umiestnené jednotlivé farby a podobné veci. Atribúty w a h nás informujú o šírke a výške obrazu, ktorý štruktúra uchováva. Ďalej máme atribút pitch, ktorý obsahuje počet bytov v jednom riadku pixelov. Spravidla sa teda jedná o šírku štruktúry vynásobenú počtom bajtov na jeden pixel. Napríklad pre 32-bitovú farebnú hĺbku obsahuje jeden pixel 4 bajty (1 bajt = 8 bitov). Najdôležitejšie je atribút pixels, ktorý uchováva samotná dáta jednotlivých pixlov. Budeme sa ním zaoberať v ďalších odsekoch.

Ďalej máme ukazovateľ userdata, do ktorého môžeme vložiť ľubovoľný objekt. Atribúty locked a lock_data sú určené len na interné použitie. Zamykaním štruktúry sa budeme ďalej v texte venovať tiež, ale SDL má zamykanie riešené vlastnými funkciami. Ďalším atribútom je clip_rect. Tu už je situácia zaujímavejšie. SDL definuje funkciu SDL_SetClipRect, ktorá tento atribút nastaví (preto je tiež v štruktúre označený ako read-only). Akékoľvek ďalšie vykreslenie bude prebiehať iba na tento obdĺžnik (zostávajúca plocha vykreslená nebude). Pri testovaní som však prišiel na to, že clip_rect sa berie do úvahy len pri funkcii SDL_BlitSurface, u SDL_BlitScaled je vyplnená celá plocha, nehľadiac na nastavený clip_rect.

Posledným atribútom je refcount. Slúži pre aplikáciu, ktorá s ním môže pracovať ľubovoľne. Je zamýšľaný ako prostriedok pre počítanie použitie. Uvediem jednoduchý príklad. Jednu SDL_Surface používame na rôznych miestach aplikácie. Tieto miesta sú na seba nezávislé. Čo sa však stane, keď už jedno zo spomínaných miest našu SDL_Surface nebude potrebovať? Ak je stále používaná na inom mieste v programe, pri zmazanie program spadne, pretože ukazovateľ na druhom mieste programu bude odkazovať na neexistujúce miesto. Ovšem ak SDL_Surface nevymaže a už ju nebude program potrebovať, nastáva únik pamäte. Ako z tejto situácie von? Každé miesto, ktoré naši SDL_Surface potrebuje, inkrementuje refcount. Akonáhle ju už nepotrebuje, dekrementuje číslo a zistí, aká je jeho aktuálna hodnota. Pokiaľ bude nula (žiadne iné miesto už naši SDL_Surface nepotrebuje), tak ju zmaže. Použitie refcount na tento účel je však na voľbe programátora. Môže ho použiť k akémukoľvek inému účelu, ale nedoporučoval by som to. Pre užívateľské dáta by malo byť využitý už spomínaný atribút userdata.

SDL_PixelFormat

SDL_PixelFormat má niekoľko atribútov, ktoré používa iba SDL, preto sa zameriame na atribúty, ktoré sú relevantné aj pre programátorov.

struct SDL_PixelFormat
{
    Uint32 format;
    SDL_Palette *palette;
    Uint8 BitsPerPixel;
    Uint8 BytesPerPixel;
    Uint32 Rmask;
    Uint32 Gmask;
    Uint32 Bmask;
    Uint32 Amask;
}

Formát je jedna hodnota z SDL_PixelForma­tEnum. Hodnoty spravidla udávajú počet bitov, ktoré farba zaberá. Napríklad SDL_PIXELFORMAT_RGBA8888 má 8 bitov pre červenú farbu, 8 pre farbu zelenú, 8 bitov pre farbu modrú a 8 bitov pre transparentnosť. Vo výsledku teda máme 32 bitov az toho 24 bitov pre farby - True color. Ak sa pozrieme napríklad na SDL_PIXELFORMAT_BGRA5551 vidíme, že máme 5 bitov pre modrú, 5 pre zelenú a 5 bitov pre červenú farbu. Zostal nám jeden bit pre alfa kanál (priehľadnosť). To znamená, že môžeme použiť priehľadnosť, ale iba jednostupňovú - farba buď vidieť pôjde, alebo nie.

palette využijeme iba pre 8 bitovú grafiku. Ak použijeme 16 alebo 32 bitovú grafiku, palette sa nenastaví a bude prázdna. Viac si dozvieme v ďalšom odseku. Ďalšie dva atribúty (BitsPerPixel a BytesPerPixel) sú predpokladám dostatočne samovysvetľujúce. Udávajú počet bitov / bajtov na jeden pixel. Posledné 4 atribúty nastavujú masku, o ktorej si povieme ďalej.

Práca s 8bitovou grafikou

Práca s 8bitovou grafikou je rozdielna od práce s 16 alebo 32-bitovú, preto sa pozrieme najskôr na ňu.

8bitová grafika používa iba jeden bajt pre určenie farby. V skutočnosti je však tá farba definovaná 4 bajty (z toho je jeden bajt alfa kanálu) - je teda TrueColor a spomínaný bajt sa používa iba pre indexáciu v poli 256 nami definovaných farieb (SDL_Palette). Po vytvorení SDL_Surface s 8 bitovou farebnou hĺbkou budú všetky farby nastavené na bielu (R = 255, G = 255, B = 255). Ak budeme chcieť vložiť vlastné farby, použijeme funkciu SDL_SetPalette­Colors. Tá prijíma paletu, ktorú bude nastavovať a ukazovateľ na pole SDL_Color, z ktorého bude farby kopírovať. Ďalej index prvej farby, ktorú má nastaviť v pôvodnej palete. Odovzdáme Ak hodnotu 5, nastaví sa šiesta (indexácia od nuly) farba na rovnakú, aká je prvá farba v poli. Ako posledný parameter odovzdáme počet farieb, ktoré chceme nastaviť. Táto hodnota nesmie vyť väčšia ako je dĺžka poľa, inak bude SDL čítať mimo rozsah poľa a program môže spadnúť alebo prečítať zlú hodnotu.

Môžeme pracovať aj priamo s paletou. SDL má funkciu SDL_AllocPalette, ktorá vytvorí novú paletu so zadaným počtom farieb. Ďalej funkciu SDL_FreePalette, ktorá paletu zmaže. Niekoho by mohlo napadnú vytvoriť paletu s viacerými farbami a tým pádom rozšíriť počet farieb, ktoré môžeme použiť. To bohužiaľ nejde. SDL má vo format->BitsPerPixel uloženú hodnotu 8, rovnako tak vo format->BytesperPixel je uložená hodnota 1. Jeden pixel môže nadobúdať maximálnej hodnoty 256. Ak by sme chceli použiť viac farieb, tak ich nemáme ako adresovať (8 bitov nemôže nadobúdať vyššie hodnoty ako 255). Museli by sme zmeniť hodnoty BitsPerPixel a BytesPerPixel. S tým by súviselo aj zväčšenie dát, ktoré SDL_Surface musia ukladať. Ak máme SDL_Surface o veľkosti 100x100 pixelov, pre 8 bitovú grafiku bude pixels ukazovať na miesto s veľkosťou 100 100=10000 bajtů. Pokud by byl každý pixel o bajt větší, museli bychom toto místo zdvojnásobit, aby obsahovalo všechny pixely v obraze. Ovšem ve chvíli, kdy provedeme tyto změny, máme vlastně 16 bitovou grafiku, která bere barvy z palety. Jak jsem již ale zmínil, 16 a 32bitová grafika nepracuje s paletou a tak ji SDL ani nepoužije. SDL bude s takto modifikovanou `SDL_Surface pracovať rovnako, ako keby bola vytvorená ako 16bitová.

Ale vráťme sa späť do reality. Vytvoríme si teda pole SDL_Color, ktoré naplníme hodnotami. Ďalej zavoláme spomínanú funkciu SDL_SetPaletteColors a nastavíme paletu. Teraz môžeme pristupovať k pixelom ukazovateľom pixels.

Zmena pixelov

SDL_Surface ukladá pixely ako jednorozmerné pole. To znamená, že do dvojrozmerného poľa sa budeme musieť dopočítať. Všimnime si však, že ide len o ukazovateľ typu void. To je z dôvodu, aby SDL_Surface fungovalo pre všetky typy bitových hĺbok. Najskôr budeme musieť ukazovateľ pretypovať a potom sa dopočítať na potrebné pixely. K tomu slúži aritmetika s ukazovateľmi a postup je nasledovný.

UmístěníPrvku=ZačátekPole + Řádek * PočetBajtůNaŘádku + Sloupec * PočetBajtůNaPixel;

Začiatok poľa je náš ukazovateľ pixels. Počet bajtov na riadku môžeme vypočítať z šírky SDL_Surface vynásobenú počtom bajtov na pixel (BytesPerPixel) alebo priamo v SDL_Surface z atribútu pitch. A počet bajtov na pixel som už napísal - BytesPerPixel.

Farba pixelu sa berie vzhľadom k palete. Pokiaľ je teda prvá farba (index 0) zelená, nastavíme ak pixelu hodnotu 0, bude jeho farba zelená. V ukážkovom programe dnes vytvoríme farebný prechod. Najzložitejšia časť aplikácie je vytvorenie palety a dopočet pixelov, preto vedľa zdrojových kódov túto časť programu prikladám tu.

SDL_Surface* MySurface = SDL_CreateRGBSurface(NULL, 256, 100, 8, 0, 0, 0, 0);

SDL_Color color[256];

for (int a = 0; a < 256; a++)
{
    color[a].r = a;
    color[a].g = color[a].a = color[a].b = 0;
}

SDL_SetPaletteColors(MySurface->format->palette, color, 0, 256);

for (int a = 0; a < 256; a++)
{
    for (int b = 0; b < 100; b++)
    {
        Uint8* BeginOfArray = (Uint8*)MySurface->pixels;
        int IndexOfRow = b*MySurface->pitch;
        int IndexOfColumn = a*MySurface->format->BytesPerPixel;
        *(BeginOfArray + IndexOfRow + IndexOfColumn) = a;
    }
}

Teraz máme MySurface naplnené a iba z nej vytvoríme SDL_Texture. Výsledok je nasledovný.

8-bitové prechod bez alfa kanálu - SDĽ

Pár ďalších dôležitých informácií

Vidíme, že prechod obsahuje všetky farby červenej, ktoré môžeme vykresliť. Výsledok sa teda nezdá ako 8 bitová grafika. Na rozdiel od 16 a 32 bitové grafiky, tu nemôžeme pridať žiadne ďalšie farby. Ak by sme chceli mať spodných desať pixelov zelených, museli by sme sa vzdať jedného odtieňa červenej. Ak by sme chceli viac odtieňov zelenej, lineárne by muselo ubudnúť aj odtieňov červenej. Tu sú ony limity 8 bitové grafiky.

Ak budeme chcieť použiť priehľadnosť (áno, 8 bitová grafika podporuje i priehľadnosť), budeme musieť nastaviť Blend mode SDL_Surface. K tomu slúži funkcia SDL_SetSurface­BlendMode. K blend módu sa dostaneme v niektorom z nadchádzajúcich dielov. S použitím alfa kanálu vyzerá výsledok nasledovne.

Prechod s priehľadnosťou - SDĽ

To je pre dnešný diel všetko. V tom budúcom sa pozrieme na prácu s 16 a 32 bitovú grafikou.


 

Stiahnuť

Stiahnutím nasledujúceho súboru súhlasíš s licenčnými podmienkami

Stiahnuté 789x (9.58 MB)

 

Predchádzajúci článok
SDĽ - Vykreslenie textu
Všetky články v sekcii
SDĽ
Preskočiť článok
(neodporúčame)
SDĽ - Práca s 16 a 32-bitovou grafikou
Č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