Display Lists

Back to index

The idea is that if you need to draw fixed stuff that involves a lot of calculation, you speed things up by 'drawing' it into a display list, just once, in init, say. Then in display you just draw the display list, rather than repeating the calculations

A nice torus

We follow the red book - but their torus has no normals, so we can't use lighting. Here is an alternative. It is wildly inefficient, calculating most points at least twice - but we want something with lots of calculations, so we leave it as it is:

   /**
     * Draw a torus.
     * The torus has its 'axis' pointing at 0.0.-1, and its venctre
     * is at 0,0,0
     * 
     * @param gl The GL thing to draw it in
     * @param numRound The number of divisions round the hole
     * @param numCircle The number of divisions around the tube
     * @param radius    The radius of the main circle
     * @param thickness The radius of the tube
     */
private void torus(GL gl, int numRound, int numCircle, float radius, float thickness)
{
    double twoPi = Math.PI*2;
    double dTheta = twoPi/numRound;
    double dPhi = twoPi/numCircle;
    double x0, y0, x,y,z, x1, y1, z1, x2, y2, z2, x3,y3,z3, xn, yn;   
   for (float theta=0; theta<twoPi; theta+=dTheta)
   {
      x0=radius*Math.sin(theta);
      y0=radius*Math.cos(theta);
      xn=radius*Math.sin(theta+dTheta);
      yn=radius*Math.cos(theta+dTheta);
      // we need a circle around x0, yo
      for (float phi=0; phi<twoPi; phi+=dPhi)
      {
          z=thickness*Math.sin(phi);
          x=x0+thickness*Math.cos(phi)*Math.sin(theta);
          y=y0+thickness*Math.cos(phi)*Math.cos(theta);

          z1=thickness*Math.sin(phi+dPhi);
          x1=x0+thickness*Math.cos(phi+dPhi)*Math.sin(theta);
          y1=y0+thickness*Math.cos(phi+dPhi)*Math.cos(theta);
          
          z2=thickness*Math.sin(phi);
          x2=xn+thickness*Math.cos(phi)*Math.sin(theta+dTheta);
          y2=yn+thickness*Math.cos(phi)*Math.cos(theta+dTheta);
   
          z3=thickness*Math.sin(phi+dPhi);
          x3=xn+thickness*Math.cos(phi+dPhi)*Math.sin(theta+dTheta);
          y3=yn+thickness*Math.cos(phi+dPhi)*Math.cos(theta+dTheta);
         
          
          gl.glBegin(GL.GL_QUADS);
          gl.glNormal3fv( WMVector.normal(x1,y1,z1,x,y,z,x2,y2,z2), 0);
          gl.glVertex3d(x, y, z);
          gl.glNormal3fv( WMVector.normal(x,y,z,x2,y2,z2,x3,y3,z3), 0);
          gl.glVertex3d(x2, y2, z2);
          gl.glNormal3fv( WMVector.normal(x2,y2,z2,x3,y3,z3,x1,y1,z1), 0);
          gl.glVertex3d(x3, y3, z3);
          gl.glNormal3fv( WMVector.normal(x3,y3,z3,x1,y1,z1,x,y,z), 0);
          gl.glVertex3d(x1, y1, z1);
          gl.glEnd();
      }     
   }
}

This produces: 1

We find the normals using this addition to WMVector:

public static float[] normal(double x0, double y0, double z0, double x1, double y1, double z1, double x2, double y2, double z2)
    {
    WMVector v0 = new WMVector(x0, y0, z0);
    WMVector v1 = new WMVector(x1, y1, z1);
    WMVector v2 = new WMVector(x2, y2, z2);
    
    WMVector v3 = v0.sub(v1);
    WMVector v4 = v2.sub(v1);
    WMVector result=v3.cross(v4);
    result=result.normalise();
    return( new float[] { result.x, result.y, result.z} );
    } 

We want to draw a lot of these, so we actually draw a torus with a random displacement:

private void randomTorus(GL gl, int numRound, int numCircle, float radius, float thickness)
    {  
        double a = Math.random()*20-10;
        double b = Math.random()*20-10;
        double c = Math.random()*20-10;
        gl.glTranslated(a,b,c);
        torus(gl, numRound, numCircle, radius, thickness);    
    }

In init, we write this 10 times into a display list:>

..
theTorus = gl.glGenLists (1);
gl.glNewList(theTorus, GL.GL_COMPILE);
for (int i=0; i<10; i++)
   randomTorus(gl,25,40, 3,1f);
gl.glEndList();

theTorus is just a global int. Then in display we call this display list:

  gl.glCallList(theTorus);

and this gives 2

The point of this is how fast it is. We can work out the frames per second like this, at the start of display:

// frame timing
        if (frameCount==0)
            start=System.currentTimeMillis();
        frameCount++;
        if (frameCount==100)
        {
            long elapsed = System.currentTimeMillis()-start;
            System.out.println("fps = "+1e5/elapsed);
            frameCount=0;
            start=System.currentTimeMillis();
        }

frameCount is a global long. This shows around 100fps. If we actually re-calculate and draw them every time:

       for (int i=0; i<10; i++)
            randomTorus(gl,25,40, 3,1f);

Then they jump all over the screen, since they go into random positions every time. It also brings down the fps to around 15