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

Wielokąty

[lekcja] Rozdział 7. Wielokąty: trójkąty, wstęgi trójkątów, wachlarze trójkątów, czworokąty, wachlarze czworokątów, wielokąty, prostokąty; ukrywanie stron wielokąta; tryby rysowania wielokąta (wierzchołki, krawędzie, wypełnienie); wypełnianie wielokątów wzorem; ukrywanie krawędzi wielokąta; kafelkowanie (podział) wielokątów; dwa przykładowe programy.
Przy rysowaniu wielokątów biblioteka OpenGL oferuje znacznie większe możliwości niż przy rysowaniu pozostałych prymitywów gra?cznych. Zamieszczone poniżej informacje dotyczą wielokątów de?niowanych pomiędzy wywołaniami funkcji glBegin i glEnd (stałe: GL_TRIANGLE_STRIP, GL_TRIANGLES, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP i GL_POLYGON) oraz częściowo prostokątów rysowanych za pomocą funkcji z grupy glRect.

Strony wielokąta

Podstawową zadaniem przy rysowaniu wielokątów jest określenie stron wielokąta. Biblioteka OpenGL operuje pojęciem przedniej i tylnej strony wielokąta. Domyślnie przednią stroną wielokąta jest ta, której wierzchołki uporządkowane są w kierunku przeciwnym do ruchu wskazówek zegara. Zmianę sposobu określania stron wielokątów umożliwia funkcja:

C/C++
void glFrontFace( GLenum mode )
Parametr mode przyjmuje jedną z dwóch wartości:

  • GL_CW - przednia strona wielokąta z wierzchołkami uporządkowanymi zgodnie z ruchem wskazówek zegara,
  • GL_CCW - przednia strona wielokąta z wierzchołkami uporządkowanymi odwrotnie do ruchu wskazówek zegara.
Określenie stron wielokątów umożliwia optymalizację procesu rysowania sceny 3D. W wielu bowiem przypadkach ?gury tworzone z wielokątów są obiektami zamkniętymi, a ich wewnętrzna część nie jest widoczna w programie. W takich sytuacjach OpenGL umożliwia wybór, która strona wielokąta nie ma być rysowana. W tym celu należy wywołać funkcję:
C/C++
void glCullFace( GLenum mode )
której parametr mode przyjmuje jedną z wartości:
  • GL_FRONT - nie jest rysowana przednia strona,
  • GL_BACK - nie jest rysowana tylna strona,
  • GL_FRONT_AND_BACK - nie są rysowane obie strony, przednia i tylna.
Zauważmy, że użycie parametru GL_FRONT_AND_BACK spowoduje wyłączenie rysowania wielokątów. Domyślnie opcja wyboru renderowanej strony wielokątów jest wyłączona, czyli rysowane są obie strony wielokątów. Po włączeniu tej opcji (funkcja glEnable z parametrem GL_CULL_FACE) domyślnie rysowana jest tylko przednia strona wielokątów.

Tryby rysowania

Biblioteka OpenGL umożliwia także wybór różnego sposobu rysowania przednich i tylnych stron wielokątów. Realizuje to funkcja:
C/C++
void glPolygonMode( GLenum face, GLenum mode )
Parametr face określa stronę wielokąta:
  • GL_FRONT - strona przednia,
  • GL_BACK - strona tylna,
  • GL_FRONT_AND_BACK - obie strony, przednia i tylna.
Parametr mode określa metodę rysowania wybranej strony wielokąta:

  • GL_POINT - rysowane są tylko wierzchołki wielokąta,
  • GL_LINE - rysowane są tylko krawędzie wielokąta,
  • GL_FILL - rysowany jest wypełniony wielokąt.
Domyślne ustawione jest rysowanie wielokątów wypełnionych po obu stronach. Warto zauważyć, że przy rysowaniu wielokątów można stosować także ustawienia dotyczące wielkości punktów, szerokości linii oraz wzorów linii.

Wypełnianie wielokątów wzorem

Podobnie jak w przypadku linii także wielokąty można rysować przy użyciu wzoru. Wzór ma postać mapy bitowej o rozmiarach 32 × 32 pikseli i jest reprezentowany przez tablicę 128 liczb typu GLubyte. Dane mapy bitowej zapisywane są wierszami w odwrotnej kolejności tj. od wiersza dolnego do górnego. Zmianę wzoru wypełnienia wielokąta umożliwia funkcja:
C/C++
void glPolygonStipple( const GLubyte * mask )
Domyślnie wypełnianie wielokątów wzorem jest wyłączone, stąd w celu zastosowania tej możliwości należy wywołać funkcję glEnable z parametrem GL_POLYGON_STIPPLE.

Ukrywanie krawędzi wielokąta

Domyślnie OpenGL rysuje wszystkie krawędzie wielokątów. Jednak przy wyświetlaniu wielokątów złożonych z wielu ?gur podstawowych (np. trójkątów) w trybie GL_LINE przydatna jest możliwość ukrywanie wybranych krawędzi wielokątów. Wybór czy aktualna krawędź ma być rysowana czy też nie umożliwiają funkcje:
C/C++
void glEdgeFlag( GLboolean flag )
void glEdgeFlagv( const GLboolean * flag )
Parametr flag określa czy bieżąca krawędź wielokąta ma być rysowana (GL_TRUE) czy nie (GL_FALSE). Ustawienie wskaźnika rysowania krawędzi obowiązuje aż do jego zmiany. Jak się już Czytelnik domyślił stałe GL_TRUE i GL_FALSE to zde?niowane w bibliotece OpenGL odpowiedniki true i false z języka C++.
Ukrywanie krawędzi nie działa w przypadku prostokątów rysowanych przy użyciu funkcji z grupy glRect.

Podział wielokątów

Funkcje biblioteki OpenGL nie umożliwiają np. rysowania wielokątów z dziurami. W takim przypadku przydatne okazują się mechanizmy zawarte w bibliotece GLU umożliwiające podział (kafelkowanie) wielokątów.
Do kafelkowania używana jest struktura (w przypadku języka C++ klasa) GLUtesselator. Można także używać alternatywnych nazw klas/struktur: GLUtesselatorObj i GLUtriangulatorObj Obiekt podziału tworzy wywołanie funkcji gluNewTess:
C/C++
GLUtesselator * gluNewTess( void )
która zwraca wskaźnik do struktury (klasy) GLUtesselator, niezbędny w wywołaniach pozostałych funkcji obsługujących kafelkowanie wielokątów. Po zakończeniu operacji na danym obiekcie podziału należy zwolnić przydzieloną mu pamięć wywołując funkcję:
C/C++
void gluDeleteTess( GLUtesselator * tess )

Defnicja wielokąta

