From: mcdonald@uxe.cso.uiuc.edu (J.D. McDonald )
Newsgroups: comp.sources.misc
Subject: v02i023: EGAFAST IBM-PC Graphics Package, Part 2/2
Message-ID: <7134@ncoast.UUCP>
Date: 26 Jan 88 04:30:40 GMT
Approved: allbery@ncoast.UUCP

Comp.sources.misc: Volume 2, Issue 23
Submitted-By: J.D. McDonald <mcdonald@uxe.cso.uiuc.edu>
Archive-Name: egafast/Part2

due to the size, distribution is in two parts 
This is part 2.

*********begin second copy of READ.ME*************
This is a very simple graphics package for the EGA and VGA. It draws the
basic primitives of lines, ellipses, filled rectangles, filled ellipses,
and text (two sizes and user defined). It is written to get the ultimate
in high speed possible while drawing in the set/reset mode. It can be
called from Microsoft C and Fortran, or any language including assembler
which follows their calling conventions.
Here is a list of the included files:

CLIPLINE C     Source code for clipped line routine.
EGAFORT  H     Header file for subroutine prototypes for Fortran.
EGAGRA   ASM   The main graphics package source.
EGAGRA   DOC   Documentation.
EGATEST  C     A test program to verify correct compilation.
ELLIPSE  C     Source code for ellipse drawers.
GRAFEX1  C     Example program that draws a star.
GRAFEX2  C     Example program that uses user-defined patterns.
INTEST   ASM   Assembler subroutine for SLUGS.FOR
MACROS   AH    Header file for EGAGRA.ASM which defines memory model.
MOVERM   C     Example program for plane masking.
MOVERS   C     Example program for page swapping and plane masking.
SLUGS    FOR   Example program in Fortran whose results look nice.

Some of the code in this package is patterned after that of U.E.Kruse of
the U. of I. Physics department. The grafex1 demo program generates
essentially the same pattern as the one of the same name in the package
by Scott Snyder of caltech recently posted on the net. The macros.ah
is also from his package.

Your comments are welcome, especially if you see anything faster.

Doug McDonald
University of Illinois
505 S. Matthews 
Urbana Ill. 61801
(mcdonald@uiucuxe or mcdonald@uxe.cso.uiuc.edu)


***********end second copy of READ.ME***********
***********begin file ELLIPSE.C*****************
/* Draw an ellipse with width irx and height iry                         */
/* from a routine by Tim Hogan in Dr. Dobb's Journal May '85 p.40        */
/* Improved by calculating increments incrementally, thus removing all   */
/* multiplies from the loops. These multiplies were very bad since they  */
/* were (long)*(long). This code, when compiled by Microsoft C Version 4,*/
/* can't be significantly improved by hand optimization.                 */
/* Written Sept. 7, 1987 by J.D. McDonald (public domain)                */

static long     alpha, beta, alpha2, alpha4, beta2, beta4, d;
static long     ddx, ddy, alphadx, betady;
static int      dy, dx;

extern void     e_start();	/* Starts off by writing right and left
				 * points                                */
extern void     e_xd();	/* Moves one step to lower x (in all 4 quadrants)*/
extern void     e_xdyu();	/* Moves to lower x, higher y            */
extern void     e_yu();   	/* Moves to higher y                     */

ellipse(x, y, irx, iry, c)
    int             x, y, irx, iry;
    unsigned        c;
{

    beta = (long) irx *(long) irx;
    alpha = (long) iry *(long) iry;

    if (alpha == 0L)
	alpha = 1L;
    if (beta == 0L)
	beta = 1L;

    dy = 0;
    dx = irx;
    alpha2 = alpha << 1;
    alpha4 = alpha2 << 1;
    beta2 = beta << 1;
    beta4 = beta2 << 1;
    alphadx = alpha * dx;
    betady = 0;
    ddx = alpha4 * (1 - dx);
    ddy = beta2 * 3;

    d = alpha2 * ((long) (dx - 1) * dx) + alpha + beta2 * (1 - alpha);
    e_start(x - dx, x + dx, y, c);

    do {
	if (d >= 0) {
	    d += ddx;
	    dx--;
	    alphadx -= alpha;
	    ddx += alpha4;
	    e_xdyu();
	} else
	    e_yu();
	d += ddy;
	dy++;
	betady += beta;
	ddy += beta4;
    } while (alphadx > betady);

    d = beta2 * ((long) dy * (dy + 1)) + alpha2 * ((long) dx * (dx - 2) + 1) 
	+ beta * (1 - alpha2);
    ddx = alpha2 * (3 - (dx << 1));
    ddy = beta4 * (1 + dy);

    do {
	if (d <= 0) {
	    d += ddy;
	    ddy += beta4;
	    dy++;
	    e_xdyu();
	} else
	    e_xd();
	d += ddx;
	ddx += alpha4;
	dx--;
    } while (dx > 0);
}

