/* Demon.c */
/* Scientific American August 1989 */
/* Lloyd Linstrom */
#include "exec/types.h"
#include "intuition/intuition.h"
#include "exec/memory.h"
#include "graphics/gfxmacros.h"

#define XMAX 200			/* Number of pixels x direction */
#define YMAX 184			/* Number of pixels y direction */

struct Window *w,*OpenWindow();		/* pointer to a window */
struct RastPort *rp;			/* pointer to a RastPort */
struct Screen *s,*OpenScreen();		/* pointer to a screen */
struct ViewPort *vp,*ViewPortAddress();	/* pointer to a ViewPort */
struct IntuiMessage *msg, *GetMsg();	/* pointer to Intuition Message */
struct Library *IntuitionBase, *GfxBase, *OpenLibrary();
void CloseScreen(), CloseWindow(), CloseLibrary();
void SetAPen(), WritePixel(), ReplyMsg(); 
void SetWindowTitles();

UBYTE new[XMAX][YMAX], old[XMAX][YMAX];		/* Area arrays */
UBYTE titlestr[40];			/* Window Title */
int ncolor;				/* Number of colors */

struct TextAttr TextFont = { (UBYTE *)"topaz.font", 8, 0, 0 };

struct NewScreen demonScreen = {
	0L, 0L,
	320L, 200L,
	4L,			/* Four bit planes */
	0L, 1L,
	0L,
	CUSTOMSCREEN,
	&TextFont,
	(UBYTE *)"Demon Screen",
	NULL
};


struct NewWindow demonWindow = {
	0L, 0L,
	280L, 200L,
	0L, 
	1L,
	CLOSEWINDOW,
	WINDOWCLOSE | WINDOWDEPTH | WINDOWSIZING
	 | WINDOWDRAG | ACTIVATE | GIMMEZEROZERO,
	NULL, NULL,
	(UBYTE *) "Demon",
	NULL,
	NULL, 
	50L, 
	30L, 
	320L, 
	200L,
	CUSTOMSCREEN
};


int HandleEvent(code)		/* Handle messages from Intuition */
long code;			/* provided by main */
{
	switch (code)
	{
	case CLOSEWINDOW:
		return(0);
		break;
	default:
		return(1);
		break;
	}
}

int init()			/* Open Libraries, Screen, & Window  */
{
	long i;
	
	IntuitionBase = NULL;
	s = NULL;
	w = NULL;

	GfxBase = OpenLibrary("graphics.library", 0L);
	if(GfxBase == NULL) return(0);

	IntuitionBase = OpenLibrary("intuition.library", 0L);
	if(IntuitionBase == NULL) return(0);

	s = OpenScreen(&demonScreen);
	if(s == NULL) return(0);

	demonWindow.Screen = s;		/* Tie window to screen */
	w = OpenWindow(&demonWindow);
	if (w == NULL) return(0);

	vp = ViewPortAddress(w);	/* ViewPort address of Window  */
	rp = w->RPort;

	return(1);		/* Successful initialization */
}


void endit()			/* Close Window, Screen, &  Librarys  */
{
	if(w) CloseWindow(w);
	if(s) CloseScreen(s);
	if(GfxBase) CloseLibrary(GfxBase);
	if(IntuitionBase) CloseLibrary(IntuitionBase);
	exit(0);
}


void drawit()
{
	register short i, j;
	register long il, jl;
	register long color;

	/* Write pixels and update old array */
	for(i=0; i<XMAX; i++)
	{
		for(j=0; j<YMAX; j++)
		{
			if(old[i][j] != new[i][j])
			{
				color = (long) new[i][j];
				SetAPen(rp, color);
				il = (long) i;
				jl = (long) j;
				WritePixel(rp, il, jl);

				old[i][j] = new[i][j];
			}
		}
	}
}


void initfield()
{
	register short i, j, k;
	short result;

	for(i=0; i<XMAX; i++)
	{
		for(j=0; j<YMAX; j++)
		{
			k = (short)( rand() % ncolor);
			new[i][j] = k;
			old[i][j] = ncolor + 1;	/* Make sure old != new */
		}
	}
	drawit();
}

void nextfield()
{
	register short p, tcolor, j, i;

	/* Make new array */
	for(i=0; i<XMAX; i++)
	{
		for(j=0; j<YMAX; j++)	
		{
			tcolor = old[i][j] + 1;	/* Current color plus one */
			if(tcolor >= ncolor) tcolor -= ncolor;

			p = i + 1;	/* Check to the right */
			if(p > XMAX) p -= XMAX;
			if(old[p][j] == tcolor)
			{
				new[i][j] = old[p][j];
				continue;
			}

			p = j + 1;	/* Check below */
			if(p > YMAX) p -= YMAX;
			if(old[i][p] == tcolor)
			{
				new[i][j] = old[i][p];
				continue;
			}

			p = j - 1;	/* Check above */
			if(p < 0) p += YMAX;
			if(old[i][p] == tcolor)
			{
				new[i][j] = old[i][p];
				continue;
			}
 
			p = i - 1;	/* Check left */
			if(p < 0) p += XMAX;
			if(old[p][j] == tcolor)
			{
				new[i][j] = old[p][j];
				continue;
			}
		}
	}
}


main(argc, argv)
int argc;
char *argv[];
{
	int result, count;
	long color;

	if(argc > 1)
	{
		ncolor = atoi(argv[1]);
		ncolor = (ncolor < 2) ? 8 : (ncolor > 16) ? 16 : ncolor;
	}
	else 
	{
		printf("Demon Program\n\n");
		printf("Four distinct phases emerge from randomness\n");
		printf("Scientific American  August 1989\n");
		printf("Phases progress faster with fewer colors\n");
		printf("Program window maybe slow to close\n\n");
		printf("Enter number of colors [2-16]: ");
		scanf("%d", &ncolor);
		if(ncolor < 2) ncolor = 2;
		if(ncolor > 16) ncolor = 16; 
	}		
	if(init() == 0) endit();	/* Initialize everything */
	srand(time(NULL));		/* Set PRN generator */
	initfield();

	result = 1; 			/* Result from HandleEvent */
	count = 0;
	sprintf(&titlestr[0], "Count:%5d    Colors:%3d", count,
		 ncolor);		/* Set title */
	SetWindowTitles(w, titlestr, -1L);

	while(1)
	{
		nextfield();
		drawit();

		sprintf(&titlestr[0], "Count:%5d    Colors:%3d", ++count,
			 ncolor);	/* Update count */
		SetWindowTitles(w, titlestr, -1L);
				 
		while((msg = GetMsg(w->UserPort))!=NULL)
		{
			result = result * HandleEvent(msg->Class);
			ReplyMsg(msg);
		}

		if(result == 0)		/* Close Window Flag */
		{
			endit();
		}
	}
}
