www.codeworx.org/opengl-tutorials/Tutorial 12: Display-Listen

Lektion 12: Display-Listen

In diesem Tutorial werde ich euch erklären wie man Display-Listen verwendet. Sie machen euren Code nicht nur schneller sondern verringern auch noch die Anzahl der Zeilen die ihr schreiben müsst.

Wenn ihr also zum Beispiel das Spiel "Asteroids" machen wollen würdet. Jedes Level fängt mit mindestens 2 Asteoriden an. Du setzt dich also an deine Grafikaufzeichnungen *g* und entwirfst einen 3D Asteroiden. Wenn du dich entschieden hast wie er aussehen soll erstellst du den Asteroiden in OpenGL aus Vierecken und Polygonen. Der Asteorid ist z.B. octagonal (8-seitig). Wenn du schlau bist erstellst du den Körper innerhalb einer Schleife. dann hast du trotzdem mindesten 18 oder mehr Zeilen Code. Den Asteroiden jedesmal neu zu erstellen wenn er auf dem Bildschirm gezeichnet werden soll geht ganz schön auf die Performance. Wenn später einmal komplexere Objekte zu zeichnen sind wisst ihr was ich meine.

So, wie löst man nun dieses Problem ? Mit Display-Listen !!! Wenn man Display-Listen verwendet erstellt man das Objekt nur ein mal. Du kannst es texturieren, färben, was auch immer. Dann gibt man der Liste einen Namen. Da es sich um einen Asteroiden handelt nennen wir die Liste "Asteroid". Nun, wenn wir einen texturierten und gefärbten Asteroiden zeichnen wollen ist alles was wir tun müssen glCallList(asteroid); aufzurufen. Der schon vorher erstellte Asteroid erscheint auf dem Bildschirm. Da der Asteroid schon in der Display-Liste erstellt wurde muss OpenGL nicht erst rausfinden wie er aufgebaut ist. Er wurde schon im Speicher vorgebaut. Dies nimmt dem Prozessor einiges an Arbeit ab und erlaubt eurem Programm um einiges schneller zu laufen.

Seit ihr bereit zu lernen ? :-) Wir nennen diese Demo "Die Q-Bert Display-Listen Demo". Am Ende wirst du einen Q-Bert auf dem Bildschrim haben, bestehend aus 15 Würfel. Jeder Würfel besteht aus einem Deckel(TOP) und einer BOX. Der Deckel wird eine eigene Display-Liste bekommen so das wir ihn dunkler zeichnen können. Die BOX ist einfach ein Würfel ohne Deckel. :-)

Der Code baut auf Tutorial 6 auf. Ich habe den grössten Teil des Programms nochmal geschrieben, so ist es einfacher zu sehen wo ich etwas verändert habe. Die folgenden Zeilen sind Standart in fast jedem Tutorial.

#include <windows.h>  // Header File For Windows
#include <stdio.h>    // Header File For Standard Input/Output
#include <gl\gl.h>    // Header File For The OpenGL32 Library
#include <gl\glu.h>   // Header File For The GLu32 Library
#include <gl\glaux.h> // Header File For The GLaux Library

HDC             hDC=NULL;  // Private GDI Device Context
HGLRC           hRC=NULL;  // Permanent Rendering Context
HWND            hWnd=NULL; // Holds Our Window Handle
HINSTANCE       hInstance; // Holds The Instance Of The Application

bool    keys[256];       // Array Used For The Keyboard Routine
bool    active=TRUE;     // Window Active Flag Set To TRUE By Default
bool    fullscreen=TRUE; 
// Fullscreen Flag Set To Fullscreen Mode By Default

Nun definieren wir vier Variablen. Als erstes schaffen wir Platz für eine Textur. Dann brauchen wir zwei neue Variablen für unsere 2 Display-Listen. Diese Variablen agieren als Pointer, welche auf die Speicherposition der Display-Listen im Ram verweisen. Wir nennen sie box und top.

