..::OpenGL I - zßkladnφ nastavenφ::..

┌vod

Dnes se asi nejvφce pro vykreslovßnφ 3D grafiky ve vlastnφch programech pou₧φvß Direct3D, ale ten je pon∞kud obtφ₧n² a najφt n∞kde popsanΘ ·plnΘ zßklady se mi nikdy nepoda°ilo. PotΘ jsem na www.builder.cz narazil na tutorißl zab²vajφcφ se OpenGL a zjistil, ₧e i MSDN obsahuje velice dobr² tutorißl. V tΘto sΘrii Φlßnk∙ se budu sna₧it popsat jak zprovoznit OpenGL a jak pomocφ n∞j kreslit. Nep°edstφrßm, ₧e jej ·pln∞ ovlßdßm (prßv∞ se jej uΦφm) a tak pokud najdete v m²ch Φlßncφch n∞jakΘ chyby dejte mi prosφm v∞d∞t.

Nastavenφ projektu

D°φve ne₧ zaΦneme vlastnφ programovßnφ musφme vlo₧it hlaviΦkovΘ soubory a to: gl.h a glu.h
Ve Visual studiu nejsou tyto hlaviΦkovΘ soubory umφst∞ny u ostatnφch standartnφch soubor∙, ale v podadresß°i gl. To ale vy°eÜφme jednoduÜe. StaΦφ zadat relativnφ cestu nap°. takto:

#include <gl\gl.h>

#include <gl\glu.h>

PotΘ jeÜt∞ musφme do projektu p°idat odpovφdajφcφ lib knihovny a to bu∩ p°φmo do nastavenφ projektu, nebo pomocφ nßsledujφcφch p°φkaz∙ vlo₧enφch pod p°edchßzejφcφ p°φkazy include:

#pragma comment(lib,"opengl32.lib")

#pragma comment(lib,"glu32.lib")

Nastavenφ okna

Abychom mohli v okn∞ pou₧φvat OpenGL musφme oknu nastavit styly WS_CLIPSIBLINGS a WS_CLIPCHILDREN. To je nejlepÜφ ud∞lat nßsledujφcφm p°φkazem ve funkci PreCreateWindow:

cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;

(Ve t°φd∞ pohledu ne rßmcovΘho okna).

Dßle je vhodnΘ zruÜit p°emazßvßnφ pozadφ implicitnφ barvou. To ud∞lßme odchycenφm zprßvy WM_ERASEBKGND a zajiÜt∞nφm, aby v₧dy vrßtila TRUE.

Inicializace OpenGL

Tu je nejlΘpe provΘst v reakci na zprßvu WM_CREATE (tj. funkci OnCreate). TΘto Φßsti nerozumφm ·pln∞ perfektn∞, ale budu se sna₧it popsat ka₧dou funkci a co d∞lß. Nßsleduje k≤d z funkce OnCreate s popisem: (Samoz°ejm∞ se nejd°φve zavolß funkce OnCreate zßkladnφ t°φdy, co₧ ClassWizard d∞lß implicitn∞)

int n;    // Pomocnß prom∞nß

HGLRC hrc;    // Obdoba DC v OpenGL

 

m_pDC = new CClientDC(this);    // zφskßnφ DC

/* m_pDC je ukazatel na CDC, kter² budeme pot°ebovat po celou dobu, tak₧e je nejlepÜφ jej deklarovat jako Φlenskou prom∞nnou nebo jako globßlnφ prom∞nnou */

 

ASSERT(m_pDC != NULL);    // UjiÜt∞nφ se, ₧e se poda°ilo DC zφskat

// Nßsledujφcφ struktura popisuje po₧adovan² formßt pixel∙

static PIXELFORMATDESCRIPTOR pfd =

{

sizeof(PIXELFORMATDESCRIPTOR), // velikost tΘto struktury

1,     // Verze

PFD_DRAW_TO_WINDOW | // Podpora oken

PFD_SUPPORT_OPENGL | // Podpora OpenGL

PFD_DOUBLEBUFFER, // Dvojt² buffer

PFD_TYPE_RGBA, //Pou₧φvß se RGB Alfa

24, // 24-bitovß barevnß hloubka

0, 0, 0, 0, 0, 0, // barevnΘ bity ignorovßny

0, // ₧ßdn² alfa buffer

0, // shift bit ignorovßn (?)

0, //₧ßdn² akumulaΦnφ bufer (?)

0, 0, 0, 0, //akumulaΦnφ bity ignorovßny

32, // 32 bitov² z-buffer

0, // ₧ßdn² Üablonov² buffer (?)

0, // ₧ßdn² pomocn² buffer

PFD_MAIN_PLANE, // hlavnφ hladina (vrstva)

0, // reservovßno

0, 0, 0 // hladinovß maska ignorovßno

};

int pixelformat; // Pomocnß porm∞nnß

 

if ( (pixelformat = ChoosePixelFormat(m_pDC->GetSafeHdc(), &pfd)) == 0 )

/* Vyhledß index formßtu pixelu, kter² je nejbli₧Üφ nßmi popsanΘmu p°edchßzejφcφ strukturou. */

{

MessageBox("ChoosePixelFormat failed");

return -1;

}

 

