home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / DKBSRC.ZIP / IBM.C < prev    next >
C/C++ Source or Header  |  1991-05-04  |  36KB  |  1,081 lines

  1. /*****************************************************************************
  2. *
  3. *                                      ibm.c
  4. *
  5. *   from DKBTrace (c) 1990  David Buck
  6. *
  7. *  This module implements the IBM-specific routines for DKBTrace.
  8. *
  9. * This software is freely distributable. The source and/or object code may be
  10. * copied or uploaded to communications services so long as this notice remains
  11. * at the top of each file.  If any changes are made to the program, you must
  12. * clearly indicate in the documentation and in the programs startup message
  13. * who it was who made the changes. The documentation should also describe what
  14. * those changes were. This software may not be included in whole or in
  15. * part into any commercial package without the express written consent of the
  16. * author.  It may, however, be included in other public domain or freely
  17. * distributed software so long as the proper credit for the software is given.
  18. *
  19. * This software is provided as is without any guarantees or warranty. Although
  20. * the author has attempted to find and correct any bugs in the software, he
  21. * is not responsible for any damage caused by the use of the software.  The
  22. * author is under no obligation to provide service, corrections, or upgrades
  23. * to this package.
  24. *
  25. * Despite all the legal stuff above, if you do find bugs, I would like to hear
  26. * about them.  Also, if you have any comments or questions, you may contact me
  27. * at the following address:
  28. *
  29. *     David Buck
  30. *     22C Sonnet Cres.
  31. *     Nepean Ontario
  32. *     Canada, K2H 8W7
  33. *
  34. *  I can also be reached on the following bulleton boards:
  35. *
  36. *     ATX              (613) 526-4141
  37. *     OMX              (613) 731-3419
  38. *     Mystic           (613) 731-0088 or (613) 731-6698
  39. *
  40. *  Fidonet:   1:163/109.9
  41. *  Internet:  David_Buck@Carleton.CA
  42. *  The "You Can Call Me RAY" BBS    (708) 358-5611
  43. *
  44. *  IBM Port by Aaron A. Collins. Aaron may be reached on the following BBS'es:
  45. *
  46. *     The "You Can Call Me RAY" BBS (708) 358-5611
  47. *     The Information Exchange BBS  (708) 945-5575
  48. *
  49. *****************************************************************************/
  50.  
  51. /* Original IBM VGA "colour" output routines for MS/DOS by Aaron A. Collins.
  52.  
  53.    This will deliver approximate colorings using HSV values for the selection.
  54.    The pallette map is divided into 4 parts - upper and lower half generated
  55.    with full and half "value" (intensity), respectively.  These halves are
  56.    further halved by full and half saturation values of each range (pastels).
  57.    There are three constant colors, black, white, and grey.  They are used
  58.    when the saturation is low enough that the hue becomes undefined, and which
  59.    one is selected is based on a simple range map of "value".  Usage of the
  60.    pallette is accomplished by converting the requested color RGB into an HSV
  61.    value.  If the saturation is too low (< .25) then black, white or grey is
  62.    selected.  If there is enough saturation to consider looking at the hue,
  63.    then the hue range of 1-63 is scaled into one of the 4 pallette quadrants
  64.    based on its "value" and "saturation" characteristics.
  65.  
  66.    Further SVGA, MVGA mods by Aaron A. Collins:
  67.    SVGA, MVGA assembler routines originally by John Bridges.
  68.    VESA assembler routines from FRACTINT, by The Stone Soup Group
  69.    AT&T VDC600 SVGA mods to DKB Trace 2.01 module IBM.C by John Gooding
  70.  
  71.    This file now represents the collective wisdom of the VGAKIT34 package,
  72.    with support for all of the SVGA types known to mankind.  Seriously,
  73.    VGAKIT34 is an excellent technical reference for IBM programmers wishing
  74.    to do any sort of SVGA video access, and it encompasses nearly all of the
  75.    SVGA adapters in use today.  It was written by John Bridges, a.k.a.
  76.    CIS:73307,606, GENIE:J.BRIDGES.  It was originally coded in IBM 80x86
  77.    assembler, and since DKBTrace is a completely "C"-based package, I have
  78.    converted John's assembler routines all into "C".  These may be a tad bit
  79.    slower, but they should be compatible across a wide variety of 80x86/(S)VGA
  80.    machines.  Note if you have a regular cheapo VGA card like myself, included
  81.    is "MODE13x" or MVGA (modified VGA) mode (some call it "tweaked", but I
  82.    call it "Simulated SVGA"), which gives 360x480 on any reasonably register-
  83.    compatible plain vanilla VGA card.  This mode gives a good simulated 640 by
  84.    480 screen resolution.  I did not implement all the neat hi-res modes of
  85.    all the various SVGA adapters, if you select a trace size bigger than the
  86.    program and/or card can handle (most likely 640x480), it is dynamically
  87.    scaled to fit the available resolution, so you'll be able to see a rough
  88.    approximation of an 800x600 trace even on any el-cheapo VGA card at 320x200
  89.    resolution.  The VESA VGA mode was freely adapted from FRACTINT, whose GIF
  90.    reading routines we are already using in DKBTrace.  I hope my conversion
  91.    of it works properly.
  92.  
  93.    There is still a reported problem with the EVEREX autodetect returning
  94.    TRIDENT.  In fact EVEREX uses a TRIDENT chip set, but apparently there
  95.    is some difference in operation.  There are cryptic diagnostic messages
  96.    such as T0000, etc. printed as a result of the autodetection routines
  97.    to help track down why the error is happening.  If you are experiencing
  98.    problems with EVEREX or TRIDENT, make note of the letter-4 digit code you
  99.    are given.  There is now an autodetect for VDC600 that I hope will work
  100.    universally.  A similar problem as the EVEREX exists, in that the VDC600
  101.    is detected as a PARADISE because it uses the PARADISE chip set.  I am now
  102.    looking for what I believe to be the model number in the BIOS ROM of the
  103.    VDC600 to differentiate between the two.  I hope this works  with all
  104.    VDC600's, as I only had one example to work from.  Please send all bug
  105.    reports to Aaron Collins at the "You Can Call Me RAY" BBS, the number is
  106.    above in the header of this and the other DKB source files.
  107. */
  108.  
  109. #include "frame.h"
  110. #include "dkbproto.h"
  111. #include <dos.h>    /* MS-DOS specific - for int86() REGS struct, etc. */
  112.  
  113. #ifdef TURBOC
  114. #include <sys\time.h>
  115. extern unsigned _stklen = 12288;   /* HUGE stack for HEAVY recursion */
  116. #else
  117. #include <time.h>
  118. #endif
  119.  
  120.  
  121. /* The supported VGA adapter types 1 - 9, A - G.  0 is for auto-detect. */
  122.  
  123. #define    BASIC_VGA    1        /* 1 - Tested: AAC */
  124. #define    MODE13x        2        /* 2 - Tested: AAC */
  125. #define    TSENG3        3        /* 3 - Tested: William Minus */
  126. #define    TSENG4        4        /* 4 - Tested: William Minus */
  127. #define    VDC600        5        /* 5 - Tested: John Gooding */
  128. #define    OAKTECH        6        /* 6 - Untested */
  129. #define    VIDEO7        7        /* 7 - Untested */
  130. #define CIRRUS        8        /* 8 - Tested: AAC */
  131. #define    PARADISE    9        /* 9 - Tested: John Degner */
  132. #define    AHEADA        17        /* A - Untested */
  133. #define    AHEADB        18        /* B - Untested */
  134. #define    CHIPSTECH    19        /* C - Untested */
  135. #define    ATIVGA        20        /* D - Tested: William Earl */
  136. #define    EVEREX        21        /* E - Tested: A+B problem - Larry Minton */
  137. #define    TRIDENT        22        /* F - Untested */
  138. #define VESA        23        /* G - Untested */
  139.  
  140.  
  141. #define    MISCOUT        0x3c2        /* VGA chip msic output reg. addr */
  142. #define    SEQUENCER    0x3c4        /* VGA chip sequencer register addr */
  143. #define    CRTC        0x3d4        /* VGA chip crt controller reg addr */
  144.  
  145.  
  146. char *vga_names[] = 
  147.     {
  148.     "",
  149.     "(1) Standard VGA",
  150.     "(2) Simulated SVGA",
  151.     "(3) Tseng Labs 3000 SVGA",
  152.     "(4) Tseng Labs 4000 SVGA",
  153.     "(5) AT&T VDC600 SVGA",
  154.     "(6) Oak Technologies SVGA",
  155.     "(7) Video 7 SVGA",
  156.     "(8) Video 7 Vega (Cirrus) VGA",
  157.     "(9) Paradise SVGA",
  158.     "",
  159.     "",
  160.     "",
  161.     "",
  162.     "",
  163.     "",
  164.     "",
  165.     "(A) Ahead Systems Ver. A SVGA",
  166.     "(B) Ahead Systems Ver. B SVGA",
  167.     "(C) Chips & Technologies SVGA",
  168.     "(D) ATI SVGA",
  169.     "(E) Everex SVGA",
  170.     "(F) Trident SVGA",
  171.     "(G) VESA Standard SVGA Adapter"
  172.     };
  173.  
  174.  
  175. unsigned int vptbl[] =        /* CRTC register values for MODE13x */
  176.     {
  177.     0x6b00,    /* horz total */
  178.     0x5901,    /* horz displayed */
  179.     0x5a02,    /* start horz blanking */
  180.     0x8e03U,    /* end horz blanking */
  181.     0x5e04,    /* start h sync */
  182.     0x8a05U,    /* end h sync */
  183.     0x0d06,    /* vertical total */
  184.     0x3e07,    /* overflow */
  185.     0x4009,    /* cell height */
  186.     0xea10U,    /* v sync start */
  187.     0xac11U,    /* v sync end and protect cr0-cr7 */
  188.     0xdf12U,    /* vertical displayed */
  189.     0x2d13,    /* offset */
  190.     0x0014,    /* turn off dword mode */
  191.     0xe715U,    /* v blank start */
  192.     0x0616,    /* v blank end */
  193.     0xe317U    /* turn on byte mode */
  194. };
  195.  
  196.  
  197. int screen_height, screen_width;
  198. int svga_width = 640;        /* default SVGA width/height, */
  199. int svga_height = 480;        /* unless we find otherwise... */
  200. int lastx, lasty, lastline;    /* Pixel / Line Caches */
  201. int whichvga = BASIC_VGA;    /* BASIC_VGA mode by default */
  202. int vga_512K = FALSE;        /* Flag for whether or not >= 512K VGA mem */
  203. unsigned char svga_cur = 255;
  204. unsigned char vesa_granularity = 1;    /* VESA default to 64K granules */
  205. void (_cdecl *vesa_bankswitch)(void);    /* ptr to VESA bankswitch function */
  206. unsigned char answer[257];        /* answer area for VESA BIOS calls */
  207.  
  208. extern unsigned int Options;
  209. extern char DisplayFormat;
  210.  
  211. int auto_detect_vga(void);
  212. int cirrus(void);
  213. int chkbk(unsigned int);
  214. int gochk(unsigned int, unsigned int);
  215. void pdrsub(unsigned char);
  216. void pallete_init(void);
  217. void newbank(void);
  218. void set_pallette_register(unsigned, unsigned, unsigned, unsigned);
  219. void hsv_to_rgb(DBL, DBL, DBL, unsigned *, unsigned *, unsigned *);
  220. void rgb_to_hsv(unsigned, unsigned, unsigned, DBL *, DBL *, DBL *);
  221. int _cdecl matherr(struct exception *);
  222.  
  223.  
  224. void display_init(width, height) /* Set video to requested or best mode */
  225. int width, height;
  226.    {
  227.    union REGS inr, outr;
  228.    unsigned char far *fp;
  229.    unsigned u;
  230.    int i;
  231.    long l, lt;
  232.  
  233.    lastline = -1;        /* make sure we display the 1st line... */
  234.    screen_height = height;
  235.    screen_width = width;
  236.    if (DisplayFormat != '0')    /* if not 0, some display type specified */
  237.     whichvga = DisplayFormat - '0';        /* de-ASCII-fy selection */
  238.    else
  239.     {
  240.     whichvga = auto_detect_vga();
  241.     printf("VGA detected: %s, with %s 512K RAM\n", vga_names[whichvga], vga_512K ? ">=" : "<");
  242.     lt = l = time(&l);
  243.     while (time(&l) < lt + 3)    /* display VGA type for 3 secs */
  244.         ;
  245.     if (!vga_512K)            /* not enough RAM for 640 x 480? */
  246.         whichvga = MODE13x;        /* then try for next best mode... */
  247.     }
  248.  
  249.     if (whichvga == CIRRUS)        /* Register Compatible VGA? */
  250.          whichvga = MODE13x;    /* MODE13x if > 320x200, else... */
  251.  
  252.     if (screen_height <= 200 || screen_width <= 320)
  253.     whichvga = BASIC_VGA;        /* BASIC_VGA if <= 320x200 */
  254.  
  255.    switch (whichvga)
  256.     {
  257.     case MODE13x:
  258.         inr.x.ax = 0x0013;   /* setup to VGA 360x480x256 (mode 13X) */
  259.         int86(0x10, &inr, &outr);   /* then we'll tweak the VGA! */
  260.  
  261.         outpw(SEQUENCER, 0x0604);   /* disable chain 4 */
  262.         outpw(SEQUENCER, 0x0f02);   /* allow writes to all planes */
  263.  
  264.         for (u = 0; u < 43200; u++) /* clear the whole screen */
  265.             {
  266.         fp = MK_FP(0xa000, u);
  267.         *fp = 0;            /* set all bytes to 0 */
  268.         }
  269.  
  270.         outpw(SEQUENCER, 0x0100);   /* synchronous reset */
  271.         outp(MISCOUT, 0xe7);        /* use 28 mhz dot clock */
  272.         outpw(SEQUENCER, 0x0300);   /* restart sequencer */
  273.         outp(CRTC, 0x11);        /* ctrl register 11, please */
  274.         outp(CRTC+1, inp(CRTC+1) & 0x7f); /* write-prot cr0-7 */
  275.  
  276.         for (i = 0; i < 17; i++)    /* write CRTC register array */
  277.         outpw(CRTC, vptbl[i]);
  278.         svga_width = 360;        /* Fake 640 mode actually is 360 */
  279.         break;
  280.     case VDC600:
  281.         inr.x.ax = 0x005E;   /* setup to VGA 640x400x256 (mode 5EH) */
  282.         svga_height = 400;     /* This is the only SVGA card w/400 Lines */
  283.         break;
  284.     case OAKTECH:
  285.         inr.x.ax = 0x0053;   /* setup to VGA 640x480x256 most SVGAs */
  286.         break;
  287.     case AHEADA:
  288.     case AHEADB:
  289.         inr.x.ax = 0x0061;
  290.         break;
  291.     case EVEREX:
  292.         inr.x.ax = 0x0070;     /* BIOS Mode 0x16 for EV-678? */
  293.         inr.h.bl = 0x30;
  294.         break;
  295.     case ATIVGA:
  296.         inr.x.ax = 0x0062;
  297.         break;
  298.     case TRIDENT:
  299.         inr.x.ax = 0x005d;
  300.         break;
  301.     case VIDEO7:
  302.         inr.x.ax = 0x6f05;
  303.         inr.h.bl = 0x67;
  304.         break;
  305.     case CHIPSTECH:
  306.         inr.x.ax = 0x0079;
  307.         break;
  308.     case PARADISE:
  309.         inr.x.ax = 0x005f;
  310.         break;
  311.     case TSENG3:
  312.         inr.x.ax = 0x002e;
  313.         break;
  314.     case TSENG4:
  315.         inr.x.ax = 0x002e;
  316.         break;
  317.     case VESA:
  318.         inr.x.ax = 0x4f02;
  319.         inr.x.bx = 0x0101;
  320.     default:        /* BASIC_VGA */
  321.         inr.x.ax = 0x0013;    /* setup to VGA 320x200x256 (mode 13H) */
  322.         svga_width = 320;    /* allow svga scaling to run at 320x200 */
  323.         svga_height = 200;
  324.     }
  325.    if (whichvga != MODE13x)
  326.     int86(0x10, &inr, &outr);    /* then do the BIOS video int */
  327.  
  328.    pallete_init();
  329.    return;
  330. }
  331.  
  332.  
  333. int auto_detect_vga()        /* Autodetect (S)VGA Adapter Type */
  334.     {
  335.     unsigned char far *biosptr;
  336.     unsigned char tmp_byte;
  337.     unsigned int tmp_word, tmp_word1;
  338.     int retcode = BASIC_VGA;
  339.     union REGS inr, outr;
  340.     struct SREGS segs;
  341.  
  342. /*  strcpy(answer, "THIS IS A TEST!$");    * Test for proper segment loss */
  343. /*  inr.x.ax = 0x0900;    */
  344. /*  inr.x.dx = (unsigned int) answer;     */
  345. /*  segread(&segs);                * get our DS, etc. */
  346. /*  segs.ds = (unsigned int) ((unsigned long)answer >> 16); * get segment? */
  347. /*  int86x(0x21, &inr, &outr, &segs);        * DOS print string call */
  348.  
  349.     inr.x.ax = 0x4F00;            /* Test for VESA Adapter */
  350.     inr.x.di = (unsigned int) answer;
  351.     segread(&segs);            /* get our DS, etc. */
  352.     segs.es = (unsigned int) ((unsigned long)answer >> 16); /* get segment? */
  353.     int86x(0x10, &inr, &outr, &segs);    /* BIOS adapter identify call */
  354.     if (outr.x.ax == 0x004F)        /* if response successful */
  355.     if (!strncmp(answer, "VESA", 4))
  356.         {
  357.         inr.x.ax = 0x4F01;        /* BIOS fetch attributes call */
  358.         inr.x.bx = inr.x.cx = 0x0101;    /* get attrs for this mode */
  359.         inr.x.di = (unsigned int) answer;    /* deposit attribs here */
  360.         segread(&segs);            /* get our DS, etc. */
  361.         segs.es = (unsigned int) ((unsigned long)answer >> 16); /* seg? */
  362.         int86x(0x10, &inr, &outr, &segs);    /* BIOS fetch attrib call */
  363.         tmp_word = (unsigned int) *(answer + 12);    /* addr low word */
  364.         tmp_word1 = (unsigned int) *(answer + 14);    /* addr hi word */
  365.         vesa_bankswitch = (void (_cdecl *)(void))(((unsigned long) tmp_word1 << 16) | tmp_word);
  366.         tmp_word = (unsigned int) *(answer + 4);    /* "granule" size */
  367.         if (tmp_word < 1)
  368.         tmp_word = 1;
  369.         vesa_granularity = (unsigned char)(64 / tmp_word);
  370.         vga_512K = TRUE;        /* assume all VESA's have >= 512K */
  371.         return (VESA);
  372.         }
  373.     biosptr = MK_FP(0xC000, 0x0040);    /* Test for ATI Wonder */
  374.     if (*biosptr == '3' && *(biosptr + 1) == '1')
  375.     {
  376.     _disable();            /* Disable system interrupts */
  377.     outp(0x1CE, 0xBB);
  378.     if (inp(0x1CD) & 0x20)
  379.         vga_512K = TRUE;
  380.     _enable();            /* Re-enable system interrupts */
  381.     return (ATIVGA);
  382.     }
  383.     inr.x.ax = 0x7000;            /* Test for Everex &| Trident */
  384.     inr.x.bx = 0;
  385. #ifndef TURBOC
  386.     _asm cld;
  387. #else
  388.     #inline    cld;
  389. #endif
  390.     int86(0x10, &inr, &outr);
  391.     if (outr.h.al == 0x70)
  392.     {
  393.     if (outr.h.ch & 0xC0)
  394.         vga_512K = TRUE;
  395.     outr.x.dx &= 0xFFF0;
  396.     if (outr.x.dx == 0x6780)
  397.         {
  398.         printf("\nT6780\n");
  399.         return (TRIDENT);
  400.         }
  401.     if (outr.x.dx == 0x2360)
  402.         {
  403.         printf("\nT2360\n");
  404.         return (TRIDENT);
  405.         }
  406.     if (outr.x.dx == 0x6730)    /* EVGA? (No BIOS Page Fn.) */
  407.         {
  408.         printf("\nE6730\n");
  409.         return (EVEREX);
  410.         }
  411.     printf("\nE0000\n");
  412.     return (EVEREX);    /* Newer board with fetchable bankswitch */
  413.     }
  414.     outp(0x3C4, 0x0B);            /* Test for Trident */
  415.     tmp_byte = (unsigned char) inp(0x3C5);
  416.     if ((tmp_byte > 1) && (tmp_byte < 0x10))
  417.     {
  418.     vga_512K = TRUE;
  419.     printf("\nT0000\n");
  420.     return (TRIDENT);
  421.     }
  422.     if (cirrus())            /* Test Video7 Vega VGA (Cirrus) */
  423.     return (CIRRUS);
  424.     inr.x.ax = 0x6F00;            /* Test for Video7 SVGA */
  425.     inr.x.bx = 0;            /* note - Vega VGA (Cirrus) will */
  426. #ifndef TURBOC
  427.     _asm cld;
  428. #else
  429.     #inline cld;
  430. #endif
  431.     int86(0x10, &inr, &outr);        /* pass this test - test Cirrus 1st */
  432.     if (outr.h.bh == 'V' && outr.h.bl == '7')
  433.     {
  434.     inr.x.ax = 0x6F07;        /* may need to clear direction flag */
  435. #ifndef TURBOC
  436.     _asm cld;
  437. #else
  438.     #inline cld;
  439. #endif
  440.     int86(0x10, &inr, &outr);
  441.     if ((outr.h.ah & 0x7F) > 1)
  442.         vga_512K = TRUE;
  443.     return (VIDEO7);
  444.     }
  445.     outp(0x3CE, 9);            /* Test for Paradise */
  446.     if (!inp(0x3CF))
  447.     {
  448.     outpw(0x3CE, 0x050F);        /* Turn off write protect on regs */
  449.     if (chkbk(1))            /* if bank 0 and 1 same not para. */
  450.         {                /* FALSE == banks same... (C) */
  451. /*        if (chkbk(64))        * if bank 0 and 64 same only 256K */
  452.         vga_512K = TRUE;
  453.         biosptr = MK_FP(0xC000, 0x0039);    /* Test for AT&T VDC600 */
  454.         if ((*biosptr == '1') && (*biosptr+1 == '6')) /* p/n 003116 */
  455.         return (VDC600);    /* a real Paradise is p/n 003145 */
  456.         return (PARADISE);
  457.         }
  458.     }
  459.     inr.x.ax = 0x5F00;            /* Test for Chips & Tech */
  460.     inr.x.bx = 0;
  461. #ifndef TURBOC
  462.     _asm cld;
  463. #else
  464.     #inline cld;
  465. #endif
  466.     int86(0x10, &inr, &outr);
  467.     if (outr.h.al == 0x5F)
  468.     {
  469.     if (outr.h.bh >= 1)
  470.         vga_512K = TRUE;
  471.     return (CHIPSTECH);
  472.     }
  473.     outp(0x3D4, 0x33);            /* Test for Tseng 4000 or 3000 Chip */
  474.     tmp_word = (unsigned int) inp(0x3D5) << 8;
  475.     outpw(0x3D4, 0x0A33);
  476.     outp(0x3D4, 0x33);
  477.     if ((inp(0x3D5) & 0x0F) == 0x0A)
  478.     {
  479.     outpw(0x3D4, 0x0533);
  480.     outp(0x3D4, 0x33);
  481.     if ((inp(0x3D5) & 0x0F) == 0x05)
  482.         {
  483.         retcode = TSENG4;
  484.         outpw(0x3D4, tmp_word | 0x33);
  485.         outp(0x3BF, 0x03);        /* Enable access to extended regs */
  486.         outp(0x3D8, 0xA0);
  487.         }
  488.     }
  489.     tmp_byte = (unsigned char) inp(0x3CD);    /* save bank switch reg */
  490.     outp(0x3CD, 0xAA);                /* test register w/ 0xAA */
  491.     if (inp(0x3CD) == 0xAA)
  492.     {
  493.     outp(0x3CD, 0x55);            /* test register w/ 0x55 */
  494.     if (inp(0x3CD) == 0x55)
  495.         {
  496.         outp(0x3CD, tmp_byte);        /* restore bank switch reg */
  497.         if (retcode != TSENG4)        /* yep, it's a Tseng... */
  498.         retcode = TSENG3;
  499.         vga_512K = TRUE;
  500.         return (retcode);
  501.         }
  502.     }
  503.     outpw(0x3CE, 0x200F);        /* Test for Ahead A or B chipsets */
  504.     tmp_byte = (unsigned char) inp(0x3CF);
  505.     if (tmp_byte == 0x21)
  506.     {
  507.     vga_512K = TRUE;        /* Assume all Ahead's have 512K... */
  508.     return (AHEADB);
  509.     }
  510.     if (tmp_byte == 0x20)
  511.     {
  512.     vga_512K = TRUE;
  513.     return (AHEADA);
  514.     }
  515.     if ((inp(0x3DE) & 0xE0) == 0x60)    /* Test for Oak Tech OTI-067 */
  516.     {
  517.     outp(0x3DE, 0x0D);
  518.     if (inp(0x3DF) & 0x80)
  519.         vga_512K = TRUE;
  520.     return(OAKTECH);
  521.     }
  522.     return (BASIC_VGA);            /* Return 1 if Unknown/BASIC_VGA */
  523.     }
  524.  
  525. int cirrus()            /* Test for presence of Cirrus VGA Chip */
  526.     {
  527.     unsigned char tmp_byte;
  528.     unsigned int crc_word, tmp_word;
  529.     int retcode = FALSE;
  530.  
  531.     outp(0x3D4, 0x0C);    /* assume 3Dx addressing, scrn A start addr hi */
  532.     crc_word = (unsigned int) inp(0x3D5) << 8;    /* save the crc */
  533.     outp(0x3D5, 0);                /* clear the crc */
  534.     outp(0x3D4, 0x1F);                /* Eagle ID register */
  535.     tmp_byte = (unsigned char) inp(0x3D5);    /* nybble swap "register" */
  536.     tmp_word = (((tmp_byte & 0x0F) << 4) | ((tmp_byte & 0xf0) >> 4)) << 8;
  537.     outpw(0x3C4, tmp_word | 0x06);        /* disable extensions */
  538.     if (!inp(0x3C5))
  539.     {
  540.     tmp_word = (unsigned int) tmp_byte << 8;
  541.     outpw(0x3C4, tmp_word | 0x06);        /* re-enable extensions */
  542.     if (inp(0x3C5) == 1)
  543.         retcode = TRUE;
  544.     }
  545.     outpw(0x3D5, crc_word | 0x0c);        /* restore the crc */
  546.     return (retcode);
  547.     }
  548.  
  549.  
  550. int chkbk(bank)        /* Paradise specific VGA bank switch test */
  551. unsigned int bank;    /* returns FALSE (C) if banks test the same... */
  552.     {
  553.     if (gochk(0x1234, bank))        /* TRUE = test failed */
  554.     return(FALSE);    /* FALSE - bank 0 and 'bank' are the same... */
  555.     if (gochk(0x4321, bank))
  556.     return(FALSE);    /* FALSE - bank 0 and 'bank' are the same... */
  557.     return (TRUE);    /* TRUE - bank 0 and 'bank' are different */
  558.     }
  559.  
  560.  
  561. int gochk(value, bank)        /* More Paradise specific stuff (feh!) */
  562.     unsigned int value, bank;    /* returns TRUE (NZ) if bank test fails */
  563.     {
  564.     unsigned char far *fp;
  565.     unsigned char bh, bl, ch, cl, oldbh, oldbl;    /* pardon my registers! */
  566.  
  567.     fp = MK_FP(0xb800, 0);        /* point out into display RAM */
  568.  
  569.     bh = (unsigned char)(value >> 8);    /* test signature hi order */
  570.     bl = (unsigned char)(value & 0xff);    /* test signature lo order */
  571.     ch = (unsigned char)(bank >> 8);    /* usually 0 */
  572.     cl = (unsigned char)(bank & 0xff);    /* bank number to test */
  573.  
  574.     pdrsub(cl);        /* save prior video data and write test values */
  575.     oldbl = *fp;
  576.     *fp = bl;
  577.     pdrsub(ch);
  578.     oldbh = *fp;
  579.     *fp = bh;
  580.  
  581.     pdrsub(cl);        /* XOR values written with old values */
  582.     bl ^= *fp;
  583.     pdrsub(ch);
  584.     bh ^= *fp;
  585.  
  586.     pdrsub(cl);        /* restore old video data after testing */
  587.     *fp = oldbl;
  588.     pdrsub(ch);
  589.     *fp = oldbh;
  590.  
  591.     pdrsub(0);        /* reselect bank zero */
  592.  
  593.     return ((int)(bh | bl));    /* bh and bl == 0 == OK, return FALSE */
  594.     }
  595.  
  596.  
  597. void pdrsub(bank)    /* Still More Paradise specific stuff (arrgh!!) */
  598.     unsigned char bank;
  599.     {
  600.     unsigned int value;
  601.  
  602.     value = (unsigned int) bank << 8;
  603.     outpw(0x3CE, value | 9);        /* perform the bank switch */
  604.     }
  605.  
  606.  
  607. void pallete_init()        /* Fill VGA 256 color palette with colors! */
  608.     {
  609.     union REGS inr, outr;
  610.     register unsigned m;
  611.     unsigned r, g, b;
  612.     register DBL hue, sat, val;
  613.  
  614.     inr.x.ax = 0x1010;           /* make pallette register 0 black */
  615.     inr.x.bx = 0;
  616.     inr.h.ch = inr.h.cl = inr.h.dh = 0;   /* full off */
  617.     int86(0x10, &inr, &outr);
  618.  
  619.     inr.x.ax = 0x1010;           /* make pallette register 64 white */
  620.     inr.x.bx = 64;
  621.     inr.h.ch = inr.h.cl = inr.h.dh = 63;  /* full on */
  622.     int86(0x10, &inr, &outr);
  623.  
  624.     inr.x.ax = 0x1010;           /* make pallette register 128 dark grey */
  625.     inr.x.bx = 128;
  626.     inr.h.ch = inr.h.cl = inr.h.dh = 31;  /* half on (dark grey) */
  627.     int86(0x10, &inr, &outr);
  628.  
  629.     inr.x.ax = 0x1010;           /* make pallette register 192 lite grey */
  630.     inr.x.bx = 192;
  631.     inr.h.ch = inr.h.cl = inr.h.dh = 48;  /* 3/4 on (lite grey) */
  632.     int86(0x10, &inr, &outr);
  633.  
  634.     for (m = 1; m < 64; m++)     /* for the 1st 64 colors... */
  635.     {
  636.     sat = 0.5;    /* start with the saturation and intensity low */
  637.     val = 0.5;
  638.     hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
  639.     hsv_to_rgb (hue, sat, val, &r, &g, &b);
  640.     set_pallette_register (m, r, g, b); /* set m to rgb value */
  641.  
  642.     sat = 1.0;    /* high saturation and half intensity (shades) */
  643.     val = 0.50;
  644.     hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
  645.     hsv_to_rgb (hue, sat, val, &r, &g, &b);
  646.     set_pallette_register (m + 64, r, g, b);  /* set m + 64 */
  647.  
  648.     sat = 0.5;    /* half saturation and high intensity (pastels) */
  649.     val = 1.0;
  650.  
  651.     hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
  652.     hsv_to_rgb (hue, sat, val, &r, &g, &b);
  653.     set_pallette_register (m + 128, r, g, b); /* set m + 128 */
  654.  
  655.     sat = 1.0;            /* normal full HSV set at full intensity */
  656.     val = 1.0;
  657.    
  658.     hue = 360.0 * ((DBL)(m)) / 64.0;   /* normalize to 360 */
  659.     hsv_to_rgb (hue, sat, val, &r, &g, &b);
  660.     set_pallette_register (m + 192, r, g, b); /* set m + 192 */
  661.     }
  662.     return;
  663.     }
  664.  
  665.  
  666. void display_finished ()
  667.     {
  668.     if (Options & PROMPTEXIT)
  669.     {
  670.     printf ("\007\007");    /* long beep */
  671.     while(!kbhit())        /* wait for key hit */
  672.        ;
  673.     if (!getch())        /* get another if ext. scancode */
  674.        getch();
  675.     }
  676.     }
  677.  
  678.  
  679. void display_close()   /* setup to Text 80x25 (mode 3) */
  680.     {
  681.     union REGS inr, outr;
  682.  
  683.     inr.x.ax = 0x0003;
  684.     int86(0x10, &inr, &outr);
  685.     return;
  686.     }
  687.  
  688.  
  689. void display_plot (x, y, Red, Green, Blue)   /* plot a single RGB pixel */
  690.    int x, y;
  691.    char Red, Green, Blue;
  692.    {
  693.    register unsigned char color, svga_byte;
  694.    unsigned char far *fp;
  695.    unsigned int svga_lo, svga_word;
  696.    unsigned long svga_loc;
  697.    DBL h, s, v, fx, fy;
  698.  
  699.    if (!x)            /* first pixel on this line? */
  700.     {
  701.     lastx = -1;        /* reset cache, make sure we do the 1st one */
  702.     lasty = lastline;    /* set last line do to prior line */
  703.     }
  704.  
  705.    if (screen_height > svga_height)    /* auto-scale Y */
  706.     {
  707.     fy = (DBL)y / ((DBL)screen_height / (DBL)svga_height);
  708.     y = (int)fy;        /* scale y to svga_height */
  709.     if (y <= lasty)        /* discard if repeated line */
  710.         return;
  711.     lastline = y;        /* save current working line */
  712.     }
  713.  
  714.    if (screen_width > svga_width)        /* auto-scale X */
  715.     {
  716.     fx = (DBL)x / ((DBL)screen_width / (DBL)svga_width);
  717.     x = (int)fx;        /* scale x to svga_width */
  718.     if (x <= lastx)        /* discard if repeated pixel */
  719.         return;
  720.     lastx = x;        /* save most recent pixel done */
  721.     }
  722.  
  723.    /* Translate RGB value to best of 256 pallete Colors (by HSV?) */
  724.  
  725.    rgb_to_hsv((unsigned)Red,(unsigned)Green,(unsigned)Blue, &h, &s, &v);
  726.  
  727.    if (s < 0.20)   /* black or white if no saturation of color... */
  728.    {
  729.       if (v < 0.25)
  730.          color = 0;        /* black */
  731.       else if (v > 0.8)
  732.          color = 64;       /* white */
  733.       else if (v > 0.5)
  734.          color = 192;      /* lite grey */
  735.       else
  736.          color = 128;      /* dark grey */
  737.       }
  738.    else
  739.       {
  740.       color = (unsigned char) (64.0 * ((DBL)(h)) / 360.0);
  741.  
  742.       if (!color)
  743.          color = 1;        /* avoid black, white or grey */
  744.       
  745.       if (color > 63)
  746.          color = 63;       /* avoid same */
  747.  
  748.       if (v > 0.50)
  749.          color |= 0x80;    /* colors 128-255 for high inten. */
  750.  
  751.       if (s > 0.50)        /* more than half saturated? */
  752.          color |= 0x40;    /* color range 64-128 or 192-255 */
  753.       }
  754.  
  755.    switch (whichvga)        /* decide on bank switching scheme to use */
  756.     {
  757.        case BASIC_VGA:    /* none */
  758.         fp = MK_FP(0xa000, 320 * y + x);
  759.         break;
  760.        case MODE13x:    /* faked */
  761.         svga_word = 1 << (x & 3);    /* form bit plane mask */
  762.         svga_word = (svga_word << 8) | 2;
  763.         outpw(SEQUENCER, svga_word);    /* tweak the sequencer */
  764.         fp = MK_FP(0xa000, 90 * y + (x >> 2));
  765.         break;
  766.        default:    /* actual bank switch for all SVGA cards */
  767.         svga_loc = (unsigned long)svga_width * y + x; /* scrn addr. */
  768.         svga_lo = (unsigned int)(svga_loc & 0x0000ffffL);
  769.         svga_loc &= 0x00ff0000L;    /* get high order byte */
  770.         svga_byte = (unsigned char)(svga_loc >> 16);  /* bank # */
  771.         if (svga_cur != svga_byte)    /* if not in correct bank */
  772.         {
  773.             _disable();           /* shut off system interrupts */
  774.             svga_cur = svga_byte;  /* set new curr. working bank */
  775.             newbank();           /* and switch to it... */
  776.             _enable();           /* restore system interrupts */
  777.         }
  778.         fp = MK_FP(0xa000, svga_lo);  /* use low order scrn addr */
  779.     }
  780.  
  781.    *fp = color;        /* write normalized pixel color val to bitplane */
  782.  
  783.    return;
  784.    }
  785.  
  786. void newbank()        /* Perform SVGA bank switch on demand - Voila! */
  787. {
  788.     register unsigned char tmp_byte, tmp_byte1;
  789.     register unsigned int tmp_word;
  790.     union REGS regs;
  791.  
  792.     switch (whichvga)
  793.         {
  794.     case VDC600:            /* AT&T VDC 600 */
  795.         tmp_byte = (unsigned char) (svga_cur << 4);    /* was >> 12... */
  796.         outpw(0x03CE,0x050F);
  797.         outp(0x03CE,0x09);
  798.         outp(0x03CF, tmp_byte);
  799.         break;
  800.     case OAKTECH:            /* Oak Technology OTI-067 */
  801.         tmp_byte = (unsigned char)(svga_cur & 0x0F);
  802.         outp(0x3DF, (tmp_byte << 4) | tmp_byte);
  803.         break;
  804.     case AHEADA:            /* Ahead Systems Ver A */
  805.         outpw(0x3CE, 0x200F);    /* enable extended registers */
  806.         tmp_byte = (unsigned char)(inp(0x3CC) & 0xDF);  /* bit 0 */
  807.         if (svga_cur & 1)
  808.             tmp_byte |= 0x20;
  809.         outp(0x3C2, tmp_byte);
  810.         outp(0x3CF, 0);           /* bits 1, 2, 3 */
  811.         tmp_word = (unsigned int)((svga_cur >> 1 )|(inp(0x3D0) & 0xf8));
  812.         outpw(0x3CF, tmp_word << 8);
  813.         break;
  814.     case AHEADB:            /* Ahead Systems Ver B */
  815.         outpw(0x3CE, 0x200F);    /* enable extended registers */
  816.         tmp_word = (unsigned int)((svga_cur << 4) | svga_cur);
  817.         outpw(0x3CF, (tmp_word << 8) | 0x000D);
  818.         break;
  819.     case EVEREX:            /* Everex SVGA's */
  820.         outp(0x3C4, 8);
  821.         if (svga_cur & 1)
  822.          tmp_word = (unsigned int)(inp(0x3C5) | 0x80);
  823.         else tmp_word = (unsigned int)(inp(0x3C5) & 0x7F);
  824.         outpw(0x3C4, (tmp_word << 8) | 0x0008);
  825.         tmp_byte = (unsigned char)(inp(0x3CC) & 0xDF);
  826.         if (!(svga_cur & 2))
  827.          tmp_byte |= 0x20;
  828.         outp(0x3C2, tmp_byte);
  829.         break;
  830.     case ATIVGA:            /* ATI VGA Wonder */
  831.         outp(0x1CE, 0xB2);
  832.         tmp_word = (unsigned int)((svga_cur << 1) | (inp(0x1CF) & 0xE1));
  833.         outpw(0x1CE, (tmp_word << 8) | 0x00B2);
  834.         break;
  835.     case TRIDENT:
  836.         outp(0x3CE, 6);        /* set page size to 64K */
  837.         tmp_word = (unsigned int)(inp(0x3CF) | 4) << 8;
  838.         outpw(0x3CE, tmp_word | 0x0006);
  839.         outp(0x3C4, 0x0b);        /* switch to BPS mode */
  840.         inp(0x3C5);            /* dummy read?? */
  841.         tmp_word = (unsigned int)(svga_cur ^ 2) << 8;
  842.         outpw(0x3C4, tmp_word | 0x000E);
  843.         break;
  844.     case VIDEO7:            /* Video-7 VRAM, FastRAM SVGA cards */
  845.         tmp_byte1 = tmp_byte = (unsigned char)(svga_cur & 0x0F);
  846.         outpw(0x3C4, 0xEA06);
  847.         tmp_word = (unsigned int)(tmp_byte & 1) << 8;
  848.         outpw(0x3C4, tmp_word | 0x00F9);
  849.         tmp_byte &= 0x0C;
  850.         tmp_word = (unsigned int)(tmp_byte >> 2 | tmp_byte) << 8;
  851.         outpw(0x3C4, tmp_word | 0x00F6);
  852.         tmp_word |= (inp(0x3C5) & 0xF0) << 8;
  853.         outpw(0x3C4, tmp_word | 0x00F6);
  854.         tmp_byte = (unsigned char)((tmp_byte1 << 4) & 0x20);
  855.         outp(0x3C2, (inp(0x3CC) & 0xDF) | tmp_byte);
  856.         break;
  857.     case CHIPSTECH:            /* Chips & Technology VGA Chip Set */
  858.         outpw(0x46E8, 0x001E);    /* put chip in setup mode */
  859.         outpw(0x103, 0x0080);    /* enable extended registers */
  860.         outpw(0x46E8, 0x000E);    /* take chip out of setup mode */
  861.         tmp_word = (unsigned int)(svga_cur << 2) << 8; /* 64K -> 16K */
  862.         outpw(0x3D6, tmp_word | 0x0010);
  863.         break;
  864.     case PARADISE:            /* Paradise, Professional, Plus */
  865.         outpw(0x3CE, 0x050F);    /* turn off VGA reg. write protect */
  866.         tmp_word = (unsigned int)(svga_cur << 4) << 8;
  867.         outpw(0x3CE, tmp_word | 0x0009);
  868.         break;
  869.     case TSENG3:            /* Tseng 3000 - Orchid, STB, etc. */
  870.         tmp_byte = (unsigned char)(svga_cur & 0x07);
  871.         tmp_byte1 = (unsigned char)((tmp_byte << 3) | tmp_byte);
  872.         outp(0x3CD, tmp_byte1 | 0x40);
  873.         break;
  874.     case TSENG4:            /* Tseng 4000 - Orchid PD+, etc. */
  875.         tmp_byte = (unsigned char)(svga_cur & 0x0F);
  876.         tmp_byte1 = (unsigned char)((tmp_byte << 4) | tmp_byte);
  877.         outp(0x3BF, 3);        /* enable access to extended regs */
  878.         outp(0x3D8, 0xA0);
  879.         outp(0x3CD, tmp_byte1);
  880.         break;
  881.     case VESA:            /* VESA standard 640x480x256 */
  882.         regs.x.dx = (unsigned int) svga_cur * vesa_granularity;
  883.         regs.x.ax = 0x4F05;
  884.         int86(0x10, ®s, ®s);    /* Do the video BIOS interrupt */
  885.         (*vesa_bankswitch)();    /* call the bios bank-switch rtn */
  886.         }
  887.     return;
  888. }
  889.  
  890. void set_pallette_register (Val, Red, Green, Blue)
  891.    unsigned Val;
  892.    unsigned Red, Green, Blue;
  893.    {
  894.    union REGS Regs;
  895.  
  896.    Regs.x.ax = 0x1010;              /* Set one pallette register function */
  897.    Regs.x.bx = Val;                 /* the pallette register to set (color#)*/
  898.    Regs.h.dh = (char)(Red & 0xff);   /* set the gun values (6 bits ea.) */
  899.    Regs.h.ch = (char)(Green & 0xff);
  900.    Regs.h.cl = (char)(Blue & 0xff);
  901.    int86(0x10, &Regs, &Regs);       /* Do the video interrupt */
  902.    }
  903.  
  904. /* Conversion from Hue, Saturation, Value to Red, Green, and Blue and back */
  905. /* From "Computer Graphics", Donald Hearn & M. Pauline Baker, p. 304 */
  906.  
  907. void hsv_to_rgb(hue, s, v, r, g, b)
  908.    DBL hue, s, v;               /* hue (0.0-360.0) s and v from 0.0-1.0) */
  909.    unsigned *r, *g, *b;         /* values from 0 to 63 */
  910.    {
  911.    register DBL i, f, p1, p2, p3;
  912.    register DBL xh;
  913.    register DBL nr = 0.0, ng = 0.0, nb = 0.0;    /* rgb values of 0.0 - 1.0 */
  914.  
  915.    if (hue == 360.0)
  916.       hue = 0.0;                /* (THIS LOOKS BACKWARDS BUT OK) */
  917.  
  918.    xh = hue / 60.0;             /* convert hue to be in 0,6     */
  919.    i = floor(xh);               /* i = greatest integer <= h    */
  920.    f = xh - i;                  /* f = fractional part of h     */
  921.    p1 = v * (1 - s);
  922.    p2 = v * (1 - (s * f));
  923.    p3 = v * (1 - (s * (1 - f)));
  924.  
  925.    switch ((int) i)
  926.       {
  927.       case 0:
  928.          nr = v;
  929.          ng = p3;
  930.          nb = p1;
  931.          break;
  932.       case 1:
  933.          nr = p2;
  934.          ng = v;
  935.          nb = p1;
  936.          break;
  937.       case 2:
  938.          nr = p1;
  939.          ng = v;
  940.          nb = p3;
  941.          break;
  942.       case 3:
  943.          nr = p1;
  944.          ng = p2;
  945.          nb = v;
  946.          break;
  947.       case 4:
  948.          nr = p3;
  949.          ng = p1;
  950.          nb = v;
  951.          break;
  952.       case 5:
  953.          nr = v;
  954.          ng = p1;
  955.          nb = p2;
  956.          break;
  957.         }
  958.  
  959.    *r = (unsigned)(nr * 63.0); /* Normalize the values to 63 */
  960.    *g = (unsigned)(ng * 63.0);
  961.    *b = (unsigned)(nb * 63.0);
  962.    
  963.    return;
  964.    }
  965.  
  966.  
  967. void rgb_to_hsv(r, g, b, h, s, v)
  968.    unsigned r, g, b;
  969.    DBL *h, *s, *v;
  970.    {
  971.    register DBL m, r1, g1, b1;
  972.    register DBL nr, ng, nb;        /* rgb values of 0.0 - 1.0      */
  973.    register DBL nh = 0.0, ns, nv;    /* hsv local values */
  974.  
  975.    nr = (DBL) r / 255.0;
  976.    ng = (DBL) g / 255.0;
  977.    nb = (DBL) b / 255.0;
  978.  
  979.    nv = max (nr, max (ng, nb));
  980.    m = min (nr, min (ng, nb));
  981.  
  982.    if (nv != 0.0)                /* if no value, it's black! */
  983.       ns = (nv - m) / nv;
  984.    else
  985.       ns = 0.0;                 /* black = no colour saturation */
  986.  
  987.    if (ns == 0.0)                /* hue undefined if no saturation */
  988.    {
  989.       *h = 0.0;                  /* return black level (?) */
  990.       *s = 0.0;
  991.       *v = nv;
  992.       return;
  993.    }
  994.  
  995.    r1 = (nv - nr) / (nv - m);    /* distance of color from red   */
  996.    g1 = (nv - ng) / (nv - m);    /* distance of color from green   */
  997.    b1 = (nv - nb) / (nv - m);    /* distance of color from blue   */
  998.  
  999.    if (nv == nr)
  1000.    {
  1001.       if (m == ng)
  1002.          nh = 5. + b1;
  1003.       else
  1004.          nh = 1. - g1;
  1005.    } 
  1006.  
  1007.    if (nv == ng)
  1008.       {
  1009.       if (m == nb)
  1010.          nh = 1. + r1;
  1011.       else
  1012.          nh = 3. - b1;
  1013.       }
  1014.  
  1015.    if (nv == nb)
  1016.       {
  1017.       if (m == nr)
  1018.          nh = 3. + g1;
  1019.       else
  1020.          nh = 5. - r1;
  1021.       }
  1022.  
  1023.    *h = nh * 60.0;      /* return h converted to degrees */
  1024.    *s = ns;
  1025.    *v = nv;
  1026.    return;
  1027.    }
  1028.  
  1029.  
  1030. #if !__STDC__
  1031.  
  1032. /* ANSI Standard psuedo-random number generator */
  1033.  
  1034. static unsigned long int next = 1;
  1035.  
  1036. int rand()
  1037.    {
  1038.    next = next * 1103515245L + 12345L;
  1039.    return ((int) (next / 0x10000L) & 0x7FFF);
  1040.    }
  1041.  
  1042. void srand(seed)
  1043.    unsigned int seed;
  1044.    {
  1045.    next = seed;
  1046.    }
  1047.  
  1048. #endif
  1049.  
  1050.  
  1051. /* Math Error exception struct format:
  1052.     int type;        - exception type - see below
  1053.     char _FAR_ *name;    - name of function where error occured
  1054.     long double arg1;    - first argument to function
  1055.     long double arg2;    - second argument (if any) to function
  1056.     long double retval;    - value to be returned by function
  1057. */
  1058.  
  1059. int _cdecl matherr(e)
  1060.    struct exception *e;
  1061.    {
  1062.    if (Options & DEBUGGING) {
  1063.       /* Since we are just making pictures, not keeping nuclear power under
  1064.          control - it really isn't important if there is a minor math problem.
  1065.          This routine traps and ignores them.  Note: the most common one is
  1066.          a DOMAIN error coming out of "acos". */
  1067.       switch (e->type) {
  1068.      case DOMAIN   : printf("DOMAIN error in '%s'\n", e->name); break;
  1069.      case SING     : printf("SING   error in '%s'\n", e->name); break;
  1070.      case OVERFLOW : printf("OVERFLOW error in '%s'\n", e->name); break;
  1071.      case UNDERFLOW: printf("UNDERFLOW error in '%s'\n", e->name); break;
  1072.      case TLOSS    : printf("TLOSS error in '%s'\n", e->name); break;
  1073.      case PLOSS    : printf("PLOSS error in '%s'\n", e->name); break;
  1074.      case EDOM     : printf("EDOM error in '%s'\n", e->name); break;
  1075.      case ERANGE   : printf("ERANGE error in '%s'\n", e->name); break;
  1076.      default       : printf("Unknown math error in '%s'\n",e->name);break;
  1077.          }
  1078.       }
  1079.    return (1);    /* Indicate the math error was corrected... */
  1080.    }
  1081.