Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Autor: Janusz Ganczarski
Biblioteki C++

Podstawy

[kategoria] Rozdział 1. Podstawowe informacje o bibliotece OpenGL, składnia funkcji, typy danych oraz teoria ogólna związana z niniejszą biblioteką.

Podstawy

Pierwsza wersja biblioteka OpenGL (ang. Open Graphics Library) powstała w 1992 roku na bazie języka GL opracowanego przez firmę Silicon Graphics Inc. (w skrócie SGI) na potrzeby stacji graficznych IRIS. Dopiero jednak sukces systemów z rodziny Microsoft Windows, w których zaimplementowano OpenGL w wersji 1.1, stał się początkiem ogromnej popularności biblioteki. Obecnie OpenGL jest podstawowa niskopoziomowa biblioteka graficzna 3D, obsługiwana przez wszystkie liczące się systemy operacyjne oraz większość procesorów graficznych.

Niezależność od platformy sprzętowej oraz ogólnie dostępna specyfikacji czyni z OpenGL standard powszechnie wykorzystywany przez producentów oprogramowania użytkowego i gier. Rozwojem OpenGL zajmuje się organizacja ARB (ang. Architecture Review Board), w skład której wchodzą przedstawiciele firm 3DLabs, Apple, ATI, Dell, IBM, Intel, NVIDIA, SGI i Sun (stan na koniec 2004 roku). Taki sposób wprowadzania zmian w bibliotece zapewnia zachowanie niezależności OpenGL od jednej platformy sprzętowej lub programowej przy jednoczesnym uwzględnieniu do najnowszych osiągnięć w dziedzinie grafiki komputerowej. Materiały ze spotkań członków ARB, specyfikacje i szeregu innych materiałów na temat OpenGL dostępne są na oficjalnej stronie ARB: http://www.opengl.org/. Ważnym uzupełnieniem OpenGL jest biblioteka GLU (ang. OpenGL Graphics System Utility Library). GLU zawiera szereg dodatkowych narzędzi, w tym do obsługi macierzy, odwzorowania tekstur, kafelkowania wielokątów, powierzchni drugiego stopnia oraz krzywych i powierzchni NURBS.

Składnia

Polecenia OpenGL określane są jako funkcje lub procedury. Znaczna część funkcji wykonuje te same operacje, ale rożni się zbiorem argumentów. Przyjęta konwencja nazewnictwa określa ilość i rodzaj parametrów funkcji według poniższego schematu:
rtype Name {1|2|3|4} {b|s|i|f|d|ub|us|ui} {v}
([args,] T arg1, ..., T argN [,args])
gdzie poszczególne elementy oznaczają:
rtypewartość zwracana przez funkcje.
Namenazwa funkcji poprzedzona przedrostkiem gl lub glu dla funkcji z biblioteki GLU.
1, 2, 3, 4ilość argumentów funkcji.
bargumenty typu GLbyte.
sargumenty typu GLshort.
iargumenty typu GLint.
fargumenty typu GLfloat.
dargumenty typu GLdouble.
ubargumenty typu GLubyte.
usargumenty typu GLushort.
uiargumenty typu GLuint.
vargument funkcji stanowi tablica wartości - w tym wypadku nie występuje określenie ilości argumentów funkcji.
T arg1, ..., T argNargumenty funkcji.
Składnia ta przypomina w swoich założeniach notacje węgierska, stosowana m.in. w API systemów z rodziny Windows. Może ona początkowo sprawiać problemy, ale przy pewnej praktyce okazuje się praktyczna i wygodna w stosowaniu. Podobnie jak w specyfikacja biblioteki OpenGL ta i dalsza
część opisu wykorzystuje notacje przyjęta w języku ANSI C.

Typy danych

Poniższa tabela zawiera typy danych dostępne w bibliotece OpenGL.

Tabela 1: Typy danych w OpenGL

