/* PlayAnim.c
 *
 * Load an ILBM raster image file from C structures in memory
 * into an existing bitmap (preloaded files from PreLoadAnim).
 *
 * Written by Gary Bonham, Sparta, Inc.  15 Aug 1986
 * Modified by Olaf `Olsen' Barthel, 16-Sep-1991
 *
 */

#include <libraries/dosextens.h>
#include <intuition/intuition.h>

#include "ilbm.h"
#include "preloadanim.h"

#define UGetByte()	(*source++)
#define UPutByte(c)	(*dest++ = (c))

extern BYTE		 CheckAbort();

extern VOID		 FrameSetup(ULONG jiffies);
extern VOID		 FrameSync(VOID);
extern VOID		 SwapBits(VOID);
extern VOID		 CopyBits(VOID);
extern VOID		 LoadPalette(UWORD *Palette);
extern VOID __asm	 decode_vkplane(register __a0 UBYTE *deltabyte,register __a2 PLANEPTR plane,register __d2 UWORD bytesperrow);

STATIC VOID __regargs	 UnPackRow(BYTE **pSource,BYTE **pDest,WORD srcBytes0,WORD dstBytes0);
STATIC VOID __regargs	 SetRIFF(struct BitMap *bm,struct FrameHD *cfr);
STATIC VOID __regargs	 SetBODY(struct BitMap *bm,struct FrameHD *cfr);
BYTE			 PlayAnim(VOID);

extern struct IFFfile	*IFFfileList;
extern struct BitMap	*DrawBitMap;
STATIC BitMapHeader	 masterbmhd;

STATIC VOID __regargs
UnPackRow(BYTE **pSource,BYTE **pDest,WORD srcBytes0,WORD dstBytes0)
{
	BYTE	*source		= *pSource,
		*dest		= *pDest,c;
	WORD	n,
		srcBytes	= srcBytes0,
		dstBytes	= dstBytes0;
		
	while(dstBytes > 0)
	{
		if((--srcBytes) < 0)
			break;

		if((n = UGetByte()) >= 0)
		{
			n++;

			if((srcBytes -= n) < 0)
				break;

			if((dstBytes -= n) < 0)
				break;

			do
				UPutByte(UGetByte());
			while(--n);
		}
		else
		{
			if(n != (WORD)(-128))	/* compiler generates a cmp.w! */
			{
				n = -n + 1;

				if((--srcBytes) < 0)
					break;

				if((dstBytes -= n) < 0)
					break;

				c = UGetByte();

				do
					UPutByte(c);
				while(--n);
			}
		}
	}

	*pSource	= source;
	*pDest		= dest;
}

STATIC VOID __regargs
SetRIFF(struct BitMap *bm,struct FrameHD *cfr)
{
	UBYTE	*deltabyte;
	LONG	*deltadata;
	int	 i;

	deltadata = (LONG *)cfr -> body;

	for(i = 0 ; i < bm -> Depth ; i++)
	{
		if(deltadata[i])
		{
			deltabyte = (UBYTE *)deltadata + deltadata[i];

			decode_vkplane(deltabyte,bm -> Planes[i],bm -> BytesPerRow);
		}
	}
}

STATIC VOID __regargs
SetBODY(struct BitMap *bm,struct FrameHD *cfr)
{
	LONG	 x,y,deltabyte,i,irow,ip;
	BYTE	*planes[9],*ss,**dd;
	WORD 	 srcRowBytes,w,h;
	UBYTE	 mask;

	if(cfr -> anhd)
	{
		w = cfr -> anhd -> w;
		h = cfr -> anhd -> h;
		x = cfr -> anhd -> x;
		y = cfr -> anhd -> y;

		mask = cfr -> anhd -> mask;
	}
	else
	{
		w = cfr -> bmhd -> w;
		h = cfr -> bmhd -> h;
		x = cfr -> bmhd -> x;
		y = cfr -> bmhd -> y;

		mask = 0xFF;
	}

	srcRowBytes	= RowBytes(w);
	deltabyte	= (masterbmhd . pageWidth >> 3) - (w >> 3);

	/* assume cmpByteRun1 data compression */

	for(i = 0 ; i < masterbmhd . nPlanes ; i++)
	{
		if((mask >> i) & 1)
			planes[i] = (BYTE *)bm -> Planes[i] + y * bm -> BytesPerRow + (x >> 3);
		else
			planes[i] = NULL;
	}

	ss = (BYTE *)cfr -> body;

	for(irow = h ; irow > 0 ; irow--)
	{
		for(ip = 0 ; ip < masterbmhd . nPlanes ; ip++)
		{
			if(planes[ip])
			{
				dd = &planes[ip];

				UnPackRow(&ss,dd,10000,srcRowBytes);

				planes[ip] += deltabyte;
			}
		}
	}
}

BYTE
PlayAnim()
{
	struct FrameHD	*currentframe	= IFFfileList -> firstframe;
	BYTE		 firstframe	= TRUE;
	ULONG		 FrameSkip	= 0;
	UBYTE		 Pop		= 0;

	while(currentframe)
	{
		if(firstframe)
		{
			if(currentframe -> bmhd)
				masterbmhd = *currentframe -> bmhd;
		}
		else
		{
			if(currentframe -> bmhd)
				masterbmhd = *currentframe -> bmhd;
		}

		if(currentframe -> anhd)
		{
			Pop		= currentframe -> anhd -> operation;
			FrameSkip	= currentframe -> anhd -> reltime;
		}

		if(currentframe -> nColorRegs)
			LoadPalette(currentframe->cmap);

		if(FrameSkip)
		{
			FrameSetup(FrameSkip);

			FrameSkip = 0;

			if(Pop >= 2)
			{
				if(currentframe -> body)
				{
					if(Pop == 5)
						SetRIFF(DrawBitMap,currentframe);
				}
			}
			else
			{
				if(currentframe -> body)
					SetBODY(DrawBitMap,currentframe);
			}

			FrameSync();
		}
		else
		{
			if(Pop >= 2)
			{
				if(currentframe -> body)
				{
					if(Pop == 5)
						SetRIFF(DrawBitMap,currentframe);
				}
			}
			else
			{
				if(currentframe -> body)
					SetBODY(DrawBitMap,currentframe);
			}
		}

		SwapBits();

		if(CheckAbort())
			return(FALSE);

		if(firstframe)
		{
			CopyBits();

			firstframe = FALSE;
		}

		if(currentframe)
			currentframe = currentframe -> next;
	}

	return(TRUE);
}
