/*
 * CaBoom, 1995 Lee Kindness.
 *         1996 Juan J. García de Soria.
 *
 * Patches:
 *  intuition.library OpenWindow()
 *  intuition.library OpenWindowTagList()
 *  intuition.library CloseWindow()
 *
 * When windows open or close a small 'explosion' is done.
 *
 * This source is in the public domain, do with it as you wish...
 *
 * version 1.4
 *
 ***************************************************************************/

#include "gst.c"

/********************************* download dev/c/SFPatch.lha for documentation */

#include "SFPatch.h"


/********************************* DONT auto open... */

extern struct IntuitionBase *IntuitionBase = NULL;
extern struct Library *CxBase = NULL;
extern struct Library *IconBase = NULL;
extern struct Library *UtilityBase = NULL;
extern struct GfxBase *GfxBase = NULL;
extern struct Library *LayersBase = NULL;

/* Save a bit of typing */
#define REG(x) register __ ## x


/********************************* The function offsets */

#define OW_OFFSET -204
#define OWTL_OFFSET -606
#define CW_OFFSET -72 

/********************************* Default prefs */

#define DEF_NOBACKDROPS FALSE
#define DEF_SPEED 1000
#define DEF_LINE 0xFFFF
#define DEF_NSTEPS 40
#define DEF_NUMBER 5
#define DEF_METHOD 0
#define DEF_MAXPEN 255
#define DEF_CYCLE FALSE
#define DEF_RANDOM FALSE
#define MAXSTEPS 21
#define LAST_METHOD 5

/********************************* types */

typedef struct Window * __asm (*OW_Caller)( REG(a0) struct NewWindow *, 
                                            REG(a6) struct Library *);
typedef struct Window * __asm (*OWTL_Caller)( REG(a0) struct NewWindow *,
                                              REG(a1) struct TagItem *,
                                              REG(a6) struct Library *);
typedef void __asm (*CW_Caller)( REG(a0) struct Window *,
                                 REG(a6) struct Library *);
struct Prefs {
	LONG Speed, Line, nSteps, Number, Method, MaxPen, Pri;
	BOOL NoBackdrops, Cycle, Random;
  struct {
    struct {
      int x, y;
    } topleft, botright;
  } step[MAXSTEPS];
};

/********************************* Prototypes */

struct Window * __asm OW_New( REG(a0) struct NewWindow *, 
                              REG(a6) struct Library *);
struct Window * __asm OWTL_New( REG(a0) struct NewWindow *,
                                REG(a1) struct TagItem *,
                                REG(a6) struct Library *);
void __asm CW_New( REG(a0) struct Window *,
                   REG(a6) struct Library *);
                   
void Draw1(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);
void Draw2(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);
void Draw3(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);
void Draw4(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);
void Draw5(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);
void Draw6(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n);

BOOL OpenLibs(void);
void CloseLibs(void);
BOOL ShowWindow(void);
void line (struct RastPort *rp, LONG x1, LONG y1, LONG x2, LONG y2);
void DrawOutline(struct RastPort *rp, struct Screen *screen, LONG xi, LONG yi, LONG xf, LONG yf);
void MoveOutline(struct NewWindow *nwin, struct TagItem *tags, struct Window *window, BOOL reverse);

/********************************* Global vars */

SetFunc *OW_SetFunc, *OWTL_SetFunc, *CW_SetFunc;
struct Remember *grk;
BOOL Active;
char vertag[] = "$VER: CaBoom 1.4 "__AMIGADATE__;
struct Prefs prefs = {
 DEF_SPEED, DEF_LINE, DEF_NSTEPS, DEF_NUMBER, DEF_METHOD, DEF_MAXPEN, -1, DEF_NOBACKDROPS, DEF_CYCLE, DEF_RANDOM
};

void (*(DrawM[]))(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)=
{
	Draw1,Draw2,Draw3,Draw4,Draw5,Draw6
};

int co[256],si[256];

/***************************************************************************/

