Kurs programowania GLUT

neuromancer

<font size="4">Kurs programowania w GLUT</span>
<font size="2">Neuro 2004</span>
1 PRZEDMOWA
2 WSTĘP
     2.1 Przegląd Funkcji
3 START
     3.2 KOMPILACJA
          3.2.1 KOMPILACJA OS/2
          3.2.2 KOMPILACJA WINDOWS
     3.3 PIERWSZY PROGRAM
     3.4 INTERAKCJA
     3.5 OKNO
     3.6 WYŚWIETLANIE
     3.7 MENU
     3.8 TIMER
     3.9 MODELE
     3.10 PISANIE
     3.11 TRYB GRY
     3.12 INFORMACJE
     3.13 MAPY KOLORÓW
     3.14 WARSTWY
     3.15 VIDEO
     3.16 DODATKI

PRZEDMOWA

Art. Będzie miał sporo braków i wiele niedomówień, bo zamierzam pisać go tak jak to robiono na NeHe (polecam, ostatnio nawet powstaje polskie tłumaczenie). Będę opierał się na plikach nagłówkowych i dokumentacji. Części funkcji niestety nie przetestuje bo po prostu nie jest to możliwe na sprzęcie który posiadam. No to do dzieła...

WSTĘP

GLUT (ang. OpenGL Utility Toolkit) to API (interfejs programowania aplikacji) dla OpenGL (biblioteka graficzna, jak by ktoś nie wiedział ;) ). Ostatnia wersja to zdaje się 3.7 (wyszła gdzieś koło 98 roku, więc to niezły staroć, ale na szczęście projekt rozwijany jest pod innymi nazwami m.in. freeglut). Glut jest zaimplementowany na kilka platform sprzętowych (Windows,Linux,MacOS), i powstały pliki nagłówkowe dla C, Delphi, Ady i Fortrana (zwykle załączane tylko do C, ale pozostałe można znależć w Internecie). Jego zaletą jest przenośność tzn. np. program napisany na Linux'ie może bez większych przeróbek zostać skompilowany pod Windows, i łatwość obsługi - krótkie logicznie zbudowane funkcje. GLUT służy do utworzenia okna, prostego GUI (graficzny interfejs użytkownika) i interakcji z użytkownikiem (mycha, klawiatura, joystick). Dzięki użyciu GLUT'a unikamy używania API przystosoanego do danego systemu operacyjnego (Windows - WGL z WinAPi, OWL, Linux - GLX z XWindow, GTK, QT).

Przegląd Funkcji

<font color="red">UWAGA ! Poniższa lista dotyczy freeglut i posiada pewne niezgodności z GLUT.</span> #Initialization Functions (Inicjalizajca) ##glutInit ##glutInitWindowPosition, glutInitWindowSize ##glutInitDisplayMode ##glutInitDisplayString #Event Processing Functions (Zdarzenia) ##glutMainLoop ##glutMainLoopEvent ##glutLeaveMainLoop #Window Functions (Funkcje dotyczące okien) ##glutCreateWindow ##glutCreateSubwindow ##glutDestroyWindow ##glutSetWindow, glutGetWindow ##glutSetWindowTitle, glutSetIconTitlew ##glutReshapeWindow ##glutPositionWindow ##glutShowWindow, glutHideWindow, glutIconifyWindow ##glutPushWindow, glutPopWindow ##glutFullScreen #Display Functions (Wyświetlanie) ##glutPostRedisplay ##glutPostWindowRedisplay ##glutSwapBuffers #Mouse Cursor Functions (Kursor myszy) ##glutSetCursor ##glutWarpPointer #Overlay Functions (Warstwy) ##glutEstablishOverlay ##glutRemoveOverlay ##glutUseLayer ##glutPostOverlayRedisplay ##glutPostWindowOverlayRedisplay ##glutShowOverlay, glutHideOverlay #Menu Functions (Menu) ##glutCreateMenu ##glutDestroyMenu ##glutGetMenu, glutSetMenu ##glutAddMenuEntry ##glutAddSubMenu ##glutChangeToMenuEntry ##glutChangeToSubMenu ##glutRemoveMenuItem ##glutAttachMenu, glutDetachMenu #Global Callback Registration Functions (Globalne funkcje typu zwrotnego) ##glutTimerFunc ##glutIdleFunc 1. Window-Specific Callback Registration Functions (Ustalane dla okna funkcje typu zwrotnego) ##glutDisplayFunc ##glutOverlayDisplayFunc ##glutReshapeFunc ##glutKeyboardFunc ##glutSpecialFunc ##glutKeyboardUpFunc ##glutSpecialUpFunc ##glutMotionFunc, glutPassiveMotionFunc ##glutVisibilityFunc ##glutEntryFunc ##glutJoystickFunc ##glutSpaceballMotionFunc ##glutSpaceballRotateFunc ##glutSpaceballButtonFunc ##glutButtonBoxFunc ##glutDialsFunc ##glutTabletMotionFunc ##glutTabletButtonFunc ##glutMenuStatusFunc ##glutWindowStatusFunc #State Setting and Retrieval Functions (Pobranie stanu okna) ##glutSetOption ##glutGet ##glutDeviceGet ##glutGetModifiers ##glutLayerGet ##glutExtensionSupported ##glutGetProcAddress #Font Rendering Functions (Wyświetlanie czcionek) ##glutBitmapCharacter ##glutBitmapString ##glutBitmapWidth ##glutBitmapLength ##glutBitmapHeight ##glutStrokeCharacter ##glutStrokeString ##glutStrokeWidth ##glutStrokeLength ##glutStrokeHeight #Geometric Object Rendering Functions (Obiekty geometryczne) ##glutWireSphere, glutSolidSphere ##glutWireTorus, glutSolidTorus ##glutWireCone, glutSolidCone ##glutWireCube, glutSolidCube ##glutWireTetrahedron, glutSolidTetrahedron ##glutWireOctahedron, glutSolidOctahedron ##glutWireDodecahedron, glutSolidDodecahedron ##glutWireIcosahedron, glutSolidIcosahedron ##glutWireRhombicDodecahedron, glutSolidRhombicDodecahedron ##glutWireTeapot, glutSolidTeapot #Game Mode Functions (Tryb gry) ##glutGameModeString ##glutEnterGameMode, glutLeaveGameMode ##glutGameModeGet #Video Resize Functions (Zmiana Video) ##glutVideoResizeGet ##glutSetupVideoResizing, glutStopVideoResizing ##glutVideoResize ##glutVideoPan #Color Map Functions (Mapy kolorów) ##glutSetColor, glutGetColor ##glutCopyColormap #Miscellaneous Functions (Pozostałe) ##glutIgnoreKeyRepeat, glutSetKeyRepeat ##glutForceJoystickFunc ##glutReportErrors

START

Dobra, zaczynamy. Ja będę pisał pod Linux'a (Mandrake 9.2) i kompilował przy użyciu gcc (więc jak się można było domyślić będę używał C). Co jest wymagane? Znajomość C i OpenGL ofcourse. Jeśli idzie o soft to: jakiś Linux z gcc, OpenGL i GLUT, albo Windows + odpowiedni kompilator + biblioteki. Potem może napiszę uzupełnienie na Windows, ale jeszcze zobaczę. <font color="red">UWAGA ! W niektórych dystrybucjach Linux'a GLUT nie jest standardowo instalowany (u mnie trzeba było wybrać samodzielnie pakiety, przełączyć widok na listę i dopiero znaleĽć coś w stylu libMESA-GLUT (z "devel" to pliki nagłówkowe) czy coć takiego [MESA - to taka wersja OpenGL]).</span> Powinieneś obsługiwać jako tako Linux'a więc: xterm, aterm, gnome-terminal, kterm - terminale (tu się pisze komendy): cd - polecenie zmień katalog (.. aby przejsc do gory, / aby przejsc na szczyt drzewa) np. cd /root/glut - przechodzi do katalogu /root/glut mc - najlepszy tekstowy menedżer plików kwrite, gedit itp. - edytory textu (w tym będziemy pisać)

KOMPILACJA

Do kompilacji będzie nam potrzebny plik "makefile" (oczywiście bez cudzysłowiu). Nie znam się na tworzeniu makefile więc po prostu otwórz jakiś edytor i wpisz (skopiuj):
INCLUDE = -I/usr/include/
LIBDIR  = -L/usr/X11R6/lib

COMPILERFLAGS = -Wall
CC = gcc
CFLAGS = $(COMPILERFLAGS) $(INCLUDE)
LIBRARIES = -lX11 -lXi -lXmu -lglut -lGL -lGLU -lm

# for all, set the targets to be every lesson1.c-lesson13.c
# file, removing the .c extension.  That is, at this point,
# it would produce lesson1, lesson2, lesson3,...,lesson13 targets.
#
all: $(basename $(wildcard lesson[1-9].c lesson1[0-3].c))

# same as for all, except set the targets to be
# lessonX.tar.gz from lessonX.c.  This is really
# only used to build smaller tutorial .tar.gz files
# to send to nehe.
#
dist: $(foreach file,$(basename $(wildcard lesson[1-9].c lesson1[0-3].c)),$(file).tar.gz)

# to produce, say, lesson1.tar.gz:
#
# 1. remove lesson1.tar.gz
# 2. build lesson1.tar containing README, makefile, lesson1.c, Data/lesson1/*.
# 3. gzip lesson1.tar.
#
lesson%.tar.gz :
	tar cvf $(subst .tar.gz,.tar,$@) README makefile $(subst .tar.gz,.c,$@) $(wildcard Data/$(subst .tar.gz,,$@)/*); \
	gzip $(subst .tar.gz,.tar,$@);

# to produce, say, lesson1:
#
# 1. compile the thing.  uses the variables defined above.
#
lesson% : lesson%.o
	$(CC) $(CFLAGS) -o $@ $(LIBDIR) $< $(LIBRARIES)

# to clean up:
# delete all of the lessonX files.
clean:
	rm $(wildcard lesson[1-9] lesson1[0-3])

# to clean up the distributions:
# delete all of the lessonX.tar.gz files.
distclean:
	rm $(wildcard lesson[1-9].tar.gz lesson1[0-3].tar.gz)

Pierwsze linijki określają katalog plików nagłówkowych i bibliotek (trzeba dodać glut, GLU, GL), dalej ustawienia kompilatora i co ma być wykonywane.

Ok. teraz zapisz to w jakimś katalogu (np. /_glut).

Dzięki temu plikowi ("makefile"), aby skompilować jakiś kod wystarczy, że zapiszemy go w tym samym katalogu (co zapisany został makefile), nazwiemy "lesson1.c" i po wpisaniu w terminalu (po przejściu do odpowiedniego katalogu poleceniem cd) "make" (ewentualnie z parametrem "makefile"), otrzymamy skompilowany plik wykonywalny, który możemy uruchomić poleceniem "./lesson1" lub klikając w jakiejś przeglądarce plików (np. nautilus, konqueror ew. mc).

KOMPILACJA OS/2

Zamieszczam metodę kompilacji pod zapomniany nieco system OS/2. Może się to komuś przyda... Nie testowałem bo go nie mam. 1. W programie dopisujemy standardowe nagłówki: ```c #include <gl/gl.h> #include <gl/glut.h> ``` 2. I kompilujemy z wiersza poleceń: cc -fullwarn -O2 -s -o crisscross crisscross.c -lc -lglut -lGL -lGLU -lX11 -lXmu -lXi -lXext -lm Gdzie: #fullwarn- extra sprawdzanie #O2- optymalizacja #s - stripped of debug info #c - biblioteka C #glut- biblioteka I/O glut (zastąpić "-lglut" z "libglut.a" jeśli skopiowane lokalnie) #GL - biblioteka OpenGL #GLU - biblioteka OpenGL Utility #X11, Xmu, Xext, Xi - biblioteka X window #m - matematyka

KOMPILACJA WINDOWS

Aby korzystać z GLUT pod Windows najpierw należy ściagnąć odpowiednie biblioteki z Internetu. Wystarczy wpsiać w dowolnej wyszukiwarce "download GLUT" i wybrać pierwszą stronę z brzegu. Zwykle wszytsko jest w postaci pliku zip. Należy go wypakować, a następnie skopiować odpowiednie pliki. Na windows aby uruchomić program korzystający z GLUT należy załączać zawsze do programu bibliotekę GLUT32.dll. Jednak na swoje potrzeby wystarczy przekopiować dll'a do folderu systemowego (C:\Windows czy C:\Windows\System32). Plik glut32.lib należy przekopiować do folderu lib w katalogu z kompilatorem, a plik glut.h do folderu GL w include. I to tyle (dla Dev-Cpp i MSVC) Na Borlandzie sprawa wygląda inaczej - aby skompilować program należy dodać oczywiście GLUT do używanych bibliotek. Możemy to zrobić np. dopisując w kodzie programu wiersz: ```c #pragma comment(lib,"glut32.LIB") ```

PIERWSZY PROGRAM

//Cóż, nie jest to "Hello world !", ale coś bardzo zbliżonego ;)
#include <GL/glut.h>    // Header File For The GLUT Library
//#include <GL/gl.h>	// Header File For The OpenGL32 Library
//#include <GL/glu.h>	// Header File For The GLu32 Library
/* The number of our GLUT window */
int window;
/* A general OpenGL initialization function.  Sets all of the initial parameters. */
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);	// Calculate The Aspect Ratio Of The Window
  glMatrixMode(GL_MODELVIEW);
}


