OpenGL.org 3Dsource.de: Infos rund um 3D-Computergrafik, OpenGL und VRML
space Telefon-Tarife space VDI - Arbeitskreis Fahrzeugtechnik space Beschallungsanlagen und Elektroakustik space Heise-News space

3 GLUT

3.010 Was ist GLUT ? Was ist der Unterschied zur OpenGL ?

Da die OpenGL keine Funktionen bietet, um auf die grafische Oberfläche oder Eingabegeräte zuzugreifen, muss das Programm systemspezifische Funktionen hierfür nutzen. Die Folge ist ein nicht portabler Code.

Ausserdem sind plattformspezifische Befehle meistens sehr komplex und umfangreich, so dass nur schwerlich einfache kleinere Programme oder Beispiele erzeugt werden können.

GLUT ist eine Bibliothek, die genau diese Ansprüche erfüllen kann, indem sie plattformunabhängige Funktionen zum Fenstermanagement, für Menüs und Eingabegeräte in einfacher Weise zur Verfügung stellt. Der Preis dafür ist ein eingeschränkter Funktionsumfang.

Jede Menge weitere Informationen gibt es in der GLUT FAQ.

3.015 Woher kann ich GLUT bekommen ?

Auf der Seite der GLUT FAQ gibt es auch den GLUT Quellcode zum Download.

Das GLUT FTP Archiv bietet nützliche Dateien, u.a. Spezifikationen, FAQs und den Quellcode verschiedener GLUT Versionen.

Auf Nate Robins Webseite ist die neueste GLUT Version (derzeit 3.7.5) gespeichert.

3.020 Sollte ich GLUT nutzen ?

Es kann natürlich sein, dass das neue Programm Funktionen bieten soll, die GLUT nicht bietet oder dass es notwendig ist, auf plattformspezifische Bibliotheken zuzugreifen, um nicht-grafische Aufgaben auszufüren. In diesem Fall kann es sinnvoll sein, vollkommen auf GLUT zu verzichten und statt dessen für die Fenster und Eingabe auch die plattformspezifischen Bibliotheken zu nutzen. Eine Entscheidungshilfe könnten die folgenden Fragen darstellen:

  • Soll das Programm nur auf einer Plattform laufen ?
  • Will ich mehr als einen Rendering Context nutzen ?
  • Muss ich Display Listen oder Texturobjekte in verschiedenen Display Listen nutzen ?
  • Will ich Eingabegeräte nutzen, auf die GLUT keinen Zugriff bietet ?
  • Muss ich plattformspezifische Bibliotheken für andere Aufgaben nutzen (z.B. Sound oder Text) ?

Falls eine dieser Fragen mit JA beantwortet wurde, sollte der Einsatz von GLUT nochmals auf Zweckmässigkeit überprüft werden.

3.025 Die GLUT Quellcode-Lizenz ist ziemlich restriktiv. Gibt es Alternativen ?

Ja, am besten mal auf der Webseite der Freeglut Initiative vorbeischauen. Es scheint eine 100% Alternative zu GLUT 3.7 zu sein.

3.027 Warum ruft glutTimerFunc() meinen Callback nur einmal auf ?

GLUTs Timerfunktion ist so programmiert, dass sie eine Zeitschleife (Timer) startet und nach Ablauf der im Befehl angegebenen Zeitspanne den dazugehörigen Callback aufruft. Danach wird der Timer gelöscht. Diese Vorgehensweise funktioniert bei den meisten API's am besten.

Falls der Timer mehrfach benötigt wird, kann er im Callback mit den gleichen Parametern nochmals aufgerufen werden (also rekursiv). Ein Beispiel dafür ist:

    static void timerCallback (int wert)
    {
      /* Aufgaben des Callbacks wahrnehmen */
      /* gegebenenfalls glutPostRedisplay()aufrufen */

      /* nach einer bestimmten Zeitspanne diesen Callback nochmal aufrufen */
      glutTimerFunc (Zeitspanne, timerCallback, wert);
    }