/* main */
int main(int argc, char **argv)
{
	int ret,k;		
	ret = RETURN_OK;
	Active = TRUE;
	grk = NULL;
	
	for(k=0;k<256;k++)
	{
		co[k]=1024*cos((3.141592*2*k)/256);
		si[k]=1024*sin((3.141592*2*k)/256);	
	}
	
	/* check version */
	if (OpenLibs()) {
		struct NewBroker nb = {
			NB_VERSION,
			"CaBoom",
			&vertag[6],
			"Window explosions",
			NBU_UNIQUE | NBU_NOTIFY,
			COF_SHOW_HIDE,
			-1,
			NULL,
			0
		};
		CxObj *broker;
		
		/* Get tooltypes */
		if (argc ? FALSE : TRUE) {
			BPTR oldcd;
			struct DiskObject *dobj;
			struct WBStartup *wbs;
			#define PROGNAME wbs->sm_ArgList->wa_Name
			#define PDIRLOCK wbs->sm_ArgList->wa_Lock
			wbs = (struct WBStartup *)argv;
			/* Run from WB */
			oldcd = CurrentDir(PDIRLOCK);
			if (dobj = GetDiskObject(PROGNAME)) {
				STRPTR s;
				if (s = FindToolType(dobj->do_ToolTypes, "SPEED")) {
					stcd_l(s, &prefs.Speed);
				}
				if (s = FindToolType(dobj->do_ToolTypes, "LINE")) {
					stcd_l(s, &prefs.Line);
				}
				if (s = FindToolType(dobj->do_ToolTypes, "NUMBER")) {
					stcd_l(s, &prefs.Number);
				}
				if (s = FindToolType(dobj->do_ToolTypes, "MAXPEN")) {
					stcd_l(s, &prefs.MaxPen);
				}
				if (s = FindToolType(dobj->do_ToolTypes, "STEPS")) {
					stcd_l(s, &prefs.nSteps);
				}
				if (s = FindToolType(dobj->do_ToolTypes, "METHOD")) {
					stcd_l(s, &prefs.Method);
				}
				
				if(prefs.Method<0 || prefs.Method>LAST_METHOD)
					prefs.Method=0;
				
				if (s = FindToolType(dobj->do_ToolTypes, "NOBACKDROPS")) {
					prefs.NoBackdrops = TRUE;
				}
				if (s = FindToolType(dobj->do_ToolTypes, "CYCLE")) {
					prefs.Cycle = TRUE;
				}
				if (s = FindToolType(dobj->do_ToolTypes, "RANDOM")) {
					prefs.Random = TRUE;
				}
				if (s = FindToolType(dobj->do_ToolTypes, "CX_PRIORITY")) {
					stcd_l(s, &prefs.Pri);
				}
				FreeDiskObject(dobj);
			}
			CurrentDir(oldcd);
		} else {
			struct RDArgs *rdargs;
			#define OPT_SPEED 0
			#define OPT_LINE 1
			#define OPT_NOBACKDROPS 2
			#define OPT_CXP 3
			#define OPT_NUMBER 4
			#define OPT_METHOD 5
			#define OPT_STEPS 6
			#define OPT_MAXPEN 7
			#define OPT_CYCLE 8
			#define OPT_RANDOM 9
			LONG args[10] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
			#define TEMPLATE "SPEED/K/N,LINE/K/N,NOBACKDROPS/S,CX_PRIORITY/K/N,NUMBER/K/N,METHOD/K/N,STEPS/K/N,MAXPEN/K/N,CYCLE/S,RANDOM/S"
			/* Run from Shell */
			if (rdargs = ReadArgs(TEMPLATE, (LONG *)&args, NULL)) {
				if (args[OPT_SPEED]) {
					prefs.Speed = *((LONG *)args[OPT_SPEED]);
				}
				if (args[OPT_LINE]) {
					prefs.Line = *((LONG *)args[OPT_LINE]);
				}
				if (args[OPT_NUMBER]) {
					prefs.Number = *((LONG *)args[OPT_NUMBER]);
				}
				if (args[OPT_MAXPEN]) {
					prefs.MaxPen = *((LONG *)args[OPT_MAXPEN]);
				}
				if (args[OPT_STEPS]) {
					prefs.nSteps = *((LONG *)args[OPT_STEPS]);
				}
				if (args[OPT_METHOD]) {
					prefs.Method = *((LONG *)args[OPT_METHOD]);
				}

				if(prefs.Method<0 || prefs.Method>LAST_METHOD)
					prefs.Method=0;

				 if (args[OPT_NOBACKDROPS]) {
					prefs.NoBackdrops = TRUE;
				}
				 if (args[OPT_CYCLE]) {
					prefs.Cycle = TRUE;
				}
				 if (args[OPT_RANDOM]) {
					prefs.Random = TRUE;
				}
				if (args[OPT_CXP]) {
					prefs.Pri = *((LONG *)args[OPT_CXP]);
				}
				FreeArgs(rdargs);	
			}
		}
		
		if (prefs.Speed < 0)
			prefs.Speed = 0;
	
		nb.nb_Pri = prefs.Pri;
				
		if ((nb.nb_Port = CreateMsgPort()) && (broker = CxBroker(&nb, NULL))) {
			
			/* Alloc our SetFunc's */
			if((OW_SetFunc = AllocVec(sizeof(SetFunc), MEMF_CLEAR)) &&
			   (OWTL_SetFunc = AllocVec(sizeof(SetFunc), MEMF_CLEAR)) &&
			   (CW_SetFunc = AllocVec(sizeof(SetFunc), MEMF_CLEAR))) {

				/* init. sfs */
				OW_SetFunc->sf_Func = OW_New;
				OW_SetFunc->sf_Library = (struct Library *)IntuitionBase;
				OW_SetFunc->sf_Offset = OW_OFFSET;
				OW_SetFunc->sf_QuitMethod = SFQ_COUNT;
				OWTL_SetFunc->sf_Func = OWTL_New;
				OWTL_SetFunc->sf_Library = (struct Library *)IntuitionBase;
				OWTL_SetFunc->sf_Offset = OWTL_OFFSET;
				OWTL_SetFunc->sf_QuitMethod = SFQ_COUNT;
				CW_SetFunc->sf_Func = CW_New;
				CW_SetFunc->sf_Library = (struct Library *)IntuitionBase;
				CW_SetFunc->sf_Offset = CW_OFFSET;
				CW_SetFunc->sf_QuitMethod = SFQ_COUNT;

				/* Replace the functions */
				if ((SFReplace(OW_SetFunc)) &&
				    (SFReplace(OWTL_SetFunc)) &&
				    (SFReplace(CW_SetFunc))) {
					
					ULONG sig, sret;
					BOOL finished;
					
					ActivateCxObj(broker, 1L);

					finished = FALSE;
					sig = 1 << nb.nb_Port->mp_SigBit;
					
					do {
						sret = Wait(SIGBREAKF_CTRL_C | sig);
						if (sret & sig) {
							CxMsg *msg;
							while(msg = (CxMsg *)GetMsg(nb.nb_Port)) {
								switch(CxMsgType(msg)) {
									case CXM_COMMAND:
										switch(CxMsgID(msg)) {
											case CXCMD_DISABLE:
												ActivateCxObj(broker, 0L);
												Active = FALSE;
												break;
											case CXCMD_ENABLE:
												ActivateCxObj(broker, 1L);
												Active = TRUE;
												break;
											case CXCMD_KILL:
												finished = TRUE;
												break;
											case CXCMD_UNIQUE:
												finished = ShowWindow();
												break;
											case CXCMD_APPEAR:
												finished = ShowWindow();
												break;
										}
										break;
								}
								ReplyMsg((struct Message *)msg);
							}
						}
						if (sret & SIGBREAKF_CTRL_C)
							finished = TRUE;
					} while (!finished);
					ActivateCxObj(broker, 0L);
	
					/* Restore functions */
					SFRestore(CW_SetFunc);
					SFRestore(OWTL_SetFunc);
					SFRestore(OW_SetFunc);
				}
				FreeVec(CW_SetFunc);
				FreeVec(OWTL_SetFunc);
				FreeVec(OW_SetFunc);
			}
			DeleteCxObj(broker);
			DeletePort(nb.nb_Port);
		}
	}
	CloseLibs();
	return(ret);
}


