132001f49Smrg/*
232001f49Smrg * Compressed texture demo.  Written by Daniel Borca.
332001f49Smrg * This program is in the public domain.
432001f49Smrg */
532001f49Smrg
632001f49Smrg#include <stdio.h>
732001f49Smrg#include <stdlib.h>
832001f49Smrg#include <math.h>
932001f49Smrg#include <string.h>
1032001f49Smrg#include <GL/glew.h>
1132001f49Smrg#include "glut_wrap.h"
1232001f49Smrg
1332001f49Smrg#include "readtex.c" /* I know, this is a hack. */
1432001f49Smrg#define TEXTURE_FILE DEMOS_DATA_DIR "tree2.rgba"
1532001f49Smrg
1632001f49Smrg
1732001f49Smrgstatic float Rot = 0.0;
1832001f49Smrgstatic GLboolean Anim = 1;
1932001f49Smrg
2032001f49Smrgtypedef struct {
2132001f49Smrg        GLubyte *data;
2232001f49Smrg        GLuint size;
2332001f49Smrg        GLenum format;
2432001f49Smrg        GLuint w, h;
2532001f49Smrg
2632001f49Smrg        GLenum TC;
2732001f49Smrg
2832001f49Smrg        GLubyte *cData;
2932001f49Smrg        GLuint cSize;
3032001f49Smrg        GLenum cFormat;
3132001f49Smrg} TEXTURE;
3232001f49Smrg
3332001f49Smrgstatic TEXTURE *Tx, t1, t2, t3;
3432001f49Smrgstatic GLboolean fxt1, dxtc, s3tc;
3532001f49Smrg
3632001f49Smrg
3732001f49Smrgstatic const char *TextureName (GLenum TC)
3832001f49Smrg{
3932001f49Smrg switch (TC) {
4032001f49Smrg        case GL_RGB:
4132001f49Smrg             return "RGB";
4232001f49Smrg        case GL_RGBA:
4332001f49Smrg             return "RGBA";
4432001f49Smrg        case GL_COMPRESSED_RGB:
4532001f49Smrg             return "COMPRESSED_RGB";
4632001f49Smrg        case GL_COMPRESSED_RGBA:
4732001f49Smrg             return "COMPRESSED_RGBA";
4832001f49Smrg        case GL_COMPRESSED_RGB_FXT1_3DFX:
4932001f49Smrg             return "GL_COMPRESSED_RGB_FXT1_3DFX";
5032001f49Smrg        case GL_COMPRESSED_RGBA_FXT1_3DFX:
5132001f49Smrg             return "GL_COMPRESSED_RGBA_FXT1_3DFX";
5232001f49Smrg        case GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
5332001f49Smrg             return "GL_COMPRESSED_RGB_S3TC_DXT1_EXT";
5432001f49Smrg        case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT:
5532001f49Smrg             return "GL_COMPRESSED_RGBA_S3TC_DXT1_EXT";
5632001f49Smrg        case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
5732001f49Smrg             return "GL_COMPRESSED_RGBA_S3TC_DXT3_EXT";
5832001f49Smrg        case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
5932001f49Smrg             return "GL_COMPRESSED_RGBA_S3TC_DXT5_EXT";
6032001f49Smrg        case GL_RGB_S3TC:
6132001f49Smrg             return "GL_RGB_S3TC";
6232001f49Smrg        case GL_RGB4_S3TC:
6332001f49Smrg             return "GL_RGB4_S3TC";
6432001f49Smrg        case GL_RGBA_S3TC:
6532001f49Smrg             return "GL_RGBA_S3TC";
6632001f49Smrg        case GL_RGBA4_S3TC:
6732001f49Smrg             return "GL_RGBA4_S3TC";
6832001f49Smrg        case 0:
6932001f49Smrg             return "Invalid format";
7032001f49Smrg        default:
7132001f49Smrg             return "Unknown format";
7232001f49Smrg }
7332001f49Smrg}
7432001f49Smrg
7532001f49Smrg
7632001f49Smrgstatic void
7732001f49SmrgPrintString(const char *s)
7832001f49Smrg{
7932001f49Smrg   while (*s) {
8032001f49Smrg      glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
8132001f49Smrg      s++;
8232001f49Smrg   }
8332001f49Smrg}
8432001f49Smrg
8532001f49Smrg
8632001f49Smrgstatic void Idle( void )
8732001f49Smrg{
8832001f49Smrg   float t = glutGet(GLUT_ELAPSED_TIME) * 0.001;  /* in seconds */
8932001f49Smrg   Rot = t * 360 / 4;  /* 1 rotation per 4 seconds */
9032001f49Smrg   glutPostRedisplay();
9132001f49Smrg}
9232001f49Smrg
9332001f49Smrg
9432001f49Smrgstatic void Display( void )
9532001f49Smrg{
9632001f49Smrg   /* draw background gradient */
9732001f49Smrg   glDisable(GL_TEXTURE_2D);
9832001f49Smrg   glBegin(GL_POLYGON);
9932001f49Smrg   glColor3f(1.0, 0.0, 0.2); glVertex2f(-1.5, -1.0);
10032001f49Smrg   glColor3f(1.0, 0.0, 0.2); glVertex2f( 1.5, -1.0);
10132001f49Smrg   glColor3f(0.0, 0.0, 1.0); glVertex2f( 1.5,  1.0);
10232001f49Smrg   glColor3f(0.0, 0.0, 1.0); glVertex2f(-1.5,  1.0);
10332001f49Smrg   glEnd();
10432001f49Smrg
10532001f49Smrg   glPushMatrix();
10632001f49Smrg   glRotatef(Rot, 0, 0, 1);
10732001f49Smrg
10832001f49Smrg   glEnable(GL_TEXTURE_2D);
10932001f49Smrg   glEnable(GL_BLEND);
11032001f49Smrg
11132001f49Smrg   glBegin(GL_POLYGON);
11232001f49Smrg   glTexCoord2f(0, 1);  glVertex2f(-1, -0.5);
11332001f49Smrg   glTexCoord2f(1, 1);  glVertex2f( 1, -0.5);
11432001f49Smrg   glTexCoord2f(1, 0);  glVertex2f( 1,  0.5);
11532001f49Smrg   glTexCoord2f(0, 0);  glVertex2f(-1,  0.5);
11632001f49Smrg   glEnd();
11732001f49Smrg
11832001f49Smrg   glPopMatrix();
11932001f49Smrg
12032001f49Smrg   glDisable(GL_TEXTURE_2D);
12132001f49Smrg
12232001f49Smrg   /* info */
12332001f49Smrg   glDisable(GL_BLEND);
12432001f49Smrg   glColor4f(1, 1, 1, 1);
12532001f49Smrg
12632001f49Smrg   glRasterPos3f(-1.2, -0.7, 0);
12732001f49Smrg   PrintString("Selected: ");
12832001f49Smrg   PrintString(TextureName(Tx->TC));
12932001f49Smrg   if (Tx->cData) {
13032001f49Smrg      char tmp[64];
13132001f49Smrg      glRasterPos3f(-1.2, -0.8, 0);
13232001f49Smrg      PrintString("Internal: ");
13332001f49Smrg      PrintString(TextureName(Tx->cFormat));
13432001f49Smrg      glRasterPos3f(-1.2, -0.9, 0);
13532001f49Smrg      PrintString("Size    : ");
13632001f49Smrg      sprintf(tmp, "%d (%d%% of %d)", Tx->cSize, Tx->cSize * 100 / Tx->size, Tx->size);
13732001f49Smrg      PrintString(tmp);
13832001f49Smrg   }
13932001f49Smrg
14032001f49Smrg   glutSwapBuffers();
14132001f49Smrg}
14232001f49Smrg
14332001f49Smrg
14432001f49Smrgstatic void Reshape( int width, int height )
14532001f49Smrg{
14632001f49Smrg   glViewport( 0, 0, width, height );
14732001f49Smrg   glMatrixMode( GL_PROJECTION );
14832001f49Smrg   glLoadIdentity();
14932001f49Smrg   glOrtho( -1.5, 1.5, -1.0, 1.0, -1.0, 1.0 );
15032001f49Smrg   glMatrixMode( GL_MODELVIEW );
15132001f49Smrg   glLoadIdentity();
15232001f49Smrg}
15332001f49Smrg
15432001f49Smrg
15532001f49Smrgstatic void ReInit( GLenum TC, TEXTURE *Tx )
15632001f49Smrg{
15732001f49Smrg   GLint rv, v;
15832001f49Smrg
15932001f49Smrg   if ((Tx->TC == TC) && (Tx->cData != NULL)) {
16032001f49Smrg      glCompressedTexImage2DARB(GL_TEXTURE_2D, /* target */
16132001f49Smrg	                        0,             /* level */
16232001f49Smrg	                        Tx->cFormat,   /* real format */
16332001f49Smrg	                        Tx->w,         /* original width */
16432001f49Smrg	                        Tx->h,         /* original height */
16532001f49Smrg	                        0,             /* border */
16632001f49Smrg	                        Tx->cSize,     /* compressed size*/
16732001f49Smrg	                        Tx->cData);    /* compressed data*/
16832001f49Smrg   } else {
16932001f49Smrg      glTexImage2D(GL_TEXTURE_2D,    /* target */
17032001f49Smrg                   0,                /* level */
17132001f49Smrg                   TC,               /* internal format */
17232001f49Smrg                   Tx->w, Tx->h,     /* width, height */
17332001f49Smrg                   0,                /* border */
17432001f49Smrg                   Tx->format,       /* texture format */
17532001f49Smrg                   GL_UNSIGNED_BYTE, /* texture type */
17632001f49Smrg                   Tx->data);        /* the texture */
17732001f49Smrg
17832001f49Smrg
17932001f49Smrg      v = 0;
18032001f49Smrg      glGetTexLevelParameteriv(GL_TEXTURE_2D, 0,
18132001f49Smrg                               GL_TEXTURE_INTERNAL_FORMAT, &v);
18232001f49Smrg      printf("Requested internal format = 0x%x, actual = 0x%x\n", TC, v);
18332001f49Smrg
18432001f49Smrg      if (0) {
18532001f49Smrg         GLint r, g, b, a, l, i;
18632001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_RED_SIZE, &r);
18732001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_GREEN_SIZE, &g);
18832001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_BLUE_SIZE, &b);
18932001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_ALPHA_SIZE, &a);
19032001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_LUMINANCE_SIZE, &l);
19132001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTENSITY_SIZE, &i);
19232001f49Smrg         printf("Compressed Bits per R: %d  G: %d  B: %d  A: %d  L: %d  I: %d\n",
19332001f49Smrg                r, g, b, a, l, i);
19432001f49Smrg      }
19532001f49Smrg
19632001f49Smrg      /* okay, now cache the compressed texture */
19732001f49Smrg      Tx->TC = TC;
19832001f49Smrg      if (Tx->cData != NULL) {
19932001f49Smrg         free(Tx->cData);
20032001f49Smrg         Tx->cData = NULL;
20132001f49Smrg      }
20232001f49Smrg      glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_ARB, &rv);
20332001f49Smrg      if (rv) {
20432001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_INTERNAL_FORMAT, (GLint *)&Tx->cFormat);
20532001f49Smrg         glGetTexLevelParameteriv(GL_TEXTURE_2D, 0, GL_TEXTURE_COMPRESSED_IMAGE_SIZE_ARB, (GLint *)&Tx->cSize);
20632001f49Smrg         if ((Tx->cData = malloc(Tx->cSize)) != NULL) {
20732001f49Smrg            glGetCompressedTexImageARB(GL_TEXTURE_2D, 0, Tx->cData);
20832001f49Smrg         }
20932001f49Smrg      }
21032001f49Smrg   }
21132001f49Smrg}
21232001f49Smrg
21332001f49Smrg
21432001f49Smrgstatic void Init( void )
21532001f49Smrg{
21632001f49Smrg   /* HEIGHT * WIDTH + 1 (for trailing '\0') */
21732001f49Smrg   static char pattern[8 * 32 + 1] = {"\
21832001f49Smrg                                \
21932001f49Smrg    MMM    EEEE   SSS    AAA    \
22032001f49Smrg   M M M  E      S   S  A   A   \
22132001f49Smrg   M M M  EEEE    SS    A   A   \
22232001f49Smrg   M M M  E         SS  AAAAA   \
22332001f49Smrg   M   M  E      S   S  A   A   \
22432001f49Smrg   M   M   EEEE   SSS   A   A   \
22532001f49Smrg                                "
22632001f49Smrg      };
22732001f49Smrg
22832001f49Smrg   GLuint i, j;
22932001f49Smrg
23032001f49Smrg   GLubyte (*texture1)[8 * 32][4];
23132001f49Smrg   GLubyte (*texture2)[256][256][4];
23232001f49Smrg
23332001f49Smrg   t1.w = 32;
23432001f49Smrg   t1.h = 8;
23532001f49Smrg   t1.size = t1.w * t1.h * 4;
23632001f49Smrg   t1.data = malloc(t1.size);
23732001f49Smrg   t1.format = GL_RGBA;
23832001f49Smrg   t1.TC = GL_RGBA;
23932001f49Smrg
24032001f49Smrg   texture1 = (GLubyte (*)[8 * 32][4])t1.data;
24132001f49Smrg   for (i = 0; i < sizeof(pattern) - 1; i++) {
24232001f49Smrg       switch (pattern[i]) {
24332001f49Smrg              default:
24432001f49Smrg              case ' ':
24532001f49Smrg                   (*texture1)[i][0] = 255;
24632001f49Smrg                   (*texture1)[i][1] = 255;
24732001f49Smrg                   (*texture1)[i][2] = 255;
24832001f49Smrg                   (*texture1)[i][3] = 64;
24932001f49Smrg                   break;
25032001f49Smrg              case 'M':
25132001f49Smrg                   (*texture1)[i][0] = 255;
25232001f49Smrg                   (*texture1)[i][1] = 0;
25332001f49Smrg                   (*texture1)[i][2] = 0;
25432001f49Smrg                   (*texture1)[i][3] = 255;
25532001f49Smrg                   break;
25632001f49Smrg              case 'E':
25732001f49Smrg                   (*texture1)[i][0] = 0;
25832001f49Smrg                   (*texture1)[i][1] = 255;
25932001f49Smrg                   (*texture1)[i][2] = 0;
26032001f49Smrg                   (*texture1)[i][3] = 255;
26132001f49Smrg                   break;
26232001f49Smrg              case 'S':
26332001f49Smrg                   (*texture1)[i][0] = 0;
26432001f49Smrg                   (*texture1)[i][1] = 0;
26532001f49Smrg                   (*texture1)[i][2] = 255;
26632001f49Smrg                   (*texture1)[i][3] = 255;
26732001f49Smrg                   break;
26832001f49Smrg              case 'A':
26932001f49Smrg                   (*texture1)[i][0] = 255;
27032001f49Smrg                   (*texture1)[i][1] = 255;
27132001f49Smrg                   (*texture1)[i][2] = 0;
27232001f49Smrg                   (*texture1)[i][3] = 255;
27332001f49Smrg                   break;
27432001f49Smrg       }
27532001f49Smrg   }
27632001f49Smrg
27732001f49Smrg   t2.w = 256;
27832001f49Smrg   t2.h = 256;
27932001f49Smrg   t2.size = t2.w * t2.h * 4;
28032001f49Smrg   t2.data = malloc(t2.size);
28132001f49Smrg   t2.format = GL_RGBA;
28232001f49Smrg   t2.TC = GL_RGBA;
28332001f49Smrg
28432001f49Smrg   texture2 = (GLubyte (*)[256][256][4])t2.data;
28532001f49Smrg   for (j = 0; j < t2.h; j++) {
28632001f49Smrg      for (i = 0; i < t2.w; i++) {
28732001f49Smrg         (*texture2)[j][i][0] = sqrt(i * j * 255 * 255 / (t2.w * t2.h));
28832001f49Smrg         (*texture2)[j][i][1] = 0;
28932001f49Smrg         (*texture2)[j][i][2] = 0;
29032001f49Smrg         (*texture2)[j][i][3] = 255;
29132001f49Smrg      }
29232001f49Smrg   }
29332001f49Smrg
29432001f49Smrg   t3.data = LoadRGBImage(TEXTURE_FILE, (GLint *)&t3.w, (GLint *)&t3.h, &t3.format);
29532001f49Smrg   t3.size = t3.w * t3.h * ((t3.format == GL_RGB) ? 3 : 4);
29632001f49Smrg   t3.TC = GL_RGBA;
29732001f49Smrg
29832001f49Smrg   ReInit(GL_RGBA, Tx = &t1);
29932001f49Smrg
30032001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
30132001f49Smrg   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
30232001f49Smrg   glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
30332001f49Smrg   glEnable(GL_TEXTURE_2D);
30432001f49Smrg
30532001f49Smrg   glEnable(GL_BLEND);
30632001f49Smrg   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
30732001f49Smrg}
30832001f49Smrg
30932001f49Smrg
31032001f49Smrgstatic void Key( unsigned char key, int x, int y )
31132001f49Smrg{
31232001f49Smrg   (void) x;
31332001f49Smrg   (void) y;
31432001f49Smrg   switch (key) {
31532001f49Smrg      case 27:
31632001f49Smrg         exit(0);
31732001f49Smrg         break;
31832001f49Smrg      case ' ':
31932001f49Smrg         Anim = !Anim;
32032001f49Smrg         if (Anim)
32132001f49Smrg            glutIdleFunc( Idle );
32232001f49Smrg         else
32332001f49Smrg            glutIdleFunc( NULL );
32432001f49Smrg         break;
32532001f49Smrg      case 't':
32632001f49Smrg         if (Tx == &t1) {
32732001f49Smrg            Tx = &t2;
32832001f49Smrg         } else if (Tx == &t2) {
32932001f49Smrg            Tx = &t3;
33032001f49Smrg         } else {
33132001f49Smrg            Tx = &t1;
33232001f49Smrg         }
33332001f49Smrg         ReInit(Tx->TC, Tx);
33432001f49Smrg         break;
33532001f49Smrg      case '9':
33632001f49Smrg         ReInit(GL_RGB, Tx);
33732001f49Smrg         break;
33832001f49Smrg      case '0':
33932001f49Smrg         ReInit(GL_RGBA, Tx);
34032001f49Smrg         break;
34132001f49Smrg      case '1':
34232001f49Smrg         ReInit(GL_COMPRESSED_RGB, Tx);
34332001f49Smrg         break;
34432001f49Smrg      case '2':
34532001f49Smrg         ReInit(GL_COMPRESSED_RGBA, Tx);
34632001f49Smrg         break;
34732001f49Smrg      case '3':
34832001f49Smrg         if (fxt1) ReInit(GL_COMPRESSED_RGB_FXT1_3DFX, Tx);
34932001f49Smrg         break;
35032001f49Smrg      case '4':
35132001f49Smrg         if (fxt1) ReInit(GL_COMPRESSED_RGBA_FXT1_3DFX, Tx);
35232001f49Smrg         break;
35332001f49Smrg      case '5':
35432001f49Smrg         if (dxtc) ReInit(GL_COMPRESSED_RGB_S3TC_DXT1_EXT, Tx);
35532001f49Smrg         break;
35632001f49Smrg      case '6':
35732001f49Smrg         if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, Tx);
35832001f49Smrg         break;
35932001f49Smrg      case '7':
36032001f49Smrg         if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, Tx);
36132001f49Smrg         break;
36232001f49Smrg      case '8':
36332001f49Smrg         if (dxtc) ReInit(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, Tx);
36432001f49Smrg         break;
36532001f49Smrg      case 'a':
36632001f49Smrg         if (s3tc) ReInit(GL_RGB_S3TC, Tx);
36732001f49Smrg         break;
36832001f49Smrg      case 's':
36932001f49Smrg         if (s3tc) ReInit(GL_RGB4_S3TC, Tx);
37032001f49Smrg         break;
37132001f49Smrg      case 'd':
37232001f49Smrg         if (s3tc) ReInit(GL_RGBA_S3TC, Tx);
37332001f49Smrg         break;
37432001f49Smrg      case 'f':
37532001f49Smrg         if (s3tc) ReInit(GL_RGBA4_S3TC, Tx);
37632001f49Smrg         break;
37732001f49Smrg   }
37832001f49Smrg   glutPostRedisplay();
37932001f49Smrg}
38032001f49Smrg
38132001f49Smrg
38232001f49Smrgint main( int argc, char *argv[] )
38332001f49Smrg{
38432001f49Smrg   float gl_version;
38532001f49Smrg   GLint num_formats;
38632001f49Smrg   GLint i;
38732001f49Smrg   GLint formats[64];
38832001f49Smrg
38932001f49Smrg
39032001f49Smrg   glutInit( &argc, argv );
39132001f49Smrg   glutInitWindowPosition( 0, 0 );
39232001f49Smrg   glutInitWindowSize( 400, 300 );
39332001f49Smrg
39432001f49Smrg   glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE );
39532001f49Smrg
39632001f49Smrg   if (glutCreateWindow(argv[0]) <= 0) {
39732001f49Smrg      printf("Couldn't create window\n");
39832001f49Smrg      exit(0);
39932001f49Smrg   }
40032001f49Smrg
40132001f49Smrg   glewInit();
40232001f49Smrg   gl_version = atof( (const char *) glGetString( GL_VERSION ) );
40332001f49Smrg   if ( (gl_version < 1.3)
40432001f49Smrg	&& !glutExtensionSupported("GL_ARB_texture_compression") ) {
40532001f49Smrg      printf("Sorry, GL_ARB_texture_compression not supported\n");
40632001f49Smrg      exit(0);
40732001f49Smrg   }
40832001f49Smrg   if (glutExtensionSupported("GL_3DFX_texture_compression_FXT1")) {
40932001f49Smrg      fxt1 = GL_TRUE;
41032001f49Smrg   }
41132001f49Smrg   if (glutExtensionSupported("GL_EXT_texture_compression_s3tc")) {
41232001f49Smrg      dxtc = GL_TRUE;
41332001f49Smrg   }
41432001f49Smrg   if (glutExtensionSupported("GL_S3_s3tc")) {
41532001f49Smrg      s3tc = GL_TRUE;
41632001f49Smrg   }
41732001f49Smrg
41832001f49Smrg   glGetIntegerv( GL_NUM_COMPRESSED_TEXTURE_FORMATS_ARB, & num_formats );
41932001f49Smrg
42032001f49Smrg   (void) memset( formats, 0, sizeof( formats ) );
42132001f49Smrg   glGetIntegerv( GL_COMPRESSED_TEXTURE_FORMATS_ARB, formats );
42232001f49Smrg
42332001f49Smrg   printf( "The following texture formats are supported:\n" );
42432001f49Smrg   for ( i = 0 ; i < num_formats ; i++ ) {
42532001f49Smrg      printf( "\t%s\n", TextureName( formats[i] ) );
42632001f49Smrg   }
42732001f49Smrg
42832001f49Smrg   Init();
42932001f49Smrg
43032001f49Smrg   glutReshapeFunc( Reshape );
43132001f49Smrg   glutKeyboardFunc( Key );
43232001f49Smrg   glutDisplayFunc( Display );
43332001f49Smrg   if (Anim)
43432001f49Smrg      glutIdleFunc( Idle );
43532001f49Smrg
43632001f49Smrg   glutMainLoop();
43732001f49Smrg   return 0;
43832001f49Smrg}
439