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.
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")
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.
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φ. */
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);
}
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;
A te∩ ji₧ mßme vÜe pot°ebnΘ pro vlastnφ kreslenφ, ale o tom a₧ p°φÜt∞.