/***************************************************************************/
/* Show our window... currently only a requester */
BOOL ShowWindow(void)
{
	struct EasyStruct ez = {
		sizeof(struct EasyStruct),
		0,
		"CaBoom",
		"%s ©Lee Kindness.\n\n"
		"wangi@fido.zetnet.co.uk\n\n"
		"Window explosions\n\n"
		"Read \"CaBoom.guide\" for more information\n\n"
		"(Program may take a couple of seconds to quit)",
		"Quit|Hide"
	};
	return((BOOL)EasyRequest(NULL, &ez, NULL, &vertag[6]));
}


/***************************************************************************/
/* Open all used libraries */
BOOL OpenLibs(void)
{
	BOOL ret;
	IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 37);
	CxBase = OpenLibrary("commodities.library", 37);
	IconBase = OpenLibrary("icon.library", 37);
	UtilityBase = OpenLibrary("utility.library", 37);
	GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 37);
	LayersBase = OpenLibrary("layers.library", 37);
	ret = ((IntuitionBase) && 
	       (CxBase) && 
	       (IconBase) &&
	       (UtilityBase) &&
	       (GfxBase) &&
	       (LayersBase));
	return(ret);
}


/***************************************************************************/
/* Close all libraries */
void CloseLibs(void)
{
	if (LayersBase)
		CloseLibrary(LayersBase);
	if (GfxBase)
		CloseLibrary((struct Library *)GfxBase);
	if (UtilityBase)
		CloseLibrary(UtilityBase);
	if (IconBase)
		CloseLibrary(IconBase);
	if (CxBase)
		CloseLibrary(CxBase);
	if (IntuitionBase)
		CloseLibrary((struct Library *)IntuitionBase);
}


