Hlavní navigace

Grafická knihovna OpenGL (7): jednobarevné rastrové obrázky

Pavel Tišnovský 12. 8. 2003

V dnešní části seriálu o OpenGL si ukážeme práci s bitmapami, což v "nářečí" dokumentace k OpenGL značí jednobarevné rastrové obrázky. Bitmapy se často využívají při vykreslování písma, vlastních kurzorů myši nebo různých jednoduchých ikon v interaktivních grafických aplikacích.

Vykreslování bitmap

Pojem bitmapa v OpenGL

V OpenGL značí pojem bitmapa obdélníkové pole, kde každý prvek tohoto pole má hodnotu 0 nebo 1 – jedná se tedy o pole bitů. Toto pole slouží jako vykreslovací maska, která je použita při vyplnění obdélníkové, osově orientované části okna OpenGL. V místě, kde je prvek pole nastavený na jedničku, se provede vykreslení pixelu a v místě s nulovým prvkem se žádný pixel nevykreslí, tj. již nakreslený obrázek na pozadí v tomto místě zůstane. Vykreslovaná bitmapa tedy může být pouze jednobarevná, protože pro každý pixel rozlišujeme jen dva stavy (vykresleno, nebo nevykresleno) a informaci o barvě pixelu již tedy nelze do jednoho bitu zakódovat.

Je důležité zdůraznit, že pokud při programování v OpenGL mluvíme o bitmapách, máme na mysli vždy pouze jednobarevné rastrové obrázky s výše popsanými vlastnostmi. Všechny ostatní typy rastrových obrázků s větší bitovou hloubkou (a tím pádem i s větším počtem barev nebo i průhledností) nazýváme v OpenGL termínem pixmapa. Pixmapami, které mají při programování OpenGL aplikací širší oblasti použití, se budeme podrobněji zabývat v dalších částech tohoto seriálu.

Cesta rastrových dat ve vykreslovacím řetězci

Při práci s bitmapami se v OpenGL pracuje s tou částí vykreslovacího řetězce, ve kterém se provádí zpracování rastrových dat. Na dalším obrázku je tato část řetězce, která se nazývá imaging pipeline, zobrazena. Kromě jednotlivých bloků jsou naznačeny i cesty, po kterých se mohou rastrová data přenášet.

imaging pipeline


Jak je z obrázku patrné, není vykreslování rastrových dat úplně přímočaré, protože mezi zdrojem rastrových dat (což je v případě bitmap buď paměť procesoru, nebo display list) a cílem (což je paměť zobrazeného snímku, takzvaný framebuffer) leží dalších pět bloků, ve kterých se mohou rastrová data dále zpracovávat. Při práci s bitmapami však nejsou použity ani všechny bloky, ani všechny cesty dat. Cestu dat si v případě práce s bitmapami můžeme zvýraznit na následujícím obrázku.

cesta bitmapových dat


Rastrová data, která tvoří pixely bitmapy, musí být nejprve vytvořena v hlavní paměti počítače. Potom jsou tato data přenesena do grafického akcelerátoru a je provedeno jejich případné rozbalení (unpacking). To, zda bude rozbalení provedeno, závisí na módu uložení bitmapy v hlavní paměti počítače. Poté jsou data bitmapy přenesena do dalších bloků, kterými data pouze projdou, protože s bitmapou (narozdíl od pixmap) nelze při vykreslování provádět téměř žádné další operace. Jednotlivé pixely bitmapy jsou poté převedeny na fragmenty a ty jsou přeneseny do framebufferu, který je následně zobrazen.

Abychom mohli bitmapu vykreslit, potřebujeme pomocí několika příkazů OpenGL specifikovat všechny vlastnosti této bitmapy. Tyto vlastnosti a příkazy pro jejich nastavení si popíšeme v následujících podkapitolách:

Mód uložení pixelů v bitmapě

Pomocí funkce glPixelStorei(pro­perties, value) je možné grafickému subsystému sdělit, jakým způsobem má transformovat rastrová data, která jsou uložena v hlavní paměti počítače. Každá platforma má totiž vlastní způsob uložení dat, zejména se to týká pořadí bytů při čtení větších celků (little endian, big endian, smíšené architektury) a zarovnání dat v paměti. Pro dosažení co nejlepší přenositelnosti je tedy nutné sdělit způsob uložení dat a tím i nastavit potřebné konverze.

