Virtual OS/2 International Consumer Education
VOICE-Homepage: http://de.os2voice.org
Januar 2005

Inhaltsverzeichnis
< Vorherige Seite | Nächste Seite >
Artikelverzeichnis

editor@os2voice.org


Visuelle Programmierung mit OpenGL und Innotek GCC C++

Von Per Johansson © Januar 2005, Übersetzung: Jürgen Gaida

Einleitung

OpenGL ist eine grafische Entwicklungsumgebung für nette Bildschirmschoner bis hin zu Maschinensimulationen. Mit OpenGL kann man bestehende Programme ausführen als auch eigene Programme erstellen. Dieser Artikel beschreibt, wie man OpenGL-Programme mit dem neuesten C++-Complier, Innotek GCC-3.2.2, erstellt. Es ist keine Einführung in OpenGL als solches, sondern beschreibt vielmehr, wie man vorhandenen Beispielcode und verfügbare Werkzeuge einsetzen kann um OpenGL-Programme zu erzeugen.

OS/2 Warp4 enthält einiges an Unterstützung für OpenGL, allerdings in der Version 1.0. Wenn ich mich recht erinnere, wurde dies nicht mehr in die eComStation übernommen. Für diesen Artikel verwende ich OpenGL 1.1. Dies ist die letzte (allerletzte?) Version für OS/2, für diesen Zweck aber ausreichend. Wenn Sie sich für neuere Entwicklungen interessieren, schauen Sie sich die MesaGL an (siehe unten). Ich werde zunächst folgende Werkzeuge einsetzen:

Laufzeitumgebung

Unter eComStation 1.1 können sie die OpenGL 1.1-Laufzeitkomponenten (letztes Dateidatum ist 1997-10-06) von der Applikationen-CD installieren. Die Installation umfaßt einige DLL-Dateien, die in Ihr X:\OS2\DLL Verzeichnis kopiert werden müssen.

API

Das OS/2-Developer-Toolkit Version 4.52, Dateidatum 2001-10-04, wird mit der eComStation 1.1 ausgeliefert. Man installiert es von CD 2, "Developer Software". Es enthält die Bibliotheken glut.lib, libaux.lib und opengl.lib. Es enthält auch Quellcode und compilierte Programme. Unglücklicherweise basiert dies alles auf OpenGL 1.0 und läuft nicht unter OpenGL 1.1. Sie können aber den Quellcode verwenden und mit den OpenGL 1.1-Bibliotheken neu kompilieren. Darüber hinaus wurde das Toolkit mit IBM Visual Age C++ Version 3 erstellt, weshalb Sie manchmal den Code modifizieren müssen, um es mit GCC zu kompilieren.

Die Version 1.1 der OpenGL API (letztes Dateidatum 1997-10-06) finden Sie auf Hobbes. Entweder nehmen Sie das opengl.zip, das ist das Original von IBM, oder das opengl_gold_110.wpi, welches einige Modifikationen enthält, um es zum Beispiel mit dem Watcom-Kompiler zu verwenden. In jedem Fall müssen Sie eine Header-Datei, glut.h, ändern, damit Sie sie mit dem GCC kompilieren können. Tatsächlich habe ich eine etwas neuere, offizielle glut.h gesehen, welche die gleichen Änderungen enthielt wie ich sie vorgenommen habe, also scheint es richtig zu sein, diese Änderungen zu machen. Der Zweck der glut.h ist zum Beispiel Funktionen zur Fensterbehandlung bereitzustellen, weshalb Sie keine PM-Programmierung vornehmen müssen.

Um das Verzeichnis F:\oglgold\include statt F:\oglgold\include\gl einzubinden, änderte ich folgende Zeilen:

#include <gl.h>
#include <glu.h>

zu:

#include <GL/gl.h>
#include <GL/glu.h>

Ich habe ebenfalls 20 Funktionsparameter abgeändert, entfernte einen APIENTRY (definiert als _System, vollständig erweitert zu __attribute__((__system__))) ), um folgenden Kompiler-Fehler zu vermeiden: "invalid type modifier within pointer declarator". Ich weiß nicht worin das Problem besteht, aber meine Programme funktionieren ohne diese Modifikation tadellos.

