NauΦφte se jak nastavit a vytvo°it OpenGL okno ve Windows. Program, kter² vytvo°φte zobrazφ "pouze" prßzdnΘ okno. ╚ernΘ pozadφ nevypadß nic moc, ale pokud porozumφte tΘto lekci, budete mφt velmi dobr² zßklad pro jakoukoliv dalÜφ prßci. Zjistφte jak OpenGL pracuje, jak probφhß vytvß°enφ okna a takΘ jak napsat jednoduÜe pochopiteln² k≤d.
Jsem obyΦejn² kluk s vßÜnφ pro OpenGL. Kdy₧ jsem o n∞m poprvΘ slyÜel, vydalo 3Dfx zrychlenΘ ovladaΦe pro Voodoo 1. Hned jsem v∞d∞l, ₧e OpenGL je n∞co, co se musφm nauΦit. Bohu₧el bylo velice t∞₧kΘ najφt n∞jakΘ informace, jak v knihßch, tak na internetu. Strßvil jsem hodiny pokusy o napsßnφ funkΦnφho k≤du a p°esv∞dΦovßnφm lidφ emaily a na IRC. Zjistil jsem, ₧e lidΘ, kte°φ rozum∞li OpenGL, se pova₧ovali za elitu a nehodlali se o svΘ v∞domosti d∞lit. Velice frustrujφcφ... Vytvo°il jsem tyto tutorißly, aby je zßjemci o OpenGL mohli pou₧φt, kdy₧ budou pot°ebovat pomoc. V ka₧dΘm tutorißlu se vÜe sna₧φm vysv∞tlit do detail∙, aby bylo jasnΘ, co ka₧d² °ßdek d∞lß. Sna₧φm se sv∙j k≤d psßt co nejjednoduÜeji (nepou₧φvßm MFC)! I absolutnφ novßΦek, jak v C++, tak v OpenGL, by m∞l b²t schopen tento k≤d zvlßdnout a mφt dalÜφ dobrΘ nßpady, co d∞lat dßl. Je mnoho tutorißl∙ o OpenGL. Pokud jste hardcorov² OpenGL programßtor asi Vßm budou p°ipadat p°φliÜ jednoduchΘ, ale pokud prßv∞ zaΦφnßte majφ mnoho co nabφdnout!
ZaΦnu tento tutorißl p°φmo k≤dem. Prvnφ, co se musφ ud∞lat, je vytvo°it projekt. Pokud nevφte jak to ud∞lat, nem∞li byste se uΦit OpenGL, ale Visual C++. N∞kterΘ verze Visual C++ vy₧adujφ, aby byl bool zm∞n∞n na BOOL, true na TRUE a false na FALSE. Pokud to budete mφt na pam∞ti nem∞ly by b²t s kompilacφ ₧ßdnΘ problΘmy. Potom co vytvo°φte novou Win32 Application (NE console application) ve Visual C++, budete pot°ebovat p°ipojit OpenGL knihovny. Jsou dv∞ mo₧nosti, jak to ud∞lat: Vyberte Project>Settings, pak zvolte zßlo₧ku Link a do kolonky Object/Library Modules napiÜte na zaΦßtek °ßdku (p°ed kernel32.lib) OpenGL32.lib Glu32.lib Glaux.lib. Potom klikn∞te na OK. Nebo napiÜte p°φmo do k≤du programu nßsledujφcφ °ßdky.
// Vlo₧enφ knihoven
#pragma comment (lib,"opengl32.lib")
#pragma comment (lib,"glu32.lib")
#pragma comment (lib,"glaux.lib")
Nynφ jste p°ipraveni napsat sv∙j prvnφ OpenGL program pro Windows. ZaΦneme vlo₧enφm hlaviΦkov²ch soubor∙.
#include <windows.h>// HlaviΦkov² soubor pro Windows
#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
Dßle pot°ebujete deklarovat globßlnφ prom∞nnΘ, kterΘ chcete v programu pou₧φt. Tento program vytvß°φ prßzdnΘ OpenGL okno, proto jich nebudeme pot°ebovat mnoho. Ty, kterΘ nynφ pou₧ijeme jsou ovÜem velmi d∙le₧itΘ a budete je pou₧φvat v ka₧dΘm programu zalo₧enΘm na tomto k≤du. Nastavφme Rendering Context. Ka₧d² OpenGL program je spojen s Rendering Contextem. Rendering Context °φkß, kterß spojenφ volß OpenGL, aby se spojilo s Device Context (kontext za°φzenφ). Nßm staΦφ v∞d∞t, ₧e OpenGL Rendering Context je definovßn jako hRC. Aby program mohl kreslit do okna pot°ebujete vytvo°it Device Context. Ve Windows je Device Context definovßn jako hDC. Device Context napojφ okno na GDI (grafickΘ rozhranφ). Prom∞nnß hWnd obsahuje handle p°id∞len² oknu a Φtvrt² °ßdek vytvo°φ instanci programu.
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
Prvnφ °ßdek deklaruje pole, kterΘ budeme pou₧φvat na sledovßnφ stisknut²ch klßves. Je mnoho zp∙sob∙, jak to ud∞lat, ale takto to d∞lßm jß. Je to spolehlivΘ a m∙₧eme sledovat stisk vφce klßves najednou. Prom∞nnß active bude pou₧ita, aby nßÜ program informovala, zda je jeho okno minimalizovßno nebo ne. Kdy₧ je okno minimalizovßno m∙₧eme ud∞lat cokoliv od pozastavenφ Φinnosti k≤du a₧ po opuÜt∞nφ programu. Jß pou₧iji pozastavenφ b∞hu programu. Dφky tomu zbyteΦn∞ nepob∞₧φ na pozadφ, kdy₧ bude minimalizovßn. Prom∞nnß fullscreen bude obsahovat informaci, jestli nßÜ program b∞₧φ p°es celou obrazovku - v tom p°φpad∞ bude fullscreen mφt hodnotu true, kdy₧ program pob∞₧φ v okn∞ bude mφt hodnotu false. Je d∙le₧itΘ, aby prom∞nnß byla globßlnφ a tφm pßdem ka₧dß funkce v∞d∞la, jestli program b∞₧φ ve fullscreenu, nebo v okn∞.
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
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);// Deklarace procedury okna (funkΦnφ prototyp)
Nßsledujφcφ funkce se volß v₧dy, kdy₧ u₧ivatel m∞nφ velikost okna. I kdy₧ nejste schopni zm∞nit velikost okna (nap°φklad ve fullscreenu), bude tato funkce volßna alespo≥ jednou, aby nastavila perspektivnφ pohled p°i spuÜt∞nφ programu. Velikost OpenGL scΘny se bude m∞nit v zßvislosti na Üφ°ce a v²Üce okna, ve kterΘm je zobrazena.
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)// Zm∞na velikosti a inicializace OpenGL okna
{
if (height==0)// ZabezpeΦenφ proti d∞lenφ nulou
{
height=1;// Nastavφ v²Üku na jedna
}
glViewport(0,0,width,height);// Resetuje aktußlnφ nastavenφ
Nastavφme obraz na perspektivnφ pohled. To znamenß, ₧e vzdßlen∞jÜφ objekty budou menÜφ. glMatrixMode(GL_PROJECTION) ovlivnφ formu obrazu. Forma obrazu urΦuje, jak v²raznß bude perspektiva. Vytvo°φme realisticky vypadajφcφ scΘnu. glLoadIdentity() resetuje matici. Vrßtφ ji do jejφho p∙vodnφho stavu. Po glLoadIdentity() nastavφme perspektivnφ pohled scΘny. Perspektiva je vypoΦφtßna s ·hlem pohledu 45 stup≥∙ a je zalo₧ena na v²Üce a Üφ°ce okna. ╚φslo 0.1f je poΦßteΦnφ a 100.0f koneΦn² bod, kter² °φkß jak hluboko do obrazovky m∙₧eme kreslit. glMatrixMode(GL_MODELVIEW) oznamuje, ₧e forma pohledu bude znovu zm∞n∞na. Nakonec znovu resetujeme matici. Pokud p°edchßzejφcφmu textu nerozumφte, nic si z toho ned∞lejte, vysv∞tlφm ho cel² v dalÜφch tutorißlech. JedinΘ co nynφ musφte v∞d∞t je, ₧e nßsledujφcφ °ßdky musφte do svΘho programu napsat, pokud chcete, aby scΘna vypadala p∞kn∞.
glMatrixMode(GL_PROJECTION);// Zvolφ projekΦnφ matici
glLoadIdentity();// Reset matice
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);// V²poΦet perspektivy
glMatrixMode(GL_MODELVIEW);// Zvolφ matici Modelview
glLoadIdentity();// Reset matice
}
Nastavφme vÜe pot°ebnΘ pro OpenGL. Definujeme ΦernΘ pozadφ, zapneme depth buffer, aktivujeme smooth shading (vyhlazenΘ stφnovßnφ), atd.. Tato funkce se volß po vytvo°enφ okna. Vracφ hodnotu, ale tφm se nynφ nemusφme zab²vat, proto₧e naÜe inicializace nenφ zatφm ·pln∞ komplexnφ.
int InitGL(GLvoid)// VÜechno nastavenφ OpenGL
{
Nßsledujφcφ °ßdek povolφ jemnΘ stφnovßnφ, aby se barvy na polygonech p∞kn∞ promφchaly. Vφce detail∙ o smooth shading si povφme v jin²ch tutorißlech.
glShadeModel(GL_SMOOTH);// Povolφ jemnΘ stφnovßnφ
Nastavφme barvu pozadφ prßzdnΘ obrazovky. Rozsah barev se urΦuje ve stupnici od 0.0f do 1.0f. 0.0f je nejtmavÜφ a 1.0f je nejsv∞tlejÜφ. Prvnφ parametr ve funkci glClearColor() je intenzita ΦervenΘ barvy, druh² zelenΘ a t°etφ modrΘ. ╚φm bli₧Üφ je hodnota barvy 1.0f, tφm sv∞tlejÜφ slo₧ka barvy bude. Poslednφ parametr je hodnota alpha (pr∙hlednost). Kdy₧ budeme Φistit obrazovku, tak se o pr∙hlednost starat nemusφme. Nynφ ji nechßme na 0.0f. M∙₧ete vytvß°et r∙znΘ barvy kombinovßnφm sv∞tlosti t°φ zßkladnφch barev (ΦervenΘ, zelenΘ, modrΘ). Pokud budete mφt glClearColor(0.0f,0.0f,1.0f,0.0f), bude obrazovka modrß. Kdy₧ budete mφt glClearColor(0.5f,0.0f,0.0f,0.0f), bude obrazovka st°edn∞ tmav∞ Φervenß. Abyste ud∞lali bφlΘ pozadφ nastavte vÜechny hodnoty na nejvyÜÜφ hodnotu (1.0f), pro ΦernΘ pozadφ zadejte pro vÜechny slo₧ky 0.0f.
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);// ╚ernΘ pozadφ
Nßsledujφcφ t°i °ßdky ovliv≥ujφ depth buffer. Depth buffer si m∙₧ete p°edstavit jako vrstvy/hladiny obrazovky. Obsahuje informace, o tom jak hluboko jsou zobrazovanΘ objekty. Tento program sice nebude deep buffer pou₧φvat (nic nevykreslujeme). Objekty se se°adφ tak, aby bli₧Üφ p°ekr²valy vzdßlen∞jÜφ.
glClearDepth(1.0f);// Nastavenφ hloubkovΘho bufferu
glEnable(GL_DEPTH_TEST);// Povolφ hloubkovΘ testovßnφ
glDepthFunc(GL_LEQUAL);// Typ hloubkovΘho testovßnφ
Dßle oznßmφme, ₧e chceme pou₧φt nejlepÜφ korekce perspektivy. Jen nepatrn∞ se snφ₧φ v²kon, ale zlepÜφ se vzhled celΘ scΘny
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);// NejlepÜφ perspektivnφ korekce
Nakonec vrßtφme true. Kdy₧ budeme chtφt zjistit zda inicializace prob∞hla bez problΘm∙, m∙₧eme zkontrolovat, zda funkce vrßtila hodnotu true nebo false. M∙₧ete p°idat vlastnφ k≤d, kter² vrßtφ false, kdy₧ se inicializace nezda°φ - nap°. loading textur. Nynφ se tφm nebudeme dßle zab²vat.
return TRUE;// Inicializace prob∞hla v po°ßdku
}
Do tΘto funkci umφstφme vÜechno vykreslovßnφ. Nßsledujφcφ tutorißly budou p°episovat p°edevÜφm tento a inicializaΦnφ k≤d tΘto lekce. ( Pokud ji₧ nynφ rozumφte zßklad∙m OpenGL, m∙₧ete si zde p°ipsat kreslenφ zßkladnφch tvar∙ (mezi glLoadIdentity() a return). Pokud jste novßΦek, tak poΦkejte do dalÜφho tutorißlu. JedinΘ co nynφ ud∞lßme, je vymazßnφ obrazovky na barvu, pro kterou jste se rozhodli, vyma₧eme obsah hloubkovΘho bufferu a resetujeme scΘnu. Zatφm nebudeme nic kreslit. P°φkaz return true nßm °φkß, ₧e p°i kreslenφ nenastaly ₧ßdnΘ problΘmy. Pokud z n∞jakΘho d∙vodu chcete p°eruÜit b∞h programu, staΦφ p°idat return false p°ed return true - to °φkß naÜemu programu, ₧e kreslenφ scΘny selhalo a program se ukonΦφ.
int DrawGLScene(GLvoid)// Vykreslovßnφ
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Sma₧e obrazovku a hloubkov² buffer
glLoadIdentity();// Reset matice
// Sem m∙₧ete kreslit
return TRUE;// Vykreslenφ prob∞hlo v po°ßdku
}
Nßsledujφcφ Φßst k≤du je volßna t∞sn∞ p°ed koncem programu. ┌kolem funkce KillGLWindow() je uvoln∞nφ renderovacφho kontextu, kontextu za°φzenφ a handle okna. P°idal jsem zde nezbytnΘ kontrolovßnφ chyb. Kdy₧ nenφ program schopen n∞co uvolnit, oznßmφ chybu, kterß °φkß co selhalo. Usnadnφ slo₧itΘ hledßnφ problΘm∙.
GLvoid KillGLWindow(GLvoid)// Zavφrßnφ okna
{
Zjistφme zda je program ve fullscreenu. Pokud ano, tak ho p°epneme zp∞t do systΘmu. Mohli bychom vypnout okno p°ed opuÜt∞nφm fullscreenu, ale na n∞kter²ch grafick²ch kartßch tφm zp∙sobφme problΘmy a systΘm by se mohl zhroutit.
if (fullscreen)// Jsme ve fullscreenu?
{
K nßvratu do p∙vodnφho nastavenφ systΘmu pou₧φvßme funkci ChangeDisplaySettings(NULL,0). Jako prvnφ parametr zadßme NULL a jako druh² 0 - pou₧ijeme hodnoty ulo₧enΘ v registrech Windows (p∙vodnφ rozliÜenφ, barevnou hloubku, obnovovacφ frekvenci, atd.). Po p°epnutφ zviditelnφme kurzor.
ChangeDisplaySettings(NULL,0);// P°epnutφ do systΘmu
ShowCursor(TRUE);// Zobrazφ kurzor myÜi
}
Zkontrolujeme zda mßme renderovacφ kontext (hRC). Kdy₧ ne, program p°eskoΦφ Φßst k≤du pod nφm, kter² kontroluje, zda mßme kontext za°φzenφ.
if (hRC)// Mßme rendering kontext?
{
Zjistφme, zda m∙₧eme odpojit hRC od hDC. VÜimn∞te si, jak kontroluji chyby. Nejd°φve programu °eknu, a¥ odpojφ Rendering Context (s pou₧itφm wglMakeCurrent(NULL,NULL)), pak zkontroluji zda akce byla ·sp∞Ünß. Takto dßm vφce °ßdku do jednoho.
if (!wglMakeCurrent(NULL,NULL))// Jsme schopni odd∞lit kontexty?
{
Pokud nejsme schopni uvolnit DC a RC, pou₧ijeme zobrazφme zprßvu, ₧e DC a RC nelze uvolnit. NULL v parametru znamenß, ₧e informaΦnφ okno nemß ₧ßdnΘho rodiΦe. Text ihned za NULL je text, kter² se vypφÜe do zprßvy. DalÜφ parametr definuje text liÜty. Parametr MB_OK znamenß, ₧e chceme mφt na chybovΘ zprßv∞ jen jedno tlaΦφtko s nßpisem OK. MB_ICONINFORMATION zobrazφ ikonu.
MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
Zkusφme vymazat Rendering Context. Pokud se pokus nezda°φ, op∞t se zobrazφ chybovß zprßva. Nakonec nastavφme hRC a NULL.
if (!wglDeleteContext(hRC))// Jsme schopni smazat RC?
{
MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
}
hRC=NULL;// Nastavφ hRC na NULL
}
Zjistφme zda mß program kontext za°φzenφ. Kdy₧ ano odpojφme ho. Pokud se odpojenφ nezda°φ, zobrazφ se chybovß zprßva a hDC bude nastaven na NULL.
if (hDC && !ReleaseDC(hWnd,hDC))// Jsme schopni uvolnit DC
{
MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hDC=NULL;// Nastavφ hDC na NULL
}
Nynφ zjistφme zda mßme handle okna a pokud ano pokusφme se odstranit okno pou₧itφm funkce DestroyWindow(hWnd). Pokud se pokus nezda°φ, zobrazφ se chybovß zprßva a hWnd bude nastaveno na NULL.
if (hWnd && !DestroyWindow(hWnd))// Jsme schopni odstranit okno?
{
MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hWnd=NULL;// Nastavφ hWnd na NULL
}
Odregistrovßnφm t°φdy okna oficißln∞ uzav°eme okno a p°edejdeme zobrazenφ chybovΘ zprßvy "Windows Class already registered" p°i op∞tovnΘm spuÜt∞nφ programu.
if (!UnregisterClass("OpenGL",hInstance))// Jsme schopni odregistrovat t°φdu okna?
{
MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
hInstance=NULL;// Nastavφ hInstance na NULL
}
}
DalÜφ Φßst k≤du mß na starosti vytvo°enφ OpenGL okna. Strßvil jsem mnoho Φasu p°em²Ülenφm zda mßm ud∞lat pouze fullscreen m≤d, kter² by vy₧adoval mΘn∞ k≤du, nebo jednoduÜe upravitelnou, u₧ivatelsky p°φjemnou verzi s variantou jak pro okno tak pro fullscreen, kterß vÜak vy₧aduje mnohem vφce k≤du. Rozhodl jsem se pro druhou variantu, proto₧e jsem dostßval mnoho dotaz∙ jako nap°φklad: Jak mohu vytvo°it okno mφsto fullscreenu? Jak zm∞nφm popisek okna? Jak zm∞nφm rozliÜenφ ne formßt pixel∙? Nßsledujφcφ k≤d dovede vÜechno. Jak si m∙₧ete vÜimnout funkce vracφ bool a p°ijφmß 5 parametr∙ v po°adφ: nßzev okna, Üφ°ku okna, v²Üku okna, barevnou hloubku, fullscreen (pokud je parametr true program pob∞₧φ ve fullscreenu, pokud bude false program pob∞₧φ v okn∞). Vracφme bool, abychom v∞d∞li zda bylo okno ·sp∞Ün∞ vytvo°eno.
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
Za chvφli po₧ßdßme Windows, aby pro nßs naÜel pixel format, kter² odpovφdß tomu, kter² chceme. Toto Φφslo ulo₧φme do prom∞nnΘ PixelFormat.
GLuint PixelFormat;// Uklßdß formßt pixel∙
Wc bude pou₧ijeme k uchovßnφ informacφ o struktu°e Windows Class. Zm∞nou hodnot jednotliv²ch polo₧ek, lze ovlivnit vzhled a chovßnφ okna. P°ed vytvo°enφm samotnΘho okna se musφ zaregistrovat n∞jakß struktura pro okno.
WNDCLASS wc;// Struktura Windows Class
DwExStyle a dwStyle ponesou informaci o normßlnφch a rozÜφ°en²ch informacφch o oknu. Pou₧iji prom∞nnΘ k uchovßnφ styl∙, tak₧e mohu m∞nit vzhled okna, kter² pot°ebuji vytvo°it (pro fullscreen bez okraje a pro okno okraj).
DWORD dwExStyle;// RozÜφ°en² styl okna
DWORD dwStyle;// Styl okna
Zjistφme polohu levΘho hornφho a pravΘho dolnφho rohu okna. Tyto prom∞nnΘ vyu₧ijeme k tomu, abychom nakreslili okno v takovΘm rozliÜenφ, v jakΘm si ho p°ejeme mφt. Pokud vytvo°φme okno s rozliÜenφm 640x480, okraje budou zabφrat Φßst naÜeho rozliÜenφ.
RECT WindowRect;// ObdΘlnφk okna
WindowRect.left = (long)0;// Nastavφ lev² okraj na nulu
WindowRect.right = (long)width;// Nastavφ prav² okraj na zadanou hodnotu
WindowRect.top = (long)0;// Nastavφ hornφ okraj na nulu
WindowRect.bottom = (long)height;// Nastavφ spodnφ okraj na zadanou hodnotu
P°i°adφme globßlnφ prom∞nnΘ fullscreen, hodnotu fullscreenflag. Tak₧e pokud naÜe okno pob∞₧φ ve fullscreenu, prom∞nnß fullscreen se bude rovnat true. Kdybychom zavφrali okno ve fullscreenu, ale hodnota prom∞nnΘ fullscreen by byla false mφsto true, jak by m∞la b²t, poΦφtaΦ by se nep°epl zp∞t do systΘmu, proto₧e by si myslel, ₧e v n∞m ji₧ je. JednoduÜe shrnuto, fullscreen v₧dy musφ obsahovat sprßvnou hodnotu.
fullscreen = fullscreenflag;// Nastavφ prom∞nnou fullscreen na sprßvnou hodnotu
Zφskßme instanci pro okno a potΘ definujeme Window Class. CS_HREDRAW a CS_VREDRAW donutφ naÜe okno, aby se p°ekreslilo, kdykoliv se zm∞nφ jeho velikost. CS_OWNDC vytvo°φ privßtnφ kontext za°φzenφ. To znamenß, ₧e nenφ sdφlen s ostatnφmi aplikacemi. WndProc je procedura okna, kterß sleduje p°φchozφ zprßvy pro program. Äßdnß extra data pro okno nepou₧φvßme, tak₧e do dalÜφch dvou polo₧ek p°i°adφme nulu. Nastavφme instanci a hIcon na NULL, co₧ znamenß, ₧e nebudeme pro nßÜ program pou₧φvat ₧ßdnou specißlnφ ikonu a pro kurzor myÜi pou₧φvßme standardnφ Üipku. Barva pozadφ nßs nemusφ zajφmat (to za°φdφme v OpenGL). Nechceme, aby okno m∞lo menu, tak₧e i tuto hodnotu nastavφme na NULL. JmΘno t°φdy m∙₧e b²t libovolnΘ. Jß pou₧iji pro jednoduchost "OpenGL".
hInstance = GetModuleHandle(NULL);// Zφskß instanci okna
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;// P°ekreslenφ p°i zm∞n∞ velikosti a vlastnφ DC
wc.lpfnWndProc = (WNDPROC) WndProc;// Definuje proceduru okna
wc.cbClsExtra = 0;// Äßdnß extra data
wc.cbWndExtra = 0;// Äßdnß extra data
wc.hInstance = hInstance;// Instance
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);// Standardnφ ikona
wc.hCursor = LoadCursor(NULL, IDC_ARROW);// Standardnφ kurzor myÜi
wc.hbrBackground = NULL;// Pozadφ nenφ nutnΘ
wc.lpszMenuName = NULL;// Nechceme menu
wc.lpszClassName = "OpenGL"// JmΘno t°φdy okna
Zaregistrujeme prßv∞ definovanou t°φdu okna. Kdy₧ nastane chyba a zobrazφ se chybovΘ hlßÜenφ. ZmßΦknutφm tlaΦφtka OK se program ukonΦφ.
if (!RegisterClass(&wc))// Registruje t°φdu okna
{
MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// P°i chyb∞ vrßtφ false
}
Nynφ si zjistφme zda mß program b∞₧et ve fullscreenu, nebo v okn∞.
if (fullscreen)// Budeme ve fullscreenu?
{
S p°epφnßnφm do fullscreenu, mφvajφ lidΘ mnoho problΘm∙. Je zde pßr d∙le₧it²ch v∞cφ, na kterΘ si musφte dßvat pozor. Ujist∞te se, ₧e Üφ°ka a v²Üka, kterou pou₧φvßte ve fullscreenu je toto₧nß s tou, kterou chcete pou₧φt v okn∞. DalÜφ v∞c je hodn∞ d∙le₧itß. Musφte p°epnout do fullscreenu p°edtφm ne₧ vytvo°φte okno. V tomto k≤du se o rovnost v²Üky a Üφ°ky nemusφte starat, proto₧e velikost ve fullscreenu i v okn∞ budou stejnΘ.
DEVMODE dmScreenSettings;// M≤d za°φzenφ
memset(&dmScreenSettings,0,sizeof(dmScreenSettings));// Vynulovßnφ pam∞ti
dmScreenSettings.dmSize=sizeof(dmScreenSettings);// Velikost struktury Devmode
dmScreenSettings.dmPelsWidth= width;// èφ°ka okna
dmScreenSettings.dmPelsHeight= height;// V²Üka okna
dmScreenSettings.dmBitsPerPel= bits;// Barevnß hloubka
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
Funkce ChangeDisplaySettings() se pokusφ p°epnout do m≤du, kter² je ulo₧en v dmScreenSettings. Pou₧iji parametr CDS_FULLSCREEN, proto₧e odstranφ pracovnφ liÜtu ve spodnφ Φßsti obrazovky a nep°esune nebo nezm∞nφ velikost okna p°i p°epφnßnφ z fullscreenu do systΘmu nebo naopak.
// Pokusφ se pou₧φt prßv∞ definovanΘ nastavenφ
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
Pokud prßv∞ vytvo°en² fullscreen m≤d neexistuje, zobrazφ se chybovß zprßva s nabφdkou spuÜt∞nφ v okn∞ nebo opuÜt∞nφ programu.
// Nejde-li fullscreen, m∙₧e u₧ivatel spustit program v okn∞ nebo ho opustit
if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
{
Kdy₧ se u₧ivatel rozhodne pro b∞h v okn∞, do prom∞nnΘ fullscreen se p°i°adφ false a program pokraΦuje dßle.
fullscreen=FALSE;// B∞h v okn∞
}
else
{
Pokud se u₧ivatel rozhodl pro ukonΦenφ programu, zobrazφ se u₧ivateli zprßva, ₧e program bude ukonΦen. Bude vrßcena hodnota false, kterß naÜemu programu °φkß, ₧e pokus o vytvo°enφ okna nebyl ·sp∞Ün² a potom se program ukonΦφ.
// Zobrazφ u₧ivateli zprßvu, ₧e program bude ukonΦen
MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
return FALSE;// Vrßtφ FALSE
}
}
}
Proto₧e pokus o p°epnutφ do fullscreenu m∙₧e selhat, nebo se u₧ivatel m∙₧e rozhodnout pro b∞h programu v okn∞, zkontrolujeme jeÜt∞ jednou zda je prom∞nnß fullscreen true nebo false. A₧ potΘ nastavφme typ obrazu.
if (fullscreen)// Jsme stßle ve fullscreenu?
{
Pokud jsme stßle ve fullscreenu nastavφme rozÜφ°en² styl na WS_EX_APPWINDOW, co₧ donutφ okno, aby p°ekrylo pracovnφ liÜtu. Styl okna urΦφme na WS_POPUP. Tento typ okna nemß ₧ßdnΘ okraje, co₧ je pro fullscreen v²hodnΘ. Nakonec vypneme kurzor myÜi. Pokud vßÜ program nenφ interaktivnφ, je v∞tÜinou vhodn∞jÜφ ve fullscreenu kurzor vypnout. Pro co rozhodnete je na vßs.
dwExStyle=WS_EX_APPWINDOW;// RozÜφ°en² styl okna
dwStyle=WS_POPUP;// Styl okna
ShowCursor(FALSE);// Skryje kurzor
}
else
{
Pokud mφsto fullscreenu pou₧φvßme b∞h v okn∞, nastavφme rozÜφ°en² styl na WS_EX_WINDOWEDGE. To dodß oknu trochu 3D vzhledu. Styl nastavφme na WS_OVERLAPPEDWINDOW mφsto na WS_POPUP. WS_OVERLAPPEDWINDOW vytvo°φ okno s liÜtou, okraji, tlaΦφtky pro minimalizaci a maximalizaci. Budeme moci m∞nit velikost.
dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;// RozÜφ°en² styl okna
dwStyle=WS_OVERLAPPEDWINDOW;// Styl okna
}
P°izp∙sobφme okno podle stylu, kter² jsme vytvo°ili. P°izp∙sobenφ ud∞lß okno v takovΘm rozliÜenφ, jakΘ po₧adujeme. Normßln∞ by okraje p°ekr²valy Φßst okna. S pou₧itφm p°φkazu AdjustWindowRectEx ₧ßdnß Φßst OpenGL scΘny nebude p°ekryta okraji, mφsto toho bude okno ud∞lßno o mßlo v∞tÜφ, aby se do n∞j veÜly vÜechny pixely tvo°φcφ okraj okna. Ve fullscreenu tato funkce nemß ₧ßdn² efekt.
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);// P°izp∙sobenφ velikosti okna
Vytvo°φme okno a zkontrolujeme zda bylo vytvo°eno sprßvn∞. Pou₧ijeme funkci CreateWindowEx() se vÜemi parametry, kterΘ vy₧aduje. RozÜφ°en² styl, kter² jsme se rozhodli pou₧φt. JmΘno t°φdy (musφ b²t stejnΘ jako to, kterΘ jste pou₧ili, kdy₧ jste registrovali Window Class).Titulek okna. Styl okna. Hornφ levß pozice okna (0,0 je nejjist∞jÜφ). èφ°ka a v²Üka okna. Nechceme mφt rodiΦovskΘ okno ani menu, tak₧e nastavφme tyto parametry na NULL. Zadßme instanci okna a koneΦn∞ p°i°adφme NULL na mφsto poslednφho parametru. VÜimn∞te si, ₧e zahrnujeme styly WS_CLIPSIBLINGS a WS_CLIPCHILDREN do stylu, kter² jsme se rozhodli pou₧φt. WS_CLIPSIBLINGS a WS_CLIPCHILDREN jsou pot°ebnΘ pro OpenGL, aby pracovalo sprßvn∞. Tyto styly zakazujφ ostatnφm okn∙m, aby kreslily do naÜeho okna.
// Vytvo°enφ okna
if (!(hWnd=CreateWindowEx(dwExStyle,// RozÜφ°en² styl
"OpenGL",// JmΘno t°φdy
title,// Titulek
dwStyle |// Definovan² styl
WS_CLIPSIBLINGS |// Po₧adovan² styl
WS_CLIPCHILDREN,// Po₧adovan² styl
0, 0,// Pozice
WindowRect.right-WindowRect.left,// V²poΦet Üφ°ky
WindowRect.bottom-WindowRect.top,// V²poΦet v²Üky
NULL,// ÄßdnΘ rodiΦovskΘ okno
NULL,// Bez menu
hInstance,// Instance
NULL)))// Nep°edat nic do WM_CREATE
Dßle zkontrolujeme zda bylo vytvo°eno. Pokud bylo, hWnd obsahuje handle tohoto okna. Kdy₧ se vytvo°enφ okna nepovede, k≤d zobrazφ chybovou zprßvu a program se ukonΦφ.
{
KillGLWindow();// ZruÜφ okno
MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// Vrßtφ chybu
}
Vybereme Pixel Format, kter² podporuje OpenGL, dßle zvolφme double buffering a RGBA (Φervenß, zelenß, modrß, pr∙hlednost). Pokusφme se najφt formßt, kter² odpovφdß tomu, pro kter² jsme se rozhodli (16 bit∙, 24 bit∙, 32 bit∙). Nakonec nastavφme Z-Buffer. Ostatnφ parametry se nepou₧φvajφ nebo pro nßs nejsou d∙le₧itΘ.
static PIXELFORMATDESCRIPTOR pfd=// Oznßmφme Windows jak chceme vÜe nastavit
{
sizeof(PIXELFORMATDESCRIPTOR),// Velikost struktury
1,// ╚φslo verze
PFD_DRAW_TO_WINDOW |// Podpora okna
PFD_SUPPORT_OPENGL |// Podpora OpenGL
PFD_DOUBLEBUFFER,// Podpora Double Bufferingu
PFD_TYPE_RGBA,// RGBA Format
bits,// Zvolφ barevnou hloubku
0, 0, 0, 0, 0, 0,// Bity barev ignorovßny
0,// Äßdn² alpha buffer
0,// Ignorovßn Shift bit
0,// Äßdn² akumulaΦnφ buffer
0, 0, 0, 0,// AkumulaΦnφ bity ignorovßny
16,// 16-bitov² hloubkov² buffer (Z-Buffer)
0,// Äßdn² Stencil Buffer
0,// Äßdn² Auxiliary Buffer
PFD_MAIN_PLANE,// Hlavnφ vykreslovacφ vrstva
0,// Rezervovßno
0, 0, 0// Maska vrstvy ignorovßna
};
Pokud nenastaly problΘmy b∞hem vytvß°enφ okna, pokusφme se p°ipojit kontext za°φzenφ. Pokud ho se nep°ipojφ, zobrazφ se chybovΘ hlßÜenφ a program se ukonΦφ.
if (!(hDC=GetDC(hWnd)))// Poda°ilo se p°ipojit kontext za°φzenφ?
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Can't Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Kdy₧ zφskßme kontext za°φzenφ, pokusφme se najφt odpovφdajφcφ Pixel Format. Kdy₧ ho Windows nenajde formßt, zobrazφ se chybovß zprßva a program se ukonΦφ.
if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))// Poda°ilo se najφt Pixel Format?
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Can't Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Kdy₧ Windows najde odpovφdajφcφ formßt, tak se ho pokusφme nastavit. Pokud p°i pokusu o nastavenφ nastane chyba, op∞t se zobrazφ chybovΘ hlßÜenφ a program se ukonΦφ.
if(!SetPixelFormat(hDC,PixelFormat,&pfd))// Poda°ilo se nastavit Pixel Format?
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Can't Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Pokud byl nastaven Pixel Format sprßvn∞, pokusφme se zφskat Rendering Context. Pokud ho nezφskßme, program zobrazφ chybovou zprßvu a ukonΦφ se.
if (!(hRC=wglCreateContext(hDC)))// Poda°ilo se vytvo°it Rendering Context?
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Can't Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Pokud nenastaly ₧ßdnΘ chyby p°i vytvß°enφ jak Device Context, tak Rendering Context, vÜe co musφme nynφ ud∞lat je aktivovat Rendering Context. Pokud ho nebudeme moci aktivovat, zobrazφ se chybovß zprßva a program se ukonΦφ.
if(!wglMakeCurrent(hDC,hRC))// Poda°ilo se aktivovat Rendering Context?
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Can't Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Pokud bylo okno vytvo°eno, zobrazφme ho na obrazovce, nastavφme ho, aby bylo v pop°edφ (vyÜÜφ priorita) a pak nastavφme zam∞°enφ na toto okno. Zavolßme funkci ResizeGLScene() s parametry odpovφdajφcφmi v²Üce a Üφ°ce okna, abychom sprßvn∞ nastavili perspektivu OpenGL.
ShowWindow(hWnd,SW_SHOW);// Zobrazenφ okna
SetForegroundWindow(hWnd);// Do pop°edφ
SetFocus(hWnd);// Zam∞°φ fokus
ReSizeGLScene(width, height);// Nastavenφ perspektivy OpenGL scΘny
KoneΦn∞ se dostßvßme k volßnφ v²Üe definovanΘ funkce InitGL(), ve kterΘ nastavujeme osv∞tlenφ, loading textur a cokoliv jinΘho, co je pot°eba. M∙₧ete vytvo°it svou vlastnφ kontrolu chyb ve funkci InitGL() a vracet true, kdy₧ vÜe prob∞hne bez problΘm∙, nebo false, pokud nastanou n∞jakΘ problΘmy. Nap°φklad, nastane-li chyba p°i nahrßvßnφ textur, vrßtφte false, jako znamenφ, ₧e n∞co selhalo a program se ukonΦφ.
if (!InitGL())// Inicializace okna
{
KillGLWindow();// Zav°e okno
MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
return FALSE;// UkonΦφ program
}
Pokud jsme se dostali a₧ takhle daleko, m∙₧eme konstatovat, ₧e vytvo°enφ okna prob∞hlo bez problΘm∙. Vrßtφme true do WinMain(), co₧ °φkß, ₧e nenastaly ₧ßdnΘ chyby. To zabrßnφ programu, aby se sßm ukonΦil.
return TRUE;// VÜe prob∞hlo v po°ßdku
}
Nynφ se vypo°ßdßme se systΘmov²mi zprßvami pro okno. Kdy₧ mßme zaregistrovanou naÜi Window Class, m∙₧eme podstoupit k Φßsti k≤du, kterß mß na starosti zpracovßnφ zprßv.
LRESULT CALLBACK WndProc(HWND hWnd,// Handle okna
UINT uMsg,// Zprßva pro okno
WPARAM wParam,// Dopl≥kovΘ informace
LPARAM lParam)// Dopl≥kovΘ informace
{
NapφÜeme mapu zprßv. Program se bude v∞tvit podle prom∞nnΘ uMsg, kterß obsahuje jmΘno zprßvy.
switch (uMsg)// V∞tvenφ podle p°φchozφ zprßvy
{
Po p°φchodu WM_ACTIVE, zkontrolujeme, zda je okno stßle aktivnφ. Pokud bylo minimalizovßno, nastavφme hodnotu active na false. Pokud je naÜe okno aktivnφ, prom∞nnß active bude mφt hodnotu true.
case WM_ACTIVATE:// Zm∞na aktivity okna
{
if (!HIWORD(wParam))// Zkontroluje zda nenφ minimalizovanΘ
{
active=TRUE;// Program je aktivnφ
}
else
{
active=FALSE;// Program nenφ aktivnφ
}
return 0;// Nßvrat do hlavnφho cyklu programu
}
Po p°φchodu WM_SYSCOMMAND (systΘmov² p°φkaz) porovnßme wParam s mo₧n²mi stavy, kterΘ mohly nastat. Kdy₧ je wParam WM_SCREENSAVE nebo SC_MONITORPOWER sna₧φ se systΘm zapnout spo°iΦ obrazovky, nebo p°ejφt do ·spornΘho re₧imu. Jestli₧e vrßtφme 0 zabrßnφme systΘmu, aby tyto akce provedl.
case WM_SYSCOMMAND:// SystΘmov² p°φkaz
{
switch (wParam)// Typ systΘmovΘho p°φkazu
{
case SC_SCREENSAVE:// Pokus o zapnutφ Üet°iΦe obrazovky
case SC_MONITORPOWER:// Pokus o p°echod do ·spornΘho re₧imu?
return 0;// Zabrßnφ obojφmu
}
break;// Nßvrat do hlavnφho cyklu programu
}
P°iÜlo-li WM_CLOSE bylo okno zav°eno. PoÜleme tedy zprßvu pro opuÜt∞nφ programu, kterß p°eruÜφ vykonßvßnφ hlavnφho cyklu. Prom∞nnou done (ve WinMain()) nastavφme na true, hlavnφ smyΦka se p°eruÜφ a program se ukonΦφ.
case WM_CLOSE:// Povel k ukonΦenφ programu
{
PostQuitMessage(0);// PoÜle zprßvu o ukonΦenφ
return 0;// Nßvrat do hlavnφho cyklu programu
}
Pokud byla stisknuta klßvesa, m∙₧eme zjistit, kterß z nich to byla, kdy₧ zjistφme hodnotu wParam. Potom zadßme do bu≥ky, specifikovanΘ wParam, v poli keys[] true. Dφky tomu potom m∙₧eme zjistit, kterß klßvesa je prßv∞ stisknutß. Tφmto zp∙sobem lze zkontrolovat stisk vφce klßves najednou.
case WM_KEYDOWN:// Stisk klßvesy
{
keys[wParam] = TRUE;// Oznßmφ to programu
return 0;// Nßvrat do hlavnφho cyklu programu
}
Pokud byla naopak klßvesa uvoln∞na ulo₧φme do bu≥ky s indexem wParam v poli keys[] hodnotu false. Tφmto zp∙sobem m∙₧eme zjistit zda je klßvesa jeÜt∞ stßle stisknuta nebo ji₧ byla uvoln∞na. Ka₧dß klßvesa je reprezentovßna jednφm Φφslem od 0 do 255. Kdy₧ nap°φklad stisknu klßvesu Φφslo 40, hodnota key[40] bude true, jakmile ji pustφm jejφ hodnota se vrßtφ op∞t na false.
case WM_KEYUP:// Uvoln∞nφ klßvesy
{
keys[wParam] = FALSE;// Oznßmφ to programu
return 0;// Nßvrat do hlavnφho cyklu programu
}
Kdykoliv u₧ivatel zm∞nφ velikost okna, poÜle se WM_SIZE. P°eΦteme LOWORD a HIWORD hodnoty lParam, abychom zjistili jakß je novß Üφ°ka a v²Üka okna. P°edßme tyto hodnoty do funkce ReSizeGLScene(). Perspektiva OpenGL scΘny se zm∞nφ podle nov²ch rozm∞r∙.
case WM_SIZE:// Zm∞na velikosti okna
{
ReSizeGLScene(LOWORD(lParam),HIWORD(lParam)); // LoWord=èφ°ka, HiWord=V²Üka
return 0;// Nßvrat do hlavnφho cyklu programu
}
}
Zprßvy, o kterΘ se nestarßme, budou p°edßny funkci DefWindowProc(), tak₧e se s nimi vypo°ßdß systΘm.
return DefWindowProc(hWnd, uMsg, wParam, lParam);// P°edßnφ ostatnφch zprßv systΘmu
}
Funkce WinMain() je vstupnφ bod do aplikace, mφsto, odkud budeme volat funkce na otev°enφ okna, snφmanφ zprßv a interakci s u₧ivatelem.
int WINAPI WinMain(HINSTANCE hInstance,// Instance
HINSTANCE hPrevInstance,// P°edchozφ instance
LPSTR lpCmdLine,// Parametry p°φkazovΘ °ßdky
int nCmdShow)// Stav zobrazenφ okna
{
Deklarujeme dv∞ lokßlnφ prom∞nnΘ. Msg bude pou₧ita na zjiÜ¥ovßnφ, zda se majφ zpracovßvat n∞jakΘ zprßvy. Prom∞nnß done bude mφt na poΦßtku hodnotu false. To znamenß, ₧e nßÜ program jeÜt∞ nemß b²t ukonΦen. Dokud se done rovnß false, program pob∞₧φ. Jakmile se zm∞nφ z false na true, program se ukonΦφ.
MSG msg;// Struktura zprßv systΘmu
BOOL done=FALSE;// Prom∞nnß pro ukonΦenφ programu
DalÜφ Φßst k≤du je volitelnß. Zobrazuje zprßvu, kterß se zeptß u₧ivatele, zda chce spustit program ve fullscreenu. Pokud u₧ivatel vybere mo₧nost Ne, hodnota prom∞nnΘ fullscreen se zm∞nφ z v²chozφho true na false, a tφm pßdem se program spustφ v okn∞.
// Dotaz na u₧ivatele pro fullscreen/okno
if (MessageBox(NULL,"Would You Like To Run In Fullscreen Mode?", "Start FullScreen?", MB_YESNO | MB_ICONQUESTION) == IDNO)
{
fullscreen=FALSE;// B∞h v okn∞
}
Vytvo°φme OpenGL okno. Zadßme text titulku, Üφ°ku, v²Üku, barevnou hloubku a true (fullscreen), nebo false (okno) jako parametry do funkce CreateGLWindow(). Tak a je to! Je to p∞kn∞ lehkΘ, ₧e? Pokud se okno nepoda°φ z n∞jakΘho d∙vodu vytvo°it, bude vrßceno false a program se okam₧it∞ ukonΦφ.
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))// Vytvo°enφ OpenGL okna
{
return 0;// Konec programu p°i chyb∞
}
SmyΦka se opakuje tak dlouho, dokud se done rovnß false.
while(!done)// Hlavnφ cyklus programu
{
Prvnφ v∞c, kterou ud∞lßme, je zkontrolovßnφ zprßv pro okno. Pomocφ funkce PeekMessage() m∙₧eme zjistit zda n∞jakΘ zprßvy Φekajφ na zpracovßnφ bez toho, aby byl program pozastaven. Mnoho program∙ pou₧φvß funkci GetMessage(). Pracuje to skv∞le, ale program nic ned∞lß, kdy₧ nedostßvß ₧ßdnΘ zprßvy.
if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))// P°iÜla zprßva?
{
Zkontrolujeme, zda jsme neobdr₧eli zprßvu pro ukonΦenφ programu. Pokud je aktußlnφ zprßva WM_QUIT, kterß je zp∙sobena volßnφm funkce PostQuitMessage(0), nastavφme done na true, Φφm₧ p°eruÜφme hlavnφ cyklus a ukonΦφme program.
if (msg.message==WM_QUIT)// Obdr₧eli jsme zprßvu pro ukonΦenφ?
{
done=TRUE;// Konec programu
}
else// P°edßme zprßvu procedu°e okna
{
Kdy₧ zprßva nevyz²vß k ukonΦenφ programu, tak p°edßme funkcφm TranslateMessage() a DispatchMessage() referenci na tuto zprßvu, aby ji funkce WndProc() nebo Windows zpracovaly.
TranslateMessage(&msg);// P°elo₧φ zprßvu
DispatchMessage(&msg);// OdeÜle zprßvu
}
}
else// Pokud nedoÜla ₧ßdnß zprßva
{
Pokud zde nebudou ji₧ ₧ßdnΘ zprßvy, p°ekreslφme OpenGL scΘnu. Nßsledujφcφ °ßdek kontroluje, zda je okno aktivnφ. NaÜe scΘna je vyrenderovßna a je zkontrolovßna vrßcenß hodnota. Kdy₧ funkce DrawGLScene() vrßtφ false nebo je stisknut ESC, hodnota prom∞nnΘ done je nastavena na true, co₧ ukonΦφ b∞h programu.
if (active)// Je program aktivnφ?
{
if (keys[VK_ESCAPE])// Byl stisknut ESC?
{
done=TRUE;// UkonΦφme program
}
else// P°ekreslenφ scΘny
{
Kdy₧ vÜechno prob∞hlo bez problΘm∙, prohodφme obsah buffer∙ (s pou₧itφm dvou buffer∙ p°edejdeme blikßnφ obrazu p°i p°ekreslovßnφ). Pou₧itφm dvojtΘho bufferingu vÜechno vykreslujeme do obrazovky v pam∞ti, kterou nevidφme. Jakmile vym∞nφme obsah buffer∙, to co je na obrazovce se p°esune do tΘto skrytΘ obrazovky a to, co je ve skrytΘ obrazovce se p°enese na monitor. Dφky tomu nevidφme probliknutφ.
DrawGLScene();// Vykreslenφ scΘny
SwapBuffers(hDC);// Prohozenφ buffer∙ (Double Buffering)
}
}
P°i stisku klßvesy F1 p°epneme z fullscreenu do okna a naopak.
if (keys[VK_F1])// Byla stisknuta klßvesa F1?
{
keys[VK_F1]=FALSE;// OznaΦ ji jako nestisknutou
KillGLWindow();// ZruÜφ okno
fullscreen=!fullscreen;// Negace fullscreen
// Znovuvytvo°enφ okna
if (!CreateGLWindow("NeHe's OpenGL Framework",640,480,16,fullscreen))
{
return 0;// Konec programu pokud nebylo vytvo°eno
}
}
}
}
Pokud se prom∞nnß done rovnß true, hlavnφ cyklus se p°eruÜφ. Zav°eme okno a opustφme program.
KillGLWindow();// Zav°e okno
return (msg.wParam);// UkonΦenφ programu
}
V tΘto lekci jsem se vßm pokouÜel co nejpodrobn∞ji vysv∞tlit ka₧d² krok p°i nastavovßnφ a vytvß°enφ OpenGL programu. Program se ukonΦφ p°i stisku klßvesy ESC a sleduje, zda je okno aktivnφ Φi nikoliv.
napsal: Jeff Molofee - NeHe
p°elo₧il: Vßclav SlovßΦek - Wessan