« Test zasłaniania, lekcja »
Rozdział 28. Bryły ograniczające i obiekty analizy przesłonięć; program przykładowy. (lekcja)
Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?
Zarejestruj się!
Autor: Janusz Ganczarski
Kurs OpenGL, C++

Test zasłaniania

[lekcja] Rozdział 28. Bryły ograniczające i obiekty analizy przesłonięć; program przykładowy.
W wersji 1.5 biblioteki OpenGL (rozszerzenie ARB occlusion query) wprowadzono technikę testowania zasłaniania niewidocznych obiektów przy użyciu brył ograniczających. Pozwala to na uniknięcie rysowania tych elementów sceny, które nie są w danym momencie widoczne. Odpowiednie użycie testów zasłaniania umożliwia znaczące przyspieszenie rysowania sceny.

Bryły ograniczające

Bryła ograniczająca jest obiektem zbudowanym z prymitywów OpenGL, która w całości zawiera wewnątrz (otacza) wybrane elementy sceny. Efektywność działania bryły ograniczającej zależy od dwóch sprzecznych wymagań. Im mniejsza ilość wielokątów opisujących bryłę ograniczającą tym szybciej wykonywany jest test zasłaniania. I przeciwnie, im bryła ograniczająca ma kształt bardziej zbliżony (przylegający) do otaczanych elementów sceny, tym dokładniej wykonywany jest test zasłaniania. W praktyce jako brył ograniczających używa się różnego rodzaju wielościanów.
Technika brył ograniczających wykorzystana w bibliotece OpenGL nie jest oczywiście niczym nowym. Jest ona znana i stosowana od wielu lat w specjalistycznych bibliotekach i programach do grafiki 3D.

Obiekty analizy przesłonięć

Przy analizie przesłonięć biblioteka OpenGL korzysta ze specjalnych obiektów. Obiekty analizy przesłonięć posiadają unikatowe identyfikatory, które generuje funkcja:
C/C++
void glGenQueries( GLsizei n, GLuint * ids )
Parametr n określa ilość generowanych identyfikatorów obiektów analizy przesłonięć, które umieszczane są w tablicy ids.
Usuwanie wybranych obiektów analizy przesłonięć wymaga wywołania funkcji:
C/C++
void glDeleteQueries( GLsizei n, const GLuint * ids )
której parametr n określa ilość usuwanych obiektów, a tablica ids zawiera ich identyfikatory.
Sprawdzenie, czy dany identyfikator jest związany z obiektem analizy przesłonięć umożliwia funkcja logiczna:
C/C++
GLboolean glIsQuery( GLuint id )

Analiza przesłonięć

Rozpoczęcie analizy przesłonięć wymaga wywołania funkcji:
C/C++
void glBeginQuery( GLenum target, GLuint id )
Parametr target określa rodzaj wykonywanego zapytania i przyjmuje wartość GL_SAMPLES_PASSED. Drugi parametr id zawiera numer identyfikatora obiektu analizy.
Funkcja glBeginQuery tworzy nowy obiekt analizy przesłonięć. Jeżeli z identyfikatorem id związany jest już inny obiekt analizy przesłonięć, lub wartość tego identyfikatora wynosi zero, generowany jest błąd GL_INVALID - OPERATION.
Zakończenie analizy przesłonięć dla bieżącego obiektu analizy wymaga wywołania funkcji:
C/C++
void glEndQuery( GLenum target )
której parametr target może przyjąć jedynie wartość GL_SAMPLES_PASSED. W danym czasie OpenGL może dokonywać tylko analizy przesłonięć tylko dla jednego obiektu analizy.
Sprawdzenie stanu analiz określonego typu (aktualnie dostępne są tylko analizy przesłonięć) umożliwia funkcja:
C/C++
void glGetQueryiv( GLenum target, GLenum pname, GLint * params )
Parametr target może przyjąć jedynie wartość GL_SAMPLES_PASSED, a sprawdzany parametr stanu analiz określa pname, który przyjmuje jedną z dwóch wartości:
  • GL_CURRENT_QUERY - identyfikator aktywnej analizy przesłonięć,
  • GL_QUERY_COUNTER_BITS - liczba bitów licznika służącego do obliczania wyników analizy.
