OpenGL - 8. díl - 3D Font, JPEG textury - Builder.cz - Informacni server o programovani

Odběr fotomagazínu

Fotografický magazín "iZIN IDIF" každý týden ve Vašem e-mailu.
Co nového ve světě fotografie!

 

Zadejte Vaši e-mailovou adresu:

Kamarád fotí rád?

Přihlas ho k odběru fotomagazínu!

 

Zadejte e-mailovou adresu kamaráda:



C/C++

OpenGL - 8. díl - 3D Font, JPEG textury

open gl

5. března 2002, 00.00 | V dnešním díle seriálu se opět vrátíme k písmu. Tentokrát budeme psát trojrozměrným písmem, a aby toho nebylo málo, potáhneme si jej texturou z JPEG obrázku. Článek navazuje na 6. díl, kde jsme se zabývali 2D písmem.

V dnešním díle seriálu se opět vrátíme k písmu. Tentokrát budeme psát trojrozměrným písmem, a aby toho nebylo málo, potáhneme si jej texturou z JPEG obrázku. Článek navazuje na 6. díl, kde jsme se zabývali 2D písmem.

Dříve než začnu popisovat 3D psaní, musím si vám trochu postěžovat na svůj C++ Builder a také na svou nepozornost. Když se vrátím k předchozím dílům tohoto seriálu vloudilo se mi do příkladů pár drobných chybek, kterých je těžké si na první problém všimnout. První chybka se mi povedla, když jsem jako časovač použil komponentu DelphiX - DXTimer a po té co jsem ji smazal z formuláře, zůstal v kódu nepříjemný řádek

#pragma link "DXClass"

který samozřejmě vyvolá chybu u překladače, kde nejsou komponenty DelphiX nainstalovány.

Druhý problém zavinil sám C++ Builder, který do každého projektu (makefile) vkládá informace o použitých knihovnách (lib a packages). A poměrně hojně se mi do projektu v poslední době přimíchávají packages (nepoužité, navíc ještě doinstalované). A při překladu na překladači, kde tyto komponenty nejsou, Builder ohlásí chybu. Řešení jsou dvě. To méně příjemné řešení je chirurgickou cestou odstranit nepotřebné knihovny a packages z projektu (souboru bpr) pomocí poznámkového bloku a to tak, že editujete řádky LIBRARIES, SPARELIBS, PACKAGES. Druhá možnost je, že v menu Project/Options... zaškrtnete volbu Packages / Build with runtime packages. Odstraníte nevhodné balíčky a znovu toto poličko vyrušíte. Nevhodné balíčky zmizí z projektu a vše je v pořádku.

 

V OpenGL máme možnost kromě obyčejného dvojrozměrného písma využívat trojrozměrné písmo. Princip je velmi podobný tomu, který jsme si popisovali v 6 díle.

Nejprve si musíme vytvořit celou znakovou sadu 3D fontu, k tomu nám podobně jako minule poslouží funkce BuildFont, kterou si sami napíšeme. Tato funkce nám vytvoří 256 znaků a každý bude uložen do display listu. Funkce glGenLists(256) nám najde 256 volných display listů jdoucích po sobě. API Funkce CreateFont vytvoří font a vrátí jeho ID (typu HFONT). A mi z tohoto vytvořeného fontu uděláme tzv. Outline font - 3D znaky. K tomu nám výborně poslouží funkce

BOOL wglUseFontOutlines(HDC hdc, DWORD first, DWORD count, DWORD listBase, FLOAT deviation, FLOAT extrusion, int format,
LPGLYPHMETRICSFLOAT lpgmf );

hdc - zařízení, kde budeme 3D font používat (Form1->hDC)
first - index prvního znaku
count - délka tabulky znaků
listbase - index prvního displaylistu ..... viz proměnná base (popsáno v 6.díle)
extrusion - zanoření písma do 3d (do osy z)
format - dvě možnosti WGL_FONT_LINES a WGL_FONT_POLYGONS; první znamená ,že modely písma budou z čar, druhá znamená - modely písmen budou z ploch (polygonů)
lpgmf - odkaz na strukturu GLYPHMETRICSFLOAT, zde se uloží informace o jednotlivých znacích - umístění a orientace znaků

Další změnou oproti 2D psaní písma je právě využití GLYPHMETRICSFLOAT pro výpočet šířky jednotlivých znaků a jejich správné umístění. Pozmění námi napsanou funkci glPrint (opět víz 6. díl). Algoritmus se liší pouze ve výpočtu šířky textu, zde je to
length+=gmf[text[loop]].gmfCellIncX;