Defnicję wielokąta rozpoczyna wywołanie funkcji:
C/C++
void gluTessBeginPolygon( GLUtesselator * tess,
GLvoid * polygon_data )
gdzie parametr polygon data zawiera dowolne dane użytkownika i w szczególności może przyjąć wartość NULL. Dane te przekazywane są do opisanych dalej funkcji zwrotnych. Po zakończeniu de?niowania wielokąta trzeba wywołać funkcję:
C/C++
void gluTessEndPolygon( GLUtesselator * tess )
Wewnątrz wielokąta umieszcza się de?nicje jednego lub wielu konturów.
Defnicja każdego konturu zawiera się pomiędzy wywołaniami funkcji:
C/C++
void gluTessBeginContour( GLUtesselator * tess )
void gluTessEndContour( GLUtesselator * tess )
Kontury wielokąta opisuje się za pomocą współrzędnych ich wierzchołków, przy czym pierwszy wierzchołek jest automatycznie łączony z ostatnim.
Wierzchołek de?niuje się przy użyciu funkcji:
C/C++
void gluTessVertex( GLUtesselator * tess,
GLdouble coords[ 3 ],
GLvoid * vertex_data )
gdzie parametr coords określa współrzędne (x, y, z) wierzchołka, a w parametrze vertex data przekazywane są dodatkowe dane opisujące wierzchołek. Może to być np. jego kolor c zy współrzędne tekstury. Dane te przekazywane są jako parametr opisanych dalej funkcji zwrotnych GLU_VERTEX, GLU_TESS_VERTEX i GLU_TESS_VERTEX_DATA.
W celu zachowania wstecznej zgodności GLU w wersjach 1.2 i 1.3 udostępnia także pochodzący z wcześniejszych wersji biblioteki interfejs do de?niowania wielokątów. Składają się na niego trzy poniższe funkcje:
C/C++
void gluBeginPolygon( GLUtesselator * tess )
void gluNextContour( GLUtesselator * tess,
GLenum type )
void gluEndPolygon( GLUtesselator * tess )
Funkcja gluBeginPolygon tworzy nowy wielokąt i jednocześnie stanowi początek de?nicji konturu. Stanowi więc odpowiednik wywołania kolejno funkcji gluTessBeginPolygon i gluTessBeginContour. Druga funkcja tworzy nowy kontur i odpowiada wywołaniu gluTessEndContour i gluTessBeginContour. Wartość parametru type jest ignorowana, choć dostępne są stałe, które określały jego dopuszczalne wartości: GLU_CW, GLU_CCW, GLU_INTERIOR, GLU_EXTERIOR i GLU_UNKNOWN.
Ostatnia funkcja gluEndPolygon jednocześnie kończy de?nicję konturu i całego wielokąta. Jest to więc odpowiednik wywołania funkcji gluTessEndContour i gluTessEndPolygon.
Specy?kacja biblioteki GLU określa trzy powyższe funkcje jako przestarzałe i zaleca stosowanie wyłącznie nowego interfejsu obsługi wielokątów i konturów.

Funkcje zwrotne

Po utworzeniu obiektu podziału trzeba zde?niować funkcje zwrotne używane podczas różnych etapów kafelkowania wielokątów. Dołączenie funkcji zwrotnej realizuje funkcja:
C/C++
void gluTessCallback( GLUtesselator * tess,
GLenum which,
void( * fn )() )
której parametr which określa rodzaj wykonywanej czynności lub rodzaj generowanych danych podczas kafelkowania wielokąta, a odpowiednia funkcja zwrotna wskazywana jest w parametrze fn.
Funkcje zwrotne występują w dwóch wersjach. Pierwsza z nich zwraca tylko dane związane z charakterem swojego działania (np. współrzędne wierzchołków wielokąta). Wersje alternatywne zwracają dodatkowo parametr polygon data zawierający dane użytkownika przekazane w parametrze polygon data funkcji gluTessBeginPolygon.
Funkcje zwrotne renderera obiektów podziału określone są następującymi stałymi:

  • GLU_BEGIN, GLU_TESS_BEGIN, GLU_TESS_BEGIN_DATA - początek de?niowania współrzędnych wierzchołków prymitywu; funkcje zwrotne mają
    postać:
    C/C++
    void begin( GLenum type )
    void beginData( GLenum type, void * polygon_data )
    gdzie parametr type określa rodzaj renderowanego prymitywu i przyjmuje jedną z poznanych już wartości: GL_TRIANGLE_FAN, GL_TRIANGLE_STRIP, GL_TRIANGLES i GL_LINE_LOOP,
  • GLU_EDGE_FLAG, GLU_TESS_EDGE_FLAG, GLU_TESS_EDGE_FLAG_DATA - zmiana znacznika rysowania krawędzi wielokąta (odpowiednik działania funkcji glEdgeFlag); funkcje zwrotne mają postać:
    C/C++
    void edgeFlag( GLboolean flag )
    void edgeFlagData( GLboolean flag, void * polygon_data )
    gdzie parametr flag zawiera nową wartość znacznika rysowania krawędzi wielokąta (GL_TRUE - krawędź zewnętrzna, GL_FALSE - krawędź wewnętrzna); funkcja ta jest zawsze wywołana przed funkcją zwrotną wywoływaną przy de?niowaniu wierzchołka,
  • GLU_VERTEX, GLU_TESS_VERTEX, GLU_TESS_VERTEX_DATA - funkcja wywoływana przy de?niowaniu wierzchołka renderowanego prymitywu; funkcje zwrotne mają postać:
    C/C++
    void vertex( void * vertex_data )
    void vertexData( void * vertex_data, void * polygon_data )
    gdzie parametr vertex data jest kopią analogicznego parametru funkcji gluTessVertex,
  • GLU_END, GLU_TESS_END, GLU_TESS_END_DATA - koniec de?niowania współrzędnych wierzchołków prymitywu; funkcje zwrotne mają postać:
    C/C++
    void end()
    void endData( void * polygon_data )
  • GLU_ERROR, GLU_TESS_ERROR, GLU_TESS_ERROR_DATA - błąd podczas kafelkowania wielokąta; funkcje zwrotne mają postać:
    C/C++
    void error( GLenum errno )
    void errorData( GLenum errno, void * polygon_data )
    gdzie parametr errno oznacza kod błędu; zestawienie kodów błędów obiektu podziału wielokątów zawiera tabela 1,
  • GLU_TESS_COMBINE, GLU_TESS_COMBINE_DATA - funkcja wywoływana, gdy
    podczas kafelkowania wielokąta występuje samoprzecięcie jego krawędzi i trzeba utworzyć nowy wierzchołek; funkcje zwrotne mają postać:
    C/C++
    void combine( GLdouble coords[ 3 ],
    void * vertex_data[ 4 ],
    GLfloat weight[ 4 ],
    void ** outData )

    void combineData( GLdouble coords[ 3 ],
    void * vertex_data[ 4 ],
    GLfloat weight[ 4 ],
    void ** outData,
    void * polygon_data )
    gdzie parametr coords zawiera współrzędne nowego wierzchołka, parametr vertex data opisuje nowy wierzchołek jako liniową kombinację czterech istniejących wierzchołków, a parametr weight zawiera wartości współczynników liniowej kombinacji wierzchołków o sumie zawsze równej 1; dane nowego wierzchołka, na które obok współrzędnych mogą składać się inne informacje wymagane przez program, przekazywane są poprzez parametr outData.

Tabela 1: Zestawienie kodów błędów obiektów podziału wielokątów