Danach haben wir 2 Variablen, genannt xloop und yloop, welche die Position des Würfels auf dem Bildschirm bestimmen. Und noch 2 Variablen xrot und yrot um den Würfel auf der X-Achse und auf der Y-Achse rotieren zu lassen.

GLuint  texture[1];  // Storage For One Texture
GLuint  box;         // Storage For The Display List
GLuint  top;         // Storage For The Second Display List
GLuint  xloop;       // Loop For X Axis
GLuint  yloop;       // Loop For Y Axis
GLfloat xrot;        // Rotates Cube On The X Axis
GLfloat yrot;        // Rotates Cube On The Y Axis

Als nächstes erschaffen wir unsere zwei Farb-Arrays. Das erste enthält die Werte für helles Rot, Orange, Gelb, Grün und Blau. Jeder Wert innerhalb der {} enthält den jeweiligen Rot, Grün und Blau Anteil. Jede Gruppe von {} entspricht einer bestimmten Farbe.

Das zweite Farb-Array enthält Dunkelrot, Dunkelorange, Dunkelgelb, Dunkelgrün und Dunkelblau. Die dunklen Farben werden dazu benutzt den Deckel der Boxen zu zeichnen. Der Deckel soll dann also dunkler sein als der Rest der Box.

static GLfloat boxcol[5][3]=  // Array For Box Colors
{
  // Bright:  Red, Orange, Yellow, Green, Blue
  {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 For Top Colors
{
  // Dark:  Red, Orange, Yellow, Green, Blue
  {.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);   
// Declaration For WndProc
Nun wollen wir unsere erste Display-Liste erstellen. Wie du gleich bemerken wirst, ist jeglicher Code für die Box in unserer ersten Liste während der Code für den Deckel in der zweiten steckt. Ich versuche das jetzt so detailrech wie möglich zu erläutern.
GLvoid BuildLists()					
// Build Box Display List
{
Wir beginnnen indem wir OpenGL sagen das wir 2 Listen bauen wollen. Die Funktion glGenLists(2) stellt den Platz für 2 Listen bereit und gibt einen Pointer zurück, der auf die erste Liste zeigt. Die Variable 'box' enthält die Position der ersten Liste. Immer wenn wir nun 'box' aufrufen wird die Liste Nummer eins gezeichnet.
box=glGenLists(2);				
// Building Two Lists

Nun stellen wir unsere erste Liste mal zusammen. Den Platz für 2 Listen haben wir bereits geschaffen, und wir wissen das 'box' auf die Stelle im Speicher zeigt wo wir die erste Liste speichern werden. Das einzigste was wir jetzt noch machen müssen ist OpenGL mitzuteilen wie die Liste aussieht und welche Art von Liste wir haben möchten.

Dafür benutzen wir die Funktion glNewList() . Du wirst bemerken das 'box' der erste Parameter ist. Dies sagt OpenGL das die Liste an der Position gespeichert wird auf die 'box' zeigt. Der zweite Parameter ist GL_COMPILE welcher OpenGL sagt, dass das Objekt im Speicher bereits erstellt werden soll so das OpenGL nicht jedesmal wenn wir es zeichnen herrausfinden muss wie es aussieht.

GL_COMPILE ist ähnlich dem Programmieren. Wenn du ein Programm schreibst und es in den Compiler lädts, musst du es jedesmal compilieren um es auszuführen. Wenn es aber schon compiliert ist und als .EXE datei vorhanden musst du es einfach nur noch anklicken um es auszuführen. Wenn OpenGL die Liste einmal compiliert hat kann es sie beliebig benutzen, ohne sie jedesmal neu zu compilieren. Daher kommt der Geschwindigkeitsvorteil wenn wir Display-Listen verwenden.

glNewList(box,GL_COMPILE);			
// New Compiled box Display List

Der nächste Abschnitt zeichnet die Box ohne Deckel. Es wird Nichts auf dem Bildschirm erscheinen sondern Alles in der Display-Liste gespeichert werden.

Du kannst jeden Befehl den du willst zwischen glNewList() und glEndList() einfügen. Du kannst die Farbe setzen, die Textur wechseln etc. das einzigste was du nicht machen kannst, ist die Display-Liste während der Laufzeit verändern. Wenn die Liste einmal gebaut wurde kannst du sie nicht mehr ändern.

Wenn du z.B. die Zeile glColo3ub(rand()%255,rand()%255,rand()%255) in den unteren Code einfügen würdest, könnte man denken das jedesmal wenn du das Objekt auf dem Bildschirm zeichnest es eine andere Farbe haben wird. Aber dadurch, dass die Liste nur einmal erstellt wird, wird die Farbe natürlich nicht gewechselt. Was auch immer das Objekt für eine Farbe hatte als es erstellt wurde, kann diese dann nicht mehr geändert werden.

Wenn du die Farbe der Display-Liste ändern möchtest musst du dies tun, bevor du die Liste zeichnest. Ich werden dies später ausführlicher erklären.


glBegin(GL_QUADS);							
// Start Drawing Quads

  // Bottom Face
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	
  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	 
  // Top Left Of The Texture and Quad
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	
  // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	
  // Bottom Right Of The Texture and Quad
  
  // Front Face
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	
  // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	
  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	
  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	
  // Top Left Of The Texture and Quad

  // Back Face
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	
  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	
  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	 
  // Top Left Of The Texture and Quad
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	
  // Bottom Left Of The Texture and Quad
  
  // Right face
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, -1.0f, -1.0f);	
  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);	
  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f); glVertex3f( 1.0f,  1.0f,  1.0f);	
  // Top Left Of The Texture and Quad
  glTexCoord2f(0.0f, 0.0f); glVertex3f( 1.0f, -1.0f,  1.0f);	
  // Bottom Left Of The Texture and Quad
  
  // Left Face
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, -1.0f, -1.0f);	
  // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0f, 0.0f); glVertex3f(-1.0f, -1.0f,  1.0f);	 
  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f); glVertex3f(-1.0f,  1.0f,  1.0f);	
  // Top Right Of The Texture and Quad
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);	
  // Top Left Of The Texture and Quad

