
/*
 *  DLineArt.c
 *
 *  DMouse screen blanker for use with DMouse V1.20
 *
 *  read the docs file for installation procedures.
 *
 *  Is your computer BORED? If so, then you need...
 *
 *		DLineArt, by Steve -Raz- Berry with help
 *		from Matt Dillon.
 *
 *  Compile +L w/ sup32.lib.  libs:dres.library no longer required
 */

#include <local/typedefs.h>
#include <local/ipc.h>
#include <local/xmisc.h>

typedef struct IORequest IORequest;

#define MAXELLIPSE 75

/* Be carefule if modifiying the following defines... */

int MAXX, MAXY;

#define MINBOUND 20
#define BOUNDX MAXX-MINBOUND
#define BOUNDY MAXY-MINBOUND

#define TEXTSTR 0x10
#define SPLINES 0x8
#define LINES 0x4
#define BOXES 0x2
#define ELLIPSES 0x1

/* Maximun # of lines,boxes,ellipses to draw (watch your stack!) */

#define MAXLINES 500

UWORD coltbl[2] = {
    0x000,		/* background color */
    0x500
};

extern int Enable_Abort;

RP *rp;
VP *vp;
static SCR *Scr;
static WIN *Win;
static TA   Ta = {  (ubyte *)"topaz.font", 11 };
static NS   Ns = {  0, 0, 0, 0, 1, -1, -1, HIRES|LACE, CUSTOMSCREEN|SCREENQUIET, &Ta };
static NW   Nw = { 0, 0, 0, 0, 2, 1, NULL, BORDERLESS|NOCAREREFRESH|BACKDROP,
NULL, NULL,NULL,NULL,NULL,0,0,8000,8000,CUSTOMSCREEN};

static long offset, scale1, scale2, flags;
static long count, trails, nice, all;
static long input, maxlines, ctemp;
static long point1[MAXLINES+1][2], point2[MAXLINES+1][2], direction[2][2];

static char *TStr = "BOING!";
static long TLen = 6;

void
InitScrStructures()
{
    SCR scr;
    if (GetScreenData(&scr, sizeof(scr), WBENCHSCREEN, NULL)) {
	if (scr.ViewPort.Modes & HIRES)
	    MAXX = scr.Width;
	else
	    MAXX = scr.Width * 2;
	if (scr.ViewPort.Modes & LACE)
	    MAXY = scr.Height;
	else
	    MAXY = scr.Height * 2;
    } else {
	MAXX = 640;
	MAXY = 200;
    }
    Ns.Width  = MAXX;
    Nw.Width  = MAXX;
    Ns.Height = MAXY;
    Nw.Height = MAXY;
}

