	#include <stdio.h>
	#include <stdlib.h>
	#include <dos/dos.h>
	#include <exec/types.h>
	#include <exec/interrupts.h>
	#include <graphics/gfxmacros.h>
	#include <hardware/dmabits.h>
	#include <hardware/custom.h>
	#include <proto/exec.h>
	#include <proto/dos.h>
	#include <proto/graphics.h>
	#include <proto/intuition.h>
	#include <intuition/screens.h>
	#include <proto/gadtools.h>
	#include <libraries/gadtools.h>
	#include "CurvoPrefs.h"

void DoCurvo(void);
void cleanup(void);
void Preferences(void);
void RemoveCurvo(void);
void InstallCurvo(void);
void plot(struct BitMap *,WORD,WORD,WORD);
void LoadPrefs(void);
void SavePrefs(void);

extern struct Custom far custom;

struct DateStamp __aligned ds;
struct Screen *aScreen;
struct Interrupt vbInt;	//={0,0,NT_INTERRUPT,52,0,0,DoCurvo};
WORD CurvoColors[]={0,0,0,0,1,2,2,2,2,4,4,4,3,6,6,6,4,8,8,8,5,10,10,10,
					6,12,12,12,7,14,14,14,-1};

//curvolength must be a power of 2 since we are using it as an AND value
//for speed further down.
#define	curvolength 64
#define maxcurvos	10

struct curvodata{
	WORD	*curvoarray;
	WORD	goalx,goaly,currentx,currenty,deltax,deltay;
	WORD	arraypointer,newgoaltimer;
};

struct curvodata thecurvos[maxcurvos];
struct Task *thistask;
struct Message *aMsg;
struct MsgPort *aPort;
WORD	numcurvos;