/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
  glMatrixMode(GL_MODELVIEW);
}

/* The main drawing function. */
void DrawGLScene()
{
glutSetWindow(window);					//Set active window

  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
  //Tutaj wstawiamy kod rysujący scenę
  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}

int main(int argc, char **argv)
{
  /* Initialize GLUT state - glut will take any command line arguments that pertain to it or
     X Windows - look at its documentation at http://reality.sgi.com/mjk/spec3/spec3.html */
  glutInit(&argc, argv);

  /* Select type of Display mode:
     Double buffer
     RGBA color
     Alpha components supported
     Depth buffered for automatic clipping */
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);
//W przypadku błędów po odpaleniu usunąć  GLUT_ALPHA | 

  /* get a 640 x 480 window */
  glutInitWindowSize(640, 480);

  /* the window starts at the upper left corner of the screen */
  glutInitWindowPosition(0, 0);

  /* Open a window */
  window = glutCreateWindow("GLUT TUTORIAL #1");

  /* Register the function to do all our OpenGL drawing. */
  glutDisplayFunc(&DrawGLScene);

  /* Go fullscreen.  This is as soon as possible. */
  glutFullScreen();

  /* Even if there are no events, redraw our gl scene. */
  glutIdleFunc(&DrawGLScene);

  /* Register the function called when our window is resized. */
  glutReshapeFunc(&ReSizeGLScene);

  /* Initialize our window. */
  InitGL(640, 480);

  /* Start Event Processing Engine */
  glutMainLoop();

  /* shut down our window */
  glutDestroyWindow(window);

  return 1;
}

Sporo tego prawda... Ale chwila popatrzmy:

#include <GL/glut.h>    // Header File For The GLUT Library
#include <GL/gl.h>	// Header File For The OpenGL32 Library
#include <GL/glu.h>	// Header File For The GLu32 Library

to tylko dołączenie plików nagłówkowych kolejno: GLUT, OpenGL, GL utilities (rozszerzenie OpenGL). Te dwa ostatnie nie są konieczne bo są już dołączone w nagłówkach GLUT.
Deklaracja "int window" potrzebna jest do zapamiętania numeru okna glut na którym potem będziemy wykonywać operacje. Procedury InitGL i ReSizeGLScene zawierają jedynie procedury, które należą do OpenGL i nie będę ich tutaj opisywał.
Wystarczy, że powiem, iż InitGL zawiera inicjalizację wyświetlania grafiki, a ReSizeGLScene zmianę perspektywy i obszaru rysowania po zmianie rozmiaru okna. Ich parametry to szerokość i wysokość okna.
Procedura DrawGLScene() służy do wyświetlania sceny. Jedyną nową procedurą jest glutSwapBuffers(); która służy do opróżnienia buffor'ów, czyli po ludzku do wyświetlenia sceny OpenGL w oknie GLUT'a.
OK. Teraz główna funkcja (main):
glutInit(&argc, argv); // inicjalizuje GLUT z parametrami podanymi dla programu (zaimplementowane są wszystkie parametry systemu XWindow [czytać w dokumentacji])
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH); //Ustala tryb wyświetlania GLUT, jako sumę logiczną podanych parametrów:
możliwe opcje:
GLUT_RGB //Kolor RGB<
GLUT_RGBA //Kolor RGBa
GLUT_INDEX //Tryb indexowania
GLUT_SINGLE //Pojedynczy buffer
GLUT_DOUBLE //Podwójny<
GLUT_ACCUM //?
GLUT_ALPHA //Kolor alpha (przezroczystość)
GLUT_DEPTH //Bufor automatycznego przycinania
GLUT_STENCIL //Stencil buffer (czytaj w OpenGL)
GLUT_MULTISAMPLE //?
GLUT_STEREO //?
GLUT_LUMINANCE //?
glutInitWindowSize(640, 480); //Ustawia rozmiar okna na 640x480

glutInitWindowPosition(0, 0); //Ustawia pozycję okna na 0x0 (lewy górny róg)

window = glutCreateWindow("GLUT TUTORIAL"); //Tworzy okno z tytułem "GLUT TUTORIAL" i zwraca jego numer do zmiennej window
glutDisplayFunc(&DrawGLScene); //Ustala funkcję wyświetlania - podajemy adres do dowolnej funkcji, tutaj mamy wswskaĽniko DrawGLScene UWAGA ! Funkcja przypisuje wyświetlanie okna aktywnego (tutaj: to które zostało utworzone ostatnio)

glutFullScreen(); //Ustala tryb pełnoekranowy - można spokojne wyłączyć

glutIdleFunc(&DrawGLScene); //Gdy nic się nie dzieje to uruchamia funkcję podaną w parametrze, tutaj znowu mamy DrawGLScene - (dzięki temu można przesuwać, zmieniać rozmiar itd. okna).

glutReshapeFunc(&ReSizeGLScene); //Ustala funkcję zmiany rozmiaru okna, która powinna mieć dwa parametry typu int do których zostaną przekazane szerokość i wysokość okna - tutaj podaliśmy funkcję ReSizeGLScene

Dalej mamy wywołanie funkcji InitGL(); której działanie opisałem wyżej.

I przedostatnia nowa funkcja:
glutMainLoop(); //Główna pętla programu, wyświetla i obsługuje okno oraz odpowiada za interakcję z użytkownikiem.

Funkcja:
glutDestroyWindow(window);
niszczy okno GLUT, którego numer podajemy w parametrze (coś jak uchwyt w WinApi).

Nooo. Jakoś przeszło.

INTERAKCJA

OK. Teraz zajmiemy się komunikacją z użytkownikiem:

glutKeyboardFunc(&keyPressed); //Ustala jaka funkcję zostanie wywołana po wciśnięciu klawisza (tutaj keyPressed). Jej parametry to jedna zmienna typu unsigned char, która zawiera klawisz jaki został wciśnięty oraz dwa parametry typu int które zawierają współrzędne myszki po wciąnięiciu klawisza. Przykładowa funkcja:

void keyPressed(unsigned char key, int x, int y)
{

    /* If 'x' is pressed, kill everything. */
    if (key == 'x')
    {
      /* shut down our window */
      glutDestroyWindow(window);

      /* exit the program...normal termination. */
      exit(0);
    }
}

Analogiczną do powyższej jest funkcja:

glutKeyboardUpFunc(&keyUp);

Różni się ona od tamtej tylko tym, że wywołuje funkcję daną w parametrze dopiero po puszczeniu klawisza

Kolejną podobną funkcją jest:

glutSpecialUpFunc(&specialKeyUp);

której parametr zostanie wywołany po puszczeniu klawisza specjalnego. Parametry identyczne jak wyżej za wyjątkiem pierwszego, który jest typu int.

I dalej:

glutSpecialFunc(&specialKeyPressed); //analogicznie jak w glutKeyboardFunc, z poprawką na pierwszy parametr ;) .

UWAGA ! Niektóre omawiane funkcje mogą nie działać w starszych wersjach API.

Istnieją predefiniowane klawisze, których znaczenia nie trudno się domyślić:
klawisz: jego numer:
GLUT_KEY_F1 1
GLUT_KEY_F2 2
GLUT_KEY_F3 3
GLUT_KEY_F4 4
GLUT_KEY_F5 5
GLUT_KEY_F6 6
GLUT_KEY_F7 7
GLUT_KEY_F8 8
GLUT_KEY_F9 9
GLUT_KEY_F10 10
GLUT_KEY_F11 11
GLUT_KEY_F12 12

GLUT_KEY_LEFT 100
GLUT_KEY_UP 101
GLUT_KEY_RIGHT 102
GLUT_KEY_DOWN 103
GLUT_KEY_PAGE_UP 104
GLUT_KEY_PAGE_DOWN 105
GLUT_KEY_HOME 106
GLUT_KEY_END 107
GLUT_KEY_INSERT 108

Za obsługę myszy odpowiedzialna jest funkcja:

glutMouseFunc(&mButtonPressed);

która przyjmuje za parametr funkcję która powinna mieć cztery parametry (wszystkie typu int):

  1. klawisz myszki

przedefinowane klawisze mychy:
GLUT_LEFT_BUTTON //lewy
GLUT_MIDDLE_BUTTON //środkowy
GLUT_RIGHT_BUTTON //prawy

  1. stan klawisza myszki

przedefinowane stany klawiszy mychy:
GLUT_DOWN //wciśnięty
GLUT_UP //puszczony

3/4. współrzędne myszki.

Przykładowa funkcja (wymaga dodania nagłówka stdio.h):

void mButtonPressed(int button, int state, int x, int y)
{
 switch(button)
 {
  case GLUT_LEFT_BUTTON:
   printf("Lewy");
  break;
  case GLUT_MIDDLE_BUTTON:
   printf("Srodkowy");
  break;
  case GLUT_RIGHT_BUTTON:
   printf("Prawy");
  break;
 }

 switch(state)
 {
  case GLUT_DOWN:
   printf(" w dol\n");
  break;
  case GLUT_UP:
   printf(" w gore\n");
  break;
 }

 printf("X: %i  Y: %i\n",x,y);
}

Do zmiany położenia kursora myszki służy funkcja:

glutWarpPointer(100,50); //której parametry to dwa int'y oznaczające położenie do którego przesunćć kuror (x i y)

Uzupełniającymi działanie mychy są funkcje:

glutMotionFunc(&ruchMychyP);
glutPassiveMotionFunc(&ruchMychyBez);

które ustalają funkcje wywoływane po wykonaniu ruchu myszki:
glutMotionFunc - gdy wciśnięty jest jakiś klawisz
glutPassiveMotionFunc - gdy żaden nie jest wciśnięty

Przykładowe funkcje podane w parametrze (ich parametry to współrzędne myszki):

void ruchMychyP(int x,int y)
{
 printf("Przesunieto myche z wcisnietym przyciskiem (%i,%i)\n",x,y);
}

void ruchMychyBez(int x,int y)
{
 printf("Przesunieto myche (%i,%i)\n",x,y);
}

Za wejcie i wyjscie myszki z obszaru [aktywnego] okna odpowiedzialna jest funkcja:

glutEntryFunc(&mouseEntry);

która przyporządkowuje funkcję wywoływaną w momencie wejścia i wyjścia myszki z obszaru okna. Funkcja ta ma w parametrze zmienną typu int, której przypisanay jest stan:

GLUT_LEFT //Mycha opuściła obszar okna
GLUT_ENTERED //Mycha "wlazła" w okno

void mouseEntry(int state)
{
 if (state==GLUT_LEFT) printf("Wejscie mychy: %i tj. mycha out \n",state);
 else printf("Wejscie mychy: %i tj. mycha in\n",state);
}

Inne urządzenia