fillelip(x, y, irx, iry, c)
    int             x, y, irx, iry;
    unsigned        c;
{

    beta = (long) irx *(long) irx;
    alpha = (long) iry *(long) iry;

    if (alpha == 0L)
	alpha = 1L;
    if (beta == 0L)
	beta = 1L;

    dy = 0;
    dx = irx;
    alpha2 = alpha << 1;
    alpha4 = alpha2 << 1;
    beta2 = beta << 1;
    beta4 = beta2 << 1;
    alphadx = alpha * dx;
    betady = 0;
    ddx = alpha4 * (1 - dx);
    ddy = beta2 * 3;

    d = alpha2 * ((long) (dx - 1) * dx) + alpha + beta2 * (1 - alpha);
    rectfill(x - dx, y, x + dx, y, c);

    do {
	if (d >= 0) {
	    d += ddx;
	    dx--;
	    alphadx -= alpha;
	    ddx += alpha4;
	}
	d += ddy;
	dy++;
	betady += beta;
	ddy += beta4;
	rectfill(x - dx, y + dy, x + dx, y + dy, c);
	rectfill(x - dx, y - dy, x + dx, y - dy, c);
    } while (alphadx > betady);

    d = beta2 * ((long) dy * (dy + 1)) + alpha2 * ((long) dx * (dx - 2) + 1) 
	+ beta * (1 - alpha2);
    ddx = alpha2 * (3 - (dx << 1));
    ddy = beta4 * (1 + dy);

    do {
	dx--;
	if (d <= 0) {
	    d += ddy;
	    ddy += beta4;
	    dy++;
	    rectfill(x - dx, y + dy, x + dx, y + dy, c);
	    rectfill(x - dx, y - dy, x + dx, y - dy, c);
	}
	d += ddx;
	ddx += alpha4;
    } while (dx > 0);
}

***********end file ELLIPSE.C*******************
***********begin file CLIPLINE.C****************
/*routine to plot clipped line*/
clipline(x1,y1,x2,y2,icol)
int x1,y1,x2,y2,icol;
{
    int x3, y3, x4, y4;
    if(clip_ln(x1,y1,&x3,&y3,x2,y2)){
      if(clip_ln(x2,y2,&x4,&y4,x3,y3))
         zline(x4,y4,x3,y3,icol);
    }
}

/* routine to clip one endpoint of a line */
/* to clip to a rectangle instead of the screen, change MINX, MAXX, and MINY
   to input parameters instead of defines, and fix maxy also */
#define MINY 0
#define MINX 0
#define MAXX 639
extern int max_lin(void);
int clip_ln(x1,y1,xc,yc,x2,y2)
int x1,y1,x2,y2,*xc,*yc;
{
  int delx,dely,maxy;
  long templ; 
  maxy = max_lin() - 1;
  *xc=x1; 
  *yc=y1;
  if ( y1 >= MINY && y1 <= maxy && x1 >= MINX && x1 <= MAXX) 
     return(1);
  dely=y1-y2;
  delx=x1-x2;
  if (y1 > maxy || y1 < MINY) {
    if (y1 > maxy) {
      if (y2 > maxy) return (0);
      *yc=maxy;
    } else {
      if (y2 < MINY ) return(0);
      *yc=MINY;
    }
    templ = (long)(*yc-y2)*(long)delx;
    *xc=templ/dely+x2;
    if (*xc >= MINX && *xc <= MAXX) {
      return(1);
    }
  }
  dely=*yc-y2;
  delx=*xc-x2;
  if (*xc > MAXX || *xc < MINX) {
    if (*xc > MAXX) {
      if (x2 > MAXX ) return(0);
      *xc=MAXX;
    }
    else {
      if (x2 < MINX ) return(0);
      *xc=MINX;
    }
    templ = (long)(*xc-x2)*(long)dely;
    *yc=templ/delx+y2;
    if (*yc >= MINY && *yc <= maxy) {
      return(1);
    }
  }
  return(0);
}

*********************end file CLIPLINE.C*************
*********************begin file GRAFEX1.C************

#include <stdio.h>
#include <math.h>

#define pi 3.1415926

