/*  :ts=8 bk=0
 *
 * cycle.c:	Color cycling interrupt server and support.
 *
 * Leo L. Schwab			8710.6		(415) 456-3960
 */
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/interrupts.h>
#include <hardware/intbits.h>
#include <graphics/view.h>
#include "marketroid.h"

struct Interrupt	intr;
struct interdat		id;
static int		installed, opened;


struct cycle *
addcycle (type, ctab, ncolors, start, end, rate)
UWORD type;
UWORD *ctab;
WORD ncolors, start, end, rate;
{
	register struct cycle	*c;

	if (!(c = AllocMem ((long) sizeof (*c), MEMF_CLEAR)))
		die ("Cycle allocation failed.\n");

	c -> type	= type;
	c -> colors	= ctab;
	c -> ncolors	= ncolors;
	c -> start	= start;
	c -> end	= end;
	c -> rate = c -> count = rate;

	Disable ();
	AddHead (&id.cycles, c);
	Enable ();

	return (c);
}

removecycle (c)
register struct cycle *c;
{
	Disable ();
	Remove (c);
	FreeMem (c, (long) sizeof (*c));
	Enable ();
}


/*
 * And finally, the routine that does all the work.
 */
long
vblank ()
{
	register struct cycle	*c;
	register UWORD		*wp, *start;
	register UWORD		tmp;

	int_start ();

	if (id.stop)		/*  Are we stopped?  */
		goto xit;

	for (c = (struct cycle *) id.cycles.lh_Head;
	     c -> node.ln_Succ;
	     c = (struct cycle *) c -> node.ln_Succ)
		if (!--c->count) {
			/*  Countdown expired, do color cycle  */
			switch (c -> type) {
			case CYCLE_SIMPLE:
/*- - - - - - - - - - - - - - -*/
for (wp = &id.ctab[c->end], start = &id.ctab[c->start], tmp = *wp;
     wp != start;
     wp--)
	*wp = *(wp-1);
*wp = tmp;
/*- - - - - - - - - - - - - - -*/
				break;

			case CYCLE_THROUGH:
				if ((tmp = ++c->end) >= c->ncolors)
					tmp = c->end = 0;
				id.ctab[c->start] = c->colors[tmp];
				break;

			case CYCLE_RANDOM:
				if (*(wp = &id.ctab[c->start]) & 1) {
					tmp = rnd (8) + 8;
					*wp = tmp + (tmp<<4) + (tmp<<8);
				} else
					id.ctab[c->start] = rnd (0x1000);
				break;
			}
			c->count = c->rate;
		}

	LoadRGB4 (id.vp, id.ctab, (long) id.ncolors);
xit:
	int_end ();
	return (0L);
}

/*  Housekeeping  */
opencycle (vp, colors, ncolors)
struct ViewPort *vp;
UWORD *colors;
WORD ncolors;
{
	if (installed)
		return;		/*  Please don't install me twice  */

	NewList (&id.cycles);
	opened = 1;

	id.vp		= vp;
	id.ctab		= colors;
	id.ncolors	= ncolors;
	id.stop		= 0;

	intr.is_Node.ln_Type	= NT_INTERRUPT;
	intr.is_Node.ln_Pri	= 0;
	intr.is_Node.ln_Name	= "Cycling Routine";
	intr.is_Code		= (void *) vblank;
	intr.is_Data		= NULL;
	AddIntServer (INTB_VERTB, &intr);
	installed = 1;
}

closecycle ()
{
	register struct cycle	*c;

	if (installed) {
		RemIntServer (INTB_VERTB, &intr);
		installed = 0;
	}

	if (opened)
		while (c = RemHead (&id))
			FreeMem (c, (long) sizeof (*c));
}
