Hlavní navigace

SDL: Hry nejen pro Linux (6)

Michal Turek 29. 3. 2005

V tomto dílu budeme dále rozvíjet naše znalosti o SDL grafice. Předvedeme si například, jak vyplnit surface barvou, jak docílit toho, aby určitá barva byla transparentní (průhledná), jak nastavit průhlednost i takového surface, který neobsahuje alfa kanál, a další užitečné věci.

Vytvoření prázdného surface

Prázdný SDL_Surface se dá v programu vytvořit pomocí funkce SDL_CreateRGBSur­face(). První čtyři parametry jistě není třeba popisovat, jsou jimi flagy, šířka, výška a barevná hloubka. Bity masek definují pořadí barevných složek v pixelu, označují tedy, jestli bude obrázek uložen jako RGB, BGR, popř. v jiném formátu. U osmi- a čtyřbitové barevné hloubky bude alokována prázdná paleta.

SDL_Surface *SDL_CreateRGBSurface(Uint32 flags,
                int width, int height, int depth,
                Uint32 Rmask, Uint32 Gmask,
                Uint32 Bmask, Uint32 Amask);

SDL_Surface *SDL_CreateRGBSurfaceFrom(void *pixels,
                int width, int height, int depth, int pitch,
                Uint32 Rmask, Uint32 Gmask,
                Uint32 Bmask, Uint32 Amask);

Při vytváření surface je vhodné specifikovat masky v závislosti na pořadí bytů, které se používá na dané platformě (little/big endian). SDL definuje symbolickou konstantu SDL_BYTEORDER, jež se rovná buď hodnotě SDL_LIL_ENDIAN, nebo SDL_BIG_ENDIAN.

Například při vytváření textury pro OpenGL je vhodné podle následujícího příkladu vytvořit pomocný surface, voláním SDL_Blit() do něj pixely zkopírovat, tím se transformují do správného formátu, a až poté vytvořit texturu.

SDL_Surface *surface = SDL_CreateRGBSurface(
                SDL_SWSURFACE,
                128, 128, 32,
#if SDL_BYTEORDER == SDL_LIL_ENDIAN
                0x000000FF,
                0x0000FF00,
                0x00FF0000,
                0xFF000000
#else
                0xFF000000,
                0x00FF0000,
                0x0000FF00,
                0x000000FF
#endif
                );

Ořezávací obdélník surface

Příkazem SDL_SetClipRect() lze surface „virtuálně ořezat“, pro funkce se pak bude chovat, jako by měl definovánu tuto novou velikost. Maximální rozměry mohou být následně obnoveny předáním NULL. Uvedená vlastnost se bere v úvahu, když se do surface kreslí, ne když je kreslen!

Pokud funkce vrátí SDL_FALSE, obdélník neprotínal surface a při vykreslování se tedy nezobrazí nic. Zasahuje-li alespoň část obdélníku do surface, je vráceno SDL_TRUE a při kreslení se bude brát v úvahu oblast průniku.

SDL_bool SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect);
void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect);

Pomocí druhé uvedené funkce lze získat aktuální ořezávací roviny obdélníku.

Specifikace barvy

Kvůli mnoha různým formátům surface – zvláště paletovým – může být výběr barvy komplikovanější, než by se na první pohled mohlo zdát. Naštěstí SDL poskytuje příkazy, které se umí postarat o všechny detaily.

Uint32 SDL_MapRGB(SDL_PixelFormat *fmt,
                Uint8 r, Uint8 g, Uint8 b);
Uint32 SDL_MapRGBA(SDL_PixelFormat *fmt,
                Uint8 r, Uint8 g, Uint8 b, Uint8 a);

První parametr funkce je formátem pixelů, který daný surface používá (většinou surface->format), a ostatní představují jednotlivé RGB(A) složky. Barva je vrácena jako 32bitové číslo, jež je buď přímo požadovanou barvou, nebo (v případě paletového pixel formátu) barvou, která se nachází v paletě a nejvíce se blíží požadované.

Opačný směr, tedy získání RGB(A) složek barvy z pixelu, zprostředková­vají funkce