numer błęduopis błędu
GLU_TESS_MISSING_BEGIN_POLYGON
GLU_TESS_ERROR1
gluTessBeginPolygon musi poprzedzać gluTessEndPolygon
GLU_TESS_MISSING_BEGIN_CONTOUR
GLU_TESS_ERROR2
gluTessBeginContour musi poprzedzać gluTessEndContour
GLU_TESS_MISSING_END_POLYGON
GLU_TESS_ERROR3
gluTessEndPolygon musi być za gluTessBeginPolygon
GLU_TESS_MISSING_END_CONTOUR
GLU_TESS_ERROR4
gluTessEndContour musi być za gluTessBeginContour
GLU_TESS_COORD_TOO_LARGE
GLU_TESS_ERROR5
ilość współrzędnych wielokąta większa od GLU_TESS_MAX_COORD
GLU_TESS_NEED_COMBINE_CALLBACK
GLU_TESS_ERROR6
wymagana funkcja zwrotna GLU_TESS_COMBINE lub GLU_TESS_COMBINE_DATA
  Wszystkie funkcje zwrotne domyślnie są niezde?niowane. W przypadku konieczności deaktywacji wybranej funkcji zwrotnej jako parametr fn funkcji gluTessCallback trzeba podać wartość NULL.

Właściwości kafelkowania

Modyfkację właściwości podziału wielokątów umożliwia funkcja:
C/C++
void gluTessProperty( GLUtesselator * tess,
GLenum which,
GLdouble data )
której parametr which określa rodzaj mody?kowanej właściwości, a parametr data zawiera nową wartość właściwości. Parametr which może przyjąć jedną z trzech wartości: GLU_TESS_WINDING_RULE, GLU_TESS_BOUNDARY_ONLY i GLU_TESS_TOLERANCE.
Pierwsza właściwość GLU_TESS_WINDING_RULE określa, która z części wielokąta (który kontur) stanowi część wewnętrzną wielokąta. W tym celu biblioteka GLU określa dla każdego konturu tzw. liczby nawijania (ang.
winding numbers). Wartość 1 otrzymuje każdy kontur złożony z krawędzi o kierunku odwrotnym do ruchu wskazówek zegara. Wartość -1 przyjmuje kontur złożony z krawędzi o kierunku zgodnym z ruchem wskazówek zegara. Wartość liczby nawijania konturu wewnętrznego jest sumą wartości liczby tego konturu i wszystkich konturów zewnętrznych. Liczby nawijania dla dwóch przykładowych konturów przedstawia rysunek 1.
Możliwe są następujące wartości właściwości GLU_TESS_WINDING_RULE:

  • GLU_TESS_WINDING_ODD - wnętrze wielokąta składa się z konturów z nieparzystą liczbą nawijania (wartość domyślna),
  • GLU_TESS_WINDING_NONZERO - wnętrze wielokąta stanowią kontury z niezerową liczbą nawijania,
  • GLU_TESS_WINDING_POSITIVE - wnętrze wielokąta składa się konturów
    z większą od zera liczbą nawijania,
    Rysunek 1. Liczby nawijania dla przykładowych konturów
    Rysunek 1. Liczby nawijania dla przykładowych konturów
  • GLU_TESS_WINDING_NEGATIVE - wnętrze wielokąta stanowią kontury z ujemną liczbą nawijania,
  • GLU_TESS_WINDING_ABS_GEQ_TWO - wnętrze wielokąta składa się z części
wspólnej dwóch konturów (prawidłowo działa tylko dla wielokąta z dwoma konturami).
Właściwość GLU_TESS_BOUNDARY_ONLY przyjmuje wartości logiczne GL_TRUE i GL_FALSE. Wartość GL_TRUE oznacza, że renderowane są wyłącznie krawędzie wielokąta. Tylko w takim przypadku wartość parametru type funkcji zwrotnych GLU_BEGIN, GLU_TESS_BEGIN i GLU_TESS_BEGIN_DATA wynosi GL_LINE_LOOP. Domyślna wartość GL_TRUE oznacza, że renderowany jest wypełniony wielokąt.
Trzecia i ostatnia właściwość GLU_TESS_TOLERANCE określa tolerancję używaną przy podziale wielokąta na trójkąty w przypadku występowania blisko położonych wierzchołków. Właściwość ta jest opcjonalna i może być pominięta przez implementację biblioteki GLU. Domyślnie wartość tolerancji wynosi 0.
Pobieranie wartości wybranych właściwości kafelkowania umożliwia funkcja:
C/C++
void gluGetTessProperty( GLUtesselator * tess,
GLenum which,
GLdouble * data )
której parametr which przyjmuje takie same wartości jak analogiczny parametr funkcji gluTessProperty.
Ostatnią funkcją biblioteki GLU związaną z kafelkowaniem wielokątów jest funkcja:
C/C++
void gluTessNormal( GLUtesselator * tess,
GLdouble valueX,
GLdouble valueY, GLdouble valueZ )
która w parametrach valueX, valueY i valueZ zawiera współrzędne wektora normalnego dla każdego z trójkątów generowanych podczas podziału wielokąta. Funkcja jest oczywiście szczególnie użyteczna wówczas, gdy cały wielokąt znajduje się w jednej płaszczyźnie. Domyślnie współrzędne wektora normalnego wynoszą (0, 0, 0).

Programy przykładowe

Pierwszy przykładowy program (plik wielokaty.cpp) prezentuje wszystkie opisane wyżej możliwości związane z rysowaniem wielokątów. Wybór rodzaju wielokąta oraz opcji jego rysowania tradycyjnie umożliwia menu podręczne.
W przykładowym programie pobieramy i wyświetlamy wartości wybranych zmiennych maszyny stanów OpenGL. Odczyt parametru określanego wywołaniem funkcji glEnable/glDisable umożliwia funkcja:
C/C++
GLboolean glIsEnabled( GLenum cap )
która zwraca odpowiednio wartość GL_TRUE lub GL_FALSE. Parametr cap przyjmuje taką samą wartość jak parametr funkcji glEnable/glDisable.
Poza powyższą funkcją i poznanymi już funkcjami glGetBooleanv, glGetDoublev, glGetFloatv i glGetIntegerv do pobierania wartości niektórych zmiennych maszyny stanów OpenGL służą specjalne funkcje. Przykładem jest niezastosowana w poniższym programie funkcja pobierająca wzór wypełnienia wielokąta:
C/C++
void glGetPolygonStipple( GLubyte * mask )
W przykładowym programie pobierane są i wyświetlane na ekranie m.in.
następujące zmienne maszyny stanów OpenGL:
  • GL_FRONT_FACE - orientacja stron wielokąta,
  • GL_CULL_FACE_MODE - nierysowana strona wielokąta,
  • GL_POLYGON_MODE - sposób rysowania przedniej i tylnej strony wielokąta,
  • GL_EDGE_FLAG - ukrywanie krawędzi wielokąta,
  • GL_POINT_SIZE - bieżąca wielkość punktów,
  • GL_LINE_WIDTH - bieżąca szerokość linii.
Przykładowe efekty działania programu przestawiają rysunki: 2, 3, 4 i 5.
Rysunek 2. Program Wielokąty - trójkąty
Rysunek 2. Program Wielokąty - trójkąty
Rysunek 3. Program Wielokąty - wstęga trójkątów
Rysunek 3. Program Wielokąty - wstęga trójkątów
Rysunek 4. Program Wielokąty - wachlarz trójkątów
Rysunek 4. Program Wielokąty - wachlarz trójkątów
Rysunek 5. Program Wielokąty - czworokąty koniec
Rysunek 5. Program Wielokąty - czworokąty koniec

