
/*
**
**		$VER: fade.c 1.0 (19.02.96)
**
**		Flexible fade module for ViewPorts
**
**		written by Grzegorz Calkowski
**
**		(c) 1996 The Beet Research
**			 All Rights Reserved
**
**		Source history:
**
**		1.0 (19.02.96)
**
**			- first version
**
*/

#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/view.h>

#include <other/fadeinfo.h>

#define __USE_SYSBASE
#include <proto/exec.h>
#include <proto/graphics.h>

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

/* local protos */

void FreeFade(struct FadeInfo *fadeinfo);


/* protos for fadeasm.s */

void __asm FadeStep(register __a0 WORD *, register __a1 WORD *,
						  register __a2 ULONG *, register __d0 WORD);

void __asm FadeEnd(register __a0 UBYTE *, register __a1 ULONG *, register __d0 WORD);

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

struct FadeInfo *InitFade(struct ViewPort *vp, ULONG *destcolors, WORD ncolors, WORD rate)
{
	struct FadeInfo *fadeinfo;
	WORD	 i, src, dest;
	WORD	 guns = ncolors * 3;

	if (!vp || !ncolors)
		return NULL;

	/* alloc the FadeInfo struct */
	if (!(fadeinfo = AllocMem(sizeof(struct FadeInfo), MEMF_PUBLIC | MEMF_CLEAR)))
		return NULL;

	/* alloc array for deltas */ 
	if (!(fadeinfo->deltas = AllocVec(guns << 1, MEMF_PUBLIC)))
		goto bailoff;

	/* alloc "working" array */
	if (!(fadeinfo->work = AllocVec(guns << 1, MEMF_PUBLIC)))
		goto bailoff;

	/* alloc tmp array for colorrecord (as passed to LoadRGB32()) */
	if (!(fadeinfo->colorrecord = AllocVec((guns << 2) + 8, MEMF_PUBLIC)))
		goto bailoff;

	/* alloc array for copy of the target colors */
	if (!(fadeinfo->dest = AllocVec(guns, MEMF_PUBLIC)))
		goto bailoff;

	fadeinfo->colortable = (ULONG *)fadeinfo->colorrecord + 1;
	fadeinfo->ncolors = ncolors;
	fadeinfo->guns = guns;
	fadeinfo->cnt = rate;

	/* init the colorrecord */
	fadeinfo->colorrecord[0] = ncolors;
	fadeinfo->colorrecord[1] = 0;
	fadeinfo->colortable[guns] = 0;

	/* we'll use this vp */
	fadeinfo->vp = vp;

	/* get actual colors to colorrecord's table - temporarily */
	GetRGB32(vp->ColorMap, 0, ncolors, fadeinfo->colortable);

	/* init arrays */
	for (i=0; i < guns; i++)
	{
		/* source color */
		src = (WORD)*(UBYTE *)&fadeinfo->colortable[i];
		/* target color */
		dest = (WORD)(*(UBYTE *)&destcolors[i]);

		/* compute start value */
		fadeinfo->work[i] = src << 7;

		/* compute delta for given rate */
		fadeinfo->deltas[i] = ((dest - src) << 7) / rate;

		/* store target color */
		fadeinfo->dest[i] = (UBYTE)dest;
	}

	return fadeinfo; /* ok */

	bailoff:
	FreeFade(fadeinfo);
	return NULL;
}

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

void FreeFade(struct FadeInfo *fadeinfo)
{
	APTR	tmp;

	/* free what we've allocated */
	if (fadeinfo)
	{
		if (tmp = fadeinfo->deltas)
		{
			FreeVec(tmp);

			if (tmp = fadeinfo->work)
			{
				FreeVec(tmp);

				if (tmp = fadeinfo->colorrecord)
				{
					FreeVec(tmp);

					if (tmp = fadeinfo->dest)
						FreeVec(tmp);
				}
			}
		}
		FreeMem(fadeinfo, sizeof(struct FadeInfo));
	}
}

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

BOOL Fade(struct FadeInfo *fadeinfo)
{
	BOOL	 done;

	/* if no fadeinfo (bad!) we gonna better tell that we've finished */
	if (!fadeinfo)
		done = TRUE;
	else
	{
		/* during 'cnt steps call FadeStep() */
		if (fadeinfo->cnt--)
		{
			FadeStep(fadeinfo->deltas, fadeinfo->work, fadeinfo->colortable, fadeinfo->guns);
			done = FALSE;
		}
		else
		/* and at last call FadeEnd() to set real target colors
			(as stored in fadeinfo->dest) */
		{
			FadeEnd(fadeinfo->dest, fadeinfo->colortable, fadeinfo->guns);
			done = TRUE;
		}

		/* load them */
		LoadRGB32(fadeinfo->vp, (ULONG *)fadeinfo->colorrecord);
	}

	return done;
}


