OpenGL 3.2
Szablon aplikacji OpenGL
Janusz Ganczarski
www.januszg.hg.pl
Wstęp
W tym odcinku kursu przygotujemy oraz omówimy szablon aplikacji OpenGL. Będą to
właściwie dwa szablony. Jeden przeznaczony dla systemów z Microsoft Windows, drugi dla systemów
posiadających X Window Serwer, czyli głównie UNIX/Linux.
Nasze przykładowe programy będą składały się z trzech zasadniczych części. Pierwszym
będzie zależny od platformy systemowej kod tworzący okno wraz z kontekstem OpenGL oraz
obsługujący interfejs użytkownika. Druga częśd obejmuje kod wykorzystujący bibliotekę OpenGL,
który napisany jest w sposób niezależny od systemu operacyjnego. Trzecią częśd stanowią biblioteki
pomocnicze najczęściej korzystające z OpenGL, które również napisane są w sposób przenośny.
Szablon aplikacji OpenGL dla Microsoft Windows
Tworzenie okna
Na początek kod zródłowy funkcji WinMain, której zadaniem jest utworzenie okna
programu. Nie opisujemy bliżej tego kodu, bowiem opis API WIN32 przekracza tematykę niniejszego
kursu, ale nie odbiega on od typowego kodu prezentowanego w dokumentacji MSDN.
#include "resource.h"
&
//////////////////////////////////////////////////////////////////////
// funkcja main
//////////////////////////////////////////////////////////////////////
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int
nCmdShow )
{
// utworzenie i rejestracja okna
WNDCLASSEX winClass;
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof( WNDCLASSEX );
winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon( hInstance, (LPCTSTR)IDI_OPENGL_ICON );
winClass.hIconSm = LoadIcon( hInstance, (LPCTSTR)IDI_OPENGL_ICON );
winClass.hCursor = LoadCursor( NULL, IDC_ARROW );
winClass.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx( &winClass ) )
return FALSE;
HWND hWnd = NULL;
hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS", "OpenGL 3.2 - szablon OpenGL",
WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, 500, 500, NULL, NULL, hInstance, NULL
);
if( hWnd == NULL )
return FALSE;
// przetwarzanie pętli komunikatów
MSG msg = { 0 };
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
SendMessage( hWnd, WM_PAINT, 0, 0 );
}
// wyrejestrowania okna i zakończenie działania programu
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return msg.wParam;
}
Zasoby
Okno zawiera zasoby z ikoną z logiem biblioteki OpenGL. Plik nagłówkowy zasobów wygląda
następująco:
#ifndef __RESOURCE_H__
#define __RESOURCE_H__
#define IDI_OPENGL_ICON 4001
#endif // __RESOURCE_H__
A tak wygląda sam plik zasobów:
#include "resource.h"
//////////////////////////////////////////////////////////////////////
// ikona OpenGL
//////////////////////////////////////////////////////////////////////
IDI_OPENGL_ICON ICON DISCARDABLE "opengl.ico"
Funkcja przetwarzajÄ…ca komunikaty
Poniżej znajduje się kod zródłowy funkcji okna w API WIN32, czyli funkcji przetwarzającej
komunikaty. Funkcja ta wykorzystuje dwie zmienne globalne hRC i hDC, deklaracje funkcji
korzystających z OpenGL oraz plik nagłówkowy extension3.h będący elementem biblioteki
pomocniczej extensions3, którą poznamy w dalszej części tego odcinka kursu.
#include "extensions3.h"
//////////////////////////////////////////////////////////////////////
// deklaracje funkcji obsługujących renderning w OpenGL
//////////////////////////////////////////////////////////////////////
void DisplayScene();
void Reshape( int width, int height );
void InitScene();
void DeleteScene();
//////////////////////////////////////////////////////////////////////
// uchwyt kontekstu renderingu OpenGL
//////////////////////////////////////////////////////////////////////
HGLRC hRC3 = NULL;
//////////////////////////////////////////////////////////////////////
// uchwyt urzÄ…dzenia
//////////////////////////////////////////////////////////////////////
HDC hDC = NULL;
//////////////////////////////////////////////////////////////////////
// funkcja okna
//////////////////////////////////////////////////////////////////////
LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
// standardowy kontekst renderingu OpenGL
HGLRC hRC;
// przetwarzanie komunikatów
switch (msg)
{
// utworzenie okna
case WM_CREATE:
// utworzenie deskryptora pikseli
GLuint PixelFormat;
PIXELFORMATDESCRIPTOR pfd;
memset( &pfd, 0, sizeof( PIXELFORMATDESCRIPTOR ) );
pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR );
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
// utworzenie uchwytu urzÄ…dzenia
hDC = GetDC( hWnd );
PixelFormat = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, PixelFormat, &pfd );
// utworzenie kontekstu renderingu OpenGL
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
// utworzenie kontekstu renderingu OpenGL 3.2
wglCreateContextAttribsARB = reinterpret_cast < PFNWGLCREATECONTEXTATTRIBSARBPROC > (
wglGetProcAddress( "wglCreateContextAttribsARB" ) );
if( wglCreateContextAttribsARB )
{
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
HGLRC hRC3 = wglCreateContextAttribsARB( hDC, hRC, attribs);
wglMakeCurrent( hDC, hRC3 );
wglDeleteContext( hRC );
hRC = hRC3;
}
else
{
MessageBox( NULL, "Nie można utworzyć kontekstu OpenGL 3.2", "Błąd", MB_OK |
MB_ICONEXCLAMATION );
PostQuitMessage( 0 );
}
// konfiguracja niezbędnych rozszerzeń
OpenGL30();
// inicjacja maszyny stanów i elementów sceny
InitScene();
InvalidateRect( hWnd, NULL, TRUE );
break;
// usuwanie okna
case WM_DESTROY:
wglMakeCurrent( hDC, NULL );
DeleteScene();
wglDeleteContext( hRC3 );
ReleaseDC( hWnd, hDC );
PostQuitMessage( 0 );
break;
// zmiana rozmiaru okna
case WM_SIZE:
Reshape( LOWORD( lParam ), HIWORD( lParam ) );
InvalidateRect( hWnd, NULL, TRUE );
break;
// odrysowanie okna
case WM_PAINT:
DisplayScene();
SwapBuffers( hDC );
ValidateRect( hWnd, NULL );
break;
// automatyczne przetworzenie pozostałych komunikatów
default:
return DefWindowProc( hWnd, msg, wParam, lParam );
}
return 0L;
}
Tworzenie okna
Strukturą opisującą zawartośd okna renderingu i bufora ramki OpenGL jest
PIXELFORMATDESCRIPTOR. Jej pełny opis znajduje się w MSDN, ale na nasze potrzeby wystarczy
wypełnienie tylko kilku jej pól. Pierwsze z nich to dwFlags zawierające rodzaj okna, a także
wskazujące na obsługę OpenGL i włączenie podwójnego buforowania:
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
Trzy pozostałe pola używane w naszym szablonie określają rodzaj danych przechowywanych w
buforze ramki OpenGL. Przyjęte przez nas dane wskazuą typowy dla wspólczesnych kart graficznych
format bufora ramki z 32-bitowym opisem koloru i 24-bitowym opisem głębi:
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
W niektórych programach zawartośd bufora ramki będzie rozszerzana o inne informacje (np.
bufor szablonu). Operacje te będą odrębnie opisywane.
Następnymi etapami tworzenia okna jest wygenerowanie uchwyt urządzenia i kontekstu
renderingu OpenGL. Funkcje wglCreateContekst i wglMakeCurrent, jak wskazuje ich
prefiks, pochodzÄ… z biblioteki WGL. Pierwsza funkcja tworzy kontekst, druga dokonuje jego aktywacji.
// utworzenie uchwytu urzÄ…dzenia
hDC = GetDC( hWnd );
PixelFormat = ChoosePixelFormat( hDC, &pfd );
SetPixelFormat( hDC, PixelFormat, &pfd );
// utworzenie kontekstu renderingu OpenGL
hRC = wglCreateContext( hDC );
wglMakeCurrent( hDC, hRC );
Razem z wersją 3.0 biblioteki OpenGL został wprowadzony nowy rozbudowany kontekst. W
przypadku biblioteki WGL jego utworzenie wymaga użycia rozszerzenia WGL_ARB_create_context
lub WGL_ARB_create_context_profile. Specyfika budowy bibliotek dynamicznych obsługujących
OpenGL w systemach Microsoft Windows powoduje, że musimy pobierad wskazniki funkcji obecnych
w rozszerzeniach. Dotyczy to niestety także funkcji z biblioteki OpenGL od wersji 1.2 wzwyż. Sam
wskaznik wglCreateContextAttribsARB znajduje się w obsługującej ten mechanizm i
wspomnianej już wcześniej bibliotece extensions3.
// utworzenie kontekstu renderingu OpenGL 3.2
wglCreateContextAttribsARB = reinterpret_cast < PFNWGLCREATECONTEXTATTRIBSARBPROC > (
wglGetProcAddress( "wglCreateContextAttribsARB" ) );
Po sprawdzeniu poprawności pobranego wskaznika tworzymy nowy kontekst hRC3,
używając do tego celu starego kontekstu hRC. Koniecznośd tworzenia dwóch kontekstów jest
bezpośrednią konsekwencją pobierania wskazników funkcji, która to czynnośd wymaga aktywnego
podstawowego kontekstu OpenGL. Tablica attribs opisuje parametry kontekstu i zawiera pary
liczb: parametr i jego wartośd. W naszym przypadku tworzony jest kontekst obsługujący bibliotekę
OpenGL 3.2 z wyłączoną obsługą przestarzałej funkcjonalności.
if( wglCreateContextAttribsARB )
{
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
HGLRC hRC3 = wglCreateContextAttribsARB( hDC, hRC, attribs );
wglMakeCurrent( hDC, hRC3 );
wglDeleteContext( hRC );
hRC = hRC3;
}
else
{
MessageBox( NULL, "Nie można utworzyć kontekstu OpenGL 3.2", "Błąd", MB_OK |
MB_ICONEXCLAMATION );
PostQuitMessage( 0 );
}
Alternatywnie od wersji 3.2 biblioteki OpenGL możemy wykorzystad profile. Interesujący nas
profil podstawowy, który nie zawiera funkcjonalności określonych jako przestarzałe, wymagałby
następującego zestawu atrybutów:
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
W przypadku wyboru profilu kompatybilnego (tj. z dostępem do przestarzałej funkcjonalności
OpenGL) zamiast stałej WGL_CONTEXT_CORE_PROFILE_BIT_ARB trzeba zastosowad
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB. Biblioteka WGL musi w takim
przypadku obsługiwad rozszerzenie WGL_ARB_create_context_profile.
Po utworzeniu kontekstu pozostaje jedynie pobranie wskazników funkcji OpenGL 3.0 (szablon
nie używa funkcji z nowszych wersji), inicjacja naszej sceny oraz wymuszenie odrysowania okna.
// konfiguracja niezbędnych rozszerzeń
OpenGL30();
// inicjacja maszyny stanów i elementów sceny
InitScene();
InvalidateRect( hWnd, NULL, TRUE );
Usuwanie okna
Przy usuwaniu okna w pierwszej kolejności następuje usunięcie zasobów używanych przez
OpenGL, a następnie usuwamy sam kontekst OpenGL.
DeleteScene();
wglMakeCurrent( hDC, NULL );
wglDeleteContext( hRC3 );
ReleaseDC( hWnd, hDC );
PostQuitMessage( 0 );
Zmiana rozmiaru okna
Przy zmianie rozmiaru okna przekazujemy do funkcji Reshape rozmiary nowego okna, które
są dostępne jako parametry funkcji obsługującej komunikaty.
Reshape( LOWORD( lParam ), HIWORD( lParam ) );
InvalidateRect( hWnd, NULL, TRUE );
Odrysowanie okna
Odrysowanie okna sprowadza się do wywołania funkcji rysującej scenę OpenGL i zamiany
buforów koloru zawartych w buforze ramki.
DisplayScene();
SwapBuffers( hDC );
ValidateRect( hWnd, NULL );
Szablon aplikacji OpenGL dla X Window Serwer
Przy tworzeniu szablonu aplikacji OpenGL dla X Window Serwer użyjemy najbardziej
podstawowej biblioteki Xlib oraz biblioteki pomocniczej Xpmlib (do obsługi ikony okna w formacie
XPM). Schemat budowy programu nie odbiega znaczÄ…co od szablonu aplikacji dla WIN32. W funkcji
main tworzymy okno, a w odrębnej funkcji okna przetwarzamy komunikaty skierowane do aplikacji
przez X Serwer.
Tworzenie okna
Tworzenie okna aplikacji podzielone jest na kilka etapów. W pierwszym tworzymy urządzenie
wyświetlające o odpowiednich parametrach (w przyszłych programach będziemy niekiedy te
parametry zmieniad). Pózniej tworzymy kontekst renderingu OpenGL przy użyciu funkcji
glXCreateContextAttribsARB z rozszerzeo GLX_ARB_create_context i
GLX_ARB_create_context_profile, przy użyciu tablicy atrybutów attribs. Tablica attribs
opisuje parametry kontekstu i zawiera pary liczb: parametr i jego wartośd. W naszym przypadku
tworzony jest kontekst obsługujący bibliotekę OpenGL 3.2 z wyłączoną obsługą przestarzałej
funkcjonalności. Następnie tworzone jest okno i dodawana jego ikona zawarta w pliku opengl.xpm .
Cały kod tworzący okno z kontekstem renderingu OpenGL znajduje się poniżej.
#include "extensions3.h"
#include "opengl.xpm"
#include
#include
#include
#include
//////////////////////////////////////////////////////////////////////
// deklaracje funkcji obsługujących renderning w OpenGL
//////////////////////////////////////////////////////////////////////
void DisplayScene();
void Reshape( int width, int height );
void InitScene();
void DeleteScene();
&
// utworzenie urządzenia wyświetlającego
Display *display = XOpenDisplay( 0 );
int attrList[] =
{
GLX_RGBA,
GLX_DOUBLEBUFFER,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_DEPTH_SIZE, 24,
None
};
XVisualInfo *visual = glXChooseVisual( display, 0, attrList );
// utworzenie kontekstu renderingu OpenGL
int nelements;
GLXFBConfig *fbc = glXChooseFBConfig( display, DefaultScreen( display ), 0, &nelements );
int attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
0
};
GLXContext ctx = glXCreateContextAttribsARB( display, *fbc, 0, true, attribs );
// utworzenie okna X Window
XSetWindowAttributes attr;
attr.colormap = XCreateColormap( display, RootWindow( display, visual -> screen ), visual ->
visual, AllocNone );
attr.border_pixel = 0;
attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask |
PointerMotionMask | StructureNotifyMask;
Window window = XCreateWindow( display, RootWindow( display, visual -> screen ),
0, 0, 512, 512, 0, visual -> depth, InputOutput, visual -> visual, CWBorderPixel |
CWColormap | CWEventMask, &attr );
Atom wmDelete = XInternAtom( display, "WM_DELETE_WINDOW", true );
XSetWMProtocols( display, window, &wmDelete, 1 );
XSetStandardProperties( display, window, "OpenGL 3.2 - szablon OpenGL", "OpenGL 3.2 - szablon
OpenGL", None, NULL, 0, NULL );
XMapRaised( display, window );
glXMakeCurrent( display, window, ctx );
// dodanie ikony okna
Pixmap icon, mask;
XpmCreatePixmapFromData( display, window, GLicon, &icon, &mask, NULL );
XWMHints winHints;
winHints.flags = IconPixmapHint;
winHints.icon_pixmap = icon;
winHints.icon_mask = mask;
XSetWMHints( display, window, &winHints );
Podobnie jak w przypadku aplikacji w systemie Windows od wersji 3.2 biblioteki OpenGL
możemy wykorzystad profile. Profil podstawowy wymagałby następującego zestawu atrybutów:
int attribs[] =
{
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
GLX_CONTEXT_MINOR_VERSION_ARB, 2,
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
0
};
W przypadku wyboru profilu kompatybilnego, zamiast stałej
GLX_CONTEXT_CORE_PROFILE_BIT_ARB trzeba zastosowad
GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB. Biblioteka GLX musi w tym przypadku
obsługiwad rozszerzenie GLX_ARB_create_context_profile.
Po utworzeniu okna pozostaje jeszcze inicjacja maszyny stanów OpenGL. Zauważmy, że nie
musimy wcześniej pobierad wskazników funkcji OpenGL:
// inicjacja maszyny stanów OpenGL
InitScene();
Przetwarzanie komunikatów X Serwera
Wywołanie funkcji przetwarzającej komunikaty X Serwera wykonywane jest bezpośrednio w
funkcji main programu:
// pętla przetwarzania komunikatów
WindowProc( display, window );
Popatrzmy zatem na samą funkcję okna. Zawiera ona nieskooczoną pętlę, którą przerywa
wystąpienie specjalnego komunikatu oznaczającego zamknięcie okna programu. Pozostałe elementy
wnętrza pętli są odpowiednikami przedstawionej wcześniej funkcji okna w WIN32. Jedyna zasadnicza
różnica polega na braku obsługi tworzenia i usuwania elementów sceny OpenGL, które wykonywane
są odpowiednio przed i po wywołaniem funkcji okna. W przyszłych programach poniższa funkcja
będzie w razie potrzeby rozbudowywana o kolejne elementy.
//////////////////////////////////////////////////////////////////////
// funkcja okna
//////////////////////////////////////////////////////////////////////
void WindowProc( Display *display, Window window )
{
// przetwarzanie komunikatów
bool running = true;
while( running )
{
while( XPending( display ) > 0 )
{
XEvent event;
XNextEvent( display, &event );
switch( event.type )
{
// zmiana rozmiaru okna
case ConfigureNotify:
Reshape( event.xconfigure.width, event.xconfigure.height );
break;
// zamknięcie okna
case ClientMessage:
if( *XGetAtomName( display, event.xclient.message_type ) ==
*"WM_PROTOCOLS" )
{
running = false;
}
break;
// pominęcie pozostałych komunikatów
default:
break;
}
}
// odrysowanie okna
DisplayScene();
glXSwapBuffers( display, window );
}
}
Zakmnięcie okna i zakończenie programu
Kooczenie pracy programu wykonywane jest już po powrocie z funkcji okna i sprowadza się
do usunięcia elementów sceny OpenGL i kontekstu renderingu OpenGL. Na koocu zamykane jest
okno programu.
// zamknięcie okna
DeleteScene();
glXMakeCurrent( display, None, NULL );
glXDestroyContext( display, ctx );
XCloseDisplay( display );
// koniec programu
return 0;
Plik makefike
Przedstawimy jeszcze plik makefile służący do kompilacji szablonu programu. Zauważmy, że
wszystkie pliki bibliotek pomocniczych znajdujÄ… siÄ™ w katalogu common.
PROJECT= szablon
SOURCES= szablon.cpp glx_main.cpp ../common/extensions3.cpp
OBJECTS= szablon.o glx_main.o extensions3.o
CC= g++
$(PROJECT): $(OBJECTS)
$(CC) -I../common -O2 -g $(OBJECTS) -L/usr/X11R6/lib -lm -lGL -lXpm -lXxf86vm -o
$(PROJECT)
@echo Compilation Complete
$(OBJECTS): $(SOURCES)
@echo Compiling Sources
$(CC) -I../common -O2 -Wall -ansi -pedantic -g -c $(SOURCES)
clean:
@echo Deleting up $(OBJECTS) $(PROJECT)
rm -f *.o;rm $(PROJECT)
Biblioteka pomocnicza extensions3
Biblioteka pomocnicza extensions3 składa się z dwóch plików (extensions3.h i
extensions3.cpp) i przede wszystkim zawiera definicje wskazników funkcji biblioteki OpenGL w wersji
3.0, 3.1 i 3.2. Wskazniki te są niezbędne do działania programów w systemach Microsoft Windows. W
systemach z rodziny UNIX/Linux operacje te nie są niezbędne, ale biblioteka także jest
wykorzystywana.
Biblioteka korzysta z trzech podstawowych plików nagłówkowych: gl3.h, wglext.h i glxext.h
dostępnych na stronie domowej OpenGL pod adresem http://www.opengl.org/registry/.
Obsługa WGL i wskazników funkcji w systemach Microsoft Windows
Początek pliku nagłówkowego biblioteki extensions3 w części obsługującej OpenGL i WGL w
systemach Microsoft Windows zawiera włączenie standardowych plików nagłówkowych:
#include "gl3.h"
#include "wglext.h"
Potem musimy ponownie włączyd plik gl3.h, ale w taki sposób aby uzyskad deklaracje tych
funkcji OpenGL z wersji 1.0 i 1.1, używanych także w wersji 3.0 - 3.2, do których nie musimy pobierad
wskazników (o pobieraniu wskazników funkcji wspominaliśmy już podczas opisu szablonu aplikacji
przy tworzeniu kontekstu OpenGL). Wprawdzie deklaracje te zawiera stary plik nagłówkowy
biblioteki OpenGL (gl.h) ale jego użycie nie jest zalecane, gdy nie korzystamy z przestarzałej
funkcjonalności OpenGL.
//////////////////////////////////////////////////////////////////////
// prototypy funkcji z OpenGL 1.0 i OpenGL 1.1
// (do tych funkcji nie sÄ… potrzebne wskazniki)
//////////////////////////////////////////////////////////////////////
#ifndef __gl_h_
#ifndef __GL_H__
#ifdef __cplusplus
extern "C" {
#endif
#undef __gl3_h_
#define GL3_PROTOTYPES
#undef GL_VERSION_1_0
#undef GL_VERSION_1_1
#include "gl3.h"
#undef GL3_PROTOTYPES
#ifdef __cplusplus
}
#endif
#endif
#endif
Potem następują kolejne definicje zmiennych globalnych - wskazników funkcji pochodzących
z różnych wersji biblioteki OpenGL i jej rozszerzeo. Na początku znajduje się wskaznik do funkcji
wglCreateContextAttribsARB którą używaliśmy przy tworzeniu kontekstu OpenGL. Z uwagi
na dużą objętośd tej części pliku prezentujemy początek definicji wskazników i koocówkę pliku z
deklaracjami funkcji pobierajÄ…cymi wskazniki.
//////////////////////////////////////////////////////////////////////
// funkcja z rozszerzenia WGL_ARB_create_context
//////////////////////////////////////////////////////////////////////
extern PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB;
//////////////////////////////////////////////////////////////////////
// funkcje z OpenGL 1.2
//////////////////////////////////////////////////////////////////////
extern PFNGLBLENDCOLORPROC glBlendColor;
extern PFNGLBLENDEQUATIONPROC glBlendEquation;
extern PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements;
extern PFNGLTEXIMAGE3DPROC glTexImage3D;
extern PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D;
extern PFNGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D;
&
//////////////////////////////////////////////////////////////////////
// pobranie wskazników do funkcji z OpenGL 3.0
//////////////////////////////////////////////////////////////////////
bool OpenGL30();
//////////////////////////////////////////////////////////////////////
// pobranie wskazników do funkcji z OpenGL 3.1
//////////////////////////////////////////////////////////////////////
bool OpenGL31();
//////////////////////////////////////////////////////////////////////
// pobranie wskazników do funkcji z OpenGL 3.2
//////////////////////////////////////////////////////////////////////
bool OpenGL32();
Plik zródłowy extensions3.cpp zawiera już właściwe definicje wskazników funkcji oraz
implementacje funkcji (ponownie przedstawiamy jedynie wybrane fragmenty pliku):
//////////////////////////////////////////////////////////////////////
// wskaznik funkcji pochodzÄ…cej z rozszerzenia WGL_ARB_create_context
//////////////////////////////////////////////////////////////////////
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
//////////////////////////////////////////////////////////////////////
// wskazniki funkcji pochodzÄ…cych z OpenGL 1.2
//////////////////////////////////////////////////////////////////////
PFNGLBLENDCOLORPROC glBlendColor = NULL;
PFNGLBLENDEQUATIONPROC glBlendEquation = NULL;
PFNGLDRAWRANGEELEMENTSPROC glDrawRangeElements = NULL;
PFNGLTEXIMAGE3DPROC glTexImage3D = NULL;
PFNGLTEXSUBIMAGE3DPROC glTexSubImage3D = NULL;
PFNGLCOPYTEXSUBIMAGE3DPROC glCopyTexSubImage3D = NULL;
&
//////////////////////////////////////////////////////////////////////
// pobranie wskazników do funkcji z OpenGL 3.0
//////////////////////////////////////////////////////////////////////
bool OpenGL31()
{
// sprawdzenie numeru wersji
if( OpenGLVersion() < 31 )
return false;
// pobranie wskazników
glDrawArraysInstanced = reinterpret_cast < PFNGLDRAWARRAYSINSTANCEDPROC > (
wglGetProcAddress( "glDrawArraysInstanced" ) );
glDrawElementsInstanced = reinterpret_cast < PFNGLDRAWELEMENTSINSTANCEDPROC > (
wglGetProcAddress( "glDrawElementsInstanced" ) );
glTexBuffer = reinterpret_cast < PFNGLTEXBUFFERPROC > ( wglGetProcAddress( "glTexBuffer" )
);
glPrimitiveRestartIndex = reinterpret_cast < PFNGLPRIMITIVERESTARTINDEXPROC > (
wglGetProcAddress( "glPrimitiveRestartIndex" ) );
// pobranie wskazników - rozszerzenie ARB_uniform_buffer_object
glGetUniformIndices = reinterpret_cast < PFNGLGETUNIFORMINDICESPROC > ( wglGetProcAddress(
"glGetUniformIndices" ) );
glGetActiveUniformsiv = reinterpret_cast < PFNGLGETACTIVEUNIFORMSIVPROC > (
wglGetProcAddress( "glGetActiveUniformsiv" ) );
glGetActiveUniformName = reinterpret_cast < PFNGLGETACTIVEUNIFORMNAMEPROC > (
wglGetProcAddress( "glGetActiveUniformName" ) );
glGetUniformBlockIndex = reinterpret_cast < PFNGLGETUNIFORMBLOCKINDEXPROC > (
wglGetProcAddress( "glGetUniformBlockIndex" ) );
glGetActiveUniformBlockiv = reinterpret_cast < PFNGLGETACTIVEUNIFORMBLOCKIVPROC > (
wglGetProcAddress( "glGetActiveUniformBlockiv" ) );
glGetActiveUniformBlockName = reinterpret_cast < PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC > (
wglGetProcAddress( "glGetActiveUniformBlockName" ) );
glUniformBlockBinding = reinterpret_cast < PFNGLUNIFORMBLOCKBINDINGPROC > (
wglGetProcAddress( "glUniformBlockBinding" ) );
// pobranie wskazników - rozszerzenie ARB_copy_buffer
glCopyBufferSubData = reinterpret_cast < PFNGLCOPYBUFFERSUBDATAPROC > ( wglGetProcAddress(
"glCopyBufferSubData" ) );
// sukces
return true;
}
&
Funkcje OpenGLVersion i OpenGLExtension opisane sÄ… na koocu niniejszego punktu.
Obsługa OpenGL i GLX w systemach UNIX/Linux
Obsługa bibliotek OpenGL i GLX w systemach UNIX/Linux sprowadza się do odpowiedniego
włączenia trzech plików nagłówkowych. Standardowy plik gl3.h jest włączany z definicją
preprocesora GL3_PROTOTYPES gwarantującą bezpośredni dostęp do deklaracji funkcji OpenGL.
Pózniej włączamy plik nagłówkowy biblioteki GLX (przyjmujemy, że znajduje się on w standardowym
miejscu). Na koniec włączamy plik glxext.h zawierających definicje rozszerzeo biblioteki GLX.
Zaprezentowane poniżej polecenia preprocesora zapewniają dostęp do deklaracji funkcji rozszerzeo,
niezależnie od tego jaka wersja tego pliku znajduje się w systemie (plik glxext.h jest włączany przez
plik glx.h).
#define GL3_PROTOTYPES
#include "gl3.h"
#undef GL3_PROTOTYPES
#define GL_GLEXT_LEGACY
#include
#undef __glxext_h_
#undef GLX_GLXEXT_VERSION
#undef GLX_ARB_create_context
#define GLX_GLXEXT_PROTOTYPES
#include "glxext.h"
#undef GLX_GLXEXT_PROTOTYPES
Pozostałe elementy biblioteki
Biblioteka extensions3 zawiera także trzy funkcje pomocnicze: pobierającą numer wersji
OpenGL i GLSL oraz sprawdzającą dostępnośd wybranego rozszerzenia. Poniżej prezentujemy ich
pełny kod zródłowy:
//////////////////////////////////////////////////////////////////////
// pobranie numeru wersji biblioteki OpenGL
// numer wersji pomnożony przez 10
//////////////////////////////////////////////////////////////////////
int OpenGLVersion()
{
int major = 0, minor = 0;
glGetIntegerv( GL_MAJOR_VERSION, &major );
glGetIntegerv( GL_MINOR_VERSION, &minor );
return 10*major + minor;
}
//////////////////////////////////////////////////////////////////////
// sprawdzenie obsługi rozszerzenia biblioteki OpenGL
// extName - nazwa sprawdzanego rozszerzenia OpenGL
//////////////////////////////////////////////////////////////////////
bool OpenGLExtension( const char *extName )
{
GLint numExt;
glGetIntegerv( GL_NUM_EXTENSIONS, &numExt );
for( int i = 0; i < numExt; i++ )
if( std::string( reinterpret_cast< const char* >( glGetStringi( GL_EXTENSIONS, i ) ) )
== std::string ( extName ) )
return true;
return false;
}
//////////////////////////////////////////////////////////////////////
// sprawdzenie wersji języka GLSL; numer wersji pomnożony przez 100
//////////////////////////////////////////////////////////////////////
int GLSLVersion()
{
// pobranie numery wersji GLSL
std::stringstream version( std::stringstream::in | std::stringstream::out );
version << reinterpret_cast< const char* >( glGetString( GL_SHADING_LANGUAGE_VERSION ) );
if( glGetError() != GL_NO_ERROR ) return 0;
// numer wersji pomnożony przez 100
int major = 0, minor = 0;
char dot;
version >> major;
if( version.fail() )return 0;
version >> dot;
if( version.fail() || dot != '.' ) return 0;
version >> minor;
if( version.fail() ) return 0;
return 100*major + minor;
}
Teraz opiszemy krótko użyte w powyższych funkcjach elementy biblioteki OpenGL. Zmienne
stanu GL_MAJOR_VERSION i GL_MINOR_VERSION zawierajÄ… numer wersji i podwersji
implementacji OpenGL. Dwie użyte funkcje OpenGL:
const GLubyte *glGetString( GLenum name );
const GLubyte *glGetStringi( GLenum name, GLuint index );
zwracają bardziej rozbudowane informacje o bieżącej implementacji biblioteki OpenGL. Dane
zwracane przez funkcję glGetString zależą od wartości parametru name:
·ð GL_VENDOR - autor implementacji OpenGL,
·ð GL_RENDERER - nazwa urzÄ…dzenia renderujÄ…cego, np. karty graficznej,
·ð GL_VERSION - numer wersji implementacji OpenGL w formacie: . lub
.. oraz opcjonalnie po pojedynczej spacji informacja o
producencie biblioteki,
·ð GL_SHADING_LANGUAGE_VERSION numer wersji GLSL - jÄ™zyka cieniowania OpenGL,
zwracany w formacie takim samym jak dla parametru GL_VERSION.
Zauważmy, że OpenGL zawiera dwa mechanizmy pozwalające na sprawdzenie numeru wersji i
podwersji implementacji biblioteki.
Funkcja glGetStringi zwraca informację o rozszerzeniach obsługiwanych przez
implementację OpenGL. Nazwa każdego obsługiwanego rozszerzenia podawana jest odrębnie
poprzez wskazanie numeru indeksu w parametrze index, a łączną ilośd rozszerzeo zawiera zmienna
stanu GL_NUM_EXTENSIONS. Jedyną dopuszczalną wartością parametru name funkcji
glGetStringi jest stała GL_EXTENSIONS.
Obie prezentowane funkcje zwracają ciągi znaków w kodowaniu UTF-8 zakooczone znakiem
NULL (zerem).
Podstawowe elementy programu w OpenGL
Przedstawione poniżej cztery funkcje będą stałym elementem każdego programu z kursu
biblioteki OpenGL, chod oczywiście różna będzie ich zawartośd. Poznamy także funkcje biblioteki
OpenGL wykorzystane w szablonie.
Inicjacja maszyny stanu OpenGL
To pierwszy element programu korzystającego z biblioteki OpenGL. Z założenia wykonywany
jest jednokrotnie i obejmuje tylko te elementy ustawieo OpenGL, które nie będą się zmieniały (lub
będą zmieniane sporadycznie) w trakcie działania programu. W szablonie umieściliśmy wywołanie
tylko jednej funkcji OpenGL
void glClearColor( GLclampf red, GLclampf green, GLclampf blue,
GLclampf alpha );
która ustala składowe RGBA koloru czyszczącego bieżącego bufora koloru, co w programie
przedkłada się na kolor tła okna.
//////////////////////////////////////////////////////////////////////
// inicjalizacja stałych elementów maszyny stanu OpenGL
//////////////////////////////////////////////////////////////////////
void InitScene()
{
// kolor tła - zawartość bufora koloru
glClearColor( 1.0f, 1.0f, 1.0f, 1.0f );
}
Generowanie sceny 3D
W szablonie programu OpenGL nie są generowane żadne elementy sceny. Wykonywane jest
tylko czyszczenie bieżącego bufora koloru i wymuszane jest wykonanie wszystkich wywołanych
poleceo OpenGL. Efektem będzie puste okno o kolorze tła określonym w poprzednio opisanej funkcji
szablonu.
//////////////////////////////////////////////////////////////////////
// funkcja generujÄ…ca scenÄ™ 3D
//////////////////////////////////////////////////////////////////////
void DisplayScene()
{
// czyszczenie bufora koloru
glClear( GL_COLOR_BUFFER_BIT );
// skierowanie poleceń do wykonania
glFlush();
}
Pierwsza z użytych funkcji:
void glClear( GLbitfield mask );
zawiera maskę bitową z wartościami wskazującymi, które bufory są czyszczone. Wartości te wynoszą:
GL_COLOR_BUFFER_BIT, GL_DEPTH_BUFFER_BIT, GL_STENCIL_BUFFER_BIT i wskazujÄ…
odpowiednio aktualnie aktywne do zapisu bufory koloru, bufor głębokości i bufor szablonu. Stałe te
mogÄ… byd Å‚Ä…czone za pomocÄ… operatora |.
Druga funkcja:
void glFlush( void );
określa, że wszystkie polecenia OpenGL, które zostały wcześniej wywołane muszą zostad wykonane w
skooczonym czasie. Działanie to dobrze określa słowo wymiatanie będące bezpośrednim
tłumaczeniem angielskiej nazwy funkcji. Podobną rolę wykonuje polecenie
void glFinish( void );
które wymusza wykonanie wszystkich poprzednich poleceo OpenGL. W odróżnieniu od funkcji
glFlush, glFinish nie zakooczy się dopóki wszystkie efekty wcześniej wydanych poleceo dla
zmiennych stanu klienta i serwera OpenGL oraz bufora ramki nie zostaną w pełni zrealizowane.
Zmiana wielkości okna
Typowym zdarzeniem, które występuje w programach okienkowych jest zmiana rozmiaru
okna. W przypadku biblioteki OpenGL obsługa takiego zdarzenia wymaga nie tylko odrysowania
okna. Niezbędne jest także podjęcie decyzji o modyfikacji (lub nie) wielkości obszaru renderingu, czyli
przestrzeni okna wykorzystywanej przez OpenGL.
Obszar renderingu określa zastosowana w szablonie funkcja:
void glViewport( GLint x, GLint y, GLsizei width, GLsizei height );
której parametry oznaczają:
·ð x, y - współrzÄ™dne lewego dolnego narożnika obszaru renderingu wzglÄ™dem lewego dolnego
narożnika okna,
·ð width - szerokoÅ›d okna renderingu,
·ð height - wysokoÅ›d okna renderingu.
Początkowo obszar renderingu zajmuje całe okno udostępnione dla aplikacji OpenGL. W szablonie
programu glViewport określa za każdym razem obszar renderingu tak, aby obejmował on całe
okno.
//////////////////////////////////////////////////////////////////////
// zmiana wielkości okna
//////////////////////////////////////////////////////////////////////
void Reshape( int width, int height )
{
// obszar renderingu - całe okno
glViewport( 0, 0, width, height );
}
Wspomnijmy jeszcze, że parametry funkcji Reshape określają odpowiednio nową szerokośd
i wysokośd okna i są określane na podstawie danych przekazywanych przez system okienkowy.
Usunięcie elementów sceny 3D
Ostatnia funkcja szablnu jest odpowiedzialna za usunięcie elementów sceny OpenGL, które
nie zostały wcześniej zniszczone. W szczególności mogą to byd elementy tworzone w funkcji
InitScene. Ponieważ w szabolnie nie mamy takich elementów, wnętrze funkcji pozostaje puste.
//////////////////////////////////////////////////////////////////////
// usunięcie obiektów OpenGL
//////////////////////////////////////////////////////////////////////
void DeleteScene()
{
}
WyglÄ…d okna programu
Poniżej znajdują się zrzuty ekranu przedstawiające okna programu szablonu aplikacji OpenGL
w obu systemach operacyjnych wykorzystywanych w kursie.
Rysunek 1 Okno szablonu OpenGL (WIN32) Rysunek 2 Okno szablonu OpenGL (Linux)
Wyszukiwarka
Podobne podstrony:
Smarty Szablony w aplikacjach PHP smarty
NeHe Productions OpenGL Article #02
2006 02 Qt ISO Maker–moja pierwsza aplikacja w Qt [Programowanie]
opengl przeksztalcenia geometryczne
OpenGL narzędzie dla bardzo ambitnych
Grafika komputerowa i OpenGL
Modelowanie oświetlenia w OpenGl
opengl podstawy
OPENGL ZajOpenGLok
opengl?finiowanie sceny=
Modelowanie oświetlenia z wykorzystaniem OpenGL
opengl
Using Opengl In Visual C
Multitexturing w OpenGL
Multitexturing w OpenGL
więcej podobnych podstron