OpenGL Imaging Subset IV
Pavel Tišnovský
Úvodník
V dnešním pokračování seriálu pojednávajícím o OpenGL Imaging Subsetu si
řekneme, jakým způsobem je možné pracovat s barvovými paletami. Při zpracování
pixelů, které se přenášejí z operační paměti počítače do framebufferu, je totiž
možné na několika místech vykreslovacího řetězce použít barvové palety, pomocí
nichž lze zásadním způsobem změnit vykreslovaný rastrový obraz. Dále si stručně
povíme, jakým způsobem je možné přeložit a spustit demonstrační příklady z
tohoto dílu.
Obsah
Umístění barvových palet ve vykreslovacím řetězci
Zadání barvové palety
Specifikace pixmapy pro naplnění barvové palety
Získání nastavené barvové palety
Povolení a zákaz použití barvové palety
Překlad a spuštění demonstračních příkladů
Pokračování
Seznam funkcí zmíněných v této části
Nové funkce popsané v této části
Demonstrační příklady
Zkomprimovaná verze článku
Umístění barvových palet ve vykreslovacím řetězci
Při použití OpenGL Imaging Subsetu je možné použít tři barvové palety, které
jsou umístěny v různých částech vykreslovacího řetězce. Umístění barvových
palet ve vykreslovacím řetězci je zvoleno tak, aby bylo možné po každé
složitější operaci s vykreslovanými pixely jednoduše změnit jejich hodnoty.
Připomeňme, že vykreslování pixelů uložených v rastrovém obrazci je spuštěno
pomocí funkce glDrawPixels().
Na prvním obrázku je zobrazena část vykreslovacího řetězce, ve které se mění
hodnoty pixelů, které do vykreslovacího řetězce proudí buď ve formátu RGBA
(true color) nebo ve formátu L (pouze Luminance, resp. index do LUT
tabulky). Vidíme, že hodnoty pixelů je možné měnit pomocí barvových palet v
několika místech:
- První barvová paleta je aplikována po vynásobení barvových složek pixelů
konstantou scale, přičtením ke konstantě bias a převodu
hodnot pomocí LUT tabulky. Použitím této barvové palety se tak de facto provádí
dvojí překódování barev - jedno pomocí LUT tabulky a druhé pomocí barvové
palety. Tato první barvová paleta bývá nazývána jednoduše
GL_COLOR_TABLE.
- Druhá barvová paleta je aplikována až po provedení konvolucí, tj. aplikaci
konvolučního filtru na přenášený rastrový obraz. Jak konvoluce, tak i další
operace lze při vykreslování zakázat (přeskočit), což je na prvním obrázku
znázorněno pomocí šedých šipek. Tato druhá barvová paleta se při volání funkcí
Imaging Subsetu nazývá GL_POST_CONVOLUTION_COLOR_TABLE.
- Třetí a poslední barvová paleta je na přenášené pixely aplikována po
provedení transformace barev pomocí barvové transformační matice. Po nalezení
nových barev v barvové paletě se mohou hodnoty pixelů podílet na vytváření
histogramu a MinMax tabulek (viz další díly). Následně jsou pixely zapsány do
framebufferu. Poslední barvová paleta se při volání funkcí Imaging Subsetu
nazývá GL_POST_COLOR_MATRIX_COLOR_TABLE.
Obrázek 1: Část vykreslovacího řetězce s barvovými paletami
V dalších odstavcích budou popsány funkce, pomocí kterých lze položky
barvových palet naplnit, změnit a zpětně přečíst do operační paměti.
Zadání barvové palety
Barvovou paletu lze pro převod pixelů z paletového režimu do režimu true
color (RGBA), nebo i při prostém převodu barev z režimu RGBA do RGBA, zadat
pomocí funkce glColorTable() tak, že se "nanečisto" provedou všechny
předem specifikované operace, které se provádí s pixely při přenosu do
vykreslovacího řetězce a následně se zapamatují výsledné hodnoty barev nově
vypočtených pixelů.
V praxi vypadá celá operace následovně:
- Do vykreslovacího řetězce se pomocí funkce glColorTable() pošle
pixmapa, která má výšku pouze jeden řádek pixelů a jejíž šířka odpovídá
výsledné velikosti barvové palety.
- Pixely jsou z této pixmapy přečteny z operační paměti počítače stejným
způsobem, jakoby se volala funkce glDrawPixels(), tj. jsou provedena
všechna potřebná dekódování a rozpakování hodnot jednotlivých pixelů.
- Hodnota barvy každého pixelu je vynásobena konstantou zadanou pomocí funkce
glColorTableParameterf(GL_COLOR_TABLE_SCALE) a posléze přičtena ke
konstantě, která je zadána pomocí funkce
glColorTableParameterf(GL_COLOR_TABLE_BIAS).
- Výsledná barva je následně oříznuta do rozsahu 0.0-1.0.
- Barvové složky jsou potom získány z vypočtených hodnot R, G, B a A, a je z
nich vytvořena barvová paleta se zadaným interním formátem (viz argument
internalFormat popsaný v následujícím odstavci). Velikost barvové
palety je nastavena tak, aby měla width položek. Indexy do palety mají
hodnoty od 0 do width-1. Platí, že i-tá pozice v barvové paletě
odpovídá i-tému pixelu ve zdrojové pixmapě.
Specifikace pixmapy pro naplnění barvové palety
Pro naplnění barvové palety z předem připravené pixmapy je zapotřebí zavolat
následující funkci:
void glColorTable(
GLenum target,
GLenum internalFormat,
GLsizei width,
GLenum format,
GLenum type,
GLvoid *table
);
Význam jednotlivých argumentů funkce glColorTable():
- Argument target musí obsahovat jednu z těchto hodnot:
GL_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE a
GL_POST_COLOR_MATRIX_COLOR_TABLE pro přímou modifikaci barvové palety.
Alternativně lze zadat hodnoty GL_PROXY_COLOR_TABLE,
GL_PROXY_POST_CONVOLUTION_COLOR_TABLE a
GL_PROXY_POST_COLOR_MATRIX_COLOR_TABLE. V případě posledních tří
hodnot se ve skutečnosti žádné výpočty neprovádí (ve vykreslovacím řetězci
neproudí data), pouze se zjistí, zda může být zadaný obraz nahrán do příslušné
barvové palety.
- V argumentu internalFormat je uložen interní formát dat barvové
palety, tj. formát, do kterého se (nezávisle na vstupním rastrovém obrázku)
barevná paleta uloží. Mezi povolené hodnoty, které je možné v tomto argumentu
zadat, patří: GL_RGBA, GL_RGB, GL_RED,
GL_GREEN, GL_BLUE, GL_ALPHA atd. Nejpoužívanější
jsou hodnoty GL_RGBA a GL_RGB, pomocí kterých lze vytvořit
barevnou paletu s výběrem libovolné barvy.
- Pomocí argumentu width je možné specifikovat šířku přenášené
pixmapy a tím i určit počet položek v barvové paletě. Maximální šířka (tj.
hodnota argumentu width) je závislá na implementaci OpenGL, minimální
podporovaná hodnota je však rovna 32 pixelům. Výšku pixmapy není zapotřebí
zadávat, protože je vždy nastavena na hodnotu 1.
- V argumentu format je zadán formát rastrového obrazu, který je
funkci předáván. Význam jednotlivých hodnot je stejný jako u funkce
glDrawPixels(), povolené hodnoty tohoto argumentu jsou:
GL_RGBA, GL_RGB, GL_RED, GL_GREEN,
GL_BLUE, GL_ALPHA a rozšířené formáty jako
GL_BGR_EXT, GL_BGRA_EXT apod.
- Argument type má, podobně jako argument předchozí, stejný význam,
jako u funkce glDrawPixels() - lze pomocí něj specifikovat, jaký
formát budou mít jednotlivé barvové složky předávaných pixelů. Povolené hodnoty
jsou GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT,
GL_SHORT, GL_UNSIGNED_INT, GL_INT a
GL_FLOAT. Všimněte si, že není povolen typ GL_BITMAP, který
by při práci s barvovou paletou nedával žádný smysluplný výstup.
- V argumentu table se předává ukazatel na rastrová data přenášeného
obrázku. Při přenosu se provádí datové konverze a případné rozpakování
barvových hodnot pixelů podobně, jako při vykreslování rastrových bitmap a
pixmapy.
Získání nastavené barvové palety
Funkce glGetColorTable() je inverzní k výše popsané funkci
glColorTable(), protože je pomocí ní možné získat aktuálně nastavenou
barevnou paletu. Barevná paleta je přečtena a uložena do operační paměti ve
formě pixmapy. Hlavička funkce glGetColorTable() má podobu:
void glGetColorTable(
GLenum target,
GLenum format,
GLenum type,
GLvoid *table
);
Význam argumentů této funkce je podobný, jako u funkce
glColorTable():
- Argument target musí být nastaven na jednu z hodnot:
GL_COLOR_TABLE, GL_POST_CONVOLUTION_COLOR_TABLE nebo
GL_POST_COLOR_MATRIX_COLOR_TABLE.
- Argumentem format je specifikováno, jaký formát budou mít přečtené
pixely. Je možné tytéž hodnoty, jako u funkce glReadPixels(), tj.
GL_RGBA, GL_RGB, GL_BGR_EXT, GL_BGRA_EXT
apod.
- V argumentu type je zadán typ barvových složek čtených pixelů.
Podobně jako u funkce glReadPixels() je možné použít hodnoty
GL_UNSIGNED_BYTE, GL_BYTE, GL_UNSIGNED_SHORT,
GL_SHORT, GL_UNSIGNED_INT, GL_INT a
GL_FLOAT.
- Ukazatel na oblast operační paměti, do které se mají pixely uložit, se
předává v argumentu table. Paměť musí být předem alokovaná, jinak může
dojít k havárii počítače (nezávisle na OS), protože přenos dat řídí přímo
grafická karta!
Všimněte si, že při čtení barvové palety není nutné zadávat počet položek v
paletě ani interní formát barvové palety, protože obě vlastnosti jsou uloženy
spolu s barvovou paletou v paměti grafického akcelerátoru.
Povolení a zákaz použití barvové palety
Pro povolení použití barvové palety je nutné jednoduše zavolat funkci
glEnable() s parametry:
glEnable(GL_COLOR_TABLE);
glEnable(GL_POST_CONVOLUTION_COLOR_TABLE); nebo
glEnable(GL_POST_COLOR_MATRIX_COLOR_TABLE);
Podobně jako povolení barvové palety, i její zákaz lze provést velmi
jednoduše. Stačí provést jeden z následujících příkazů:
glDisable(GL_COLOR_TABLE);
glDisable(GL_POST_CONVOLUTION_COLOR_TABLE); nebo
glDisable(GL_POST_COLOR_MATRIX_COLOR_TABLE);
Překlad a spuštění demonstračních příkladů
Na mnoha systémech pravděpodobně nepůjdou dnes popsané demonstrační příklady
ani přeložit ani spustit. V těchto příkladech jsou totiž využity funkce Imaging
Subsetu, které nemusí být podporovány - bližší informace jsou uvedeny v
úvodních částech tohoto seriálu.
Pro překlad je nutné, aby byly k dispozici upravené hlavičkové soubory
knihovny OpenGL a aby byl dostupný i příslušný soubor pro linker. Pro spuštění
je nutné, aby byla přítomna dynamická knihovna OpenGL s podporou Imaging
Subsetu - statická verze se téměř nepoužívá, protože by velikost výsledného
spustitelného souboru vzrostla až o několik set kilobytů.
Pravděpodobně nejjednodušším postupem pro testování Imaging Subsetu je
instalace knihovny Mesa. Ke knihovně Mesa
se dodávají i nové hlavičkové soubory gl.h apod., kterými lze nahradit
soubory stávající.
V Unixových systémech je překlad a instalace této knihovny velmi jednoduchá,
stačí použít připravený soubor Makefile. Pro některé systémy, například
Solaris, lze stáhnout i přeloženou verzi knihovny spolu s hlavičkovými
soubory.
V systémech Microsoft Windows lze použít buď připravené makefile soubory pro
překladač MinGW, ale z mých zkušeností plyne, že se někdy nemusí překlad
podařit díky špatně nastaveným cestám v souboru makefile.mgw, proto je
nutné tento soubor ručně projít a upravit.
Se zdrojovými kódy knihovny Mesa je dodáván i projektový soubor pro
Microsoft Visual Studio 6.0. V tomto projektovém souboru je i odkaz na knihovnu
GLUT, takže se při otevírání
projektu hledají neznámé soubory. Hledání je však možné stornovat a výsledný
projekt se přeloží bez problémů. Výsledkem překladu jsou dynamické knihovny
glu32.dll, opengl32.dll a osmesa32.dll spolu s
verzemi pro linker, které je možné použít pro překlad demonstračních
aplikací.
Pokračování
V následující části tohoto seriálu si popíšeme zpusob nastavení parametrů,
které ovlivňují naplnění barvové palety. Dále budou popsány operace pro
zjištění těchto parametrů, změnu barvové palety, načtení barvové palety přímo z
framebufferu a změnu části barvové palety.
Seznam funkcí zmíněných v této části
glDrawPixels()
glReadPixels()
glEnable()
glDisable()
Nové funkce popsané v této části
glColorTable()
glGetColorTable()
Demonstrační příklady
V prvním příkladu, který zobrazuje obrázek Leny pomocí funkce
glDrawPixels(), je použita barvová paleta pro inverzi jedné barvové
složky.
Zdrojový kód prvního demonstračního příkladu je dostupný
zde, HTML verze se zvýrazněním syntaxe
zde.
Obrázek 2: Screenshot prvního demonstračního příkladu
Ve druhém demonstračním příkladu, je barvová paleta použita pro inverzi
všech barev - výsledkem je tedy barevný negativ původního obrázku.
Zdrojový kód druhého demonstračního příkladu je dostupný
zde, HTML verze se zvýrazněním syntaxe
zde.
Obrázek 3: Screenshot druhého demonstračního příkladu
Pro spuštění demonstračních příkladů je nutné mít stažený i původní obrázek
Leny.
Zkomprimovaná verze článku
Zkomprimovaná verze tohoto článku spolu s demonstračními příklady a obrázky
je umístěna zde.
Autor: Pavel Tišnovský 2004