Warto zauważyć, że liczba bitów licznika analizy może wynosić 0, co w praktyce oznacza niedostępność testu zasłaniania. Minimalna ilość bitów licznika zależy od implementacji i wynika z maksymalnych obsługiwanych rozmiarów okna renderingu OpenGL.

Właściwości obiektu analizy przesłonięć

Pobieranie właściwości obiektu analizy przesłonięć umożliwiają funkcje z grupy glGetQueryObject:
C/C++
void glGetQueryObjectiv( GLuint id, GLenum pname, GLint * params )
void glGetQueryObjectuiv( GLuint id, GLenum pname, GLuint * params )
Parametr id zawiera unikatowy identyfikator obiektu analizy przesłonięć. Drugi parametr pname wskazuje rodzaj pobieranej właściwości obiektu, której wartość zostanie zwrócona w parametrze params. Dostępne są następując właściwości obiektów analizy przesłonięć:
  • GL_QUERY_RESULT - wartość licznika analizy,
  • GL_QUERY_RESULT_AVAILABLE - informacja, czy wartość licznika analizy jest dostępna; dostępność licznika uwarunkowana jest oczekiwaniem na zakończenie analizy.
Wyjaśnienia wymaga jeszcze jak należy interpretować wynik analizy przesłonięć. Jest to po prostu ilość fragmentów bryły ograniczającej, które przeszły pomyślnie test głębokości. Wartość zero licznika analizy oznacza, że żaden fragment bryły ograniczającej nie jest widoczny, a zatem nie jest widoczny także właściwy obiekt.
Sprawdzanie dostępności wyników analizy jest niezbędne, ponieważ mogą zdarzyć się sytuacje, w których wynik jednaj analizy jest zależny od wyniku innych analiz. W czasie oczekiwania na wynik analizy aplikacja może wykonywać inne operacje.

Program przykładowy

Program przykładowy prezentowany na listingu test zaslaniania.cpp zawiera prosty test skuteczności techniki analizy przesłonięć. Program rysuje dwie skomplikowane kule, które przedzielone są tak ułożonym prostopadłościanem, aby istniała możliwość całkowitego zasłonięcia jednej z kul. Jako bryłę ograniczającą wykorzystano sześcian, który przy tak skonstruowanej scenie jest wystarczająco efektywny.
Kolejność postępowania przy rysowaniu sceny z testem zasłaniania jest następująca:
1. rysujemy wszystkie elementy sceny, które nie są objęte testem zasłaniania,
2. wyłączamy wszystkie zbędne właściwości sceny (np. oświetlenie) pozostawiając jedynie włączony bufor głębokości,
3. wyłączamy zapis do bufora głębokości i do bufora koloru,
4. wykonujemy analizę zasłonięć dla wybranych obiektów,
5. po zakończeniu analizy przesłonięć na podstawie jej wyników rysujemy wszystkie widoczne obiekty sceny, oczywiście po wcześniejszym włączeniu zapisu do buforów głębokości i koloru oraz ponownej aktywacji pozostałych efektów wykorzystywanych w scenie.
Wymienione w punkcie drugim wyłącznie efektów stosowanych w scenie za wyjątkiem bufora głębokości ma na celu przyspieszenie wykonywania testu zasłaniania, w którym przykładowo parametry oświetlenia nie mają żadnego znaczenia dla ostatecznego wyniku.
Rysunek 1. Program Test zasłaniania - scena z włączonym testem zasłaniania
Rysunek 1. Program Test zasłaniania - scena z włączonym testem zasłaniania
Wyniki działania przykładowego programu pokazują, że analiza zasłania potrafi znacząco przyspieszyć rysowanie sceny. Wystarczy porównać ilość wyświetlanych ramek na sekundę przy włączonym (rysunek 1) i wyłączonym (rysunek 2) teście zasłaniania. Jak należało się spodziewać rysowanie szybkość sceny przy wyłączony teście zasłaniana nie jest w żaden sposób zależna od tego, które elementy są aktualnie widoczne - patrz rysunek 3. Na ostatnim rysunku 4 przedstawiono scenę z widocznymi krawędziami brył ograniczających.
Rysunek 2. Program Test zasłaniania - scena z wyłączonym testem zasłaniania
Rysunek 2. Program Test zasłaniania - scena z wyłączonym testem zasłaniania