main(argc,argv)
int argc;
char *argv[];
{
    int var;
    IORequest AddReq;	/* for dmouse ipc	*/
    IORequest RemReq;
    PORT    *dmport;
    PORT    *ipport;
    char    foo;	/*  dummy variable, address used as id	*/
    short   notdone = 1;

    input  = 3; 	/* Some defaults for switches */
    trails = 1;
    maxlines = 20;
    nice  = FALSE;
    all   = FALSE;
    flags = LINES;


    Enable_Abort = 0;

    while(--argc >= 1) {
	switch (argv[argc][0]) {
	    case '-':
		switch (argv[argc][1]) {
		    case 'T':
			flags = TEXTSTR;
			TStr = &argv[argc][2];
			if (TStr[0] != \0)
			    TLen = strlen(TStr);
			break;
		    case 's':
			flags = SPLINES;
			break;
		    case 't':
			trails = 0;
			break;
		    case 'n':
			nice = TRUE;
			break;
		    case 'l':
			maxlines = atoi(&argv[argc][2]);
			maxlines = (maxlines > MAXLINES) ? MAXLINES : (maxlines < 1) ? 1 : maxlines;
			break;
		    case 'c':
			ctemp = atoi(&argv[argc][2]);
			coltbl[1] = (ctemp > 4096) ? 4096 : (ctemp < 1) ? 1 : ctemp;
			break;
		    case 'b':
			flags = BOXES;
			break;
		    case 'e':
			flags = ELLIPSES;
			break;
		    case 'a':
			all = TRUE;
			break;
		    default:
			exit(20);
		}
		break;
	    default:
		input = atoi(argv[argc]);
		break;
	}
    }

    input = (input > 9) ? 9 : (input < 0) ? 1 : input;

    count = 0;
    scale1 = 2;
    scale2 = 2;
    offset = 0;

    ipport = CreatePort(NULL, 0);   /*  ipc port    */

    if (openlibs(INTUITION_LIB|GRAPHICS_LIB) == 0)
	goto fail;

    InitScrStructures();

    for(var = 0; var < VBeamPos(); ++var)
	get_rand_point();

    point1[0][0] = get_rand_point();    /* Initial start x,y (one endpoint) */
    point1[0][1] = get_rand_point();

    point2[0][0] = get_rand_point();
    point2[0][1] = get_rand_point();

    for(var = 0; var < 2; ++var){
	direction[var][0] = get_rand_dir();
	direction[var][1] = get_rand_dir();
    }

    AddReq.io_Message.mn_ReplyPort = ipport;
    AddReq.io_Command = 0x84;
    AddReq.io_Unit = (struct Unit *)&foo;
    AddReq.io_Flags = 0x0C;	/* %1100 (screen blanker, no mouse blanker) */

    RemReq.io_Message.mn_ReplyPort = ipport;
    RemReq.io_Command = 0x85;
    RemReq.io_Unit = (struct Unit *)&foo;

    Forbid();
    if (dmport = FindPort("DMouse.ipc"))
	PutMsg(dmport, &AddReq.io_Message);
    Permit();
    if (dmport == NULL) {
	puts("DMouse not running or <V1.20");
	goto fail;
    }

    while (notdone) {
	long mask = SIGBREAKF_CTRL_C | (1 << ipport->mp_SigBit);
	if (Scr)
	    mask = SetSignal(0L, mask);
	else
	    mask = Wait(mask);

	if (mask & SIGBREAKF_CTRL_C)
	    notdone = 0;
	if (mask & (1 << ipport->mp_SigBit)) {
	    IORequest *ior;
	    while (ior = (IORequest *)GetMsg(ipport)) {
		if (ior->io_Message.mn_Node.ln_Type == NT_REPLYMSG) {
		    notdone = 0;
		    continue;
		}
		switch(ior->io_Command) {
		case 0x82:
		    screenon();
		    break;
		case 0x83:
		    screenoff();
		    break;
		case 0x86:
		    notdone = 0;
		    break;
		}
		ReplyMsg(&ior->io_Message);
	    }
	}
	if (Win)
	    LineArt();
    }
    screenon();
    PutMsg(dmport, &RemReq.io_Message);
    {
	register IORequest *ior = NULL;
	while (ior != &AddReq) {
	    WaitPort(ipport);
	    ior = (IORequest *)GetMsg(ipport);
	    if (ior->io_Message.mn_Node.ln_Type == NT_MESSAGE)
		ReplyMsg(&ior->io_Message);
	}
    }
fail:
    DeletePort(ipport);
    closelibs(-1);
}

screenoff()
{
    if (Scr)
	ScreenToFront(Scr);
    else if (Scr = OpenScreen(&Ns)) {
	Nw.Screen = Scr;
	if (Win = OpenWindow(&Nw)){
		vp = &Scr->ViewPort;
		rp = Win->RPort;
		LoadRGB4(vp,coltbl,2L);
	}
	ShowTitle(Scr, FALSE);
    }
}

screenon()
{
    if (Win)
	CloseWindow(Win);
    if (Scr)
	CloseScreen(Scr);
    Win = NULL;
    Scr = NULL;
    vp = NULL;
    rp = NULL;
}