void SDL_GetRGB(Uint32 pixel, SDL_PixelFormat *fmt,
                Uint8 *r, Uint8 *g, Uint8 *b);
void SDL_GetRGBA(Uint32 pixel, SDL_PixelFormat *fmt,
                Uint8 *r, Uint8 *g, Uint8 *b, Uint8 *a);

Vyplnění surface barvou

Funkce SDL_FillRect() se většinou používá ke změně barvy pozadí okna, ale lze ji použít na libovolný surface.

int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color);

První parametr představuje surface, na který bude operace aplikována, a druhý omezuje velikost obarvované plochy. Pokud by byl tento obdélník nastaven na NULL, předpokládá se vyplnění celého surface. Color určuje barvu.

Obsahuje-li surface ořezávací obdélník, bude vyplněn pouze jeho průnik s dstrect a dstrect bude nastaven na rozměry vyplněné oblasti. Následující příklad nastaví pozadí okna na červenou barvu.

// Červené pozadí okna
SDL_FillRect(g_screen, NULL, SDL_MapRGB(g_screen->format, 255, 0, 0));

Nastavení klíčové (průhledné) barvy

Transparentní barva surface se dá nastavit pomocí funkce SDL_SetColorKey(). Při blittingu nebudou pixely této barvy vykresleny.

int SDL_SetColorKey(SDL_Surface *surface, Uint32 flag, Uint32 key);

Za parametr flag se při této operaci musí předat symbolická konstanta SDL_SRCCOLORKEY, předáním nuly se transparentní barva zruší. Následujícím příkazem se v surface zprůhlední růžové pixely.

SDL_SetColorKey(surface, SDL_SRCCOLORKEY,
                SDL_MapRGB(surface->format, 255, 0, 255));

Pokud je flag binárně ORován se SDL_RLEACCEL, bude surface vykreslován s použitím RLE akcelerace. To je výhodné u spojitých oblastí průhledných pixelů (na řádcích). Surface je pro použití RLE akcelerace zakódován při prvním předání do funkce SDL_BlitSurface() nebo SDL_DisplayFor­mat().

Alfa hodnota surface

Pomocí funkce SDL_SetAlpha() lze nastavit globální úroveň průhlednosti, která bude aplikována na každý pixel surface.

int SDL_SetAlpha(SDL_Surface *surface, Uint32 flag, Uint8 alpha);

Parametr flag musí být nastaven na SDL_SRCALPHA a může být, stejně jako u předešlé funkce, ORován se SDL_RLEACCEL. Poslední parametr specifikuje úroveň alfy. Nula (SDL_ALPHA_TRAN­SPARENT) má význam úplné průhlednosti a 255 (SDL_ALPHA_OPAQUE) značí neprůhlednost. Speciální hodnotou je 128, která je určitým způsobem optimalizována, takže blitting bude rychlejší než u jiných hodnot. Při použití této techniky nesmí mít surface alfa kanál, použila by se alfa jednotlivých pixelů.

Nastavení palety

Barvy v paletě osmibitového a čtyřbitového surface se dají nastavit pomocí funkce SDL_SetColors().

int SDL_SetColors(SDL_Surface *surface, SDL_Color *colors,
                int firstcolor, int ncolors);

Funkci se předává ukazatel na daný surface, pole barev, první barva a celkový počet barev. Pokud byly úspěšně nastaveny všechny barvy, je vrácena jednička. Pokud některé byly nastaveny a některé ne, je vrácena nula. V takovém případě by měl programátor zjistit ze surface nově vzniklou paletu. Nejedná-li se o paletový surface, nic se neprovede a je vrácena také nula.

Je-li předaný surface asociován s oknem a byl-li v SDL_SetVide­oMode() definován flag SDL_HWPALETTE, vrátí tato funkce vždy jedničku a nastavení palety je vždy garantováno.

V případě, že se jedná o framebuffer s hardwarovým surface, obsahuje vždy dvě palety, logickou (používají ji funkce pro blitting) a fyzickou (používá ji hardware k mapování na obrazovku). Aby je bylo možné specifikovat odděleně, musí mít framebuffer nastaven již zmíněný flag SDL_HWPALETTE. K oddělené specifikaci palet pak slouží funkce