main()
{
  int n, i, j, d;
  unsigned color;
  struct {
    int x, y;
  } vert[32];

  do {
    printf("Enter number of vertices, 4 to 32: ");
    scanf("%d", &n);
    if ( n < 4 || n > 32 ) printf("Try again!\n");
     } while( n < 4 || n > 32);

  setmod(16);     /*change ega to graphics mode*/
  zsetup();       /*initialize drawing package...bios drawing stops working */

/* space n vertices equally on an ellipse that fits nicely on the screen */

  for (i=0; i<n; i++) {
    vert[i].x = 319.49 + 200.*sin(2*pi/n*i);
    vert[i].y = 174.49 - 160.*cos(2*pi/n*i);
  }

/*
 * draw the figure. the colors are selected so that points that are the
 * same distance from each other on the ellipse have the same color.
 */

  for (i=0; i<n; i++)
    for (j=i+1; j<n; j++) {
      d = j-i;
      if (d > n/2) d = n - d;
      color = (float)d/(n/2+1)*15 + 1;
      zline(vert[i].x, vert[i].y, vert[j].x, vert[j].y, color);
    }

/* wait... */

  curmod();    /*reset to allow bios to draw letters */
  printf("Press any key...");
  getch();

/* and clean up. */

  setmod(3);   /*back to text mode*/
}

*******************end file GRAFEX1.C***************
*******************begin file GRAFEX2.C*************
char bigsym[5] = {60,102,195,102,60};
char littlesym[5] = {0,24,60,24,0};

main()
{
      char *cptr;
      int i, ix, iy, icount, icolor;
      setmod(16);  /* set graphics mode*/
      zsetup(); /*initialize graphics package*/
      for (icount = 0 ; icount < 10000 ; icount++){
            ix = rand()/51;
            iy = rand()/93;
            icolor = rand() & 7;

/*    symbol(ix,iy,iheight,icolor,symbol) draws a rectangular pattern 8 bits
      wide and iheight bits high with upper left corner at ix,iy in color
      *symbol. The patterns in this program are 
                     bigsum               littlesym

                    ..****..              ........
                    .**..**.              ...**...
                    **....**              ..****..
                    .**..**.              ...**...
                    ..****..              ........
     The result is a little spot with a bright center and a dim border.     */

                    
            symbol(ix,iy,5,icolor+8,littlesym);
            symbol(ix,iy,5,icolor,bigsym);
         }
      for(i = 0 ,cptr = "Hit any key to quit."; *cptr ;i++)
          llettr(i << 3,0,*cptr++,15);

      while(!kbhit());
      getch();
      setmod(3);   /*go back to text mode*/
}


*******************end file GRAFEX2.c***************
*******************begin file EGAGRA.DOC************
             EGAGRA - Fast Graphics Routines for the EGA or VGA

      Egagra is as set of high speed graphics routines for the IBM EGA
and VGA graphics systems. It runs on these in the BIOS modes 15, 16, and 18,
which are 350X640 monochrome, 350X640 16 color and 480 X 640 16 color
modes respectively. It provides routines for lines, filled rectangles,
and open and filled ellipses, as well as two sizes of text and a routine
to display text-like patterns. The routines (including the text ones) all
draw over any previous pattern in a given area; the text ones do not result
in a black rectangle around the text. The text drawing routines also allow
text to be places to any arbitrary pixel position. A mask function allows
writing to one or more bit planes while leaving others uneffected.
      All of these routines are written in assembler in the calling sequence
of Microsoft C, except for the ellipses and the clipped-line routine which
are in C. A header file is provided so they can be used from Microsoft
Fortran without changes. A set of demonstration programs in C and Fortran
is included.
      The first subroutine called when using this package is setmod(n),
where n is the desired graphics mode. This simply calls the ROM BIOS to 
set the desired mode; it still leaves the system in a text state so that
the io routines of the language used are operational. The actual graphics
calls (including text routines slettr, llettr and symbol) must be preceeded
by a call to zsetup. After this call, language io to the console, such
as printf or scanf in C or read and write to the console in Fortran, results
in garbage. However, a call to curmod then re-enables language io. In 
other words, between calls to zsetup and curmod you use these graphics
routines, while after curmod calls you use the facilities of the programming
language. (Of course, there is no effect on io to disk files or COM ports.)
At the end of you program there must be a call to reset the BIOS mode to
the original value, usually 2, 3, or 7. If this isn't done, DOS will write
garbage to the screen, a problem which can be fixed from DOS by using
MODE CO80, MODE BW80 or MODE MONO as desired. When using an EGA with the
minimum memory on an IBM monochrome display in mode 15, use colors 0,
3, 12 and 15 only.   
      All the drawing routines except zpoint clip the drawing to the
