Lekce 14

Lekce 14 - Outline fonty

BitmapovΘ fonty nestaΦφ? Pot°ebujete kontrolovat pozici textu i na ose z? Cht∞li byste fonty s hloubkou? Pokud znφ vaÜe odpov∞∩ ano, pak jsou 3D fonty nejlepÜφ °eÜenφ. M∙₧ete s nimi pohybovat na ose z a tφm m∞nit jejich velikost, otßΦet je, prost∞ d∞lat vÜe, co nem∙₧ete s obyΦejn²mi. Jsou nejlepÜφ volbou ke hrßm a dem∙m.

Tato lekce je voln²mi pokraΦovßnφm tΘ minulΘ (13). Tehdy jsme se nauΦili pou₧φvat bitmapovΘ fonty. 3D pφsma se vytvß°ejφ velmi podobn∞. NicmΘn∞... vypadajφ stokrßt lΘpe. M∙₧ete je zv∞tÜovat, pohybovat s nimi ve 3D, majφ hloubku. P°i osv∞tlenφ vypadajφ opravdu efektn∞. Stejn∞ jako v minulΘ lekci je k≤d specifick² pro Windows. Pokud by m∞l n∞kdo na platform∞ nezßvisl² k≤d, sem s nφm a jß napφÜu nov² tutorißl. RozÜφ°φme typick² k≤d prvnφ lekce.

#include <windows.h>// HlaviΦkov² soubor pro Windows

#include <math.h>// HlaviΦkov² soubor pro matematickou knihovnu

#include <stdio.h>// HlaviΦkov² soubor pro standardnφ vstup/v²stup

#include <stdarg.h>// HlaviΦkov² soubor pro funkce s prom∞nn²m poΦtem parametr∙

#include <gl\gl.h>// HlaviΦkov² soubor pro OpenGL32 knihovnu

#include <gl\glu.h>// HlaviΦkov² soubor pro Glu32 knihovnu

#include <gl\glaux.h>// HlaviΦkov² soubor pro Glaux knihovnu

HDC hDC = NULL;// Privßtnφ GDI Device Context

HGLRC hRC = NULL;// Trval² Rendering Context

HWND hWnd = NULL;// Obsahuje Handle naÜeho okna

HINSTANCE hInstance;// Obsahuje instanci aplikace

Base si pamatujete z 13. lekce jako ukazatel na prvnφ z display list∙ ascii znak∙, rot slou₧φ k pohybu, rotaci a vybarvovßnφ textu.

GLuint base;// ╚φslo zßkladnφho display listu znak∙

GLfloat rot;// Pro pohyb, rotaci a barvu textu

bool keys[256];// Pole pro uklßdßnφ vstupu z klßvesnice

bool active = TRUE;// Ponese informaci o tom, zda je okno aktivnφ

bool fullscreen = TRUE;// Ponese informaci o tom, zda je program ve fullscreenu

GLYPHMETRICSFLOAT gmf[256] uklßdß informace o velikosti a orientaci ka₧dΘho z 256 display list∙ fontu. Dßle v lekci vßm ukß₧u, jak zjistit Üφ°ku jednotliv²ch znak∙ a tφm velmi snadno a p°esn∞ vycentrovat text na obrazovce.

GLYPHMETRICSFLOAT gmf[256];// Uklßdß informace o fontu

Skoro cel² k≤d nßsledujφcφ funkce byl pou₧it ji₧ ve 13. lekci, tak₧e pokud mu moc nerozumφte, vφte, kde hledat informace.

GLvoid BuildFont(GLvoid)// Vytvo°enφ fontu

{

HFONT font;// Prom∞nnß fontu

base = glGenLists(256);// 256 znak∙

font = CreateFont(-24,// V²Üka

0,// èφ°ka

0,// ┌hel escapement

0,// ┌hel orientace

FW_BOLD,// TuΦnost

FALSE,// Kurzφva

FALSE,// Podtr₧enφ

FALSE,// P°eÜkrtnutφ

ANSI_CHARSET,// Znakovß sada

OUT_TT_PRECIS,// P°esnost v²stupu (TrueType)

CLIP_DEFAULT_PRECIS,// P°esnost o°ezßnφ

ANTIALIASED_QUALITY,// V²stupnφ kvalita

FF_DONTCARE|DEFAULT_PITCH,// Rodina a pitch

"Courier New");// JmΘno fontu

SelectObject(hDC, font);// V²b∞r fontu do DC

Pomocφ funkce wglUseFontOutlines() vytvo°φme 3D font. V parametrech p°edßme DC, prvnφ znak, poΦet display list∙, kterΘ se budou vytvß°et a ukazatel na pam∞¥, kam se budou vytvo°enΘ display listy uklßdat.

wglUseFontOutlines(hDC,// Vybere DC

0,// PoΦßteΦnφ znak

255,// Koncov² znak

base,// Adresa prvnφho znaku

Nastavφme ·rove≥ odchylek, kterß urΦuje jak hranat∞ bude vypadat. Potom urΦφme Üφ°ku nebo spφÜe hloubku na ose z. 0.0f by byl ploch² 2D font. ╚φm v∞tÜφ Φφslo p°i°adφme, tφm bude hlubÜφ. Parametr WGL_FONT_POLYGONS °φkß, ₧e mß OpenGL vytvo°it pevnΘ (celistvΘ) znaky s pou₧itφm polygon∙. P°i pou₧itφ WGL_FONT_LINES se vytvo°φ z linek (podobnΘ drßt∞nΘmu modelu). Je d∙le₧itΘ poznamenat, ₧e by se v tomto p°φpad∞ negenerovaly normßlovΘ vektory, tak₧e sv∞tlo nebude vypadat dob°e. Poslednφ parametr ukazuje na buffer pro ulo₧enφ informacφ o display listech.

0.0f,// Hranatost

0.2f,// Hloubka v ose z

WGL_FONT_POLYGONS,// Polygony ne drßt∞n² model

gmf);// Adresa bufferu pro ulo₧enφ informacφ.

}

