Lekce 43 - FreeType Fonty v OpenGL

Tak tu je rýchly tutoriál, ktorý vám ukáže, ako používať FreeType Font rendering library v OpenGL. Použitím knižnice FreeType môžeme vytvoriť anti-aliasovaný text, ktorý vyzerá lepšie ako text vytvorený použitím bitmáp (lekcia 13). Náš text bude mať aj iné výhody - môžeme ho ľahko rotovať a tiež dobre spolupracuje s OpenGL vyberacími (picking) funkciami.

Verze v češtině...

Motivácia: Tu je ukážka toho istého textu vytvoreného pomocou WGL bitmap a vykresleného pomocou FreeType (oba Arial Black Kurzíva):

FreeType font a WGL font

Základný problém s použitím bitmapových fontov je, že OpenGL bitmapy sú binárne obrázky. To znamená, že OpenGL si pamätá len 1 bit na 1 pixel. Ak zoomujete na text tvorený pomocou WGL, výsledok vyzerá asi takto:

Zvětšený WGL font

Pretože bitmapy sú binárne obrázky, nie sú okolo nich šedé pixely a to znamená, že vyzerajú horšie. Našťastie je veľmi jednoduché vytvoriť dobre vyzerajúce fonty pomocou GNU FreeType knižnice. Túto knižnicu používa aj Blizzard vo svojich hrách, takže to musí byť dobré :-))) Tu je priblížený text, ktorý bol vytvorený s pomocou knižnice FreeType:

Zvětšený FreeType font

Ako môžeme vidieť, okolo hrán sa nachádza kopec šedých pixelov, čo je typické pre anti-aliasované (vyhlazené) fonty. Šedé pixely skrášľujú font, pri pohľade z diaľky.

Najprv si siahnite knižnicu GNU FreeType z http://gnuwin32.sourceforge.net/packages/freetype.htm. Stiahnite si binárky a vývojárske súbory. Keď to nainštalujete, určite si všimnite licenčné podmienky - hovorí sa tam, že ak použijete FreeType vo vlastných programoch, musíte uviesť ich kredit niekde vo vašej dokumentácii.

Teraz treba nastaviť MSVC, aby vedelo používať FreeType. V menu Project - Settings - Link sa uistite, že ste pridali libfreetype.lib do Object/libraries spolu s opengl32.lib, glaux.lib a glu32.lib (ak je to potrebné).

Ďalej potrebujeme v Tools - Options - Directories pridať adresáre knižnice FreeType. Pod Show Directories for vyberieme Include Files, dvojklik na prázdny riadok na spodku zoznamu, objaví sa ... tlačítko, ktoré použijeme pre vybratie adresára. Takto pridáme:

C:\PROGRAM FILES\GNUWIN32\INCLUDE\FREETYPE32

a

C:\PROGRAM FILES\GNUWIN\INCLUDE

Teraz pod Show Directories For vyberieme Library Files a pridáme

C:\PROGRAM FILES\GNUWIN32\LIB

Na tomto mieste by sme už mali byť schopní kompilovať programy používajúce FreeType, aj keď nepôjdu bez freetype-6.dll. Kópiu tohto súboru máme v GNUWIN32\BIN a umiestnime ho aj do adresára, kam všetky programy vidia (napr. C:\PROGRAM FILES\MICROSOFT\VISUAL STUDIO\VC98\BIN alebo do C:\WINDOWS\SYSTEM, pre WIN9x alebo C:\WINNT\SYSTEM32 pre WIN NT/2000/XP). Pamätajte, freetype-6.dll musíte priložiť ku každému programu čo vytvoríte.

Ok, teraz už konečne môžeme začať programovať. Za základ programu zoberieme Lekciu 13. Takže si skopírujte lesson13.cpp do vášho adresára a pridajte ho do projektu. Pridajte aj skopírujte dva nové súbory freetype.cpp a freetype.h. Do týchto súborov budeme pridávať všetok FreeTypový kód. Trochu modifikujeme kód lekcie 13 aby sme si ukázali čo sme napísali. Keď skončíme, budemem mať malú jednoduchú OpenGL FreeType knižnicu, ktorú môžete použiť aj v iných OpenGL projektoch.