glEnd();								
// Done Drawing Quads
Wir sagen OpenGL das wir fertig mit unserer Liste sind mit dem Befehl glEndList() .Alles was innerhalb von glNewList() und glEndList() steht ist Teil der Display-Liste, alles was davor oder danach steht ist logischer Weise nicht Teil der Liste.
glEndList();									
// Done Building The box List
Nun machen wir unsere zweite Liste. Um heraus zu finden wo die zweite Liste im Speicher abgelegt wird nehmen wir die alte Display-Liste und addieren eins hinzu. Der folgende Code setzt 'top' auf die Position der zweiten Liste.
top=box+1;									
// top List Value Is box List Value +1
Jetzt wissen wir wo die zweite Liste gespeichert wird und erstellen sie einfach mal. Das geschiet genauso wie auch bei der ersten Display-Liste, nur teilen wir diesmal OpenGl mit die Liste an der Position 'top' und nicht 'box' zu speichern.
glNewList(top,GL_COMPILE);							
// New Compiled top Display List
Der fogende Abschnitt zeichnet den Deckel der Box. Dieser besteht einfach aus einem Quadrat auf der Z-Ebene.

glBegin(GL_QUADS);                                                      
// Start Drawing Quad

  // Top Face
  glTexCoord2f(0.0f, 1.0f); glVertex3f(-1.0f,  1.0f, -1.0f);      
  // Top Left Of The Texture and Quad
  glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f,  1.0f,  1.0f);       
  // Bottom Left Of The Texture and Quad
  glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f,  1.0f,  1.0f);      
  // Bottom Right Of The Texture and Quad
  glTexCoord2f(1.0f, 1.0f); glVertex3f( 1.0f,  1.0f, -1.0f);      
  // Top Right Of The Texture and Quad