Plik podzial_wielokatow.cpp

C/C++
/*
(c) Janusz Ganczarski
http://www.januszg.hg.pl
JanuszG(małpeczka)enter.net.pl
*/

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

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

enum
{
    CLEAR_VERTEX, // usuwanie wierzchołków
    EXIT // wyjście
};

// maksymalna ilość wierzchołków wielokąta

#define MAX_VERTEX 2000

// tablica ze współrzędnymi wierzchołków wielokąta

GLdouble vertex[ MAX_VERTEX ][ 3 ];

// numer bieżącego wierzchołka

int vertex_count = 0;

// rodzaj prymitywu użytego do renderingu wielokąta

GLenum primitive = 0;

// właściwość GLU_TESS_WINDING_RULE

GLdouble winding_rule = GLU_TESS_WINDING_ODD;

// właściwość GLU_TESS_BOUNDARY_ONLY

GLdouble boundary_only = GL_FALSE;

// definicja CALLBACK jeżeli nie występuje w danym systemie

#ifndef CALLBACK
#define CALLBACK
#endif

// funkcja zwrotna GLU_TESS_BEGIN

void CALLBACK beginCallback( GLenum type )
{
    glBegin( type );
    primitive = type;
}

// funkcja zwrotna z obsługą błędów - GLU_TESS_ERROR

void CALLBACK errorCallback( GLenum errorCode )
{
    printf( "Błąd kafelkowania: %s\n", gluErrorString( errorCode ) );
    exit( 0 );
}

// funkcja zwrotna GLU_TESS_COMBINE

void CALLBACK combineCallback( GLdouble coords[ 3 ],
GLdouble * vertex_data[ 4 ],
GLfloat weight[ 4 ],
GLdouble ** dataOut )
{
    // przydzielenie pamięci na dane nowego wierzchołka - tylko współrzędne
    GLdouble * new_vertex =( GLdouble * ) malloc( 3 * sizeof( GLdouble ) );
   
    // pobranie współrzędnych wierzchołka
    new_vertex[ 0 ] = coords[ 0 ];
    new_vertex[ 1 ] = coords[ 1 ];
    new_vertex[ 2 ] = coords[ 2 ];
   
    // zwrócenie rezultatu
    * dataOut = new_vertex;
}

// funkcja rysująca napis w wybranym miejscu

void DrawString( int x, int y, char * string )
{
    // położenie napisu
    glRasterPos2i( 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 Display()
{
    // kolor tła - zawartość bufora koloru
    glClearColor( 1.0, 1.0, 1.0, 1.0 );
   
    // czyszczenie bufora koloru
    glClear( GL_COLOR_BUFFER_BIT );
   
    // wybór macierzy modelowania
    glMatrixMode( GL_MODELVIEW );
   
    // macierz modelowania = macierz jednostkowa
    glLoadIdentity();
   
    // kolor wielokąta
    glColor3f( 0.0, 1.0, 0.0 );
   
    // utworzenie obiektu podziału
    GLUtesselator * tess = gluNewTess();
   
    // dowiązanie funkcji zwrotnych
    gluTessCallback( tess, GLU_TESS_VERTEX,( _GLUfuncptr ) glVertex3dv );
    gluTessCallback( tess, GLU_TESS_BEGIN,( _GLUfuncptr ) beginCallback );
    gluTessCallback( tess, GLU_TESS_END,( _GLUfuncptr ) glEnd );
    gluTessCallback( tess, GLU_TESS_ERROR,( _GLUfuncptr ) errorCallback );
    gluTessCallback( tess, GLU_TESS_COMBINE,( _GLUfuncptr ) combineCallback );
   
    // właściwość GLU_TESS_WINDING_RULE
    gluTessProperty( tess, GLU_TESS_WINDING_RULE, winding_rule );
   
    // właściwość GLU_TESS_BOUNDARY_ONLY
    gluTessProperty( tess, GLU_TESS_BOUNDARY_ONLY, boundary_only );
   
    // początek definicji wielokąta
    gluTessBeginPolygon( tess, NULL );
   
    // początek definicji konturu
    gluTessBeginContour( tess );
   
    // definicja kolejnych wierzchołów wielokąta
    for( int i = 0; i < vertex_count; i++ )
         gluTessVertex( tess, vertex[ i ], vertex[ i ] );
   
    // koniec definicji konturu
    gluTessEndContour( tess );
   
    // koniec definicji wielokąta
    gluTessEndPolygon( tess );
   
    // usunięcie obiektu podziału
    gluDeleteTess( tess );
   
    // kolor numerów wierzchołków i krawędzi wielokąta
    glColor3f( 0.0, 0.0, 0.0 );
   
    // narysowanie krawędzi wielokąta
    if( primitive != GL_LINE_LOOP )
    {
        glBegin( GL_LINE_LOOP );
        for( int i = 0; i < vertex_count; i++ )
             glVertex3dv( vertex[ i ] );
       
        glEnd();
    }
   
    // rysowanie numerów wierzchołków wielokąta
    for( int i = 0; i < vertex_count; i++ )
    {
        // położenie napisu
        glRasterPos2i( vertex[ i ][ 0 ] + 2, vertex[ i ][ 1 ] + 2 );
       
        // konwersja liczba -> ciąg znaków
        char str[ 10 ];
        sprintf( str, "%i", i + 1 );
       
        // długość napisu
        int len = strlen( str );
       
        // wyświetlenie kolejnych znaków (cyfr) napisu
        for( int j = 0; j < len; j++ )
             glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[ j ] );
       
    }
   
    // rodzaj prymitywu użytego do rysowania wielokąta
    if( primitive == GL_TRIANGLE_FAN )
         DrawString( 2, 2, "GLU_TESS_BEGIN = GL_TRIANGLE_FAN" );
    else
    if( primitive == GL_TRIANGLE_STRIP )
         DrawString( 2, 2, "GLU_TESS_BEGIN = GL_TRIANGLE_STRIP" );
    else
    if( primitive == GL_TRIANGLES )
         DrawString( 2, 2, "GLU_TESS_BEGIN = GL_TRIANGLES" );
    else
    if( primitive == GL_LINE_LOOP )
         DrawString( 2, 2, "GLU_TESS_BEGIN = GL_LINE_LOOP" );
   
    // właściwość GLU_TESS_BOUNDARY_ONLY
    if( boundary_only == GL_TRUE )
         DrawString( 2, 16, "GLU_TESS_BOUNDARY_ONLY = GL_TRUE" );
    else
         DrawString( 2, 16, "GLU_TESS_BOUNDARY_ONLY = GL_FALSE" );
   
    // właściwość GLU_TESS_WINDING_RULE
    switch(( int ) winding_rule )
    {
    case GLU_TESS_WINDING_ODD:
        DrawString( 2, 30, "GLU_TESS_WINDING_RULE = GLU_TESS_WINDING_ODD" );
        break;
    case GLU_TESS_WINDING_NONZERO:
        DrawString( 2, 30, "GLU_TESS_WINDING_RULE = GLU_TESS_WINDING_NONZERO" );
        break;
    case GLU_TESS_WINDING_POSITIVE:
        DrawString( 2, 30, "GLU_TESS_WINDING_RULE = GLU_TESS_WINDING_POSITIVE" );
        break;
    case GLU_TESS_WINDING_NEGATIVE:
        DrawString( 2, 30, "GLU_TESS_WINDING_RULE = GLU_TESS_WINDING_NEGATIVE" );
        break;
    case GLU_TESS_WINDING_ABS_GEQ_TWO:
        DrawString( 2, 30, "GLU_TESS_WINDING_RULE = GLU_TESS_WINDING_ABS_GEQ_TWO" );
        break;
    }
   
    // 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();
   
    // rzutowanie prostokątne
    gluOrtho2D( 0, width, 0, height );
   
    // generowanie sceny 3D
    Display();
}

// obsługa przycisków myszki

void MouseButton( int button, int state, int x, int y )
{
    if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN && vertex_count < MAX_VERTEX )
    {
        // zapamiętanie współrzędnych wierzchołka wielokąta
        vertex[ vertex_count ][ 0 ] = x;
        vertex[ vertex_count ][ 1 ] = glutGet( GLUT_WINDOW_HEIGHT ) - y;
        vertex[ vertex_count ][ 2 ] = 0.0;
       
        // następny wierzchołek
        vertex_count++;
       
        // odrysowanie sceny
        Display();
    }
}

