OpenGL:Tutorials:Tutorial Framework:Display Lists

From GPWiki
Jump to: navigation, search

Warning, Deprecated!

The OpenGL programming technics presented on this webpage are deprecated in the last versions of OpenGL.

What is a display list?

Display lists are a way of bundling OpenGL commands for future execution. They can give a performance boost when construction of our objects involves calculation or other slow downs. Once our object data is in the display list, it can be recalled easily and without the calculation that was required to produce it. The other nice aspect of display lists is that they fit in with OpenGL's state system, we can change the texture, color, size or any aspect of the object that isn't explicitly defined in the list.

Using Display Lists

We use the glGenLists() function to allocate storage for display lists:

   DListRoot=glGenLists(3);

This is similar to generating texture storage except that the lists originate from the returned base point rather than the array used for textures. To access display list n we simply call:

   glCallList(DListRoot+n);

To clean up or delete the lists we use:

   glDeleteLists(DListRoot,3);


An Example

In our example we are going to create display lists for three objects. These objects will then be displayed with different textures and scale factors to demonstrate the adjustments that are possible due to GL's state system.


Our objects are managed by a a similar setup to the particle demo; a structure contains the unique parameters for each object:

   typedef struct
    {
     float xPos,yPos,zPos,Rotate;
     int TexNum,ObjList;
     float Red,Green,Blue;
     float Scale,rVec;
    }ObjInfo;

These parameters are initalised to random values:

   for(index=0;index<NUM_OBJ;++index)
    {
     Obj[index].xPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].yPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].zPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].Scale=(rand()%11)/10.0f;
     Obj[index].Rotate=(float)(rand()%180);
     Obj[index].rVec=(float)((rand()%100)/200.0f)-0.25f;
     Obj[index].TexNum=rand()%2;
     Obj[index].ObjList=rand()%3;
    }

An important note here is that scaling our object will scale all our geometery, including normals. This will change the lighting of the polygons. To stop this we use:

   glEnable(GL_NORMALIZE);

Which prevents scaling from changing our normal lengths.


So, on to the lists. First, we allocate 3 lists as discussed:

   DListRoot=glGenLists(3);

The actual compilation of the lists can occur anywhere, but here we'll separate it into three functions, BuildCube(),BuildDiamond() and BuildStar(). These functions build some simple objects.

Looking at the functions, we can see that most of the code is pretty standard OpenGL, we are specifing UV and vertex coords in the usual way. The only difference is that the call to glNewList() means that we are storing the instructions rather than rendering the polygons.

   glNewList(ListID,GL_COMPILE);
 
    // OpenGL code here
 
   glEndList();

The GL_COMPILE flag tells OpenGL to store the instructions with no output, if we use GL_COMPILE_AND_EXECUTE the instructions will be stored and displayed. This can be useful for scenes where the geometery is rendered more than once per frame, e.g. when producing reflections.


To execute a display list we use the glCallList() function. As previously mentioned, any current states that are not explicitly set in the list will be used when rendering the objects in the list.

Because our lists only specify UV coords, not textures, we are able to change the appearance of the objects easily.

Our demo looks like this:

GLTut7 (DispList).jpg


Other things to try with display lists are:

  • Changing object colors,
  • Nesting display lists,
  • Calling multiple lists with glCallLists().


Source Code

The source to Render.cpp, compile this demo using the OpenGL Tutorial Framework.

#include "Framework.h"
#include <ctime>
#include <cmath>
#include "tga.h"
 
const int NUM_OBJ=2000; // Number of Objects
 
// Vector structure
typedef struct
 {
  float x,y,z;
 }stVec;
 
// Object Structure
typedef struct
 {
  float xPos,yPos,zPos,Rotate;
  int TexNum,ObjList;
  float Red,Green,Blue;
  float Scale,rVec;
 }ObjInfo;
 
// Function declarations
bool LoadTexture(char *TexName, GLuint TexHandle);
 
stVec CalcNormal(float x1, float y1, float z1,
                 float x2, float y2, float z2,
                 float x3, float y3, float z3);
 
void BuildCube(GLuint ListID);
void BuildDiamond(GLuint ListID);
void BuildStar(GLuint ListID);
 
