Lekce 1

Lekce 1 - Vytvo°enφ OpenGL okna ve Windows

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

ZdrojovΘ k≤dy

Lekce 1

Lekce 2 >>>