extern void APIENTRY glutDisplayFunc (void (* APIENTRY)(void));

zu:

extern void APIENTRY glutDisplayFunc (void (*)(void));

Die überarbeitete glut.h erhalten Sie hier.

Innotek GCC 3.2.2

Sie erhalten den GCC von Innotek. Ich habe die beta 4 CSD 1 eingesetzt. Sie enthält eine Installationsroutine.

IBM Link 5.0

Dieser Linker ist wird standardmäßig für GCC 3.2.2 eingesetzt. Ich habe erfolglos ältere Alternativen versucht, IBM Linker 4.0 (oder LINK386), der mit OS/2, eComStation und dem Toolkit ausgeliefert wird, einzusetzen. Auch den IBM C/C++ 3.6.5-Linker habe ich getestet. Keiner hat funktioniert, jedenfalls nicht im C++-Modus. Den IBM Linker 5.0 (Dateidatum 2003-10-07) findet man nicht so leicht; Ich habe ihn auf der Warpzilla build Seite gefunden. Die Installation ist simpel. Entpacken Sie das Archiv und ergänzen sie den PATH- und LIBPATH-Eintrag um das BIN-Verzeichnis.

Das erste Programm

Während des Studiums der OpenGL-Programmierung haben wir das Buch

Hill: Computer Programming using Open GL, 2nd edition. ISBN 0-02-254856-8
genutzt. Dieses Buch enthält viele Programmbeispiele, die auch auf der Webseite hinterlegt sind. Hier ist das erste Programm, FIG2_10.CPP mit meinen Änderungen:
/*
#include <windows.h> entfernt
#include <GL/Gl.h> entfernt, da es schon in der glut.h eingebunden ist
#include <gl/glut.h> in #include <GL/glut.h> geändert, wegen UNIX Kompatibilität
Der Rücksprung im Hauptprogramm von der Fehlerstelle auf int geändert,
in Übereinstimmung mit ISO C/C++ (ein ausdrücklicher Rücksprungbefehl ist im Hauptprogramm nicht nötig)
*/

#define OS2
#define __IBMC__
/*
#include <windows.h>   // Wenn Ihr System dies benötigt
#include <gl/Gl.h>
#include <gl/glut.h>
*/
#include <GL/glut.h>
//<<<<<<<<<<<<<<<<<<<<<<< myInit >>>>>>>>>>>>>>>>>>>>
 void myInit(void)
 {
    glClearColor(1.0,1.0,1.0,0.0);       // setze weißen Hintergrund
    glColor3f(0.0f, 0.0f, 0.0f);          // setze die Zeichnungsfarbe
        glPointSize(4.0);                      // ein Rasterpunkt sind 4 mal 4 Punkte
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluOrtho2D(0.0, 640.0, 0.0, 480.0);
}
//<<<<<<<<<<<<<<<<<<<<<<<< myDisplay >>>>>>>>>>>>>>>>>
void myDisplay(void)
{
        glClear(GL_COLOR_BUFFER_BIT);     // den Fensterinhalt löschen
        glBegin(GL_POINTS);
                glVertex2i(100, 50);         // zeichne 3 Punkte
                glVertex2i(100, 130);
                glVertex2i(150, 130);
        glEnd();
        glFlush();                               // erzeuge Ausgabe auf dem Bildschirm
}

//<<<<<<<<<<<<<<<<<<<<<<<< main >>>>>>>>>>>>>>>>>>>>>>
int main(int argc, char** argv)
{
        glutInit(&argc, argv);          // das Toolkit initialisieren
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); // den Anzeigemodus setzen
        glutInitWindowSize(640,480);     // Fenstergröße setzen
        glutInitWindowPosition(100, 150); // Fensterposition auf dem Bildschirm setzen
        glutCreateWindow("my first attempt"); // öffnen des Ausgabefensters
        glutDisplayFunc(myDisplay);     // Register Neuzeichnungsfunktion
        myInit();
        glutMainLoop();                      // starte Endlosschleife
}