main()
{
	long sigs;

	DateStamp(&ds);
	srand(ds.ds_Tick);

	vbInt.is_Node.ln_Type=NT_INTERRUPT;
	vbInt.is_Code=DoCurvo;

	thistask=FindTask(NULL);

	Forbid();
	aPort=FindPort("PowerManagerBlank");
	if (aPort)
	{
		aMsg=AllocMem(sizeof(struct Message),0x10000);
		if(aMsg)
		{
			aMsg->mn_Length=sizeof(struct Message);
			aMsg->ln_Name=(char *)thistask;
		}
		PutMsg (aPort,aMsg);
	}
	Permit();

	LoadPrefs();

	while(1)
	{
		sigs=Wait(SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
		if (sigs&SIGBREAKF_CTRL_C)
			cleanup();
		if (sigs&SIGBREAKF_CTRL_D)
			InstallCurvo();
		if (sigs&SIGBREAKF_CTRL_E)
			RemoveCurvo();
		if (sigs&SIGBREAKF_CTRL_F)
			Preferences();
	}
}

void LoadPrefs()
{
	BPTR	fh;

	numcurvos=6;
	fh=(BPTR)(Open("envarc:CurvoBlanker.prefs",1005));
	if (fh)
	{
		Read(fh,&numcurvos,2);
		Close(fh);
	}
	if (numcurvos>10) numcurvos=10;
}

void SavePrefs()
{
	BPTR	fh;

	fh=(BPTR)(Open("envarc:CurvoBlanker.prefs",1006));
	if (fh)
	{
		Write(fh,&numcurvos,2);
		Close(fh);
	}
}

void RemoveCurvo(void)
{
	int blah;

	if (!aScreen) return;

	RemIntServer(5,&vbInt);
	for (blah=0;blah<numcurvos;blah++)
		if (thecurvos[blah].curvoarray) FreeMem(thecurvos[blah].curvoarray,curvolength<<2);
	CloseScreen(aScreen);
	aScreen=0;
	ON_SPRITE;
}

void InstallCurvo()
{
	int blah;
	if (aScreen) return;

	aScreen=OpenScreenTags(NULL,SA_Width,320,SA_Height,200,SA_Depth,3,
				SA_Colors,CurvoColors,SA_Type,CUSTOMSCREEN,SA_ShowTitle,0,
				SA_Quiet,1,SA_Draggable,0,TAG_END);
	if (!aScreen)
		return;

	for (blah=0;blah<numcurvos;blah++)
	{
		thecurvos[blah].curvoarray=AllocMem(curvolength<<2,0x10000);
		if (!thecurvos[blah].curvoarray)
		{
			RemoveCurvo();
			return;
		}
		thecurvos[blah].deltax=4;
		thecurvos[blah].deltay=0;
		thecurvos[blah].currentx=rand()%(320<<5);
		thecurvos[blah].currenty=rand()%(200<<5);
		thecurvos[blah].goalx=rand()%(160<<5)+(80<<5);
		thecurvos[blah].goaly=rand()%(100<<5)+(50<<5);
		thecurvos[blah].newgoaltimer=(rand()&31)+16;
	}
	AddIntServer(5,&vbInt);
	OFF_SPRITE;
}

void Preferences()
{
	LONG	sigs,result;

	if (!SetupScreen())
	{
		if (!OpenCurvoBlankerWindow())
		{
			GT_SetGadgetAttrs(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL,GTIN_Number,numcurvos,TAG_END);
//			((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt=numcurvos;
//			RefreshGadgets(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL);

			result=TRUE;
			do {
				sigs=Wait(1<<(CurvoBlankerWnd->UserPort->mp_SigBit)|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E);
				if (sigs&SIGBREAKF_CTRL_D)	InstallCurvo();
				if (sigs&SIGBREAKF_CTRL_E)	RemoveCurvo();
				if (sigs&(~(SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E)))
				{
					RemoveCurvo();
					result=HandleCurvoBlankerIDCMP();
				}
			} while (result);
			CloseCurvoBlankerWindow();
		}
		CloseDownScreen();
	}
	SetSignal(0,SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F);
}

void cleanup()
{
	if (aScreen) RemoveCurvo();

	Forbid();
	aPort=FindPort("PowerManagerBlank");
	if (aPort)
	{
		aMsg=AllocMem(sizeof(struct Message),0x10000);
		if(aMsg)
		{
			aMsg->mn_Length=sizeof(struct Message);
			aMsg->ln_Name=NULL;
		}
		PutMsg (aPort,aMsg);
	}
	Permit();

	exit(0);
}

void __saveds __interrupt DoCurvo()
{
	struct BitMap *aBitMap;
	long	blah,count,shadeindex,speedindex;
	WORD	planeoffset,planebit;
	
	for (count=0;count<numcurvos;count++)
	{
		for (speedindex=0;speedindex<2;speedindex++)
		{
			thecurvos[count].newgoaltimer--;
			if (!thecurvos[count].newgoaltimer)
			{
				thecurvos[count].goalx=rand()%(160<<5)+(80<<5);
				thecurvos[count].goaly=rand()%(100<<5)+(50<<5);
				thecurvos[count].newgoaltimer=(rand()&31)+16;
			}

//			*((WORD *)0xdff180)=0xf00;

			aBitMap=aScreen->RastPort.BitMap;

			if (thecurvos[count].currentx<thecurvos[count].goalx)
			{
				thecurvos[count].deltax++;
				if (thecurvos[count].deltax>32) thecurvos[count].deltax=32;
			}
			else
			{
				thecurvos[count].deltax--;
				if (thecurvos[count].deltax<-32) thecurvos[count].deltax=-32;
			}
			if (thecurvos[count].currenty<thecurvos[count].goaly)
			{
				thecurvos[count].deltay++;
				if (thecurvos[count].deltay>32) thecurvos[count].deltay=32;
			}
			else
			{
				thecurvos[count].deltay--;
				if (thecurvos[count].deltay<-32) thecurvos[count].deltay=-32;
			}
			thecurvos[count].currentx+=thecurvos[count].deltax;
			thecurvos[count].currenty+=thecurvos[count].deltay;
			planeoffset=(thecurvos[count].currenty>>5)*(aBitMap->BytesPerRow)+((thecurvos[count].currentx>>5)>>3);
			planebit=0x80>>((thecurvos[count].currentx>>5)&7);

			plot(aBitMap,thecurvos[count].curvoarray[thecurvos[count].arraypointer<<1],thecurvos[count].curvoarray[(thecurvos[count].arraypointer<<1)+1],0);
			thecurvos[count].curvoarray[thecurvos[count].arraypointer<<1]=planeoffset;
			thecurvos[count].curvoarray[(thecurvos[count].arraypointer<<1)+1]=planebit;
			thecurvos[count].arraypointer=(thecurvos[count].arraypointer+1)&(curvolength-1);

			plot(aBitMap,planeoffset,planebit,7);

			blah=thecurvos[count].arraypointer;
			for (shadeindex=0;shadeindex<64;shadeindex++)
			{
				plot(aBitMap,thecurvos[count].curvoarray[blah<<1],
						thecurvos[count].curvoarray[(blah<<1)+1],
						shadeindex>>3);
				blah=(blah+1)&(curvolength-1);
			}
		}
	}
}

void plot(struct BitMap *aBitMap,WORD planeoffset,WORD bit,WORD col)
{
	WORD notbit,planedex;

	notbit=~bit;
	for (planedex=0;planedex<3;planedex++)
	{
		if (col&(1<<planedex))
			((char *)aBitMap->Planes[planedex])[planeoffset]|=bit;
		else
			((char *)aBitMap->Planes[planedex])[planeoffset]&=notbit;
	}
}

int NumCurvosClicked( void )
{
	/* routine when gadget "Number Of Curvos" is clicked. */
	if (((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt < 1)
	{
		GT_SetGadgetAttrs(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL,GTIN_Number,1,TAG_END);
//		((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt =1;
//		RefreshGadgets(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL);
	}
	return 1;
}

int CurvoSaveClicked( void )
{
	if (((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt < 1)
	{
		GT_SetGadgetAttrs(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL,GTIN_Number,1,TAG_END);
//		((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt =1;
//		RefreshGadgets(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL);
	}
	numcurvos=((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt;
	SavePrefs();
	return 0;
}

int CurvoUseClicked( void )
{
	if (((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt < 1)
	{
		GT_SetGadgetAttrs(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL,GTIN_Number,1,TAG_END);
//		((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt =1;
//		RefreshGadgets(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL);
	}
	numcurvos=((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt;
	return 0;
}

int CurvoBlankerCloseWindow( void )
{
	if (((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt < 1)
	{
		GT_SetGadgetAttrs(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL,GTIN_Number,1,TAG_END);
//		((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt =1;
//		RefreshGadgets(CurvoBlankerGadgets[GD_NumCurvos],CurvoBlankerWnd,NULL);
	}
	numcurvos=((struct StringInfo *)CurvoBlankerGadgets[GD_NumCurvos]->SpecialInfo)->LongInt;
	return 0;
}