Začneme s freetype.h. Samozrejme, treba pridať hlavičky FreeType a OpenGL. Tiež pridáme zopár užitočných častí z Standard Template Library (STL), vrátane STL exception classes, ktoré nám zjednodušia vytváranie pekných debugovacich správ.

#ifndef FREE_NEHE_H

#define FREE_NEHE_H

// FreeType hlavicky

#include <ft2build.h>

#include <freetype/freetype.h>

#include <freetype/ftglyph.h>

#include <freetype/ftoutln.h>

#include <freetype/fttrigon.h>

// OpenGL hlavicky

#include <windows.h>

#include <GL/gl.h>

#include <GL/glu.h>

// STL hlavicky

#include <vector>

#include <string>

// Pouzitie STL zvysuje sance, ze niekto iny, kto pouziva nas kod uspesne zachyti vsetky vynimky, co mu posleme

#include <stdexcept>

// MSVC vypluje vsetky druhy zbytocnych varovani ak vytvorime vektory retazcov, tato pragma tomu zabrani

#pragma warning(disable: 4786)

Všetky informácie, ktoré každý font potrebuje dáme do jednej štruktúry (toto uľahčí prácu z viacerými písmami). Ako sme sa naučili v lekcii 13, keď WGL vytvára font, generuje sadu postupných display listov. Toto je šikovné, lebo to znamená, že môžete použiť glCallLists na vypísanie reťazca znakov iba jedným príkazom. Keď vytvoríme naše písmo, nastavíme veci vždy tak isto, čo znamená, že pole list_base si zapamätá prvých 128 postupných display listov. Keďže sa chystáme používať textúry, tiež si potrebujeme uložiť 128 textúr. Posledné čo nám treba je výška fontu, ktorý sme vytvorili v pixeloch (toto nám umožní handlovať nové riadky v našej print funkcii).

// Dame vsetko do namespacu, tak mozme pouzit nazov funkcie ako print bez toho, aby sme sa bali ci uz taka niekde v kode nie je

namespace freetype

{

using std::vector;// Vnurti tohto Namespacu, si umoznime pisat len vector namiesto std::vector

using std::string;// To iste pre String

struct font_data// Toto uchovava vsetky informacie spojene s hocijakym FreeType fontom, ktory chceme vytvorit

{

float h;// Uchovava vysku fontu

GLuint* textures;// ID textur

GLuint list_base;// ID prveho display listu

void init(const char * fname, unsigned int h);// Init funkcia vytvori pismo s vyskou h zo suboru fname

void clean();// Uvolnenie vsetkcy prostriedkov spojenych s fontom

};

Posledná vec, ktorú potrebujeme je prototyp pre našu print funkciu.

// Vlajkova funkcia kniznice - tato nam vykresli nas text na suradniciach X, Y

// Pouzitim ft_font sucastna Modelview Matica bude tiez aplikovana na text

void print(const font_data &ft_font, float x, float y, const char *fmt, ...) ;

}

#endif

A to je koniec hlavičkového súboru freetype.h. Nastal čas otvoriť freetype.cpp.

#include "freetype.h"// Zahrňme náš súbor freetype.h

namespace freetype