3.030 Ich brauche jeweils andere Funktionen für die linke und rechte Maustaste. Allerdings kann ich nur den glutMotionFunc()-Callback setzen und der übermittelt nicht, welche Maustaste derzeit gedrückt ist.

Um verschiedene Motion-Callbacks für die linke bzw. rechte Maustaste zu nutzen, muss vor dem Aufruf des Motion-Callbacks der Status der Maus- bzw. Zusatztasten abgefragt werden. Mit glutMouseFunc() kann in Abhängigkeit von der gedrückten Taste ein jeweils anderer Callback aktiviert werden. Die Parameter des Callbacks für glutMouseFunc() sind: als erster Parameter der Mausknopf (GLUT_LEFT, GLUT_MIDDLE, GLUT_RIGHT), als zweiter Parameter der Status (GLUT_UP or GLUT_DOWN), also Knopf gedrückt oder losgelassen sowie die aktuelle Mausposition. Ein Beispiel für diesen Callback wäre:

    /* Deklarationen */
    void leftMotion (int x, int y);
    void rightMotion (int x, int y);

    /* Callback, Festlegen mit glutMouseFunc(mouseCallback) */
    void mouseCallback (int button, int state, int x, int y)
    {
      if (state==GLUT_DOWN) {
        /* Ein Knopf wurde gedrückt. Passenden Callback festlegen */
        if (button==GLUT_LEFT)
          glutMotionFunc (leftMotion);
        else if (button==GLUT_RIGHT)
          glutMotionFunc (rightMotion);
      }
    }

Man kann auch leicht verschiedene Funktionen in Abhängigkeit von der SHIFT, ALT und STRG Taste festlegen. Deren Status lässt sich dabei mit glutGetModifiers() ermitteln.

3.040 Wie arbeitet GLUT ?

Es ist mit Sicherheit für viele interessant, wie GLUT die Funktionen zum Fenster erzeugen, Eingaben verarbeiten, Menüs anzeigen und andere Aufgaben löst. Der beste Weg, um dieses nachzuvollziehen ist es, sich den Quelltext herunterzuladen und anzusehen.

3.050 Wie kann ich Animationen mit GLUT realisieren ?

Um GLUT zum Generieren eines neuen Frames zu zwingen, muss glutPostRedisplay() aufgerufen werden. Dieses wird z.B. dann notwendig, wenn sich die Fenstergrösse geändert hat oder aber sich die Parameter für die Szene geändert haben. Während ein Resize das Neuzeichnen automatisch veranlasst, muss nach einer Tastatur- oder Mauseingaben der explizite Aufruf von glutPostRedisplay() erfolgen. Nach Abarbeitung wird die Kontrolle wieder an glutMainLoop() zurückgegeben.

Um nun eine Animation mit schnellstmöglicher Geschwindigkeit ausführen zu können, lässt sich ein Neuzeichnen auch als Callback von glutIdleFunc() realisieren. Dieser wird immer dann ausgeführt, wenn alle anderen Aufgaben abgearbeitet sind, das Programm also nichts mehr zu tun hat. Aus diesem Callback kann auch glutPostRedisplay() aufgerufen werden.

Eine zweite Möglichkeit besteht in der zeitgesteuerten Animation. Hier wird der Callback nicht als Idle (im Leerlauf), sondern nur nach einer verstrichenen Zeitdauer mittels glutTimerFunc() aufgerufen. Nach dem Aufruf wird der Timer deaktiviert, der Callback kann allerdings zusätzlich zum Neuzeichnen auch einen neuen Timer festlegen.

3.060 Kann ich die Fenstergrösse auch noch ändern, nachdem das Fenster geöffnet wurde (also nach dem Aufruf von glutInitWindowSize(); und glutCreateWindow();) ?

Nachdem das Programm den glutMainLoop() erreicht hat und einen Callback aufruft, kann die Funktion glutReshapeWindow(int breite, int hoehe) zum Festlegen der Fenstergrösse genutzt werden.