GLUT pozwala też na obsługę innych niekonwencjonalnych urządzeń. Niestety niektóre nie są obsługiwane przez Windows. Funkcje do ich obsługi to:

(wszystkie są typu callback, czyli wymagają podania w parametrze adresu do funkcji która będzie wywoływana po określonym zdarzeniu, tak jak niektóre z wyżej wymienionych):

-Spaceball (cokolwiek to jest)
GLUTAPI void GLUTAPIENTRY glutSpaceballMotionFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); //Wywołane po ruchu
GLUTAPI void GLUTAPIENTRY glutSpaceballRotateFunc(void (GLUTCALLBACK *func)(int x, int y, int z)); //Wywołane po obrocie
GLUTAPI void GLUTAPIENTRY glutSpaceballButtonFunc(void (GLUTCALLBACK *func)(int button, int state)); //Wywołane po wciśnięciu przycisku

-ButtonBox (??)
GLUTAPI void GLUTAPIENTRY glutButtonBoxFunc(void (GLUTCALLBACK *func)(int button, int state)); //Przycisk
GLUTAPI void GLUTAPIENTRY glutDialsFunc(void (GLUTCALLBACK *func)(int dial, int value)); *Zmienia podłączenia do aktywnego okna (tak napisali na http:*pyopengl.sourceforge.net/ - co to znaczy? nie wiem !)

-Tablet
GLUTAPI void GLUTAPIENTRY glutTabletMotionFunc(void (GLUTCALLBACK *func)(int x, int y)); //Ruch
GLUTAPI void GLUTAPIENTRY glutTabletButtonFunc(void (GLUTCALLBACK *func)(int button, int state, int x, int y)); //Przycisk

Przykład:

ustawienie (w main):

glutSpaceballMotionFunc(&ruchSpaceball);

funkcja:

void ruchSpaceball(int posx, int posy, int posz)
{
 printf("Polozenie spaceball: x: %i  y: %i  z: %i",posx,posy,posz);
}

Noooo. wreszcie zostało jeszcze ostatnie urządzonko. Ostatnie nie znaczy najmniej istotne. Joystick. Niestety obsługa tego kontrolera w wersji 3.7 nie jest jeszcze dopracowana (braki na Linuxie i korzystanie z MMApi na Windowsie) to jednak warto zapoznać się z jego obsługą. Zwłaszcza, że jest łatwa i krótka:

GLUTAPI void GLUTAPIENTRY glutJoystickFunc(void (GLUTCALLBACK *func)(unsigned int buttonMask, int x, int y, int z), int pollInterval);

Funkcja glutJoystickFunc przyjmuje dwa parametry: adres funkcji do której zwracany będzie stan urządzenia i czas co jaki będzie to następowało (w milisekundach). Funkcja do której będzie zwracany stan ma z kolei cztery parametry: wciśnięte przyciski (jako suma ich wartości) i wychylenie w każdą stronę. Wychylenie może mieć wartość od -1000 do 1000, a w stanie normalnym wynosi 0. Predefiniowane przyciski to:

Przycisk: Wartość:
GLUT_JOYSTICK_BUTTON_A 1
GLUT_JOYSTICK_BUTTON_B 2
GLUT_JOYSTICK_BUTTON_C 4
GLUT_JOYSTICK_BUTTON_D 8

Przykładowe wywołanie (UWAGA ! Nie testowane):

glutJoystickFunc(&joyFunc,100);

Przykładowa funkcja:

void joyFunc(unsigned int btn,int x,int y, int z)
{
 if (GLUT_JOYSTICK_BUTTON_A || GLUT_JOYSTICK_BUTTON_B) printf("przyciski A i B\n");
 printf("X: %i  Y: %i  Z: %i\n",x,y,z);
}

Do wymuszenia zwracania stanu joysticka służy funkcja (nie testowane !):

glutForceJoystickFunc();

I to tyle...

UZUPEŁNIENIE 

Do obsługi klawiatury służą dwie dodatkowe funkcje:

void glutIgnoreKeyRepeat (int ignore );
int glutSetKeyRepeat (int repeatMode );

Służą one do obsługi powtarzalności klawiszy. Ich działanie niestety jest determinowane przez system i różnie funkcjonuje na różnych platformach.

Funkcja glutIgnoreKeyRepeat określa czy powtróki wciśnięcia klawisza są relacjonowane do aktualnego okna. Jest jeden parametr, który przyjmuje jedynie dwie wartości 0 (auto-powtórki będą reportowane) i 1 (powtórki nie będą reportowane).

Druga funkcja (glutSetKeyRepeat) zmienia tryb powtarzania klawiszy. W parametrze podajemy tryb. Możliwe są wartości:
GLUT_KEY_REPEAT_OFF //wyłącza powtarzanie klawiszy (jeśli tylko jest to możliwe)
GLUT_KEY_REPEAT_ON //włącza
GLUT_KEY_REPEAT_DEFAULT //resetuje do domyślnego stanu 

Funkcja zwraca stan GLUT jako liczbę typu int.
UWAGA ! Na Win32 powyższe funkcje nie działają. No cóż, nie można mieć wszystkiego :(.

Podsumowujący kod:
o pozwala obracać myszką figurę
o zmieniać kolor kwadratu przy użyciu klawiszy '+' i '-'

#include <GL/glut.h>    // Header File For The GLUT Library
//#include <GL/gl.h>	// Header File For The OpenGL32 Library
//#include <GL/glu.h>	// Header File For The GLu32 Library

/* The number of our GLUT window */
int window;

//Zmienne przechowujące
float r=0,g=0,b=0.7;	//kolor "tła"
int ox,oy;		//współrzędne myszki
float rx,ry;		//obroty obiektu


/* A general OpenGL initialization function.  Sets all of the initial parameters. */
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_FLAT);			// Enables Smooth Color Shading

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);	// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);
}


/* The function called when our window is resized (which shouldn't happen, because we're fullscreen) */
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,100.0f);
  glMatrixMode(GL_MODELVIEW);
}

/* The main drawing function. */
void DrawGLScene()
{
glutSetWindow(window);	//Ustala aktywne okno

  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
  //Tutaj wstawiamy kod rysujący scenę

	glTranslatef(0,0,-5);

	glPushMatrix();
	//quasi-tło
	glTranslatef(0,0,-3);
	glColor3f(r,g,b);
	glBegin(GL_QUADS);
         glVertex3f(-10,-10,0);
         glVertex3f(-10, 10,0);
         glVertex3f( 10, 10,0);
         glVertex3f( 10,-10,0);
	glEnd();

	glPopMatrix();


	//Figura
	glRotatef(ry,1,0,0);
	glRotatef(rx,0,1,0);
	glBegin(GL_TRIANGLES);

	glColor3f(1,1,0);
	 glVertex3f(0,1,0);
	 glVertex3f(-1,-1,1);
	 glVertex3f( 1,-1,1);

	glColor3f(1,0,0);
	 glVertex3f(0,1,0);
	 glVertex3f( 1,-1,1);
	 glVertex3f( 1,-1,-1);

	glColor3f(0,1,0);
	 glVertex3f(0,1,0);
	 glVertex3f( 1,-1,-1);
	 glVertex3f(-1,-1,-1);

	glColor3f(0,0,1);
	 glVertex3f(0,1,0);
	 glVertex3f(-1,-1,1);
	 glVertex3f(-1,-1,-1);

	glEnd();



  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}


//Funkcja wywoływana po wciśnięciu klawisza
void keyPressed(unsigned char key, int x, int y)
{
	switch (key)&nbsp;
	{
 	 case '-':		//Używamy klawisza '-' do przyciemnienia "tła"
 	  if(r<1)r+=0.1;
 	  if(g<1)g+=0.1;
 	  if(b<1)b+=0.1;
	 break;
	 case '+':		//Używamy klawisza '+' do rozjaśnienia "tła"
	  if(r>0)r-=0.1;
	  if(g>0)g-=0.1;
	  if(b>0)b-=0.1;
	 break;
	}

    /* If 'x' is pressed, kill everything. */
    if (key == 'x')
    {
      /* shut down our window */
      glutDestroyWindow(window);

      /* exit the program...normal termination. */
      exit(0);
    }
}

//Funkcja wykonywana gdy przesunięto mychę z wciśniętym przyciskiem
void ruchMychyP(int x,int y)
{
 rx+=(x-ox)*0.25;
 ry+=(oy-y)*0.25;
 ox=x;
 oy=y;
}

//Funckja wywołana po wciśnięciu klawisza&nbsp;
void mButtonPressed(int button, int state, int x, int y)
{
 ox=x;
 oy=y;
}

int main(int argc, char **argv)
{
  /* Initialize GLUT state - glut will take any command line arguments that pertain to it or
     X Windows - look at its documentation at http://reality.sgi.com/mjk/spec3/spec3.html */
  glutInit(&argc, argv);

  /* Select type of Display mode:
     Double buffer
     RGBA color
     Alpha components supported
     Depth buffered for automatic clipping */
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);

  /* get a 640 x 480 window */
  glutInitWindowSize(640, 480);

  /* the window starts at the upper left corner of the screen */
  glutInitWindowPosition(0, 0);

  /* Open a window */
  window = glutCreateWindow("GLUT TUTORIAL #2");

  /* Register the function to do all our OpenGL drawing. */
  glutDisplayFunc(&DrawGLScene);


  /* Register the function called when our window is resized. */
  glutReshapeFunc(&ReSizeGLScene);

  //Ustalenie funkcji
  glutKeyboardFunc(&keyPressed);	// która zostanie wywołana po wciśnięciu klawisza
  glutMotionFunc(&ruchMychyP);		// po ruchu myszki z przyciskiem
  glutMouseFunc(&mButtonPressed);	// po wciśnięciu przycisku

  //Inicjalizacja OpenGL
  InitGL(640, 480);

  /* Even if there are no events, redraw our gl scene. */
  glutIdleFunc(&DrawGLScene);


  /* Start Event Processing Engine */
  glutMainLoop();

  /* shut down our window */
  glutDestroyWindow(window);

  return 1;
}

OKNO

Podstawowe funkcje obsługi okien (oddziałowują na aktualnie aktywne):

glutSetWindowTitle("TYTUL"); //Zmienia tytuł okna. Jeden parametr typu const char*.
glutPositionWindow(10, 10); //Zmienia pozycję okna. Dwa parametry typu int (określają lewy górny róg okna)
glutReshapeWindow(int width, int height); //Zmienia rozmiar okna. Pierwszy parametr to szerokość, drugi to wysokość

GLUT umożliwia tworzenie "pod-okien" służy do tego funkcja:

int glutCreateSubWindow(window,10,10,100,100); //Zwraca uchwyt do nowo utworzonego pod-okna. Pierwszy parametr to numer (uchwyt) do okna-"rodzica" czyli tego w którym będzie zawarte nowo utworzone. Dwa kolejne parametry to położenie, dwa ostatnie to szerokość i wysokość. Wszystkie są typu int. UWAGA ! Do każdego nowo utworzonego okna należy przypisać funkcje jakie będą używane. Najważniejszą i konieczną jest glutDispayFunc.

przykład:

int subwindow;

subwindow=glutCreateSubWindow(window,10,10,100,100);
glutDisplayFunc(&DrawSubWindowGLScene);

Do pobrania aktywnego okna służy funkcja:

int glutGetWindow(void); //która zwraca uchwyt (nr) bieżącego okna

Do zmiany aktywnego okna służy funkcja:

glutSetWindow(int win); // w parametrze podajemy uchwyt okna które ma być aktywne

Do sterowania oknem służą funkcje:

glutIconifyWindow(void); //Minimalizuje okno (aktywne)
glutShowWindow(void); //Pokazuje okno (aktywne)
glutHideWindow(void); //Ukrywa okno (aktywne)

glutPopWindow(void); //Funkcja pobiera okno ze stosu
glutPushWindow(void); //Funkcja kładzie okno na stos

Działanie dwóch powyższych funkcji jest analogiczne jak działanie funkcji
glPopMatrix();
glPuchMatrix();
w OpenGL. Najlepiej spróbować samemu.

