Biblioteka OpenGL oferuje kilka podstawowych prymitywów graficznych, które słuza do modelowania dowolnych obiektów. Projektanci biblioteki celowo nie umiescili w niej bardziej skomplikowanych obiektów (wybrane powierzchnie 3D zawiera biblioteka GLU). Decyzja o stopniu złozonosci stosowanych obiektów została pozostawiona uzytkownikom i mozliwosciom konkretnych implementacji OpenGL.
Wybór rodzaju prymitywu
Definiowanie współrzednych wierzchołków figur podstawowych musi zawierac sie pomiedzy wywołaniami funkcji:
void glBegin( GLenum mode )
void glEnd( void )
Parametr mode okresla rodzaj prymitywu, którego wierzchołki beda definiowane. Parametr przyjmuje jedna z ponizszych wartosci:
Szczególne znaczenie w grafice 3D ma trójkat. Zasadnicza zaleta trójkąta jest jego ... płaskosc, co w geometrycznym ujeciu oznacza, ze trzy niewspółliniowe punkty wyznaczaja dokładnie jedna płaszczyzne w przestrzeni trójwymiarowej.
Przy budowie skomplikowanych obiektów 3D składajacych sie z trójkątów proporcjonalnie rosnie ilosc wierzchołków, czyli ilosc danych przetwarzanych przez procesor komputera i karty graficznej. Stad duze znaczenie ma mozliwosc definiowania wsteg (patrz rysunek 1) i wachlarzy trójkatów (rysunek 2). Prymitywy te bowiem umozliwiaja definiowanie kolejnych trójkątów tylko przy pomocy jednego wierzchołka. Oczywiscie nie w każdym przypadku bedzie mozliwe wykorzystanie wstegi lub wachlarza trójkatów, ale wykorzystywac te prymitywy zawsze, gdy jest to mozliwe.
Nieco bardziej skomplikowana grupa prymitywów graficznych obsługiwanych przez biblioteke OpenGL sa czworokaty i wstegi czworokatów (patrz rysunki 3 i 4). Zastosowanie tych prymitywów moze byc wygodne w wielu sytuacjach, ale trzeba liczyc sie z nastepujacymi ograniczeniami:
Ponadto nalezy dodac, ze wiele implementacji biblioteki OpenGL w procesie przetwarzania wierzchołków dzieli czworokaty na trójkaty, co takze może powodowac nieoczekiwane efekty.
Ostatnim prymitywem graficznym jest wielokat. Wielokaty podlegaja takim samym ograniczeniom jak czworokaty. Ich wierzchołki musza znajdowac sie w jednej płaszczyznie, a krawedzie nie powinny sie przecinac. Podobnie jak w przypadku czworokatów, wiele implementacji OpenGL dzieli wielokaty
na trójkaty, co moze byc zródłem niepozadanych efektów. Specyfikacja wskazuje ograniczona grupe funkcji biblioteki OpenGL, które moga byc wywoływane pomiedzy glBegin a glEnd. Naleza do nich następujące funkcje (lub grupy funkcji): glVertex, glColor, glSecondaryColor, glIndex, glNormal, glTexCoord, glMultiTexCoord, glVertexAttrib, glFogCoord, glArrayElement, glEvalCoord, glEvalPoint, glMaterial, glEdgeFlag, glCallList i glCallLists. Wywołanie funkcji spoza powyższej grupy spowoduje zgłoszenie błedu. Nie ma natomiast ograniczen co do wywoływania funkcji pochodzacych z innych bibliotek wykorzystywanych w programie.
Definiowanie współrzędnych wierzchołków figur
Współrzedne wierzchołków figur podstawowych standardowo definiuje sie przy pomocy funkcji z grupy glVertex. Co do zasady wierzchołki prymitywów graficznych opisywane sa w bibliotece OpenGL przy pomocy czterech współrzednych: (x, y, z,w). Poniewaz nie we wszystkich przypadkach konieczne jest stosowanie wszystkich współrzednych, OpenGL zawiera funkcje definiujace tylko trzy pierwsze współrzedne (wtedy wartosc współrzędnej w wynosi domyslnie 1) oraz funkcje definiujace dwie pierwsze współrzędne (wtedy wartosc współrzednej z wynosi domyslnie 0, a wartosc współrzędnej w wynosi 1).
Grupa glVertex obejmuje 24 funkcje, które mozna podzielic na 3 równoliczne podgrupy, kazda wymagajaca innej ilosci współrzednych. Parametrami funkcji z kazdej podgrup sa albo kolejne współrzedne wierzchołków, albo wskazniki na tablice zawierajace te współrzedne. Jak zapewne Czytelnik zauwazył, wiekszosc prymitywów wymaga scisle okreslonej ilosci wierzchołków. OpenGL w trakcie procesu rysowania prymitywu pomija te ostatnie wierzchołki, których ilosc nie pozwala na zbudowanie prymitywu.
Funkcje z grupy glVertex2
void glVertex2d( GLdouble x, GLdouble y )
void glVertex2f( GLfloat x, GLfloat y )
void glVertex2i( GLint x, GLint y )
void glVertex2s( GLshort x, GLshort y )
void glVertex2dv( const GLdouble * v )
void glVertex2fv( const GLfloat * v )
void glVertex2iv( const GLint * v )
void glVertex2sv( const GLshort * v )
Funkcje z grupy glVertex3
void glVertex3d( GLdouble x, GLdouble y, GLdouble z )
void glVertex3f( GLfloat x, GLfloat y, GLfloat z )
void glVertex3i( GLint x, GLint y, GLint z )
void glVertex3s( GLshort x, GLshort y, GLshort z )
void glVertex3dv( const GLdouble * v )
void glVertex3fv( const GLfloat * v )
void glVertex3iv( const GLint * v )
void glVertex3sv( const GLshort * v )
Funkcje z grupy glVertex4
void glVertex4d( GLdouble x, GLdouble y, GLdouble z, GLdouble w )
void glVertex4f( GLfloat x, GLfloat y, GLfloat z, GLfloat w )
void glVertex4i( GLint x, GLint y, GLint z, GLint w )
void glVertex4s( GLshort x, GLshort y, GLshort z, GLshort w )
void glVertex4dv( const GLdouble * v )
void glVertex4fv( const GLfloat * v )
void glVertex4iv( const GLint * v )
void glVertex4sv( const GLshort * v )
Prostokąty
Wspecjalny sposób potraktowano w bibliotece OpenGL prostokaty. Opracowana została bowiem oddzielna grupa funkcji glRect rysujacych prostokąt na podstawie współrzednych dwóch wierzchołków: lewego górnego i prawego dolnego. Prostokat rysowany jest na płaszczyznie o równaniu Z = 0, a jego boki sa równoległe do osi układu współrzednych. Stanowi to duze oczywiście ograniczenie, ale umozliwia jednoczesnie opracowanie szczególnie szybkiej implementacji rysowania prostokatów.
Podobnie jak funkcje z grupy glVertex, funkcje glRect dostepne sa w wersjach wymagajacych dwóch par współrzednych wierzchołków oraz pobierających wskaznik na tablice ze współrzednymi wierzchołków:
void glRectd( GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2 )
void glRectf( GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2 )
void glRecti( GLint x1, GLint y1, GLint x2, GLint y2 )
void glRects( GLshort x1, GLshort y1, GLshort x2, GLshort y2 )
void glRectdv( const GLdouble * v1, const GLdouble * v2 )
void glRectfv( const GLfloat * v1, const GLfloat * v2 )
void glRectiv( const GLint * v1, const GLint * v2 )
void glRectsv( const GLshort * v1, const GLshort * v2 )
Punkty
Punkt w bibliotece OpenGL nie podlega efektom perspektywy i ma standardowo kształt kwadratu (piksela lub jego wielokrotnosci). Wielkosc rysowanych punktów okresla funkcja:
void glPointSize( GLfloat size )
Parametr size okresla srednice punktu i jego wartosc musi byc wieksza od 0. Domyslnie wielkosc punktów wynosi 1 i jest to jedyna wielkosc, której obsługe wymaga specyfikacja OpenGL. Dopuszczalny zakres wielkosci punktu oraz krok z jakim wielkosc ta moze byc zmieniana zalezy od implementacji biblioteki OpenGL. Punkty o róznych rozmiarach przedstawia rysunek 5.
Linie
Podobnie jak w przypadku punktów biblioteka OpenGL umozliwia zmiane grubosci (szerokosci) rysowanych linii. Słuzy do tego funkcja:
void glLineWidth( GLfloat width )
Parametr okresla grubosc linii i musi byc wiekszy od 0. Domyslnie grubosc linii wynosi 1. Dopuszczalny zakres grubosci linii oraz krok z jakim wielkość ta moze byc zmieniana zalezy od implementacji biblioteki OpenGL.
Poza gruboscia biblioteka OpenGL pozwala na okreslenie wzoru jakim bedzie rysowana linia (patrz rysunek 6). Umozliwia to funkcja:
void glLineStipple( GLint factor, GLushort pattern )
której parametr pattern to 16-bitowa liczba całkowita zawierajaca wzór rysowanej linii, a factor okresla zwielokrotnienie bitów wzoru. Wartosc parametru factor jest ograniczona i w razie potrzeby obcinana do przedziału [1, 256], a wartosc poczatkowa wynosi 1. Poczatkowy wzór linii okresla stała FFFFh, która oznacza linie ciagła. Standardowo rysowanie linii ze wzorami jest wyłaczone. Właczenie tego mechanizmu wymaga wywołania funkcji glEnable z parametrem GL LINE - STIPPLE.
Programy przykładowe
Pierwszy przykładowy program (plik prymitywy graficzne.cpp) pozwala na przetestowanie wszystkich prymitywów graficznych dostępnych w bibliotece OpenGL. Szczególnie wazna jest mozliwosc bezposredniej oceny sposobu konstruowania takich prymitywów jak wstegi trójkatów i czworokatów. Program umozliwia zmiane rodzaju prymitywu bez usuwania współrzędnych wierzchołków poprzedniego prymitywu. Moze dac to czasami bardzo zaskakujace efekty. Do przechowywania współrzednych wierzchołków prymitywów zastosowano klase vector z biblioteki standardowej C++.
Nowym elementem biblioteki GLUT, który pojawił sie w pierwszym przykładowym programie jest wyswietlanie ciagów znaków w postaci numerów wierzchołków prymitywów. Realizuje to funkcja:
void glutBitmapCharacter( void * font, int character )
której parametr font okresla rodzaj wyswietlanej czcionki bitmapowej, a character znak jaki ma zostac wyswietlony. Czcionki bitmapowe sa na stałe zapisane w bibliotece GLUT jako mapy bitowe. GLUT nie zawiera funkcji umozliwiajacych skorzystanie z czcionek bitmapowych zawartych w zewnetrznych plikach.
Biblioteka GLUT w wersji 3.x zawiera nastepujace czcionki bitmapowe:
Jak Czytelnik juz zapewne zauwazył wszystkie czcionki zawieraja znaki ASCII kodowane w standardzie ISO 8859-1, czyli bez polskich liter. Niestety nie istnieje prosta metoda wyswietlenia czcionek zawierajacych polskie litery. W tym miejscu jedynie sygnalizujemy uzycie w programie nowej funkcji:
void glRasterPos2i( GLint x, GLint y )
Funkcja ta, nalezaca do licznej grupy funkcji glRasterPos, okresla położenie wyswietlanej grafiki rastrowej - w tym przypadku liczby określającej numer wierzchołka prymitywu. Dokładny opis operacji na rastrach znajdzie sie w jednym z nastepnych odcinków kursu.
Drugi przykładowy program (plik punkty.cpp) prezentuje podstawowe mozliwosci rysowania punktów w bibliotece OpenGL. Rozmiar punktów reguluja przyciski ?+? (zwiekszenie) i ?-? (zmniejszenie). Rozmiar punktów oraz ich współrzedne przechowywane sa w obiektach klasy vector z biblioteki standardowej C++.
Trzeci przykładowy program (plik linie.cpp) prezentuje podstawowe mozliwosci rysowania linii w bibliotece OpenGL. Szerokosc rysowanej linii reguluja przyciski ?+? (zwiekszenie) i ?-? (zmniejszenie). Menu podręczne udostepnia kilka wzorów linii. Szerokosc i wzór linii oraz współrzedne ich poczatku i konca przechowywane sa w obiektach klasy vector z biblioteki standardowej C++.
Plik prymitywy graficzne.cpp
#include <GL/glut.h>
#include <stdlib.h>
#include <stdio.h>
#include <vector>
enum
{
RECTANGLES = GL_POLYGON + 100,
CLEAR_VERTEX,
EXIT
};
int primitive = GL_POINTS;
std::vector < GLint > vertex_x;
std::vector < GLint > vertex_y;
void Display()
{
glClearColor( 1.0, 1.0, 1.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3f( 0.0, 1.0, 0.0 );
if( primitive == 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( primitive );
for( unsigned int i = 0; i < vertex_x.size(); i++ )
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glEnd();
glColor3f( 0.0, 0.0, 0.0 );
if( primitive == GL_TRIANGLES )
{
glBegin( GL_LINES );
unsigned int pos = 0;
while( vertex_x.size() - pos >= 3 )
{
glVertex2i( vertex_x[ pos + 0 ], vertex_y[ pos + 0 ] );
glVertex2i( vertex_x[ pos + 1 ], vertex_y[ pos + 1 ] );
glVertex2i( vertex_x[ pos + 1 ], vertex_y[ pos + 1 ] );
glVertex2i( vertex_x[ pos + 2 ], vertex_y[ pos + 2 ] );
glVertex2i( vertex_x[ pos + 2 ], vertex_y[ pos + 2 ] );
glVertex2i( vertex_x[ pos + 0 ], vertex_y[ pos + 0 ] );
pos += 3;
}
glEnd();
}
else
if( primitive == GL_TRIANGLE_STRIP )
{
glBegin( GL_LINES );
if( vertex_x.size() > 2 )
{
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
}
for( unsigned int i = 3; i < vertex_x.size(); i++ )
{
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i - 1 ], vertex_y[ i - 1 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i - 2 ], vertex_y[ i - 2 ] );
}
glEnd();
}
else
if( primitive == GL_TRIANGLE_FAN )
{
glBegin( GL_LINES );
if( vertex_x.size() > 2 )
{
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
}
for( unsigned int i = 3; i < vertex_x.size(); i++ )
{
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i - 1 ], vertex_y[ i - 1 ] );
}
glEnd();
}
else
if( primitive == GL_QUADS )
{
glBegin( GL_LINES );
unsigned int pos = 0;
while( vertex_x.size() - pos >= 4 )
{
glVertex2i( vertex_x[ pos + 0 ], vertex_y[ pos + 0 ] );
glVertex2i( vertex_x[ pos + 1 ], vertex_y[ pos + 1 ] );
glVertex2i( vertex_x[ pos + 1 ], vertex_y[ pos + 1 ] );
glVertex2i( vertex_x[ pos + 2 ], vertex_y[ pos + 2 ] );
glVertex2i( vertex_x[ pos + 2 ], vertex_y[ pos + 2 ] );
glVertex2i( vertex_x[ pos + 3 ], vertex_y[ pos + 3 ] );
glVertex2i( vertex_x[ pos + 3 ], vertex_y[ pos + 3 ] );
glVertex2i( vertex_x[ pos + 0 ], vertex_y[ pos + 0 ] );
pos += 4;
}
glEnd();
}
else
if( primitive == GL_QUAD_STRIP )
{
glBegin( GL_LINES );
if( vertex_x.size() > 3 )
{
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 1 ], vertex_y[ 1 ] );
glVertex2i( vertex_x[ 3 ], vertex_y[ 3 ] );
glVertex2i( vertex_x[ 3 ], vertex_y[ 3 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 2 ], vertex_y[ 2 ] );
glVertex2i( vertex_x[ 0 ], vertex_y[ 0 ] );
}
for( unsigned int i = 4; i + 1 < vertex_x.size(); i += 2 )
{
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i - 2 ], vertex_y[ i - 2 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i - 1 ], vertex_y[ i - 1 ] );
}
glEnd();
}
else
if( primitive == GL_POLYGON )
{
glBegin( GL_LINE_LOOP );
for( unsigned int i = 0; i < vertex_x.size(); i++ )
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glEnd();
}
else
if( primitive == RECTANGLES )
{
glBegin( GL_LINES );
for( unsigned int i = 0; i + 1 < vertex_x.size(); i += 2 )
{
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i + 1 ] );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
}
glEnd();
}
glPointSize( 3.0 );
glBegin( GL_POINTS );
for( unsigned int i = 0; i < vertex_x.size(); i++ )
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glEnd();
for( unsigned int i = 0; i < vertex_x.size(); i++ )
{
glRasterPos2i( vertex_x[ i ] + 2, vertex_y[ i ] + 2 );
char str[ 10 ];
sprintf( str, "%i", i + 1 );
int len = strlen( str );
for( int i = 0; i < len; i++ )
glutBitmapCharacter( GLUT_BITMAP_9_BY_15, str[ i ] );
}
glFlush();
glutSwapBuffers();
}
void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, width, 0, height );
Display();
}
void MouseButton( int button, int state, int x, int y )
{
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
vertex_x.insert( vertex_x.end(), x );
vertex_y.insert( vertex_y.end(), glutGet( GLUT_WINDOW_HEIGHT ) - y );
Display();
}
}
void Menu( int value )
{
switch( value )
{
case GL_POINTS:
primitive = GL_POINTS;
glutSetWindowTitle( "Prymitywy graficzne - punkty (GL_POINTS)" );
Display();
break;
case GL_LINES:
primitive = GL_LINES;
glutSetWindowTitle( "Prymitywy graficzne - odcinki (GL_LINES)" );
Display();
break;
case GL_LINE_STRIP:
primitive = GL_LINE_STRIP;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - łamana (GL_LINE_STRIP)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - lamana (GL_LINE_STRIP)" );
#endif
Display();
break;
case GL_LINE_LOOP:
primitive = GL_LINE_LOOP;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - łamana zamknięta (GL_LINE_LOOP)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - lamana zamknieta (GL_LINE_LOOP)" );
#endif
Display();
break;
case GL_TRIANGLES:
primitive = GL_TRIANGLES;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - trójkąty (GL_TRIANGLES)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - trojkaty (GL_TRIANGLES)" );
#endif
Display();
break;
case GL_TRIANGLE_STRIP:
primitive = GL_TRIANGLE_STRIP;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - wstęga trójkątów (GL_TRIANGLE_STRIP)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - wstega trojkatow (GL_TRIANGLE_STRIP)" );
#endif
Display();
break;
case GL_TRIANGLE_FAN:
primitive = GL_TRIANGLE_FAN;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - wachlarz trójkątów (GL_TRIANGLE_FAN)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - wachlarz trojkatow (GL_TRIANGLE_FAN)" );
#endif
Display();
break;
case GL_QUADS:
primitive = GL_QUADS;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - czworokąty (GL_QUADS)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - czworokaty (GL_QUADS)" );
#endif
Display();
break;
case GL_QUAD_STRIP:
primitive = GL_QUAD_STRIP;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - wstęga czworokątów (GL_QUAD_STRIP)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - wstega czworokatow (GL_QUAD_STRIP)" );
#endif
Display();
break;
case GL_POLYGON:
primitive = GL_POLYGON;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - wielokąt (GL_POLYGON)" );
#else
glutSetWindowTitle( "Prymitywy graficzne - wielokat (GL_POLYGON)" );
#endif
Display();
break;
case RECTANGLES:
primitive = RECTANGLES;
#ifdef WIN32
glutSetWindowTitle( "Prymitywy graficzne - prostokąty" );
#else
glutSetWindowTitle( "Prymitywy graficzne - prostokaty" );
#endif
Display();
break;
case CLEAR_VERTEX:
vertex_x.erase( vertex_x.begin(), vertex_x.end() );
vertex_y.erase( vertex_y.begin(), vertex_y.end() );
Display();
break;
case EXIT:
exit( 0 );
}
}
int main( int argc, char * argv[] )
{
glutInit( & argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 550, 500 );
glutCreateWindow( "Prymitywy graficzne - punkty (GL_POINTS)" );
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutMouseFunc( MouseButton );
int MenuPrimitive = glutCreateMenu( Menu );
glutAddMenuEntry( "Punkty (GL_POINTS)", GL_POINTS );
glutAddMenuEntry( "Odcinki (GL_LINES)", GL_LINES );
#ifdef WIN32
glutAddMenuEntry( "Łamana (GL_LINE_STRIP)", GL_LINE_STRIP );
glutAddMenuEntry( "Łamana zamknięta (GL_LINE_LOOP)", GL_LINE_LOOP );
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( "Lamana (GL_LINE_STRIP)", GL_LINE_STRIP );
glutAddMenuEntry( "Lamana zamknieta (GL_LINE_LOOP)", GL_LINE_LOOP );
glutAddMenuEntry( "Trojkaty (GL_TRIANGLES)", GL_TRIANGLES );
glutAddMenuEntry( "Wstega trójkatów (GL_TRIANGLE_STRIP)", GL_TRIANGLE_STRIP );
glutAddMenuEntry( "Wachlarz trójkatow (GL_TRIANGLE_FAN)", GL_TRIANGLE_FAN );
glutAddMenuEntry( "Czworokaty (GL_QUADS)", GL_QUADS );
glutAddMenuEntry( "Wstega czworokatów (GL_QUAD_STRIP)", GL_QUAD_STRIP );
glutAddMenuEntry( "Wielokat (GL_POLYGON)", GL_POLYGON );
glutAddMenuEntry( "Prostokaty", RECTANGLES );
#endif
glutCreateMenu( Menu );
glutAddSubMenu( "Prymitywy", MenuPrimitive );
#ifdef WIN32
glutAddMenuEntry( "Usuń wierzchołki", CLEAR_VERTEX );
glutAddMenuEntry( "Wyjście", EXIT );
#else
glutAddMenuEntry( "Usun wierzcholki", CLEAR_VERTEX );
glutAddMenuEntry( "Wyjscie", EXIT );
#endif
glutAttachMenu( GLUT_RIGHT_BUTTON );
glutMainLoop();
return 0;
}
Plik punkty.cpp
#include <GL/glut.h>
#include <stdlib.h>
#include <vector>
enum
{
CLEAR_POINTS,
EXIT
};
std::vector < GLint > vertex_x;
std::vector < GLint > vertex_y;
std::vector < GLfloat > points_size;
GLfloat point_size = 10.0;
void Display()
{
glClearColor( 1.0, 1.0, 1.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3f( 1.0, 0.0, 0.0 );
for( unsigned int i = 0; i < vertex_x.size(); i++ )
{
glPointSize( points_size[ i ] );
glBegin( GL_POINTS );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glEnd();
}
glFlush();
glutSwapBuffers();
}
void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, width, 0, height );
Display();
}
void MouseButton( int button, int state, int x, int y )
{
if( button == GLUT_LEFT_BUTTON && state == GLUT_DOWN )
{
vertex_x.insert( vertex_x.end(), x );
vertex_y.insert( vertex_y.end(), glutGet( GLUT_WINDOW_HEIGHT ) - y );
points_size.insert( points_size.end(), point_size );
Display();
}
}
void Keyboard( unsigned char key, int x, int y )
{
if( key == '+' )
point_size += 0.25;
else
if( key == '-' && point_size > 0 )
point_size -= 0.25;
Display();
}
void Menu( int value )
{
switch( value )
{
case CLEAR_POINTS:
vertex_x.erase( vertex_x.begin(), vertex_x.end() );
vertex_y.erase( vertex_y.begin(), vertex_y.end() );
points_size.erase( points_size.begin(), points_size.end() );
Display();
break;
case EXIT:
exit( 0 );
}
}
int main( int argc, char * argv[] )
{
glutInit( & argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 500, 500 );
glutCreateWindow( "Punkty" );
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutMouseFunc( MouseButton );
glutKeyboardFunc( Keyboard );
glutCreateMenu( Menu );
#ifdef WIN32
glutAddMenuEntry( "Usuń punkty", CLEAR_POINTS );
glutAddMenuEntry( "Wyjście", EXIT );
#else
glutAddMenuEntry( "Usun punkty", CLEAR_POINTS );
glutAddMenuEntry( "Wyjscie", EXIT );
#endif
glutAttachMenu( GLUT_RIGHT_BUTTON );
glutMainLoop();
return 0;
}
Plik linie.cpp
#include <GL/glut.h>
#include <stdlib.h>
#include <vector>
enum
{
STIPPLE_1111111111111111,
STIPPLE_0000000011111111,
STIPPLE_1111111100000000,
STIPPLE_0000111100001111,
STIPPLE_1111000011110000,
STIPPLE_0011001100110011,
STIPPLE_1100110011001100,
CLEAR_LINES,
EXIT
};
std::vector < GLint > vertex_x;
std::vector < GLint > vertex_y;
std::vector < GLfloat > lines_width;
GLfloat line_width = 10.0;
std::vector < GLfloat > lines_stipple;
GLushort line_stipple = 0xFFFF;
int button_state = GLUT_UP;
void Display()
{
glClearColor( 1.0, 1.0, 1.0, 1.0 );
glClear( GL_COLOR_BUFFER_BIT );
glMatrixMode( GL_MODELVIEW );
glLoadIdentity();
glColor3f( 1.0, 0.0, 0.0 );
glEnable( GL_LINE_STIPPLE );
for( unsigned int i = 0; i < vertex_x.size(); i += 2 )
{
glLineWidth( lines_width[ i / 2 ] );
glLineStipple( 1, lines_stipple[ i / 2 ] );
glBegin( GL_LINES );
glVertex2i( vertex_x[ i ], vertex_y[ i ] );
glVertex2i( vertex_x[ i + 1 ], vertex_y[ i + 1 ] );
glEnd();
}
glDisable( GL_LINE_STIPPLE );
glFlush();
glutSwapBuffers();
}
void Reshape( int width, int height )
{
glViewport( 0, 0, width, height );
glMatrixMode( GL_PROJECTION );
glLoadIdentity();
gluOrtho2D( 0, width, 0, height );
Display();
}
void MouseButton( int button, int state, int x, int y )
{
if( button == GLUT_LEFT_BUTTON )
{
if( state == GLUT_DOWN && button_state == GLUT_UP )
{
vertex_x.insert( vertex_x.end(), x );
vertex_y.insert( vertex_y.end(), glutGet( GLUT_WINDOW_HEIGHT ) - y );
vertex_x.insert( vertex_x.end(), x );
vertex_y.insert( vertex_y.end(), glutGet( GLUT_WINDOW_HEIGHT ) - y );
lines_width.insert( lines_width.end(), line_width );
lines_stipple.insert( lines_stipple.end(), line_stipple );
button_state = GLUT_DOWN;
Display();
}
else
if( state == GLUT_UP && button_state == GLUT_DOWN )
{
vertex_x[ vertex_x.size() - 1 ] = x;
vertex_y[ vertex_y.size() - 1 ] = glutGet( GLUT_WINDOW_HEIGHT ) - y;
button_state = GLUT_UP;
Display();
}
}
}
void MouseMotion( int x, int y )
{
if( button_state == GLUT_DOWN )
{
vertex_x[ vertex_x.size() - 1 ] = x;
vertex_y[ vertex_y.size() - 1 ] = glutGet( GLUT_WINDOW_HEIGHT ) - y;
Display();
}
}
void Keyboard( unsigned char key, int x, int y )
{
if( key == '+' )
line_width += 0.25;
else
if( key == '-' && line_width > 0 )
line_width -= 0.25;
Display();
}
void Menu( int value )
{
switch( value )
{
case STIPPLE_1111111111111111:
line_stipple = 0xFFFF;
Display();
break;
case STIPPLE_0000000011111111:
line_stipple = 0x00FF;
Display();
break;
case STIPPLE_1111111100000000:
line_stipple = 0xFF00;
Display();
break;
case STIPPLE_0000111100001111:
line_stipple = 0x0F0F;
Display();
break;
case STIPPLE_1111000011110000:
line_stipple = 0xF0F0;
Display();
break;
case STIPPLE_0011001100110011:
line_stipple = 0x3333;
Display();
break;
case STIPPLE_1100110011001100:
line_stipple = 0xCCCC;
Display();
break;
case CLEAR_LINES:
vertex_x.erase( vertex_x.begin(), vertex_x.end() );
vertex_y.erase( vertex_y.begin(), vertex_y.end() );
lines_width.erase( lines_width.begin(), lines_width.end() );
lines_stipple.erase( lines_stipple.begin(), lines_stipple.end() );
Display();
break;
case EXIT:
exit( 0 );
}
}
int main( int argc, char * argv[] )
{
glutInit( & argc, argv );
glutInitDisplayMode( GLUT_DOUBLE | GLUT_RGB );
glutInitWindowSize( 500, 500 );
glutCreateWindow( "Linie" );
glutDisplayFunc( Display );
glutReshapeFunc( Reshape );
glutMouseFunc( MouseButton );
glutMotionFunc( MouseMotion );
glutKeyboardFunc( Keyboard );
int MenuStipple = glutCreateMenu( Menu );
glutAddMenuEntry( "1111111111111111", STIPPLE_1111111111111111 );
glutAddMenuEntry( "0000000011111111", STIPPLE_0000000011111111 );
glutAddMenuEntry( "1111111100000000", STIPPLE_1111111100000000 );
glutAddMenuEntry( "0000111100001111", STIPPLE_0000111100001111 );
glutAddMenuEntry( "1111000011110000", STIPPLE_1111000011110000 );
glutAddMenuEntry( "0011001100110011", STIPPLE_0011001100110011 );
glutAddMenuEntry( "1100110011001100", STIPPLE_1100110011001100 );
glutCreateMenu( Menu );
#ifdef WIN32
glutAddSubMenu( "Wzór linii", MenuStipple );
glutAddMenuEntry( "Usuń linie", CLEAR_LINES );
glutAddMenuEntry( "Wyjście", EXIT );
#else
glutAddSubMenu( "Wzor linii", MenuStipple );
glutAddMenuEntry( "Usun linie", CLEAR_LINES );
glutAddMenuEntry( "Wyjscie", EXIT );
#endif
glutAttachMenu( GLUT_RIGHT_BUTTON );
glutMainLoop();
return 0;
}