Zum Kompilieren:


set path=F:\ILINK50\bin;%path%
set beginlibpath=F:\ILINK50\bin
g++ -Wall -ansi -pedantic -DOS2=1 -D__IBMC__=1 fig2_10.cpp -I\oglgold\INCLUDE -lglut -lopengl -L/oglgold/lib  -Zomf -Zlinker /PM:PM

Starten Sie das Programm mit dem Befehl fig2_10. Sie werden ein Fenster mit drei Rasterpunkten sehen.

Abbild des Fensters zur fig2_10.exe

Ein zweites Programm

Dies ist schon etwas aufwendiger. Es zeigt ein (unrealistisches) Sonnensystem mit einer Sonne und drei sich mit verschiedenen Geschwindigkeiten umkreisenden Planeten. Der Beobachtungspunkt liegt in einem Winkel zur Rotationsebene, weshalb die Umlaufbahnen elliptisch erscheinen. Durch die eingesetzte perspektivische Betrachtung ändern sich die Größen der Planeten mit ihren Entfernungen. Die Planeten werden durch das Sonnenlicht beleuchtet, das Umgebungslicht läßt auch die dunklen Seiten sichtbar werden.

#include <GL/glut.h>
#include <cstdlib>

const GLfloat
        light_pos[]      = {0, 0, 0, 1} ,
        light_ambient[]  = {0.1, 0.1, 0.1, 1} ,
        light_diffuse[]  = {1, 1, 1, 1} ,
        light_specular[] = {1, 1, 1, 1} ;

static int iteration = 0;

static GLint
        slices = 30 ,
        stacks = 30 ;

void myCreateObjects(int iteration)
{
        GLfloat
                white[] = {1, 1, 1, 1},
                red[] = {1, 0, 0, 1},
                green[] = {0, 1, 0, 1},
                blue[] = {0, 1, 1, 1},
                spec_exp = 100;

        glPushAttrib(GL_LIGHTING_BIT);
        glDisable(GL_LIGHTING);
        glColor3ub(255, 255, 0);
        glutSolidSphere(5, slices, stacks);
        glPopAttrib();

        glMaterialfv(GL_FRONT, GL_AMBIENT, white);
        glMaterialfv(GL_FRONT, GL_SPECULAR, white);
        glMaterialf(GL_FRONT, GL_SHININESS, spec_exp);

        for (int i(1); i <=3; ++i) {
                glPushMatrix();
                glRotatef((iteration) * 3/i, 0, 1, 0);
                glTranslatef(i * 10, 0, 0);
                switch (i)
                {
                        case 1: glMaterialfv(GL_FRONT, GL_DIFFUSE, red) ;
                        break ;
                        case 2: glMaterialfv(GL_FRONT, GL_DIFFUSE, green) ;
                        break ;
                        case 3: glMaterialfv(GL_FRONT, GL_DIFFUSE, blue) ;
                        break ;
                        default: glMaterialfv(GL_FRONT, GL_DIFFUSE, white) ;
                }
                glutSolidSphere(2, slices, stacks);
                glPopMatrix();
        }
}

void myKeyHandler(unsigned char key, int x, int y)
{
        //während der Mauszeiger auf dem Fenster liegt
        if (key == 'q') {
                exit(0);
        }
}

void myDisplay()
{
}

void myReshape(int w, int h)
{
        GLint border = 10 ;
        GLint size_of_curve ;
        GLint low_left_x, low_left_y ;
        if (w > h) {
                if (h < 2 * border) {
                        border = 0 ;
                } /* endif */
                size_of_curve = h - 2 * border ;
                low_left_x = static_cast<GLint>(0.5 * (w - size_of_curve)) ;
                low_left_y = border ;
        } else {
                if (w < 2 * border) {
                        border = 0 ;
                } /* endif */
                size_of_curve = w - 2 * border ;
                low_left_x = border ;
                low_left_y = static_cast<GLint>(0.5 * (h - size_of_curve)) ;
        } /* endif */
        glViewport(low_left_x, low_left_y, size_of_curve, size_of_curve) ;
}