Dodatkową funkcję pozwalającą kontrolować stan okna (ustala się jak wszystkie dla bieżącego aktywnego okna) jest:

glutVisibilityFunc

która ustala funckję wywoływaną po ukryciu (ew. minimalizacji) i po ukazaniu (ew. przywróceniu) okna.
Możliwe wartości parametru w wywołanej funkcji to :

GLUT_NOT_VISIBLE //Okno niewidoczne
GLUT_VISIBLE //Okno widoczne

Przykład:

wywołanie (w main() ):

glutVisibilityFunc(&oknoWidok)

funkcja:

void oknoWidok(int state)
{
if (state==GLUT_VISIBLE) printf(" okno widoczne \n"); else printf("okno niewidoczne \n");
}

Do pobrania aktualnego stanu okna służy funkcja:
glutWindowStatusFunc
która przyjmuje jeden parametr - adres do funkcji która zostanie uruchomiona w przypadku zmiany stanu okna. Możliwe warto?ci parametru funkcji to:

nazwa: wartość:
GLUT_HIDDEN 0
GLUT_FULLY_RETAINED 1
GLUT_PARTIALLY_RETAINED 2
GLUT_FULLY_COVERED 3

Przykład:

glutWindowStatusFunc(&winStatus);

i funkcja:

void winStatus(int state)
{
 printf("Nastąpiła zmiana stanu na:");
 switch (state)
 {
  case GLUT_HIDDEN:
   printf("HIDDEN\n");
  break;
  case GLUT_FULLY_RETAINED:
   printf("FULLY_RETAINED\n");
  break;
  case GLUT_PARTIALLY_RETAINED:
   printf("PARTIALLY_RETAINED\n");
  break;
  case GLUT_FULLY_COVERED:
   printf("FULLY_COVERED\n");
  break;
 }
}

No i na koniec mały przykładzik. Generuje okno z przesuwającym się napisem na belce, które można przesuwać klikając w jego dowolnym miejscu i pod okno o tej samej właściwości. UWAGA! Zastosowałem procedurkę glutGet która jest opisana w dalszej części tekstu.

#include <GL/glut.h>    // Nagłówek do GLUT
//#include <GL/gl.h> 	//Pozostałe nagłówki (nie konieczne gdyż zawarte już w GLUT)
//#include <GL/glu.h>

//Główne okno
int window;

//Pod-okno
int subwindow;


//Współrzędne myszki
int mx,my;


//Inicjalizacja OpenGL
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,10.0f);	// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);
}


//Zmiana rozmiaru
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,10.0f);
  glMatrixMode(GL_MODELVIEW);
}

//Zmienne do przewijania napisu na pasku&nbsp;
char txt[]="GLUT TUTORIAL #3 ";	//Text
char txtlen=17;			//Długość textu
char snap[20];			//Pomocnicza

//Funkcja, powiązana z timer'em, odpowiedzialna za przesuwanie napisu na pasku
void scrollBar(int scroll)
{
unsigned short int i;	//Zmienna pomocnicza

 //Wygenerowanie napisu na pasek
 for (i=0; i<txtlen; i++)
 if (i+scroll<txtlen)
 snap[i]=txt[i+scroll]; else
 snap[i]=txt[i+scroll-txtlen];

 snap[txtlen]='\0';

 glutSetWindow(window);			//Zmiana aktywnego okna
 glutSetWindowTitle(snap);		//Zmiana napisu na pasku tytułowym

 //Utrzymanie timer'a w ruchu
 if (scroll>=txtlen)
   glutTimerFunc (1000,&scrollBar,0); else
   glutTimerFunc (1000,&scrollBar,scroll+1);
}




int rot=0;

//Główna funkcja rysująca
void DrawGLScene()
{

  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
  glTranslatef(0,0,-1);
      glRotatef(rot++,0,0,1);
	glBegin(GL_TRIANGLES);
	glColor3f(1,0,0);
	 glVertex3f(0,0.4,0);
	glColor3f(0,1,0);
	 glVertex3f(-0.4,-0.25,0);
	glColor3f(0,0,1);
	 glVertex3f( 0.4,-0.25,0);
	glEnd();

  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}


//Rysuje scenę z pod-okna
void DrawSubWindowGLScene()
{
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //Scena OpenGL
  glTranslatef(0,0,-1);
      glRotatef(rot,1,0,1);
	glBegin(GL_QUADS);
		glColor3f(1,0,0);
	 glVertex3f(-0.4,-0.4,0);
		glColor3f(0,1,0);
	 glVertex3f( 0.4,-0.4,0);
		glColor3f(0,0,1);
	 glVertex3f( 0.4, 0.4,0);
		glColor3f(0,1,1);
	 glVertex3f(-0.4, 0.4,0);
	glEnd();

  glutSwapBuffers();

}

//Funkcja rysująca sceny w obu oknach
void DrawAll()
{

 glutSetWindow(window);				//Zmiana aktywnego okna
 DrawGLScene();

 glutSetWindow(subwindow);			//Zmiana aktywnego okna
 DrawSubWindowGLScene();
}

//Funckja wywołana po przesunięciu myszki z wciśniętym klawiszem
void mBtnMove(int x,int y)
{
 int lx,ly;
  lx=glutGet(GLUT_WINDOW_X);	//pobiera położenie x aktywnego okna
  ly=glutGet(GLUT_WINDOW_Y);	//pobiera położenie y aktywnego okna
  glutPositionWindow(x-mx+lx,y-my+ly);	//Zmienie położenie okna
}

//Funckja wywołana po wciśnięciu klawisza
void mButtonPressed(int button, int state, int x, int y)
{
 mx=x;
 my=y;
}


//Funckja wywołana po przesunięciu myszki z wciśniętym klawiszem dla pod-okna
void mSBtnMove(int x,int y)
{&nbsp;
int ax,ay,kx,ky;

  kx=glutGet(GLUT_WINDOW_X);	//pobiera położenie x aktywnego pod-okna
  ky=glutGet(GLUT_WINDOW_Y);	//pobiera położenie y aktywnego pod-okna
	glutSetWindow(window);	//Zmienia aktywne okno
  ax=glutGet(GLUT_WINDOW_X);	//pobiera położenie x aktywnego okna
  ay=glutGet(GLUT_WINDOW_Y);	//pobiera położenie y aktywnego okna
	glutSetWindow(subwindow);//Zmienia aktywne okno
 	glutPositionWindow(kx+x-mx-ax,ky+y-my-ay);	//Zmienie położenie pod-okna
}

//Funckja wywołana po wciśnięciu klawisza dla pod-okna
void mSButtonPressed(int button, int state, int x, int y)
{
 mx=x;
 my=y;
}


//Podstawowa funkcja każdego programu
int main(int argc, char **argv)
{
  glutInit(&argc, argv);	//Inicjalizacja GLUT
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);	//Ustalenie trybu wyświetlania

  //Inicjalizacja i ustawienia dla okna renderingu
  glutInitWindowSize(640, 480);		//rozmiar
  glutInitWindowPosition(0, 0); 	//położenie
  window = glutCreateWindow("GLUT TUTORIAL #3");//utworzenie okna
  glutDisplayFunc(&DrawGLScene); 	//funkcja wyświetlania
  glutReshapeFunc(&ReSizeGLScene);	//zmiana rozmiaru
  InitGL(640, 480);			//Inicjalizacja OpenGL

  //Funkcje callback dla okna głównego
  glutTimerFunc (500,&scrollBar,0);	//Przesuwanie napisu na pasku
  glutMotionFunc(&mBtnMove);		// po ruchu myszki z przyciskiem
  glutMouseFunc(&mButtonPressed);	// po wciśnięciu przycisku

  subwindow=glutCreateSubWindow(window,270,190,100,100);	//Utworzenie pod-okna
  glutDisplayFunc(&DrawSubWindowGLScene);			//Ustalenie funkcji wyświetlania
  InitGL(100, 100);			//Inicjalizacja OpenGL dla pod-okna (może być zupełnie inna)

  //Funkcje callback dla pod-okna
  glutMotionFunc(&mSBtnMove);		// po ruchu myszki z przyciskiem
  glutMouseFunc(&mSButtonPressed);	// po wciśnięciu przycisku


  glutIdleFunc(&DrawAll);		//Funkcja wywołana w przypadku braku żadnych zdarzeń


  glutMainLoop();			//Główna pętla

  glutDestroyWindow(window);		//Usunięcie okna
  return 1;
}

WYŚWIETLANIE

Oprócz wyżej wymienionej funkcji: glutDisplayFunc związane z wyświetlaniem są:

glutPostRedisplay();

i

glutPostWindowRedisplay(int win);

służą one do niezależnego od pętli wyświetlenia zawartości okna. Pierwsza działa na aktywne okno, druga na to do którego uchwyt (którego numer) podaliśmy w parametrze.

oraz funkcja:

glutInitDisplayString 

której działanie opisane jest dalej (czyt. dodatki).

MENU

GLUT umożliwia utworzenie menu tekstowego typu pop-up, czyli takiego, które zostanie ukazane po wciśnięciu klawisza myszki.
Do utworzenia menu lub pod-menu służy funkcja:

glutCreateMenu(&selectMessage); //za parametr przyjmuje ona adres do funkcji (z parametrem int) i zwraca numer utworzonego menu (jego uchwyt)

Przykład użycia:

int submenu1 = glutCreateMenu(&selectMessage);

gdzie funkcja selectMessage ma postać np.

void selectMessage(int i)
{
printf("Pozycja z menu: %i\n",i);
}

do dodania pozycji do menu służy funkcja:

glutAddMenuEntry("abc", 1); //przyjmuje ona dwa parametry: typu const char * który zawiera opis pozycji menu i drugi który jest jej numerem (gdy wciśniemy tę pozycję to zostanie wywołana funkcja ustalona przy utworzeniu menu, której parametrem będzie właśnie ten numer)

UWAGA ! GLUT jest maszyną stanu (podobnie jak OpenGL). W uproszczeniu znaczy to, że to co zrobiliśmy ostatnio (i nie tylko) jest zapisane. Tak więc używając funkcji glutAddMenuEntry dodamy pozycję do ostatnio utworzonego menu (lub tego które zmieniliśmy ostatnio na aktywne).
Do zmiany aktywnego menu służy funkcja:

glutSetMenu(submenu1); //gdzie podajemy jeden parametr typu int i jest to numer (uchwyt) menu, które ustawiamy na aktywne

Podobnie do funkcji glutAddMenuEntry działa funkcja:

glutAddSubMenu("Color", submenu2); //która służy do dodania do aktywnego menu, pod-menu, pierwszy parametr (const char *) to opis jaki zostanie nadany menu, drugi to numer/uchwyt menu, które dodajemy.

Do ustalenia klawisza myszki po wciśnięciu którego uruchomi się menu służy funkcja:

glutAttachMenu(GLUT_LEFT_BUTTON); //której parametrem jest przycisk mychy, jeden z trzech:

GLUT_LEFT_BUTTON //lewy
GLUT_MIDDLE_BUTTON //środkowy
GLUT_RIGHT_BUTTON //prawy

i która ustawia aktywne menu do pokazania po wciśnięciu klawisza.

Przykładowy kod:

tworzy menu z pozycjami: 9 by 15 , Times Roman 10 , Times Roman 24 i dwoma pod-menu:
Messages (pozycje: abc i ABC) i Color (pozycje: Green, Red, White), które zostanie wywołane po wciśnięciu lewego przycisku myszki

//Do main
int submenu1, submenu2;

submenu1 = glutCreateMenu(selectMessage);

submenu2 = glutCreateMenu(selectColor);
glutAddMenuEntry("Green", 1);
glutAddMenuEntry("Red", 2);
glutAddMenuEntry("White", 3);

glutSetMenu(submenu1);
glutAddMenuEntry("abc", 1);
glutAddMenuEntry("ABC", 2);

glutCreateMenu(selectFont);
glutAddMenuEntry("9 by 15", 0);
glutAddMenuEntry("Times Roman 10", 1);
glutAddMenuEntry("Times Roman 24", 2);
glutAddSubMenu("Messages", submenu1);
glutAddSubMenu("Color", submenu2);