LineArt()
{
    register int newoffset, tempx, tempy;

    SetAPen(rp, 1L);

    if (nice)
	WaitTOF();

    switch (flags) {
    case LINES:
	Move(rp, point1[offset][0], point1[offset][1]);
	Draw(rp, point2[offset][0], point2[offset][1]);
	break;
    case ELLIPSES:
	doellipse(offset);
	break;
    case BOXES:
	dobox(offset);
	break;
    case SPLINES:
	dospline(offset);
	break;
    case TEXTSTR:
	doteresa(offset);
	break;
    }

    if (checkbounce1(offset)) {
	tempx = direction[0][0];
	tempy = direction[0][1];

	direction[0][0] = (point1[offset][0] <= MINBOUND) ? 1 :
	(point1[offset][0] >= BOUNDX) ? -1 :
	get_rand_dir();

	direction[0][1] = (point1[offset][1] <= MINBOUND) ? 1 :
	(point1[offset][1] >= BOUNDY) ? -1 :
	get_rand_dir();

	scale1 = get_rand_scale();
    }

    if (checkbounce2(offset)) {
	tempx = direction[1][0];
	tempy = direction[1][1];

	direction[1][0] = (point2[offset][0] <= MINBOUND) ? 1 :
	(point2[offset][0] >= BOUNDX) ? -1 :
	get_rand_dir();

	direction[1][1] = (point2[offset][1] <= MINBOUND) ? 1 :
	(point2[offset][1] >= BOUNDY) ? -1 :
	get_rand_dir();

	scale2 = get_rand_scale();
    }

    if ((++count > 60000) | (count > 2500 && (flags == ELLIPSES))) {
	count = maxlines;
	if (trails == 0 | all) {
	    count = 0;
	    offset = 0;
	    Move(rp, 0, 0);
	    ClearScreen(rp);
	}
	if (all) {
	    flags = flags << 1;
	    if (flags > TEXTSTR)
		flags = ELLIPSES;
	}
    }

    if (++offset > maxlines){
	coltbl[1]++;
	LoadRGB4(vp,coltbl,2L);
	if ((coltbl[1] && 0x00f) > 0xb) {
	    coltbl[1] = coltbl[1] & 0xff0;
	    coltbl[1] += 0x010;
	}
	if ((coltbl[1] && 0x0f0) > 0xb0) {
	    coltbl[1] = coltbl[1] & 0xf0f;
	    coltbl[1] += 0x100;
	}
	if ((coltbl[1] && 0xf00) > 0xb00) {
	    coltbl[1] = ctemp;
	}
    }

    if (offset > maxlines)
	offset = 0;

    /* Erase the oldest line... (or ellipse) */

    if (count > maxlines-1) {
	newoffset = (offset == maxlines) ? 0 : offset + trails;
	SetAPen(rp, 0L);
	switch (flags) {
	case LINES:
	    Move(rp, point1[newoffset][0], point1[newoffset][1]);
	    Draw(rp, point2[newoffset][0], point2[newoffset][1]);
	    break;
	case ELLIPSES:
	    doellipse(newoffset);
	    break;
	case BOXES:
	    dobox(newoffset);
	    break;
	case SPLINES:
	    dospline(newoffset);
	    break;
	case TEXTSTR:
	    doteresa(newoffset);
	    break;
	}
	SetAPen(rp, 1L);
    }

    /* Calculate the next point */

    newoffset = (offset > 0) ? offset-1 : maxlines;
    point1[offset][0] = (scale1 * direction[0][0]) + point1[newoffset][0];
    point1[offset][1] = (scale1 * direction[0][1]) + point1[newoffset][1];

    if (flags != TEXTSTR){
      point2[offset][0] = (scale2 * direction[1][0]) + point2[newoffset][0];
      point2[offset][1] = (scale2 * direction[1][1]) + point2[newoffset][1];
    } else {
      point2[offset][0] = point1[offset][0] + TextLength(rp, TStr, TLen);
      point2[offset][1] = point1[offset][1];
    }
}