Funkce glPixelStorei() má dva parametry. Do prvního parametru (properties) se zadává vlastnost, která se bude měnit, do druhého parametru (value) potom hodnota tohoto parametru.

Pro práci s bitmapami lze měnit hodnoty těchto vlastností:

  • GL_UNPACK_SWAP_BY­TES může být nastaveno na hodnotu GL_TRUE nebo GL_FALSE. Touto vlastností se řídí prohození bytů (swap) v operačním slově počítače. Vlastnost je implicitně nastavena na hodnotu FALSE, prohození se tedy neprovádí.
  • GL_UNPACK_LSB_FIRST může být taktéž nastaveno na hodnotu GL_TRUE nebo GL_FALSE. Tato vlastnost řídí otočení pořadí bitů v každém bytu. Implicitně je nastavena hodnota GL_FALSE, otáčení se tedy neprovádí.
  • GL_UNPACK_ALIGNMENT specifikuje zarovnání každého řádku pixelů v paměti. Možné hodnoty tohoto parametru jsou 1 (zarovnání na byte), 2 (zarovnání na sudé byty), 4 (zarovnání na 32bitové slovo) a 8 (zarovnání na 64bitové). Je potřeba dát pozor na to, že implicitně je nastavena hodnota 4, tedy zarovnání na 32bitové slovo, což může zejména u bitmap způsobit nekorektní vykreslení.

Barva bitmapy

Barva bitmapy se specifikuje už známým příkazem void glColor*(). Pro vykreslení bitmapy sytě zelenou barvou můžeme použít například funkci glColor3f(0.0f, 1.0f, 0.0f). Je potřeba dát pozor na to, aby barva byla zadána před zavoláním příkazu pro specifikaci aktuální polohy bitmapy ve scéně, protože jinak by se změna barvy na právě vykreslované bitmapě neprojevila. Aktuální barva bitmapy je totiž jeden ze stavů, který je po zadání polohy již neměnný.

Aktuálně používanou barvu bitmapy lze získat pomocí funkce glGetFloatv() s prvním parametrem nastaveným na hodnotu GL_CURRENT_RAS­TER_COLOR. Další parametr je ukazatel na pole čtyř čísel typu GLfloat, do kterého je aktuálně používaná barva uložena, přičemž se postupně ukládají barevné složky Red, Green, Blue a Alpha.

Aktuální pozice bitmapy

Aktuální pozice bitmapy udává počáteční bod, od kterého se bitmapa bude vykreslovat. Pro specifikaci počátečního bodu se používá příkaz void glRasterPos(), pomocí kterého lze zadat, podobně jako u příkazu void glVertex(), dvě, tři nebo čtyři souřadnice. Pokud jsou zadány pouze dvě souřadnice x a y, je třetí souřadnice z nastavena na nulu a čtvrtá souřadnice w (váha) nastavena na jedničku. Pokud jsou zadány tři souřadnice x, y a z, je čtvrtá souřadnice w

nastavena na jedničku. Nejčastěji se počáteční bod bitmapy zadává ve 2D pomocí dvou celočíselných souřadnic a používá se příkaz void glRasterPos2i(GLint x, GLint y). Jsou však samozřejmě možné i další kombinace počtu souřadnic (2, 3, 4) a datových typů těchto souřadnic (GLshort, GLint, GLfloat,

GLdouble)

Počáteční bod vykreslování bitmapy je podroben stejným transformacím jako vrcholy geometrických primitiv – na bod jsou tedy postupně aplikovány transformace specifikované v ModelView matici, Transformation matici a výsledné abstraktní souřadnice jsou následně transformovány dle nastaveného Viewportu. Podrobnější popis transformací byl uveden v předchozích dílech tohoto seriálu, kde je také popsán způsob nastavení jednotlivých transformačních ma­tic.

Při vykreslování bitmap i pixmap je zapotřebí dávat pozor na skutečnost, že počáteční bod bitmapy či pixmapy může být v průběhu transformací odstraněn (například proto, že je umístěn mimo zobrazované okno). V případě odstranění počátečního bodu se nevykreslí ani ta část bitmapy či pixmapy, která by byla viditelná. Proto je při zobrazování částečně viditelných rastrových obrázků zapotřebí buď vhodně zvětšit oblast zadanou ve Viewportu, nebo rastrový obrázek nanést jako texturu na obdélníky (podrobnější popis texturování bude uveden v dalších dílech věnovaných 3D scénám). Pokud je počáteční bod v průběhu průchodu vykreslovacím řetězcem odstraněn, je aktuální pozice bitmapy označena za neplatnou (invalid).