/***************************************************************************/
/* Draws a line */
void line (struct RastPort *rp, LONG x1, LONG y1, LONG x2, LONG y2)
{
	Move(rp, x1, y1);
	Draw(rp, x2, y2);
}


/***************************************************************************/
/* Draws a box-outline */

#define MAX(a,b) (((a)>(b))?(a):(b))
#define MIN(a,b) (((a)<(b))?(a):(b))
#define xclip(x) (MAX(0, MIN(x, screen->Width - 1)))
#define yclip(y) (MAX(0, MIN(y, screen->Height - 1)))

void Drawline(struct RastPort *rp, struct Screen *screen, LONG xi, LONG yi, LONG xf, LONG yf)
{
	xi = xclip(xi);
	yi = yclip(yi);
	xf = xclip(xf);
	yf = yclip(yf);
	line(rp, xi, yi, xf, yf);
}

void Draw1(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG xi,yi,xf,yf;
	
	xi = x0 + ((n * dxi) / prefs.nSteps);
	yi = y0 + ((n * dyi) / prefs.nSteps);
	xf = x0 + ((n * dxf) / prefs.nSteps);
	yf = y0 + ((n * dyf) / prefs.nSteps);
	
	Drawline(rp,screen,xi,yi,xf,yi);
	Drawline(rp,screen,xi,yi,xi,yf);
	Drawline(rp,screen,xf,yi,xf,yf);
	Drawline(rp,screen,xi,yf,xf,yf);
}

