 |
V tomto tutorialu se dozvíte, jak vytvořit základní strukturu OpenGL aplikace a jak nakreslit trojúhelník.
|
 |
 |
Abychom mohli používat OpenGL příkazy, musíme do programu začlenit hlavičkové soubory
gl.h a glu.h
|
 |
#include <
gl/gl.h> //hlavičkový soubor pro užívání instrukcí z ovladače OpenGL32.dll
#include <
gl/glu.h> //hlavičkový soubor pro užívání instrukcí z ovladače GLu32.dll
 |
Vytvoříme si formulář, do kterého budeme vykreslovat scénu.
|
 |
void __fastcall TForm1::FormCreate(TObject *Sender)
{
SetWindowStats(640, 480, 16); //nastav rozlišení 640*480 16 bitovou hloubku barev
m_hDC = GetDC(Handle); //načti handle okna do m_hDC (Windows Device Context)
SetPixelFormatDescriptor(); //nastav formát výstupniho pixelu
m_hRC = wglCreateContext(m_hDC); //vytvoř m_hRC (OpenGL Rendering Context)
wglMakeCurrent(m_hDC, m_hRC); //připoj m_hRC (OpenGL Rendering Context) do m_hDC (Windows Device Context), který komunikuje s wokenim GDI (Graphics Device Interface)
FormResize(NULL); //vyčisti okno před iniciací OpenGL
InitGL(); //inicializuj OpenGL
}
 |
m_hDC je proměnná typu HDC.
HDC (Windows Device Context), je kontext zařízení, který se připojuje do
grafického rozhraní woken GDI (Graphics Device Interface).
m_hRC je proměnná typu HGLRC.
HGLRC (OpenGL Rendering Context) - připojuje OpenGL do HDC (Windows Device Context)
|
 |
bool __fastcall TForm1::SetWindowStats(int iWidth_, int iHeight_, int iColor_)
{
ClientWidth = iWidth_; //přečti šířku okna
ClientHeight = iHeight_; //přečti výšku okna
//zeptej se, jestli budu chtít okno přepnout do fullscreenu
if(Application->MessageBox("Would You Like To Run In Fullscreen Mode?",
"Start FullScreen?",
MB_YESNO|MB_ICONQUESTION)==IDYES)
{
//pokud zadám Ano nastav tyto hodnoty
DEVMODE dmScreenSettings; //Device Mode - mód zařízení
memset(&dmScreenSettings,0,sizeof(dmScreenSettings)); //vyčisti paměť
dmScreenSettings.dmSize=sizeof(dmScreenSettings); //velikost struktury
dmScreenSettings.dmPelsWidth = iWidth_; //nastav šířku obrazovky
dmScreenSettings.dmPelsHeight = iHeight_; //nastav výšku obrazovky
dmScreenSettings.dmBitsPerPel = iColor_; //nastav hloubku barev
dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;
//pokud jsou některé parametry špatně nastaveny
if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
{
return false; //tak opusť funkci
}
else //jinak přepni na fullscreen a
{
BorderStyle = bsNone; //nastav okno, aby bylo bez rámečků a tlačítek
Left = 0; //nastav levý okraj okna na 0
Top = 0; //nastav horní okraj okna na 0
ShowCursor(FALSE); //schovej kurzor myši
}
}
return true;
}
 |
Funkce SetWindowStats() nám vyplivne zprávu, ve které se nás zeptá, jestli budeme chtít aplikaci
rozjet v okně, nebo ve fullscreenu. Podle volby, kterou si zvolíme pak změní rozlišení obrazovky
a velikost formuláře.
|
 |
void __fastcall TForm1::SetPixelFormatDescriptor()
{
PIXELFORMATDESCRIPTOR pfd = { //řekni woknům jak maj zobrazit obrazovkový pixel
sizeof(PIXELFORMATDESCRIPTOR), //velikost descriptoru
1, //číslo verze
PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //formáty podporující wokna, OpenGL, nastavení doublebufferu
PFD_TYPE_RGBA, //používej barvy ve formátu RGBA
24, //buffer barev
0,0,0,0,0,0,
0,0,
0,0,0,0,0,
32, //32Bit Z-Buffer (Depth buffer)
0, // Stencil buffer
0,
PFD_MAIN_PLANE, //vykreslovací vrstva
0,
0,0,0
};
m_iPixelFormat = ChoosePixelFormat(m_hDC, &pfd); //vyber nejvhodnější pixelový formát
SetPixelFormat(m_hDC, m_iPixelFormat, &pfd); //a tento pixelový formát nastav
}
 |