Naposledy použitou aktuální pozici bitmapy lze zjistit pomocí funkce glGetFloatv() s prvním argumentem nastaveným na hodnotu GL_CURRENT_RAS­TER_POSITION. Druhým parametrem je ukazatel na pole čtyř čísel typu GLfloat, do kterého se tato pozice uloží. Dále je možné zjistit, zda je aktuální pozice bitmapy platná – použije se funkce glGetBooleanv() s prvním parametrem nastaveným na hodnotu GL_CURRENT_RAS­TER_POSITION_VA­LID.

Rozměry bitmapy, relativní pozice počátku a vlastní bitmapová data

Posledními údaji, které se při vykreslení bitmap musí zadat, jsou její rozměry, relativní pozice bitmapy vůči zadanému počátečnímu bodu a vlastní bitmapová data (hodnoty bitů rastrového obrázku). Všechny tyto údaje se zadávají současně v jednom příkazu glBitmap(), jehož hlavička vypadá následovně:

void glBitmap(
  GLsizei width,
  GLsizei height,
  GLfloat xorig,
  GLfloat yorig,
  GLfloat xmove,
  GLfloat ymove,
  const GLubyte * bitmap
);

význam parametrů funkce glBitmap()

Význam jednotlivých parametrů funkce glBitmap() je vysvětlen v dalších odstavcích:

width
V tomto parametru je uvedena šířka vykreslované bitmapy. Tato hodnota je zadána v pixelech. Narozdíl od dalších příkazů pro vykreslování rastrových dat (pixmapy, textury) můžeme zadat šířku libovolnou. Může jít tedy například i o číslo nedělitelné osmi, liché číslo apod. Pixely bitmapy jsou sice uloženy po bytech (8 bitů), ale případné nepotřebné bity na konci řádku jsou při vykreslování ignorovány.
height
V tomto parametru je uvedena výška vykreslované bitmapy. Podobně jako u předchozího parametru, i zde je hodnota zadána v pixelech a nejsou kladeny žádné zvláštní požadavky na velikost či zarovnání zadávané hodnoty.
xorig
Relativní horizontální pozice počátku vykreslované bitmapy od aktuální pozice bitmapy. Pokud je xorig=yorig=0, aktuální pozice bitmapy určuje levý dolní roh bitmapy. Pokud jsou tyto hodnoty nenulové, lze bitmapou vůči této pozici posouvat. Kladné hodnoty posouvají počátek doprava, záporné doleva.
yorig
Relativní vertikální pozice počátku vykreslované bitmapy. Význam je podobný jako u předchozího parametru. Kladné hodnoty posouvají počátek nahoru, záporné dolů. Tento parametr se často používá při vykreslování písma, protože některé znaky (například g, j a y) mají svůj obraz vykreslený až k místu dolní dotažnice, ale pozice znaku se většinou udává relativně k hlavní dotažnici.
xmove
Horizontální posun nové aktuální pozice bitmapy od pozice současné. Po vykreslení je k bodu aktuální pozice bitmapy připočten vektor (xmove, ymove) a nová bitmapa se tedy vykreslí relativně posunutá (pokud se ovšem mezitím nepoužije příkaz glRasterPos*(), který nastaví novou aktuální pozici bitmapy). Tento parametr se často používá v případě, že pomocí bitmap vykreslujeme písmo. Kladné hodnoty posouvají počátek nové bitmapy doprava, záporné doleva.
ymove
Vertikální posun nové aktuální pozice bitmapy od pozice současné. Význam je podobný jako u předchozího parametru. Kladné hodnoty posouvají počátek nové bitmapy směrem nahoru, záporné dolů.
bitmap
V tomto parametru je funkci glBitmap() předán ukazatel na datovou oblast, ve které jsou uložena rastrová data bitmapy. Pro každý pixel v bitmapě je vyhrazen jeden bit, ovšem data jsou při čtení z paměti přístupná po vyšších celcích – bytech, wordech a dwordech. Vzhledem k tomu, že organizace paměti může být na jednotlivých platformách odlišná (nelze například číst paměť po bytech, ale pouze po dwordech apod.), je potřeba při psaní přenositelných programů v OpenGL zadat interní formát bitmapových dat. Pro tento účel se používá funkce void glPixelStore*(), která již byla popsána v podkapitole Mód uložení pixelů v bitmapě.