Dabei arbeitet glutReshapeWindow() nicht unmittelbar, sondern es wird eine Anforderung an die GLUT Bibliothek gestellt. Sobald das Programm wieder den glutMainLoop() aufruft, wird die Grössenänderung durch GLUT veranlasst.

3.070 In meinen Programm alloziiere ich Speicher nach dem Start dynamisch. Wie kann ich diesen Speicher zum Programmende wieder frei geben ?

Wird das Programm durch eine Funktion beendet die sich abfangen lässt (Tastendruck, Menü), so ist die Anwort einfach. Es muss in dem entsprechenden Callback (z.B. quitProgram()) nur der aloziierte Speicher freigegeben werden.

Diese Frage ist eher interessant, wenn der Anwender das Programm über andere Funktionen beendet, z.B. über das Schliessen-Kreuz rechts oberhalb der Menüleiste unter MS Windows. In diesem Fall erhält das Programm keine Nachricht von der GLUT Ereignisroutine, es wird stattdessen einfach über exit(0) beendet.

Übliche Resourcen wie dynamisch angeforderter Speicher werden dabei nach Programmende durch das Betriebssystem wieder freigegeben.

Eindeutig aufwendiger wird es, wenn vor Beendigung eine Dialogbox dem Anwender z.B. die Möglichkeit geben soll, den Inhalt des Speichers in eine Datei zu sichern.

Unter C++ kann GLUT innerhalb einer C++ Klasse aufgerufen und gleichzeitig global definiert werden. C++ garantiert den Aufruf des Klassendestruktors, bevor das Programm endgültig beendet wird.

Ein zweite Möglichkeit steht mit ANSI C/C++ zur Verfügung. Hier gibt es die Funktion atexit(), mit der die Aufgaben vor dem endgültigen Ende des Programms definiert werden können. Auch hier müssen die dynamisch angelegten Objekte global verfügbar sein, um durch atexit() wieder freigegeben werden zu können. Detailiertere Informationen bietet jede ANSI C/C++ Referenz. Ausserhalb C/C++ ist atexit() oder vergleichbares in der Regel nicht verfügbar.

Eine letzte Möglichkeit ist der Eingriff in den GLUT Quelltext, um hier einen expliziten Callback für die Beendigungsnachricht durch das Betriebssystem im glutMainLoop() festzulegen. Ideal ist die Lösung allerdings nicht, denn so muss der gesamte Funktionsumfang des glutMainLoop() innerhalb des eigenen Programms neu definiert, also ein eigener MainLoop programmiert werden.

3.080 Wie kann mein Programm feststellen, dass der Benutzer das Fenster geschlossen hat ?

Diese Frage wird im vorherigen Abschnitt 3.070 beantwortet.

3.090 Wie kann ich es realisieren, dass glutMainLoop() wieder zum aufrufenden Programm zurückkehrt ?

glutMainLoop() ist grundsätzlich nicht dazu ausgelegt, zu einer aufrufenden Funktion zurückzukehren. GLUT ist für ein ereignisgesteuertes Programm konzipiert, in dem die Beendigungsfunktion durch Callbacks (Tastatur, Menü) aufgerufen wird.

Falls es unbedingt notwendig ist, aus dem glutMainLoop() zum Programm zurückzukehren, muss auch hier der glutMainLoop() entsprechend geändert und als eigenständige Funktion im Programm realisiert werden (siehe auch glutMainLoop Hack).

3.100 Wie kann ich das Konsolenfenster mit GLUT unter MS Windows verhindern ?

Unter MS Vc++ 6.0 kann unter Projekteigenschaften der Eintrag "/SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup" eingefügt werden. Vergleichbar gilt dies auch für andere Compiler.

3.110 Ich habe keine Antwort zu meinem GLUT-Problem gefunden. Wo kann ich noch suchen ?

Die GLUT FAQ stellt eine hervorragende Quelle für GLUT Fragen dar.

Seite durchsuchen nach:

Fragen oder Ideen an:
Thomas.Kern@3Dsource.de
Linux-Counter
(C) Thomas Kern