Plik test_zaslaniania.cpp

Rysunek 3. Program Test zasłaniania - scena z widocznymi dwiema kulami
Rysunek 3. Program Test zasłaniania - scena z widocznymi dwiema kulami
Rysunek 4. Program Test zasłaniania - scena z widocznymi krawędziami brył ograniczających
Rysunek 4. Program Test zasłaniania - scena z widocznymi krawędziami brył ograniczających
C/C++
/*
(c) Janusz Ganczarski
http://www.januszg.hg.pl
JanuszG@enter.net.pl
*/

#include <GL/glut.h>
#include <GL/glext.h>
#ifndef WIN32
#define GLX_GLXEXT_LEGACY
#include <GL/glx.h>
#define wglGetProcAddress glXGetProcAddressARB
#endif
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include "colors.h"

// wskaźnik na funkcję glWindowPos2i

PFNGLWINDOWPOS2IPROC glWindowPos2i = NULL;

// wskaźnik na funkcję glGenQueries

PFNGLGENQUERIESPROC glGenQueries = NULL;

// wskaźnik na funkcję glBeginQuery

PFNGLBEGINQUERYPROC glBeginQuery = NULL;

// wskaźnik na funkcję glEndQuery

PFNGLENDQUERYPROC glEndQuery = NULL;

// wskaźnik na funkcję glGetQueryObjectiv

PFNGLGETQUERYOBJECTIVPROC glGetQueryObjectiv = NULL;

// wskaźnik na funkcję glDeleteQueries

PFNGLDELETEQUERIESPROC glDeleteQueries = NULL;

// stałe do obsługi menu podręcznego

enum
{
    OCCLUSION_TEST, // włączenie/wyłączenie testu zasłaniania
    OCCLUSION_BOX, // włączenie/wyłączenie rysowania brył ograniczających
    FULL_WINDOW, // aspekt obrazu - całe okno
    ASPECT_1_1, // aspekt obrazu 1:1
    EXIT // wyjście
};

// aspekt obrazu

int aspect = FULL_WINDOW;

// usunięcie definicji makr near i far

#ifdef near
#undef near
#endif
#ifdef far
#undef far
#endif

// rozmiary bryły obcinania

const GLdouble left = - 2.0;
const GLdouble right = 2.0;
const GLdouble bottom = - 2.0;
const GLdouble top = 2.0;
const GLdouble near = 3.0;
const GLdouble far = 7.0;

// kąty obrotu

GLfloat rotatex = 0.0;
GLfloat rotatey = 0.0;

// wskaźnik naciśnięcia lewego przycisku myszki

int button_state = GLUT_UP;

// położenie kursora myszki

int button_x, button_y;

// włączenie/wyłączenie testu zasłaniania

bool occlusion_test = true;

// włączenie/wyłączenie rysowania bryły ograniczającej

bool occlusion_box = false;

// identyfikatory list wyświetlenia

GLuint SPHERE_0, SPHERE_1, WALL, CUBE_0, CUBE_1;

// licznik ramek (FPS)

int frames = 0;

// licznik czasu

long start_time = 0;

// tablica znaków ze wartością FPS

char time_string[ 100 ] = "FPS:";

// funkcja rysująca napis w wybranym miejscu
// (wersja korzystająca z funkcji glWindowPos2i)

void DrawString( GLint x, GLint y, char * string )
{
    // położenie napisu
    glWindowPos2i( x, y );
   
    // wyświetlenie napisu
    int len = strlen( string );
    for( int i = 0; i < len; i++ )
         glutBitmapCharacter( GLUT_BITMAP_9_BY_15, string[ i ] );
   
}

// funkcja generująca scenę 3D