void myMenuHandler(int id)
{
        if (id == 1) {
                slices = 4 ;
                stacks = 4 ;
                } else {
                        if (id == 2) {
                                slices = 30 ;
                                stacks = 30 ;
                                } else {
                                        if (id == 3) {
                                                exit(0);
                                        } else {
                        } /* endif */
                } /* endif */
        } /* endif */
}

void myIdle()
{
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
        myCreateObjects(++iteration);
        glFlush();
        glutSwapBuffers();
        glutPostRedisplay();
}

void myInit()
{
        GLdouble aspect = 1;
        glClearColor(0.0, 0.0, 0.2, 0.0);

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        gluPerspective(45, aspect, 50, -50);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        gluLookAt(0, 20, 80,  0, 0, 0,  0, 1, 0);

        glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
        glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse);
        glLightfv(GL_LIGHT0, GL_SPECULAR, light_specular);
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);

        glLightfv(GL_LIGHT0, GL_POSITION, light_pos);
        glShadeModel(GL_SMOOTH);
        glEnable(GL_DEPTH_TEST);

}


int main(int argc, char** argv)
{
       glutInit(&argc, argv);
       glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
       glutInitWindowSize(640, 480);
       glutInitWindowPosition(100, 150);
       glutCreateWindow("Solar System");
       glutKeyboardFunc(myKeyHandler);
       glutDisplayFunc(myDisplay);
       glutReshapeFunc(myReshape);
       glutCreateMenu(myMenuHandler);
       glutAddMenuEntry("Fast", 1);
       glutAddMenuEntry("Slow", 2);
       glutAddMenuEntry("Quit", 3);
       glutAttachMenu(GLUT_RIGHT_BUTTON);
       glutIdleFunc(myIdle);
       myInit();
       glutMainLoop();
}

Zum Kompilieren:

g++ -ansi -pedantic -DOS2=1 -D__IBMC__=1 solar.cpp -I\oglgold\INCLUDE -lglut -lopengl -L/oglgold/lib -Zomf -Zlinker /PM:PM

Bild 1 des Sonnensystem-Programms Bild 2 des Sonnensystem-Programs

Das OS/2 Toolkit

Im Verzeichnis \OS2TK45\samples\opengl liegen einige Beispiele. Die meisten davon verwenden die abgelehnte libaux Bibliothek, aber es gibt zwei GLUT-Programme, atlantis und test7 im glutdemo Verzeichnis. Ich konnte sie kompilieren und ausführen lassen, nachdem ich die OpenGL #include wie oben gezeigt abgeändert hatte, obwohl test7 nicht ganz korrekt läuft - ich weiß bis heute nicht warum.

Mehr Informationen und Quellen

Zusammenfassung

Ich hatte Schwierigkeiten mit dem Einstieg in OpenGL, weil ich es mit dem GCC machen wollte. Vielleicht hilft dieser Artikel anderen aufstrebenden Programmierern. Er zeigt, was man benötigt, um einfachen Beispielcode mit dem Innotek GCC Compiler zu kompilieren und auszuführen.

Daten und Quellen:

Hobbes: http://hobbes.nmsu.edu
Innotek: http://www.innotek.de
Warpzilla build site: http://www.mozilla.org/ports/os2/gccsetup.html
OpenGL book programming samples: http://www.prenhall.com/hill/html/cg.html
EDM/2: http://www.edm2.com
Interview re. OpenGL: http://www.os2voice.org/VNL/past_issues/VNL0398H/vnewsf4.htm
Snow Storm Software: http://www.snowstormsoftware.com
Escape GL review: http://www.os2voice.org/VNL/past_issues/VNL1099H/vnewsn5.htm
MesaGL homepage: http://www.laser.ru/soft/WarpMesaGL


Artikelverzeichnis
editor@os2voice.org
< Vorherige Seite | Inhaltsverzeichnis | Nächste Seite >
VOICE-Homepage: http://de.os2voice.org