OpenGL 9. díl - Bitmap Font - 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:

Soutěž

Sponzorem soutěže je:

IDIF

 

Kde se koná výstava fotografií Luďka Vojtěchovského?

V dnešní soutěži hrajeme o:



C/C++

OpenGL 9. díl - Bitmap Font

open gl

29. března 2002, 00.00 | Další díl seriálu o OpenGL je věnován bitmapovým fontům a navazuje na předešlé díly věnované písmu. Vyzkoušíme si také vytvořit jednoduché menu.

V dnešním díle seriálu se ještě vrátíme k písmu. Opět jsem se inspiroval haldou tutoriálů, nejvíce se mi líbil tutoriál na NeHe, který se jmenuje stejně jako tento díl - Bitmap Font. To znamená, že budeme psát písmenky z bitmap. To ale neznamená, že by jsme ukládali každé písmeno do jednoho obrázku. Celou sadu písmen si uložíme do jednoho jpg (bmp) obrázku a načteme jej jako texturu, a že je to velmi užitečná technika, uvidíte sami.

Ještě než začneme, rád bych vám připomenul články na podobné téma z DelphiX (pouze jiné hřiště - OpenGL).

Posuvný text v DelphiX

A první dnešní počin s bitmapovým fontem vidíte na obrázku.

Jak jsem již říkal, potřebujeme mít bitmapu, kde budou nasázené jednotlivé písmenka. A jelikož obrázek bude brát OpenGL jako texturu, musí mít obvyklou velikost (128*128, 256*256 ...). Původně jsem použil font, který byl v příkladu na NeHe, ale ten není košer. Tento font nemá české znaky. Proto jsem si musel udělat vlastní font (a věřte, moc se mi nechtělo, protože je to ukrutná piplačka). Však se podívejte, jak se mi povedl (nepovedl):

Font jsem vytvářel v NeoPaintu, protože se tam pohodlně pracuje s mřížkou. Velikost jednoho znaku je 32x32. Jak se dělá takový bitmapový font se dočtete v článku Václava Krejčího,

Posuvný text v DelphiX

Pojďme se prohrabat jednotlivými algoritmy.

AnsiString FindString = " !\"#$%&'()*+,-. 0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[/]^_´abcdefghijklmnopqrstuvwxyz{|}~ ěščřžýáíéúůĚŠČŽÝÁÍÉÚŮňŇďĎťŤŘ";

Tento řetězec je seznam, všech znaků v bitmapě, tak jak jsou po sobě naskládané. Jak za chvíli uvidíte je velmi důležitý. Dále budeme potřebovat dvě textury, které načteme z jpg souboru (viz minulý díl seriálu).

Jak z načtené textury vytvořit sadu písmen?

GLvoid BuildFont(GLvoid)
 {
 float cx;
 float cy;            

base=glGenLists(256);
for (loop=0; loop<256; loop++)
{
 cx=float(loop%16)/16.0f;
 cy=float(loop/16)/16.0f;
 glNewList(base+loop,GL_COMPILE);
 glBegin(GL_QUADS);
 glTexCoord2f(cx,1-cy-0.0625f);
 glVertex2i(0,0);
 glTexCoord2f(cx+0.0625f,1-cy-0.0625f);
 glVertex2i(16,0);
 glTexCoord2f(cx+0.0625f,1-cy);
 glVertex2i(16,16);
 glTexCoord2f(cx,1-cy);
 glVertex2i(0,16);
 glEnd();
 glTranslated(10,0,0);
 glEndList();
}
}
             

Tento kód jsem s malými úpravami přejal z NeHe a nedělá nic jiného, než že vytváří sadu 256 čtverců, do kterých mapuje části bitmapy tak, aby jsme vytvořili tabulku znaků jdoucích po sobě. Abych objasnil číslo 0.0625 ve výpočtech při mapování části textury, tak je to 1/16. To jest pomyslná šířka jednoho písmene.

GLvoid glPrint(GLint x, GLint y, char *string)
 {
 glBindTexture(GL_TEXTURE_2D, 1);
 glDisable(GL_DEPTH_TEST);
 glMatrixMode(GL_PROJECTION);
 glPushMatrix();
 glLoadIdentity();
 glOrtho(0,640,0,480,-100,100);
 glMatrixMode(GL_MODELVIEW);
 glPushMatrix();
 glLoadIdentity();
 glTranslated(x,y,0);
 glListBase(base);
 for (int i = 0; i < strlen(string); i++)
  glCallList(FindString.Pos(string[i]));
 glMatrixMode(GL_PROJECTION);
 glPopMatrix();
 glMatrixMode(GL_MODELVIEW);
 glPopMatrix();
 glEnable(GL_DEPTH_TEST);
 }
             