typ OpenGLminimalna
ilość
bitów
opis
GLboolean1typ logiczny
GLbyte8liczba całkowita ze znakiem (U2)
GLubyte8liczba całkowita bez znaku
GLchar8ciąg znaków tekstowych
GLshort16liczba całkowita ze znakiem (U2)
GLushort16liczba całkowita bez znaku
GLint32liczba całkowita ze znakiem (U2)
GLuint32liczba całkowita bez znaku
GLsizei32nieujemna liczba całkowita
GLenum32typ wyliczeniowy całkowity
GLintptrptrbitswskaźnik na liczbę całowitą ze znakiem (U2)
GLsizeiptrptrbitswskaźnik na nieujemna liczbę całkowita
GLbitfield32pole bitowe
GLfloat32liczba zmiennoprzecinkowa
GLclampf32liczba zmiennoprzecinkowa z przedziału [0, 1]
GLdouble64liczba zmiennoprzecinkowa
GLclampd64liczba zmiennoprzecinkowa z przedziału [0, 1]
Specyfikacja nie określa jakiego rodzaju typy danych są użyte w konkretnej implementacji biblioteki OpenGL. W szczególnosci typy danych OpenGL nie są typami danych występującymi w języku C (pomimo częściowej zgodności nazw). Implementacja OpenGL może stosować typy danych zawierające większą niż minimalna ilość bitów. prtbits oznacza minimalna ilość bitów niezbędna do umieszczenia wskaźnika Stad typy intptr i sizeiptr muszą umożliwić zapamiętanie dowolnego adresu. Poza wyżej wymienionymi typami danych biblioteka OpenGL zawiera typ pusty GLvoid.

Układ współrzędnych

Biblioteka OpenGL stosuje prawoskrętny układ współrzędnych kartezjańskich (patrz rysunek 1), w którym os OZ skierowana jest prostopadle do płaszczyzny monitora. Warto także pamiętać, ze literatura informatyczna preferuje lewoskrętne układy współrzędnych z osia OZ skierowana w głąb monitora.
Rysunek 1. Układ współrzędnych w OpenGL
Rysunek 1. Układ współrzędnych w OpenGL

Barwy

Biblioteka OpenGL wykorzystuje model barw RGB, opierający się na trzech podstawowych barwach: czerwonej, zielonej i niebieskiej. Barwa może być opisywana bezpośrednio przez wartości składowych RGB, bądź w trybie indeksowym z użyciem mapy (tablicy) barw. Obecne możliwości procesorów graficznych czynią stosowanie trybu indeksowego nieopłacalnym, stad w przykładowych programach będziemy używać pełnego zakresu barw oferowanego przez model RGB, w razie potrzeby uzupełniając składowe RGB o kanał alfa (RGBA). Wybór trybu w jakim będzie generowany obraz dokonywany jest podczas tworzenia okna renderingu.

Bufor ramki

W OpenGL w skład bufora ramki (pamięci obrazu) wchodzą następujące elementy:
  • bufor koloru (ang. color buffer),
  • bufor głębokości, nazywany także buforem głębi (ang. depth buffer),
  • bufor szablonowy, nazywany także buforem szablonu (ang. stencil buffer),
  • bufor akumulacyjny (ang. accumulation buffer).
Specyfikacja wymaga istnienie co najmniej jednego bufora koloru, ale implementacje biblioteki OpenGL zawierają najczęściej dwa bufory koloru: przedni i tylni. Zamiana buforów umożliwia płynne wyświetlenie animacji - jeden bufor jest aktualnie prezentowany na ekranie monitora, a drugi służy do generowania nowej sceny 3D. Ponadto implementacja OpenGL może zawierać lewe i prawe bufory koloru, które umożliwiają tworzenie obrazów stereoskopowych. Bufor głębokości używany jest podczas działania algorytmu Z-bufor, którego zadaniem jest ukrywanie niewidocznych powierzchni. Bufor szablonu służy do ograniczenia obszaru renderingu do wybranej części okna i w implementacjach często jest łączony z buforem głębokości Ostatni z wymienionych elementów ramki - bufor akumulacyjny, umożliwia łączenie kilku obrazów w celu uzyskania określonego efektu końcowego Wybór, które bufory wchodzą w skład ramki dokonuje się podczas tworzenia okna renderingu.

Okno renderingu

Jedna z konsekwencji sprzętowej i systemowej niezależności biblioteki OpenGL jest brak jakichkolwiek funkcji obsługujących komunikacje z użytkownikiem, w tym obsługi okien, klawiatury i myszki. Większość graficznych systemów operacyjnych posiada jednak specjalizowane funkcje pozwalające na obsługę okna renderingu OpenGL. Przykładowo X Windows zawiera bibliotekę GLX, Microsoft Windows bibliotekę WGL, IBM OS/2 bibliotekę PGL, a Mac OS X aż trzy biblioteki: AGL, CGL i NSGL. Także systemy wbudowane, korzystające ze znacznie skromniejszej biblioteki OpenGL ES (ang. OpenGL Embedded Systems), zawierają bibliotekę narzędziową EGL. Oczywiście stosowanie rozwiązań specyficznych dla danego systemu operacyjnego powoduje, ze danego programu nie można skompilować i uruchomić w innym systemie operacyjnym bez dokonania szeregu zmian w tekście źródłowym Rozwiązanie tego problemu stanowią biblioteki oferujące jeden, niezależny od systemu operacyjnego, interfejs do obsługi okien i komunikatów.