V nßsledujφ funkci se ma₧e 256 display list∙ fontu poΦφnaje prvnφm, kter² je definovßn v base. Nejsem si jist², jestli by to Windows ud∞laly automaticky. Jeden °ßdek za jistotu stojφ. Funkce se volß p°i skonΦenφ programu.

GLvoid KillFont(GLvoid)// Sma₧e font

{

glDeleteLists(base, 256);// Sma₧e vÜech 256 znak∙

}

Tento k≤d zavolßte v₧dy, kdy₧ budete pot°ebovat vypsat n∞jak² text. ╪et∞zec je ulo₧en ve "fmt".

GLvoid glPrint(const char *fmt, ...)// Klon printf() pro OpenGL

{

Prom∞nnou "length" pou₧ijeme ke zjiÜt∞nφ dΘlky textu. Pole "text" uklßdß koneΦn² °et∞zec pro vykreslenφ. T°etφ prom∞nnß je ukazatel do parametr∙ funkce (pokud bychom zavolali funkci s n∞jakou prom∞nnou, "ap" na ni bude ukazovat.

float length=0;// DΘlka znaku

char text[256];// KoneΦn² °et∞zec

va_list ap;// Ukazatel do argument∙ funkce

if (fmt == NULL)// Pokud nebyl p°edßn °et∞zec

return;// Konec

Nßsledujφcφ k≤d konvertuje veÜkerΘ symboly v °et∞zci (%d, %f ap.) na znaky, kterΘ reprezentujφ ΦφselnΘ hodnoty v prom∞nn²ch. Poupravovan² text se ulo₧φ do °et∞zce text.

va_start(ap, fmt);// Rozbor °et∞zce pro prom∞nnΘ

vsprintf(text, fmt, ap);// Zam∞nφ symboly za Φφsla

va_end(ap);// V²sledek je nynφ ulo₧en v text

Text by Üel vycentrovat manußln∞, ale nßsledujφcφ metoda je urΦit∞ lepÜφ. V ka₧dΘm pr∙chodu cyklem p°iΦteme k dΘlce °et∞zce Üφ°ku aktußlnφ znaku, kterou najdeme v gmf[text[loop]].gmfCellIncX. gmf uklßdß informace o ka₧dΘm znaku (display listu), tedy nap°φklad i v²Üku znaku, ulo₧enou pod gmfCellIncY. Tuto techniku lze pou₧φt p°i vertikßlnφm vykreslovßnφ.

for (unsigned int loop=0;loop<(strlen(text));loop++)// Zjistφ poΦet znak∙ textu

{

length+=gmf[text[loop]].gmfCellIncX;// Inkrementace o Üφ°ku znaku

}

K vycentrovßnφ textu posuneme poΦßtek doleva o polovinu dΘlky °et∞zce.

glTranslatef(-length/2,0.0f,0.0f);// Zarovnßnφ na st°ed

Nastavφme GL_LIST_BIT a tφm zamezφme p∙sobenφ jin²ch display list∙, pou₧it²ch v programu na glListBase(). P°edeÜl²m p°φkazem urΦφme, kde mß OpenGL hledat sprßvnΘ display listy jednotliv²ch znak∙.

glPushAttrib(GL_LIST_BIT);// Ulo₧φ souΦasn² stav display list∙

glListBase(base);// Nastavφ prvnφ display list na base

Zavolßme funkci glCallLists(), kterß najednou zobrazuje vφce display list∙. strlen(text) vrßtφ poΦet znak∙ v °et∞zci a tφm i poΦet k zobrazenφ. Dßle pot°ebujeme znßt typ p°edßvanΘho parametru (poslednφ). Ani te∩ nebudeme vklßdat vφce ne₧ 256 znak∙, tak₧e pou₧ijeme GL_UNSIGNED_BYTE (byte m∙₧e nab²vat hodnot 0-255, co₧ je p°esn∞ to, co pot°ebujeme). V poslednφm parametru p°edßme text. Ka₧d² display list vφ, kde je pravß hrana toho p°edchozφho, Φφm₧ zamezφme nakupenφ znak∙ na sebe, na jedno mφsto. P°ed zaΦßtkem kreslenφ nßsledujφcφ znaku se p°esune o tuto hodnotu doprava (glTranslatef()). Nakonec nastavφme GL_LIST_BIT zp∞t na hodnotu majφcφ p°ed volßnφm glListBase().

glCallLists(strlen(text), GL_UNSIGNED_BYTE, text);// Vykreslφ display listy

glPopAttrib();// Obnovφ p∙vodnφ stav display list∙

}

Provedeme pßr drobn²ch zm∞n v inicializaΦnφm k≤du. ╪ßdka BuildFont() ze 13. lekce z∙stala na stejnΘm mφst∞, ale p°ibyl nov² k≤d pro pou₧itφ sv∞tel. Light0 je p°eddefinovßn na v∞tÜin∞ grafick²ch karet. TakΘ jsem p°idal glEnable(GL_COLOR_MATERIAL). Ke zm∞n∞ barvy pφsma pot°ebujeme zapnout vybarvovßnφ materißl∙, proto₧e i znaky jsou 3D objekty. Pokud vykreslujete vlastnφ objekty a n∞jak² text, musφte p°ed funkcφ glPrint() zavolat glEnable(GL_COLOR_MATERIAL) a po vykreslenφ textu glDisable(GL_COLOR_MATERIAL), jinak by se zm∞nila barva i vßmi vykreslovanΘho objektu.

int InitGL(GLvoid)// VÜechna nastavenφ OpenGL

{

glShadeModel(GL_SMOOTH);// Povolφ jemnΘ stφnovßnφ

glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// ╚ernΘ pozadφ

glClearDepth(1.0f);// Nastavenφ hloubkovΘho bufferu

glEnable(GL_DEPTH_TEST);// Povolφ hloubkovΘ testovßnφ

glDepthFunc(GL_LEQUAL);// Typ hloubkovΘho testovßnφ

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// NejlepÜφ perspektivnφ korekce

glEnable(GL_LIGHT0);// Zapne implicitnφ sv∞tlo

glEnable(GL_LIGHTING);// Zapne sv∞tla

glEnable(GL_COLOR_MATERIAL);// Zapne vybarvovßnφ materißl∙

BuildFont();// Vytvo°φ font

return TRUE;

}

P°esuneme se 10 jednotek do obrazovky. Outline fonty vypadajφ skv∞le v perspektivnφm m≤du. Kdy₧ jsou umφst∞ny hloub∞ji, zmenÜujφ se. Pomocφ funkce glScalef(x,y,z) m∙₧eme takΘ m∞nit m∞°φtka os. Pokud bychom nap°φklad cht∞li vykreslit font dvakrßt vyÜÜφ, pou₧ijeme glScalef(1.0f,2.0f,1.0f).

int DrawGLScene(GLvoid)// Vykreslovßnφ

{

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer

glLoadIdentity();// Reset matice

glTranslatef(0.0f,0.0f,-10.0f);// P°esun do obrazovky

glRotatef(rot,1.0f,0.0f,0.0f);// Rotace na ose x

glRotatef(rot*1.5f,0.0f,1.0f,0.0f);// Rotace na ose y

glRotatef(rot*1.4f,0.0f,0.0f,1.0f);// Rotace na ose z

Jako obyΦejn∞ jsem pou₧il pro zm∞nu barev "jednoduchΘ" matematiky. (Pozn. p°ekladatele: tahle v∞ta se mi povedla :)

// Pulzovßnφ barev zßvislΘ na pozici a rotaci

glColor3f(1.0f*float(cos(rot/20.0f)),1.0f*float(sin(rot/25.0f)),1.0f-0.5f*float(cos(rot/17.0f)));

glPrint("NeHe - %3.2f",rot/50);// V²pis textu

rot+=0.5f;// Inkrementace ΦφtaΦe

return TRUE;

}

Poslednφ k≤d, kter² se provede p°ed opuÜt∞nφm programu je smazßnφ fontu volßnφm KillFont().

//Konec funkce KillGLWindow(GLvoid)

if(!UnregisterClass("OpenGL",hInstance))

{

MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);

hInstance=NULL;

}

KillFont();//Smazßnφ fontu

}

Po doΦtenφ tΘto lekce byste m∞li b²t schopni pou₧φvat 3D fonty. Stejn∞ jako jsem psal ve 13. lekci, ani tentokrßt jsem na internetu nenaÜel podobn² Φlßnek. Mo₧nß jsem opravdu prvnφ, kdo pφÜe o tomto tΘmatu.

napsal: Jeff Molofee - NeHe
p°elo₧il: Michal Turek - Woq

ZdrojovΘ k≤dy

Lekce 14

<<< Lekce 13 | Lekce 15 >>>