void Render(void)
 {
  GLuint Texture[128];  // Handles to our textures
  ObjInfo Obj[NUM_OBJ]; // Object array
  GLuint DListRoot;     // Display List
  float Rot=0.0f;       // Rotation value for the observer
  int index;   
  float view_height=600.0f/800.0f;
 
  // Allocate all textures in one go
  glGenTextures(128,Texture);
 
  // Setup our screen
  glViewport(0,0,800,600);
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  glFrustum(-0.5f,0.5f,-0.5f* view_height,0.5f*view_height, 1.0f, 500.0f);
  glMatrixMode(GL_MODELVIEW);
  glClearColor(0.0f,0.0f,0.0f,1.0f);
 
  // Enable z-buffer
  glEnable(GL_DEPTH_TEST);
  glDepthMask(GL_TRUE);
  glEnable(GL_CULL_FACE);
 
  // Prevent scaling operations from affecting normal values
  glEnable(GL_NORMALIZE);
 
  // Load the textures
  LoadTexture("../Images/Logo.tga",Texture[0]);
  LoadTexture("../Images/lightbricks.tga",Texture[1]);
 
  // Allocate 3 display lists
  DListRoot=glGenLists(3);
 
  // Build the display lists
  BuildCube(DListRoot);
  BuildDiamond(DListRoot+1);
  BuildStar(DListRoot+2);
 
  // Seed the randomiser
  srand(time(NULL));
 
  // Init the object parameters
   for(index=0;index<NUM_OBJ;++index)
    {
     Obj[index].xPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].yPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].zPos=((rand()%200)/5.0f)-20.0f;
     Obj[index].Scale=(rand()%11)/10.0f;
     Obj[index].Rotate=(float)(rand()%180);
     Obj[index].rVec=(float)((rand()%100)/200.0f)-0.25f;
     Obj[index].TexNum=rand()%2;
     Obj[index].ObjList=rand()%3;
    }
 
  // Set the general scene properties
  glColor4f(1.0f,1.0f,1.0f,1.0f);
  glEnable(GL_TEXTURE_2D);
  glEnable(GL_LIGHTING);
  glEnable(GL_LIGHT0);
 
 
  // Main loop
   while(RunLevel)
    {
      if(Keys[VK_ESCAPE])
       RunLevel=0;
 
      // Update the objects
      for(index=0;index<NUM_OBJ;++index)
       {
        Obj[index].Rotate+=Obj[index].rVec;
       }
 
     // Start the scene
     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
     glLoadIdentity(); 
 
     // Rotate the view
     glRotatef(Rot,0.0f,1.0f,0.0f);
     glRotatef(Rot,1.0f,0.0f,0.0f);
 
     // Draw the objects
      for(index=0;index<NUM_OBJ;++index)
       {
        glBindTexture(GL_TEXTURE_2D,Texture[Obj[index].TexNum]);
 
        glPushMatrix();
 
         glTranslatef(Obj[index].xPos,Obj[index].yPos,Obj[index].zPos);
         glRotatef(Obj[index].Rotate,0.0f,0.2f,1.0f);
         glRotatef(Obj[index].Rotate,1.0f,0.0f,0.0f);
         glScalef(Obj[index].Scale,Obj[index].Scale,Obj[index].Scale);
 
         glCallList(DListRoot+Obj[index].ObjList); // Call the display list
 
        glPopMatrix();
      }
 
     // Update the rotation value
     Rot+=0.01f;
 
     // Show our scene
     FlipBuffers();
    }
 
  // Clean up
  glDeleteTextures(128,Texture);
  glDeleteLists(DListRoot,3);
 }
 
 
// Load a TGA texture
bool LoadTexture(char *TexName, GLuint TexHandle)
 {
  TGAImg Img;        // Image loader
 
  // Load our Texture
   if(Img.Load(TexName)!=IMG_OK)
    return false;
 
  glBindTexture(GL_TEXTURE_2D,TexHandle); // Set our Tex handle as current
 
  // Create the texture
   if(Img.GetBPP()==24)
    glTexImage2D(GL_TEXTURE_2D,0,3,Img.GetWidth(),Img.GetHeight(),0,
                 GL_RGB,GL_UNSIGNED_BYTE,Img.GetImg());
   else if(Img.GetBPP()==32)
    glTexImage2D(GL_TEXTURE_2D,0,4,Img.GetWidth(),Img.GetHeight(),0,
                 GL_RGBA,GL_UNSIGNED_BYTE,Img.GetImg());
   else
    return false;
 
  // Specify filtering and edge actions
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
 
  return true;
 }
 