void DisplayScene()
{
    // licznik czasu
    if( !frames++ )
         start_time = clock();
   
    // kolor tła - zawartość bufora koloru
    glClearColor( 1.0, 1.0, 1.0, 1.0 );
   
    // czyszczenie bufora koloru i bufora głębokości
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
   
    // wybór macierzy modelowania
    glMatrixMode( GL_MODELVIEW );
   
    // macierz modelowania = macierz jednostkowa
    glLoadIdentity();
   
    // przesunięcie układu współrzędnych obiektów do środka bryły odcinania
    glTranslatef( 0.0, 0.0, -( near + far ) / 2 );
   
    // obroty obiektu
    glRotatef( rotatex, 1.0, 0.0, 0.0 );
    glRotatef( rotatey, 0.0, 1.0, 0.0 );
   
    // włączenie testu bufora głębokości
    glEnable( GL_DEPTH_TEST );
   
    // włączenie oświetlenia
    glEnable( GL_LIGHTING );
   
    // włączenie źródła światła GL_LIGHT0
    glEnable( GL_LIGHT0 );
   
    // włączenie śledzenia kolorów
    glEnable( GL_COLOR_MATERIAL );
   
    // włączenie automatycznej normalizacji wektorów normalnych
    glEnable( GL_NORMALIZE );
   
    // narysownaie elementów sceny nie objętych testem zasłaniania
    glCallList( WALL );
   
    // test zasłaniania włączony
    if( occlusion_test == true )
    {
        // wyłączenie oświetlenia
        glDisable( GL_LIGHTING );
       
        // wyłączenie źródła światła GL_LIGHT0
        glDisable( GL_LIGHT0 );
       
        // wyłączenie śledzenia kolorów
        glDisable( GL_COLOR_MATERIAL );
       
        // wyłączenie automatycznej normalizacji wektorów normalnych
        glDisable( GL_NORMALIZE );
       
        // wyłączenie zapisu do bufora głębokości
        glDepthMask( GL_FALSE );
       
        // wyłączenie zapisu składowych RGBA do bufora kolorów
        glColorMask( GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE );
       
        // generowanie identyfikatorów obiektów analizy przesłonięć
        GLuint query_id[ 2 ];
        glGenQueries( 2, query_id );
       
        // analiza przesłaniania pierwszej kuli
        glBeginQuery( GL_SAMPLES_PASSED, query_id[ 0 ] );
        glCallList( CUBE_0 );
        glEndQuery( GL_SAMPLES_PASSED );
       
        // analiza przesłaniania drugiej kuli
        glBeginQuery( GL_SAMPLES_PASSED, query_id[ 1 ] );
        glCallList( CUBE_1 );
        glEndQuery( GL_SAMPLES_PASSED );
       
        // skierowanie poleceń do wykonania
        glFlush();
       
        // sprawdzenie czy dostępne są wyniki analizy przesłaniania pierwszej kuli
        GLint available;
        do
        {
            glGetQueryObjectiv( query_id[ 0 ], GL_QUERY_RESULT_AVAILABLE, & available );
        }
        while( !available );
       
        // sprawdzenie czy dostępne są wyniki analizy przesłaniania drugiej kuli
        do
        {
            glGetQueryObjectiv( query_id[ 1 ], GL_QUERY_RESULT_AVAILABLE, & available );
        }
        while( !available );
       
        // włączenie zapisu do bufora głębokości
        glDepthMask( GL_TRUE );
       
        // włączenie zapisu składowych RGBA do bufora kolorów
        glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE );
       
        // włączenie oświetlenia
        glEnable( GL_LIGHTING );
       
        // włączenie źródła światła GL_LIGHT0
        glEnable( GL_LIGHT0 );
       
        // włączenie śledzenia kolorów
        glEnable( GL_COLOR_MATERIAL );
       
        // włączenie automatycznej normalizacji wektorów normalnych
        glEnable( GL_NORMALIZE );
       
        // pobranie wyniku analizy przesłaniania pierwszej kuli
        GLint result;
        glGetQueryObjectiv( query_id[ 0 ], GL_QUERY_RESULT, & result );
       
        // w przypadku widoczności narysowanie pierwszej kuli
        if( result )
             glCallList( SPHERE_0 );
       
        // pobranie wyniku analizy przesłaniania drugiej kuli
        glGetQueryObjectiv( query_id[ 1 ], GL_QUERY_RESULT, & result );
       
        // w przypadku widoczności narysowanie drugiej kuli
        if( result )
             glCallList( SPHERE_1 );
       
        // usunięcie obiektów analizy przesłonięć
        glDeleteQueries( 2, query_id );
    }
   
    // test zasłaniania wyłączony
    else
    {
        // narysowanie pierwszej i drugiej kuli
        glCallList( SPHERE_0 );
        glCallList( SPHERE_1 );
    }
   
    // rysowanie brył ograniczających
    if( occlusion_box == true )
    {
        glColor3fv( Black );
        glPushMatrix();
        glTranslatef( 0.0, 0.0, 1.2 );
        glutWireCube( 1.5 );
        glTranslatef( 0.0, 0.0, - 2.4 );
        glutWireCube( 1.5 );
        glPopMatrix();
    }
   
    // komunikat o ilości ramek rysowanych na sekundę (FPS)
    glColor3fv( Black );
    if( frames == 100 )
    {
        frames = 0;
        sprintf( time_string, "FPS: %i",( int )( 100 * CLOCKS_PER_SEC /( float )( clock() - start_time ) ) );
    }
   
    // narysowanie napisu
    DrawString( 1, 1, time_string );
   
    // skierowanie poleceń do wykonania
    glFlush();
   
    // zamiana buforów koloru
    glutSwapBuffers();
}