if (SetPixelFormat(m_pDC->GetSafeHdc(), pixelformat, &pfd) == FALSE)

/* Nastavφ formßt pixelu. */

{

MessageBox("SetPixelFormat failed");

return -1;

}

 

n = ::GetPixelFormat(m_pDC->GetSafeHdc()); /* Zjistφ aktußlnφ formßt pixelu */

::DescribePixelFormat(m_pDC->GetSafeHdc(), n, sizeof(pfd), &pfd); /* Naplnφ strukturu pfd informacemi o aktußlnφm formßtu. Tyto dv∞ funkce jsou podle mΘho nßzoru zbyteΦnΘ. Ale nezkouÜel jsem je vynechat. */

 

// Zde je MSDN inicializace palety ale to je v dneÜnφ dob∞ ji₧ zbyteΦnΘ

hrc = wglCreateContext(m_pDC->GetSafeHdc()); /* Vytvo°φ HGLRC (obdobu DC).*/

wglMakeCurrent(m_pDC->GetSafeHdc(), hrc); /* Nastavφ toto HGLRC jako aktußlnφ. */

 

CRect rc;

GetClientRect(&rc); //ZjiÜt∞nφ velikosti okna

glClearDepth(1.0f); //Nastavφ Φisticφ hodnotu pro hloubkov² buffer

glEnable(GL_DEPTH_TEST); /* Povolφ kontrolu hloubky. */

 

if (rc.bottom) // Pokud je v²Üka okna v∞tÜφ jak 0

GLfloat fAspect = (GLfloat)m_oldRect.right/m_oldRect.bottom; /* Pom∞r Üφ°ky k v²Üce.*/

else fAspect = 1.0f; // Jinak by se d∞lilo nulou, tak₧e nastavφme na 1

 

glMatrixMode(GL_PROJECTION); /* Nastavφ aktußlnφ matici pro v²poΦty pot°ebnΘ pro vykreslovßnφ. */

glLoadIdentity(); // Resetuje aktußlnφ matici.

gluPerspective(45.0f, fAspect, 0,100); /* Nastavφ jak se na scΘnu dφvßte. Parametry znamenajφ toto: Vzdßlenost ze kterΘ se dφvßme, pom∞r Üφ°ky okna k jeho v²Üce, nejmenÜφ vzdßlenost ve kterΘ jsou zobrazovanΘ objekty jeÜt∞ viditelnΘ, nejv∞tÜφ vzdßlenost ve kterΘ jsou zobrazovanΘ objekty jeÜt∞ viditelnΘ. Dejte si pozor a¥ poslednφ dv∞ hodnoty nastavφte na dostateΦn∞ velkΘ hodnoty, jinak se vßm m∙₧e, a₧ budete kreslit, stßt, ₧e se nevykreslφ nic nebo Φernß obrazovka, jako m∞, kdy₧ jsem se to sna₧il rozchodit. */

glMatrixMode(GL_MODELVIEW);/* Nastavφ aktußlnφ matici pro v²poΦty pot°ebnΘ pro vykreslovßnφ. */

Reakce na zm∞nu velikosti okna

P°i zm∞n∞ velikosti okna musφme p°enastavit n∞kterß nastavenφ OpenGL, abychom sprßvn∞ kreslili do okna. Na zm∞nu velikosti okna nßs upozor≥uje zprßva WM_SIZE. Nßsleduje zdrojov² k≤d z funkce OnSize (reakce na WM_SIZE) s popisem:

/*cx, cy je Üφ°ka a v²Üka okna*/

if(cy > 0) //Pokud je v²Üka okna v∞tÜφ jak 0

{

glViewport(0, 0, cx, cy); /* Nastavφ obdΘlnφk do kterΘho lze vykreslovat. Pomocφ tΘto funkce m∙₧ete nastavit vykreslovßnφ jen do Φßsti okna.*/

 

RedrawWindow(); /*Vyvolß p°ekreslenφ okna. Je to standartnφ funkce a ne OpenGL funkce, proto₧e vykreslovßnφ se provßdφ v reakci na zprßvu WM_PAINT*/

 

// Nßsledujφcφ je popsßno ji₧ d°φve

glMatrixMode(GL_PROJECTION);

glLoadIdentity();

gluPerspective(45.0f, (GLdouble)cx/cy, 0.0f, 100.0f);

glMatrixMode(GL_MODELVIEW);

}

┌klid po kreslenφ

Ten je nejlepÜφ provßd∞t v reakci na zprßvu WM_DESTROY. Nßsleduje v²pis z funkce OnDestroy:

HGLRC hrc;

hrc = ::wglGetCurrentContext(); /*Zjistφ aktußln∞ pou₧φvatn² HGLRC*/

::wglMakeCurrent(NULL, NULL); /* Nastavφ aktußlnφ DC a HGLRC na nulovΘ hodnoty. */

if (hrc) ::wglDeleteContext(hrc); /* Sma₧e HGLRC */

if (m_pDC) delete m_pDC; /* Sma₧e CDC zφskanΘ ve funkci OnCreate */

m_pDC = NULL;

Zßv∞r

A te∩ ji₧ mßme vÜe pot°ebnΘ pro vlastnφ kreslenφ, ale o tom a₧ p°φÜt∞.