doteresa(offset)
int offset;
{
    register short x,y;

    x = (Scr->Width - TextLength(rp, TStr, TLen) - 20);
    y = (Scr->Height- Scr->RastPort.TxHeight - Scr->RastPort.TxBaseline - 8);

    if (x < 0 || y < 0)
	return;

    x = (x < point1[offset][0]) ? x : point1[offset][0];
    y = (y < point1[offset][1]) ? y : point1[offset][1];

    Move(rp, x, y);
    Text(rp, TStr, TLen);
}

doellipse(newoffset)
register int newoffset;
{
    register int tempx,tempy;

    tempx = (point2[newoffset][0] > point1[newoffset][0]) ?
	point2[newoffset][0] - point1[newoffset][0] :
	point1[newoffset][0] - point2[newoffset][0];

    tempy = (point2[newoffset][1] > point1[newoffset][1]) ?
	point2[newoffset][1] - point1[newoffset][1] :
	point1[newoffset][1] - point2[newoffset][1];

    tempx = (tempx > point1[newoffset][0]) ? point1[newoffset][0] :
	((tempx + point1[newoffset][0]) > BOUNDX) ? BOUNDX - point1[newoffset][0] :
	tempx;

    tempy = (tempy > point1[newoffset][1]) ? point1[newoffset][1] :
	((tempy + point1[newoffset][1]) > BOUNDY) ? BOUNDY - point1[newoffset][1] :
	tempy;

    tempx = (tempx > MAXELLIPSE) ? MAXELLIPSE : tempx;
    tempy = (tempy > MAXELLIPSE) ? MAXELLIPSE : tempy;

    if (tempx > 0 && tempy > 0)
	DrawEllipse(rp, point1[newoffset][0], point1[newoffset][1], tempx, tempy);
}

dobox(offset)
register int offset;
{
    register int tempx, tempy;

    Move(rp, point1[offset][0], point1[offset][1]);
    Draw(rp, point2[offset][0], point2[offset][1]);

    tempx = MAXX - point1[offset][0];
    tempy = MAXY - point1[offset][1];

    if (tempx >= 0 && tempy >= 0)
	Draw(rp, tempx, tempy);

    tempx = MAXX - point2[offset][0];
    tempy = MAXY - point2[offset][1];

    if (tempx >= 0 || tempy >= 0)
	Draw(rp, tempx, tempy);

    Draw(rp, point1[offset][0], point1[offset][1]);
}

long checkbounce1(index)
register int index;
{

    return (point1[index][0] >= BOUNDX) | (point1[index][1] >= BOUNDY) |
	    (point1[index][0] <= MINBOUND) | (point1[index][1] <= MINBOUND);
}

long checkbounce2(index)
register int index;
{
    return (point2[index][0] >= BOUNDX) | (point2[index][1] >= BOUNDY) |
	    (point2[index][0] <= MINBOUND) | (point2[index][1] <= MINBOUND);
}

int get_rand_point()
{
    register short temp;

    temp = ran();
    if (temp < 0)
	temp = temp * -1;
    temp = temp/319+19;

    return (temp > MAXY) ? MAXY : temp ;
}

int get_rand_dir()
{
    register short num;

    num = ran((short)3);

    return (num < -5000) ? -1 : (num > 5000) ? 1 : 0;
}

int get_rand_scale()
{
    register short temp;

    temp = ran();
    if (temp < 0)
	temp = temp * -1;
    temp = temp/6560 + (short)input;

    return (temp > 17) ? 17 : temp;
}

#define MAXPOINTS 5
#define FIX(x) (((long)(x)) << 7)

/*
 *   Draws a spline!  Expects all arguments in registers.
 */
#asm
	public	_Draw
	cseg
rspline
	move.l	a0,d0
	sub.l	d6,d0
	move.l	d0,d3
	bpl	save1
	neg.l	d0
save1
	move.l	a1,d1
	sub.l	d7,d1
	move.l	d1,d4
	bpl	save2
	neg.l	d1
save2
	move.l	d0,d2
	cmp.l	d0,d1
	bmi	save3
	lsr.l	#3,d2
	bra	save9
