/****************************************************************
 * fault fractals, by John M. Olsen
 ****************************************************************/

#include <math.h>
#include <graphics/gfxbase.h>
#include <graphics/gfxmacros.h>
#include <graphics/rastport.h>
#include <hardware/blit.h>
#include <hardware/custom.h>
#include <intuition/intuition.h>

/* Only one of the following two should be defined. */
/* #define NOCYCLE  /* define this to make it not color cycle. */
#define CYCLE     /* define this to make it color cycle. */

#define WIDTH  320
#define HEIGHT 200
#define BASE   0

int trash;
long mybltsize, offset, minbltsize;
void *OpenLibrary();
struct IntuiMessage *GetMsg(), *msg;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;
struct Screen *s, *s1, *OpenScreen();
struct Window *w, *w1, *w2, *w3, *OpenWindow();
BYTE *AllocRaster();
WORD areabuffer[250];
struct TmpRas tmpras;
struct AreaInfo myareainfo;

struct NewScreen ss =
{
	0,0,320,200,5,0,1, /* 5 planes */
	NULL,CUSTOMSCREEN,NULL,(UBYTE *)"  Fractal Brownian Motion",
	NULL,NULL
};

struct NewScreen ss1 =
{
	0,0,320,200,2,0,1, /* 2 planes */
	NULL,CUSTOMSCREEN,NULL,(UBYTE *)"  Sneaky Blitter Work Area",
	NULL,NULL
};

struct NewWindow ww =
{
	0,0,320,200,-1,-1,MOUSEBUTTONS, /* IDCMP */
	NOCAREREFRESH | BACKDROP | BORDERLESS | RMBTRAP,
	NULL,NULL,(UBYTE *)NULL,
	NULL,NULL,0,0,0,0,CUSTOMSCREEN
};

struct NewWindow wb =
{
	0,0,14,10,-1,-1, CLOSEWINDOW, /* IDCMP */
	NOCAREREFRESH | WINDOWCLOSE | BORDERLESS | RMBTRAP,
	NULL,NULL,(UBYTE *)NULL,
	NULL,NULL,0,0,0,0,CUSTOMSCREEN
};

struct NewWindow wb1 =
{
	0,0,14,10,-1,-1, CLOSEWINDOW, /* IDCMP */
	NOCAREREFRESH | WINDOWCLOSE | BORDERLESS | RMBTRAP,
	NULL,NULL,(UBYTE *)NULL,
	NULL,NULL,0,0,0,0,CUSTOMSCREEN
};

struct NewWindow ww1 =
{
	0,0,320,200,-1,-1,MOUSEBUTTONS, /* No IDCMP */
	NOCAREREFRESH | BACKDROP | BORDERLESS | RMBTRAP,
	NULL,NULL,(UBYTE *)NULL,
	NULL,NULL,0,0,0,0,CUSTOMSCREEN
};

short colormap[32] =
{
	0x000, 0x101, 0x111, 0x212, 0x222, 0x323, 0x333, 0x434,
	0x444, 0x545, 0x555, 0x656, 0x666, 0x767, 0x777, 0x878,
	0x888, 0x989, 0x999, 0xa9a, 0xaaa, 0xbab, 0xbbb, 0xcbc,
	0xccc, 0xdcd, 0xddd, 0xede, 0xeee, 0xfee, 0xfef, 0xfff
};

main(argc, argv)
char *argv[];
{
	long count, class, code;
	struct RastPort *r, *r1;
	register long x,y;
	float m,b,theta;

	setup();
	r = w->RPort;
	r1 = w1->RPort;
	SetRast(r,(long)BASE);
	while(1)
	{
		if(msg = GetMsg(w->UserPort)) ReplyMsg(msg);
		if(msg = GetMsg(w1->UserPort)) ReplyMsg(msg);
		if(msg = GetMsg(w2->UserPort))
		{
			class = msg->Class;
			ReplyMsg(msg);
			if(class == CLOSEWINDOW) die(0);
		}
		if(msg = GetMsg(w3->UserPort))
		{
			class = msg->Class;
			ReplyMsg(msg);
			if(class == CLOSEWINDOW) die(0);
		}
/* draw mask into plane 0 of s1 */
		SetRast(r1, 0L);
		SetAPen(r1, 1L);
		AreaMove(r1, (long)(rand()%320), (long)(rand()%200));
		AreaDraw(r1, (long)(rand()%320), (long)(rand()%200));
		AreaDraw(r1, (long)(rand()%320), (long)(rand()%200));
		AreaEnd(r1);
		if(count) fracadd(r,w1->RPort->BitMap->Planes[1],
			w1->RPort->BitMap->Planes[0]);
		else fracsub(r,w1->RPort->BitMap->Planes[1],
			w1->RPort->BitMap->Planes[0]);
#ifdef CYCLE
		FudgeColors();
#endif
		count = !count;
	}
}

