/* $Header:zip.c 12.0$ */
/* $ACIS:zip.c 12.0$ */
/* $Source: /ibm/acis/usr/src/usr.lib/libaed/examples/RCS/zip.c,v $ */

#ifndef lint
static char *rcsid = "$Header:zip.c 12.0$";
#endif

#include "stdio.h"

#define rnd(L,H) (L + (rand() % (H-L+1)))
#define then
#define begin {
#define end }
#define forever -1

static int x1,x2,y1,y2;
static int min,max;
static int dx1,dx2,dy1,dy2;
typedef struct nd { int xa,xb,ya,yb;
                    struct nd *next;
                  } node, *nodeptr;
static nodeptr root;

/* QIX or ZIP--
 * A toy to bounce a sequence of vectors around a Viking screen, much like 
 * the antagonist in the video game QIX (tm).
 * 
 * Syntax: { QIX | ZIP } [p1 [p2 [p3]]]
 *               p1 = lifetime of a vector, or how many vectors will be on the
 *                    screen at any time t.
 *               p2 = minimum allowable delta.  A delta is the amount that a
 *                    coordinate (x or y) will change for each new vector.
 *               p3 = maximum allowable delta.
 *
 * Each point has its own X and Y; and each point has its own deltaX and deltaY,
 * each independent of the other.
 *
 * A point travels in a straight line until it hits a screen edge, when it will
 * reflect.  The wall is elastic in that it may change the delta normal to it;
 * the delta parallel to it will not change.
 * 
 * Every time a pair of points is generated, a vector is drawn (EXOR) between
 * them, and between the oldest pair of points as well. (The twice EXOR 
 * effectively erases the old vector.)
 *
 */

main(argc,argv)
int argc;
char *argv[];
{ short i,j,k;
  short n;

  n = 50;		/* default number of vectors on screen */
  min = 2;		/* default minimum delta X or Y per endpoint move */
  max = 20;		/* default maximum delta */
  k=0;

  if (argc>=2) n = atoi(*++argv);
  if (argc>=3) min = atoi(*++argv);	/* pick up user-supplied parameters */
  if (argc>=4) max = atoi(*++argv);
  if (argc>=5) k = atoi(*++argv);

  VI_Init(&i,&j);
  VI_Tile((int)i,j,1,1,&k);		/* clear the screen */
  VI_Merge(6);  /* EXOR */
  srand(getpid());		/* use process-id for random seed */
  initstack(n);			/* create circular buffer ('stack') */

  x1 = rnd(0,1023);		
  x2 = rnd(0,1023);		/* initial points */
  y1 = rnd(0,799);
  y2 = rnd(0,799);
  dx1 = rnd(min,max);
  dx2 = rnd(min,max);		/* initial deltas */
  dy1 = rnd(min,max);
  dy2 = rnd(min,max);

  while(forever)
    { VI_AMove(x1,y1);			/* draw a new vector */
      VI_ALine(x2,y2);
      VI_AMove(root->xa,root->ya);	/* erase an old vector */
      VI_ALine(root->xb,root->yb);
      VI_Force();			/* for continuity */
      rollstack();			/* replace old with new */
      newpoints();			/* get new pair of points */
    }
  VI_Term();		/* never reached */
}

newpoints()
{ x1 += dx1;
  x2 += dx2;	/*just increment by delta, which could be > or < 0  */
  y1 += dy1;
  y2 += dy2;
  if (x1 > 1023) {x1=1023; newd(&dx1);}
  if (x2 > 1023) {x2=1023; newd(&dx2);}	/* if off screen, bounce */
  if (y1 >  799) {y1= 799; newd(&dy1);}
  if (y2 >  799) {y2= 799; newd(&dy2);}
  if (x1 <    0) {x1=   0; newd(&dx1);}
  if (x2 <    0) {x2=   0; newd(&dx2);}
  if (y1 <    0) {y1=   0; newd(&dy1);}
  if (y2 <    0) {y2=   0; newd(&dy2);}
}

newd(delta)	/* elastically bounce; delta speed in one dimension only. */
int *delta;
{ int d;		
  d = rnd(min,max);		/* elastic wall.  change speed after bouncing */
  if (*delta > 0) d = -d;	/* change direction */
  *delta = d;
}

initstack(n) 
int n;
{  int i;
   nodeptr ptr,*lastptr;
   char *malloc();
   lastptr = &root;
   for (i=0; i<n; i++)
      { ptr = (nodeptr) malloc(sizeof(node));
        ptr->xa = ptr->xb = ptr->ya = ptr->yb = 0;
        ptr->next = root;  
        *lastptr = ptr;
        lastptr = &(ptr->next);
      }
}

rollstack()
{ root->xa = x1;
  root->xb = x2;
  root->ya = y1;
  root->yb = y2;
  root = root->next;
}