glEnd();
// Done Drawing Quad
Wieder sagen wir OpenGL das wir fertig sind mit unserer Liste mit dem Befehl glEndList(). Das wars schon. Wir haben nun erfolgreich 2 Display-Listen erstellt.
  glEndList();                                                                    
  // Done Building The top Display List
}
Der Bitmap/Textur Code ist der selbe wie in den Tutorials zuvor. Wir brauchen eine Textur die wir auf alle 6 Seiten des Würfels packen können. Ich hab mich entschieden eine mipmapped Textur zu nehmen da das ganze dann einfach besser aussieht. Ich hasse es wenn man die einzelnen Pixel erkenne kann :-) Die Textur die wir laden werden heisst 'cube.bmp' aus dem Verzeichnis data. Gehe im Quelltext zu LoadBMP und ändere die zeile wie folgt:
  if (TextureImage[0]=LoadBMP("Data/Cube.bmp"))           
  // Load The Bitmap

Die Resizing Routine aus Lektion 6 wird nicht verändert.

Die Initialisierungsroutine erfährt ein paar kleine Veränderungen. Ich habe die Zeile BuildList() hinzu gefügt. Dadurch wird die Funktion aufgerufen die unsere Display-Listen erstellt. Wichtig ist das BuildList() erst nach LoadGLTextures() aufgerufen wird. Es ist wichtig zu wissen in welcher Reihenfolge Dinge passieren müssen. Zuerst müssen wir unsere Textur laden damit wenn unsere Listen erstellt werden die Objekte bereits mit den Texturen verknüpft werden können.

int InitGL(GLvoid)                                              
// All Setup For OpenGL Goes Here
{
  if (!LoadGLTextures())                                  
  // Jump To Texture Loading Routine
  {
    return FALSE;                                   
    // If Texture Didn't Load Return FALSE
  }
  BuildLists();                         
  // Jump To The Code That Creates Our Display Lists
  glEnable(GL_TEXTURE_2D);              // Enable Texture Mapping 
  glShadeModel(GL_SMOOTH);              // Enable Smooth Shading
  glClearColor(0.0f, 0.0f, 0.0f, 0.5f); // Black Background
  glClearDepth(1.0f);                   // Depth Buffer Setup
  glEnable(GL_DEPTH_TEST);              // Enables Depth Testing
  lDepthFunc(GL_LEQUAL);                // The Type Of Depth Testing To Do
Die nächsten Zeilen ermöglichen einfach und schnell Lichteffekte einzubinden. Light0 ist meistens auf den Grafikkarten schon vordefiniert, dies erspart uns den Ärger selbst ein Licht zu erstellen. Danach aktivieren wir Light0 natürlich noch. Wenn die Sache mit Light0 auf eurer Videokarte nicht funktionieren sollte (der Bildschirm bleibt Schwarz) deaktiviere das Licht einfach wieder.

Die letze zeile GL_COLOR_MATERIAL ermöglicht es uns Licht auf Texturen zu sehen. Wenn wir diese Funktion nicht aktivieren behalten die Texturen ihre ursprüngliche Farbe und glColor3f(r,g,b) wird auf sie keine Effekt haben. Es ist also wichtig diese Funktion zu aktivieren.
  glEnable(GL_LIGHT0);
  // Quick And Dirty Lighting (Assumes Light0 Is Set Up)
  glEnable(GL_LIGHTING);                                  
  // Enable Lighting
  glEnable(GL_COLOR_MATERIAL);                            
  // Enable Material Coloring
Letztendlich lassen wir die Perspektive noch "schön" aussehen und leifern ein TRUE zurück damit unser Programm weiss das alles gut gegangen ist.

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Nice Perspective Correction return TRUE; // Initialization Went OK

Nun zum Zeichnen. Wie üblich werde ich ein bisschen Mathe abfordern. Keine Sinus- oder Cosinusfunktionen aber schon nicht ganz einfach :-) Erstmal löschen wir den Bildschirm- und den Tiefenspeicher.