// obsługa menu podręcznego

void Menu( int value )
{
    switch( value )
    {
        // właściwość GLU_TESS_WINDING_RULE
    case GLU_TESS_WINDING_ODD:
    case GLU_TESS_WINDING_NONZERO:
    case GLU_TESS_WINDING_POSITIVE:
    case GLU_TESS_WINDING_NEGATIVE:
    case GLU_TESS_WINDING_ABS_GEQ_TWO:
        winding_rule = value;
        Display();
        break;
       
        // właściwość GLU_TESS_BOUNDARY_ONLY
    case GLU_TESS_BOUNDARY_ONLY:
        boundary_only = !boundary_only;
        Display();
        break;
       
        // usuwanie wierzchołków
    case CLEAR_VERTEX:
        vertex_count = 0;
        Display();
        break;
       
        // wyjście
    case EXIT:
        exit( 0 );
    }
}

int main( int argc, char * argv[] )
{
    // inicjalizacja biblioteki GLUT
    glutInit( & argc, argv );
   
    // inicjalizacja bufora ramki
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
   
    // rozmiary głównego okna programu
    glutInitWindowSize( 500, 500 );
   
    // utworzenie głównego okna programu
    #ifdef WIN32
   
    glutCreateWindow( "Podział wielokątów" );
    #else
   
    glutCreateWindow( "Podzial wielokatow" );
    #endif
   
    // dołączenie funkcji generującej scenę 3D
    glutDisplayFunc( Display );
   
    // dołączenie funkcji wywoływanej przy zmianie rozmiaru okna
    glutReshapeFunc( Reshape );
   
    // obsługa przycisków myszki
    glutMouseFunc( MouseButton );
   
    // utworzenie podmenu - GLU_TESS_WINDING_RULE
    int MenuWindingRule = glutCreateMenu( Menu );
    glutAddMenuEntry( "GLU_TESS_WINDING_ODD", GLU_TESS_WINDING_ODD );
    glutAddMenuEntry( "GLU_TESS_WINDING_NONZERO", GLU_TESS_WINDING_NONZERO );
    glutAddMenuEntry( "GLU_TESS_WINDING_POSITIVE", GLU_TESS_WINDING_POSITIVE );
    glutAddMenuEntry( "GLU_TESS_WINDING_NEGATIVE", GLU_TESS_WINDING_NEGATIVE );
    glutAddMenuEntry( "GLU_TESS_WINDING_ABS_GEQ_TWO", GLU_TESS_WINDING_ABS_GEQ_TWO );
   
    // menu główne
    glutCreateMenu( Menu );
    glutAddSubMenu( "GLU_TESS_WINDING_RULE", MenuWindingRule );
    glutAddMenuEntry( "GLU_TESS_BOUNDARY_ONLY: GL_TRUE/GL_FALSE", GLU_TESS_BOUNDARY_ONLY );
   
    #ifdef WIN32
   
    glutAddMenuEntry( "Usuń wierzchołki", CLEAR_VERTEX );
    glutAddMenuEntry( "Wyjście", EXIT );
    #else
   
    glutAddMenuEntry( "Usun wierzcholki", CLEAR_VERTEX );
    glutAddMenuEntry( "Wyjscie", EXIT );
    #endif
   
    // określenie przycisku myszki obsługującego menu podręczne
    glutAttachMenu( GLUT_RIGHT_BUTTON );
   
    // wprowadzenie programu do obsługi pętli komunikatów
    glutMainLoop();
    return 0;
}

Plik wielokaty.cpp

C/C++
/*
(c) Janusz Ganczarski
http://www.januszg.hg.pl
JanuszG(małpeczka)enter.net.pl
*/

#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>

// wzór wypełnienia wielokąta - szachownica 4x4

GLubyte chequers4x4[] =
{
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0x0F, 0x0F, 0x0F, 0x0F, // 00001111000011110000111100001111
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0, // 11110000111100001111000011110000
    0xF0, 0xF0, 0xF0, 0xF0 // 11110000111100001111000011110000
};

// wzór wypełnienia wielokąta - szachownica 8x8

GLubyte chequers8x8[] =
{
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0x00, 0xFF, 0x00, 0xFF, // 00000000111111110000000011111111
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
    0xFF, 0x00, 0xFF, 0x00, // 11111111000000001111111100000000
};

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

enum
{
    RECTANGLES = GL_POLYGON + 100, // prostokąty
    CLEAR_VERTEX, // usuwanie wierzchołków
    MODE_FRONT_FACE_POINT, // przednia strona - wierzchołki
    MODE_FRONT_FACE_LINE, // przednia strona - krawędzie
    MODE_FRONT_FACE_FILL, // przednia strona - wypełnienie
    MODE_BACK_FACE_POINT, // tylna strona - wierzchołki
    MODE_BACK_FACE_LINE, // tylna strona - krawędzie
    MODE_BACK_FACE_FILL, // tylna strona - wypełnienie
    CHEQUERS_8X8, // wzór wypełnienia - szachownia 8x8
    CHEQUERS_4X4, // wzór wypełnienia - szachownia 4x4
    CULL_FACE_ON_OFF, // nierysowanie stron wielokąta włącz/wyłącz
    POLYGON_STIPPLE_ON_OFF, // wypełnianie wielokąta wzorem włącz/wyłącz
    EDGE_FLAG_ON_OFF, // ukrywanie krawędzi włącz/wyłącz
    EXIT // wyjście
};

// rodzaj rysowanego wielokąta

GLenum polygon = GL_TRIANGLES;

// nierysowana strona wielokątów

GLenum cull_face = GL_BACK;

// orientacja stron wielokątów

GLenum front_face = GL_CCW;

// sposób rysowania przedniej i tylnej strony wielokąta

GLenum polygon_mode_front_face = GL_FILL;
GLenum polygon_mode_back_face = GL_FILL;

// wzór wypełnienia wielokąta

GLubyte * polygon_stipple = chequers8x8;