Pierwsza biblioteka tego typu była biblioteka AUX (ang. Auxiliary Library), zwana także pod nazwa GLAUX. Przy jej pomocy zostały napisane m.in. przykłady z pracy [3]. Jednak największą popularność zdobyła biblioteka GLUT (ang. OpenGL Utility Toolkit), opracowana i rozwijana w latach 1994-1998 przez Marka J. Kilgarda. Jej autor rozwinął idee zapoczątkowane przez twórców biblioteki AUX, co ułatwia konwersje programów korzystających z tej biblioteki (patrz skrypt aux2glut.sed). Bibliotek GLUT, choć od kilku lat nie rozwijana (ostatnia wersja to 3.6), jest ciągle najbardziej popularna i powszechnie stosowana wieloplatformowa biblioteka służąca do uruchamiania programów w OpenGL. Stad naturalna decyzja o wyborze tej biblioteki przy pisaniu przykładowych programów.

Maszyna stanów

Maszyna stanów OpenGL to po prostu zbiór wszystkich zmiennych wewnętrznych (zmiennych stanu) i ustawień biblioteki. Wiele zmiennych stanu jest dwustanowych, inne maja wartości całkowite lub zmiennoprzecinkowe. Ważna cecha maszyny stanów OpenGL jest zachowywanie zmiennych stanu do czasu, aż zostaną one zmienione przez jakąś funkcje. Pozwala to na prosta optymalizacje programów poprzez oddzielenie i jednokrotne wywołanie grupy funkcji ustawiających wartości tych zmiennych stanu, które nie ulegają dalszym zmianom.

Obsługa błędów

Ważne znaczenie w bibliotece OpenGL spełniają zmienne stanu oznaczające wystąpienie błędu Informacje o kodzie bieżącego błędu zwraca funkcja:
C/C++
GLenum glGetError( void )
Oto znaczenie poszczególnych kodów błędów:
  • GL_NO_ERROR - brak błędu,
  • GL_INVALID_ENUM - argument typu wyliczeniowego poza dopuszczalnym zakresem,
  • GL_INVALID_VALUE - argument liczbowy poza dopuszczalnym zakresem,
  • GL_INVALID_OPERATION - operacja niewykonalna w obecnym stanie,
  • GL_STACK_OVERFLOW - operacja spowodowałaby przepełnienie stosu,
  • GL_STACK_UNDERFLOW - operacja spowodowałaby niedomiar stosu,
  • GL_OUT_OF_MEMORY - brakuje pamięci do wykonania operacji,
  • GL_TABLE_TOO_LARGE - wskazana tablica jest za duża.
Wystąpienie błędu nie powoduje przerwania wykonywania programu - nie jest wykonywana jedynie funkcja odpowiedzialna za jego powstanie. Wyjątek stanowi wystąpienie błędu o kodzie GL_OUT_OF_MEMORY, który powoduje powstanie stanu nieokreślonego Uwagę należy zwrócić na mechanizm przechowywania kodów błędów Każdy rodzaj błędu jest oddzielnie zapamietywany, a każdorazowe wywołanie funkcji glGetError zwraca kod tylko jednego błędu Stad w przypadku sprawdzania wystąpienia błędu niezbędne jest wywoływanie funkcji glGetError tak długo, aż zwrócona zostanie wartość GL_NO_ERROR. Biblioteka GLU ma odrębne kody błędów będące odpowiednikami kodów błędów OpenGL: GLU_INVALID_OPERATION, GLU_INVALID_ENUM, GLU_INVALID_VALUE i GLU_OUT_OF_MEMORY. Ciąg znaków opisujący kod błędu biblioteki OpenGL oraz GLU, wskazany w parametrze errorCode, zwraca funkcja:
C/C++
const GLubyte * gluErrorString( GLenum errorCode )
Przykładowo błąd o kodzie GL_INVALID_VALUE spowoduje zwrócenie ciągu znaków "invalid value".

Wykaz elementów dowiązanych

Rozdział 2. Opis instalacji biblioteki SDL dla Visual C++.
Rozdział 4. Podkreślanie tekstu w konsoli.
Rozdział 4. Wczytywanie i wyświetlanie grafiki 2D.
Rozdział 6. Pobieranie pozycji kursora i jego przesuwanie oraz wyświetlanie tekstu na określonej pozycji.