horizontal confines of the screen. The rectangle and filled ellipse ones 
clip vertically also. The rest simply draw on the portion of the screen
buffer which is not mapped to the screen. A really long line or big ellipse
will "wrap around". A routine called clipline draws a line clipped to the
screen area.
     Since these routines use the set/reset register of the ega, and the
BIOS doesn't, if you ctrl-break out of one of them into DOS, screen
garbage results. You should therefore put the zsetup/curmod calls closely
around the actual drawing routines, and to be sure, trap the MS-DOS
break interrupt and call a setmod(orig_mode) in the inteppupt routine.
     The following description is for the C versions of the subroutines.
The calling sequence for Fortran can be seen in the header file EGAFORT.H,
which should be included in any Fortran routine using them. The routines
will work in any memory model, but must be compiled separately for each.
To make a library for a given model, perform the following steps:
     1. Edit MACROS.AH to define the appropriate memory model. 
     2. Use MASM on egagra.asm.
     3. Compile ELLIPSE.C with the appropriate memory model switch, 
        either /AS /AM /AC or /AL for small, medium, compact, or large.
        ALSO use the /Fa switch. This will generate an ellipse.asm file.
     4. Use MASM on ellipse.asm.
     5. Repeat steps 4 & 5 on clipline.c.
     6. Use LIB to combine the three .obj files into a library
        egagrafs.lib, egagrafm.lib, egagrafc.lib, or egagrafl.lib as
        appropriate.
The contortions involved in making a .asm file out of ellipse and clipline
and THEN assembling it are needed ONLY if you wish to use the library file
with Fortran. This is done so that the C run-time library will not be
automatically called, even if using Fortran. The ellipse routines don't
need any run-time routines out of the C libraries, as all the necessary
ones exist in Fortran. If you NEVER use Fortran, just compile ellipse.c
directly with the correct memory-model switch. If you only have a Fortran
compiler, you're out of luck with ellipses and clipped lines unless you 
translate ellipse.c and clipline.c into Fortran (which is perfectly easy.)

                    Subroutine Descriptions

                    Utility Routines

setmod(i)
int i;
              This routine calls the BIOS to put the graphics adapter
              into mode i.


zsetup()
              This routine initializes graphics drawing mode (see
              text above). Zsetup is cancelled by curmod. The special
              graphics drawing mode used by this package is slightly
              different from the normal bios mode with the same resolution.

curmod()
              This routine returns the adapter to normal bios drawing
              mode, allowing BIOS calls to produce text.  

setpal(ipal,icol)
int ipal, icol;
              This routine changes the color produced by call a drawing
              routine with color ipal to the physical color icol.
              Ipal is a number from 0 to 15 whereas icol can vary from
              0 to 63.

setpals(palete)
char *palete;
              The useage in a C program is
                    char pal[17];
                    setpals(pal);
              where pal[0] to pal[15] are preset to the value desired
              for the corresponding drawing color. pal[16] is the
              border color; for ega mode it must be set to 0; the
              other 16 values can range from 0 to 63. This call, unlike
              setpal, sets all the 16 colors in one call.

setmask(mask)
int mask;
              This routine sets the bit map write enable mask. Since this
              is rather cryptic, a bit of explanation is in order.
              Consider a given pixel. Let's say it is presently in color
              1. If we set mask to 15, which is the default state, and
              write a point at that pixel with color 4, the pixel changes
              to color 4. Set it back to 1. But now set mask to 4. Then
              write color 4. The hardware then allows changes only to the
              4's bit of the color; the 1's, 2's and 8's bits are write 
              protected. Hence the color changes to 5. If we now set mask 
              to 11 (1+2+8) and write a color 0, the color, now 5, changes 
              to 4, since the 4's bit was protected. For an example
              of the use of this, see the program "movers.c" and "moverm.c",
              which generate exactly the same diaplay. The only difference
              is that "movers.c" also uses page swapping.


setdraw(i)
int i;
              This routine sends all following output to display page i.
              Note that i must be 0 or 1. See the example program
              "movers.c". A page need not be visible to be written to.
              Apparently the VGA mode 18 has only one page.

setdisp(i)
int i;
              This routine causes page i (0 or 1) to be visible on the 
              screen. See the example program "movers.c".



                    Text Routines

slettr(ix, iy, ichr, col)
int ix, iy, ichr, col;