// zmiana wielkości okna

void Reshape( int width, int height )
{
    // obszar renderingu - całe okno
    glViewport( 0, 0, width, height );
   
    // wybór macierzy rzutowania
    glMatrixMode( GL_PROJECTION );
   
    // macierz rzutowania = macierz jednostkowa
    glLoadIdentity();
   
    // parametry bryły obcinania
    if( aspect == ASPECT_1_1 )
    {
        // wysokość okna większa od wysokości okna
        if( width < height && width > 0 )
             glFrustum( left, right, bottom * height / width, top * height / width, near, far );
        else
       
        // szerokość okna większa lub równa wysokości okna
        if( width >= height && height > 0 )
             glFrustum( left * width / height, right * width / height, bottom, top, near, far );
       
    }
    else
         glFrustum( left, right, bottom, top, near, far );
   
    // generowanie sceny 3D
    DisplayScene();
}

// obsługa przycisków myszki

void MouseButton( int button, int state, int x, int y )
{
    if( button == GLUT_LEFT_BUTTON )
    {
        // zapamiętanie stanu lewego przycisku myszki
        button_state = state;
       
        // zapamiętanie położenia kursora myszki
        if( state == GLUT_DOWN )
        {
            button_x = x;
            button_y = y;
        }
    }
}

// obsługa ruchu kursora myszki

void MouseMotion( int x, int y )
{
    if( button_state == GLUT_DOWN )
    {
        rotatey += 30 *( right - left ) / glutGet( GLUT_WINDOW_WIDTH ) *( x - button_x );
        button_x = x;
        rotatex -= 30 *( top - bottom ) / glutGet( GLUT_WINDOW_HEIGHT ) *( button_y - y );
        button_y = y;
        glutPostRedisplay();
    }
}

// obsługa menu podręcznego

void Menu( int value )
{
    switch( value )
    {
        // włączenie/wyłączenie testu zasłaniania
    case OCCLUSION_TEST:
        occlusion_test = !occlusion_test;
        DisplayScene();
        break;
       
        // włączenie/wyłączenie rysowania brył ograniczających
    case OCCLUSION_BOX:
        occlusion_box = !occlusion_box;
        DisplayScene();
        break;
       
        // obszar renderingu - całe okno
    case FULL_WINDOW:
        aspect = FULL_WINDOW;
        Reshape( glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ) );
        break;
       
        // obszar renderingu - aspekt 1:1
    case ASPECT_1_1:
        aspect = ASPECT_1_1;
        Reshape( glutGet( GLUT_WINDOW_WIDTH ), glutGet( GLUT_WINDOW_HEIGHT ) );
        break;
       
        // wyjście
    case EXIT:
        exit( 0 );
    }
}

// utworzenie list wyświetlania