glutAttachMenu(GLUT_LEFT_BUTTON);
//luzem

void selectMessage(int i)
{
 printf("msg nr %i\n",i);
}

void selectColor(int i)
{
 printf("color nr %i\n",i);
}

void selectFont(int i)
{
 printf("font nr %i\n",i);
}

OK. Kolejna funkcja:

int glutGetMenu();

nie ma parametrów i służy do pobrania uchwytu aktywnego okna, który to zwraca.

Przykład

int aktywne_menu;
aktywne_menu=glutGetMenu();

Do usunięcia menu służy funkcja:
glutDestroyMenu(int menu);
której parametrem jest uchwyt do menu, które chcemy usunąć.

Aby rozkojarzyć przycisk myszki z menu służy funkcja:

glutDetachMenu(GLUT_LEFT_BUTTON);

której parametr jest analogiczny jak w glutAttachMenu.

Do usunięcia pozycji z menu służy funkcja:
glutRemoveMenuItem(int); //która ma jeden parametr, za który podajemy numer pozycji z aktywnego menu, którą chcemy usunąć.
Funkcja działa zarówno na pozycje jak i pod-menu.

Do zmiany pozycji menu służy funkcja:

glutChangeToMenuEntry(int item, const char *label, int value);

Pierwszy parametr to nr pozycji, którą zmieniamy, drugi to opis na jaki zmieniamy bieżący opis pozycji. Ostatni to wartość jaka zostanie przekazana do funkcji ustalonej przy tworzeniu menu (ofcourse po wybraniu pozycji z menu przez użytkownika).

Analogiczną do powyższej, ale odpowiadającą za zmianę pod-menu jest funkcja:

glutChangeToSubMenu(int item, const char *label, int submenu);

Zmienia się jedynie ostatni parametr. Podajemy numer (uchwyt) utworzonego menu, które zastąpi pod-menu lub pozycję na pozycji podanej w pierwszym parametrze.

Ufff. Do podstawowych funkcji obsługi menu służą jeszcze dwa polecenia:

glutMenuStateFunc(void (GLUTCALLBACK *func)(int state));
glutMenuStatusFunc(void (GLUTCALLBACK *func)(int status, int x, int y));

Pierwsza służy do przypisania (wybrania, analogicznie jak np. po wciśnięciu klawisza) funkcji która zostanie wywołana po zmianie stanu przez menu. Funkcja do której adres podamy powinna mieć jeden parametr typu int, do którego zostanie przekazany obecny stan menu. Możliwe wartości:

0 czyli GLUT_MENU_NOT_IN_USE
i
1 czyli GLUT_MENU_IN_USE

Przykładowa funkcja

void menuState(int state)
{
printf("stan menu: %i\n",state);
}

i przykładowe przypisanie

glutMenuStateFunc(&menuState);

Druga czyli glutMenuStatusFunc różni się od pierwszej tym jedynie, że zwraca do funkcji oprócz stanu współrzędne (x i y) myszki, co jest praktycznie równoznaczne położeniu menu.

No i oczywiście na koniec mały przykład. Pozwala sterować tym co jest pokazywane na ekranie za pomocą menu.

#include <GL/glut.h>    // Nagłówek do GLUT
//#include <GL/gl.h> 	//Pozostałe nagłówki (nie konieczne gdyż zawarte już w GLUT)
//#include <GL/glu.h>

//Główne okno
int window;

//Zmienne służące przy wyświetlanie
#define triangle 1
#define quad 2
int color=4,figure=triangle,showing=1;

//Uchwyty menu
int submenu1, submenu2;

//Inicjalizacja OpenGL
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_SMOOTH);			// Enables Smooth Color Shading

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,500.0f);	// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_COLOR_MATERIAL);
}


//Zmiana rozmiaru
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,(GLfloat)Width/(GLfloat)Height,0.1f,500.0f);
  glMatrixMode(GL_MODELVIEW);
}


//Główna funkcja rysująca
void DrawGLScene()
{
glutSetWindow(window);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
if (showing)
{
 glTranslatef(0,0,-1);
   switch (color)
   {
    case 1:
		glColor3f(1,0,0);
	break;
    case 2:
		glColor3f(0,1,0);
	break;
    case 3:
		glColor3f(0,0,1);
	break;
    case 4:
		glColor3f(1,1,1);
	break;
   }

 if (figure==triangle)
 {&nbsp;
  glBegin(GL_TRIANGLES);
	glVertex3f(0,0.2,0);
	glVertex3f(0.2,-0.2,0);
	glVertex3f(-0.2,-0.2,0);
  glEnd();
 } else
 {&nbsp;
  glBegin(GL_QUADS);
	glVertex3f(-0.1,-0.1,0);
	glVertex3f(0.1,-0.1,0);
	glVertex3f(0.1,0.1,0);
	glVertex3f(-0.1,0.1,0);
  glEnd();
 }
}
  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}

//Funkcje wywoływane po wybraniu pozycji z menu:

void selectShowing(int i)
{
 showing=i;
 if (i==0)
 glutChangeToMenuEntry(2,"Rysuj", 1); else
 glutChangeToMenuEntry(2,"Ukryj", 0);
}


void selectFigure(int i)
{
 switch (i)
 {
  case 1:
   figure=triangle;
  break;
  case 2:
   figure=quad;
  break;
 }
}


void selectColor(int i)
{
 color=i;
}


//Podstawowa funkcja każdego programu
int main(int argc, char **argv)
{
  glutInit(&argc, argv);	//Inicjalizacja GLUT
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);	//Ustalenie trybu wyświetlania

  //Inicjalizacja i ustawienia dla okna renderingu;
  glutInitWindowSize(480, 480);		//rozmiar
  glutInitWindowPosition(0, 0); 	//położenie
  window = glutCreateWindow("GLUT TUTORIAL #4");//utworzenie okna
  glutDisplayFunc(&DrawGLScene); 	//funkcja wyświetlania
  glutReshapeFunc(&ReSizeGLScene);	//zmiana rozmiaru
  InitGL(480, 480);			//Inicjalizacja OpenGL


	//Tworzymy menu i pod-menu'a oraz przy tym ustalamy wywoływane po wybraniu pozycji funkcje
	submenu1 = glutCreateMenu(selectFigure);

	submenu2 = glutCreateMenu(selectColor);
	glutAddMenuEntry("Czerwony", 1);
	glutAddMenuEntry("Zielony", 2);
	glutAddMenuEntry("Niebieski", 3);
	glutAddMenuEntry("Biały", 4);

	glutSetMenu(submenu1);		//przykładowe użycie funkcji setmenu do przełączenia się na początkowe pod-menu
	glutAddMenuEntry("Trójkąt", 1);
	glutAddMenuEntry("Kwadrat", 2);
;
	glutCreateMenu(selectShowing);
	glutAddSubMenu("Figura", submenu1);
	glutAddMenuEntry("Ukryj", 0);
	glutAddSubMenu("Kolor", submenu2);

	//Kojarzymy lewy przycisk z menu
	glutAttachMenu(GLUT_LEFT_BUTTON);
	glutAttachMenu(GLUT_RIGHT_BUTTON);	//prawy zresztą też...

  glutIdleFunc(&DrawGLScene);		//Funkcja wywołana w przypadku braku żadnych zdarzeń

  glutMainLoop();			//Główna pętla

  glutDestroyWindow(window);		//Usunięcie okna
  return 1;
}

TIMER

Timer jest to zegarek który za określony czas wywołuje pewną funkcję.
Do obsługi timera w GLUT służy funkcja:

glutTimerFunc(unsigned int millis, void (GLUTCALLBACK *func)(int value), int value);

przyjmuje ona trzy parametry:
millis - czas za który zostanie wywołana funkcja (w milisekundach)
funkcja (która musi mieć parametr int)
wartość jaka zostanie przekazana do parametru powyższej funkcji.

Przykład:

glutTimerFunc (1000,&timerFunc,22); //Co sekundę wywołuje funkcję timerFunc z parametrem 22

Aby powtórzyć lub wywoływać działanie timer'a należy procedurę ponownie uruchomić.

Przykładowy kod: mierzy liczbę klatek na sekundę i pokazuje na wykresie (czerwone trójkąty oznaczają setki , skala jest od 0 do 500).

#include <GL/glut.h>    // Nagłówek do GLUT
//#include <GL/gl.h> 	//Pozostałe nagłówki (nie konieczne gdyż zawarte już w GLUT)
//#include <GL/glu.h>

//Główne okno
int window;

//Liczba klatek na sek. i aktualna
int fps=0,sfps=0;

//Inicjalizacja OpenGL
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(0.7f, 0.7f, 0.7f, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  //glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_FLAT);			// Enables Smooth Color Shading

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,6.4,0.1f,500.0f);	// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_COLOR_MATERIAL);
}


//Zmiana rozmiaru
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,6.4,0.1f,500.0f);
  glMatrixMode(GL_MODELVIEW);
}


 //Rysuje trójkąt (przy podziałce)
 void DrawTri(float fx)
 {&nbsp;
  glVertex3f(fx,0.16,0);
  glVertex3f(fx+0.04,0.36,0);
  glVertex3f(fx-0.04,0.36,0);
 }

//Główna funkcja rysująca
void DrawGLScene()
{
fps++;		//Zliczaj fps

glutSetWindow(window);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
  glTranslatef(0,0,-1);
	//Tło
	glColor3f(1,1,1);
	glBegin(GL_QUADS);
	 glVertex3f(-2.55,-0.15,0);
	 glVertex3f(-2.55, 0.15,0);
	 glVertex3f( 2.55, 0.15,0);
	 glVertex3f( 2.55,-0.15,0);
	glEnd();

	//Skala
        glTranslatef(0,0,0.005);
	glColor3f(0,1,0);
	glBegin(GL_QUADS);
	 glVertex3f(-2.5,-0.1,0);
	 glVertex3f(-2.5, 0.1,0);
	 glVertex3f(-2.5+sfps*0.01, 0.1,0);
	 glVertex3f(-2.5+sfps*0.01,-0.1,0);
	glEnd();

	//Podziałka
	glBegin(GL_TRIANGLES);
	  glColor3f(1,0,0);
         DrawTri(-2.5);	//0
         DrawTri(-1.5);	//100
         DrawTri(-0.5); //200
         DrawTri(0.5); //300
         DrawTri(1.5); //400
         DrawTri(2.5); //500
 	  glColor3f(1,1,1);
         DrawTri(-2);//50 = 0.25
         DrawTri(-1);//150
         DrawTri(0);//250
         DrawTri(1); //350
         DrawTri(2);   //450
 	glEnd();

  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}

//Funkcja wywoływana przez timer
void timerFunc(int i)
{
 sfps=fps;
 fps=0;
 //powtórz wywoływanie
 glutTimerFunc (1000,&timerFunc,0);    //Co sekundę wywołuje funkcję timerFunc
}

//Podstawowa funkcja każdego programu
int main(int argc, char **argv)
{
  glutInit(&argc, argv);	//Inicjalizacja GLUT
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);	//Ustalenie trybu wyświetlania

  //Inicjalizacja i ustawienia dla okna renderingu
  glutInitWindowSize(640, 100);		//rozmiar
  glutInitWindowPosition(0, 0); 	//położenie
  window = glutCreateWindow("GLUT TUTORIAL #5");//utworzenie okna
  glutDisplayFunc(&DrawGLScene); 	//funkcja wyświetlania
  glutReshapeFunc(&ReSizeGLScene);	//zmiana rozmiaru
  InitGL(640, 100);			//Inicjalizacja OpenGL


  glutTimerFunc (1000,&timerFunc,0);    //Co sekundę wywołuje funkcję timerFunc

  glutIdleFunc(&DrawGLScene);		//Funkcja wywołana w przypadku braku żadnych zdarzeń


  glutMainLoop();			//Główna pętla

  glutDestroyWindow(window);		//Usunięcie okna
  return 1;
}

MODELE