int SDL_SetPalette(SDL_Surface *surface, int flags,
                SDL_Color *colors, int firstcolor,
                int ncolors);

Parametr flags může být nastaven buď na hodnotu SDL_LOGPAL (logická paleta), nebo SDL_PHYSPAL (fyzická paleta), většinou se modifikuje pouze jedna z nich, čímž se dociluje různých efektů. Volání SDL_SetPalette() s parametrem flags nastaveným na SDL_LOGPAL | SDL_PHYSPAL je ekvivalentem SDL_SetColors().

V SDL manuálu se u popisu těchto funkcí nachází příklad na nastavení palety úrovně šedi.

Ukázkové programy

Vlastnosti surface

Podstata tohoto programu tkví především ve vykreslovací funkci. Surface okna je zmenšen pomocí SDL_SetClipRect() tak, aby u okrajů vznikla desetipixelová mezera. Poté je vykresleno červené pozadí a do každého rohu stejný obrázek, ale s jinými vlastnostmi.

V levém horním rohu se nachází originál tak, jak byl nahrán z disku, u obrázku vpravo je bílá barva pixelů nastavena na transparentní. Vlevo dole byla nastavena 50% průhlednost a vpravo dole se nachází kombinace obou. Je důležité poznamenat, že obrázek je ve formátu RGB, bez alfa kanálu. (Zdrojový kód se zvýrazněním syntaxe.)

Vlastnosti surface

Download

Pokračování

V příští části se budeme věnovat přímému přístupu k pixelům surface a změně kurzoru myši.

Našli jste v článku chybu?
Vitalia.cz: Říká amoleta - a myslí palačinka

Říká amoleta - a myslí palačinka

Podnikatel.cz: K EET. Štamgast už peníze na stole nenechá

K EET. Štamgast už peníze na stole nenechá

Podnikatel.cz: Vládu obejde, kvůli EET rovnou do sněmovny

Vládu obejde, kvůli EET rovnou do sněmovny

DigiZone.cz: Česká televize mění schéma ČT :D

Česká televize mění schéma ČT :D

Podnikatel.cz: Přehledná titulka, průvodci, responzivita

Přehledná titulka, průvodci, responzivita

DigiZone.cz: ČT má dalšího zástupce v EBU

ČT má dalšího zástupce v EBU

Vitalia.cz: To není kašel! Správná diagnóza zachrání život

To není kašel! Správná diagnóza zachrání život

Lupa.cz: Není sleva jako sleva. Jak obchodům nenaletět?

Není sleva jako sleva. Jak obchodům nenaletět?

Lupa.cz: UX přestává pro firmy být magie

UX přestává pro firmy být magie

Lupa.cz: Co se dá měřit přes Internet věcí

Co se dá měřit přes Internet věcí

Měšec.cz: U levneELEKTRO.cz už reklamaci nevyřídíte

U levneELEKTRO.cz už reklamaci nevyřídíte

Vitalia.cz: Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

Láska na vozíku: Přitažliví jsme pro tzv. pečovatelky

DigiZone.cz: Sony KD-55XD8005 s Android 6.0

Sony KD-55XD8005 s Android 6.0

120na80.cz: Rakovina oka. Jak ji poznáte?

Rakovina oka. Jak ji poznáte?

Podnikatel.cz: 1. den EET? Problémy s pokladnami

1. den EET? Problémy s pokladnami

Lupa.cz: Propustili je z Avastu, už po nich sahá ESET

Propustili je z Avastu, už po nich sahá ESET

120na80.cz: Bojíte se encefalitidy?

Bojíte se encefalitidy?

Lupa.cz: Google měl výpadek, nejel Gmail ani YouTube

Google měl výpadek, nejel Gmail ani YouTube

Podnikatel.cz: Na poslední chvíli šokuje vyjímkami v EET

Na poslední chvíli šokuje vyjímkami v EET

Lupa.cz: Avast po spojení s AVG propustí 700 lidí

Avast po spojení s AVG propustí 700 lidí