{

Na vykreslenie každého znaku použijeme textúru. OpenGL textúry potrebujú mať rozmery ktoré sú mocninami 2, takže potrebujeme aby bitmapy vytvorené FreeTypom mali povolenú veľkosť. Na to potrebujeme túto funkciu:

// Tato funkcia vrati prvu mocninu 2 vacsiu alebo rovnu ako cele cislo, ktore jej dame ako parameter

inline int next_p2(int a)

{

int rval = 1;

while(rval < a)

{

rval <<= 1;// Krajsi sposob ako pisat rval *= 2

}

return rval;

}

Ďalšia funkcia, ktorú budeme potrebovať je make_dlist(). Je to naozaj srdce tohoto kódu. Parameter je FT_Face, je to objekt, ktorý FreeType používa na uchovanie informácii o fonte a vytvára display list podľa toho, aký znak je pošleme.

void make_dlist(FT_Face face, char ch, GLuint list_base, GLuint * tex_base)// Vytvorme display list pre dany znak

{

// Prva vec, ktoru urobime je ze povieme FreeTypu aby vykrelil nas znak do bitmapy. Na to treba zopar FreeTypovych prikazov

if(FT_Load_Glyph(face, FT_Get_Char_Index(face, ch), FT_LOAD_DEFAULT))// Nacitaj glyph pre nas znak

{

throw std::runtime_error("FT_Load_Glyph failed");

}

FT_Glyph glyph;

if(FT_Get_Glyph(face->glyph, &glyph))// Presun glyph do glyph objektu

{

throw std::runtime_error("FT_Get_Glyph failed");

}

FT_Glyph_To_Bitmap(&glyph, ft_render_mode_normal, 0, 1);// Konvertuj glyph na bitmapu

FT_BitmapGlyph bitmap_glyph = (FT_BitmapGlyph)glyph;

FT_Bitmap& bitmap = bitmap_glyph->bitmap;// Tota reference nam ulahci pristup k bitmape:

Teraz, keď už máme bitmapu vytvorenú pomocou FreeType, potrebujeme ju vyplniť prázdnymi pixelmi aby umožnili jej použitie v OpenGL. Je dôležité pamätať si, že kým OpenGL používa pojem bitmapy ako binárne obrázky, vo FreeType bitmapy uchovávajú 8 bitov informácií na pixel (256 možností), takže bitmapy FreeTypu môžu obsahovať aj šedé farby aby vytvorili anti-aliasovaný text.

// Pouzime nasu Helper funkciu aby sme dostali sirky bitmap, ktore budeme potrebovat na vytvorenie nasej textury

int width = next_p2(bitmap.width);

int height = next_p2(bitmap.rows);

// Alokujme pamat na texturu

GLubyte* expanded_data = new GLubyte[2 * width * height];

// Tu naplnime data pre bitmapu.

// Vsimnite si, ze pouzivame dvojkanalovu bitmapu

// 1 kanal pre ziarivost a druhy ako alfa kanal

// Ale priradime oba kanaly hodnote, ktoru najdeme vo FreeType bitmape

// Pouzijeme ?: operator aby sme povedali ktora hodnota ma byt 0

// ak sme v prazdnej zone a 1 ak sme v FreeType bimape

for(int j=0; j <height;j++)

{

for(int i=0; i < width; i++)

{

expanded_data[2 * (i + j*width)] = expanded_data[2 * (i + j*width) + 1] = (i >= bitmap.width || j >= bitmap.rows) ? 0 : bitmap.buffer[i + bitmap.width*j];

}

}

Keď sme hotoví, môžeme sa pustiť do vytvárania OpenGL textúry. Zahŕňame alfa kanál, takže čierne časti bitmapy budú priehľadné a okraje textu budú plynulo priesvitné (preto by mali vyzerať správne na akomkoľvek podklade).

// Teraz len nastavime parametre textury

glBindTexture(GL_TEXTURE_2D, tex_base[ch]);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

// Tu vytvarame samotnu texturu, vsimnite si, ze pouzivame GL_LUMINANCE_ALPHA aby sme vyjadrili, ze pouzivame data 2 kanalov

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, expanded_data);

delete [] expanded_data;// Ked mame texturu vytvorenu, nepotrebujeme uz Expanded Data

Na vykreslenie nášho textu používame štvoruholníky s textúrami. To znamená, že bude jednoduché otáčať a zväčšovať/zmenšovať text a text bude dediť farbu z aktuálnej OpenGL farby (čo by tak nebolo, ak by sme používali pixmapy).

glNewList(list_base + ch, GL_COMPILE);// Teraz vytvorime Display List

glBindTexture(GL_TEXTURE_2D,tex_base[ch]);

// Najprv potrebujeme pohnut kameru trosku nahor tak, ze znak bude mat dost miesta medzi nim, a tym pred nim

glTranslatef(bitmap_glyph->left,0,0);

// Teraz sa presunieme o kusok dole pre pripad ze bitmapa presahuje cez spodok

// Toto plati len pre znaky ako 'g' alebo 'y' a pod.

glPushMatrix();

glTranslatef(0,bitmap_glyph->top-bitmap.rows,0);

// Teraz musime ratat s faktom, ze vela z nasich textur je vyplnenych prazdnym miestom.

// Vyjadrime aka cast textury je pouzivana aktualnym znakom

// a ulozime tu informaciu do premennych x a y, potom vykreslime

// stvorec, budeme ukazovat len na tie casti textury, ktore

// znak sam obsahuje.

float x = (float)bitmap.width / (float)width;

float y = (float)bitmap.rows / (float)height;

// Tu vykreslime otexturovane stvoruholniky.

// Bitmapa, ktoru sme ziskali z FreeTypu nebola

// orientovana celkom tak, ako sme chceli, takze

// dame texturu na stvoruholnik tak, aby bol

// vysledok umiestneny spravne.

glBegin(GL_QUADS);

glTexCoord2d(0,0); glVertex2f(0,bitmap.rows);

glTexCoord2d(0,y); glVertex2f(0,0);

glTexCoord2d(x,y); glVertex2f(bitmap.width,0);

glTexCoord2d(x,0); glVertex2f(bitmap.width,bitmap.rows);

glEnd();

glPopMatrix();

glTranslatef(face->glyph->advance.x >> 6 ,0,0);

// Inkrementujeme poziciu rastra akoby sme pracovali s bitmapovym fontom.

// Potrebne len ak chcete vyratat dlzku textu.

// glBitmap(0, 0, 0, 0, face->glyph->advance.x >> 6, 0, NULL);

glEndList();// Ukoncime display list

}