llettr(ix, iy, ichr, col)  
int ix, iy, ichr, col;
             
             These two routines write text. They differ only in that slettr
             draws using the 8 pixel high BIOS character set, while llettr
             uses the ega 14 pixel high set. Ix and iy are the pixel
             location of the upper left corner of the character box. They
             need not be at a normal text cursor position; any value
             -7 < ix < 647 and -14 < iy < (screen height + 13) is OK.
             Ichr is the character; any value in the drawing set will 
             work including the values less than 32 and the ones between
             128 and 255. Character 219 is good for filling a whole
             character box, such as simulating a background color. The
             VGA 8x16 character set could be added by adapting the
             initialization parts of slettr and llettr. I'm going to do
             so when I get a PS/2, and call it xlettr. Adding a 9th
             pixel row would be trickier.
             

symbol(ix,iy,height,col,symb)
int ix, iy, height, col;
char *symb;
             This routine operates just like the text routines except
             that it draws a character of height height whose description
             is contained in the array symb. Thus with height = 8
             you can set an arbitrary patten of 256 pixels in an 8x8 
             array. You can define your own character set, or use it
             for icons.

                    Drawing Routines

zline(ix0, iy0, ix1, iy1, col)
int ix0, iy0, ix1, iy1, col;
             
             This routine draws a line from ix0, iy0 to ix1, iy1 in
             color col. The horizontal extent is restricted to the screen.

clipline(ix0, iy0, ix1, iy1, col)
int ix0, iy0, ix1, iy1, col;
             
             This routine draws a line from ix0, iy0 to ix1, iy1 in
             color col. It is restricted to the screen.

rectfill(ix0, iy0, ix1, iy1, col)
int ix0, iy0, ix1, iy1, col;

             This routine draws a solid rectangle between diagonally
             opposite corners ix0, iy0 and ix1, iy1 in color col.
             Both horizontal and vertical extents are clipped to the screen.

ellipse(ix0, iy0, irx, iry, col)
int ix0, iy0, irx, iry, col;

fillelip(ix0, iy0, irx, iry, col)
int ix0, iy0, irx, iry, col;

             These routines draw ellipses centered at ix0, iy0 with
             horizontal and vertical semi-axes irx and iry in color col.
             Ellipse is open, fillelip is solid. The horizontal extent
             is clipped to the screen. For a normal ega monitor,
             iry = .8*irx generates a circle.

These routines were written by J. D. McDonald at the University of
Illinois and are public domain.

****************end file EGAGRA.DOC***************
****************begin file EGATEST.C**************
char palete1[] = { 56, 9, 18, 27, 36, 45, 54, 63,
             0, 1, 2, 3, 4, 5, 6, 7, 0};
char palete2[] = { 0, 1, 2, 3, 4, 5, 6, 7,
             56, 9, 18, 27, 36, 45, 54, 63, 0};
unsigned char pattern[] = {204, 102, 51, 102, 204, 153, 51, 102,
                           204, 102, 51, 102, 204, 153, 51, 102,
                           204, 102, 51, 102, 204, 153, 51, 102 }; 

main()
{
char *cptr;
int i, j, imode;
int maxline = 350;
do {
    printf("Enter mode number, 16 for EGA, 16 or 18 for VGA");
    scanf("%d",&imode); 
 }  while( imode != 16 && imode != 18);
if(imode == 18) maxline = 480;
setmod(imode);
zsetup();
for(i = 0 ,cptr = "This should be large brown letters."; *cptr ;i++)
       llettr(i << 3,0,*cptr++,6);
for(i = 0 ,cptr = "At the upper left corner of the screen.";  *cptr ;i++)
       llettr(i << 3,14,*cptr++,6);
for(i = 0 ,cptr = "\003 \033There should be half a green heart (\003) at"; *cptr ;i++)
       llettr((i << 3)-3,maxline/2-7,*cptr++,2);
for(i = 0 ,cptr = "   the center of each edge of the screen."; *cptr ;i++)
       llettr((i << 3)-3,maxline/2+7,*cptr++,2);
llettr(316,-7,3,2);
llettr(316,maxline-7,3,2);
llettr(636,maxline/2-7,3,2);
for(i = 0 ,cptr = "This should be small bright blue letters."; *cptr ;i++)
       slettr(i << 3,30,*cptr++,9);
ellipse(500,100,50,90,3);
fillelip(500,100,20,20,4);
for(i = 0 ,cptr = "Small filled red ellipse"; *cptr ;i++)
       llettr(400+(i << 3),196,*cptr++,4);
for(i = 0 ,cptr = "Large open cyan ellipse"; *cptr ;i++)
       llettr(400+(i << 3),210,*cptr++,3);
rectfill(100,250,539,300,7);
zline(99,249,540,249,13);
zline(99,249,99,301,13);
zline(99,301,540,301,13);
zline(540,249,540,301,13);
zline(99,249,540,301,13);
zline(99,301,540,249,13);
for(i = 0 ,cptr = "Gray rectangle with violet border and cross."; *cptr ;i++)
       llettr(142+(i << 3),310,*cptr++,13);
for(i = 0 ,cptr = "Hit any key."; *cptr ;i++)
       llettr(40+(i << 3),100,*cptr++,7);
for(i = 0; i < 245; i += 8)symbol(i,50,24,6,pattern);
for(i = 0 ,cptr = " Yellow text on brown pattern."; *cptr ;i++)
       llettr((i << 3),55,*cptr++,14);
for(i = 0 ,cptr = "This will appear only in mode 18"; *cptr ;i++)
       llettr((i << 3),390,*cptr++,7);
zline(0,412,256,412,7);
while(!kbhit());
setpals(palete1);
getch();
for(i = 0 ,cptr = "Dark and light colors should be reversed."; *cptr ;i++)
       llettr(40+(i << 3),196,*cptr++,7);
while(!kbhit());
getch();
for(i = 0 ,cptr = "The red ellipse should now be green."; *cptr ;i++)
       llettr(40+(i << 3),210,*cptr++,7);
rectfill(50,480,100,600,7);
setdraw(1);
for(i = 0 ,cptr = "This is the second video page."; *cptr ;i++)
       llettr(150+(i << 3),200,*cptr++,7);
for(i = 0 ,cptr = "Three lines of text, and nothing else,should appear."
                ; *cptr ;i++)llettr(150+(i << 3),215,*cptr++,7);
for(i = 0 ,cptr = "Hit any key."; *cptr ;i++)
       llettr(150+(i << 3),230,*cptr++,7);
setpal(4,18);
while(!kbhit());
getch();
setpals(palete2);
setdisp(1);
while(!kbhit());
getch();
setmod(3);
} 

*****************end file EGATEST.C*****************
*****************begin file MOVERS.C****************
#include <math.h>
#define PI128 3.141585/128.
    char quit_string[] = "Hit any key to quit.";
    char palete1[17] = { 0, 1, 58, 58, 62, 62, 62, 62, 4,
                           7, 4, 4,  4,  4,  4,  4, 0 } ;
/*This program draws a moving ball with animation done using the page
  swapping method. It is speed limited by the necessity to swap only
  during vertical retrace.                                            */


double xs[256], ys[256];
main()
{
    int  x1, y1, x2, y2, i, icol, j;
    double x, y;

    setmod(16);
    zsetup();
    setpals(palete1);    
    setmask(15);
    setdraw(0);
    rectfill(0,0,639,349,0);
    for (i = 0; i < 8; i++) {
      rectfill(i*80, 0, i*80+19,349,1);
      rectfill(i*80+40, 0 , i*80+59, 349,8);
    }
    for (i = 0; i < 20; i++) llettr(i*9, 16, quit_string[i], 9);
    setdraw(1);
    rectfill(0,0,639,349,0);
    for (i = 0; i < 8; i++) {
      rectfill(i*80, 0, i*80+19,349,1);
      rectfill(i*80+40, 0 , i*80+59, 349,8);
    }
    for (i = 0; i < 20; i++) llettr(i*9, 16, quit_string[i], 9);
      setmask(6);
    x2=320;
    y2=175;
    for (i = 0; i < 256; i++) {
        xs[i] = 320.-300.*sin(PI128*i);
        ys[i] = 175.+100.*cos(PI128*i);
    }
    for (i = 0; !kbhit() ; i = (i+1) & 255 ) {
      if( i & 1) {
          setdisp(0);
          setdraw(1);
      } else {
          setdisp(1);
          setdraw(0);
      }    
      while( !( inp(0x3da) & 8));      
        x= xs[i];
        y= ys[i];
        rectfill(x2-10,y2-9,x2+10,y2+9,0);
          x2 = x1;
          y2 = y1;
          x1 = x;
          y1 = y;
          if(y1 > 175 && x1 >= 50 && x1 <= 130) icol = 2;
              else icol = 4;
          fillelip(x1,y1,10,8,icol);
    }
    setdisp(0);
    setmod(3);
 }


**************end file MOVERS.C***************
**************begin file MOVERM.C*************
#include <math.h>
#define PI128 3.141585/128.
    char quit_string[] = "Hit any key to quit.";
    char palete1[17] = { 0, 1, 0, 1, 62, 62, 62, 62, 4,
                           7, 4, 4,  4,  4,  4,  4, 0 } ;
    char palete2[17] = { 0, 1, 62, 62, 0, 1, 62, 62, 4,
                           7, 4, 4,  4,  4,  4,  4, 0 } ;
    char palete3[17] = { 0, 1, 0, 1, 58, 58, 58, 58, 4,
                           7, 4, 4,  4,  4,  4,  4, 0 } ;
    char palete4[17] = { 0, 1, 58, 58, 0, 1, 58, 58, 4,
                           7, 4, 4,  4,  4,  4,  4, 0 } ;