Do programu jsem přidal pro příznivce VCL komponenty Panel, Edit a 2x UpDown, aby bylo jasně, jak jde poměrně dobře VCL kombinovat s OpneGL. Výřez OpenGL je menší než je velikost formuláře.

gldAspect = (double) (ClientWidth)/ (double) (ClientHeight-Panel1->Height);

. . . . .
- při výpočtu poměru výšky a šířky OpenGL okna musíme uvažovat navíc i výšku panelu. Ale to není všechno, gl Viewport je rovněž menší než celé okno.
. . . . .

glViewport(0, 0, ClientWidth, ClientHeight-Panel1->Height);

Všechno ostatní je stejné jako v díle 6.
Příklad je ke stažení ZDE (240KB).

3D Font s JPEG texturou

Aby tento článek nebyl tak suchý, pokusím se vám popsat jiný způsob načítání textur. Bude více orientovaný na možnosti VCL. A jelikož ve VCL máme i třídu TJPEGImage, vyzkoušíme, jak se používají JPG textury.

Pro načtení textury potřebujeme znát jeho velikost. Já si ji uložím do proměnných vyska a sirka (ale není to nezbytně nutné, jde to i jinak). Dále budeme potřebovat ukazatel na bitmapu, kterou vycucneme z JPEG obrázku. Ukazatel bude typu BYTE, protože potřebujeme pouze surové obrazové data.

TColor Barva;
TJPEGImage *Obr;
Obr = new TJPEGImage();
Obr->LoadFromFile("lights.jpg");
sirka = Obr->Bitmap->Width;
vyska = Obr->Bitmap->Height;
textura1 = new BYTE[3*Obr->Bitmap->Width*Obr->Bitmap->Height];
for (int y = 0; y < Obr->Bitmap->Height; y++) {
 for (int x = 0; x < Obr->Bitmap->Width; x++) {
 Barva = Obr->Bitmap->Canvas->Pixels[x][y];
  // z vlastnosti Pixels přečteme všechny barvy bodů a rozložíme na složky
 *(textura1+3*(Obr->Bitmap->Height-y-1)*Obr->Bitmap->Height+3*x) = 
        GetRValue(Barva);
 *(textura1+3*(Obr->Bitmap->Height-y-1)*Obr->Bitmap->Height+3*x+1) = 
        GetGValue(Barva);
 *(textura1+3*(Obr->Bitmap->Height-y-1)*Obr->Bitmap->Height+3*x+2) = 
        GetBValue(Barva);
 }
}

Uznávám, že uvedený algoritmus nepatří zrovna k nejrychlejším, protože vlastnost Pixels[][] je pomalá (ale takové už je VCL). Nicméně uvedený algoritmus je velmi jednoduchý a nějaké nepatrné zpoždění při načítání textur nám nevadí, protože jej provádíme při startu programu. Algoritmus načte JPG obrázek do objektu Obr (TJPEGImage), ukazatel textura1 bude ukazovat na obrazové data, a proto dynamicky alokujeme potřebné množství bajtů. Informaci o barvě daného bodu čteme z vlastnosti Pixels[][], vrací se hodnota TColor. A jelikož potřebujeme u každého bodu jednotlivé složky R,G,B s chutí využijeme makra GetRValue(), GetGValue(), GetBValue().

Navíc, aby OpenGL otexturoval napsaný text, musíme učinit potřebné nastavení pro texturování:

glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
glEnable(GL_TEXTURE_GEN_S);
glEnable(GL_TEXTURE_GEN_T);

Toto nastavení vám musím interpretovat vlastními slovy, protože nápovědě jsem příliš neporozuměl. Nastavení glTexGeni na GL_S koordinuje namapování textury na členitý objekt svisle a nastavení glTexGeni na GL_T koordinuje namapování textury na členitý objekt vodorovně. Kombinací obou dvou nastavení dosáhneme kvalitního pokrytí písmen texturami. To je celé.

Výsledek lze stáhnout ZDE (300 KB).

Pro tentokrát je toho dost, nicméně, problematiku fontů a písma jsme ještě nevyčerpali. V některém z příštích dílů se podíváme na tzv. bitmapové písmo.

Podobné příklady, jako v tomto článku najdete na Nehe. Z velké časti jsem se jimi inspiroval.

Obsah seriálu (více o seriálu):

Tématické zařazení:

 » Rubriky  » C/C++  

 

 

 

Nejčtenější články
Nejlépe hodnocené články

 

Přihlášení k mému účtu

Uživatelské jméno:

Heslo: