/* Debris generator, jfr. Scientific American August 1989 */
#include <intuition/intuition.h>
#include <graphics/gfx.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <functions.h>
#include <exec/memory.h>

#define SIZEX 120
#define SIZEY 120
#define RANGE 16

char *OldBuffer=NULL,*CurrentBuffer=NULL;

struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;

struct NewScreen DebrisNewScreen = {
	0,0,320,200,4,
	0,4,NULL,CUSTOMSCREEN,NULL,NULL,NULL,NULL };

UWORD DebrisColours[16] = {
	0x0E09, 0x0B09, 0x090A, 0x056B,
	0x008C, 0x00AC, 0x00BB, 0x00B8,
	0x04C0, 0x09D0, 0x0CE0, 0x0FF0,
	0x0FD0, 0x0FA0, 0x0F70, 0x0F06};

struct NewWindow DebrisNewWindow = {
	0,1,123,130,-1,-1,
	CLOSEWINDOW, WINDOWCLOSE | SMART_REFRESH | ACTIVATE,
	NULL, NULL, (UBYTE *)"Debris from Scientific American",
	NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN };

struct Screen *DebrisScreen=NULL;
struct Window *DebrisWindow=NULL;

OpenAll()
{
	register long i,j;
	long seconds,micros;
	
	IntuitionBase = (struct IntuitionBase*)OpenLibrary("intuition.library",0L);
	GfxBase = (struct GfxBase*)OpenLibrary("graphics.library",0L);
	
	if (!(DebrisScreen = OpenScreen(&DebrisNewScreen)))
		abort("No Screen");
	DebrisNewWindow.Screen = DebrisScreen;
	if (!(DebrisWindow = OpenWindow(&DebrisNewWindow)))
		abort("No Window");
	LoadRGB4(&(DebrisScreen->ViewPort), DebrisColours, 16L);
	CurrentTime(&seconds,&micros);
	seconds=micros; micros>>8; micros+=seconds;
	srand(seconds);
	if (!(CurrentBuffer=AllocMem((long)SIZEX*SIZEY,MEMF_PUBLIC)))
		abort("No memory");
	if (!(OldBuffer=AllocMem((long)SIZEX*SIZEY,MEMF_PUBLIC)))
		abort("No buffer memory");
	for (i=0; i < SIZEX; i++)
		for (j=0; j<SIZEY; j++)
		{
			*(CurrentBuffer+i*SIZEY+j) = rand() % RANGE;
			*(OldBuffer+i*SIZEY+j)=-1;
		}
}

abort(Tekst)
char *Tekst;
{
	if (Tekst!=NULL) puts(Tekst);
	
	if (CurrentBuffer) FreeMem(CurrentBuffer,(long)SIZEX*SIZEY);
	if (OldBuffer) FreeMem(OldBuffer,(long)SIZEX*SIZEY);
	if (DebrisWindow) CloseWindow(DebrisWindow);
	if (DebrisScreen) CloseScreen(DebrisScreen);

	if (IntuitionBase) CloseLibrary(IntuitionBase);
	if (GfxBase) CloseLibrary(GfxBase);
	exit(0);
}

DoGeneration()
{
	register long i,j,k,l;

	for (i=0; i<SIZEX; i++)
		for (j=0; j<SIZEY; j++)
			*(OldBuffer+i*SIZEY+j) = *(CurrentBuffer+i*SIZEY+j);
	for (i=1; i<SIZEX; i++)
		for (j=1; j<SIZEY; j++)
		{
			k=i*SIZEY+j;
			if (*(OldBuffer+k-SIZEY)==(*(CurrentBuffer+k)+1)%RANGE)
				*(CurrentBuffer+k)+=1;
			else
			{
				if (*(OldBuffer+k-1)==(*(CurrentBuffer+k)+1)%RANGE)
					*(CurrentBuffer+k)+=1;
				else
				{
					if (*(OldBuffer+k+1)==(*(CurrentBuffer+k)+1)%RANGE)
						*(CurrentBuffer+k)+=1;
					else
						if (*(OldBuffer+k+SIZEY)==(*(CurrentBuffer+k)+1)%RANGE)
							*(CurrentBuffer+k)+=1;
				}
			}
			if (*(CurrentBuffer+k)>=RANGE) *(CurrentBuffer+k)=0;
			if (*(OldBuffer+k)!=*(CurrentBuffer+k))
			{
				SetAPen(DebrisWindow->RPort,(long)*(CurrentBuffer+k));
				WritePixel(DebrisWindow->RPort,i+1,j+9L);
			}
		}
}

DisplayGeneration()
{
	register long i,j;
	
	for (i=1;i<SIZEX;i++)
		for (j=1;j<SIZEY;j++)
		{
			SetAPen(DebrisWindow->RPort,(long)*(CurrentBuffer+i*SIZEY+j));
			WritePixel(DebrisWindow->RPort,i+1L,j+9L);
		}
}

main()
{
	struct IntuiMessage *Msg;
	
	OpenAll();
	DisplayGeneration();
	while (!(Msg = (struct IntuiMessage*)GetMsg(DebrisWindow->UserPort)))
		DoGeneration();
	ReplyMsg((struct Message*)Msg);
	abort(0L);
}

	