void Draw2(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG x1,y1,x2,y2,x3,y3,x4,y4;
	LONG w,h;
	LONG dx,dy;
	int k;
	
	dx=(dxi+dxf)>>1;
	dy=(dyi+dyf)>>1;
	
	w=(((dxf-dxi)>>1)*n)/prefs.nSteps;
	h=(((dyf-dyi)>>1)*n)/prefs.nSteps;
	
	k=(n*128)/prefs.nSteps;
	
	x1=x2=x3=x4=x0+(dx*n)/prefs.nSteps;
	y1=y2=y3=y4=y0+(dy*n)/prefs.nSteps;
	
	x1+=((-w*co[k]-h*si[k])>>10);
	x2+=((w*co[k]-h*si[k])>>10);
	x3+=((w*co[k]+h*si[k])>>10);
	x4+=((-w*co[k]+h*si[k])>>10);
	
	y1+=((-w*si[k]+h*co[k])>>10);
	y2+=((w*si[k]+h*co[k])>>10);
	y3+=((w*si[k]-h*co[k])>>10);
	y4+=((-w*si[k]-h*co[k])>>10);
	
	Drawline(rp,screen,x1,y1,x2,y2);
	Drawline(rp,screen,x2,y2,x3,y3);
	Drawline(rp,screen,x3,y3,x4,y4);
	Drawline(rp,screen,x4,y4,x1,y1);
}

void Draw3(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG x1,y1,x2,y2,x3,y3,x4,y4;
	LONG w,h;
	LONG dx,dy;
	int k;
	
	dx=(dxi+dxf)>>1;
	dy=(dyi+dyf)>>1;
	
	w=(((dxf-dxi)>>1)*n)/prefs.nSteps;
	h=(((dyf-dyi)>>1)*n)/prefs.nSteps;
	
	k=((n*448)/prefs.nSteps)&255;
	
	w=(w*(-si[k]+2048))/3072;
	h=(h*(-si[k]+2048))/3072;
	
	k=(n*128)/prefs.nSteps;
	
	x1=x2=x3=x4=x0+(dx*n)/prefs.nSteps;
	y1=y2=y3=y4=y0+(dy*n)/prefs.nSteps;
	
	x1+=((-w*co[k]-h*si[k])>>10);
	x2+=((w*co[k]-h*si[k])>>10);
	x3+=((w*co[k]+h*si[k])>>10);
	x4+=((-w*co[k]+h*si[k])>>10);
	
	y1+=((-w*si[k]+h*co[k])>>10);
	y2+=((w*si[k]+h*co[k])>>10);
	y3+=((w*si[k]-h*co[k])>>10);
	y4+=((-w*si[k]-h*co[k])>>10);
	
	Drawline(rp,screen,x1,y1,x2,y2);
	Drawline(rp,screen,x2,y2,x3,y3);
	Drawline(rp,screen,x3,y3,x4,y4);
	Drawline(rp,screen,x4,y4,x1,y1);
}

void Draw4(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG x1,y1,x2,y2,x3,y3,x4,y4;
	LONG w,h;
	LONG dx,dy;
	int k;
	
	dx=(dxi+dxf)>>1;
	dy=(dyi+dyf)>>1;
	
	w=(((dxf-dxi)>>1)*n)/prefs.nSteps;
	h=(((dyf-dyi)>>1)*n)/prefs.nSteps;
	
	k=((n*448)/prefs.nSteps)&255;
	
	w=(w*(-si[k]+2048))/3072;
	h=(h*(-si[k]+2048))/3072;
	
	x1=x2=x3=x4=x0+(dx*n)/prefs.nSteps;
	y1=y2=y3=y4=y0+(dy*n)/prefs.nSteps;
	
	x1-=w;
	x2+=w;
	x3+=w;
	x4-=w;
	
	y1+=h;
	y2+=h;
	y3-=h;
	y4-=h;
	
	Drawline(rp,screen,x1,y1,x2,y2);
	Drawline(rp,screen,x2,y2,x3,y3);
	Drawline(rp,screen,x3,y3,x4,y4);
	Drawline(rp,screen,x4,y4,x1,y1);
}