Vlastní vykreslení bitmapy

Pro úspěšné vykreslení první bitmapy je většinou zapotřebí zavolat všechny výše popsané příkazy: glPixelStore(), glColor(), glRasterPos*() a glBitmap() (první příkaz nemusí být uveden v případě, že nám vyhovují standardně nastavené parametry uložení pixelů). Pokud je vyžadováno vykreslení více bitmap vedle sebe nebo pod sebe (například při vykreslování písma), je možné další bitmapy vykreslit pouze příkazem glBitmap() s vhodně nastaveným posunem.

Ukázkové příklady

Příklad vykreslení jednoduché bitmapy, kde je zobrazeno písmeno F je demonstrován na příkladu číslo 10. K dispozici je i zdrojový kód s obarvenou syntaxí. V tomto příkladu je také ukázáno, že změna barvy bitmapy musí být provedena před příkazem, který mění pozici bitmapy, jinak se barva další vykreslované bitmapy nezmění.

V demonstračním příkladu číslo 11 je ukázáno řetězové zobrazení více bitmap s využitím posunu počátku vykreslování další bitmapy. Také k tomuto příkladu je k dispozici zdrojový kód s obarvenou syntaxí.

V posledním dnešním příkladu číslo 12 je ukázáno, jak se změní vykreslení bitmapy, pokud se zadá jiný režim uložení pixelů. Samozřejmě dodávám i zdrojový kód s obarvenou syntaxí.

V další části tohoto seriálu si popíšeme využití bitmap a display-listů při vykreslování písma.

Našli jste v článku chybu?

9. 11. 2006 17:32

Xennus (neregistrovaný)
mam trochu zmetok v zdrojovom kode je napisane ze bitmapa ma 10x12 pixelov avsak v prvom (ci druhom) diely bolo ze GLubite ma 8 bitov cize mi vychadza 16x12 pixelov
dalsia vec, ked chcem vecsie rozmery napr 24x24 ako to spravit aby mi to nebralo len 16(alebo tych 10)x(daco)
dakujem za pomoc

13. 8. 2003 13:47

Pavel Tisnovsky (neregistrovaný)

Přeji pěkný den,

tak, jak je nadstavbová knihovna GLUT vytvořena, je možná konfigurace a alokace bufferů pouze na začátku aplikace. Přitom se používá, jak jste sám napsal, funkce glutInitDisplayMode(). Ovšem v GLUTu nemůžete po inicializaci změnit rendering kontext OpenGL (to je možné například ve WinAPI pomocí funkcí wglCreateContext(), wglDeleteContext()).

Proto po inicializaci GLUTu už nelze konfiguraci bufferů změnit. Mimo jiné to znamená, že všechna okna aplikace budou mít stejnou kon…



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

Přehledná titulka, průvodci, responzivita

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

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

Lupa.cz: Slevové šílenství je tu. Kde nakoupit na Black Friday?

Slevové šílenství je tu. Kde nakoupit na Black Friday?

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

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

Podnikatel.cz: Prodává přes internet. Kdy platí zdravotko?

Prodává přes internet. Kdy platí zdravotko?

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

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

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í

Lupa.cz: Proč firmy málo chrání data? Chovají se logicky

Proč firmy málo chrání data? Chovají se logicky

Podnikatel.cz: EET: Totálně nezvládli metodologii projektu

EET: Totálně nezvládli metodologii projektu

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

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

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

Sony KD-55XD8005 s Android 6.0

Měšec.cz: Kdy vám stát dá na stěhování 50 000 Kč?

Kdy vám stát dá na stěhování 50 000 Kč?

DigiZone.cz: Recenze Westworld: zavraždit a...

Recenze Westworld: zavraždit a...

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

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

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

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

Měšec.cz: Zdravotní a sociální pojištění 2017: Připlatíte

Zdravotní a sociální pojištění 2017: Připlatíte

Vitalia.cz: Jsou čajové sáčky toxické?

Jsou čajové sáčky toxické?

120na80.cz: Pánové, pečujte o svoje přirození a prostatu

Pánové, pečujte o svoje přirození a prostatu

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