Funkce SetPixelFormatDescriptor() nastavuje formát pixelu obrazovky
|
 |
bool __fastcall TForm1::InitGL()
{
wglMakeCurrent(m_hDC, m_hRC); //připoj m_hRC (OpenGL Rendering Context) do m_hDC (Windows Device Context), který komunikuje s wokenim GDI (Graphics Device Interface)
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); //nastav černé pozadí scény
wglMakeCurrent(m_hDC, NULL); //vynuluj m_hRC (OpenGL Rendering Context)
return TRUE;
}
 |
Funkce InitGL() vytvoří základní scénu s čeným pozadím. Barva pozadí se nastavuje ve funkci
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
Hodnoty barev jsou glClearColor(red, green, blue, alfa);
|
 |
void __fastcall TForm1::Loop()
{
wglMakeCurrent(m_hDC, m_hRC); //připoj m_hRC (OpenGL Rendering Context) do m_hDC (Windows Device Context), který komunikuje s wokenim GDI (Graphics Device Interface)
RenderGLScene(); //vykresli OpenGl scénu
SwapBuffers(m_hDC); //prohoď buffery (double burrefing)
wglMakeCurrent(m_hDC, NULL); //vynuluj m_hRC (OpenGL Rendering Context)
}
 |
Funkce Loop() běží v nekonečné smyčce a volá funkci RenderGLScene(); ve
které budeme vykreslovat objekty.
Funkce Loop() běží v odděleném procesu TThread. Priorita vlákna TThread
je nastavena na maximum Priority = tpTimeCritical;,
aby jiná činnost systému nezpomalovala překreslování OpenGL objektů.
|
 |