Ďalšia funkcia, ktorú ideme vytvoriť bude používať make_dlist na vytvorenie množiny display listov korešpondujúcich k danému súboru s fontom a výške v pixeloch.

FreeType používa truetype fonty, takže budete potrebovať nejaké súbory s truetype písmami ako parametre tejto funkcie (súbory .ttf). Truetypové písma sú veľmi bežné a je kopec stránok, kde si ich môžete stiahnuť. Aj Windows používa ttf ako väčšinu písiem, takže môžete použiť aj tieto z adresára windows/fonts.

void font_data::init(const char * fname, unsigned int h)

{

textures = new GLuint[128];// Alokujme pamat pre uchovanie ID cisel textur

this->h = h;

// Vytvorime a inicializujeme kniznicu FreeType

FT_Library library;

if (FT_Init_FreeType(&library))

{

throw std::runtime_error("FT_Init_FreeType failed");

}

// Objekt, v ktorom uchovavame FreeType informacie pre dany font sa vola face

FT_Face face;

// Tu nacitavame informacie fontu zo suboru.

// Spomedzi roznych miest kodu, najcastejsie tu sa zasekuje,

// lebo FT_New_Face spadne ak subor s fontom neexistuje alebo je chybny.

if (FT_New_Face(library, fname, 0, &face))

{

throw std::runtime_error("FT_New_Face failed (there is probably a problem with your font file)");

}

// Pre nejaky nevysvetlitelny dovod, FreeType meria velkost pisma

// v 1/64-nach pixelov. Preto, aby sme mali font vyskoky h pixelov,

// musime davat velkost h * 64.

// (h << 6 je len krajsi sposob pisania h*64)

FT_Set_Char_Size(face, h << 6, h << 6, 96, 96);

// Tu poziadame OpenGL o alokacie prostriedkov pre vsetky nase textury a display listy, ktore chceme vytvorit.

list_base = glGenLists(128);

glGenTextures(128, textures);

for(unsigned char i = 0; i < 128; i++)//Tu vytvarame kazdy z display listov

{

make_dlist(face, i, list_base, textures);

}

// Nepotrebujeme face informacie, pretoze display list uz bol vytvoreny, tak uvolnime pridruzene prostriedky.

FT_Done_Face(face);

FT_Done_FreeType(library);// To iste pre Font Library.

}

