home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk10 / apps / mandel / mdraw.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-08-11  |  24.2 KB  |  1,002 lines

  1. /*    mdraw.c - display Mandelbrot set on EGA
  2.  *    R. A. Garmoe  86/12/15
  3.  */
  4.  
  5.  
  6.  
  7. /**    Mdraw displays the elements of the Mandelbrot set
  8.  *
  9.  *        z = z**2 + c
  10.  *
  11.  *    where z and c are in the complex plane and z = 0 + 0i for the first
  12.  *    iteration.  The elements of the set are displayed in black and
  13.  *    elements not in the set are displayed in color.  The data to be
  14.  *    displayed is computed by the program mandel.
  15.  */
  16.  
  17.  
  18. /**    Call
  19.  *
  20.  *    mdraw file file ...
  21.  *
  22.  *    where
  23.  *        file    a .cnt file created by the computation program mandel
  24.  *
  25.  *    All of the files are read and displayed in order.  After all of
  26.  *    the images are displayed, keystrokes have the following meaning.
  27.  *        e           edit palette registers
  28.  *                    up/down arrow - select register
  29.  *                    right/left arrow - select color
  30.  *        i           reinitialize palette registers
  31.  *        n           advance to next display
  32.  *        p           backup to previous display
  33.  *        q           cleanup and exit
  34.  *        r           decrement palette register ripple
  35.  *        R           increment palette register ripple
  36.  *        z           continous forward zoom through images
  37.  *        Z           continous backward zoom through images
  38.  *
  39.  *    All other characters are ignored.
  40.  */
  41.  
  42.  
  43.  
  44.  
  45. /*
  46.  *    The .cnt file has the format
  47.  *        int    number of points along the real axis
  48.  *        int    number of points along the imaginary axis
  49.  *        int    maximum iteration point for each point
  50.  *        double    real coordinate of upper left
  51.  *        double    imaginary coordinate of upper left
  52.  *        double    real coordinate of lower right
  53.  *        double    imaginary coordinate lower rightft
  54.  *        double    increment between points on real axis
  55.  *        double    increment between points on imaginary axis
  56.  *        long    (loop + 1) counters for histogram values
  57.  *
  58.  *    The remainder of the file is the run length encoded scan
  59.  *    lines encoded as:
  60.  *        int    number of words in scan line encoded as:
  61.  *            +int        actual count value for pixel
  62.  *            -int int    The first value is the run length and
  63.  *                    second value is the run value
  64.  */
  65.  
  66.  
  67.  
  68. #include <stdio.h>
  69. #include <subcalls.h>
  70. #include <doscalls.h>
  71. #include <dos.h>
  72. #include "mdraw.h"
  73.  
  74. /*    The routines that are in the IOPL segment must be declared
  75.  *    as pascal routines.  When the IOPL routine is called through
  76.  *    the intersegment call gate, the parameters are copied from the
  77.  *    ring 3 user's stack to the ring 2 IOPL stack.  The parameters
  78.  *    must be popped from the IOPL stack (and the ring 3 stack) by the
  79.  *    ret n instruction of the IOPL routine.    Otherwise, the ring 2
  80.  *    stack is left in an invalid state.  For more information, refer
  81.  *    to the 80286 Programmer's Manual for
  82.  *        intersegment calls
  83.  *        parameter passing through call gates
  84.  *        CALLs to and RETurns from inner protection rings
  85.  *
  86.  *    Note also that the number of words of passed parameters defined in
  87.  *    each of these functions must exactly match the word counts defined
  88.  *    in the EXPORTS statements in the mdraw.def linker definitions file.
  89.  */
  90.  
  91. extern void far pascal SetDVideo ();
  92. extern void far pascal SetEVideo ();
  93. extern void far pascal SetScanClear ();
  94. extern void far pascal SetScan (int, int, char *);
  95. extern void far pascal SetScanSave (unsigned far *);
  96. extern void far pascal SetScanSFont (unsigned);
  97. extern void far pascal SetScanRFont (unsigned);
  98. extern void far pascal SetScanRestore (unsigned far *);
  99. extern void far pascal SetCursor (char far *);
  100.  
  101.  
  102. void far mode_wait (void);    /* starting address for a thread */
  103. void far redraw_wait (void);    /* starting address for another thread */
  104.  
  105.  
  106.  
  107. /*    Structures for VIO calls */
  108.  
  109. struct    ConfigData config;    /* Display configuration data */
  110. struct    ModeData mode;        /* Display mode data */
  111. struct    ModeData grmode;    /* graphics display mode data */
  112. struct    PhysBufData physbuf;    /* Physical buffer data */
  113. struct    CursorData cursor;    /* Cursor data structure */
  114. struct    KeyData key;        /* Keystroke data */
  115. struct    VIOSTATE vstate;    /* Set vio state */
  116.  
  117.  
  118.  
  119.  
  120. char    pmand[60] = "mandel.cnt";
  121. FILE    *fmand;
  122.  
  123. char    chvalid = FALSE;    /* key valid if true */
  124. char    cinit[15] = {WHITE, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, IWHITE,
  125.              DGRAY, LBLUE, LGREEN, LCYAN, LRED, LMAGENTA, YELLOW};
  126. char    firstread = FALSE;    /* first character read from keyboard if true */
  127. char    flip = FALSE;        /* flip display pages if true */
  128. char    graphics = FALSE;    /* display is in graphics mode if true */
  129. char    mapped[MAXREAL];    /* character array holding mapped interation counters */
  130. char    initpal[16] = {
  131.     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  132.     0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F
  133. };
  134. char    palette[16] = {
  135.     0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
  136.     0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F
  137. };
  138.  
  139. char   *screenbuf;        /* pointer to buffer to hold text screen */
  140.  
  141. int    *bp;            /* pointer to next iteration counter in buf */
  142. int    buf[BUFFER];        /* run length encoded iteration counters */
  143. int    count = 0;        /* number of integers remaining in buf */
  144.  
  145. long    delay = 0;        /* ripple delay in milliseconds */
  146. long    drawsem = 0;        /* RAM semaphore to control drawing */
  147. long    hist[MAXLOOP + 1] = {0}; /* histogram counters */
  148.  
  149. struct image timage = {0};    /* local image descriptor structure */
  150. struct ilist *head = NULL;    /* pointer to head of ilist */
  151. struct ilist *curr = NULL;    /* pointer to current ilist */
  152. struct ilist *tail = NULL;    /* pointer to tail of ilist */
  153.  
  154. unsigned curcol;        /* cursor column position */
  155. unsigned currow;        /* cursor row position */
  156. unsigned descsel;        /* selector for image structure */
  157. unsigned fontsel;        /* selectors for font saves */
  158. unsigned dpoffset = 0;        /* display page offset 0x0000 or 0x8000 */
  159. unsigned *psel;         /* display memory selector */
  160. unsigned screenlen;        /* length of screen buffer */
  161.  
  162. main (argc, argv)
  163. int    argc;
  164. char    **argv;
  165. {
  166.     int    c;
  167.     int    i;
  168.     int    temp;
  169.     int    pal;
  170.     unsigned char    *stack1,      /* stack for mode_wait thread  */
  171.             *stack2;      /* stack for redraw_wait thread  */
  172.     unsigned    ThreadID;
  173.  
  174.     /*  Validate the display configuration.  It must be an EGA on an
  175.      *  EGA  adapter with at least 128k of memory.
  176.      */
  177.  
  178.     config.length = 10;
  179.     if ((temp = VIOGETCONFIG (0, (struct ConfigData far *)&config, 0)) != 0) {
  180.         printf ("Unable to get display configuration data - %d\n", temp);
  181.         exit (1);
  182.     }
  183.     if ((config.adapter_type != 2) || (config.display_type != 2) ||
  184.         config.memory_size < 0x20000) {
  185.         printf ("Display is not EGA on 128k EGA adapter %d %d %ld\n",
  186.             config.adapter_type, config.display_type, config.memory_size);
  187.         exit (1);
  188.     }
  189.  
  190.     if (config.memory_size == 0x40000)
  191.         flip = TRUE;
  192.  
  193.     /*  Save information about the current display mode.  This includes
  194.      *  the current mode as known by VIO, the cursor type data, the
  195.      *  current cursor position and the text screen data.
  196.      */
  197.  
  198.     mode.length = sizeof (struct ModeData);
  199.     if ((temp = VIOGETMODE ((struct ModeData far *)&mode, 0)) != 0) {
  200.         printf ("Unable to get display mode data - %d\n", temp);
  201.         exit (1);
  202.     }
  203.     if (VIOGETCURTYPE ((struct CursorData *)&cursor, 0) != 0) {
  204.         printf ("Unable to get current cursor data\n");
  205.         exit (1);
  206.     }
  207.     if (VIOGETCURPOS ((unsigned far *)&currow, (unsigned far *)&curcol, 0) != 0) {
  208.         printf ("Unable to get current cursor position\n");
  209.         exit (1);
  210.     }
  211.  
  212.     /*  Allocate buffer to hold text screen data.  Note that the buffer
  213.      *  size is doubled because of the attribute bytes.
  214.      */
  215.  
  216.     screenlen = mode.col * mode.row * 2;
  217.     if ((screenbuf = (char *)malloc (screenlen)) == NULL) {
  218.         printf ("Unable to allocate memory for text screen buffer\n");
  219.         exit (1);
  220.     }
  221.     if (VIOREADCELLSTR ((char far *)screenbuf, (unsigned far *)&screenlen,
  222.         0, 0, 0) != 0) {
  223.         printf ("Unable to read text screen data\n");
  224.         exit (1);
  225.     }
  226.  
  227.     /*  Obtain selectors to the display memory */
  228.  
  229.     physbuf.buf_start = 0xa0000;
  230.     physbuf.buf_length = 0x20000;
  231.     if ((temp = VIOGETPHYSBUF ((struct PhysBufData far *)&physbuf, 0)) != 0) {
  232.         printf ("Unable to get physical buffer mapping - %d\n", temp);
  233.         exit (1);
  234.     }
  235.     if (DOSALLOCSEG (0,(unsigned far *)&fontsel, 0) != 0) {
  236.         printf ("Unable to allocate text font save segment\n");
  237.         exit (1);
  238.     }
  239.     /* Allocate memory for separate thread execution */
  240.  
  241.     stack1 = (unsigned char *)malloc (STACKSIZE);
  242.     stack2 = (unsigned char *)malloc (STACKSIZE);
  243.     if (!stack1 || !stack2) {
  244.         printf ("Out of memory\n");
  245.         exit (1);
  246.     }
  247.     stack1 += STACKSIZE;
  248.     stack2 += STACKSIZE;
  249.  
  250.     /* create thread to execute the mode wait */
  251.  
  252.     DOSCREATETHREAD (mode_wait, &ThreadID, stack1);
  253.  
  254.     /* create thread that will execute the redraw_wait () */
  255.  
  256.     DOSCREATETHREAD (redraw_wait, &ThreadID, stack2);
  257.  
  258.  
  259.     /* Pass pointer to the selectors for display memory and the
  260.      * selector to the font save segment to the ring 2 IOPL code.
  261.      */
  262.  
  263.     psel = physbuf.selectors;
  264.  
  265.     /* Save the font tables */
  266.  
  267.     SetScanSFont (fontsel);
  268.  
  269.     /* Set the EGA to 640 x 350 graphics mode */
  270.  
  271.     grmode = mode;
  272.     grmode.type = grmode.type | 0x02;
  273.     grmode.hres = 640;
  274.     grmode.vres = 350;
  275.     VIOSETMODE ((struct ModeData far *)&grmode, 0);
  276.     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  277.     setpalette (palette);
  278.     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  279.  
  280.     /* Set the file name if specified and open the file for reading */
  281.  
  282.     argc--;
  283.     argv++;
  284.     graphics = TRUE;
  285.     printf ("Clearing screen\n");
  286.     SetScanClear ();
  287.     printf ("Screen cleared\n");
  288.     while (argc > 0) {
  289.         /* set file name */
  290.         strcpy (pmand, *argv);
  291.         strcat (pmand, ".cnt");
  292.         if ((fmand = fopen (pmand, "rb")) == NULL) {
  293.             cleandisplay ();
  294.             printf ("Unable to open count file %s\n", pmand);
  295.             exit (3);
  296.         }
  297.         readimage ();
  298.         fclose (fmand);
  299.         argc--;
  300.         argv++;
  301.     }
  302.  
  303.     /* Wait for keyboard input to switch display or terminate.  This
  304.      * thread must delay between checks for keyboard input.  Otherwise,
  305.      * the code will execute a CPU bound loop and all other threads
  306.      * and processes will execute at a reduced rate.
  307.      */
  308.  
  309.     while (TRUE) {
  310.         if (nextchar (&c, 1)) {
  311.             switch (c) {
  312.                 case 'e':
  313.                     /* edit palette registers */
  314.                     paledit ();
  315.                     break;
  316.  
  317.                 case 'i':
  318.                     /* reinitialize palette registers */
  319.                     for (i = 0; i < 16; i++)
  320.                         palette[i] = initpal[i];
  321.                     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  322.                     setpalette (palette);
  323.                     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  324.                     break;
  325.  
  326.                 case 'n':
  327.                     /* advance to next display */
  328.                     nextimage ();
  329.                     break;
  330.  
  331.                 case 'p':
  332.                     /* backup to previous display */
  333.                     previmage ();
  334.                     break;
  335.  
  336.                 case 'q':
  337.                     /* cleanup and exit */
  338.                     cleandisplay ();
  339.                     exit ();
  340.  
  341.                 case 'r':
  342.                     /* decrement palette register ripple */
  343.                     delay += SCANTIME;
  344.                     break;
  345.  
  346.                 case 'R':
  347.                     /* increment palette register ripple */
  348.                     delay -= SCANTIME;
  349.                     break;
  350.  
  351.                 case 'z':
  352.                     /* continous forward zoom through images */
  353.                     while (!nextchar (&c, 1))
  354.                         nextimage ();
  355.                     ungetchar ();
  356.                     break;
  357.  
  358.                 case 'Z':
  359.                     /* continous backward zoom through images */
  360.                     while (!nextchar (&c, 1))
  361.                         previmage ();
  362.                     ungetchar ();
  363.                     break;
  364.  
  365.                 default:
  366.                     /* ignore character */
  367.                     break;
  368.             }
  369.         }
  370.  
  371.         /* delay to prevent CPU bound loop */
  372.  
  373.         if (delay == 0)
  374.             DOSSLEEP ((long)100);
  375.         else if (delay > 0) {
  376.             ripple (RIPPLE_UP);
  377.             DOSSLEEP (delay);
  378.         }
  379.         else {
  380.             ripple (RIPPLE_DN);
  381.             DOSSLEEP ((long)(-delay));
  382.         }
  383.     }
  384. }
  385.  
  386.  
  387.  
  388.  
  389. /**    mdisp - display Mandelbrot set
  390.  *
  391.  *    mdisp (im);
  392.  *
  393.  */
  394.  
  395.  
  396.  
  397. mdisp (im)
  398. struct image far *im;
  399. {
  400.     int    i;
  401.     int    ni;            /* scan row counter */
  402.     int    temp;
  403.     int    len;
  404.     char    *pmapped;
  405.  
  406.     VIOSCRLOCK (1, (char far *)&temp, 0);
  407.     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  408.     SetScanClear ();
  409.     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  410.  
  411.     for (ni = 0; ni < im->lni; ni++) {
  412.         pmapped = mapped;
  413.         if (!nextvalue (&len))
  414.             break;
  415.         while ((--len >= 0) && (pmapped - mapped < im->lnr) && nextvalue (&i)) {
  416.             if (i >= 0)
  417.                 *pmapped++ = im->cmap[i];
  418.             else {
  419.                 if (!nextvalue (&temp))
  420.                     break;
  421.                 len--;
  422.                 temp = im->cmap[temp];
  423.                 for (; (i < 0) && (pmapped - mapped < im->lnr); i++)
  424.                     *pmapped++ = temp;
  425.             }
  426.         }
  427.  
  428.         /*  The scan line drawing is locked with a RAM semaphore so
  429.          *  the redraw-wait routine can save and restore the screen
  430.          */
  431.  
  432.         DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  433.         SetScan (ni, im->lnr, mapped);
  434.         DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  435.     }
  436.  
  437.     /*  Save screen image and unlock the screen */
  438.  
  439.     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  440.     SetScanSave (curr->desc->savesel);
  441.     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  442.  
  443.     VIOSCRUNLOCK (0);
  444. }
  445.  
  446.  
  447.  
  448.  
  449. /**    nextvalue - return next value from file
  450.  *
  451.  *    flag = nextvalue (ptr);
  452.  *
  453.  *    Entry    ptr = pointer to integer to receive value
  454.  *    Exit    *ptr = next value from file
  455.  *    Return    TRUE if next value returned
  456.  *        FALSE if end of file
  457.  */
  458.  
  459.  
  460. int nextvalue (p)
  461. int *p;
  462. {
  463.     if (count == 0) {
  464.         count = fread ((char *)buf, sizeof (int), BUFFER, fmand);
  465.         bp = buf;
  466.     }
  467.     if (count == EOF)
  468.         return (FALSE);
  469.     *p = *bp++;
  470.     count--;
  471.     return (TRUE);
  472. }
  473.  
  474.  
  475.  
  476.  
  477. /**    mode_wait - wait for mode reset request
  478.  *
  479.  *    This routine is executed by another thread that is started
  480.  *    by the main routine.
  481.  *
  482.  *    This routine calls VIOmode_wait requesting to be notified
  483.  *    after the completion of an application or hard error popup.
  484.  *    On such a notification, it puts the screen in the desired
  485.  *    graphics mode.
  486.  */
  487.  
  488. void mode_wait ()
  489. {
  490.     unsigned NotifyType;
  491.  
  492.     while (TRUE) {
  493.         /* wait for notification to restore mode */
  494.         VIOMODEWAIT (0, &NotifyType, 0);
  495.         if (NotifyType == 0 && graphics)
  496.             DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  497.             VIOSETMODE ((struct ModeData far *)&grmode, 0);
  498.             SetScanClear ();
  499.             DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  500.     }
  501. }
  502.  
  503.  
  504.  
  505.  
  506. /**    redraw_wait - wait for mode reset request
  507.  *
  508.  *    This routine is executed by another thread that is started
  509.  *    by the main routine.
  510.  *
  511.  *    This routine calls VioSavRedrawWait requesting to be notified
  512.  *    for both save and redraw.  On save notification, it copies the
  513.  *    EGA adapter memory to allocated memory segments.  On redraw
  514.  *    notification, it puts the screen in the desired graphics mode
  515.  *    and then redraws the Mandelbrot set.
  516.  */
  517.  
  518.  
  519. void redraw_wait ()
  520. {
  521.     unsigned NotifyType;
  522.  
  523.     while (TRUE) {
  524.         VIOSAVREDRAWWAIT (0, &NotifyType, 0);
  525.         if (graphics) {
  526.             if (NotifyType == 0) {
  527.                 /* save graphics screen */
  528.                 DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  529.                 SetScanSave (curr->desc->savesel);
  530.                 SetScanClear ();
  531.                 continue;
  532.             }
  533.             else if (NotifyType == 1) {
  534.                 /* restore graphics screen */
  535.                 dpoffset = 0;
  536.                 VIOSETMODE ((struct ModeData far *)&grmode, 0);
  537.                 SetScanClear ();
  538.                 SetDVideo ();
  539.                 SetScanRestore (curr->desc->savesel);
  540.                 SetEVideo ();
  541.                 DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  542.             }
  543.         }
  544.     }
  545. }
  546.  
  547.  
  548.  
  549.  
  550. /**    readimage - read and display next image
  551.  *
  552.  *    readimage ();
  553.  *
  554.  */
  555.  
  556.  
  557. readimage ()
  558. {
  559.     int    i;
  560.     struct ilist *tlist;
  561.     int    nr;
  562.  
  563.     /*  Allocate memory for image structure and link to chain of images */
  564.  
  565.     if ((tlist = (struct ilist *)malloc (sizeof (struct ilist))) == NULL) {
  566.         cleandisplay ();
  567.         printf ("Unable to allocate memory for ilist structure\n");
  568.         exit (1);
  569.     }
  570.     if (DOSALLOCSEG (sizeof (struct image),(unsigned far *)&descsel, 0) != 0) {
  571.         cleandisplay ();
  572.         printf ("Unable to allocate image descriptor segment of %d bytes\n", sizeof (struct image));
  573.         exit (1);
  574.     }
  575.  
  576.     FP_SEG (tlist->desc) = descsel;
  577.     FP_OFF (tlist->desc) = 0;
  578.  
  579.     /*  Read description of the computed Mandelbrot set from the file
  580.      *  and perform simple validation checks.  Limit the display rows and
  581.      *  columns to the display maximums.
  582.      */
  583.  
  584.     if (fread ((char *)&timage.nreal, sizeof (int), 1, fmand) != 1) {
  585.         cleandisplay ();
  586.         printf ("Error reading maximum number of reals %d\n", timage.nreal);
  587.         exit (2);
  588.     }
  589.     timage.lnr = (timage.nreal > 640)? 640: timage.nreal;
  590.     if (fread ((char *)&timage.nimag, sizeof (int), 1, fmand) != 1) {
  591.         cleandisplay ();
  592.         printf ("Error reading maximum number of imaginaries %d\n", timage.nimag);
  593.         exit (2);
  594.     }
  595.     timage.lni = (timage.nimag > 350)? 350: timage.nimag;
  596.     if (fread ((char *)&timage.mloop, sizeof (int), 1, fmand) != 1) {
  597.         cleandisplay ();
  598.         printf ("Error reading maximum loop count %d\n", timage.mloop);
  599.         exit (2);
  600.     }
  601.     if (fread ((char *)&timage.ul, sizeof (timage.ul), 1, fmand) != 1) {
  602.         cleandisplay ();
  603.         printf ("Error reading upper left coordinates\n");
  604.         exit (2);
  605.     }
  606.     if (fread ((char *)&timage.lr, sizeof (timage.lr), 1, fmand) != 1) {
  607.         cleandisplay ();
  608.         printf ("Error reading lower right coordinates\n");
  609.         exit (2);
  610.     }
  611.  
  612.     if (fread ((char *)&timage.rinc, sizeof (timage.rinc), 1, fmand) != 1) {
  613.         cleandisplay ();
  614.         printf ("Error reading real increment\n");
  615.         exit (2);
  616.     }
  617.     if (fread ((char *)&timage.iinc, sizeof (timage.iinc), 1, fmand) != 1) {
  618.         cleandisplay ();
  619.         printf ("Error reading imaginary increment\n");
  620.         exit (2);
  621.     }
  622.     if (fread ((char *)&timage.aspect, sizeof (timage.aspect), 1, fmand) != 1) {
  623.         cleandisplay ();
  624.         printf ("Error reading aspect ratio\n");
  625.         exit (2);
  626.     }
  627.     if (fread ((char *)timage.hist, sizeof (long), timage.mloop + 1, fmand) != timage.mloop + 1) {
  628.         cleandisplay ();
  629.         printf ("Error reading histogram\n");
  630.         exit (2);
  631.     }
  632.  
  633.     /*  Assign colors to each iteration count.  Black is reserved for
  634.      *  points within the Mandelbrot set.
  635.      */
  636.  
  637.     for (nr = 0; nr < timage.mloop; nr++) {
  638.         timage.cmap[nr] = (nr % 15) + 1;
  639.     }
  640.     timage.cmap[timage.mloop] = 0;
  641.  
  642.     /*  Allocate memory for segments to save graphics screen and
  643.      *  EGA font tables.
  644.      */
  645.  
  646.     for ( i = 0; i < 2; i++) {
  647.         if (DOSALLOCSEG (56020, (unsigned far *)&timage.savesel[i], 0) != 0) {
  648.             cleandisplay ();
  649.             printf ("Unable to allocate screen save segments\n");
  650.             exit (1);
  651.         }
  652.     }
  653.  
  654.     /* Link image to chain of images */
  655.  
  656.     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  657.     /* copy structure to far segment */
  658.     *(tlist->desc) = timage;
  659.     tlist->next = NULL;
  660.     tlist->prev = tail;
  661.     if (head == NULL)
  662.         head = tlist;
  663.     else
  664.         tail->next = tlist;
  665.     tail = tlist;
  666.     curr = tlist;
  667.  
  668.     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  669.  
  670.     /*  Lock the screen, set the display to graphics mode
  671.      *  and draw the Mandelbrot set
  672.      */
  673.  
  674.     mdisp (curr->desc);
  675. }
  676.  
  677.  
  678.  
  679.  
  680. /**
  681.  *
  682.  *
  683.  */
  684.  
  685. cleandisplay ()
  686. {
  687.     /* cancel mode wait and redraw wait threads */
  688.  
  689.     VIOMODEUNDO (GIVEUPOWNER, KILLTHREAD, RESERVED);
  690.     VIOSAVREDRAWUNDO (GIVEUPOWNER, KILLTHREAD, RESERVED);
  691.  
  692.     /*  Return the EGA adapter to a default mode that hopefully
  693.      *  matches the mode that was present when we went into graphics
  694.      *  mode.  Then restore mode data, text screen data, cursor
  695.      *  position and cursor type.
  696.      */
  697.  
  698.     SetDVideo ();
  699.     if (graphics) {
  700.         /* clear display memory */
  701.         dpoffset = 0;
  702.         SetScanClear ();
  703.         if (flip)
  704.             dpoffset = PAGESIZE;
  705.             SetScanClear ();
  706.         SetScanRFont (fontsel);
  707.     }
  708.     SetEVideo ();
  709.     VIOSETMODE ((struct ModeData far *)&mode, 0);
  710.     if (VIOWRTCELLSTR ((char far *)screenbuf, screenlen, 0, 0, 0) != 0) {
  711.         printf ("Unable to write text screen data\n");
  712.         exit (1);
  713.     }
  714.     if (VIOSETCURPOS (currow, curcol, 0) != 0) {
  715.         printf ("Unable to set current cursor position\n");
  716.         exit (1);
  717.     }
  718.     if (VIOSETCURTYPE ((struct CursorData *)&cursor, 0) != 0) {
  719.         printf ("Unable to set current cursor data\n");
  720.         exit (1);
  721.     }
  722. }
  723.  
  724.  
  725.  
  726. /**    nextimage
  727.  *
  728.  */
  729.  
  730.  
  731. nextimage ()
  732. {
  733.     int    temp;
  734.  
  735.     if (head != tail) {
  736.         DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  737.         if (curr->next == NULL)
  738.             curr = head;
  739.         else
  740.             curr = curr->next;
  741.         if (flip)
  742.             dpoffset ^= PAGESIZE;
  743.         SetScanRestore (curr->desc->savesel);
  744.         DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  745.     }
  746. }
  747.  
  748.  
  749.  
  750. /**    previmage
  751.  *
  752.  */
  753.  
  754.  
  755. previmage ()
  756. {
  757.     int    temp;
  758.  
  759.     if (head != tail) {
  760.         DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  761.         VIOSCRLOCK (1, (char far *)&temp, 0);
  762.         if (curr->prev == NULL)
  763.             curr = tail;
  764.         else
  765.             curr = curr->prev;
  766.         if (flip)
  767.             dpoffset ^= PAGESIZE;
  768.         SetScanRestore (curr->desc->savesel);
  769.         VIOSCRUNLOCK (0);
  770.         DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  771.     }
  772. }
  773.  
  774.  
  775.  
  776.  
  777. /**    ripple - ripple palette registers
  778.  *
  779.  *    ripple (direction);
  780.  *
  781.  *    Entry    direction = 0 if rotate palette registers up
  782.  *        direction = 1 if rotate palette registers down
  783.  *    Exit    palette registers rotated by one
  784.  *    Returns none
  785.  */
  786.  
  787.  
  788. ripple (dir)
  789. int dir;
  790. {
  791.     int temp;
  792.     int i;
  793.  
  794.     switch (dir) {
  795.         case RIPPLE_UP:
  796.             temp = palette[0x0f];
  797.             for (i = 0x0f; i > 1; i--)
  798.                 palette[i] = palette[i - 1];
  799.             palette[1] = temp;
  800.             break;
  801.  
  802.         case RIPPLE_DN:
  803.             temp = palette[1];
  804.             for (i = 1; i < 0x0f; i++)
  805.                 palette[i] = palette[i + 1];
  806.             palette[0x0f] = temp;
  807.             break;
  808.     }
  809.     DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  810.     setpalette (palette);
  811.     DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  812. }
  813.  
  814.  
  815.  
  816.  
  817. /**    flicker - flicker palette value
  818.  *
  819.  *    flicker (pal);
  820.  *
  821.  *    Entry    pal = index of register to flicker
  822.  *    Exit    palette register toggled between value and black
  823.  *        until keyboard input
  824.  *    Returns none
  825.  */
  826.  
  827.  
  828. flicker (pal)
  829. int pal;
  830. {
  831.     int temp;
  832.     int c;
  833.  
  834.     if ((pal > 0) && (pal < 0x10)) {
  835.         temp = palette[pal];
  836.         while (!nextchar (&c, 1)) {
  837.             palette[pal] = BLACK;
  838.             DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  839.             setpalette (palette);
  840.             DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  841.             DOSSLEEP ((long)100);
  842.             palette[pal] = temp;
  843.             DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  844.             setpalette (palette);
  845.             DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  846.             DOSSLEEP ((long)100);
  847.         }
  848.         ungetchar ();
  849.     }
  850. }
  851.  
  852.  
  853.  
  854.  
  855.  
  856. /**    paledit - edit palette registers
  857.  *
  858.  *    paledit ();
  859.  *
  860.  *    Entry    none
  861.  */
  862.  
  863.  
  864. paledit ()
  865. {
  866.     int    pal;
  867.     int    c;
  868.  
  869.     /* select palette register */
  870.  
  871.     pal = 1;
  872.     flicker (pal);
  873.     while (TRUE) {
  874.         nextchar (&c, 0);
  875.         switch (-c) {
  876.             case UP:
  877.                 if (pal++ > 0x0f)
  878.                     pal = 1;
  879.                 flicker (pal);
  880.                 break;
  881.  
  882.             case DOWN:
  883.                 if (pal-- < 1)
  884.                     pal = 0x0f;
  885.                 flicker (pal);
  886.                 break;
  887.  
  888.             case RIGHT:
  889.                 if (++palette[pal] > 0x3f)
  890.                     palette[pal] = 1;
  891.                 DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  892.                 setpalette (palette);
  893.                 DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  894.                 break;
  895.  
  896.             case LEFT:
  897.                 if (--palette[pal] == 0)
  898.                     palette[pal] = 0x3f;
  899.                 DOSSEMREQUEST ((unsigned long)(long far *)&drawsem, (long)-1);
  900.                 setpalette (palette);
  901.                 DOSSEMCLEAR ((unsigned long)(long far *)&drawsem);
  902.                 break;
  903.  
  904.             default:
  905.                 ungetchar ();
  906.                 return;
  907.         }
  908.     }
  909. }
  910.  
  911.  
  912.  
  913.  
  914. /**    nextchar - get next character from keyboard
  915.  *
  916.  *    flag = nextchar (pchar, wait);
  917.  *
  918.  *    Entry    char = pointer to character return location
  919.  *        wait = 0 if delay until character entered
  920.  *        wait = 1 if immediate return if no character
  921.  *    Exit    char = next character if found
  922.  *        char = -scan code if extend character
  923.  *    Return    flag = TRUE if character read from keyboard
  924.  *        flag = FALSE if no character read and immediate return
  925.  */
  926.  
  927.  
  928. nextchar (pchar, wait)
  929. int *pchar;
  930. int wait;
  931. {
  932.     int    ret;
  933.  
  934.     if (!chvalid) {
  935.         if ((ret = KBDCHARIN ((struct KeyData far *)&key, wait, 0)) != 0) {
  936.             cleandisplay ();
  937.             printf ("Error %d return from KBDCHARIN\n", ret);
  938.             exit (1);
  939.         }
  940.         firstread = TRUE;
  941.         if ((key.status & 0x40) != 0x40)
  942.             return (FALSE);
  943.     }
  944.     chvalid = FALSE;
  945.     if (key.char_code == 0x00)
  946.         /* process extended ASCII character */
  947.         *pchar = -(int)key.scan_code;
  948.     else
  949.         *pchar = (int)key.char_code;
  950.     return (TRUE);
  951. }
  952.  
  953.  
  954.  
  955.  
  956.  
  957. /**    ungetchar - unget character from keyboard
  958.  *
  959.  *    ungetchar ();
  960.  *
  961.  *    Entry    none
  962.  *    Exit    previous character returned to keyboard
  963.  *    Return    none
  964.  */
  965.  
  966.  
  967. ungetchar ()
  968. {
  969.     if (firstread)
  970.         chvalid = TRUE;
  971. }
  972.  
  973.  
  974.  
  975.  
  976. /**    setpalette - set EGA palette registers
  977.  *
  978.  *    setpalette (palette);
  979.  *
  980.  *    Entry    palette = byte array of palette registers
  981.  *    Exit    palette registers written to EGA
  982.  *    Return    none
  983.  */
  984.  
  985.  
  986. setpalette (p)
  987. char   *p;
  988. {
  989.     int    *ip;
  990.  
  991.     vstate.length = sizeof (struct VIOSTATE);
  992.     vstate.req_type = 0;
  993.     vstate.double_defined = 0;
  994.     for (ip = &vstate.palette0; ip <= &vstate.palette15; )
  995.         *ip++ = *p++;
  996.     if (VIOSETSTATE ((struct VIOSTATE far *)&vstate, 0) != 0) {
  997.         cleandisplay ();
  998.         printf ("Unable to set palette registers\n");
  999.         exit (1);
  1000.     }
  1001. }
  1002.