save3
	lsr.l	#3,d1
save9
	add.l	d1,d2
	asr.l	#3,d2
	asr.l	#5,d3
	asr.l	#5,d4
	move.l	a2,d0
	sub.l	a0,d0
	move.l	a3,d1
	sub.l	a1,d1
	asr.l	#5,d0
	asr.l	#5,d1
	muls.w	d4,d0
	muls.w	d3,d1
	sub.l	d1,d0
	bpl	save4
	neg.l	d0
save4
	cmp.l	d0,d2
	bmi	pushem
	move.l	a5,d0
	sub.l	a0,d0
	move.l	a6,d1
	sub.l	a1,d1
	asr.l	#5,d0
	asr.l	#5,d1
	muls.w	d4,d0
	muls.w	d3,d1
	sub.l	d1,d0
	bpl	save5
	neg.l	d0
save5
	cmp.l	d0,d2
	bmi	pushem
makeline
	lsr.l	#7,d7
	move.l	d7,-(sp)
	lsr.l	#7,d6
	move.l	d6,-(sp)
	move.l	_rp,-(sp)
	jsr	_Draw
	add.w	#12,a7
	rts
pushem
	movem.l d6/d7,-(sp)
	move.l	a5,d0
	add.l	d6,d0
	asr.l	#1,d0
	move.l	a6,d1
	add.l	d7,d1
	asr.l	#1,d1
	movem.l d0/d1,-(sp)
	move.l	a2,d2
	add.l	a5,d2
	asr.l	#1,d2
	move.l	a3,d3
	add.l	a6,d3
	asr.l	#1,d3
	move.l	d0,d4
	add.l	d2,d4
	asr.l	#1,d4
	move.l	d1,d5
	add.l	d3,d5
	asr.l	#1,d5
	movem.l d4/d5,-(sp)
	move.l	a0,d6
	add.l	a2,d6
	asr.l	#1,d6
	move.l	a1,d7
	add.l	a3,d7
	asr.l	#1,d7
	move.l	d2,d0
	add.l	d6,d0
	asr.l	#1,d0
	move.l	d3,d1
	add.l	d7,d1
	asr.l	#1,d1
	move.l	d6,a2
	move.l	d7,a3
	move.l	d0,d6
	add.l	d4,d6
	asr.l	#1,d6
	move.l	d1,d7
	add.l	d5,d7
	asr.l	#1,d7
	movem.l d6/d7,-(sp)
	move.l	d0,a5
	move.l	d1,a6
	jsr	rspline
	movem.l (sp)+,a0/a1
	movem.l (sp)+,a2/a3/a5/a6
	movem.l (sp)+,d6/d7
	bra	rspline
#endasm
/*
 *   Now our linkage to the spline routine.  Parameters are in 8(a5)...
 */
int drawspline(x1, y1, x2, y2, x3, y3, x4, y4)
long x1, y1, x2, y2, x3, y3, x4, y4 ;
{
#asm
	movem.l saver,-(sp)
	move.l	8(a5),a0
	move.l	12(a5),a1
	move.l	16(a5),a2
	move.l	20(a5),a3
	move.l	28(a5),a6
	move.l	32(a5),d6
	move.l	36(a5),d7
	move.l	24(a5),a5
	jsr	rspline
	movem.l (sp)+,saver
saver	reg	d0-d7/a0-a6
#endasm
}

/*
 *   Here we draw splines!  Magic, you know.
 */
dospline(index)
register int index;
{
    int index1;

    if (index == 0)
	index1 = maxlines;
    else
	index1 = index - 1;

    Move(rp, (long)(point1[index][0]), (long)(point1[index][1])) ;
    drawspline(FIX(point1[index][0]), FIX(point1[index][1]),
	      FIX(point2[index][1]), FIX(point2[index][1]),
	      FIX(point1[index1][0]), FIX(point1[index1][1]),
	      FIX(point2[index1][0]), FIX(point2[index1][1])) ;
}