Funkce glPrint se stará o vypsání řetězce. glBindTexture aktivuje texturu s písmeny. Voláním glOrtho změníme pohled. Takže noví rozsah v okně OpenGL je v ose X 0 až 640, v ose Y 0 až 480 a v ose Z -100 až 100. To uděláme pro to, aby se nám lépe umisťoval text na obrazovku.

Velice důležité jsou červeně vyznačené řádky, to je vlastní vypsání řetězce. Funguje to asi takto. Nejprve nastavíme bázoví display list, po té procházíme v cyklu řetězec, který se má vypsat. Dále potřebujeme řetězec FindString, kde jsou seřazeny všechny znaky, jak po sobě jdou (v textuře). A v tomto řetězci hledáme postupně pozice jednotlivých znaků. To provádíme přes vlastnost Pos, která vrací pozici znaku v řetězci. Pak už stačí zavolat tento display list a požadovaný znak je na světě. No a vcelku to vypíše celý zadaný řetězec. V tutoriálu na NeHe je jiný algoritmus, ale ten nešlo využít právě kvůli českým znakům.

Nyní nám již ke spokojenosti stačí nastavit správné filtrování textur, a také alfa blending, abychom písmu mohli nastavit libovolnou barvu a průhlednost.

Nyní se podívejte na jednoduchou ukázku ZDE (300 KB).

Sami vidíte, že písmo v akci vypadá dobře a efektně. Pokusme se program ještě trochu vylepšit. Jak bylo vidět v příkladu, v levé části obrazu bylo naznačeno takové droboučké menu. Asi cítíte, kam mířím. Chtělo by nepatrně zvětšit. To bude další náš příklad - menu s vyjíždějícími položkami. Takové menu se velmi často objevovalo ve starších hrách (nebo alespoň tento efekt), tuším že v Half-lifu.

Z toho, co jsem vám popsal výše, není nic jednoduššího. Musíme jen pozměnit algoritmus na vytváření sady písmen. Tabulku písmen, kterou jsme tvořili pomocí funkce BuildFont musíme vylepšit tak, aby funkce vytvořila více sad písmenek v různých velikostech. Potom už jenom stačí vypisovat řetězce v růžných velikostech a zvětšující text je na světě. Podívejme se tedy na změny v programu. Změní se cyklus ve funkci BuildFont:

base=glGenLists(256*pocet_sad);
for (int count = 0; count < pocet_sad; count++) {
for (loop=0; loop<256; loop++)
{
cx=float(loop%16)/16.0f;
cy=float(loop/16)/16.0f;
  glNewList(base+loop+256*count,GL_COMPILE);
    
    . . . . . . . . .
 
  glEndList();
  }
}

Změny jsem vyznačil přehledně červeně. Potřebujeme si vytvořit 256*pocet_sad display listů na písmenka. Přibude jedno vnoření cyklu. A důležité je správně počítat display listy ve funkci glNewList, tak aby se písmenka tvořili pořád dál a nepřepisovalo se opakovaně prvních 256 písmenek.

Funkce glPrint také doznala několika změn, tady jsou:

GLvoid glPrint(GLint x, GLint y, char *string, int sada)
{
. . . . . . . . . . .
glListBase(base);
 for (int i = 0; i < strlen(string); i++)
  glCallList(FindString.Pos(string[i])+sada*256);

  . . . . . . . . . . . . . . 


}
             

Přidáme parametr sada, kterým budeme říkat, kterou sadu písmen (resp. velikost) budeme chtít použít. A ve funkci glCallList stačí přičíst sada*256 a je to. Ve funkci DrawScene, kde se staráme o vykreslení menu zajistíme plynulé zvětšování písma a je už pouze programátorská rachota, tak to ani nebudu uvádět.

Výsledek je k nahlédnutí ZDE (304 KB).

A to je pro dnešek vše. Po tomto článku vám mohu slíbit, že již o fontech a písmech v OpenGL nenapíši ani řádku.

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: