OpenGL provides an efficient mechanism to execute several display lists in succession. This mechanism requires that you put the display-list indices in an array and call glCallLists(). An obvious use for such a mechanism occurs when display-list indices correspond to meaningful values. For example, if you're creating a font, each display-list index might correspond to the ASCII value of a character in that font. To have several such fonts, you would need to establish a different initial display-list index for each font. You can specify this initial index by using glListBase() before calling glCallLists(). void glListBase(GLuint base);
Specifies the offset that's added to the display-list indices in glCallLists() to obtain the final display-list indices. The default display-list base is 0. The list base has no effect on glCallList(), which executes only one display list, or on glNewList().
void glCallLists(GLsizei n, GLenum type, const GLvoid *lists);
Executes n display lists. The indices of the lists to be executed are computed by adding the offset indicated by the current display-list base (specified with glListBase()) to the signed integer values in the array pointed to by lists.
The type parameter indicates the data type and the "stride" (or size) of each element in the array of indices. It's usually one of these constants: GL_BYTE, GL_UNSIGNED_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT, or GL_FLOAT. It can also be GL_2_BYTES, GL_3_BYTES, or GL_4_BYTES, in which case sequences of two, three, or four bytes are shifted and added together, byte by byte, to calculate the display-list offset, using this algorithm:
/* b = 2, 3, or 4; bytes are numbered 0, 1, 2, 3 in array */
offset = 0;
for (i = 0; i < b; i++) {
offset = offset << 8;
offset += byte[i];
}
index = offset + listbase;
This means that for multiple-byte data, as bytes are taken from the array in order, the highest-order data comes first.
As an example of the use of multiple display lists, look at the program fragments in Example 4-7 taken from the full program in Example 4-8 . This program draws characters with a stroked font (a set of letters made from line segments). The routine initStrokedFont() sets up the display-list indices for each letter so they correspond with their ASCII values.
Example 4-7 : Defining Multiple Display Lists
void initStrokedFont(void)
{
GLuint base;
base = glGenLists (128);
glListBase(base);
glNewList(base+'A', GL_COMPILE);
drawLetter(Adata); glEndList();
glNewList(base+'E', GL_COMPILE);
drawLetter(Edata); glEndList();
glNewList(base+'P', GL_COMPILE);
drawLetter(Pdata); glEndList();
glNewList(base+'R', GL_COMPILE);
drawLetter(Rdata); glEndList();
glNewList(base+'S', GL_COMPILE);
drawLetter(Sdata); glEndList();
glNewList(base+' ', GL_COMPILE); /* space character */
glTranslatef(8.0, 0.0, 0.0); glEndList();
}
The glGenLists() command allocates 128 contiguous display-list indices. The first of the contiguous indices becomes the display-list base. A display list is made for each letter; each display-list index is the sum of the base and the ASCII value of that letter. In this example, only a few letters and the space character are created.
After the display lists have been created, glCallLists() can be called to execute the display lists. For example, you can pass a character string to the subroutine printStrokedString():
void printStrokedString(GLbyte *s)
{
GLint len = strlen(s);
glCallLists(len, GL_BYTE, s);
}
The ASCII value for each letter in the string is used as the offset into the display-list indices. The current list base is added to the ASCII value of each letter to determine the final display-list index to be executed. The output produced by Example 4-8 is shown in Figure 4-1 .
![[IMAGE]](figures/stroke.gif)
Figure 4-1 : Example of a Stroked Font That Defines the Characters A, E, P, R, S
Example 4-8 : Using Multiple Display Lists to Define a Stroked Font: stroke.c
#include <GL/gl.h>
#include <GL/glu.h>
#include "aux.h"
#define PT 1
#define STROKE 2
#define END 3
typedef struct charpoint {
GLfloat x, y;
int type;
} CP;
CP Adata[] = {
{ 0, 0, PT}, {0, 9, PT}, {1, 10, PT}, {4, 10, PT},
{5, 9, PT}, {5, 0, STROKE}, {0, 5, PT}, {5, 5, END}
};
CP Edata[] = {
{5, 0, PT}, {0, 0, PT}, {0, 10, PT}, {5, 10, STROKE},
{0, 5, PT}, {4, 5, END}
};
CP Pdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, END}
};
CP Rdata[] = {
{0, 0, PT}, {0, 10, PT}, {4, 10, PT}, {5, 9, PT},
{5, 6, PT}, {4, 5, PT}, {0, 5, STROKE}, {3, 5, PT},
{5, 0, END}
};
CP Sdata[] = {
{0, 1, PT}, {1, 0, PT}, {4, 0, PT}, {5, 1, PT}, {5, 4, PT},
{4, 5, PT}, {1, 5, PT}, {0, 6, PT}, {0, 9, PT}, {1, 10, PT},
{4, 10, PT}, {5, 9, END}
};
void drawLetter(CP *l)
{
glBegin(GL_LINE_STRIP);
while (1) {
switch (l->type) {
case PT:
glVertex2fv(&l->x);
break;
case STROKE:
glVertex2fv(&l->x);
glEnd();
glBegin(GL_LINE_STRIP);
break;
case END:
glVertex2fv(&l->x);
glEnd();
glTranslatef(8.0, 0.0, 0.0);
return;
}
l++;
}
}
void myinit (void)
{
GLuint base;
glShadeModel (GL_FLAT);
base = glGenLists (128);
glListBase(base);
glNewList(base+'A', GL_COMPILE); drawLetter(Adata);
glEndList();
glNewList(base+'E', GL_COMPILE); drawLetter(Edata);
glEndList();
glNewList(base+'P', GL_COMPILE); drawLetter(Pdata);
glEndList();
glNewList(base+'R', GL_COMPILE); drawLetter(Rdata);
glEndList();
glNewList(base+'S', GL_COMPILE); drawLetter(Sdata);
glEndList();
glNewList(base+' `, GL_COMPILE);
glTranslatef(8.0, 0.0, 0.0); glEndList();
}
char *test1 = "A SPARE SERAPE APPEARS AS";
char *test2 = "APES PREPARE RARE PEPPERS";
void printStrokedString(char *s)
{
GLsizei len = strlen(s);
glCallLists(len, GL_BYTE, (GLbyte *)s);
}
void display(void)
{
glClear(GL_COLOR_BUFFER_BIT);
glColor3f(1.0, 1.0, 1.0);
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 30.0, 0.0);
printStrokedString(test1);
glPopMatrix();
glPushMatrix();
glScalef(2.0, 2.0, 2.0);
glTranslatef(10.0, 13.0, 0.0);
printStrokedString(test2);
glPopMatrix();
glFlush();
}
int main(int argc, char** argv)
{
auxInitDisplayMode (AUX_SINGLE | AUX_RGBA);
auxInitPosition (0, 0, 440, 120);
auxInitWindow (argv[0]);
myinit ();
auxMainLoop(display);
}
OpenGL Programming Guide