void Draw5(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG x1,y1,x2,y2,x3,y3,x4,y4;
	LONG x1b,y1b,x2b,y2b,x3b,y3b,x4b,y4b;
	LONG w,h,ws,hs;
	LONG dx,dy;
	
	dx=(dxi+dxf)>>1;
	dy=(dyi+dyf)>>1;
	
	w=(dxf-dxi)>>1;
	h=(dyf-dyi)>>1;
	ws=(w*n)/prefs.nSteps;
	hs=(h*n)/prefs.nSteps;
	
	x1=x2=x3=x4=x1b=x2b=x3b=x4b=x0+(dx*n)/prefs.nSteps;
	y1=y2=y3=y4=y1b=y2b=y3b=y4b=y0+(dy*n)/prefs.nSteps;
	
	x1-=ws;
	x2+=ws;
	x3+=ws;
	x4-=ws;
	
	y1-=hs;
	y2-=hs;
	y3+=hs;
	y4+=hs;

	x2b+=w;
	x4b-=w;
	
	y1b-=h;
	y3b+=h;
	
	Drawline(rp,screen,x1,y1,x1b,y1b);
	Drawline(rp,screen,x1b,y1b,x2,y2);
	Drawline(rp,screen,x2,y2,x2b,y2b);
	Drawline(rp,screen,x2b,y2b,x3,y3);
	Drawline(rp,screen,x3,y3,x3b,y3b);
	Drawline(rp,screen,x3b,y3b,x4,y4);
	Drawline(rp,screen,x4,y4,x4b,y4b);
	Drawline(rp,screen,x4b,y4b,x1,y1);
}


void Draw6(struct RastPort *rp, struct Screen *screen, LONG x0, LONG y0, LONG dxi, LONG dyi, LONG dxf, LONG dyf, LONG n)
{
	LONG x1,y1,x2,y2,x3,y3,x4,y4;
	LONG x1b,y1b,x2b,y2b,x3b,y3b,x4b,y4b;
	LONG w,h,ws,hs;
	LONG dx,dy;
	int k;
	
	dx=(dxi+dxf)>>1;
	dy=(dyi+dyf)>>1;
	
	w=(dxf-dxi)>>1;
	h=(dyf-dyi)>>1;
	ws=(w*n)/prefs.nSteps;
	hs=(h*n)/prefs.nSteps;
	
	k=(n*128)/prefs.nSteps;
	
	x1=x2=x3=x4=x1b=x2b=x3b=x4b=x0+(dx*n)/prefs.nSteps;
	y1=y2=y3=y4=y1b=y2b=y3b=y4b=y0+(dy*n)/prefs.nSteps;
	
	x1+=((-ws*co[k]-hs*si[k])>>10);
	x2+=((ws*co[k]-hs*si[k])>>10);
	x3+=((ws*co[k]+hs*si[k])>>10);
	x4+=((-ws*co[k]+hs*si[k])>>10);
	
	y1+=((-ws*si[k]+hs*co[k])>>10);
	y2+=((ws*si[k]+hs*co[k])>>10);
	y3+=((ws*si[k]-hs*co[k])>>10);
	y4+=((-ws*si[k]-hs*co[k])>>10);

	x1b+=((-h*si[k])>>10);
	x2b+=((w*co[k])>>10);
	x3b+=((h*si[k])>>10);
	x4b+=((-w*co[k])>>10);
	
	y1b+=((h*co[k])>>10);
	y2b+=((w*si[k])>>10);
	y3b+=((-h*co[k])>>10);
	y4b+=((-w*si[k])>>10);
	
	Drawline(rp,screen,x1,y1,x1b,y1b);
	Drawline(rp,screen,x1b,y1b,x2,y2);
	Drawline(rp,screen,x2,y2,x2b,y2b);
	Drawline(rp,screen,x2b,y2b,x3,y3);
	Drawline(rp,screen,x3,y3,x3b,y3b);
	Drawline(rp,screen,x3b,y3b,x4,y4);
	Drawline(rp,screen,x4,y4,x4b,y4b);
	Drawline(rp,screen,x4b,y4b,x1,y1);
}


