/*
 * Make the specified FX/Mesa context the current one.
 */
void GLAPIENTRY
fxMesaMakeCurrent(fxMesaContext fxMesa)
{
   if (!fxMesa) {
      _mesa_make_current(NULL, NULL, NULL);
      fxMesaCurrentCtx = NULL;

      if (TDFX_DEBUG & VERBOSE_DRIVER) {
	 fprintf(stderr, "fxMesaMakeCurrent(NULL)\n");
      }

      return;
   }

   /* if this context is already the current one, we can return early */
   if (fxMesaCurrentCtx == fxMesa
       && fxMesaCurrentCtx->glCtx == _mesa_get_current_context()) {
      if (TDFX_DEBUG & VERBOSE_DRIVER) {
	 fprintf(stderr, "fxMesaMakeCurrent(NOP)\n");
      }

      return;
   }

   if (TDFX_DEBUG & VERBOSE_DRIVER) {
      fprintf(stderr, "fxMesaMakeCurrent(...)\n");
   }

   if (fxMesaCurrentCtx)
      grGlideGetState((GrState *) fxMesaCurrentCtx->state);

   fxMesaCurrentCtx = fxMesa;

   grSstSelect(fxMesa->board);
   grGlideSetState((GrState *) fxMesa->state);

   _mesa_make_current(fxMesa->glCtx, fxMesa->glBuffer, fxMesa->glBuffer);

   fxSetupDDPointers(fxMesa->glCtx);
}
Exemple #2
0
void
main( int argc, char **argv ) {
  float
    minColor = 55.f,
    maxColor = 200.f;

  GrVertex
    localVerts[3],
    texVerts[4];

  float
    alpha = 192.0f,
    y_angle = 0.0f;

  int
    n,
    nTris = 0;

  FxBool
    depthBias = FXTRUE,
    blend = FXFALSE,
    texturing = FXFALSE,
    antialias = FXTRUE,
    bilinear = FXTRUE,
    render = FXTRUE,
    backbuffer = FXTRUE,
    background = FXTRUE;

  GrState
    nonBlendState, blendState;

  float
    wWidth, wHeight;

  GrScreenResolution_t
    screenRes;

  GrMipMapId_t
    triDecal,
    bgDecal;

  Gu3dfInfo
    bgInfo, triInfo;

  FxU16
    *scrnImage;

  GrColorCombineFnc_t
    ccFnc = GR_COLORCOMBINE_ITRGB;

  int
    numFrames = -1,
    frameCount = 0;

  char
    *bgFileName = NULL,
    *triFileName = NULL;
  wWidth = 640.0f;
  wHeight = 480.0f;

  screenRes = GR_RESOLUTION_640x480;

  --argc; ++argv;

  while (argc) {
    if (strstr(*argv, "320x200")) {
      wWidth = 320.0f; wHeight = 200.0f;
      screenRes = GR_RESOLUTION_320x200;
      --argc; ++argv;
    } else if (strstr(*argv, "320x240")) {
      wWidth = 320.0f; wHeight = 240.0f;
      screenRes = GR_RESOLUTION_320x240;
      --argc; ++argv;
    } else if (strstr(*argv, "400x256")) {
      wWidth = 400.0f; wHeight = 256.0f;
      screenRes = GR_RESOLUTION_400x256;
      --argc; ++argv;
    } else if (strstr(*argv, "512x384")) {
      wWidth = 512.0f; wHeight = 384.0f;
      screenRes = GR_RESOLUTION_512x384;
      --argc; ++argv;
    } else if (strstr(*argv, "640x480")) {
      wWidth = 640.0f; wHeight = 480.0f;
      screenRes = GR_RESOLUTION_640x480;
      --argc; ++argv;
    } else if (strstr(*argv, "800x600")) {
      wWidth = 800.0f; wHeight = 600.0f;
      screenRes = GR_RESOLUTION_800x600;
      --argc; ++argv;
    } else if (strstr(*argv, "856x480")) {
      wWidth = 856.0f; wHeight = 480.0f;
      screenRes = GR_RESOLUTION_856x480;
      --argc; ++argv;
    } else if (strstr(*argv, "960x720")) {
      wWidth = 960.0f; wHeight = 720.0f;
      screenRes = GR_RESOLUTION_960x720;
      --argc; ++argv;
    } else if (strstr(*argv, "640x200")) {
      wWidth = 640.f; wHeight = 200.f;
      screenRes = GR_RESOLUTION_640x200;
      --argc; ++argv;
    } else if (strstr(*argv, "640x350")) {
      wWidth = 640.f; wHeight = 350.f;
      screenRes = GR_RESOLUTION_640x350;
      --argc; ++argv;
    } else if (strstr(*argv, "640x400")) {
      wWidth = 640.f; wHeight = 400.f;
      screenRes = GR_RESOLUTION_640x400;
      --argc; ++argv;
    } else if (strstr(*argv, "bgFile")) {
      bgFileName = argv[1];
      argc-= 2; argv += 2;
    } else if (strstr(*argv, "triFile")) {
      triFileName = argv[1];
      argc-= 2; argv += 2;
    } else if (strstr(*argv, "alpha")) {
      alpha = (float)atof(argv[1]);
      argc -= 2; argv += 2;                    
    } else if (strstr(*argv, "-n")) {
      numFrames = atoi(argv[1]);
      argc -= 2; argv += 2;
    } else {
      fprintf(
              stderr,
              "Useage:  test24 [-bgFile bgfile.3ds] [-triFile triFile.3ds] [ScreenRes (i.e. 640x480 .. 960x720] [-alpha alphavalue] [-n numFrames]\n");
      exit(-1);
    }
  }

  scrnImage = malloc((int)wWidth * (int)wHeight * sizeof(FxU16));

  puts( "\ntest30:" );
  puts( "Depth Bias Level Test\n" );
  puts("press H for help\n");
  if(numFrames == -1)
  {
    puts("Press a key to continue");
    getch();
  }

  grGlideInit();

  if ( !grSstQueryHardware( &hwconfig ) )
  {
    fprintf( stderr, "main: grSstQueryHardware failed!\n" );
    grGlideShutdown();
    exit( -1 );
  }

  /* Select SST 0 */
  grSstSelect( 0 );

  /* Open up the hardware */
  if ( !grSstOpen( screenRes,
                   GR_REFRESH_60Hz,
                   GR_COLORFORMAT_ABGR,
                   GR_ORIGIN_LOWER_LEFT,
                   GR_SMOOTHING_ENABLE,
                   2 ) )
  {
    fprintf( stderr, "main: grSstOpen failed!\n" );
    grGlideShutdown();
    exit( -1 );
  }

  localVerts[0].x = 0.f;
  localVerts[0].y = 0.75f;
  localVerts[0].z = 0.0f;
  localVerts[0].tmuvtx[0].sow = 255.f;
  localVerts[0].tmuvtx[0].tow = 255.f;
  localVerts[0].oow = 1.f;  
  localVerts[0].r = maxColor;
  localVerts[0].g = minColor;
  localVerts[0].b = minColor;
  localVerts[0].a = 255.f;

  localVerts[1].x = -0.75f;
  localVerts[1].y = -0.75f;
  localVerts[1].z = 0.0f;
  localVerts[1].tmuvtx[0].sow = 0.f;
  localVerts[1].tmuvtx[0].tow = 255.f;
  localVerts[1].oow = 1.f;  
  localVerts[1].r = minColor;
  localVerts[1].g = maxColor;
  localVerts[1].b = minColor;
  localVerts[1].a = 255.f;

  localVerts[2].x = 0.75f;
  localVerts[2].y = -0.75f;
  localVerts[2].z = 0.0f;
  localVerts[2].tmuvtx[0].sow = 255.f;
  localVerts[2].tmuvtx[0].tow = 0.f;
  localVerts[2].oow = 1.f;  
  localVerts[2].r = minColor;
  localVerts[2].g = minColor;
  localVerts[2].b = maxColor;
  localVerts[2].a = 255.f;

  texVerts[0].x = 0.f;
  texVerts[0].y = 0.f;
  texVerts[0].a = 255.f;
  texVerts[0].oow = 1.f;
  texVerts[0].tmuvtx[0].sow = 0.f * texVerts[0].oow;
  texVerts[0].tmuvtx[0].tow = 255.f * texVerts[0].oow;

  texVerts[1].x = wWidth;
  texVerts[1].y = 0.f;
  texVerts[1].a = 255.f;
  texVerts[1].oow = 1.f;
  texVerts[1].tmuvtx[0].sow = 255.f * texVerts[1].oow;
  texVerts[1].tmuvtx[0].tow = 255.f * texVerts[1].oow;

  texVerts[2].x = wWidth;
  texVerts[2].y = wHeight;
  texVerts[2].a = 255.f;
  texVerts[2].oow = 1.f;
  texVerts[2].tmuvtx[0].sow = 255.f * texVerts[2].oow;
  texVerts[2].tmuvtx[0].tow = 0.f * texVerts[2].oow;
  
  texVerts[3].x = 0.f;
  texVerts[3].y = wHeight;
  texVerts[3].a = 255.f;
  texVerts[3].oow = 1.f;
  texVerts[3].tmuvtx[0].sow = 0.f * texVerts[3].oow;
  texVerts[3].tmuvtx[0].tow = 0.f * texVerts[3].oow;
  
  if (bgFileName == NULL)
    bgFileName = "miro.3df";
  if (triFileName == NULL)
    triFileName = "matt1.3df";

  if ( gu3dfGetInfo( bgFileName, &bgInfo ) )  {
     bgInfo.data = malloc( bgInfo.mem_required );

     if ( bgInfo.data == 0 ) {
       fprintf( stderr, "out of memory for texture file %s\n", bgFileName );
       grGlideShutdown();
       exit( -1 );
     }

     if ( !gu3dfLoad( bgFileName, &bgInfo ) ) {
       fprintf( stderr, "could not load texture file %s\n", bgFileName );
       grGlideShutdown();
       exit( -1 );
     }

     bgDecal = guTexAllocateMemory( 0, GR_MIPMAPLEVELMASK_BOTH,
                                  bgInfo.header.width, bgInfo.header.height,
                                  bgInfo.header.format,
                                  GR_MIPMAP_NEAREST,
                                  bgInfo.header.small_lod, bgInfo.header.large_lod,
                                  bgInfo.header.aspect_ratio,
                                  GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP,
                                  GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR,
                                  0.0F,
                                  FXFALSE );
     if ( bgDecal == GR_NULL_MIPMAP_HANDLE ) {
       fprintf( stderr, "could not allocate memory for texture file %s\n", bgFileName );
       grGlideShutdown();
       exit( -1 );
     }
     guTexDownloadMipMap( bgDecal, bgInfo.data, &bgInfo.table.nccTable );
     free( bgInfo.data );
  } else {
    fprintf( stderr, "could not get info on %s\n", bgFileName );
    grGlideShutdown();
    exit( -1 );
  }
  
  if ( gu3dfGetInfo( triFileName, &triInfo ) )  {
    triInfo.data = malloc( triInfo.mem_required );
    
    if ( triInfo.data == 0 ) {
      fprintf( stderr, "out of memory for texture file  %s\n", triFileName );
      grGlideShutdown();
      exit( -1 );
    }
    
    if ( !gu3dfLoad( triFileName, &triInfo ) ) {
      fprintf( stderr, "could not load texture file %s\n", triFileName );
      grGlideShutdown();
      exit( -1 );
    }

    triDecal = guTexAllocateMemory( 0, GR_MIPMAPLEVELMASK_BOTH,
                                    triInfo.header.width,  
                                    triInfo.header.height, 
                                    triInfo.header.format,
                                    GR_MIPMAP_NEAREST,
                                    triInfo.header.small_lod,
                                    triInfo.header.large_lod, 
                                    triInfo.header.aspect_ratio,
                                    GR_TEXTURECLAMP_WRAP,
                                    GR_TEXTURECLAMP_WRAP, 
                                    GR_TEXTUREFILTER_BILINEAR,
                                    GR_TEXTUREFILTER_BILINEAR, 
                                    0.0F,
                                    FXFALSE );
    if ( triDecal == GR_NULL_MIPMAP_HANDLE ) {
       fprintf( stderr, "could not allocate memory for %s\n", triFileName );
       grGlideShutdown();
       exit( -1 );
     }
     guTexDownloadMipMap( triDecal, triInfo.data, &triInfo.table.nccTable );
     free( triInfo.data );
  } else {
    fprintf( stderr, "could not get info on %s\n", triFileName );
    grGlideShutdown();
    exit( -1 );
  }

  grTexCombineFunction(GR_TMU0, GR_TEXTURECOMBINE_DECAL);
  grRenderBuffer(backbuffer == FXTRUE ? GR_BUFFER_BACKBUFFER : GR_BUFFER_FRONTBUFFER);

  /* Set up alpha blend state for compositing and antialiasing */
  guAlphaSource( GR_ALPHASOURCE_ITERATED_ALPHA );
  grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
                        GR_BLEND_ONE_MINUS_SRC_ALPHA, GR_BLEND_ONE,
                        GR_BLEND_ZERO ); 
  grAlphaTestFunction( GR_CMP_ALWAYS );
  
  while ( 1 ) {
    Matrix rotm;
    GrVertex xformedVerts[4];
    int i;

    grSstIdle();

    
    ++nTris;
    MatMakeYRot( rotm, DEG2RAD( y_angle ) );
    
    for( i = 0; i < 4; i++ ) {
      PointMatMult( &xformedVerts[i], &localVerts[i], rotm );
      xformedVerts[i].x = xformedVerts[i].x / ( xformedVerts[i].z + 2.0f );
      xformedVerts[i].y = xformedVerts[i].y / ( xformedVerts[i].z + 2.0f );
      xformedVerts[i].x *= wHeight / 2.0f;
      xformedVerts[i].y *= wHeight / 2.0f;
      xformedVerts[i].x += wHeight / 2.0f;
      xformedVerts[i].y += wHeight / 2.0f;
      xformedVerts[i].oow = 1.f / ((xformedVerts[i].z + 2) * wHeight);
      xformedVerts[i].tmuvtx[0].sow *= xformedVerts[i].oow;
      xformedVerts[i].tmuvtx[0].tow *= xformedVerts[i].oow;
      SNAP_COORD( xformedVerts[i].x );
      SNAP_COORD( xformedVerts[i].y );
    }
    

    if (render == FXTRUE) {
      grBufferClear( 0xffffffff, 0, GR_WDEPTHVALUE_FARTHEST );
    
      if (background == FXTRUE) {
        GrState
          oldState;

        grGlideGetState(&oldState);

        grAlphaBlendFunction(
                             GR_BLEND_ONE, GR_BLEND_ZERO,
                             GR_BLEND_ONE, GR_BLEND_ZERO);

        grColorCombine(
                       GR_COMBINE_FUNCTION_SCALE_OTHER,
                       GR_COMBINE_FACTOR_ONE,
                       GR_COMBINE_LOCAL_NONE,
                       GR_COMBINE_OTHER_TEXTURE, FXFALSE
                       );

        guTexSource(bgDecal);
        
        for (i = 0; i < NTRIS; i++) {
          grDrawTriangle(&texVerts[0], &texVerts[1], &texVerts[2]);
          grDrawTriangle(&texVerts[2], &texVerts[3], &texVerts[0]);
        }
        grGlideSetState(&oldState);

      }

      guTexSource(triDecal);

      if (antialias == FXTRUE) {
        if (depthBias) 
            grDepthBiasLevel((short)0x8000);
        guColorCombineFunction(GR_COLORCOMBINE_DECAL_TEXTURE);
        grAADrawTriangle(
                         &xformedVerts[0],  &xformedVerts[1],
                         &xformedVerts[2], FXTRUE, FXTRUE, FXTRUE
                         );
#define SHIFT 20.f;
        for (n = 0; n < 3; n++) {
          xformedVerts[n].x += SHIFT;
          xformedVerts[n].y -= SHIFT;
        }
        if (depthBias)
          grDepthBiasLevel(0x7fff);
        guColorCombineFunction(GR_COLORCOMBINE_ITRGB);
        grAADrawTriangle(
                         &xformedVerts[0],  &xformedVerts[1],
                         &xformedVerts[2], FXTRUE, FXTRUE, FXTRUE
                         );
        
      } else {
        if (depthBias)
            grDepthBiasLevel((short)0x8000);
        guColorCombineFunction(GR_COLORCOMBINE_DECAL_TEXTURE);
        grDrawTriangle(
                       &xformedVerts[0], &xformedVerts[1],
                       &xformedVerts[2]
                       );
        for (n = 0; n < 3; n++) {
          xformedVerts[n].x += SHIFT;
          xformedVerts[n].y -= SHIFT;
        }
        if (depthBias)
          grDepthBiasLevel(0x7fff);
        guColorCombineFunction(GR_COLORCOMBINE_ITRGB);
        grDrawTriangle(
                       &xformedVerts[0], &xformedVerts[1],
                       &xformedVerts[2]
                       );
      }
      if (backbuffer) {
        grBufferSwap( 1 );
      }
    }
    
    if (kbhit()) {
      char c = getch();
      
      switch (c) {
      case 'a':
      case 'A':
        if (antialias == FXFALSE) {
          printf("Turning ON Antialiasing\n");
          antialias = FXTRUE;
        } else {
          printf("Turning OFF Antialiasing\n");
          antialias = FXFALSE;
        }
        break;
      case 'B':
      case 'b':
        if (bilinear == FXFALSE) {
          bilinear = FXTRUE;
          printf("Turning ON BiLinear blending\n");
          guTexChangeAttributes(
                                triDecal, bgInfo.header.width,
                                bgInfo.header.height, 
                                bgInfo.header.format, GR_MIPMAP_NEAREST,
                                bgInfo.header.small_lod,
                                bgInfo.header.large_lod, 
                                bgInfo.header.aspect_ratio,
                                GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP,
                                GR_TEXTUREFILTER_BILINEAR,
                                GR_TEXTUREFILTER_BILINEAR);
        } else {
          bilinear = FXFALSE;
          printf("Turning OFF BiLinear blending\n");
          guTexChangeAttributes(
                                triDecal, bgInfo.header.width,
                                bgInfo.header.height, 
                                bgInfo.header.format, GR_MIPMAP_NEAREST,
                                bgInfo.header.small_lod,
                                bgInfo.header.large_lod,
                                bgInfo.header.aspect_ratio, 
                                GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP,
                                GR_TEXTUREFILTER_POINT_SAMPLED,
                                GR_TEXTUREFILTER_POINT_SAMPLED);
        }
        break;

      case 'c':
      case 'C':
        if (blend == FXTRUE) {
          blend = FXFALSE;
          localVerts[0].a = 255.0f;
          localVerts[1].a = 255.0f;
          localVerts[2].a = 255.0f;
          localVerts[3].a = 255.0f;

        } else {
          blend = FXTRUE;
          localVerts[0].a = alpha;
          localVerts[1].a = alpha;
          localVerts[2].a = alpha;
        }
        break;

      case 'd':
      case 'D':
        if (depthBias == FXTRUE)  {
          printf("Turning OFF depth bias level\n");
          depthBias = FXFALSE;
          grDepthBiasLevel(0);
        } else {
          printf("Turning ON depth bias level\n");        
          depthBias = FXTRUE;
        }
        break;

      case 'f':
      case 'F':
        if (backbuffer == FXTRUE) {
          backbuffer = FXFALSE;
          grRenderBuffer(GR_BUFFER_FRONTBUFFER);
        } else {
          backbuffer = FXTRUE;
          grRenderBuffer(GR_BUFFER_BACKBUFFER);
        }
        break;

      case 'g':
      case 'G':
        grLfbBegin();

        grLfbWriteMode(GR_LFBWRITEMODE_565);
        grLfbOrigin(GR_ORIGIN_UPPER_LEFT);
        grLfbGetReadPtr(GR_BUFFER_FRONTBUFFER);
        printf("Press a key to get front buffer\n");
        while (!kbhit());
        c = getch();
        guFbReadRegion(0,0,(int)wWidth,(int)wHeight,scrnImage,(int)wWidth * sizeof(FxU16));
        printf("Press a key to put image in back buffer and swap\n");
        while (!kbhit());
        getch();

        grLfbGetWritePtr(GR_BUFFER_BACKBUFFER);
        guFbWriteRegion(0,0,(int)wWidth,(int)wHeight,scrnImage,(int)wWidth * sizeof(FxU16));
        grBufferSwap(1);

        printf("Press a key to continue...\n");
        while (!kbhit());
        getch();

        grLfbEnd();

        break;

      case 'h':
      case 'H':
      case '?':
        grSstPassthruMode(GR_PASSTHRU_SHOW_VGA);
        printf("Keymap:\n");
        printf("        A or a:         toggle Antialiasing\n");
        printf("        B or b:         toggle Bilinear\n");
        printf("        D or d:         toggle Depth bias level\n");
        printf("        F or f:         toggle Front buffer \n");
        printf("        H, h, or ?:     Help\n");
        printf("        I or i:         toggle background Image\n");
        printf("        P or p:         Pause rendering\n");
        printf("        Q or q:         Quit\n");
        printf("Press a key to continue...\n");
        getch();
        grSstPassthruMode(GR_PASSTHRU_SHOW_SST1);
        break;

      case 'i':
      case 'I':
        if (background == FXTRUE) {
          background = FXFALSE;
          printf("Turning off background\n");
        } else {
          printf("Turning on background\n");
          background = FXTRUE;
        }
        break;

      case 'p':
      case 'P':
        if (render == FXTRUE)
          render = FXFALSE;
        else
          render = FXTRUE;
        break;
        
      case 'q':
      case 'Q':
        grGlideShutdown();
        exit(0);
        break;

      case 'T':
      case 't':
        if (texturing == FXFALSE) {
          printf("Turning ON texturing\n");
          ccFnc = GR_COLORCOMBINE_DECAL_TEXTURE;
          texturing = FXTRUE;
        } else {
          printf("Turning OFF texturing\n");
          ccFnc = GR_COLORCOMBINE_ITRGB;
          texturing = FXFALSE;
        }
        break;
        
      }
    }
    
    if (render) {
      y_angle += 2.f;
      if( y_angle > 360.0f )
        y_angle -= 360.0f;
    }

    frameCount++;
    if(frameCount < 0)
      frameCount = 0;
    if(numFrames == frameCount)
      break;
  }
  grGlideShutdown();
}
Exemple #3
0
void main( int argc, char **argv) {
  char match; 
  char **remArgs;
  int  rv;

  GrScreenResolution_t resolution = GR_RESOLUTION_640x480;
  float                scrWidth   = 640.0f;
  float                scrHeight  = 480.0f;
  int frames                      = -1;

  float
    minColor = 10.f,            /* Vertex min color */
    maxColor = 245.f;           /* Vertex max color */
    
  GrVertex
    localVerts[VERT_COUNT],     /* Vertices in world coordinates */
    texVerts[4];                /* Texture vertices for background */
    
  float
    alpha = 192.0f,             /* Alpha for blending tringle over background */
    y_angle = 0.0f;             /* rotation amount */
    
  int
    firstTime;                  /* Used for performance calculations */

  FxBool
    plugging = FXFALSE,         /* Show shameless plug */
    printPerf = FXFALSE,        /* Print performance numbers */
    lines = FXFALSE,            /* Draw lines instead of triangles */
    blend = FXFALSE,            /* Blend the triangle over the background */
    texturing = FXFALSE,        /* Texture the tiangle */
    antialias = FXTRUE,         /* Antialias the triangle? */
    bilinear = FXTRUE,          /* Perform bilinear filtering on the texture? */
    render = FXTRUE,            /* Draw? */
    backbuffer = FXTRUE,        /* Draw to backbuffer? */
    background = FXTRUE;        /* Draw background? */

  GrOriginLocation_t
    origin = GR_ORIGIN_LOWER_LEFT; /* Origin */

  FxU32
    swapDelay = 1,              /* Arg to grBufferSwap */
    trisDrawn,                  /* # triangles drawn */
    trisProcessed,              /* # triangles through pipeline */
    lastFrame,                  /* Number of last frame we did perf stats */
    frameNum = 0L;              /* id of each frame drawn */
    
  GrCullMode_t
    cullMode = GR_CULL_DISABLE; /* backface culling */
    
  FxU32 startAddress = 0, bgDecalAddress = 0, triDecalAddress = 0;

  GrTexInfo
    triDecal,                   /* Triangle decal texture */
    bgDecal;                    /* Background decal texture */
    
  Gu3dfInfo
    bgInfo,                     /* Info on background texture */
    triInfo;                    /* Info on triangle texture */
    
  GrColorCombineFnc_t
    ccFnc = GR_COLORCOMBINE_ITRGB; /* Start of w/ Gouraud shading */
    
  char
    *bgFileName = NULL,         /* Name of background texture file */
    *triFileName = NULL;        /* Name of triangle texture file */
    
  int
    frameCount = 0;

  FxU32 wrange[2];
  FxI32 state_size;
  void *oldState;

  /* Initialize Glide */
  grGlideInit();
  assert( hwconfig = tlVoodooType() );

  /* Process Command Line Arguments */
  while( rv = tlGetOpt( argc, argv, "nrbtea", &match, &remArgs ) ) {
    if ( rv == -1 ) {
      printf( "Unrecognized command line argument\n" );
      printf( "%s %s\n", name, usage );
      printf( "Available resolutions:\n%s\n",
             tlGetResolutionList() );
      return;
    }
    switch( match ) {
    case 'n':
      frames = atoi( remArgs[0] );
      break;
    case 'r':
      resolution = tlGetResolutionConstant( remArgs[0], 
                                           &scrWidth, 
                                           &scrHeight );
      break;
    case 'b':
      bgFileName = strdup( remArgs[0] );
      break;
    case 't':
      triFileName = strdup( remArgs[0] );
      break;
    case 'a':
      alpha = (float)atof( remArgs[0] );
      break;
    }
  }

  tlSetScreen( scrWidth, scrHeight );

  version = grGetString( GR_VERSION );
    
  printf( "%s:\n%s\n", name, purpose );
  printf( "%s\n", version );
  printf( "Resolution: %s\n", tlGetResolutionString( resolution ) );
  if ( frames == -1 ) {
    printf( "Press A Key To Begin Test.\n" );
    tlGetCH();
  }
    
  grSstSelect( 0 );
  assert( grSstWinOpen(tlGethWnd(),
                       resolution,
                       GR_REFRESH_60Hz,
                       GR_COLORFORMAT_ABGR,
                       origin,
                       2, 1 ) );

  grVertexLayout(GR_PARAM_XY,  GR_VERTEX_X_OFFSET << 2, GR_PARAM_ENABLE);
  grVertexLayout(GR_PARAM_RGB, GR_VERTEX_R_OFFSET << 2, GR_PARAM_ENABLE);
  grVertexLayout(GR_PARAM_A,   GR_VERTEX_A_OFFSET << 2, GR_PARAM_ENABLE);

  grGet(GR_WDEPTH_MIN_MAX, 8, wrange);  
  grGet(GR_GLIDE_STATE_SIZE, 4, &state_size);
  oldState = malloc(state_size);        

  tlConSet( 0.0f, 0.0f, 1.0f, 1.0f,
           80, 40, 0xffffff );

  if(frames == -1) {
    doHelp();
  }

  localVerts[0].x = 0.f;
  localVerts[0].y = 0.75f;
  localVerts[0].z = 0.0f;
  localVerts[0].tmuvtx[0].sow = 255.f;
  localVerts[0].tmuvtx[0].tow = 255.f;
  localVerts[0].oow = 1.f;  
  localVerts[0].r = maxColor;
  localVerts[0].g = minColor;
  localVerts[0].b = minColor;
  localVerts[0].a = 255.f;

  localVerts[1].x = -0.75f;
  localVerts[1].y = -0.75f;
  localVerts[1].z = 0.0f;
  localVerts[1].tmuvtx[0].sow = 0.f;
  localVerts[1].tmuvtx[0].tow = 255.f;
  localVerts[1].oow = 1.f;  
  localVerts[1].r = minColor;
  localVerts[1].g = maxColor;
  localVerts[1].b = minColor;
  localVerts[1].a = 255.f;

  localVerts[2].x = 0.75f;
  localVerts[2].y = -0.75f;
  localVerts[2].z = 0.0f;
  localVerts[2].tmuvtx[0].sow = 255.f;
  localVerts[2].tmuvtx[0].tow = 0.f;
  localVerts[2].oow = 1.f;  
  localVerts[2].r = minColor;
  localVerts[2].g = minColor;
  localVerts[2].b = maxColor;
  localVerts[2].a = 255.f;

  texVerts[0].x = 0.f;
  texVerts[0].y = 0.f;
  texVerts[0].a = 255.f;
  texVerts[0].oow = 1.f;
  texVerts[0].tmuvtx[0].sow = 0.f * texVerts[0].oow;
  texVerts[0].tmuvtx[0].tow = 255.f * texVerts[0].oow;

  texVerts[1].x = scrWidth;
  texVerts[1].y = 0.f;
  texVerts[1].a = 255.f;
  texVerts[1].oow = 1.f;
  texVerts[1].tmuvtx[0].sow = 255.f * texVerts[1].oow;
  texVerts[1].tmuvtx[0].tow = 255.f * texVerts[1].oow;

  texVerts[2].x = scrWidth;
  texVerts[2].y = scrHeight;
  texVerts[2].a = 255.f;
  texVerts[2].oow = 1.f;
  texVerts[2].tmuvtx[0].sow = 255.f * texVerts[2].oow;
  texVerts[2].tmuvtx[0].tow = 0.f * texVerts[2].oow;
  
  texVerts[3].x = 0.f;
  texVerts[3].y = scrHeight;
  texVerts[3].a = 255.f;
  texVerts[3].oow = 1.f;
  texVerts[3].tmuvtx[0].sow = 0.f * texVerts[3].oow;
  texVerts[3].tmuvtx[0].tow = 0.f * texVerts[3].oow;
  
  if (bgFileName == NULL)
    bgFileName = "miro.3df";
  if (triFileName == NULL)
    triFileName = "matt1.3df";
  
  /* Read in background texture file  */
  if ( gu3dfGetInfo( bgFileName, &bgInfo ) )  {
    bgInfo.data = malloc( bgInfo.mem_required );

    if ( bgInfo.data == 0 ) {
      fprintf( stderr, "out of memory for texture file %s\n", bgFileName );
      grGlideShutdown();
      exit( -1 );
    }

    if ( !gu3dfLoad( bgFileName, &bgInfo ) ) {
      fprintf( stderr, "could not load texture file %s\n", bgFileName );
      grGlideShutdown();
      exit( -1 );
    }

    bgDecal.smallLodLog2    = bgInfo.header.small_lod;
    bgDecal.largeLodLog2    = bgInfo.header.large_lod;
    bgDecal.aspectRatioLog2 = bgInfo.header.aspect_ratio;
    bgDecal.data            = bgInfo.data;
    bgDecal.format          = bgInfo.header.format;
    grTexDownloadMipMap( GR_TMU0, startAddress, GR_MIPMAPLEVELMASK_BOTH, &bgDecal);
    grTexMipMapMode(GR_TMU0, GR_MIPMAP_NEAREST, FXTRUE);
    grTexClampMode( GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP);
    grTexFilterMode( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR );
    bgDecalAddress = startAddress;
    startAddress += grTexCalcMemRequired ( bgDecal.smallLodLog2, bgDecal.largeLodLog2, 
                                           bgDecal.aspectRatioLog2, bgDecal.format );
    free( bgInfo.data );
  } else {
    fprintf( stderr, "could not get info on %s\n", bgFileName );
    grGlideShutdown();
    exit( -1 );
  }
  
  if ( gu3dfGetInfo( triFileName, &triInfo ) )  {
    triInfo.data = malloc( triInfo.mem_required );
    
    if ( triInfo.data == 0 ) {
      fprintf( stderr, "out of memory for texture file  %s\n", triFileName );
      grGlideShutdown();
      exit( -1 );
    }
    
    if ( !gu3dfLoad( triFileName, &triInfo ) ) {
      fprintf( stderr, "could not load texture file %s\n", triFileName );
      grGlideShutdown();
      exit( -1 );
    }

    triDecal.smallLodLog2    = triInfo.header.small_lod;
    triDecal.largeLodLog2    = triInfo.header.large_lod;
    triDecal.aspectRatioLog2 = triInfo.header.aspect_ratio;
    triDecal.data            = triInfo.data;
    triDecal.format          = triInfo.header.format;
    grTexDownloadMipMap( GR_TMU0, startAddress, GR_MIPMAPLEVELMASK_BOTH, &triDecal);
    grTexMipMapMode(GR_TMU0, GR_MIPMAP_NEAREST, FXTRUE);
    grTexClampMode( GR_TMU0, GR_TEXTURECLAMP_WRAP, GR_TEXTURECLAMP_WRAP);
    grTexFilterMode( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR );
    triDecalAddress = startAddress;
    free( triInfo.data );
  } else {
    fprintf( stderr, "could not get info on %s\n", triFileName );
    grGlideShutdown();
    exit( -1 );
  }

  grTexCombine( GR_TMU0, GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE,
                GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, FXFALSE, FXFALSE );
  grRenderBuffer(backbuffer == FXTRUE ? GR_BUFFER_BACKBUFFER : GR_BUFFER_FRONTBUFFER);

  /* Set up alpha blending for AA and compositing... */
  grAlphaCombine( GR_COMBINE_FUNCTION_LOCAL, 
                  GR_COMBINE_FACTOR_NONE, 
                  GR_COMBINE_LOCAL_ITERATED, 
                  GR_COMBINE_OTHER_NONE, 
                  FXFALSE );
  grAlphaBlendFunction( GR_BLEND_SRC_ALPHA,
                       GR_BLEND_ONE_MINUS_SRC_ALPHA, GR_BLEND_ONE,
                       GR_BLEND_ZERO );
  grAlphaTestFunction( GR_CMP_ALWAYS );


  while ( 1 ) {
    Matrix rotm;
    GrVertex xformedVerts[VERT_COUNT];
    int i;

    
    MatMakeYRot( rotm, DEG2RAD( y_angle ) );
    
    if (resolution == GR_RESOLUTION_NONE) 
      tlGetResolutionConstant("0",
                              &scrWidth, 
                              &scrHeight );


    for( i = 0; i < VERT_COUNT; i++ ) {
      PointMatMult( &xformedVerts[i], &localVerts[i], rotm );
      xformedVerts[i].x = xformedVerts[i].x / ( xformedVerts[i].z + 2.0f );
      xformedVerts[i].y = xformedVerts[i].y / ( xformedVerts[i].z + 2.0f );
      xformedVerts[i].x *= scrWidth / 2.0f;
      xformedVerts[i].y *= scrHeight / 2.0f;
      xformedVerts[i].x += scrWidth / 2.0f;
      xformedVerts[i].y += scrHeight / 2.0f;
      xformedVerts[i].oow = 1.f / ((xformedVerts[i].z + 2) * scrHeight);
      xformedVerts[i].tmuvtx[0].sow *= xformedVerts[i].oow;
      xformedVerts[i].tmuvtx[0].tow *= xformedVerts[i].oow;
      SNAP_COORD( xformedVerts[i].x );
      SNAP_COORD( xformedVerts[i].y );
    }
    
    switch ( ccFnc )
      {
      case GR_COLORCOMBINE_ITRGB:
        grColorCombine( GR_COMBINE_FUNCTION_LOCAL, GR_COMBINE_FACTOR_NONE, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_NONE, FXFALSE );
        break;
        
      case GR_COLORCOMBINE_DECAL_TEXTURE:
        grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_ONE, GR_COMBINE_LOCAL_NONE, GR_COMBINE_OTHER_TEXTURE, FXFALSE );
        break;
        
      case GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB:
        grColorCombine( GR_COMBINE_FUNCTION_SCALE_OTHER, GR_COMBINE_FACTOR_LOCAL, GR_COMBINE_LOCAL_ITERATED, GR_COMBINE_OTHER_TEXTURE, FXFALSE );
        break;
      }
    
    /*    grLfbBypassMode(GR_LFBBYPASS_ENABLE); */

    if (render == FXTRUE) {
      ++frameNum;
      if ((frameNum % NFRAMES) == 0) {
        if (printPerf) {
          if (!firstTime)  {
            GrSstPerfStats_t
              pStats;
            FxU32
              lfbWritePixels,
              nFrames = frameNum - lastFrame,
              fillPixels = nFrames * screenFulls[resolution],
              totFail;
            
            lastFrame = frameNum;

            grGet(GR_STATS_PIXELS_IN,             4, &pStats.pixelsIn);
            grGet(GR_STATS_PIXELS_CHROMA_FAIL,    4, &pStats.chromaFail);
            grGet(GR_STATS_PIXELS_DEPTHFUNC_FAIL, 4, &pStats.zFuncFail);
            grGet(GR_STATS_PIXELS_AFUNC_FAIL,     4, &pStats.aFuncFail);
            grGet(GR_STATS_PIXELS_OUT,            4, &pStats.pixelsOut);
            grGet(GR_STATS_TRIANGLES_IN,          4, &trisProcessed);
            grGet(GR_STATS_TRIANGLES_OUT,         4, &trisDrawn);
            
            totFail = pStats.chromaFail + pStats.zFuncFail +
              pStats.aFuncFail;  
            
            lfbWritePixels = pStats.pixelsOut - pStats.pixelsIn - fillPixels;

            tlConOutput("In the last %d frames:\n", nFrames);
            tlConOutput("      Pixels Processed:               %d\n",
                        pStats.pixelsIn);
            tlConOutput("      Chroma Failures:                %d\n",
                        pStats.chromaFail);
            tlConOutput("      Z Compare Failures:             %d\n",
                        pStats.zFuncFail);
            tlConOutput("      Alpha Compare Failures:         %d\n",
                        pStats.aFuncFail);
            tlConOutput("      Fast Fill Pixels:               %d\n",
                        fillPixels);
            tlConOutput("      LFB Write Pixels:               %d\n",
                        lfbWritePixels);                   
            tlConOutput("      Total Pixels Drawn:             %d\n",
                        pStats.pixelsOut);
            tlConOutput("      Triangles Processed             %d\n",
                        trisProcessed);
            tlConOutput("      Triangles Drawn                 %d\n",
                        trisDrawn);

            if (
                (pStats.pixelsOut - lfbWritePixels - fillPixels - pStats.pixelsIn) != totFail)
              tlConOutput("Error:  %d != %d\n",
                          pStats.pixelsOut - lfbWritePixels - fillPixels,
                          totFail);

            grReset(GR_STATS_PIXELS);
          } else {
            lastFrame = frameNum;
            grReset(GR_STATS_PIXELS);
            firstTime = 0;
          }
        }
      }

      grBufferClear( 0xffffffff, 0, (FxU16)wrange[1] );
    
      if (background == FXTRUE) {

        texVerts[0].x = 0.f;
        texVerts[0].y = 0.f;

        texVerts[1].x = scrWidth;
        texVerts[1].y = 0.f;

        texVerts[1].x = scrWidth;
        texVerts[1].y = 0.f;

        texVerts[2].x = scrWidth;
        texVerts[2].y = scrHeight;

        texVerts[3].x = 0.f;
        texVerts[3].y = scrHeight;

        grGlideGetState(oldState);

        grVertexLayout(GR_PARAM_Q,   GR_VERTEX_OOW_OFFSET << 2, GR_PARAM_ENABLE);
        grVertexLayout(GR_PARAM_ST0, GR_VERTEX_SOW_TMU0_OFFSET << 2, GR_PARAM_ENABLE);

        grAlphaBlendFunction(
                             GR_BLEND_ONE, GR_BLEND_ZERO,
                             GR_BLEND_ONE, GR_BLEND_ZERO);

        grColorCombine(
                       GR_COMBINE_FUNCTION_SCALE_OTHER,
                       GR_COMBINE_FACTOR_ONE,
                       GR_COMBINE_LOCAL_NONE,
                       GR_COMBINE_OTHER_TEXTURE, FXFALSE
                       );

        grTexSource( GR_TMU0, bgDecalAddress, GR_MIPMAPLEVELMASK_BOTH, &bgDecal );
        
        for (i = 0; i < NTRIS; i++) {
          grDrawTriangle(&texVerts[0], &texVerts[1], &texVerts[2]);
          grDrawTriangle(&texVerts[2], &texVerts[3], &texVerts[0]);
        }
        grGlideSetState(oldState);
        grClipWindow(0, 0, (FxU32) scrWidth, (FxU32) scrHeight);

      }

      if (texturing == FXTRUE)
        grTexSource( GR_TMU0, bgDecalAddress, GR_MIPMAPLEVELMASK_BOTH, &bgDecal );

      if (texturing)
        grTexSource( GR_TMU0, triDecalAddress, GR_MIPMAPLEVELMASK_BOTH, &triDecal );

      if (antialias == FXTRUE) {
        grEnable(GR_AA_ORDERED);
        if (lines == FXTRUE) {
          grDrawLine(&xformedVerts[0], &xformedVerts[1]);
          grDrawLine(&xformedVerts[1], &xformedVerts[2]);
          grDrawLine(&xformedVerts[2], &xformedVerts[0]);
        } else {
          grAADrawTriangle(
                           &xformedVerts[0],  &xformedVerts[1],
                           &xformedVerts[2], FXTRUE, FXTRUE, FXTRUE
                           );
        }
      } else {
        grDisable(GR_AA_ORDERED);
        if (lines == FXTRUE) {
          grDrawLine(&xformedVerts[0], &xformedVerts[1]);
          grDrawLine(&xformedVerts[1], &xformedVerts[2]);
          grDrawLine(&xformedVerts[2], &xformedVerts[0]);
        } else {          
          grDrawTriangle(
                         &xformedVerts[0], &xformedVerts[1],
                         &xformedVerts[2]
                         );
        }
      }

      if (plugging) 
        grSplash(0.f, 0.f, scrWidth / 5.f, scrHeight / 5.f, frameNum);
      
      if (backbuffer) {
        tlConRender();
        grBufferSwap( swapDelay );
      }
    }
    
    if (tlKbHit()) {
      char c = (char) tlGetCH();
      
      switch (c) {
      case 'a':
      case 'A':
        if (antialias == FXFALSE) {
          tlConOutput("Turning ON Antialiasing\n");
          antialias = FXTRUE;
        } else {
          tlConOutput("Turning OFF Antialiasing\n");
          antialias = FXFALSE;
        }
        break;
      case 'B':
      case 'b':
        if (bilinear == FXFALSE) {
          bilinear = FXTRUE;
          tlConOutput("Turning ON BiLinear blending\n");
          grTexFilterMode ( GR_TMU0, GR_TEXTUREFILTER_BILINEAR, GR_TEXTUREFILTER_BILINEAR );
        } else {
          bilinear = FXFALSE;
          tlConOutput("Turning OFF BiLinear blending\n");
          grTexFilterMode ( GR_TMU0, GR_TEXTUREFILTER_POINT_SAMPLED, 
                          GR_TEXTUREFILTER_POINT_SAMPLED );
        }
        break;

      case 'c':
      case 'C':
        if (blend == FXTRUE) {
                  int i;
          blend = FXFALSE;
                  for(i=0;i<VERT_COUNT;i++) localVerts[i].a = 255.0f;
        } else {
                  int i;
          blend = FXTRUE;
          for(i=0;i<VERT_COUNT;i++) localVerts[i].a = alpha;
        }
        break;

      case 'd':
      case 'D':
        tlConOutput("vtxa = (%.2f, %.2f), vtxb = (%.2f, %.2f), vtxc = (%.2f, %.2f)\n",
                    xformedVerts[0].x, xformedVerts[0].y,
                    xformedVerts[1].x, xformedVerts[1].y,
                    xformedVerts[2].x, xformedVerts[2].y
                    );
        break;

      case 'f':
      case 'F':
        if (backbuffer == FXTRUE) {
          backbuffer = FXFALSE;
          grRenderBuffer(GR_BUFFER_FRONTBUFFER);
        } else {
          backbuffer = FXTRUE;
          grRenderBuffer(GR_BUFFER_BACKBUFFER);
        }
        break;

      case 'g':
      case 'G':
#if 0
        grLfbBegin();

        grLfbWriteMode(GR_LFBWRITEMODE_565);
        grLfbOrigin(GR_ORIGIN_UPPER_LEFT);
        grLfbGetReadPtr(GR_BUFFER_FRONTBUFFER);
        tlConOutput("Press a key to get front buffer\n");
        while (!tlKbHit());
        c = (char) tlGetCH();
        guFbReadRegion(0,0,(int)wWidth,(int)scrHeight,scrnImage,(int)wWidth * sizeof(FxU16));
        tlConOutput("Press a key to put image in back buffer and swap\n");
        while (!tlKbHit());
        tlGetCH();

        grLfbGetWritePtr(GR_BUFFER_BACKBUFFER);
        guFbWriteRegion(0,0,(int)wWidth,(int)scrHeight,scrnImage,(int)wWidth * sizeof(FxU16));
        grBufferSwap(swapDelay);

        tlConOutput("Press a key to continue...\n");
        while (!tlKbHit());
        tlGetCH();

        grLfbEnd();
#endif
        break;

      case 'h':
      case 'H':
      case '?':
        doHelp();
        break;

      case 'i':
      case 'I':
        if (background == FXTRUE) {
          background = FXFALSE;
          tlConOutput("Turning off background\n");
        } else {
          tlConOutput("Turning on background\n");
          background = FXTRUE;
        }
        break;

      case 'l':
      case 'L':
        if (lines == FXTRUE) {
          lines = FXFALSE;
          tlConOutput("Turning OFF lines\n");
        } else {
          lines = FXTRUE;
          tlConOutput("Turning ON lines\n");
        }
        break;
      case 'm':
      case 'M':
        ccFnc = GR_COLORCOMBINE_TEXTURE_TIMES_ITRGB;
        break;

      case 'n':
      case 'N':
        if (printPerf == FXFALSE) {
          printPerf = FXTRUE;
          firstTime = 1;
          grReset(GR_STATS_PIXELS);
          grReset(GR_STATS_TRIANGLES);
        } else {
          printPerf= FXFALSE;
        }
        break;

      case 'o':
      case 'O':
        if (origin == GR_ORIGIN_LOWER_LEFT)
          origin = GR_ORIGIN_UPPER_LEFT;
        else
          origin = GR_ORIGIN_LOWER_LEFT; 

        grSstOrigin(origin);
        break;

      case 'p':
      case 'P':
        if (render == FXTRUE)
          render = FXFALSE;
        else
          render = FXTRUE;
        break;
        
      case 'q':
      case 'Q':
      case 27:
        grGlideShutdown();
        exit(0);
        break;

      case 'r':
      case 'R':
        tlConOutput("Screen Resolution is %s\n", tlGetResolutionString( resolution ) );
        break;

      case 'S':
      case 's':
        if (cullMode == GR_CULL_DISABLE) {
          cullMode = GR_CULL_NEGATIVE;
          tlConOutput("Turning ON backface culling (hidden Surface removal)\n");
        } else  {
          cullMode = GR_CULL_DISABLE;
          tlConOutput("Turning OFF backface culling (hidden Surface removal)\n");
        }
        grCullMode(cullMode);
        break;
      case 'T':
      case 't':
        if (texturing == FXFALSE) {
          tlConOutput("Turning ON texturing\n");
          ccFnc = GR_COLORCOMBINE_DECAL_TEXTURE;
          texturing = FXTRUE;
          grVertexLayout(GR_PARAM_Q,   GR_VERTEX_OOW_OFFSET << 2, GR_PARAM_ENABLE);
          grVertexLayout(GR_PARAM_ST0, GR_VERTEX_SOW_TMU0_OFFSET << 2, GR_PARAM_ENABLE);
        } else {
          tlConOutput("Turning OFF texturing\n");
          ccFnc = GR_COLORCOMBINE_ITRGB;
          texturing = FXFALSE;
          grVertexLayout(GR_PARAM_Q,   GR_VERTEX_OOW_OFFSET << 2, GR_PARAM_DISABLE);
          grVertexLayout(GR_PARAM_ST0, GR_VERTEX_SOW_TMU0_OFFSET << 2, GR_PARAM_DISABLE);
        }
        break;
      case 'u':
      case 'U':
        if (plugging == FXTRUE) {
          plugging = FXFALSE;
          grDisable(GR_SHAMELESS_PLUG);
        }
        else {
          plugging = FXTRUE;
          grEnable(GR_SHAMELESS_PLUG);
        }
        break;
        
      case '1':
      case '2':
      case '3':
      case '4':
      case '5':
      case '6':
      case '7':
      case '8':
      case '9':
      case '0':
        {
          char str[256];
          swapDelay = (int) c - 0x30;
          sprintf(str, "Swapdelay = %d\n", swapDelay);
          tlConOutput(str);
        }
        break;
      }
    }
    
    if (render) {
      y_angle += 2.f;
      if( y_angle > 360.0f )
        y_angle -= 360.0f;
    }
    frameCount++;
    if(frameCount < 0)
      frameCount = 0;
    if(frames == frameCount)
      break;
  }
  grGlideShutdown();
}