GLUT zawiera też funkcje do rysowania prostych modeli:

  • glutWireSphere(GLdouble radius, GLint slices, GLint stacks); //siatka kuli

  • glutSolidSphere(GLdouble radius, GLint slices, GLint stacks); //kula

  • glutWireCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); //stożek - siatka

  • glutSolidCone(GLdouble base, GLdouble height, GLint slices, GLint stacks); //stożek

  • glutWireCube(GLdouble size); //siatka sześcianu

  • glutSolidCube(GLdouble size); //sześcian

  • glutWireTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); //siatka torusa

  • glutSolidTorus(GLdouble innerRadius, GLdouble outerRadius, GLint sides, GLint rings); //torus

  • glutWireDodecahedron(void); //siatka dwunastościanu

  • glutSolidDodecahedron(void); //dwunastościan

  • glutWireTeapot(GLdouble size); //siatka czajnika

  • glutSolidTeapot(GLdouble size); //czajnik

  • glutWireOctahedron(void); //siatka ośmioboku

  • glutSolidOctahedron(void); //ośmiobok

  • glutWireTetrahedron(void); //czworościan - siatka

  • glutSolidTetrahedron(void); //czworościan

  • glutWireIcosahedron(void); //znowu wielościan - siatka

  • glutSolidIcosahedron(void); //wielościan

Przykładowo:

glutSolidTorus(0.5,3,20,20);

rysuje torus (taki pączek ;) ). Tym razem nie będzie przykładziku, bo całość jest zbyt oczywista. Wystarczy wstawić funkcję do DrawGLScene i tyle.

PISANIE

GLUT udostępnia możliwość pisania bitmapowymi czcionkami. Niestety umożliwia pisanie tylko jednego znaku na raz. służy do tego funkcja:

glutBitmapCharacter(void *font, int character);

Możliwe typy czcionki (pierwszy parametr):

GLUT_BITMAP_9_BY_15
GLUT_BITMAP_8_BY_13
GLUT_BITMAP_TIMES_ROMAN_10
GLUT_BITMAP_TIMES_ROMAN_24
GLUT_BITMAP_HELVETICA_10
GLUT_BITMAP_HELVETICA_12
GLUT_BITMAP_HELVETICA_18

Drugi parametr umożliwia podanie jednego znaku (np. 'a','1' lub '@').

Funkcja:

int glutBitmapWidth(void *font, int character);

umożliwia pobranie (zwraca wartość) szerokości znaku w danej czcionce. Parametry identyczne jak wyżej.

Przykładowe wykorzystanie, wypisuje określony tekst na ekranie w określonej pozycji (wymaga dodania modułu string.h:
"#include <string.h>" na początku do obsługi strlen)

float glutPrint(float x,float y,void *font,char *txt,float scale)
{ int i;
  int len=strlen(txt);
 for (i=0; i<len; i++)
 {
  glRasterPos2f(x,y);
  glutBitmapCharacter(font, txt[i]);
  x+=glutBitmapWidth(font,txt[i])*scale;
 }
}

Podobne działanie do powyższych mają funkcje (różni się to, że nie używają czcionek bitmapowych):

glutStrokeCharacter(void *font, int character)
int glutStrokeWidth(void *font, int character);

Możliwe typy czcionki dla powyższych funkcji to:

GLUT_STROKE_ROMAN
GLUT_STROKE_MONO_ROMAN

Ostatnimi funkcjami z tej grupy są:

int glutBitmapLength(void *font, const unsigned char *string);
int glutStrokeLength(void *font, const unsigned char *string);

które podają "długość" (zwracana jako int) ciągu znaków (podanego w drugim parametrze) w określonej czcionce (pierwszy parametr). Z nazwy można wywnioskować, które dotyczą czcionek bitmapowych, a które nie ;) .

Prosty przykład na zakończenie:

  • przewijająca się lista autorów
  • obliczanie fps
    Oczywiście poniższy kod jest strasznie nie-efektywny i wymaga zooptymalizowania (nawet na podstawowym poziomie), ale przecież ma być jedynie demonstracją...
#include <GL/glut.h>    // Nagłówek do GLUT
//#include <GL/gl.h> 	//Pozostałe nagłówki (nie konieczne gdyż zawarte już w GLUT)
//#include <GL/glu.h>

#include <stdio.h>	//Standardowa obsługa we/wy

//Główne okno
int window;

//Liczba klatek na sek. i aktualna
int fps=0,sfps=0;

//Przewijane napisu
char* txt[]={"      ABOUT","____________","","","Program ten","jest czescia","kursu","programowania","GLUT","(GL Utility Toolkit)","       by","Neuromancer","      2004","____________"};
#define txtcount 14//liczba pozycji w tekście
float starty=-1; 	//startowa pozycja przewijanego text'u

//Inicjalizacja OpenGL
void InitGL(int Width, int Height)	        // We call this right after our OpenGL window is created.
{
  glClearColor(1, 1, 1, 0.0f);		// This Will Clear The Background Color To Black
  glClearDepth(1.0);				// Enables Clearing Of The Depth Buffer
  glDepthFunc(GL_LESS);			        // The Type Of Depth Test To Do
  glEnable(GL_DEPTH_TEST);		        // Enables Depth Testing
  glShadeModel(GL_FLAT);			// Enables Smooth Color Shading

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();				// Reset The Projection Matrix

  gluPerspective(45.0f,64/48,0.1f,500.0f);	// Calculate The Aspect Ratio Of The Window

  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_COLOR_MATERIAL);
}


//Zmiana rozmiaru
void ReSizeGLScene(int Width, int Height)
{
  if (Height==0)				// Prevent A Divide By Zero If The Window Is Too Small
    Height=1;

  glViewport(0, 0, Width, Height);		// Reset The Current Viewport And Perspective Transformation

  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();

  gluPerspective(45.0f,64/48,0.1f,500.0f);
  glMatrixMode(GL_MODELVIEW);
}

//Konwersja
char ascii[25];
FILE*f;

void itoa(int i)
{

 f=fopen("tmp.tmp","w");
  fprintf(f,"%i\n",i);
 fclose(f);

 f=fopen("tmp.tmp","r");
  fscanf(f,"%s\n",&ascii);
 fclose(f);
}

//Wartość bezwzględna
float abstract(float f)
{
 if (f>=0) return f; else return -f;
}

//Pisze czcionką bitmapową
float glutPrint(float x,float y,void *font,char *txt,float scale)
{ int i;
  int len=strlen(txt);
 for (i=0; i<len; i++)
 {
  glRasterPos2f(x,y);
  glutBitmapCharacter(font, txt[i]);
  x+=glutBitmapWidth(font,txt[i])*scale;
 }
}

//Główna funkcja rysująca
void DrawGLScene()
{
int i;
float y;

fps++;		//Zliczaj fps

glutSetWindow(window);
  glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);	// Clear The Screen And The Depth Buffer
  glLoadIdentity();				// Reset The View
  //OpenGL scene goes here///////////////////////////////////////
  glTranslatef(0,0,-2.5);
  glColor3f(0,0,0);

   //FPS
   itoa(sfps);
   strcat(ascii," fps");
   glutPrint(-0.8,-0.8,GLUT_BITMAP_9_BY_15,ascii,0.005);

   y=starty;
   for (i=0; i<txtcount; i++)
   {&nbsp;
    if (y<1) //Jeśli napis jest widoczny (w strefie 1>y>-1) to&nbsp;
    {
     glColor3f(0+abstract(y),0+abstract(y),0+abstract(y)); //Ustal kolor
     glutPrint(-0.4,y,GLUT_BITMAP_TIMES_ROMAN_24,txt[i],0.004);	//Napisz go
    }
    y-=0.3;		//PrzejdĽ niżej ("następny wiersz")
    if (y<-1) break;	//Jeśli już nic więcej nie widać to przerwij rysowanie
   }

   starty+=0.005;		//Przewijaj całość
   if (starty>6) starty=-1;	//Zresetuj po pewnym czasie

  ///////////////////////////////////////////////////////////////
  // swap the buffers to display, since double buffering is used.
  glutSwapBuffers();
}

//Funkcja wywoływana przez timer
void timerFunc(int i)
{
 sfps=fps;
 fps=0;
 //powtórz wywoływanie
 glutTimerFunc (1000,&timerFunc,0);    //Co sekundę wywołuje funkcję timerFunc
}

//Podstawowa funkcja każdego programu
int main(int argc, char **argv)
{
  glutInit(&argc, argv);	//Inicjalizacja GLUT
  glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);	//Ustalenie trybu wyświetlania

  //Inicjalizacja i ustawienia dla okna renderingu
  glutInitWindowSize(640, 480);		//rozmiar
  glutInitWindowPosition(0, 0); 	//położenie
  window = glutCreateWindow("GLUT TUTORIAL #6");//utworzenie okna
  glutDisplayFunc(&DrawGLScene); 	//funkcja wyświetlania
  glutReshapeFunc(&ReSizeGLScene);	//zmiana rozmiaru
  InitGL(640, 480);			//Inicjalizacja OpenGL


  glutTimerFunc (1000,&timerFunc,0);    //Co sekundę wywołuje funkcję timerFunc

  glutIdleFunc(&DrawGLScene);		//Funkcja wywołana w przypadku braku żadnych zdarzeń


  glutMainLoop();			//Główna pętla

  glutDestroyWindow(window);		//Usunięcie okna
  return 1;
}

TRYB GRY

GLUT posiada coś takiego jak tryb gry (GAME MODE). Obsługują go funkcje:

void glutGameModeString(const char *string); //Ustala ciąg znaków game mode (?), prawdopodobnie parametry
int glutEnterGameMode(void); //Włącza tryb game mode. Zwraca wartość int.
void glutLeaveGameMode(void); //Wyłącza
int glutGameModeGet(GLenum mode); //Pobiera ustawienia trybu. Zwraca int. Możliwe wartości to:

GLUT_GAME_MODE_ACTIVE 0
GLUT_GAME_MODE_POSSIBLE 1
GLUT_GAME_MODE_WIDTH 2
GLUT_GAME_MODE_HEIGHT 3
GLUT_GAME_MODE_PIXEL_DEPTH 4
GLUT_GAME_MODE_REFRESH_RATE 5
GLUT_GAME_MODE_DISPLAY_CHANGED 6

Przyznam się szczerze, że nie wiem cóż ów tajemniczy tryb powoduje. Jest on innowacją.

INFORMACJE

GLUT zawiera tez funkcje pozwalajace nie tylko pobrac biezacy stan jego komponentow, ale takze rozszezenia systemu i inne. 

Pierwszą tego typu funkcją jest:
int glutGet(GLenum type); 
Jak widać zwraca wartość typu int, a w parametrze pobiera to czego wartość będzie zwracać. Możliwe wartości parametru:

//predefiniowana nazwa wartość zwraca
GLUT_WINDOW_X 100 x aktywnego okna
GLUT_WINDOW_Y 101 y aktywnego okna
GLUT_WINDOW_WIDTH 102 szerokość -"-
GLUT_WINDOW_HEIGHT 103 wysokość -"-
GLUT_WINDOW_BUFFER_SIZE 104 rozmiar bufora renderowania
GLUT_WINDOW_STENCIL_SIZE 105 rozmiar bufora Stencil (patrz. OpenGl)
GLUT_WINDOW_DEPTH_SIZE 106 rozmiar bufora głębi
GLUT_WINDOW_RED_SIZE 107 rozmiary buforów poszczególnych kolorów (?)
GLUT_WINDOW_GREEN_SIZE 108
GLUT_WINDOW_BLUE_SIZE 109
GLUT_WINDOW_ALPHA_SIZE 110
GLUT_WINDOW_ACCUM_RED_SIZE 111
GLUT_WINDOW_ACCUM_GREEN_SIZE 112
GLUT_WINDOW_ACCUM_BLUE_SIZE 113
GLUT_WINDOW_ACCUM_ALPHA_SIZE 114
GLUT_WINDOW_DOUBLEBUFFER 115 rozmiar podwójnego bufora render
GLUT_WINDOW_RGBA 116 rgba okna (?)
GLUT_WINDOW_PARENT 117 rodzic bieżącego okna
GLUT_WINDOW_NUM_CHILDREN 118 numer dziecka (?)
GLUT_WINDOW_COLORMAP_SIZE 119 ?
GLUT_WINDOW_NUM_SAMPLES 120 ?
GLUT_WINDOW_STEREO 121 ?
GLUT_WINDOW_CURSOR 122 bieżący kursor
GLUT_SCREEN_WIDTH 200 szerokość ekranu
GLUT_SCREEN_HEIGHT 201 wysokość ekranu
GLUT_SCREEN_WIDTH_MM 202 ?
GLUT_SCREEN_HEIGHT_MM 203 ?
GLUT__NUM_ITEMS 300 ?
GLUT_DISPLAY_MODE_POSSIBLE 400 możliwy tryb wyświetlania
GLUT_INIT_WINDOW_X 500 zainicjowane x okna
GLUT_INIT_WINDOW_Y 501 zainicjowane y okna
GLUT_INIT_WINDOW_WIDTH 502 zainicjowana szerokość okna
GLUT_INIT_WINDOW_HEIGHT 503 zainicjowana wysokość okna
GLUT_INIT_DISPLAY_MODE 504 zainicjowany tryb wyświetlania okna
GLUT_ELAPSED_TIME 700 czas jaki pozostał (?)
GLUT_WINDOW_FORMAT_ID 123 format id okna (?)