/***************************************************************************/
/* The 'anim' */
void MoveOutline(struct NewWindow *nwin, struct TagItem *tags, struct Window *window, BOOL reverse)
{
	struct RastPort *rp;
	struct timerequest *tr;
	struct MsgPort *tmp;
	struct Screen *screen;
	LONG x, y, w, h;
	BOOL unlockscr, backdrop;
	struct TagItem *tag;
	
	if (Active)
	{
		unlockscr = FALSE;
		/* Get Screen that window will open/close on */
		if( reverse )
		{
			screen = window->WScreen;
		} else
		{
			screen = NULL;
			if (nwin)
			{
				if ((nwin->Type != WBENCHSCREEN))
					screen = nwin->Screen;
			}
			if (tag = FindTagItem(WA_CustomScreen, tags))
			{
				screen = (struct Screen *)tag->ti_Data;
			} else
			{
				if (tag = FindTagItem(WA_PubScreen, tags))
				{
					screen = (struct Screen *)tag->ti_Data;
				} else
				{
					if (tag = FindTagItem(WA_PubScreenName, tags))
					{
						screen = LockPubScreen((STRPTR)(tag->ti_Data));
						unlockscr = TRUE;
					}
				}
			}
		}
		
		if (screen == NULL)
		{
			screen = LockPubScreen(NULL);
			unlockscr = TRUE;
		}
	
		if (screen)
		{
			/* Calculate dimensions and positioning */
			if( reverse )
			{
				x = window->LeftEdge;
				y = window->TopEdge;
				w = window->Width;
				h = window->Height;
			} else
			{
				if (nwin)
				{
					x = nwin->LeftEdge;
					y = nwin->TopEdge;
					w = nwin->Width;
					h = nwin->Height;
				} else
				{
					x = 0;
					y = 0;
					w = screen->Width;
					h = screen->Height;
				}
				if (tag = FindTagItem(WA_Left, tags))
					x = tag->ti_Data;
				if (tag = FindTagItem(WA_Top, tags))
					y = tag->ti_Data;
				if (tag = FindTagItem(WA_InnerWidth, tags))
					w = tag->ti_Data + 8;
				if (tag = FindTagItem(WA_Width, tags))
					w = tag->ti_Data;
				if (tag = FindTagItem(WA_InnerHeight, tags))
					h = tag->ti_Data + 8;
				if (tag = FindTagItem(WA_Height, tags))
					h = tag->ti_Data;
			}
			
			/* findout if backdrop */
			backdrop = FALSE;
			if( reverse )
			{
				if( window->Flags & WFLG_BACKDROP )
					backdrop = TRUE;
			} else
			{
				if( (nwin) && (nwin->Flags & WFLG_BACKDROP) )
					backdrop = TRUE;
				if( (tag = FindTagItem(WA_Flags, tags)) && (tag->ti_Data & WFLG_BACKDROP) )
					backdrop = TRUE;
				if( (tag = FindTagItem(WA_Backdrop, tags)) && (tag->ti_Data) )
					backdrop = TRUE;
			}
			
			if ( !(prefs.NoBackdrops && backdrop) )
			{
				if ((rp = AllocVec(sizeof(struct RastPort), MEMF_CLEAR)) &&
	    	    (tmp = CreateMsgPort()) &&
	   	     (tr = (struct timerequest *)CreateIORequest(tmp, sizeof(struct timerequest))))
				{
					LONG timerres;
					register LONG i, n, n2;
					LONG dxi, dyi, dxf, dyf;
					LONG x0, y0;
		
					timerres = OpenDevice("timer.device", UNIT_MICROHZ, (struct IORequest *)tr, 0);

					*rp = screen->RastPort;
	
					SetDrMd(rp, COMPLEMENT | JAM1);
  				SetDrPt(rp, prefs.Line);
  				SetAPen(rp, 1);
  				SetMaxPen(rp, prefs.MaxPen);
	
					x0 = screen->MouseX;
  					y0 = screen->MouseY;

					dxi = x - x0;
					dyi = y - y0;
					dxf = (x + w - 1) - x0;
					dyf = (y + h - 1) - y0;
	
					LockLayers (&screen->LayerInfo);

					if(prefs.Cycle)
					{
						prefs.Method++;
						if(prefs.Method>LAST_METHOD)
							prefs.Method=0;
					}
					
					if(prefs.Random)
					{
						prefs.Method=rand()%(LAST_METHOD+1);
					}

					for (i = 0; i < prefs.nSteps+prefs.Number; i++)
					{
						if (reverse)
						{
							n = prefs.nSteps - i;
							n2 = prefs.nSteps - i + prefs.Number;
						}
						else
						{
							n = i;
							n2 = i - prefs.Number;
						}
						
						if(n >= 0 && n < prefs.nSteps)
							(*(DrawM[prefs.Method]))(rp, screen, x0, y0, dxi, dyi, dxf, dyf, n);	/* draws outline */
			
						if ((prefs.Speed) && (timerres == 0))
						{
							tr->tr_node.io_Command = TR_ADDREQUEST;
							tr->tr_node.io_Flags = 0;
							tr->tr_time.tv_secs = 0;
							tr->tr_time.tv_micro = prefs.Speed;
							DoIO((struct IORequest *)tr);
						}
						
						if(n2 >= 0 && n2 < prefs.nSteps)
							(*(DrawM[prefs.Method]))(rp, screen, x0, y0, dxi, dyi, dxf, dyf, n2);	/* erases outline */
					}
					if (timerres == 0)
						CloseDevice((struct IORequest *)tr);
					DeleteIORequest((struct IORequest *)tr);
					DeleteMsgPort(tmp);
					FreeVec(rp);
				}
				UnlockLayers(&screen->LayerInfo);
			}

			if (unlockscr)
				UnlockPubScreen(NULL, screen);	
		}
	}
}