Dann verknüpfen wir den Würfel mit einer Textur. Ich hätte dies auch in der Diplay-Liste direkt machen können, aber so kann ich die Textur nach belieben wechseln. Wenn ich die Zeile glBindTexture(GL_TEXTURE_2D, texture[0]) in die Liste geschrieben hätte, würde die der Würfel mit dieser Textur erstellt werden und sie auch permanent behalten.

  int DrawGLScene(GLvoid)                                         
  // Here's Where We Do All The Drawing
  {
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);     
    // Clear The Screen And The Depth Buffer

    glBindTexture(GL_TEXTURE_2D, texture[0]);               
    // Select The Texture
Nun zum schönen Teil. Wir haben eine Schleife, genannt yloop. Sie wird benutzt um die Würfel auf der Y-Achse von oben nach unten anzuordnen. Wir wollen 5 Reihen von oben nach unten erstellen also nehmen wir unsere Schleife von 1 bis 6 (was 5 Durchläufe ergibt).
  for (yloop=1;yloop<6;yloop++)                           
  // Loop Through The Y Plane
  {
Wir haben auch eine andere Schleife namens xloop. Sie wird dazu benutzt die Würfel auf der X-Achse auszurichten. Die Anzahl der Würfel von links nach rechts ist abhängig davon, in welcher Reihe wir uns befinden. Wenn wir uns in der obersten Reihe befinden läuft die Schleife nur von 0 bis 1 ( ein Würfel wird gezeichnet). Die nächte Reihe läuft von 0 bis 2 ( zwei Würfel werden gezeichnet), usw.
    for (xloop=0;xloop
    // Loop Through The X Plane
    {
Wir setzen unseren Sichtweise wieder zurück.
      glLoadIdentity();                       
      // Reset The View

Die nächste Zeile bewegt uns zu einem bestimmten Punkt auf dem Bildschirm. Es sieht verwirrend aus, aber so schlimm ist es gar nicht. Auf der X-Achse passiert folgendes:

Wir bewegen uns um 1,4 Einheiten so das die Pyramide in der Mitte des Bildschirms steht. Dann multiplizieren wir xloop mit 2,8 und addieren 1,4 dazu. (wir multiplizieren mit 2,8 damit die Würfel nicht direkt aufeinander stehen (2,8 ist die ungefähre Breite eines Würfels der um 45° gedreht wurde)). Zum Schluss subtrahieren wir yloop*1,4. Dies bewegt die Würfel nach links in abhängigkeit der zeile in der wir uns befinden. Wenn wir uns nicht nach links bewegen würden, würde die Pyramide nicht wirklich wie eine Pyramide aussehen.

Auf der Y-Achse subtrahieren wir yloop von 6 ansonsten würde die Pyramide verkehrt herum aufgebaut werden. Danach multiplizieren wir das ergebnis mit 2,4. Sonst wären die Würfel wieder direkt aufeinander, diesmal auf der Y-Achse (2,4 entspricht ungefähr der Höhe des Würfels). Dann ziehen wir 7 ab so dass die Pyramide unten am Bildschirm anfängt und sich nach oben aufbaut.

Letztendlich bewegen wir die Pyramide noch 20 Einheiten auf der Z-Achse nach hinten. Auf diese Art passt die Pyramide wunderbar auf den Bilschrim.

      // Position The Cubes On The 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 um die X-Achse. Wir drehen den Würfel um 45° minus 2mal yloop. Der Perspektiven-Modus dreht den Würfel für uns schon automtisch, also rechne ich minus um dies wieder zu kompensieren. Es ist nicht die beste möglichkeit dies zu tun, aber es funktioniert :-)

Zum Schluss addieren wir xrot dazu. Dies gibt uns die Tastaturkontrolle über die Drehung. (es macht Spass damit zu spielen).

Nachdem wir uns auf der X-Achse gedreht haben, rotieren wir nun auf der Y-Achse um 45° und addieren yrot um die Tastaturkontrolle zu bekommen.

      glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f);      
      // Tilt The Cubes Up And Down

      glRotatef(45.0f+yrot,0.0f,1.0f,0.0f);                   
      // Spin Cubes Left And Right

Da die Farbe bereits gesetzt ist, ist alles was wir noch tun müssen den Würfel zu zeichnen. Anstatt den ganzen Code aufzuschreiben der nötig wäre um einen Würfel zu zeichnen rufen wir einfach unsere Display-Liste auf. Dies geschiet durch den Befehl glCallList(box). box teilt OpenGL mit das es sich um die Display-Liste box handelt. Diese Liste enthält den Würfel ohne Deckel.

Die Box wird in der Farbe gezeichnet die wir mit glColor3fv() ausgewählt haben und an der Position an die wir sie verschoben haben.

      glRotatef(45.0f-(2.0f*yloop)+xrot,1.0f,0.0f,0.0f);      
      // Tilt The Cubes Up And Down

      glRotatef(45.0f+yrot,0.0f,1.0f,0.0f);                   
      // Spin Cubes Left And Right
Nun suchen wir eine dunklere Farbe für den Deckel der Box. Wenn du wirklich einen Q-Bert machen wollen würdest bräuchtest du nur jedesmal die Farbe zu ändern wenn Q-Bert auf die Box springt. Die Farbe ist abhängig von der Reihe (yloop-1).
      glColor3fv(topcol[yloop-1]);            
      // Select The Top Color
Das einzigste was jetzt noch übriggeblieben ist, ist die top Liste aufzurufen. Das wird einen dunkleren Deckel auf die Box setzen. So einfach.

      glCallList(top);                        
      // Draw The Top
      }
    }
    return TRUE;                                            
    // Jump Back
  }