/*This program draws a moving ball with animation done using the palete
  swapping method. It is speed limited by the necessity to swap only
  during vertical retrace.                                            */

double xs[256], ys[256];

main()
{
    int  x1, y1, x2, y2, i;
    double x, y;

    setmod(16);
    zsetup();
    setpals(palete1);    
    setmask(15);
    for (i = 0; i < 8; i++) {
      rectfill(i*80, 0, i*80+19,349,1);
      rectfill(i*80+40, 0 , i*80+59, 349,8);
    }
    for (i = 0; i < 256; i++ ) {
      xs[i] = 320.-300.*sin(PI128*i);
      ys[i] = 175.+100.*cos(PI128*i);
    }
    x2=320;
    y2=175;
    for (i = 0; i < 20; i++) llettr(i*9, 16, quit_string[i], 9);
    for (i = 0; !kbhit() ; i = (i+1) & 255 ) {
      x= xs[i];
      y= ys[i];
      if( i & 1) {
          setmask(4);
          rectfill(x2-10,y2-9,x2+10,y2+9,0);
          x2 = x1;
          y2 = y1;
          x1 = x;
          y1 = y;
          fillelip(x1,y1,10,8,4);
          if(y1 > 175 && x1 >= 50 && x1 <= 130) setpals(palete3);
              else setpals(palete1);
      } else {
          setmask(2);
          rectfill(x2-10,y2-9,x2+10,y2+9,0);
          x2 = x1;
          y2 = y1;
          x1 = x;
          y1 = y;
          fillelip(x1,y1,10,8,2);
          if(y1 > 175 && x1 >= 50 && x1 <= 130) setpals(palete4);
              else setpals(palete2);
      }  
    }
    setmod(3);
 }



***************end file MOVERM.C**************
***************begin file INTEST.ASM**********
_TEXT	SEGMENT  BYTE PUBLIC 'CODE'
_TEXT	ENDS
_DATA	SEGMENT  WORD PUBLIC 'DATA'
_DATA	ENDS
CONST	SEGMENT  WORD PUBLIC 'CONST'

CONST	ENDS
_BSS	SEGMENT  WORD PUBLIC 'BSS'

_BSS	ENDS
DGROUP	GROUP	CONST, _BSS, _DATA
	ASSUME  CS: _TEXT, DS: DGROUP, SS: DGROUP, ES:  DGROUP
_TEXT      SEGMENT


;intest.asm
;if there is no input returns 0
;if there is input it returns 255

intest          PROC      FAR
PUBLIC           intest
          mov       ah,0bh
          int       21h
          xor       ah,ah
          ret
intest   endp


_TEXT	ENDS
END


**************end file INTEST.ASM***************
**************begin file SLUGS.FOR**************
$storage:2
$include:'egafort.h'
        IMPLICIT INTEGER*2 (I-N)
        CHARACTER*10 IZC
	DIMENSION JCOL(11)
        WRITE(*,*)' Demo program for EGA.'
        WRITE(*,*)' To begin hit return'
        READ(*,1000)IZC
1000    FORMAT(A10)
        IDRAW=0
        CALL SETMOD(16)
        CALL ZSETUP
1       DO 2 I=1,11
2           JCOL(I)=0
        CALL RECTFILL(0,0,639,349,0)
        DO 5  I=1,11
3	    ICOL=RAN()*25.+1.1
	    DO 4 J=1,11
4	        IF(ICOL.EQ.JCOL(J))GOTO 3
	    JCOL(I)=ICOL
            IF(RAN().GT..6)THEN
  	        CALL BLOT(ICOL)
	    ELSE
     	        CALL SLUG(ICOL)
            ENDIF
5	CONTINUE
        CALL SLEEP(4)
        GOTO 1
	END
	SUBROUTINE BLOT(ICOL)
	IMPLICIT INTEGER*2 (I-N)
        IXCEN=639.*RAN()
	IYCEN=349.*RAN()
	DO 1 I=1,25
  	    IRAD=4.+12.*RAN()
	    RADIUS=70.*RAN()
	    ANG=6.28*RAN()
	    IX=RADIUS*SIN(ANG)
	    IY=.8*RADIUS*COS(ANG)
	    CALL FCIRC(IXCEN+IX,IYCEN+IY,IRAD,ICOL)