void GenerateDisplayLists()
{
    // generowanie identyfikatora pierwszej listy wyświetlania
    SPHERE_0 = glGenLists( 1 );
   
    // pierwsza lista wyświetlania - pierwsza kula
    glNewList( SPHERE_0, GL_COMPILE );
    glColor3fv( Blue );
    glPushMatrix();
    glTranslatef( 0.0, 0.0, 1.2 );
    glutSolidSphere( 0.7, 200, 200 );
    glPopMatrix();
   
    // koniec pierwszej listy wyświetlenia
    glEndList();
   
    // generowanie identyfikatora drugiej listy wyświetlania
    SPHERE_1 = glGenLists( 1 );
   
    // druga lista wyświetlania - druga kula
    glNewList( SPHERE_1, GL_COMPILE );
    glColor3fv( Lime );
    glPushMatrix();
    glTranslatef( 0.0, 0.0, - 1.2 );
    glutSolidSphere( 0.7, 200, 200 );
    glPopMatrix();
   
    // koniec drugiej listy wyświetlenia
    glEndList();
   
    // generowanie identyfikatora trzeciej listy wyświetlania
    WALL = glGenLists( 1 );
   
    // trzecia lista wyświetlania - murek
    glNewList( WALL, GL_COMPILE );
    glColor3fv( Red );
    glPushMatrix();
    glScalef( 1.0, 1.0, 0.1 );
    glutSolidCube( 2.8 );
    glPopMatrix();
   
    // koniec trzeciej listy wyświetlenia
    glEndList();
   
    // generowanie identyfikatora czwartej listy wyświetlania
    CUBE_0 = glGenLists( 1 );
   
    // czwarta lista wyświetlania - sześcian otaczający pierwszą kulę
    glNewList( CUBE_0, GL_COMPILE );
    glPushMatrix();
    glTranslatef( 0.0, 0.0, 1.2 );
    glutSolidCube( 1.5 );
    glPopMatrix();
   
    // koniec czwartej listy wyświetlenia
    glEndList();
   
    // generowanie identyfikatora piątej listy wyświetlania
    CUBE_1 = glGenLists( 1 );
   
    // piąta lista wyświetlania - sześcian otaczający drugą kulę
    glNewList( CUBE_1, GL_COMPILE );
    glPushMatrix();
    glTranslatef( 0.0, 0.0, - 1.2 );
    glutSolidCube( 1.5 );
    glPopMatrix();
   
    // koniec piątej listy wyświetlenia
    glEndList();
}

// sprawdzenie i przygotowanie obsługi wybranych rozszerzeń

void ExtensionSetup()
{
    // pobranie numeru wersji biblioteki OpenGL
    const char * version =( char * ) glGetString( GL_VERSION );
   
    // odczyt wersji OpenGL
    int major = 0, minor = 0;
    if( sscanf( version, "%d.%d", & major, & minor ) != 2 )
    {
        #ifdef WIN32
        printf( "Błędny format wersji OpenGL\n" );
        #else
       
        printf( "Bledny format wersji OpenGL\n" );
        #endif
       
        exit( 0 );
    }
   
    // sprawdzenie czy jest co najmniej wersja 1.4
    if( major > 1 || minor >= 4 )
    {
        // pobranie wskaźnika wybranej funkcji OpenGL 1.4
        glWindowPos2i =( PFNGLWINDOWPOS2IPROC ) wglGetProcAddress( "glWindowPos2i" );
    }
    else
    // sprawdzenie czy jest obsługiwane rozszerzenie ARB_window_pos
    if( glutExtensionSupported( "GL_ARB_window_pos" ) )
    {
        // pobranie wskaźnika wybranej funkcji rozszerzenia ARB_window_pos
        glWindowPos2i =( PFNGLWINDOWPOS2IPROC ) wglGetProcAddress
        ( "glWindowPos2iARB" );
    }
    else
    {
        printf( "Brak rozszerzenia ARB_window_pos!\n" );
        exit( 0 );
    }
   
    // sprawdzenie czy jest co najmniej wersja 1.5
    if( major > 1 || minor >= 5 )
    {
        // pobranie wskaźnika wybranych funkcji OpenGL 1.5
        glGenQueries =( PFNGLGENQUERIESPROC ) wglGetProcAddress( "glGenQueries" );
        glBeginQuery =( PFNGLBEGINQUERYPROC ) wglGetProcAddress( "glBeginQuery" );
        glEndQuery =( PFNGLENDQUERYPROC ) wglGetProcAddress( "glEndQuery" );
        glGetQueryObjectiv =( PFNGLGETQUERYOBJECTIVPROC )
        wglGetProcAddress( "glGetQueryObjectiv" );
        glDeleteQueries =( PFNGLDELETEQUERIESPROC )
        wglGetProcAddress( "glDeleteQueries" );
    }
    else
    // sprawdzenie czy jest obsługiwane rozszerzenie ARB_occlusion_query
    if( glutExtensionSupported( "GL_ARB_occlusion_query" ) )
    {
        // pobranie wskaźniki wybranych funkcji rozszerzenia ARB_occlusion_query
        glGenQueries =( PFNGLGENQUERIESPROC ) wglGetProcAddress( "glGenQueriesARB" );
        glBeginQuery =( PFNGLBEGINQUERYPROC ) wglGetProcAddress( "glBeginQueryARB" );
        glEndQuery =( PFNGLENDQUERYPROC ) wglGetProcAddress( "glEndQueryARB" );
        glGetQueryObjectiv =( PFNGLGETQUERYOBJECTIVPROC )
        wglGetProcAddress( "glGetQueryObjectivARB" );
        glDeleteQueries =( PFNGLDELETEQUERIESPROC )
        wglGetProcAddress( "glDeleteQueriesARB" );
    }
    else
    {
        printf( "Brak rozszerzenia ARB_window_pos!\n" );
        exit( 0 );
    }
}