// nierysowanie stron wielokąta włącz/wyłącz

GLboolean cull_face_on_off = GL_TRUE;

// wypełnianie wielokąta wzorem włącz/wyłącz

GLboolean polygon_stipple_on_off = GL_TRUE;

// ukrywanie krawędzi wielokąta

GLboolean edge_flag = GL_TRUE;

// współrzędne wierzchołków wielokątów

std::vector < GLint > vertex_x;
std::vector < GLint > vertex_y;

// znaczniki ukrywania krawędzi wielokąta

std::vector < GLboolean > edge_flags;

// funkcja rysująca napis w wybranym miejscu

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

// wyświetlenie aktualnych parametrów renderingu

void DrawParameters()
{
    // zmienne pomocnicze
    char string[ 100 ];
    GLfloat f;
    GLboolean b;
    GLint itab[ 2 ], i;
   
    // kolor napisów
    glColor3f( 0.0, 0.0, 0.0 );
   
    // nierysowanie stron wielokątów: włączone/wyłączone
    if( glIsEnabled( GL_CULL_FACE ) == GL_TRUE )
         strcpy( string, "GL_CULL_FACE: true" );
    else
         strcpy( string, "GL_CULL_FACE: false" );
   
    DrawString( 0, 1, string );
   
    // nierysowana strona wielokątów
    glGetIntegerv( GL_CULL_FACE_MODE, & i );
    if( i == GL_BACK )
         strcpy( string, "GL_CULL_FACE_MODE: GL_BACK" );
    else
    if( i == GL_FRONT )
         strcpy( string, "GL_CULL_FACE_MODE: GL_FRONT" );
    else
    if( i == GL_FRONT_AND_BACK )
         strcpy( string, "GL_CULL_FACE_MODE: GL_FRONT_AND_BACK" );
   
    DrawString( 0, 16, string );
   
    // orientacja stron wielokątów
    glGetIntegerv( GL_FRONT_FACE, & i );
    if( i == GL_CCW )
         strcpy( string, "GL_FRONT_FACE: GL_CCW" );
    else
    if( i == GL_CW )
         strcpy( string, "GL_FRONT_FACE: GL_CW" );
   
    DrawString( 0, 31, string );
   
    // sposób rysowania przedniej i tylnej strony wielokąta
    glGetIntegerv( GL_POLYGON_MODE, itab );
    strcpy( string, "GL_POLYGON_MODE: " );
   
    // przednia strona wielokąta - pierwszy element tablicy
    if( itab[ 0 ] == GL_POINT )
         strcat( string, "GL_POINT (front), " );
    else
    if( itab[ 0 ] == GL_LINE )
         strcat( string, "GL_LINE (front), " );
    else
    if( itab[ 0 ] == GL_FILL )
         strcat( string, "GL_FILL (front), " );
   
    // tylna strona wielokąta - drugi element tablicy
    if( itab[ 1 ] == GL_POINT )
         strcat( string, "GL_POINT (back)" );
    else
    if( itab[ 1 ] == GL_LINE )
         strcat( string, "GL_LINE (back)" );
    else
    if( itab[ 1 ] == GL_FILL )
         strcat( string, "GL_FILL (back)" );
   
    DrawString( 0, 46, string );
   
    // wzór wypełnienia wielokąta: włączony/wyłączony
    if( glIsEnabled( GL_POLYGON_STIPPLE ) == GL_TRUE )
         strcpy( string, "GL_POLYGON_STIPPLE: true" );
    else
         strcpy( string, "GL_POLYGON_STIPPLE: false" );
   
    DrawString( 0, 61, string );
   
    // ukrywanie krawędzi
    glGetBooleanv( GL_EDGE_FLAG, & b );
    if( b == GL_TRUE )
         strcpy( string, "GL_EDGE_FLAG: true" );
    else
         strcpy( string, "GL_EDGE_FLAG: false" );
   
    DrawString( 0, 76, string );
   
    // bieżąca wielkość punktu
    glGetFloatv( GL_POINT_SIZE, & f );
    sprintf( string, "GL_POINT_SIZE: %f", f );
    DrawString( 0, 91, string );
   
    // bieżąca szerokość linii
    glGetFloatv( GL_LINE_WIDTH, & f );
    sprintf( string, "GL_LINE_WIDTH: %f", f );
    DrawString( 0, 106, string );
}

// funkcja generująca scenę 3D

void Display()
{
    // kolor tła - zawartość bufora koloru
    glClearColor( 1.0, 1.0, 1.0, 1.0 );
   
    // czyszczenie bufora koloru
    glClear( GL_COLOR_BUFFER_BIT );
   
    // wybór macierzy modelowania
    glMatrixMode( GL_MODELVIEW );
   
    // macierz modelowania = macierz jednostkowa
    glLoadIdentity();
   
    // kolor wielokąta
    glColor3f( 1.0, 0.0, 0.0 );
   
    // orientacja stron wielokąta
    glFrontFace( front_face );
   
    // sposób rysowania przedniej i tylnej strony wielokąta
    glPolygonMode( GL_FRONT, polygon_mode_front_face );
    glPolygonMode( GL_BACK, polygon_mode_back_face );
   
    // włączenie wypełniania wielokątów wzorem
    if( polygon_stipple_on_off == GL_TRUE )
         glEnable( GL_POLYGON_STIPPLE );
   
    // włączenie nierysowania wybranej strony wielokątów
    if( cull_face_on_off == GL_TRUE )
         glEnable( GL_CULL_FACE );
   
    // wzór wypełnienia wielokąta
    glPolygonStipple( polygon_stipple );
   
    // określenie nierysowanej strony wielokąta
    glCullFace( cull_face );
   
    // wielkość wierzchołków wielokąta
    glPointSize( 3.0 );
   
    // szerokość krawędzi wielokąta
    glLineWidth( 3.0 );
   
    // rysowanie wielokąta
    if( polygon == RECTANGLES )
    for( unsigned int i = 0; i + 1 < vertex_x.size(); i += 2 )
         glRecti( vertex_x[ i ], vertex_y[ i ], vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
    else
         glBegin( polygon );
   
    for( unsigned int i = 0; i < vertex_x.size(); i++ )
    {
        glEdgeFlag( edge_flags[ i ] );
        glVertex2i( vertex_x[ i ], vertex_y[ i ] );
    }
    glEnd();
   
    // wypisanie parametrów renderingu
    DrawParameters();
   
    // wyłączenie wypełniania wielokątów wzorem
    glDisable( GL_POLYGON_STIPPLE );
   
    // włączenie nierysowania wybranej strony wielokątów
    glDisable( GL_CULL_FACE );
   
    // kolor numerów wierzchołków przymitywu
    glColor3f( 0.0, 0.0, 0.0 );
   
    // rysowanie numerów wierzchołków prymitywów
    for( unsigned int i = 0; i < vertex_x.size(); i++ )
    {
        // położenie napisu
        glRasterPos2i( vertex_x[ i ] + 2, vertex_y[ i ] + 2 );
       
        // konwersja liczba -> ciąg znaków
        char str[ 10 ];
        sprintf( str, "%i", i + 1 );
       
        // długość napisu
        int len = strlen( str );
       
        // wyświetlenie kolejnych znaków (cyfr) napisu
        for( int i = 0; i < len; i++ )
             glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[ i ] );
       
    }
   
    // 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();
   
    // rzutowanie prostokątne
    gluOrtho2D( 0, width, 0, height );
   
    // generowanie sceny 3D
    Display();
}