Teraz potrebujeme funkciu na vyčistenie všetkých display listov a textúr spojených s fontom.

void font_data::clean()

{

glDeleteLists(list_base, 128);

glDeleteTextures(128, textures);

delete [] textures;

}

Tu sú dve malé funkcie, ktoré definujme v očakávaní našej print funkcie. Funkcia print bude chcieť myslieť v pixelových súradniciach (tiež nazývané window coordinates), takže budeme potrebovať prepnúť do projekčnej matice, ktorá spôsobí že všetko bude merané v oknových súradniciach (od ľavého horného rohu).

Použijeme dve veľmi užitočné funkcie, glGet() na získanie rozmerov okna a glPushAttrib / glPopAttrib na uistenie sa, že sme nechali maticu v pôvodnom stave, ako sme ju našli. Ak tieto funkcie nepoznáte, je pravdepodobne vhodné vyhľadať si ich vo vašej obľúbenom OpenGL manuály.

// Dost samovystizna funkcia, ktora potlaci projekcnu maticu,

// ktora urobi object world suradnice identickymi s suradnicami okna.

inline void pushScreenCoordinateMatrix()

{

glPushAttrib(GL_TRANSFORM_BIT);

GLint viewport[4];

glGetIntegerv(GL_VIEWPORT, viewport);

glMatrixMode(GL_PROJECTION);

glPushMatrix();

glLoadIdentity();

gluOrtho2D(viewport[0],viewport[2],viewport[1],viewport[3]);

glPopAttrib();

}

// Uvolni projekcnu maticu bez zmeny aktualneho MatrixModu

inline void pop_projection_matrix()

{

glPushAttrib(GL_TRANSFORM_BIT);

glMatrixMode(GL_PROJECTION);

glPopMatrix();

glPopAttrib();

}

Naša funkcia print vyzerá veľmi podobne ako tá z lekcie 13, ale je tu zopár dôležitých výnimiek. OpenGL umožňujúce príznaky (flags), ktoré nastavujeme sú iné, čo sa odrazí vo fakte, že používame 2 kanálové textúry namiesto bitmáp. Tiež urobíme trochu extra spracovania na riadku textu aby sme správne zvládli nové riadky. Použijeme OpenGL matíce a attribute háldy (stacks) aby sme sa uistili, že funkcia napraví všetky zmeny, ktoré robí do interného stavu OpenGL (toto zabráni tomu, aby ktokoľvek použil funkciu a zrazu zistil, že sa ModelView matica záhadne zmenila).

// Skoro ako NeHe glPrint funckcia, ale modifikovana, aby pracovala s freetype fontmi

void print(const font_data &ft_font, float x, float y, const char *fmt, ...)