int main( int argc, char * argv[] )
{
    // inicjalizacja biblioteki GLUT
    glutInit( & argc, argv );
   
    // inicjalizacja bufora ramki
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH );
   
    // rozmiary głównego okna programu
    glutInitWindowSize( 500, 500 );
   
    // utworzenie głównego okna programu
    #ifdef WIN32
   
    glutCreateWindow( "Test zasłaniania" );
    #else
   
    glutCreateWindow( "Test zaslaniania" );
    #endif
   
    // dołączenie funkcji generującej scenę 3D
    glutDisplayFunc( DisplayScene );
   
    // dołączenie funkcji wywoływanej przy zmianie rozmiaru okna
    glutReshapeFunc( Reshape );
   
    // obsługa przycisków myszki
    glutMouseFunc( MouseButton );
   
    // obsługa ruchu kursora myszki
    glutMotionFunc( MouseMotion );
   
    // utworzenie podmenu - Aspekt obrazu
    int MenuAspect = glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddMenuEntry( "Aspekt obrazu - całe okno", FULL_WINDOW );
    #else
   
    glutAddMenuEntry( "Aspekt obrazu - cale okno", FULL_WINDOW );
    #endif
   
    glutAddMenuEntry( "Aspekt obrazu 1:1", ASPECT_1_1 );
   
    // menu główne
    glutCreateMenu( Menu );
   
    #ifdef WIN32
   
    glutAddMenuEntry( "Test zasłaniania włącz/wyłącz", OCCLUSION_TEST );
    glutAddMenuEntry( "Rysowania brył ograniczających włącz/wyłącz", OCCLUSION_BOX );
    glutAddSubMenu( "Aspekt obrazu", MenuAspect );
    glutAddMenuEntry( "Wyjście", EXIT );
    #else
   
    glutAddMenuEntry( "Test zaslaniania wlacz/wylacz", OCCLUSION_TEST );
    glutAddMenuEntry( "Rysowania bryly ograniczajacych wlacz/wylacz", OCCLUSION_BOX );
    glutAddSubMenu( "Aspekt obrazu", MenuAspect );
    glutAddMenuEntry( "Wyjscie", EXIT );
    #endif
   
    // określenie przycisku myszki obsługującego menu podręczne
    glutAttachMenu( GLUT_RIGHT_BUTTON );
   
    // sprawdzenie i przygotowanie obsługi wybranych rozszerzeń
    ExtensionSetup();
   
    // utworzenie list wyświetlania
    GenerateDisplayLists();
   
    // funkcja bezczynności
    glutIdleFunc( DisplayScene );
   
    // wprowadzenie programu do obsługi pętli komunikatów
    glutMainLoop();
    return 0;
}
Poprzedni dokumentNastępny dokument
NURBSObiekty buforowe