1	CONTINUE
	RETURN
	END
	SUBROUTINE SLUG(ICOL)
        IMPLICIT INTEGER*2 (I-N)
	DIMENSION WIDTH(12),SINTAB(0:32)
        DATA IFIRST/0/
        IF(IFIRST.EQ.0)THEN
            DO 1 I=0,32
1           SINTAB(I)=SIN(3.1415926*I/16.)
            IFIRST = 1
        ENDIF
	DO 2 I=1,12
2	WIDTH(I)=5.05*RAN()
	IX=320.+160.*RAN()
	IY=175.+90.*RAN()
	DTHET=6.28*RAN()
	DR=1.5+2.5*RAN()
	DX=DR*SIN(DTHET)
	DY=DR*COS(DTHET)
	DIST=0.
	DIST2=0.
	DO 5 I=1,60
	DTHET=1.6*RAN()
	IF(DTHET.LT..8)DTHET=DTHET-1.6
	CCOS=.05*COS(DTHET)
	SSIN=.05*SIN(DTHET)
	DDX=DX*CCOS+DY*SSIN-.05*DX
	DDY=DY*CCOS-DX*SSIN-.05*DY
	DO 4 J=1,20
 	    DX=DX+DDX
	    DY=DY+DDY
	    IX2=IX+DX
	    IY2=IY+DY
	    DIST2=DIST2+DX
	    DIST=DIST+DR
	    IF(DIST.GE.1.3)THEN
  	        DIST=0.
	        WD=0.
	        DO 3 LL=1,6
                    MSIN = IAND(IFIX(DIST2*WIDTH(LL+6)),31)
3	            WD=WD+WIDTH(LL)*SINTAB(MSIN)
	        IWD=ABS(WD)+4.
	        CALL FCIRC(IX,IY,IWD,ICOL)
            ENDIF
	    IX=IX2
	    IY=IY2
	    IF(IX.GT.690)IX=IX-750
	    IF(IY.GT.400)IY=IY-450
	    IF(IX.LT.-50)IX=IX+750
	    IF(IY.LT.-50)IY=IY+450
4	    CONTINUE
        IF(INTEST().NE.0)THEN
            CALL SETMOD(3)
            STOP
        ENDIF
5	CONTINUE
	RETURN
	END
        FUNCTION RAN()
        IMPLICIT INTEGER*4 (L)
        IMPLICIT INTEGER*2 (M-N)
        DIMENSION M(2)
        EQUIVALENCE (M(1),L2)
        DATA IFIRST/0/
        IF(IFIRST.EQ.0)THEN
            CALL GETTIM(ID1,ID2,ITT2,ITT1)
            L1=ITT1+100*ITT2
            IF(MOD(L1,2).EQ.0)L1=L1+1
            IFIRST = 1
        ENDIF
        L2=L1
        M(2)=0
        L2=L2*259
        M(2)=0
        RAN=L2/65536.
        L1=L2
        RETURN
        END
        SUBROUTINE FCIRC(IX,IY,ISIZ,ICOL)
        IMPLICIT INTEGER*2 (I-N)
        DIMENSION ICOLSO(46),ICOLSI(46)
        DATA ICOLSO/1,1,1,1,1,1,1,1,
     1              2,2,2,2,3,3,
     2              4,4,4,4,4,4,4,
     3              5,5,5,6,6,6,6,6,6,
     4              7,8,8,8,8,
     5              9,9,9,9,9,
     6              12,12,12,12,12,13/
        DATA ICOLSI/2,6,7,9,10,12,13,14,
     1              1,10,14,15,12,14,
     2              2,7,9,10,12,13,14,
     3              2,7,13,2,3,7,10,14,15,
     4              14,9,11,12,13,
     5              2,7,10,13,14,
     6              2,7,9,10,15,15/
        ISIZ2 = (ISIZ*8)/10
        CALL FILLELIP(IX,IY,ISIZ,ISIZ2,ICOLSI(ICOL))
        CALL ELLIPSE(IX,IY,ISIZ,ISIZ2,ICOLSO(ICOL))
        RETURN
        END
        subroutine sleep(isleep)
        implicit integer*2 (a-z)
        call gettim(ihr,imin,isec,itic)
        isec = isec+isleep
        if(isec.gt.59)then
            isec = isec-60
            imin = imin+1
        endif
        if(imin.gt.59)then
            imin = imin-60
            ihr = ihr+1
        endif
        if(ihr.eq.23)then
            ihr = 0
        endif
1       call gettim(ihr1,imin1,isec1,itic)
        if(ihr1.ne.ihr.or.imin.ne.imin1.or.isec.ne.isec1)goto 1
        return
        end

****************end file SLUGS.FOR*****************