{

// Chceme system suradnic, kde je je vzdialenost merana v pixeloch

pushScreenCoordinateMatrix();

GLuint font = ft_font.list_base;

float h = ft_font.h / 0.63f;// Trochu zvacsime výšku, aby bola medzera medzi riadkami

chartext[256];// Nas retazec

va_listap;// Ukazatel na nas zoznam argumentov

if (fmt == NULL)// Ak nemame ziadny text

{

*text = 0;// Nerobme nic

}

else

{

va_start(ap, fmt);// Rozoberia retazec na premenne

vsprintf(text, fmt, ap);// A konevrtuje symboly na cisla

va_end(ap);// Vysledky sa ulozia do text

}

// Tento kod rozdeli dany text text na sadu riadkov.

// Toto by sa dalo spravit ak milsia pomocou knižnice regulárnych výrazov,

// dostupnych napr. na boost.org.

const char *start_line = text;

vector<string> lines;

for(const char *c = text; *c; c++)

{

if(*c == '\n')

{

string line;

for(const char *n = start_line; n < c; n++)

{

line.append(1, *n);

}

lines.push_back(line);

start_line = c + 1;

}

}

if(start_line)

{

string line;

for(const char *n = start_line; n < c; n++)

{

line.append(1, *n);

}

lines.push_back(line);

}

glPushAttrib(GL_LIST_BIT | GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TRANSFORM_BIT);

glMatrixMode(GL_MODELVIEW);

glDisable(GL_LIGHTING);

glEnable(GL_TEXTURE_2D);

glDisable(GL_DEPTH_TEST);

glEnable(GL_BLEND);

glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glListBase(font);

Pretože používame otexturované štvoruholníky, všetky transformácie, ktoré urobíme do ModelView matice pred volaním glCallLists sa prejavia na texte samotnom. To znamená, že je možnosť rotovať, alebo meniť veľkosť textu (ďalšia výhoda WGL bitmáp). Najprirodzenejší spôsob ako to využiť by bolo nechať aktuálnu maticu samotnú, teda urobiť všetky transformácie pred použitím print funkcie. Ale kvôli spôsobu akým používame maticu ModelView na nastavenie pozície textu, toto nepôjde. Naša ďalšia možnosť je uložiť si kópiu matice a aplikovať je medzi glTranslate a glCallLists. Toto je dosť jednoduché, ale pretože potrebujeme vykresľovať text používajúc špeciálnu projekčnú maticu, efekty modelview matice by boli trochu iné ako by sa dalo predpokladať - všetko by bolo interpretované vo veľkosti pixelov. Cez toto by sme sa mohli dostať resetovaním projekčnej matice vnútri funkcie print. To je asi dobrý nápad - ale ak sa o to pokúsite, určite scalujte fonty na požadovanú veľkosť (snažia sa byť 32x32, ale vy asi potrebujete niečo okolo 0.01x0.01).

float modelview_matrix[16];

glGetFloatv(GL_MODELVIEW_MATRIX, modelview_matrix);

// Tu sa vlastne deje zobrazovanie textu.

// Pre kazdy riadok textu resetneme maticu modelview aby

// text zacal na spravnej pozicii.

// Vsimnite si, ze potrebuejeme resetnut maticu, radsej ako ju

// len posuvat dole o h. To preto, lebo ked kazdy znak je nakresleny,

// modifikuje aktualnu maticu aby dalsi znak bol vykresleny hned za nim.

for(int i = 0; i < lines.size(); i++)

{

glPushMatrix();

glLoadIdentity();

glTranslatef(x, y - h*i, 0);

glMultMatrixf(modelview_matrix);

// Vypoznamkovane veci ohladom Raster pozicie by mohli byt uzitocne ak by ste potrebovali vediet dlzku textu, ktory vytvarate.

// Ak sa rozhodnete pouzit to, ujistite sa ze tiez odpoznamkujete aj prikaz glBitmap v make_dlist().

// glRasterPos2f(0,0);

glCallLists(lines[i].length(), GL_UNSIGNED_BYTE, lines[i].c_str());

// float rpos[4];

// glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);

// float len = x - rpos[0];

glPopMatrix();

}

glPopAttrib();

pop_projection_matrix();

}

}// Ukoncime Namespace

Knižnica je teraz hotová. Otvorme teraz lesson13.cpp a urobíme tam zopár malých zmien aby sme mohli použiť funkcie, ktoré sme práve napísali. Pod ostatnými hlavičkami, pridajte freetype.h.

#include "freetype.h"// Hlavicka pre nasu kniznicu

A kým sme tu, vytvorme globálny objekt font_data.

freetype::font_data our_font;// Toto uchováva všetky informácie pre font, ktorý ideme vytvoriť

Teraz potrebuejme vedieť ako vytvoriť a zničiť prostriedky nášho fontu. Takže pridajte nasledujúci riadok na koniec InitGL.