setup()
{
	long sec,mic;
	register long i,j;

	if(!(GfxBase = OpenLibrary("graphics.library",0L)))
		die(1);
	if(!(IntuitionBase = OpenLibrary("intuition.library",0L)))
		die(1);
	if(!(s1 = OpenScreen(&ss1)))
		die(2);
	ww1.Screen = s1;
	if(!(w1 = OpenWindow(&ww1)))
		die(3);
	wb1.Screen = s1;
	if(!(w3 = OpenWindow(&wb1)))
		die(3);
	if(!(s = OpenScreen(&ss)))
		die(2);
	ww.Screen = s;
	if(!(w = OpenWindow(&ww)))
		die(3);
	wb.Screen = s;
	if(!(w2 = OpenWindow(&wb)))
		die(3);
	LoadRGB4(&s->ViewPort, colormap, 32L);

	InitArea(&myareainfo, areabuffer, 100L);
	w1->RPort->AreaInfo = &myareainfo;
	tmpras.RasPtr = (BYTE *) AllocRaster(320L, 200L);
	tmpras.Size = (long) RASSIZE(320L, 200L);
	w1->RPort->TmpRas = &tmpras;

	offset = 10 * w1->RPort->BitMap->BytesPerRow;
 	minbltsize = ((w1->RPort->BitMap->Rows - 10) << 6) |
		(w1->RPort->BitMap->BytesPerRow >> 1);
	/* now make the silly title visible.  Colors 1,2,3 -> 8,16,24 */
	for(i = 0; i < 10; i++)
	{
		for(j = 0; j < 320; j++)
		{
			SetAPen(&(s->RastPort), 
				(long)(8*ReadPixel(&(s->RastPort),j,i)));
			WritePixel(&(s->RastPort), j,i);
		}
	}
	CurrentTime(&sec,&mic);
	srand((int)mic); /* microseconds makes a good random seed. */
}

fracadd(r,a,b)
struct RastPort *r;
PLANEPTR a,b;
{
	register int x, newoff;

	newoff = offset;
 	mybltsize = ((w1->RPort->BitMap->Rows - 10) << 6) |
		(w1->RPort->BitMap->BytesPerRow >> 1);
	OwnBlitter();
	for(x = 0; x < 5; x++) /* for each bitplane */
	{
		WaitBlit();
/* plane a = plane x AND plane b */
		custom.bltapt = (APTR)(b+newoff);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltdpt = (APTR)(a+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ABC | ABNC;
		custom.bltsize = mybltsize;
/* plane x = plane x XOR plane b */
		WaitBlit();
		custom.bltapt = (APTR)(b+newoff);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltdpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ANBC | NABC | ANBNC | NABNC;
		custom.bltsize = mybltsize;
/* plane b = plane a */
		WaitBlit();
		custom.bltapt = (APTR)(a+newoff);
		custom.bltdpt = (APTR)(b+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ABC | ANBC | ABNC | ANBNC;
		custom.bltsize = mybltsize;
	}
/* fill planes with 1 wherever plane b is set to 1, except for title area. */
#ifdef NOCYCLE
	for(x = 0; x < 5; x++)
	{
		WaitBlit();
		custom.bltapt = (APTR)(b + offset);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x] + offset);
		custom.bltdpt = (APTR)(r->BitMap->Planes[x] + offset);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			A_OR_B;
		custom.bltsize = minbltsize;
	}
#endif 
	WaitBlit();
	DisownBlitter();
}

fracsub(r,a,b)
struct RastPort *r;
PLANEPTR a,b;
{
	register int x,newoff;

	newoff = offset;
 	mybltsize = ((w1->RPort->BitMap->Rows - 10) << 6) |
		(w1->RPort->BitMap->BytesPerRow >> 1);
	OwnBlitter();
	for(x = 0; x < 5; x++) /* for each bitplane */
	{
		WaitBlit();
/* plane a = !plane x AND plane b */
		custom.bltapt = (APTR)(b+newoff);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltdpt = (APTR)(a+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ANBC | ANBNC;
		custom.bltsize = mybltsize;
/* plane x = plane x XOR plane b */
		WaitBlit();
		custom.bltapt = (APTR)(b+newoff);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltdpt = (APTR)(r->BitMap->Planes[x]+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ANBC | NABC | ANBNC | NABNC;
		custom.bltsize = mybltsize;
/* plane b = plane a */
		WaitBlit();
		custom.bltapt = (APTR)(a+newoff);
		custom.bltdpt = (APTR)(b+newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			ABC | ANBC | ABNC | ANBNC;
		custom.bltsize = mybltsize;
	}
/* fill planes with 0 wherever plane a is set to 1 */
#ifdef NOCYCLE
	for(x = 0; x < 5; x++)
	{
		WaitBlit();
		custom.bltapt = (APTR)(b + newoff);
		custom.bltbpt = (APTR)(r->BitMap->Planes[x] + newoff);
		custom.bltdpt = (APTR)(r->BitMap->Planes[x] + newoff);
		custom.bltafwm = 0xffff;
		custom.bltalwm = 0xffff;
		custom.bltamod = 0;
		custom.bltbmod = 0;
		custom.bltdmod = 0;
		custom.bltcon1 = 0;
		custom.bltcon0 = BC0F_SRCA | BC0F_SRCB | BC0F_DEST |
			NABC | NABNC ;
		custom.bltsize = mybltsize;
	}
#endif
	WaitBlit();
	DisownBlitter();
}

FudgeColors()
{
	short a, i;

	a = colormap[31];
	for(i = 31; i > 0; i--) colormap[i] = colormap[i-1];
	colormap[0] = a;
	LoadRGB4(&s->ViewPort, colormap, 32L);
}

die(kind)
int kind;
{
	while(msg = GetMsg(w->UserPort)) ReplyMsg(msg);
	while(msg = GetMsg(w1->UserPort)) ReplyMsg(msg);
	while(msg = GetMsg(w2->UserPort)) ReplyMsg(msg);
	while(msg = GetMsg(w3->UserPort)) ReplyMsg(msg);
	if(tmpras.RasPtr) FreeRaster(tmpras.RasPtr, 320L, 200L);
	if(w2) CloseWindow(w2);
	if(w3) CloseWindow(w3);
	if(w1) CloseWindow(w1);
	if(s1) CloseScreen(s1);
	if(w) CloseWindow(w);
	if(s) CloseScreen(s);
	if(IntuitionBase) CloseLibrary(IntuitionBase);
	if(GfxBase) CloseLibrary(GfxBase);
	exit(kind);
}