void BuildCube(GLuint ListID)
 {
  glNewList(ListID,GL_COMPILE);
 
   glBegin(GL_QUADS);
    glNormal3f(0.0f,1.0f,0.0f);
    glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 1.0f,-1.0f);
    glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 1.0f,-1.0f);
 
    // Draw bottom face
    glNormal3f(0.0f,-1.0f,0.0f);
    glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 1.0f);
 
    // Side faces
    glNormal3f(0.0f,0.0f,1.0f);
    glTexCoord2f(1.0f,0.0f);  glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(0.0f,0.0f);  glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.0f,1.0f);  glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(1.0f,1.0f);  glVertex3f( 1.0f, 1.0f, 1.0f);
 
    glNormal3f(1.0f,0.0f,0.0f);
    glTexCoord2f(0.0f,1.0f);  glVertex3f( 1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.0f,1.0f);  glVertex3f( 1.0f,-1.0f, 1.0f);
    glTexCoord2f(1.0f,2.0f);  glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.0f,2.0f);  glVertex3f( 1.0f, 1.0f,-1.0f);
 
    glNormal3f(0.0f,0.0f,-1.0f);
    glTexCoord2f(0.0f,2.0f);  glVertex3f( 1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.0f,3.0f);  glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(1.0f,3.0f);  glVertex3f(-1.0f, 1.0f,-1.0f);
    glTexCoord2f(1.0f,2.0f);  glVertex3f( 1.0f, 1.0f,-1.0f);
 
    glNormal3f(-1.0f,0.0f,0.0f);    
    glTexCoord2f(1.0f,3.0f);  glVertex3f(-1.0f,-1.0f,-1.0f);
    glTexCoord2f(0.0f,3.0f);  glVertex3f(-1.0f,-1.0f, 1.0f);
    glTexCoord2f(0.0f,4.0f);  glVertex3f(-1.0f, 1.0f, 1.0f);
    glTexCoord2f(1.0f,4.0f);  glVertex3f(-1.0f, 1.0f,-1.0f);
   glEnd();
 
  glEndList();
 }
 
void BuildDiamond(GLuint ListID)
 {
  glNewList(ListID,GL_COMPILE);
  stVec Norm;
 
   glBegin(GL_TRIANGLES);
    Norm=CalcNormal(-1.0f,0.0f,1.0f,0.0f, -1.0f, 0.0f,1.0f, 0.0f, 1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f);
 
    Norm=CalcNormal(-1.0f, 0.0f,-1.0f,0.0f,-1.0f,0.0f,-1.0f,0.0f,1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f);
 
    Norm=CalcNormal( 1.0f,0.0f,-1.0f,0.0f,-1.0f,0.0f,-1.0f, 0.0f,-1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f);
 
    Norm=CalcNormal(1.0f, 0.0f, 1.0f,0.0f,-1.0f,0.0f, 1.0f,0.0f,-1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f);
 
 
    Norm=CalcNormal( 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,-1.0f, 0.0f, 1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z); 
    glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f);
 
    Norm=CalcNormal( 1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.0f,0.0f); glVertex3f( 1.0f, 0.0f, 1.0f);
 
    Norm=CalcNormal(-1.0f, 0.0f,-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,-1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.0f,1.0f); glVertex3f( 1.0f, 0.0f,-1.0f);
 
    Norm=CalcNormal(-1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, -1.0f, 0.0f,-1.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.0f); glVertex3f(-1.0f, 0.0f, 1.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(1.0f,1.0f); glVertex3f(-1.0f, 0.0f,-1.0f);
 
   glEnd();
 
  glEndList();
 
 }
 