// InitGL()

our_font.init("test.TTF", 16); //Build the freetype font

A pridajte tento riadok na začiatok KillGLWindow aby sa odstránil font, keď program skončil.

// KillGLWindow()

our_font.clean();

Teraz musíme zmeniť funkcie DrawGLScene, aby používala našu print funkciu. Toto by mohlo byť dosť ale sťažíme si to kreatívnejším postupom aby sme mohli font rotovať a meniť jeho veľkosť.

int DrawGLScene(GLvoid)// Tu vsetko vykreslujeme

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Vycistime zasobniky

glLoadIdentity();// Resetnime aktualnu maticu ModelView

glTranslatef(0.0f, 0.0f, -1.0f);// Pohnime sa 1 jednotku do obrazovky

glColor3ub(0, 0, 0xff);// Modrý text

// Umiestnime WGL Text na obrazovku

glRasterPos2f(-0.40f, 0.35f);

glPrint("Active WGL Bitmap Text With NeHe - %7.2f", cnt1);// Vykreslime text do sceny

// Tu vykreslime nejaky text pomocou FreeTypu.

// Jediny dolezity prikaz je Print(), ale aby sme vysledky trochu

// zatraktivnlili, pridali sme kod na tocenie a scalovanie textu.

glColor3ub(0xff,0,0);// Cerveny Text

glPushMatrix();

glLoadIdentity();

glRotatef(cnt1,0,0,1);

glScalef(1,.8+.3*cos(cnt1/5),1);

glTranslatef(-180,0,0);

freetype::print(our_font, 320, 240, "Active FreeType Text - %7.2f", cnt1);

glPopMatrix();

// Odstrante tuto poznamu ak chcete vyskusat schopnost funkcie print zvladnut nove riadky

// freetype::print(our_font, 320, 200, "Here\nthere\nbe\n\nnewlines\n.", cnt1);

cnt1 += 0.051f;// Zvysme prve pocitadlo

cnt2 += 0.005f;// Zvysme druhe pocitadlo

return TRUE;// Vsetko prebehlo OK

}

Posledná vec, ktorú treba urobiť, je pridať kód na handlovanie výnimiek. Choďte do WinMain a vyhľadajte odstavec try { .. } na začiatku funkcie.

// WinMain()

MSG msg;// Windows Message Structure

BOOL done = FALSE;// Bool Variable To Exit Loop

try// Use exception handling

{

Potom modifikujte koniec funkcie aby sme mali prikaz catch { }.

KillGLWindow();// Zruš okno

}

catch (std::exception &e)// Chyt vsetky dane vyjimky

{

MessageBox(NULL, e.what(), "CAUGHT AN EXCEPTION", MB_OK | MB_ICONINFORMATION);

}

Tak a teraz ak natrafíme na výnimku, dostaneme message box hovoriaci čo sa stalo. Pozor, tento kód môže spomaliť váš program, takže keď kompilujete konečnú verziu vášho programu, možno sa vám bude hodiť vypnúť exception handling v Project->Settings->C/C++, "C++ Language".

A to je ono! Skompilujte program a mali by ste vidieť pekný FreeType renderovaný text pohybujúci sa okolo originálneho bitmapového textu z lekcie 13.

Zopár odkazov na záver:

napsal: Sven Olsen <sven (zavináč) sccs.swarthmore.edu>
do slovenštiny přeložil: Pavel Hradský - PcMaster<pcmaster (zavináč) stonline.sk>
do češtiny přeložil: Michal Turek - Woq <WOQ (zavináč) seznam.cz>

Pozn.: Prosím ospravedlote všetky chyby v tomto článku, je to môj prvý preklad. Dúfam, že vám pomohol, ak máte nejaké problémy s porozumením, alebo ste natrafili na závažnú chybu, kontaktujte prosím mňa, alebo autora tohto webu.

Zdrojové kódy

Lekce 43

<<< Lekce 42 | Lekce 44 >>>