// obsługa przycisków myszki

void MouseButton( int button, int state, int x, int y )
{
    if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
    {
        // zapamiętanie współrzędnych wierzchołka prymitywu
        // oraz zmacznika rysowania krawędzi
        vertex_x.insert( vertex_x.end(), x );
        vertex_y.insert( vertex_y.end(), glutGet( GLUT_WINDOW_HEIGHT ) - y );
        edge_flags.insert( edge_flags.end(), edge_flag );
        Display();
    }
}

// obsługa menu podręcznego

void Menu( int value )
{
    switch( value )
    {
        // trójkąty
    case GL_TRIANGLES:
        polygon = GL_TRIANGLES;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - trójkąty (GL_TRIANGLES)" );
        #else
       
        glutSetWindowTitle( "Wielokaty - trojkaty (GL_TRIANGLES)" );
        #endif
       
        Display();
        break;
       
        // wstęga trójkątów
    case GL_TRIANGLE_STRIP:
        polygon = GL_TRIANGLE_STRIP;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - wstęga trójkątów (GL_TRIANGLE_STRIP)" );
        #else
       
        glutSetWindowTitle( "Wielokaty - wstega trojkatow (GL_TRIANGLE_STRIP)" );
        #endif
       
        Display();
        break;
       
        // wachlarz trójkątów
    case GL_TRIANGLE_FAN:
        polygon = GL_TRIANGLE_FAN;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - wachlarz trójkątów (GL_TRIANGLE_FAN)" );
        #else
       
        glutSetWindowTitle( "Wielokaty - wachlarz trojkatow (GL_TRIANGLE_FAN)" );
        #endif
       
        Display();
        break;
       
        // czworokąty
    case GL_QUADS:
        polygon = GL_QUADS;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - czworokąty (GL_QUADS)" );
        #else
       
        glutSetWindowTitle( "Wielokaty - czworokaty (GL_QUADS)" );
        #endif
       
        Display();
        break;
       
        // wstęga czworokątów
    case GL_QUAD_STRIP:
        polygon = GL_QUAD_STRIP;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - wstęga czworokątów (GL_QUAD_STRIP)" );
        #else
       
        glutSetWindowTitle( "Wielokaty - wstega czworokatow (GL_QUAD_STRIP)" );
        #endif
       
        Display();
        break;
       
        // wielokąt
    case GL_POLYGON:
        polygon = GL_POLYGON;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąt (GL_POLYGON)" );
        #else
       
        glutSetWindowTitle( "Wielokat (GL_POLYGON)" );
        #endif
       
        Display();
        break;
       
        // prostokąty
    case RECTANGLES:
        polygon = RECTANGLES;
        #ifdef WIN32
       
        glutSetWindowTitle( "Wielokąty - prostokąty" );
        #else
       
        glutSetWindowTitle( "Wielokaty - prostokaty" );
        #endif
       
        Display();
        break;
       
        // usuwanie wierzchołków
    case CLEAR_VERTEX:
        vertex_x.erase( vertex_x.begin(), vertex_x.end() );
        vertex_y.erase( vertex_y.begin(), vertex_y.end() );
        edge_flags.erase( edge_flags.begin(), edge_flags.end() );
        Display();
        break;
       
        // orientacja stron wielokąta odwrotna do ruchu wskazówek zegara
    case GL_CCW:
        front_face = GL_CCW;
        Display();
        break;
       
        // orientacja stron wielokąta zgodna z ruchem wskazówek zegara
    case GL_CW:
        front_face = GL_CW;
        Display();
        break;
       
        // nierysowana strona wielokąta - przednia
    case GL_FRONT:
        cull_face = GL_FRONT;
        Display();
        break;
       
        // nierysowana strona wielokąta - tylna
    case GL_BACK:
        cull_face = GL_BACK;
        Display();
        break;
       
        // nierysowana strona wielokąta - przednia i tylna
    case GL_FRONT_AND_BACK:
        cull_face = GL_FRONT_AND_BACK;
        Display();
        break;
       
        // przednia strona - wierzchołki
    case MODE_FRONT_FACE_POINT:
        polygon_mode_front_face = GL_POINT;
        Display();
        break;
       
        // przednia strona - krawędzie
    case MODE_FRONT_FACE_LINE:
        polygon_mode_front_face = GL_LINE;
        Display();
        break;
       
        // przednia strona - wypełnienie
    case MODE_FRONT_FACE_FILL:
        polygon_mode_front_face = GL_FILL;
        Display();
        break;
       
        // tylna strona - wierzchołki
    case MODE_BACK_FACE_POINT:
        polygon_mode_back_face = GL_POINT;
        Display();
        break;
       
        // tylna strona - krawędzie
    case MODE_BACK_FACE_LINE:
        polygon_mode_back_face = GL_LINE;
        Display();
        break;
       
        // tylna strona - wypełnienie
    case MODE_BACK_FACE_FILL:
        polygon_mode_back_face = GL_FILL;
        Display();
        break;
       
        // wzór wypełnienia - szachownica 8x8
    case CHEQUERS_8X8:
        polygon_stipple = chequers8x8;
        Display();
        break;
       
        // wzór wypełnienia - szachownica 4x4
    case CHEQUERS_4X4:
        polygon_stipple = chequers4x4;
        Display();
        break;
       
        // nierysowanie stron wielokąta: włącz/wyłącz
    case CULL_FACE_ON_OFF:
        cull_face_on_off = !cull_face_on_off;
        Display();
        break;
       
        // wypełnianie wielokąta wzorem: włącz/wyłącz
    case POLYGON_STIPPLE_ON_OFF:
        polygon_stipple_on_off = !polygon_stipple_on_off;
        Display();
        break;
       
        // ukrywanie krawędzi włącz/wyłącz
    case EDGE_FLAG_ON_OFF:
        edge_flag = !edge_flag;
        Display();
        break;
       
        // wyjście
    case EXIT:
        exit( 0 );
    }
}