//---------------------------------------------------------------------------
TMyThread *RenderThread; //definice proměnné RenderThread
//---------------------------------------------------------------------------
__fastcall TMyThread::TMyThread(bool CreateSuspended): TThread(CreateSuspended)
{
//Priority = tpIdle; //vlákno je prováděno, když systém je nečinný
//Priority = tpLowest; //priorita vlákna je dva body pod normálem
//Priority = tpLower; //priorita vlákna je jeden bod pod normálem
//Priority = tpNormal; //vlákno má normálni prioritu
//Priority = tpHigher; //priorita vlákna je jeden bod nad normálem
//Priority = tpHighest; //priorita vlákna je dva body nad normálem
Priority = tpTimeCritical; //vlákno získá nejvyšší prioritu
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Render()
{
Form1->Loop(); //volej funkci pro překreslování scény
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Execute()
{
while (!Terminated) Synchronize(Render); //pokud neni vlákno ukončeno volej funkci Render
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Run()
{
Resume(); //rozjeď vlákno
}
//---------------------------------------------------------------------------
void __fastcall TMyThread::Done()
{
RenderThread->~TMyThread(); //volej destruktor vlákna
}
//---------------------------------------------------------------------------
__fastcall TMyThread:: ~TMyThread()
{
RenderThread->Terminated; //ukonči vlákno
}
//---------------------------------------------------------------------------
 |
Vlákno se vytváří při vytváření formuláře Form1
|
 |
__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
TMyThread *RenderThread = new TMyThread(true); //vytvoř renderovací vlákno
RenderThread->Run(); //rozjeď renderovací vlákno
_control87(MCW_EM, MCW_EM); //zamezení dělení nulou
}
 |
Funkce Loop() volá v nekonečné smyčce funkci RenderGLScene(), ve
které budeme vykrelovat všechny objekty.
|
 |
void __fastcall TForm1::RenderGLScene()
{
glClear(GL_COLOR_BUFFER_BIT); //vyčisti obrazovkový buffer
glLoadIdentity(); //resetuj současnou modelovou matici
DrawTriangles(); //vykresli trojúhelník
}
 |
Ve funkci RenderGLScene() budeme volat funkce pro vytváření OpenGL objektů. Nejzákladnější
objekt je trojúhelník, ze kterého lze vytvořit jakýkoli složitější objekt. Všechny grafické karty
podporující OpenGL mají instrukce, které urychlují vykreslování trojúhelníků. Pokud tedy budeme chtít,
aby naše aplikace běžela opravdu plynule, je nejlepší všechny objekty tvořit z trojúhelníků
glBegin(GL_TRIANGLES);, nebo ještě rychleji se překreslují trojúhelníky glBegin(GL_TRIANGLE_STRIP);,
nebo glBegin(GL_TRIANGLE_FAN);, avšak u těchto dvou funkcí jsou menší omezení v případě texturování, ale
to už moc předbíhám.
|
 |
void DrawTriangles(void)
{
glTranslatef(-1.5f,0.0f,-6.0f); //pohni trojúhelníkem o 1.5 doleva o 6.0 od kamery
glBegin(GL_TRIANGLES); //začni vykreslovat trojúhelník
glVertex3f( 0.0f, 1.0f, 0.0f); //horní bod
glVertex3f(-1.0f,-1.0f, 0.0f); //dolní levý bod
glVertex3f( 1.0f,-1.0f, 0.0f); //dolní pravý bod
glEnd(); //ukonči vykreslování trojúhelníka
}
 |
glTranslatef(-1.5f,0.0f,-6.0f); pohybuje celým objektem ve směru x,y,z.
Hodnoty funkce jsou: glTranslatef(x,y,z);
glVertex3f( 0.0f, 1.0f, 0.0f); určuje bod objektu. Hodnoty jsou
glVertex3f(x,y,z);
|
 |
void __fastcall TForm1::FormResize(TObject *Sender)
{
wglMakeCurrent(m_hDC, m_hRC); //připoj m_hRC (OpenGL Rendering Context) do m_hDC (Windows Device Context), který komunikuje s wokenim GDI (Graphics Device Interface)
glViewport(0, 0, ClientWidth, ClientHeight); //nastav velikost zobrazovací plochy
glMatrixMode(GL_PROJECTION); //nastav matici zobrazení prostoru
glLoadIdentity(); //použij tuto matici
//vypočti velikost zobrazovací plochy. Nastav úhel pohledu kamery, poměr výšky a šířky, nejbližši a nejvzdálenější viditelný bod
gluPerspective(45.0, static_cast<
double>(ClientWidth) / static_cast<
double>(ClientHeight),0.1,100.0);
glMatrixMode(GL_MODELVIEW); //nastav matici zobrazení objektu
glLoadIdentity(); //použij tuto matici
wglMakeCurrent(m_hDC, NULL); //vynuluj m_hRC (OpenGL Rendering Context)
}
 |
Funkce FormResize(TObject *Sender) nastavi velikost renderovací scény. Při změně velikosti formuláře, se
automaticky změní velikost renderovací scény.
Hodnoty funkce glViewport(0, 0, ClientWidth, ClientHeight); jsou:
glViewport(x,y,šířka,výška);
x,y je levý-dolní roh zobrazovací plochy
Hodnoty funkce
gluPerspective(45.0, static_cast< double>(ClientWidth) / static_cast< double>(ClientHeight),0.1,100.0); jsou:
gluPerspective(zorný úhel kamery, poměr šířky a výšky projekčního plátna (formuláře), nejbližší bod, nejvzdálenější bod);
|
 |
void __fastcall TForm1::FormKeyPress(TObject *Sender, char &Key)
{
if(Key == VK_ESCAPE) //jestliže klepnu na klávesu Esc
Close(); //ukonči aplikaci
}
 |
Ve funkci FormKeyPress(TObject *Sender, char &Key)
budeme volat funkce, které se provedou po klepnutí na určitou klávesu. Zatím tu
máme klávesu Esc, která nám ukončí aplikaci.
|
 |
void __fastcall TForm1::FormDestroy(TObject *Sender)
{
if(BorderStyle == bsNone) //pokud je fullscreen
ChangeDisplaySettings(NULL,0); //nastav původní hodnotu rozlišení obrazovky
ReleaseDC(Handle, m_hDC); //uvolni handle okna m_hDC (Windows Device Context)
wglMakeCurrent(m_hDC, NULL); //vynuluj m_hRC (OpenGL Rendering Context)
wglDeleteContext(m_hRC); //vymaž m_hRC (OpenGL Rendering Context)
RenderThread->Done(); //ukonči renderovací vlákno
}
 |
Při uzavírání aplikace se uvolní handle okna, vymaže OpenGL Rendering Context z paměti a
ukončí se renderovací vlákno.
|
 |

Home