home *** CD-ROM | disk | FTP | other *** search
/ MacFormat España 21 / macformat_21.iso / Shareware / Programación / VideoToolbox / (Demos) / TestGDVideo.c < prev    next >
C/C++ Source or Header  |  1996-03-05  |  17KB  |  492 lines

  1. /* 
  2. TestGDVideo.c by Denis G. Pelli
  3. Tests all the documented Control and Status calls implemented in GDVideo.c
  4. The calls are documented in Designing Cards and Drivers, 3rd Edition.
  5.  
  6. The main purpose of this program is to find bugs in video drivers. If you do
  7. find a bug that isn't already listed in the table at the end of “Video synch”
  8. then please send it to denis@xp.psych.nyu.edu 
  9.  
  10. Unfortunately, the most common way to discover a new bug is for this program to
  11. crash. Please report crashes to denis@xp.psych.nyu.edu
  12.  
  13. BUGS:
  14.  
  15. HISTORY:
  16. 8/11/89    dgp    wrote it
  17. 3/23/90    dgp    introduced special case conditionals to skip tests known to crash
  18.             particular drivers.
  19. 3/23/90    dgp    made it compatible with MPW C, as a tool.
  20. 3/24/90    dgp    made some of the printouts less cryptic.
  21. 3/31/90    dgp    introduced RestoreDeviceClut after SetMode call.
  22. 7/12/90    dgp    tidied up the initial printf
  23. 7/19/90    dgp    Renamed VideoTest.c 
  24.             Open & close a window on each screen and DrawMenuBar()
  25.             so that QuickDraw will restore each screen.
  26. 7/28/90    dgp    italicized name of book.
  27. 9/9/90    dgp    Added quit by Command-. for graceful exit from bad situations.
  28. 10/17/90 dgp Removed unused variables. Replaced TRUE & FALSE by 1 & 0.
  29. 10/20/90    dgp    Apple has renamed the control and status calls, so I followed suit:
  30.                 GDGetPageBase replaces GDGetBaseAddr
  31.                 GDReset replaces GDInit
  32.                 GDGrayPage replace GDGrayScreen
  33.                 GDGetPageCnt replaces GDGetPages
  34. 10/22/90 dgp Print out number of pages for all modes, not just current mode.
  35.          dgp Restore clut manually since RestoreDeviceClut() doesn't
  36.              work on NuVista.
  37. 10/28/90 dgp Only test GetInterrupt & SetInterrupt if System is 6.05 or higher. This
  38.             avoids SetInterrupt() crash on old Apple TFB video driver.
  39. 2/12/91    dgp    Preceded GDGrayPage() call by GDSetMode() to cure crash when running
  40.             program immediately after rebooting. Mysterious.
  41.             Added SelectWindow() at end of program.
  42. 3/9/91    dgp    Print out mode names.
  43. 4/15/91    dgp    Make sure that new palette manager exists before calling RestoreDeviceClut.
  44.             Thanks to Chuck Stein for alerting me to the bug.
  45. 6/6/91    dgp    Time and print out how long GDSetEntries takes.
  46. 8/24/91    dgp    Made compatible with THINK C 5.0.
  47. 1/19/92    dgp    Cosmetic improvements to the printout.
  48. 2/25/92    dgp    Put timing info in bold.
  49. 8/22/92    dgp Display results of calling GDFrameRate() and GDFramesPerClutUpdate().
  50. 8/27/92    dgp    replace SysEnvirons() by Gestalt()
  51. 12/17/92 dgp enhanced to work with any dac size.
  52. 12/30/92 dgp Use GDClutSize() to determine clut size.
  53. 1/6/93    dgp    Tidied up the cscGetEntries/cscSetEntries code, now that we don't have
  54.             to test for the Mac IIci driver.
  55.             Skip cscGetEntries on Relax driver.
  56. 1/7/93 dgp    1.1 First numbered version.
  57. 1/18/93    dgp    Renamed ModeName() to GDModeName().
  58. 1/18/93    dgp    Moved the code that checked for bad drivers into GDGetEntries() in GDVideo.c,
  59.             where it belongs.
  60. 2/1/93    dgp Report whether driver is RAM- or ROM-based.
  61. 2/5/93    dgp    1.2. Recompiled with latest version of GDVideo, which now supports
  62.             patching of Mac IIci ROM-based driver.
  63. 2/6/93    dgp    1.3. Report ROM version, if driver is ROM-based.
  64. 2/7/93    dgp    1.4. Recompiled after fixing endless loop in PatchMacIIciVideoDriver
  65.             in GDVideo.c
  66. 2/18/93    dgp    1.5 Made compatible with PowerBook 160, by omitting call to GDSetInterrupt.
  67. 2/22/93    dgp    1.6 No longer assume that driver uses a version 0 gamma table.
  68. 4/17/93    dgp    1.7 Replaced obsolete GDFramesPerClutUpdate and GDTimeClutUpdate by 
  69.             GDTimeClut.
  70. 7/7/93    dgp    1.8 A bit more error checking of GDGetGamma.
  71. 7/29/94 dgp Eliminated use of "#s" printf format, since it's not supported by
  72.             Metrowerks CodeWarrior C.
  73. 9/5/94 dgp removed assumption in printf's that int==short.
  74. 5/22/95 dgp fixed minor bug reported by Michael Pelikan:
  75.             systemVersion was never properly initialized.
  76. */
  77. #include "VideoToolbox.h"
  78. //#include <Files.h>
  79. //#include <Menus.h>
  80. #if UNIVERSAL_HEADERS
  81.     #include <LowMem.h>
  82. #else
  83.     #define LMGetMBarHeight() (* (short *) 0x0BAA)
  84.     #define LMSetMBarHeight(MBarHeightValue) ((* (short *) 0x0BAA) = (MBarHeightValue))
  85. #endif
  86. #if UNIVERSAL_HEADERS<2
  87.     enum{dRAMBasedMask=0x0040};    /* dCtlDriver is a handle (1) or pointer (0) */
  88. #endif
  89. int PatchMacIIciVideoDriver(void);
  90. void GammaReport(GammaTbl *gamma);
  91. void main(void);
  92. void TestGDVideo(void);
  93. static void Error(int error);
  94. #define VERSION "1.8"
  95. #define SCREENS 8
  96. static Boolean printGammaTable=0;    // Set this to 1 to enable printing of gamma table.
  97.  
  98. void main(void)
  99. {
  100.     StackGrow(20000);
  101.     Require(gestalt8BitQD);
  102.     TestGDVideo();
  103. }
  104.     
  105. CWindowPtr cw;            // just for poking around in the debugger
  106. GDHandle mainDevice;    // just for poking around in the debugger
  107. void TestGDVideo(void)
  108. {
  109.     WindowPtr window[SCREENS],oldPort;
  110.     static ColorSpec myTable[1024];    // Enough for 10-bit dacs
  111.     ColorSpec black={0,0,0,0};
  112.     WindowPtr theWindow;
  113.     GDHandle device;
  114.     short i,error,screen,mode,page,pages,start,count,pixelSize,type,clutSize;
  115.     short textSize=12,dacSize,dataSize,dataCnt,fontNumber,where;
  116.     short gammaDataWidth;
  117.     long systemVersion=0;
  118.     Boolean flag,keepWaiting;
  119.     GammaTbl *gamma=NULL,*myGamma=NULL;
  120.     char *name;
  121.     Ptr baseAddr;
  122.     Rect myRect;
  123.     double f;
  124.     unsigned char *byte;
  125.     unsigned short *word;
  126.     Boolean patch;
  127.     char typeName[][16]={"clutType","fixedType","directType"};
  128.     AuxDCE **auxDCEHandle;
  129.     long size;
  130.     Ptr ptr;
  131.     long romSize,romVersion;
  132.     double s,frames,missingFrames,frameRate;
  133.     EventRecord event;
  134.     
  135.     InitGraf(&qd.thePort);
  136.     InitFonts();
  137.     InitWindows();
  138.     InitCursor();
  139.     GetPort(&oldPort);
  140.     _atexit(RestoreCluts);
  141.     patch=PatchMacIIciVideoDriver();
  142.     Gestalt(gestaltSystemVersion,&systemVersion);
  143.     for(screen=0;screen<SCREENS;screen++){
  144.         SetPort(oldPort);
  145.         device = GetScreenDevice(screen);
  146.         if(device == NULL) break;
  147.  
  148.         /*
  149.         For reasons that I don't understand, calling cscGrayPage() first,
  150.         immediately after rebooting, results in a crash when using an Apple's
  151.         old "Toby" video card. Preceding the call by
  152.         a call to cscSetMode() cures the symptom. Later calls to cscGrayPage()
  153.         seem to always work fine. Presumably something is not properly initialized
  154.         in the Apple video card driver. (Toby card driver version 4.)
  155.         */
  156.         error=GDGetMode(device,&mode,&page,&baseAddr);
  157.         error=GDSetMode(device,mode,page,&baseAddr);
  158.         GDRestoreDeviceClut(device);
  159.         
  160.         error=GDGrayPage(device,page);
  161.         if(screen==0)DrawMenuBar();    /* restore menu bar after GrayScreen */
  162.  
  163.         /* Open window */
  164.         myRect = (*device)->gdRect;    /* rect of desired screen in global coordinates */
  165.         if(screen==0)myRect.top+=LMGetMBarHeight();    /* allow for menu bar */
  166.         myRect.top+=17;                                /* allow for title bar */
  167.         InsetRect(&myRect,1,1);
  168.         name=GDCardName(device);
  169.         c2pstr(name);
  170.         window[screen]=
  171.             NewCWindow(NULL,&myRect,(unsigned char *)name,TRUE,documentProc,(WindowPtr) -1L,TRUE,123L);
  172.         cw=(CWindowPtr)window[screen];    // just for poking around in the debugger
  173.         mainDevice=GetMainDevice();        // just for poking around in the debugger
  174.         /* Write in window */
  175.         SetPort(window[screen]);
  176.         myRect=window[screen]->portRect;
  177.         GetFNum("\pTimes",&fontNumber);
  178.         TextFont(fontNumber);
  179.         TextSize(textSize);
  180.         DrawPrintf("\n");
  181.         if(screen==0)DrawPrintf("Welcome to TestGDVideo " VERSION ". Now testing all your video drivers."
  182.         " Please report any crash to denis@xp.psych.nyu.edu\n");
  183.  
  184.         DrawPrintf("Driver: %s version %d",GDNameStr(device),(int)GDVersion(device));
  185.         auxDCEHandle = (AuxDCE **) GetDCtlEntry((*device)->gdRefNum);
  186.         if((**auxDCEHandle).dCtlFlags & dRAMBasedMask){
  187.             /* RAM-based driver. */
  188.             size=GetHandleSize((Handle)(**auxDCEHandle).dCtlDriver);
  189.             DrawPrintf(", occupying %ld bytes in RAM.",size);
  190.         }else{
  191.             /* ROM-based driver. */
  192.             ptr=(**auxDCEHandle).dCtlDriver;
  193.             Gestalt(gestaltROMSize,&romSize);
  194.             Gestalt(gestaltROMVersion,&romVersion);
  195.             DrawPrintf(", at 0x%lx in ROM. %ld K ROM version %ld (%ld)."
  196.                 ,ptr,romSize/1024,romVersion%256,(romVersion/256));
  197.         }
  198.         DrawPrintf("\n");
  199.         if(GetDeviceSlot(device)>=0)DrawPrintf("Slot: %d\n",(int)GetDeviceSlot(device));
  200.         else DrawPrintf("Slot: none\n");
  201.     
  202.         DrawPrintf("GrayPage: ");
  203.         if(error) Error(error);
  204.         else DrawPrintf("ok\n");
  205.  
  206.         DrawPrintf("cscGetMode: ");
  207.         error=GDGetMode(device,&mode,&page,&baseAddr);
  208.         if(error) Error(error);
  209.         else DrawPrintf("%d-bit mode, page %d base address 0x%lX\n"
  210.             ,(int)GDPixelSize(device),(int)page,baseAddr);
  211.     
  212.         DrawPrintf("cscSetMode: ");
  213.         error=GDSetMode(device,mode,page,&baseAddr);
  214.         if(error) Error(error);
  215.         else DrawPrintf("ok\n");
  216.  
  217.         /* 
  218.             GDSetMode has the annoying side effect of 
  219.             setting the clut to uniform gray, so let's restore the clut.
  220.         */
  221.         GDRestoreDeviceClut(device);
  222.  
  223.         for(i=0x80;i<=0x85;i++){
  224.             pixelSize=GDModePixelSize(device,i);
  225.             if(pixelSize>0){
  226.                 DrawPrintf("cscGetPageCnt: ");
  227.                 error=GDGetPageCnt(device,i,&pages);
  228.                 if(error)DrawPrintf("%d-bit mode n/a\n",(int)pixelSize);
  229.                 else DrawPrintf("%d-bit mode has %d pages available\n",(int)pixelSize,(int)pages);
  230.             }
  231.         }
  232.  
  233.         DrawPrintf("cscGetPageBase: ");
  234.         page=0;    /* Ask for first page */
  235.         error=GDGetPageBase(device,page,&baseAddr);
  236.         if(error) Error(error);
  237.         else DrawPrintf("%d-bit mode, page %d base address 0x%lX\n"
  238.             ,(int)GDModePixelSize(device,mode),(int)page,baseAddr);
  239.         if(pages>1){
  240.             DrawPrintf("cscGetPageBase: ");
  241.             page=1;    /* Ask for second page */
  242.             error=GDGetPageBase(device,page,&baseAddr);
  243.             if(error) Error(error);
  244.             else DrawPrintf("%d-bit mode, page %d base address 0x%lX\n"
  245.                 ,(int)GDModePixelSize(device,mode),(int)page,baseAddr);
  246.         }
  247.     
  248.         DrawPrintf("cscGetGray: ");
  249.         error=GDGetGray(device,&flag);
  250.         if(error) Error(error);
  251.         else DrawPrintf("flag %d\n",(int)flag);
  252.     
  253.         DrawPrintf("cscSetGray: ");
  254.         flag=0;
  255.         error=GDSetGray(device,flag);
  256.         if(error) Error(error);
  257.         else DrawPrintf("ok\n");
  258.     
  259.         /* GetInterrupt crashes the NuVista driver.  */
  260.         if(!EqualString("\p.Display_Video_NuVista",GDName(device),0,0)){
  261.             /* SetInterrupt crashes the old Apple driver.  */
  262.             if(systemVersion>=0x605){
  263.                 DrawPrintf("cscGetInterrupt: ");
  264.                 error=GDGetInterrupt(device,&flag);
  265.                 if(error) Error(error);
  266.                 else DrawPrintf("%d\n",(int)flag);
  267.         
  268.                 if(0){
  269.                     // disabled 'cause it crashes built-in video on PowerBook 160
  270.                     DrawPrintf("cscSetInterrupt: ");
  271.                     error=GDSetInterrupt(device,flag);
  272.                     if(error) Error(error);
  273.                     else DrawPrintf("ok\n");
  274.                 }
  275.             }
  276.             else DrawPrintf("•••••Skipping GetInterrupt & SetInterrupt.\n");
  277.         }
  278.         else DrawPrintf("•••••Skipping GetInterrupt & SetInterrupt to avoid known bug in %s.\n",GDCardName(device));
  279.  
  280.         DrawPrintf("cscGetGamma: ");
  281.         gamma=NULL;
  282.         error=GDGetGamma(device,&gamma);
  283.         if(error) Error(error);
  284.         else GammaReport(gamma);
  285.         if(!error && gamma!=NULL)gammaDataWidth=gamma->gDataWidth;
  286.         else gammaDataWidth=0;
  287.         
  288.         DrawPrintf("cscSetGamma: ");
  289.         if(gamma==NULL || gamma->gDataWidth==0){
  290.             // Get the dac's size from the current gamma table.
  291.             if(gamma!=NULL && gamma->gDataWidth!=0){
  292.                 dacSize=gamma->gDataWidth;
  293.                 dataCnt=gamma->gDataCnt;
  294.             }else{ // The driver won't tell us, so assume 8-bit dacs.
  295.                 dacSize=8;
  296.                 dataCnt=1L<<dacSize;
  297.             }
  298.             if(dacSize<=8)dataSize=1;
  299.             else dataSize=2;
  300.             myGamma=(GammaTbl *)NewPtr(sizeof(GammaTbl)+dataCnt*dataSize);
  301.             assert(myGamma!=NULL);
  302.             myGamma->gVersion=0;
  303.             myGamma->gType=0;
  304.             myGamma->gFormulaSize=0;
  305.             myGamma->gChanCnt=1;
  306.             myGamma->gDataCnt=dataCnt;
  307.             myGamma->gDataWidth=dacSize;
  308.             byte=(unsigned char *)myGamma->gFormulaData+myGamma->gFormulaSize;
  309.             word=(unsigned short *)byte;
  310.             if(myGamma->gDataWidth<=8)
  311.                 for(i=0;i<myGamma->gDataCnt;i++) byte[i]=i;
  312.             else
  313.                 for(i=0;i<myGamma->gDataCnt;i++) word[i]=i;
  314.             gamma=myGamma;
  315.         }else myGamma=NULL;
  316.         error=GDSetGamma(device,gamma);
  317.         if(error) Error(error);
  318.         else DrawPrintf("ok.\n");
  319.         if(myGamma!=NULL){
  320.             DisposPtr((Ptr)myGamma);
  321.             myGamma=NULL;
  322.         }
  323.  
  324.     DrawPrintf("cscGetGamma: ");
  325.     gamma=NULL;
  326.     error=GDGetGamma(device,&gamma);
  327.     if(error) Error(error);
  328.     else GammaReport(gamma);
  329.     if(!error && gamma!=NULL)gammaDataWidth=gamma->gDataWidth;
  330.     else gammaDataWidth=0;
  331.     
  332.         // cscGetEntries
  333.         start=0;
  334.         count=GDClutSize(device)-1;
  335.         if(count>sizeof(myTable)/sizeof(myTable[0])-1)
  336.             count=sizeof(myTable)/sizeof(myTable[0])-1;
  337.         DrawPrintf("cscGetEntries: ");
  338.         error=GDGetEntries(device,start,count,myTable);
  339.         if(error)Error(error);
  340.         else DrawPrintf("ok\n");
  341.         
  342.         // cscSetEntries
  343.         count=GDClutSize(device)-1;
  344.         switch((*device)->gdType){
  345.             case clutType:
  346.                 DrawPrintf("cscSetEntries: ");
  347.                 error=GDSetEntries(device,0,count,((**(**(**device).gdPMap).pmTable)).ctTable);
  348.                 if(error)Error(error);
  349.                 else DrawPrintf("ok\n");
  350.                 break;
  351.             case directType:
  352.                 DrawPrintf("DirectSetEntries: ");
  353.                 error=GDDirectSetEntries(device,0,0,&black);
  354.                 if(error)Error(error);
  355.                 else DrawPrintf("ok\n");
  356.                 break;
  357.             case fixedType:
  358.                 DrawPrintf("A fixedType clut cannot be modified.\n");
  359.                 break;
  360.         }
  361.         
  362.         // Miscellaneous
  363.         clutSize=GDClutSize(device);
  364.         pixelSize=1<<(mode&7);
  365.         type=(*device)->gdType;
  366.         DrawPrintf("Currently in mode %d, pixelSize %d bits, clutSize %d entries, %s"
  367.             ,(int)mode,(int)pixelSize,(int)clutSize,typeName[type]);
  368.         if(gammaDataWidth!=0)DrawPrintf(", dacSize %d bits",(int)gammaDataWidth);
  369.         DrawPrintf(".\n");
  370.  
  371.         TextFace(bold);
  372.         f=GDFrameRate(device);
  373.         DrawPrintf("%.1f Hz frame rate (%.1f ms).\n",f,1000.0/f);
  374.         if((*device)->gdType!=fixedType){
  375.             if((*device)->gdType==clutType)name="cscSetEntries";
  376.             else name="cscDirectSetEntries";
  377.             error=GDTimeClut(device,GDSetEntries,0
  378.                 ,&s,&frames,&missingFrames,&frameRate);
  379.             DrawPrintf("Repeatedly loading the clut, by calling %s(), "
  380.                 "takes %.2f frame each time.\n",name,frames);
  381.             DrawPrintf("%.1f Hz clut update rate (%.1f ms).\n",1.0/s,1000.0*s);
  382.         }
  383.         TextFace(0);
  384.         
  385.         if(0){
  386.             /* I haven't found any use for these calls, so skip 'em */
  387.             DrawPrintf("cscGetDefaultMode: ");
  388.             error=GDGetDefaultMode(device,&mode);
  389.             if(error) Error(error);
  390.             else DrawPrintf("0x%X\n",mode);
  391.         
  392.             DrawPrintf("cscSetDefaultMode: ");
  393.             error=GDSetDefaultMode(device,mode);
  394.             if(error) Error(error);
  395.             else DrawPrintf("ok\n");
  396.         }
  397.         if(patch && EqualString("\p.Display_Video_Apple_RBV1",GDName(device),TRUE,FALSE))
  398.             DrawPrintf(
  399.             "This Mac IIci video driver has been patched (until reboot) to fix a bug\n"
  400.             "that prevents reading the clut. The version number was changed from 0 to %d.\n"
  401.             ,(int)GDVersion(device));
  402.     }
  403.     SelectWindow(window[0]);
  404.     SetPort(window[0]);
  405.     DrawPrintf(
  406.         "This completes the test of the known Control and Status calls for each\n"
  407.         "of your video devices. For an explanation of what these calls do, see\n"
  408.         "Apple’s book ");
  409.     TextFace(italic);
  410.     DrawPrintf("Designing Cards and Drivers,");
  411.     TextFace(0);
  412.     DrawPrintf(" 3rd Ed., Addison Wesley, Chapter 9.\n");
  413.     TextFace(bold);
  414.     DrawPrintf("Quit by closing any window, or hitting Command-.\n");
  415.     do{
  416.         keepWaiting=1;
  417.         while(!GetNextEvent(mDownMask+keyDownMask,&event)) ;
  418.         switch(event.what){
  419.         case mouseDown:
  420.             where=FindWindow(event.where,&theWindow);
  421.             switch(where){
  422.             case inContent:
  423.             case inDrag:
  424.             case inGrow:
  425.             case inGoAway:
  426.                 SelectWindow(theWindow);
  427.             }
  428.             if(where==inGoAway) keepWaiting = !TrackGoAway(theWindow,event.where);
  429.             break;
  430.         case keyDown:
  431.             if(event.modifiers & cmdKey) switch(event.message & charCodeMask) {
  432.                 case '.':
  433.                 case 'w':
  434.                 keepWaiting=0;
  435.             }
  436.             break;
  437.         }
  438.     } while (keepWaiting);
  439.     SetPort(oldPort);
  440.     for(i=0;i<screen;i++)DisposeWindow(window[i]);
  441.     _exit(0);
  442. }
  443.  
  444. void GammaReport(GammaTbl *gamma)
  445. {
  446.     short i,j,newFontNumber,fontNumber,textSize;
  447.     unsigned char *byte;
  448.     unsigned short *word;
  449.     WindowPtr window;
  450.  
  451.     if(gamma==NULL)DrawPrintf("error--NULL gamma table pointer\n");
  452.     else{
  453.         DrawPrintf("gamma table @%lx indicates that the video card has %d-bit dacs, "
  454.         "and %d entries in its clut.\n"
  455.         ,gamma,(int)gamma->gDataWidth,(int)gamma->gDataCnt);
  456.         DrawPrintf("gVersion %d, gType %d, gFormulaSize %d, gChanCnt %d\n"
  457.         ,(int)gamma->gVersion,(int)gamma->gType,(int)gamma->gFormulaSize,(int)gamma->gChanCnt);
  458.         if(printGammaTable && gamma->gVersion==0 && gamma->gType==0){
  459.             GetFNum("\pMonaco",&newFontNumber);
  460.             GetPort(&window);
  461.             fontNumber=window->txFont;
  462.             textSize=window->txSize;
  463.             TextFont(newFontNumber);
  464.             TextSize(9);
  465.             byte=(unsigned char *)gamma->gFormulaData+gamma->gFormulaSize;
  466.             word=(unsigned short *)byte;
  467.             DrawPrintf("Gamma Table:\n");
  468.             for(i=0;i<gamma->gDataCnt;i+=64) {
  469.                 DrawPrintf("%3d: ",i);
  470.                 if(gamma->gDataWidth<=8)
  471.                     for(j=0;j<64;j++) DrawPrintf(" %3u",byte[i+j]);
  472.                 else
  473.                     for(j=0;j<64;j++) DrawPrintf(" %3u",word[i+j]);
  474.                 DrawPrintf("\n");
  475.             }
  476.             TextFont(fontNumber);
  477.             TextSize(textSize);
  478.         }
  479.     }
  480. }
  481.  
  482. static void Error(int error)
  483. {
  484.     switch(error){
  485.     case -17:
  486.     case -18:
  487.         DrawPrintf("n/a\n");
  488.         break;
  489.     default:
  490.         DrawPrintf("error %d\n",error);
  491.     }
  492. }