Lektion 12
In diesem Tutorial werde ich Ihnen beibringen, wie man Display Listen verwendet. Nicht nur, dass Display Listen Ihren Code schneller machen, damit reduzieren Sie auch die Anzahl der zu schreibenden Codezeilen, wenn Sie eine einfach GL Szene erzeugen.
Zum Beispiel. Sagen wir, Sie machen ein Spiel wie Asteroids. Jedes Level beginnt mit mindestens 2 Asteroiden. Sie setzen sich also mit Ihrem Zeichnenpapier hin (grins) und finden heraus, wie Sie einen 3D Asteroiden erstellen. Wenn Sie erst einmal alles herausgefunden haben, erzeugen Sie die Asteroiden in OpenGL, indem Sie Polygone oder Quadrate erstellen. Sagen wir, der Asteroid ist ein Oktaeder (8-flächig). Wenn Sie klever sind, erzeugen Sie eine Schleife und zeichnen den Asteoriden innerhalb der Schleife. Sie erhalten dann also 18 Zeilen oder mehr an Code, um ein Asteroid zu erzeugen. Wenn Sie den Asteroiden jedes Mal erzeugen, wenn Sie die Szene zeichnen, wird es für Ihr System recht hart. Wenn Sie erst einmal mit komplexeren Objekten zu tun haben, werden Sie sehen, was ich meine.
Was ist also die Lösung? Display Listen!!! Indem Sie eine Display Liste benutzen, erzeugen Sie das Objekt nur einmal. Sie können es texturieren, einfärben, was immer Sie machen wollen. Sie geben der Display Liste einen Namen. Da es sich um einen Asteroiden handelt, nennen wir die Display Liste 'asteroid'. Jedes Mal, wenn wir jetzt unseren texturierten / gefärbten Asteroiden in der Szene zeichnen wollen, müssen wir lediglich glCallList(asteroid) aufrufen. Der vorherige Asteroid wird unverzüglich auf dem Bildschirm erscheinen. Da der Asteroid bereits zuvor in einer Display Liste erzeugt wurde, muss OpenGL nicht mehr herausfinden, wie die Figur erzeugt werden muss. Er ist ja bereits im Speicher. Das nimmt dem Prozessor viel Arbeit ab und erlaubt Ihrme Programm wesentlich schneller zu laufen!
Sind Sie nun bereit zum lernen? :) Wir werden das die Q-Bert Display Liste Demo nennen. Am Ende wird ein Q-Bert auf dem Bildschirm, bestehend aus 15 Würfeln, erscheinen. (Anm. des Übersetzers: Q-Bert ist eine Spielfigur aus einem Videospiel). Jeder Würfel wird aus einem Deckel (TOP) und einer BOX bestehen. Der Deckel wird eine eigene Display Liste werden, so dass wir ihn eine dunklere Schattierung geben können. Die Box ist ein Würfel ohne den Deckel :)
Dieser Code basiert auf Lektion 6. Ich schreibe fast das ganze Programm nochmal auf, so dass Sie Änderungen leicht verfolgen können. Die folgenden Codezeilen sind Standard-Code, der auch in allen vorherigen Lektionen verwendet wurde.
#include <windows.h> // Header Datei für Windows
#include <stdio.h> // Header Datei für Standard Input/Output
#include <gl\gl.h> // Header Datei für die OpenGL32 Library
#include <gl\glu.h> // Header Datei für die GLu32 Library
#include <gl\glaux.h> // Header Datei für die GLaux Library
HDC hDC=NULL; // Privater GDI Device Context
HGLRC hRC=NULL; // Permanenter Rendering Context
HWND hWnd=NULL; // Enthält unser Fenster-Handle
HINSTANCE hInstance; // Enthält die Instanz der Applikation
bool keys[256]; // Array das für die Tastatur Routine verwendet wird
bool active=TRUE; // Fenster Aktiv Flag standardmäßig auf TRUE gesetzt
bool fullscreen=TRUE; // Fullscreen Flag ist standardmäßig auf TRUE gesetzt
Als nächstes deklarieren wir unsere Variablen. Als erstes ein Speicherplatz für eine Textur. Dann erzeugen wir zwei neue Variablen für unsere 2 Display Listen. Diese Variablen arbeiten als Zeiger auf die Display Listen, wo diese im Speicher liegen. Sie werden box und top genannt.
Danach haben wir 2 Variablen namens xloop und yloop, die dazu verwendet werden, um unsere Würfel auf dem Bildschirm zu positionieren und 2 Variablen namens xrot und yrot, die dazu verwendet werden um die Würfel auf der X und Y-Achse zu rotieren.
GLuint texture[1]; // Speicherplatz für eine Textur
GLuint box; // Speicherplatz für die Display Liste
GLuint top; // Speicherplatz für die zweite Display Liste
GLuint xloop; // Schleife für die X-Achse
GLuint yloop; // Schleife für die Y-Achse
GLfloat xrot; // Rotiert den Würfel auf der X-Achse
GLfloat yrot; // Rotiert den Würfel auf der Y-Achse
Als nächstes erzeugen wir zwei Farb-Arrays. Das erste, boxcol, speichert die Farbwerte für hell Rot, Orange, Gelb, Grün und Blau. Jeder Wert innerhalb der {} repräsentieren ein Rot, Grün und Blau-Wert. Jede Gruppe der {} ist eine bestimmte Farbe.
Das zweite Farb-Array, das wir erzeugen, ist für dunkel Rot, dunkel Orange, dunkel Geld, dunkel Grün und dunkel Blau. Die dunklen Farben werden dazu benutzt, um die Deckel zu zeichnen. Wir wollen diese dunkler als den Rest der Box haben.
static GLfloat boxcol[5][3]= // Array für die Box Farben
{
// helles: Rot, Orange, Gelb, Grün, Blau
{1.0f,0.0f,0.0f},{1.0f,0.5f,0.0f},{1.0f,1.0f,0.0f},{0.0f,1.0f,0.0f},{0.0f,1.0f,1.0f}
};
static GLfloat topcol[5][3]= // Array für die Deckel Farben
{
// Dunkel: Rot, Orange, Gelb, Grün, Blau
{.5f,0.0f,0.0f},{0.5f,0.25f,0.0f},{0.5f,0.5f,0.0f},{0.0f,0.5f,0.0f},{0.0f,0.5f,0.5f}
};
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Deklaration für WndProc
Nun erzeugen wir die eigentliche Display Liste. Sie werden bemerken, dass der gesamte Code, um die Box zu erzeugen, in der ersten Liste steht und der Code für den Deckel in der anderen Liste. Ich versuche diesen Abschnitt so detailiert wie möglich zu erläutern.
GLvoid BuildLists() // erzeuge Box Display List
{
Wir fangen damit an, OpenGL mitzuteilen, dass wir 2 Listen erzeugen wollen. glGenLists(2) erzeugt Platz für zwei Listen und gibt einen Zeiger auf die erste Liste zurück. 'box' enthält den Ort der ersten Liste. Jedes Mal wenn wir box aufrufen, wird die erste Liste gezeichnet.
box=glGenLists(2); // erzeuge zwei Listen
Nun erzeugen wir die erste Liste. Wir haben bereits Platz für zwei Listen geschafft und wir wissen, dass Box auf den Bereich zeigt, wo wir die erste Liste speichern werden. Nun müssen wir OpenGL lediglich mitteilen, wo die Liste hinkommen soll und um welche Art Liste es sich handelt.
Wir benutzen den Befehl glNewList(), um jenes zu bewerkstelligen. Sie werden bemerken, dass box der erste Parameter ist. Damit wird OpenGL mitgeteilt, die Liste dort im Speicher zu speichern, wo box hinzeigt. Der zweite Parameter, GL_COMPILE, teilt OpenGL mit, dass wir die Liste bereits vorher im Speicher erzeugen wollen, so dass OpenGL nicht jedesmal herausfinden muss, wie das Objekt erzeugt werden muss, wenn wir das Objekt zeichnen.
GL_COMPILE ist dem Programmieren ähnlich. Wenn Sie ein Programm schreiben und in Ihrem Compiler laden, müssen Sie es jedes mal kompilieren, wenn Sie es ausführen wollen. Wenn es bereits als .EXE Datei kompiliert wurde, müssen Sie lediglich die .exe Datei ausführen, um das Programm laufen zu lassen. Es wird keine Kompilierung benötigt. Wenn GL einmal eine Display Liste kompiliert hat, ist sie bereit und muss nicht mehr kompiliert werden. Daher bekommen wir den Geschwindigkeitswachstum, wenn wir Display Listen verwenden.
glNewList(box,GL_COMPILE); // Neu kompilierte box Display List
Der nächste Codeabschnitt zeichnet die Box ohne Deckel. Sie wird nicht auf dem Screen erscheinen. Sie wird in der Display Liste gespeichert.
Sie können jeden Befehl, den Sie wollen, zwischen glNewList() und glEndList() verwenden. Sie können Farben setzen, Texturen ändern, etc. Die einzige Art Code, die Sie NICHT verwenden können, ist Code, der die Display Liste 'on the fly' verändert. Wenn die Display Liste erst einmal erzeugt wurde, können Sie sie NICHT ändern.
Wenn Sie die Zeile glColor3ub(rand()%255,rand()%255,rand()%255) in den folgenden Code eingefügt haben, werden Sie vielleicht denken, dass das Objekt jedesmal eine andere Farbe hat, wenn es gezeichnet wird. Da die Liste aber nur einmal ERZEUGT wir, wird sich die Farbe nicht bei jedem Zeichnen ändern. Welche Farbe auch immer das Objekt bei der Erzeugung erhält, so wird diese Farbe beibehalten.
Wenn Sie die Farbe der Display Liste ändern wollen, müssen Sie diese ändern, BEVOR Sie die Display Liste auf dem Screen zeichnen. Ich werde dazu später mehr erklären.
glBegin(GL_QUADS); // fange an Quadrate zu zeichnen
// untere Seite
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // oben rechts der Textur und des Quadrates
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // oben links der Textur und des Quadrates
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // unten links der Textur und des Quadrates
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // unten rechts der Textur und des Quadrates
// vordere Seite
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // unten links der Textur und des Quadrates
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // unten rechts der Textur und des Quadrates
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // oben rechts der Textur und des Quadrates
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // oben links der Textur und des Quadrates
// Back Face
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // unten rechts der Textur und des Quadrates
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // oben rechts der Textur und des Quadrates
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // oben links der Textur und des Quadrates
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // unten links der Textur und des Quadrates
// Right face
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f); // unten rechts der Textur und des Quadrates
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // oben rechts der Textur und des Quadrates
glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // oben links der Textur und des Quadrates
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, 1.0f); // unten links der Textur und des Quadrates
// Left Face
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f); // unten links der Textur und des Quadrates
glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, 1.0f); // unten rechts der Textur und des Quadrates
glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // oben rechts der Textur und des Quadrates
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // oben links der Textur und des Quadrates
glEnd(); // fertig mit Quadrate zeichnen
Wir teilen OpenGL mittels glEndList() mit, dass wir mit dem Erstellen unserer Liste fertig sind. Alles zwischen glNewList() und glEndList() ist Teil der Display Liste, alles vor glNewList() oder nach glEndList() ist nicht Teil der aktuellen Display Liste.
glEndList(); // fertig mit dem erstellen der box Liste
Nun machen wir unsere zweite Display Liste. Um herauszufinden, wo die zweite Display Liste im Speicher liegt, nehmen wir den Wert der alten Display Liste (box) und addieren eins. Der folgende Code setzt 'top' mit der Speicherstelle der zweiten Display Liste gleich.
top=box+1; // top Listen Wert ist gleich box Listen Wert +1
Nun, da wir wissen, wo wir unsere zweite Display Liste speichern, können wir Sie erzeugen. Wir machen das auf dem selben Weg, wie wir auch die erste Display Liste erzeugt haben, aber diesmal teilen wir OpenGL mit, die Liste in 'top' anstatt von 'box' zu speichern.
glNewList(top,GL_COMPILE); // Neu kompilierte top Display Liste
Der folgende Codeabschnitt zeichnet nur den Deckel der Box. Das ist ein einfaches Quadrat auf der Z-Ebene.
glBegin(GL_QUADS); // fange an Quadrate zu zeichnen
// Top Face
glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, -1.0f); // oben links der Textur und des Quadrates
glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 1.0f); // unten links der Textur und des Quadrates
glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); // unten rechts der Textur und des Quadrates
glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f, 1.0f, -1.0f); // oben rechts der Textur und des Quadrates
glEnd(); // fertig mit Quadrate zeichnen
Erneut teilen wir OpenGL mittels glEndList() mit, dass wir fertig mit dem Erzeugen unserer zweiten Liste sind. Wir haben erfolgreich 2 Display Listen erzeugt.
glEndList(); // fertig mit dem erzeugen der top Display Liste
}
Der Bitmap/Textur Erzeugungs-Code ist der selbe Code, den wir im vorherigen Tutorials zum laden und erzeugen von Texturen erzeugt haben. Wir wollen eine Textur, die wir auf alle 6 Seiten jedes Würfel mappen. Ich habe mich entschieden Mipmapping zu verwenden, um die Texturen wirklich weich aussehen zu lassen. Ich hasse es, wenn es pixelig wird :) Der Name der zu ladenden Textur ist 'cube.bmp'. Sie ist in dem Verzeichnis 'data' gespeichert. Suchen Sie LoadBMP und ändern Sie diese Zeile, dass Sie wie folgt aussieht:
if (TextureImage[0]=LoadBMP("Data/Cube.bmp")) // Lade das Bitmap
Der Resizing Code ist genau der Selbe Code wie in Lektion 6.
Der Init-Code hat einige kleine Änderungen erfahren. Ich habe die Zeile BuildList() eingefügt. Damit springen wir in den Codeabschnitt der die Display Listen erzeugt. Beachten Sie, dass BuildList() nach LoadGLTextures() kommt. Es ist wichtig zu wissen, in welcher Reihenfolge die Dinge ablaufen sollten. Als erstes erzeugen wir die Texturen, dann erzeugen wir unsere Display Listen, wo die Textur bereits erzeugt wurde, so dass wir diese auf den Würfel mappen können.
int InitGL(GLvoid) // Der ganze Setup Kram für OpenGL kommt hier rein
{
if (!LoadGLTextures()) // springe zur Textur-Laderoutine
{
return FALSE; // wenn die Textur nicht geladen wurde, gebe FALSE zurück
}
BuildLists(); // springe zum Code, der unsere Display Listen erzeugt
glEnable(GL_TEXTURE_2D); // aktiviere Texture Mapping
glShadeModel(GL_SMOOTH); // aktiviere Smooth Shading
glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Schwarzer Hintergrund
glClearDepth(1.0f); // Depth Buffer Setup
glEnable(GL_DEPTH_TEST); // aktiviere Depth Testing
glDepthFunc(GL_LEQUAL); // Die Art des auszuführenden Depth Test
Die nächsten drei Codezeilen aktivieren schnell und schmutzig Beleuchtung. Light0 ist auf den meisten Grafikkarten vordefiniert, was uns das ganze Heckmeck um die Initialisierung der Beleuchtung erspart. Nachdem wir light0 aktiviert haben, aktivieren wir die Beleuchtung. Wenn light0 auf Ihrer Grafikkarte nicht funktioniert (Sie sehen nur Dunkelheit), deaktivieren Sie einfach die Beleuchtung.
Die letzte Zeile GL_COLOR_MATERIAL erlaubt es uns, Farbe auf Texturen hinzuzufügen. Wenn wir Material Coloring (Material Färbung) nicht aktivieren, bleibt die Textur immer in der original Farbe. glColor3f(r,g,b) hat keinen Einfluß auf die Färbung. Es ist also wichtig, dass Sie dies aktivieren.
glEnable(GL_LIGHT0); // schnelle und schmutzige Beleuchtung (nimmt an, dass Light0 gesetzt ist)
glEnable(GL_LIGHTING); // aktiviere Beleuchtung
glEnable(GL_COLOR_MATERIAL); // aktiviere Material Färbung
Letztendlich setzen wir die Perspektiven Korrektur, damit es auch gut aussieht und geben TRUE zurück, damit unser Programm weiß, dass die Initialisierung in Ordnung war.
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // nette Perspektiven Korrektur
return TRUE; // Initialisierung war OK
Nun zum Zeichnen-Code. Wie immer werde ich etwas verrückt, wenn es um Mathe geht. Kein SIN und COS, aber dennoch etwas eigenartig :) Wir fangen ganz normal an, den Screen und den Depth Buffer zu löschen.
Dann binden wird die Textur an den Würfel. Ich hätte diese Zeile auch innerhalb der Display Liste einfügen können, aber solange ich diese Zeile außerhalb der Display Liste lassen, kann ich die Textur wann immer ich will ändern. Wenn ich die Zeile glBindTexture(GL_TEXTURE_2D, texture[0]) innerhalb des Display Listen Codes eingefügt hätte, würde die Display Liste mit der zuvor ausgewählten Textur permanent texturiert werden.
int DrawGLScene(GLvoid) // Hier kommt der ganze Zeichnen-Kram hin
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Lösche den Bildschirm und den Depth-Buffer
glBindTexture(GL_TEXTURE_2D, texture[0]); // wähle Textur aus
`
Nun zum spaßigen Teil. Wir haben eine Schleife namens yloop. Diese Schleife wird verwendet, um die Würfel auf der Y-Achse (hoch und runter) zu positionieren. Wir wollen 5 Reihen an Würfeln, hoch und runter, haben, weshalb wir eine Schleife von 1 bis weniger als 6 (was 5 ist) durchlaufen lassen.
for (yloop=1;yloop// durchlaufe die Y-Ebene
{
Wir haben eine weitere Schleife namens xloop. Sie wird verwendet, um die Würfel auf der X-Achse (von links nach rechts) zu positionieren. Die Anzahl der zu zeichnenden Würfel hängt von der Reihe ab, in der wir uns befinden. Wenn wir uns in der obersten Reihe befinden, geht xloop von 0 bis 1 (zeichnet einen Würfel). Die nächste Reihe wir xloop von 0 bis 2 durchlaufen (zeichnet 2 Würfel), etc.
for (xloop=0;xloop<yloop;xloop++) // durchlaufe die X-Ebene
{
Wir resetten unsere View mit glLoadIdentity().
glLoadIdentity(); // Resette die View
Die nächste Zeile geht zu einem bestimmten Punkt auf dem Screen. Es sieht etwas verwirrend aus, ist es aber eigentlich nicht. Auf der X-Achse passiert folgendes:
Wir bewegen uns 1,4 Einheiten nach rechts, so dass die Pyramide im Mittelpunkt des Screens ist. Dann multiplizieren wir xloop mit 2,8 und addieren 1,4. Wir multiplizieren mit 2,8, damit die Würfel nicht alle direkt aufeinander stehen (2,8 ist ungefähr der Wert der Breite, den die Würfel haben, wenn sie um 45 Grad gedreht sind). Zu letzt subtrahieren wir yloop*1,4. Damit bewegen wir den Würfel nach links, abhängig davon in welcher Reihe wir uns befinden. Wenn wir nicht nach links bewegen, würde das ganze nicht wirklich wie eine Pyramide aussehen.
Auf der Y-Achse subtrahieren wir yloop von 6, da ansonsten die Pyramide auf dem Kopf stehen würde. Dann multiplizieren wir das Ergebniss mit 2,4. Ansonsten wären die Würfel jeweils direkt übereinander auf der Y-Achse (2,4 ist ungefähr die Höhe eines jeden Würfels). Dann subtrahieren wir 7, so dass die Pyramide unten beginnt und dann nach oben hin aufgebaut wird.
Zu letzt bewegen wir uns 20 Einheiten auf der Z-Achse in den Screen hinein. Dadurch passt die Pyramide locker auf den Bildschirm.
// Positioniere die Würfel auf dem Screen
glTranslatef(1.4f+(float(xloop)*2.8f)-(float(yloop)*1.4f),((6.0f-float(yloop))*2.4f)-7.0f,-20.0f);
Nun rotieren wir auf der X-Achse. Wir neigen den Würfel zum Betrachter, um 45 Grad minus 2 multipliziert mit yloop. Der Perspektiven-Modus neigt die Würfel automatisch, weshalb ich subtrahiere um diese Neigung zu kompensieren. Nicht der beste Weg, um das zu machen, aber es funktioniert :)
Zu letzt addieren wir xrot. Damit haben wir die Tastaturkontrolle über den Winkel (was auch Spaß macht, damit zu spielen).
Nachdem wir auf der X-Achse rotiert haben, rotieren wir um 45 Grad auf der Y-Achse und addieren yrot, so dass wir die Tastaturkontrolle auf der Y-Achse haben.
glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f); // neige die Würfel vor und zurück
glRotatef(45.0f+yrot,0.0f,1.0f,0.0f); // rotiere die Würfel links und rechts
Als nächstes wählen wir eine (helle) Farbe für unsere Box bevor wir den eigentlichen Box-Teil des Würfels zeichnen. Beachten Sie, dass wir glColor3fv() verwenden. Was diese Funktion macht, ist das Laden aller drei Werte (rot, grün, blau) innerhalb der {} und zwar in einem Rutsch und setzt diese Farbe. 3fv steht für 3 Werte, Fließkommazahl, v ist ein Zeiger auf ein Array. Die Farbe die wir auswählen, ist yloop-1, was uns verschiedene Farben für jede Würfelreihe gibt. Wenn wir xloop-1 verwenden würden, würden wir verschiedene Farbe für jeden Spalte erhalten.
glColor3fv(boxcol[yloop-1]); // wähle eine Farbe für die Box aus
Nun, da die Farbe gesetzt ist, müssen wir nur noch unsere Box zeichnen. Anstatt den gesamten Code zum Zeichnen einer Box zu schreiben, müssen wir nur unsere Display-Liste aufrufen. Wir machen das mit dem Befehl glCallList(box). box teilt OpenGL mit, die box Display Liste zu wählen. Die box Display Liste ist ein Würfel ohne seinen Deckel.
Die Box wird mit der Farbe gezeichnet, die wir mit glColor3fv() gewählt haben, an der Position zu der wir uns bewegt haben.
glCallList(box); // zeichne die Box
Nun wählen wir die Deckel-Farbe (dunkel) bevor wir den Deckel der Box zeichnen. Wenn Sie wirklich Q-Bert erstellen wollten, müssten Sie diese Farbe ändern, wenn Q-Bert auf die Box springt. Die Farbe hängt von der Reihe (yloop-1) ab.
glColor3fv(topcol[yloop-1]); // wähle die Deckel Farbe aus
Letztendlich müssen wir nur noch die top Display Liste zeichnen. Das fügt unserer Box einen dunkelfarbigen Deckel hinzu. Das ist alles. Sehr einfach!
glCallList(top); // Zeichne den Deckel
}
}
return TRUE; // Springe zurück
}
Die verbleibenden Änderungen wurden alle in der WinMain() vorgenommen. Der Code wurde direkt nach unserer SwapBuffers(hDC) Zeile eingefügt. Er überprüft ob einer der Pfeil-Tasten gedrückt wurden und bewegt die Würfel dann entsprechend.
SwapBuffers(hDC); // Swap Buffers (Double Buffering)
if (keys[VK_LEFT]) // linker Pfeil gedrückt?
{
yrot-=0.2f; // wenn ja, neige die Würfel nach links
}
if (keys[VK_RIGHT]) // rechter Pfeil gedrückt?
{
yrot+=0.2f; // wenn ja, neige die Würfel nach rechts
}
if (keys[VK_UP]) // Pfeil-nach-oben gedrückt?
{
xrot-=0.2f; // wenn ja, neige die Würfel nach oben
}
if (keys[VK_DOWN]) // Pfeil-nach-unten gedrückt?
{
xrot+=0.2f; // wenn ja, neige die Würfel nach unten
}
Wie in den vorherigen Tutorials, ändern wir den Titel des Fensters noch, damit dieser korrekt ist.
if (keys[VK_F1]) // Wurde F1 gedrückt?
{
keys[VK_F1]=FALSE; // Wenn ja, setze Taste auf FALSE
KillGLWindow(); // Kill unser aktuelles Fenster
fullscreen=!fullscreen; // Wechsel zwischen Fullscreen und Fester-Modus
// Erzeuge unser OpenGL Fenster erneut
if (!CreateGLWindow("NeHe's Display List Tutorial",640,480,16,fullscreen))
{
return 0; // Beenden, wenn das Fenster nicht erzeugt wurde
}
}
}
}
Zum Ende dieses Tutorials sollten Sie ein gutes Verständnis dafür haben, wie Display-Listen arbeiten, wie man sie erzeugt und wie man sie am Screen anzeigt. Display-Listen sind großartig. Nicht nur, dass sie das programmieren komplexer Projekte vereinfachen, sie geben Ihnen auch das bißchen extra Geschwindigkeit, die Sie benötigen, um hohe Frameraten zu erreichen.
Ich hoffe Sie haben dieses Tutorial genossen. Wenn Sie irgendwelche Fragen haben oder denken, dass etwas nicht klar genug ist, mailen Sie mir bitte und lassen Sie es mich wissen.
Jeff Molofee (NeHe)
* DOWNLOAD Visual C++ Code für diese Lektion.
* DOWNLOAD Borland C++ Builder 6 Code für diese Lektion. ( Conversion by Christian Kindahl )
* DOWNLOAD C# Code für diese Lektion. ( Conversion by Brian Holley )
* DOWNLOAD Code Warrior 5.3 Code für diese Lektion. ( Conversion by Scott Lupton )
* DOWNLOAD Cygwin Code für diese Lektion. ( Conversion by Stephan Ferraro )
* DOWNLOAD Delphi Code für diese Lektion. ( Conversion by Michal Tucek )
* DOWNLOAD Dev C++ Code für diese Lektion. ( Conversion by Dan )
* DOWNLOAD Euphoria Code für diese Lektion. ( Conversion by Evan Marshall )
* DOWNLOAD Game GLUT Code für diese Lektion. ( Conversion by Milikas Anastasios )
* DOWNLOAD Irix Code für diese Lektion. ( Conversion by Rob Fletcher )
* DOWNLOAD Java Code für diese Lektion. ( Conversion by Jeff Kirby )
* DOWNLOAD Jedi-SDL Code für diese Lektion. ( Conversion by Dominique Louis )
* DOWNLOAD JoGL Code für diese Lektion. ( Conversion by Abdul Bezrati )
* DOWNLOAD LCC Win32 Code für diese Lektion. ( Conversion by Robert Wishlaw )
* DOWNLOAD Linux Code für diese Lektion. ( Conversion by Richard Campbell )
* DOWNLOAD Linux/GLX Code für diese Lektion. ( Conversion by Mihael Vrbanec )
* DOWNLOAD Linux/SDL Code für diese Lektion. ( Conversion by Ti Leggett )
* DOWNLOAD LWJGL Code für diese Lektion. ( Conversion by Mark Bernard )
* DOWNLOAD Mac OS Code für diese Lektion. ( Conversion by Anthony Parker )
* DOWNLOAD Mac OS X/Cocoa Code für diese Lektion. ( Conversion by Bryan Blackburn )
* DOWNLOAD MASM Code für diese Lektion. ( Conversion by Nico (Scalp) )
* DOWNLOAD Visual C++ / OpenIL Code für diese Lektion. ( Conversion by Denton Woods )
* DOWNLOAD Pelles C Code für diese Lektion. ( Conversion by Pelle Orinius )
* DOWNLOAD Visual Basic Code für diese Lektion. ( Conversion by Ross Dawson )
* DOWNLOAD Visual Studio .NET Code für diese Lektion. ( Conversion by Grant James )
Deutsche Übersetzung: Joachim Rohde
Der original Text ist hier zu finden.
Die original OpenGL Tutorials stammen von NeHe's Seite.