int main( int argc, char * argv[] )
{
    // inicjalizacja biblioteki GLUT
    glutInit( & argc, argv );
   
    // inicjalizacja bufora ramki
    glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
   
    // rozmiary głównego okna programu
    glutInitWindowSize( 550, 500 );
   
    // utworzenie głównego okna programu
    #ifdef WIN32
   
    glutCreateWindow( "Wielokąty - trójkąty (GL_TRIANGLES)" );
    #else
   
    glutCreateWindow( "Wielokaty - trojkaty (GL_TRIANGLES)" );
    #endif
   
    // dołączenie funkcji generującej scenę 3D
    glutDisplayFunc( Display );
   
    // dołączenie funkcji wywoływanej przy zmianie rozmiaru okna
    glutReshapeFunc( Reshape );
   
    // obsługa przycisków myszki
    glutMouseFunc( MouseButton );
   
    // utworzenie podmenu - Wielokąty
    int MenuPolygons = glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddMenuEntry( "Trójkąty (GL_TRIANGLES)", GL_TRIANGLES );
    glutAddMenuEntry( "Wstęga trójkątów (GL_TRIANGLE_STRIP)", GL_TRIANGLE_STRIP );
    glutAddMenuEntry( "Wachlarz trójkątów (GL_TRIANGLE_FAN)", GL_TRIANGLE_FAN );
    glutAddMenuEntry( "Czworokąty (GL_QUADS)", GL_QUADS );
    glutAddMenuEntry( "Wstęga czworokątów (GL_QUAD_STRIP)", GL_QUAD_STRIP );
    glutAddMenuEntry( "Wielokąt (GL_POLYGON)", GL_POLYGON );
    glutAddMenuEntry( "Prostokąty", RECTANGLES );
    #else
   
    glutAddMenuEntry( "Trojkąty (GL_TRIANGLES)", GL_TRIANGLES );
    glutAddMenuEntry( "Wstega trojkatow (GL_TRIANGLE_STRIP)", GL_TRIANGLE_STRIP );
    glutAddMenuEntry( "Wachlarz trojkstow (GL_TRIANGLE_FAN)", GL_TRIANGLE_FAN );
    glutAddMenuEntry( "Czworokaty (GL_QUADS)", GL_QUADS );
    glutAddMenuEntry( "Wstega czworokatow (GL_QUAD_STRIP)", GL_QUAD_STRIP );
    glutAddMenuEntry( "Wielokat (GL_POLYGON)", GL_POLYGON );
    glutAddMenuEntry( "Prostokaty", RECTANGLES );
    #endif
   
    // utworzenie podmenu - Orientacja stron wielokąta
    int PolygonFaceOrientation = glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddMenuEntry( "Odwrotna do ruchu wskazówek zegara (GL_CCW)", GL_CCW );
    glutAddMenuEntry( "Zgodna z ruchem wskazówek zegara (GL_CW)", GL_CW );
    #else
   
    glutAddMenuEntry( "Odwrotna do ruchu wskazowek zegara (GL_CCW)", GL_CCW );
    glutAddMenuEntry( "Zgodna z ruchem wskazowek zegara (GL_CW)", GL_CW );
    #endif
   
    // utworzenie podmenu - Nierysowana strona wielokąta
    int PolygonCullFace = glutCreateMenu( Menu );
    glutAddMenuEntry( "Przednia (GL_FRONT)", GL_FRONT );
    glutAddMenuEntry( "Tylna (GL_BACK)", GL_BACK );
    glutAddMenuEntry( "Przednia i tylna (GL_FRONT_AND_BACK)", GL_FRONT_AND_BACK );
   
    // utworzenie podmenu - Rysowanie przedniej strony wielokąta
    int PolygonModeFrontFace = glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddMenuEntry( "Wierzchołki (GL_POINT)", MODE_FRONT_FACE_POINT );
    glutAddMenuEntry( "Krawędzie (GL_LINE)", MODE_FRONT_FACE_LINE );
    glutAddMenuEntry( "Wypełnienie (GL_FILL)", MODE_FRONT_FACE_FILL );
    #else
   
    glutAddMenuEntry( "Wierzcholki (GL_POINT)", MODE_FRONT_FACE_POINT );
    glutAddMenuEntry( "Krawedzie (GL_LINE)", MODE_FRONT_FACE_LINE );
    glutAddMenuEntry( "Wypelnienie (GL_FILL)", MODE_FRONT_FACE_FILL );
    #endif
   
    // utworzenie podmenu - Rysowanie tylnej strony wielokąta
    int PolygonModeBackFace = glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddMenuEntry( "Wierzchołki (GL_POINT)", MODE_BACK_FACE_POINT );
    glutAddMenuEntry( "Krawędzie (GL_LINE)", MODE_BACK_FACE_LINE );
    glutAddMenuEntry( "Wypełnienie (GL_FILL)", MODE_BACK_FACE_FILL );
    #else
   
    glutAddMenuEntry( "Wierzcholki (GL_POINT)", MODE_BACK_FACE_POINT );
    glutAddMenuEntry( "Krawedzie (GL_LINE)", MODE_BACK_FACE_LINE );
    glutAddMenuEntry( "Wypelnienie (GL_FILL)", MODE_BACK_FACE_FILL );
    #endif
   
    // utworzneie podmenu - Wzór wypełnienia wielokąta
    int PolygonStipple = glutCreateMenu( Menu );
    glutAddMenuEntry( "Szachownica 8x8", CHEQUERS_8X8 );
    glutAddMenuEntry( "Szachownica 4x4", CHEQUERS_4X4 );
   
    // menu główne
    glutCreateMenu( Menu );
    #ifdef WIN32
   
    glutAddSubMenu( "Wielokąty", MenuPolygons );
    glutAddSubMenu( "Orientacja stron wielokąta", PolygonFaceOrientation );
    glutAddSubMenu( "Nierysowana strona wielokąta", PolygonCullFace );
    glutAddSubMenu( "Rysowanie przedniej strony wielokąta", PolygonModeFrontFace );
    glutAddSubMenu( "Rysowanie tylnej strony wielokąta", PolygonModeBackFace );
    glutAddSubMenu( "Wzór wypełnienia wielokąta", PolygonStipple );
    glutAddMenuEntry( "Nierysowanie stron wielokąta: włącz/wyłącz", CULL_FACE_ON_OFF );
    glutAddMenuEntry( "Wypełnianie wielokąta wzorem: włącz/wyłącz", POLYGON_STIPPLE_ON_OFF );
    glutAddMenuEntry( "Ukrywanie krawędzi włącz/wyłącz", EDGE_FLAG_ON_OFF );
    glutAddMenuEntry( "Usuń wierzchołki", CLEAR_VERTEX );
    glutAddMenuEntry( "Wyjście", EXIT );
    #else
   
    glutAddSubMenu( "Wielokaty", MenuPolygons );
    glutAddSubMenu( "Orientacja stron wielokata", PolygonFaceOrientation );
    glutAddSubMenu( "Nierysowana strona wielokata", PolygonCullFace );
    glutAddSubMenu( "Rysowanie przedniej strony wielokata", PolygonModeFrontFace );
    glutAddSubMenu( "Rysowanie tylnej strony wielokata", PolygonModeBackFace );
    glutAddSubMenu( "Wzor wypelnienia wielokata", PolygonStipple );
    glutAddMenuEntry( "Nierysowanie stron wielokata: włacz/wyłacz", CULL_FACE_ON_OFF );
    glutAddMenuEntry( "Wypelnianie wielokata wzorem: włacz/wyłacz", POLYGON_STIPPLE_ON_OFF );
    glutAddMenuEntry( "Ukrywanie krawedzi włacz/wyłacz", EDGE_FLAG_ON_OFF );
    glutAddMenuEntry( "Usun wierzcholki", CLEAR_VERTEX );
    glutAddMenuEntry( "Wyjscie", EXIT );
    #endif
   
    // określenie przycisku myszki obsługującego menu podręczne
    glutAttachMenu( GLUT_RIGHT_BUTTON );
   
    // wprowadzenie programu do obsługi pętli komunikatów
    glutMainLoop();
    return 0;
}
Poprzedni dokument Następny dokument
Elementarne obiekty geometryczne Kolory i cieniowanie