Drugą funkcją jest:
int glutDeviceGet(GLenum type); //której działanie i wykorzystanie jest identyczne jak powyższej, a służy do pobrania informacji o urządzeniu.
Możliwe wartości parametru to:

//predefinowana wartość wartość zwraca
GLUT_HAS_KEYBOARD 600 czy jest klawiatura
GLUT_HAS_MOUSE 601 -"- myszka
GLUT_HAS_SPACEBALL 602 -"- spaceball (cokolwiek to jest ;) )
GLUT_HAS_DIAL_AND_BUTTON_BOX 603 -"- button box
GLUT_HAS_TABLET 604 -"- tablet
GLUT_NUM_MOUSE_BUTTONS 605 ile mycha ma przycisków
GLUT_NUM_SPACEBALL_BUTTONS 606 ile spaceball -"-
GLUT_NUM_BUTTON_BOX_BUTTONS 607 ile button box -"- 
GLUT_NUM_DIALS 608 ?
GLUT_NUM_TABLET_BUTTONS 609 -"- tablet -"-
GLUT_DEVICE_IGNORE_KEY_REPEAT 610 czy urządzenie ignoruje powtarzanie klawiszy
GLUT_DEVICE_KEY_REPEAT 611 czy urządzenie nie ignoruje powtarzania klawiszy
GLUT_HAS_JOYSTICK 612 czy jest joy 
GLUT_OWNS_JOYSTICK 613 ?
GLUT_JOYSTICK_BUTTONS 614 info o przyciskach joy'a (?)
GLUT_JOYSTICK_AXES 615 ?
GLUT_JOYSTICK_POLL_RATE 616 ?

Do pobrania obsługiwanych rozszerzeń służy funkcja:

int glutExtensionSupported(const char *name);

w której rozszerzenia podajemy w parametrze jako ciągi znakowe.

Kolejną funkcją jest:

int glutGetModifiers(void);

która zwraca wartość typu int, będącą sumą logiczną następujących wartości:

//predefiniowana wartość
GLUT_ACTIVE_SHIFT 1
GLUT_ACTIVE_CTRL 2
GLUT_ACTIVE_ALT 4

Dzięki tej funkcji, możemy pobrać w dowolnym momencie stan klawiszy specjalnych. Brak przykładziku jedynie z powodu oczywistości przedstawionych funkcji.

MAPY KOLORÓW

Do obsługi tego służą trzy funkcje:

glutCopyColormap
glutSetColor
glutGetColor

Funkcja 
void glutCopyColormap (int win);
kopiuje mapę kolorów z okna podanego w paramerze (warstwy) do aktualnego.

Funkcja 
void glutSetColor(int cell, GLfloat red, GLfloat green, GLfloat blue);
zmienia składowe koloru. Pierwszy parametr to index (typ int), kolejne trzy to już float, które są składowymi RGB (każda może mieć wartość od 0 do 1).

Przykładowy kod (do main):

int win1, win2;				//Deklaracja okien

glutInitDisplayMode(GLUT_INDEX);	//Inicjalizacja trybu indexowania ISTOTNE ! aby pamiętać o jego ustaleniu
win1 = glutCreateWindow("first color index win");	//Utworzenie pierwszego okna
glutSetColor(0, 0.0, 0.0, 0.0); /* black */		//Modyfikacje kolorów z mapy kolorów z pierwszego okna
glutSetColor(1, 0.5, 0.5, 0.5); /* gray */
glutSetColor(2, 1.0, 1.0, 1.0); /* black */
glutSetColor(3, 1.0, 0.0, 0.0); /* red */
win2 = glutCreateWindow("second color index win");	//Utworzenie drugiego okna
glutCopyColormap(win1);					//Skopiowanie mapy kolorów dla drugiego okna

Ostatni funkcja służy (jak nietrudno się domyślić) służy do pobrania składowych danego koloru, z bieżącej mapy kolorów.
Jej deklaracja to:

GLfloat glutGetColor(int cell, int component);

jak widać zwraca ona wartość float, która jest właśnie wartością składowej. W parametrach podejmy index (liczony od zera) koloru, a następnie którą składową chcemy pobrać:
GLUT_RED //czerwona 
GLUT_GREEN //zielona
GLUT_BLUE //niebieska

W przypadku przezroczystości koloru (lub innej modyfikacji) funkcja zwraca wartość -1.

WARSTWY

Czyli: wracamy do rozmów o cebuli ;).

Niestety jestem z nich marny. Zwyczajnie się na nich nie znam. Ale jak mus to mus.

OK. Pierwsza funkcja to:

glutEstablishOverlay();

nie przyjmuje parametrów i nic też nie zwraca. Służy do "ustalania" warstwowości dla okna (o ile to możliwe). Tryb wyświetlania ustalamy przez "initial display mode". Po wywołaniu funkcji pierwsza istniejąca warstwa jest usuwana, a pokazywana jest kolejna.

Funkcja:
glutRemoveOverlay(); //bez parametrów
służy do usuwania jednej warstwy z aktywnego okna.

Funkcja:
void glutUseLayer(GLenum layer);
ustawia tryb warstwowania dla okna.

Możliwe wartości parametru layer:
GLUT_NORMAL - normalny plan
GLUT_OVERLAY - kolejna warstwa

Funkcja:
void glutPostOverlayRedisplay(void); 
ma działanie jak glutPostRedisplay, tyle, że odnosi się do warstw.

Do ukrywania i pokazywania warstw służą funkcje:

void glutShowOverlay(void);
void glutHideOverlay(void);

Funkcja:

void glutOverlayDisplayFunc(void (*func)(void));

jest typu callback i w parametrze podajemy funkcję, która będzie używana do wyświetlania sceny na warstwie (działanie jak w glutDisplayFunc).

Funkcje:

void glutPostOverlayRedisplay(void);
void glutPostWindowOverlayRedisplay(int win);

są już zupełnie oczywiste. Pierwsza powoduje niezależne od DisplayFunc wyświetlenie scenki. Druga robi to samo tyle, że w parametrze podajemy dla którego okna to zrobimy (warstwa bieżąca dla danego).

Do pobrania ustawień warst służy funkcja:

int glutLayerGet(int); //która jak widać ma w parametrze int, możliwe wartości to:

//Predefiniowana wartość znaczenie
GLUT_OVERLAY_POSSIBLE 800 //możliwe użycie warstw
GLUT_LAYER_IN_USE 801 //czy używane są warstwy
GLUT_HAS_OVERLAY 802 //czy są warstwy
GLUT_TRANSPARENT_INDEX 803 //index przezrczystości (?)
GLUT_NORMAL_DAMAGED 804 //?
GLUT_OVERLAY_DAMAGED 805 //?

i zwraca int'a.

Może i nie jest to wszystko zbyt zrozumiałe, ale może kod ułatwi zrozumienie:

Zmienne:

int overlaySupport; //Zmienna użyta do sprawdzenia obsługi warstw
int transparent, red, white; //Przezroczystość, czerwony, biały

Do main:

glutInitDisplayMode(GLUT_SINGLE | GLUT_INDEX); //Inicjalizacja wyświetlania<
overlaySupport = glutLayerGet(GLUT_OVERLAY_POSSIBLE); //Sprawdzenie czy warstwy są obsługiwane
if (overlaySupport) //Jeśli tak to
{
glutEstablishOverlay();&nbsp;
glutHideOverlay();

transparent = glutLayerGet(GLUT_TRANSPARENT_INDEX); //Pobranie index'u przezroczystości
glClearIndex(transparent);&nbsp;
red = (transparent + 1) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);&nbsp;
white = (transparent + 2) % glutGet(GLUT_WINDOW_COLORMAP_SIZE);
glutSetColor(red, 1.0, 0.0, 0.0); /* Red. */
glutSetColor(white, 1.0, 1.0, 1.0); /* White. */

glutOverlayDisplayFunc(redrawOverlay); //Ustalenie funkcji wyświetlającej
glutReshapeFunc(reshape); //Ustalenie funkcji przy zmianie rozmiaru okna
} else //Jeśli warstwy nie chodzą to
{
printf("Sorry, no nifty overlay (try an SGI workstation)!\n"); //wyświetl komunikat
}

Funkcja zmiany rozmiaru okna:

void reshape(int w, int h)
{
if (overlaySupport) //Jeśli obsługiwane są warstwy
{
glutUseLayer(GLUT_OVERLAY); /* Setup overlay to have X style coordinate system. */
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0, w, 0, h);
glScalef(1, -1, 1);
glTranslatef(0, -h, 0);
glMatrixMode(GL_MODELVIEW);
glutUseLayer(GLUT_NORMAL);
}
glViewport(0, 0, w, h);
}

UWAGA ! Niestety, u mnie wstawka do programu powyższego kodu, daje niemiły efekt:

"Sorry, no nifty overlay (try an SGI workstation)!"