Die restlichen Veränderungen sind alle in der Funktion WinMain(). Der Code wird direkt nach SwapBuffers(hDC) eingefügt. Er überprüft ob entweder links, rechts, oben oder unten gedrückt wurde und bewegt die Würfel entsprechend.
      SwapBuffers(hDC);                               
      // Swap Buffers (Double Buffering)
      if (keys[VK_LEFT])                              
      // Left Arrow Being Pressed?
      {
        yrot-=0.2f;                             
        // If So Spin Cubes Left
      }
      if (keys[VK_RIGHT])                             
      // Right Arrow Being Pressed?
      {
        yrot+=0.2f;                             
        // If So Spin Cubes Right
      }
      if (keys[VK_UP])                                
      // Up Arrow Being Pressed?
      {
        xrot-=0.2f;                             
        // If So Tilt Cubes Up
      }
      if (keys[VK_DOWN])                              
      // Down Arrow Being Pressed?
      {
        xrot+=0.2f;                             
        // If So Tilt Cubes Down
      }
Wie in allen Tutorials wird auch noch der Name des Fensters angepasst.
      if (keys[VK_F1])                                
      // Is F1 Being Pressed?
      {
        keys[VK_F1]=FALSE;  // If So Make Key FALSE
        KillGLWindow();     // Kill Our Current Window
        fullscreen=!fullscreen;                 
        // Toggle Fullscreen / Windowed Mode
        // Recreate Our OpenGL Window
        if (!CreateGLWindow("NeHe's Display List Tutorial",
                             640,480,16,fullscreen))
        {
          return 0;  // Quit If Window Was Not Created
        }
      }
    }
  }

Nach diesem Tutorial solltet ihr ein gutes Verständnis haben wie Display-Listen funktionieren, wie sie erstellt und schliesslich auch benutzt werden. Display-Listen sind grossartig. Sie vereinfachen nicht nur den Code in komplexen Projekten sondern geben zusätzlich auch noch ein wenig Geschwindigkeit die benötigt wird um hohe Frameraten zu erreichen.

Ich hoffe euch hat dieses Tutorial Spass gemacht. Wenn ihr noch irgendwelche Fragen habt oder euch einfach einige Sachen noch nicht ganz klar sind mailed mir.

Die Source Codes und Ausführbaren Dateien zu den Kursen liegen auf der Neon Helium Website

Übersetzung von Delax & ChaosAngel/ Sundancer Inc.

(Präsentiert von www.codeworx.org)