

/*
 * In the tradition of stupid programs, Leo Schwab presents (yet again)
 * The Art Program.
 * 8511.24
 */

#include <exec/types.h>
#include <graphics/gfxbase.h>
#include <intuition/intuition.h>

#define XSIZE          639
#define YSIZE          199
#define ever           (;;)

extern short     rnd ();

struct IntuitionBase   *IntuitionBase;
struct GfxBase         *GfxBase;
struct Screen  *scr, *OpenScreen();
struct Window  *win, *OpenWindow();
long GetMsg();

struct NewScreen scrdef = {
	0, 0, XSIZE+1, YSIZE+1,
	4,              /*  16 colors  */
	0, 1,           /*  detail/block pens  */
					/*  "Automatically" set up screen format  */
	((XSIZE>320) ? HIRES : 0) | ((YSIZE>200) ? LACE : 0),
	CUSTOMSCREEN,
	NULL, NULL, NULL, NULL  /* no special font, title, gadg, or bitmap */
};

struct NewWindow windef = {
	0, 0, XSIZE+1, YSIZE+1,
	0, 1,
	CLOSEWINDOW,
	WINDOWCLOSE | BACKDROP | BORDERLESS,
	NULL, NULL, NULL,       /* no special gadget, checkmark or title */
	NULL,                   /* screen pointer; will get set later */
	NULL,                   /* no custom bitmap */
	0, 0, 0, 0,             /* ignored */
	CUSTOMSCREEN
};


main ()
{
	register struct RastPort *rp;
	long i, dx1, dy1, dx2, dy2, pen = 0, flag = 0,
		xa1[150], ya1[150], xa2[150], ya2[150];
	register long x1, y1, x2, y2;

	openstuff ();
	rnd (-87634L);
/*     rp = win -> RPort;      <--- This is slower because of layers   */
	rp = & (scr -> RastPort);
	SetDrMd (rp, COMPLEMENT);
	ShowTitle (scr, FALSE);
	SetRast (rp, 0L);
	x1 = rnd (XSIZE+1L);  y1 = rnd (YSIZE+1L);
	x2 = rnd (XSIZE+1L);  y2 = rnd (YSIZE+1L);
	setdisp (&dx1, &dy1);
	setdisp (&dx2, &dy2);

	for ever {
			for (i=0; i<150; i++) {
					if (GetMsg (win -> UserPort)) {
							closestuff ();
							exit (TRUE);
					}
					if (!rnd (20L))
							if (rnd (2L))
									setdisp (&dx1, &dy1);
							else
									setdisp (&dx2, &dy2);
					
					x1 += dx1;  y1 += dy1;
					if (x1 > XSIZE || x1 < 0) {
							dx1 = -dx1;
							x1 = x1<0 ? 0 : XSIZE;
					}
					if (y1 > YSIZE || y1 < 0) {
							dy1 = -dy1;
							y1 = y1<0 ? 0 : YSIZE;
					}

					x2 += dx2;  y2 += dy2;
					if (x2 > XSIZE || x2 < 0) {
							dx2 = -dx2;
							x2 = x2<0 ? 0 : XSIZE;
					}
					if (y2 > YSIZE || y2 < 0) {
							dy2 = -dy2;
							y2 = y2<0 ? 0 : YSIZE;
					}

					pen++;
					if (!(pen &= 15))
							pen++;
					rp -> Mask = pen;       /* kludge; COMPLEMENT does */
					Move (rp, x1, y1);      /* not perform as advertised */
					Draw (rp, x2, y2);
					if (flag) {
							Move (rp, xa1[i], ya1[i]);
							Draw (rp, xa2[i], ya2[i]);
					}
					xa1[i] = x1;  ya1[i] = y1;
					xa2[i] = x2;  ya2[i] = y2;
			}
			flag = 1;
	}
}

openstuff ()
{
	char *OpenLibrary();

	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary ("intuition.library", 1L))) {
			printf ("Awright, where's Intuition?\n");
			exit (FALSE);
	}

	if (!(GfxBase = (struct GfxBase *)
		OpenLibrary ("graphics.library", 1L))) {
			printf ("Graphics?  Heeeere graphics....\n");
			exit (FALSE);
	}

	if (!(scr = OpenScreen (&scrdef))) {
			printf ("Can't open your screen.\n");
			exit (FALSE);
	}

	windef.Screen = scr;
	if (!(win = OpenWindow (&windef))) {
			printf ("Window painted shut.\n");
			exit (FALSE);
	}
}

closestuff ()
{
	CloseWindow (win);
	CloseScreen (scr);
	CloseLibrary (GfxBase);
	CloseLibrary (IntuitionBase);
}

/*  Commented out to test machine language equivalent
short
rnd (range)
register int range;
{
	static int seed;
	register int i, n;

	if (range < 0)
			seed = -range;
	i = (seed & 1<<27) ? 1 : 0;
	n = (seed & 1<<30) ? 1 : 0;
	seed <<= 1;
	seed |= (i ^ n);
	return ((short) ((short) seed % (short) range));
}      */

setdisp (x, y)
register long *x, *y;
{
	*x = rnd (9L) - 4;
	*y = rnd (9L) - 4;
}

/* ----------------------------------------------------------------------
*
* Here's the machine code random number generator
*
------------------------------------------

*\
* A random number generator.  By Leo Schwab.
* Based on a hardware random number generator appearing in the TTL Cookbook
* by Don Lancaster
*
* Calling convention:
*  int rnd (range);
*  int range;
*
* 8511.26
*/

#asm
			public    _rnd

_rnd        move.l  d2,-(sp)
			lea     rndseed,a0      Get address of seed
			move.l  8(sp),d2        Get range argument
			tst.l   d2
			ble.s   setseed         Go reset seed

			move.l  d1,-(sp)        Probably not necessary
			andi.l  #$ffff,d2       Coerce into a word
			move.l  #$48000000,d0   Set bits 27 & 30
			and.l   (a0),d0         Get interesting bits
			swap    d0              Pull them downstairs
			lsl.w   #2,d0           Move first bit into X flag
			roxl.b  #1,d1            and put it in D1
			rol.w   #3,d0           Put other bit into bit 0 of D0
			eor.b   d0,d1           EOR them together
			lsr.b   #1,d1           Put back into X bit
			roxl.w  2(a0)           Generate new random number
			roxl.w  (a0)
			moveq   #0,d0           Clean D0
			move.w  (a0),d0         Get random number
			divu    d2,d0           Divide by range
			swap    d0               and get remainder (modulus)
			ext.l   d0
			move.l  (sp)+,d1
			move.l  (sp)+,d2        Restore D1 and D2
			rts

setseed     neg.l   d2              Probably don't need this
			move.l  d2,(a0)
			move.l  (sp)+,d2
			rts


			dseg
rndseed     dc.l    0
			cseg
#endasm