/***************************************************************************/
/* The new OpenWindow() */
struct Window * __saveds __asm OW_New(REG(a0) struct NewWindow *nwin, 
                                      REG(a6) struct Library *lib)
{
	OW_Caller Caller;
	struct Window *ret;
	
	/* increment count */
	Forbid();
	OW_SetFunc->sf_Count += 1;
	Permit();
	
	MoveOutline(nwin, NULL, NULL, FALSE);
	
	Caller = (APTR)OW_SetFunc->sf_OriginalFunc;
	
	/* Pass the buck */
	ret = Caller(nwin, lib);
	
	/* decrement count */
	Forbid();
	OW_SetFunc->sf_Count -= 1;
	Permit();
	
	/* and return */
	return(ret);

}


/***************************************************************************/
/* The new OpenWindowTagList() */
struct Window * __saveds __asm OWTL_New(REG(a0) struct NewWindow *nwin, 
                                        REG(a1) struct TagItem *tags,
                                        REG(a6) struct Library *lib)
{
	struct Window *ret;
	OWTL_Caller Caller;
	
	/* increment count */
	Forbid();
	OWTL_SetFunc->sf_Count += 1;
	Permit();
	
	MoveOutline(nwin, tags, NULL, FALSE);
	
	Caller = (APTR)OWTL_SetFunc->sf_OriginalFunc;
	
	/* Pass the buck */
	ret = Caller(nwin, tags, lib);
	
	/* decrement count */
	Forbid();
	OWTL_SetFunc->sf_Count -= 1;
	Permit();
	
	/* and return */
	return(ret);
}


/***************************************************************************/
/* The new CloseWindow() */
void __saveds __asm CW_New(REG(a0) struct Window *win, 
                           REG(a6) struct Library *lib)
{
	CW_Caller Caller;
	struct Window *wincopy;
	
	/* increment count */
	Forbid();
	CW_SetFunc->sf_Count += 1;
	Permit();
	
	if( wincopy = AllocVec(sizeof(struct Window), MEMF_CLEAR) )
	{
		*wincopy = *win;
	}

	Forbid();

	/* Pass the buck */
	Caller = (APTR)CW_SetFunc->sf_OriginalFunc;
	Caller(win, lib);
	
	if ( wincopy )
	{
		MoveOutline(NULL, NULL, wincopy, TRUE);
		FreeVec(wincopy);
	}

	Permit();
	
	/* decrement count */
	Forbid();
	CW_SetFunc->sf_Count -= 1;
	Permit();
}
/***************************************************************************/