void BuildStar(GLuint ListID)
 {
  glNewList(ListID,GL_COMPILE);
  stVec Norm;
 
   glBegin(GL_TRIANGLES);
    Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.3f, 0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
    glTexCoord2f(0.75f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f);
 
    Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.3f, 0.3f, 0.0f, 0.0f, 0.0f, 0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.75f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
 
    Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f, 0.3f,-0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
    glTexCoord2f(0.75f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f);
 
    Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.75f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
 
    Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.0f, 0.0f, 0.4f,-0.3f,-0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
    glTexCoord2f(0.25f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f);
 
    Norm=CalcNormal(-1.0f, 0.0f, 0.0f,-0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.25f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
 
    Norm=CalcNormal(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.4f,-0.3f, 0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
    glTexCoord2f(0.25f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f);
 
    Norm=CalcNormal(0.0f, 1.0f, 0.0f,-0.3f, 0.3f, 0.0f, 0.0f, 0.0f, 0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.25f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f, 0.4f);
 
 
    Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.3f, 0.3f, 0.0f, 0.0f, 0.0f,-0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.25f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
 
    Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-0.4f, 0.3f, 0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
    glTexCoord2f(0.25f,0.25f); glVertex3f( 0.3f, 0.3f, 0.0f);
 
    Norm=CalcNormal(1.0f, 0.0f, 0.0f, 0.3f,-0.3f, 0.0f, 0.0f, 0.0f,-0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.0f,0.5f); glVertex3f( 1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.25f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
 
    Norm=CalcNormal(0.0f,-1.0f, 0.0f, 0.0f, 0.0f,-0.4f, 0.3f,-0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
    glTexCoord2f(0.25f,0.75f); glVertex3f( 0.3f,-0.3f, 0.0f);
 
    Norm=CalcNormal(0.0f,-1.0f, 0.0f,-0.3f,-0.3f, 0.0f, 0.0f, 0.0f, 0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,1.0f); glVertex3f( 0.0f,-1.0f, 0.0f);
    glTexCoord2f(0.75f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
 
    Norm=CalcNormal(-1.0f, 0.0f, 0.0f, 0.0f, 0.0f,-0.4f,-0.3f,-0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
    glTexCoord2f(0.75f,0.75f); glVertex3f(-0.3f,-0.3f, 0.0f);
 
    Norm=CalcNormal(-1.0f, 0.0f, 0.0f,-0.3f, 0.3f, 0.0f, 0.0f, 0.0f,-0.4f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(1.0f,0.5f); glVertex3f(-1.0f, 0.0f, 0.0f);
    glTexCoord2f(0.75f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
 
    Norm=CalcNormal(0.0f, 1.0f, 0.0f, 0.0f, 0.0f,-0.4f,-0.3f, 0.3f, 0.0f);
    glNormal3f(Norm.x,Norm.y,Norm.z);
    glTexCoord2f(0.5f,0.0f); glVertex3f( 0.0f, 1.0f, 0.0f);
    glTexCoord2f(0.5f,0.5f); glVertex3f( 0.0f, 0.0f,-0.4f);
    glTexCoord2f(0.75f,0.25f); glVertex3f(-0.3f, 0.3f, 0.0f);
   glEnd();
 
  glEndList();
 
 }
 
// Calculate normal from vertices
stVec CalcNormal(float x1, float y1, float z1,
                 float x2, float y2, float z2,
                 float x3, float y3, float z3)
 {
  double v1x,v1y,v1z,v2x,v2y,v2z;
  double nx,ny,nz;
  double vLen;
 
  stVec Result;
 
  // Calculate vectors
  v1x = x1 - x2;
  v1y = y1 - y2;
  v1z = z1 - z2;
 
  v2x = x2 - x3;
  v2y = y2 - y3;
  v2z = z2 - z3;
 
  // Get cross product of vectors
  nx = (v1y * v2z) - (v1z * v2y);
  ny = (v1z * v2x) - (v1x * v2z);
  nz = (v1x * v2y) - (v1y * v2x);
 
  // Normalise final vector
  vLen = sqrt( (nx * nx) + (ny * ny) + (nz * nz) );
 
  Result.x = (float)(nx / vLen);
  Result.y = (float)(ny / vLen);
  Result.z = (float)(nz / vLen);
 
  return Result;
 }

Downloads

GLTut7_(Display_Lists).zip - Zip containing Win32 and GLFW source code, texture images and a Win32 Binary.