więc (jak się pewnie domyśliłeś), żadna z powyższych funkcji nie była testowana i upewnienie się co do ich działania pozostaje w kompetencji czytającego :( .

VIDEO

Pierwszą omówioną funkcją z tej grupy jest:

int glutVideoResizeGet ( GLenum param );

jak widać przyjumuje ona jeden parametr. Możliwe wartości dla parametru to:

// Predefiniowane: wartość: działanie:
GLUT_VIDEO_RESIZE_POSSIBLE 900 //Parametr,przy którym funkcja zwraca 0 gdy zmiana vid. nie jest obsługiwana (i wtedy pozostałe parametry są bezużyteczne), lub 1 gdy jest obsługiwane

GLUT_VIDEO_RESIZE_IN_USE 901 //Zwracają pozostałe informacje o vid.
GLUT_VIDEO_RESIZE_X_DELTA 902
GLUT_VIDEO_RESIZE_Y_DELTA 903
GLUT_VIDEO_RESIZE_WIDTH_DELTA 904
GLUT_VIDEO_RESIZE_HEIGHT_DELTA 905
GLUT_VIDEO_RESIZE_X 906
GLUT_VIDEO_RESIZE_Y 907
GLUT_VIDEO_RESIZE_WIDTH 908
GLUT_VIDEO_RESIZE_HEIGHT 909

void glutSetupVideoResizing(void); //Uruchamia ustalanie rozmiaru vid.
void glutStopVideoResizing(void); //Kończy owoż
void glutVideoResize(int x, int y, int width, int height); //Zmienia rozmiar vid.
void glutVideoPan(int x, int y, int width, int height); //?

Nie to, żeby mi się nie chciało, ale cóż, nie sądzę aby to było istotne, a nie czuję się najlepiej w tym temacie.

DODATKI

No i na koniec kilka uzupełniających całość funkcji:

glutSetCursor(2); //Funkcja pozwala na zmianę kursora mychy, w parametrze podajemy numer oznaczający jaki kursor z systemu (różne dla Windows'a, Linux'a, Mac'a)

Predefiniowane kursory:

//predefiniowane wartość wygląd
GLUT_CURSOR_RIGHT_ARROW 0 strzałka w prawo
GLUT_CURSOR_LEFT_ARROW 1 strzałka w lewo
GLUT_CURSOR_INFO 2 informacja
GLUT_CURSOR_DESTROY 3 zniszcz
GLUT_CURSOR_HELP 4 pomoc
GLUT_CURSOR_CYCLE 5 kółko
GLUT_CURSOR_SPRAY 6 spray
GLUT_CURSOR_WAIT 7 czekaj
GLUT_CURSOR_TEXT 8 text
GLUT_CURSOR_CROSSHAIR 9 krzyżyk
GLUT_CURSOR_UP_DOWN 10 góra, dół //zmiana rozmiaru
GLUT_CURSOR_LEFT_RIGHT 11 prawo, lewo //zmiana rozmiaru
GLUT_CURSOR_TOP_SIDE 12 góra //zmiana rozmiaru
GLUT_CURSOR_BOTTOM_SIDE 13 dół //zmiana rozmiaru
GLUT_CURSOR_LEFT_SIDE 14 lewo //zmiana rozmiaru
GLUT_CURSOR_RIGHT_SIDE 15 prawo //zmiana rozmiaru
GLUT_CURSOR_TOP_LEFT_CORNER 16 górny lewy róg //zmiana rozmiaru
GLUT_CURSOR_TOP_RIGHT_CORNER 17 górny prawy róg //zmiana rozmiaru
GLUT_CURSOR_BOTTOM_RIGHT_CORNER 18 dolny prawy róg //zmiana rozmiaru
GLUT_CURSOR_BOTTOM_LEFT_CORNER 19 dolny lewy róg //zmiana rozmiaru
GLUT_CURSOR_INHERIT 100 ?
GLUT_CURSOR_NONE 101 brak kursora
GLUT_CURSOR_FULL_CROSSHAIR 102 wypełniony krzyżyk

glutSetIconTitle("Napis na pasku"); //Pozwala na zmianę napisu na belce okna na pasku. Przyjmuje jeden parametr typu const char*

glutReportErrors(); //GLUT wyświetla raporty o błędach (w oknie konsoli)

W GLUT istnieje funkcja:

void* glutGetProcAddress ( const char * procName );

której działanie jest identyczne jak funkcji:

glXGetProcAddress(); //Na systemie X-Window (Linux)
wglGetProcAddress(); //Na Windows-GL (Windows)

Służy ona do pobrania wskaĽnika (zwraca go) do adresu funkcji, której nazwę podajemy w parametrze.

Funkcja:

glutInitDisplayString

służu do ustawienia trybu wyświetlania przez string'a podanego w parametrze. Specyfikacja funkcji w C wygląda następująco:

void glutInitDisplayString(char *string);

Opis działania (kopia z dokumentacji):

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
The initial display mode description string is used when creating top-level windows, subwindows, and overlays to determine the OpenGL display mode for the to-be-created window or overlay.

The string is a list of zero or more capability descriptions separated by spaces and tabs. Each capability description
is a capability name that is optionally followed by a comparator and a numeric value. For example, "double"
and "depth>=12" are both valid criteria.

The capability descriptions are translated into a set of criteria used to select the appropriate frame buffer
configuration.

The criteria are matched in strict left to right order of precdence. That is, the first specified criteria (leftmost)
takes precedence over the later criteria for non-exact criteria (greater than, less than, etc. comparators). Exact
criteria (equal, not equal compartors) must match exactly so precedence is not relevant.

The numeric value is an integer that is parsed according to ANSI C's strtol(str, strptr,
0) behavior. This means that decimal, octal (leading 0), and hexidecimal values (leading 0x) are accepeted.

The valid compartors are:
[Dozwolonymi symbolami są:] 

=

Equal. [równe]

!=

Not equal. [nie równe]

<

Less than and preferring larger difference (the least is best). [mniejsze]

Greater than and preferring larger differences (the most is best). [większe]

<=

Less than or equal and preferring larger difference (the least is best). [mniejsze lub równe]

= [większe lub równe]

Greater than or equal and preferring more instead of less. This comparator is useful for allocating
resources like color precsion or depth buffer precision where the maximum precison is generally preferred.
Contrast with the tilde (~) comprator.

~

Greater than or equal but preferring less instead of more. This compartor is useful for allocating
resources such as stencil bits or auxillary color buffers where you would rather not over allocate. When
the compartor and numeric value are not specified, each capability name has a different default (one
default is to require a a compartor and numeric value).

The valid capability names are:
[Dozwolonymi typami nazw są:]

alpha

Alpha color buffer precision in bits. Default is ">=1".

acca

Red, green, blue, and alpha accumulation buffer precision in bits. Default is ">=1" for red,
green, blue, and alpha capabilities.

acc

Red, green, and green accumulation buffer precision in bits and zero bits of alpha accumulation buffer
precision. Default is ">=1" for red, green, and blue capabilities, and "~0" for the
alpha capability.

blue

Blue color buffer precision in bits. Default is ">=1".

buffer

Number of bits in the color index color buffer. Default is ">=1".

conformant

Boolean indicating if the frame buffer configuration is conformant or not. Conformance information is based
on GLX's EXT_visual_rating extension if supported. If the extension is not supported, all visuals are
assumed conformat. Default is "=1".

depth

Number of bits of precsion in the depth buffer. Default is ">=12".

double

Boolean indicating if the color buffer is double buffered. Default is "=1".

green

Green color buffer precision in bits. Default is ">=1".

index

Boolean if the color model is color index or not. True is color index. Default is ">=1".

num

A special capability name indicating where the value represents the Nth frame buffer configuration matching
the description string. When not specified, glutInitDisplayString also returns the first (best matching)
configuration. num requires a compartor and numeric value.

red

Red color buffer precision in bits. Default is ">=1".

rgba

Number of bits of red, green, blue, and alpha in the RGBA color buffer. Default is ">=1" for
red, green, blue, and alpha capabilities, and "=1" for the RGBA color model capability.

rgb

Number of bits of red, green, and blue in the RGBA color buffer and zero bits of alpha color buffer
precision. Default is ">=1" for the red, green, and blue capabilities, and "~0" for
alpha capability, and "=1" for the RGBA color model capability.

luminance

Number of bits of red in the RGBA and zero bits of green, blue (alpha not specified) of color buffer
precision. Default is ">=1" for the red capabilitis, and "=0" for the green and blue
capabilities, and "=1" for the RGBA color model capability, and, for X11, "=1" for the
StaticGray ("xstaticgray") capability.

SGI InfiniteReality (and other future machines) support a 16-bit luminance (single channel) display mode
(an additional 16-bit alpha channel can also be requested). The red channel maps to gray scale and green
and blue channels are not available. A 16-bit precision luminance display mode is often appropriate for
medical imaging applications. Do not expect many machines to support extended precision luminance display
modes.

stencil

Number of bits in the stencil buffer.

single

Boolean indicate the color buffer is single buffered. Double buffer capability "=1".

stereo

Boolean indicating the color buffer is supports OpenGL-style stereo. Default is "=1".

samples

Indicates the number of multisamples to use based on GLX's SGIS_multisample extension (for antialiasing).
Default is "<=4". This default means that a GLUT application can request multipsampling if
available by simply specifying "samples".

slow

Boolean indicating if the frame buffer configuration is slow or not. For the X11 implementation of GLUT,
slowness information is based on GLX's EXT_visual_rating extension if supported. If the EXT_visual_rating
extension is not supported, all visuals are assumed fast. For the Win32 implementation of GLUT, slowness is
based on if the underlying Pixel Format Descriptor (PFD) is marked "generic" and not
"accelerated". This implies that Microsoft's relatively slow software OpenGL implementation is
used by this PFD. Note that slowness is a relative designation relative to other frame buffer
configurations available. The intent of the slow capability is to help programs avoid frame buffer
configurations that are slower (but perhaps higher precision) for the current machine. Default is
">=0" if not comparator and numeric value are provided. This default means that slow visuals
are used in preference to fast visuals, but fast visuals will still be allowed.

win32pfd

Only recognized on GLUT implementations for Win32, this capability name matches the Win32 Pixel Format
Descriptor by numer. win32pfd requires a compartor and numeric value.

xvisual

Only recongized on GLUT implementations for the X Window System, this capability name matches the X visual
ID by number. xvisual requires a compartor and numeric value.

xstaticgray

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type StaticGray. Default is "=1".

xgrayscale

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type GrayScale. Default is "=1".

xstaticcolor

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type StaticColor. Default is "=1".

xpseudocolor

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type PsuedoColor. Default is "=1".

xtruecolor

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type TrueColor. Default is "=1".

xdirectcolor

Only recongized on GLUT implementations for the X Window System, boolean indicating if the frame buffer
configuration's X visual is of type DirectColor. Default is "=1".

Unspecifed capability descriptions will result in unspecified criteria being generated. These unspecified criteria help
glutInitDisplayString behave sensibly with terse display mode description strings. For example, if
no "slow" capability description is provided, fast frame buffer configurations will be choosen in preference
to slow frame buffer configurations, but slow frame buffer configurations will still be choosen if no better fast frame
buffer configuration is available.
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

Przykładowe użycie:
glutInitDisplayString("stencil~2 rgb double depth>=16 samples");
//ustala okno w trybie RGBA, z głębią 16 lub więcej bitów, z czymś zwanym "mutlisampling" i 2 bitami na stencil buffer.

No to by było na tyle. Zdaje się, że opisałem (jako-tako) wszystkie istotne funkcje w wersji 3.7, więc jeśli traficie na jakieś inne to prawdopodobnie będą należały już do nowszych implementacji lub (co bardziej prawdopodobne) do innego wydania biblioteki GLUT. Standardowa formułka: czytajcie Ľródła i arty oraz piszcie ile się tylko da. W przypadku niejasności najlepiej (o ile na przeszkodzie nie stoi język) poszukać na stronach angielskojęzycznych, bo tam jest sporo materiałów, czego niestety nie można powiedzieć o polskiej sieci (mnie nie udało się znaleĽć żadnego opracowania tematu w naszym ojczystym języku, co nawiasem mówiąc było jednym z powodów napisania tego art'a). 

Zdaję sobie sprawę, że w tekście jest dużo błędów i dlatego proszę o ocenę i "konstruktywne" uzupełnienia na mój e-mail.

</p>

W temacie mam zamiar jeszcze napisać podsumowujący kod. Ale chwilowo są pewne problemy...

No i coś na co wszyscy niezadowoleni czekali:
wersja wejściowa tego art'a

12 komentarzy

Dodane formatowanie, menu, usunąłem większość niepotrzebnych odstępów itp, poprawiłem znaki. Od razu lepiej :P

UWAGA !!!
jak by były problemy z uruchomieniem (freeglut) to usunąć
GLUT_ALPHA
z
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_ALPHA | GLUT_DEPTH);

ciekawe czy oryginał też tak beznadziejnei wyglądał ;>

weś sformatuj to koles %(%$$%$ !

Masz to poprawić, bo beznadziejnie to wygląda. Wyrzuć chociaż te białe dziury

Fakt. Formatowanie by się przydało. Ale pisałem w gedit'cie i potem z odsyłaczami byłoby kupę roboty, chociaż może się postaram i poprawię :). Co do tego angielskiego to jeszcze pomyślę. A co do kodowania to... to nie wiem coo .. :)

podoba sie bardzo

i polskie literki poszły w las... - dodaj do tego jakiś spis treści (jako linki) i zdecyduj się na jeden język w artykule

nom :\ do formatowania mozna sie doczepic...
(duzo bialych miejsc)

Tak, tylko że połowa tekstu jest po angielsku ... mogłeś chociaż troche przetłumaczyć...

Napracowałeś się i to sporo. Moja uwaga: rozumiem, że chciałeś napisać czarno na białym, ale kto to będzie czytał (żadnych odnośników, spisu treści, tylko tekst i tekst przez ponad 80 stron)

Mam nadzieję, że sie spodoba ...