#include <intuition/intuition.h>
#include <exec/memory.h>

struct BitMap		*mybitmap[4];

STATIC struct BitMap	 bitmap2,bitmap3,bitmap4;
STATIC LONG		*DeltaData,mxDeltaData,nDeltaData;
STATIC LONG		 rastersize;

BYTE	AnimOpen(UBYTE *Name,struct ViewPort *VPort,struct RastPort *RPort);
BYTE	AnimAdd(struct RastPort *RPort);
VOID	AnimClose(VOID);

VOID	GenViewCopy(LONG sbuf,LONG nbuf);
VOID	FreeBitmaps(VOID);
BYTE	OpenBitmaps(LONG Width,LONG Height,LONG Depth);
BYTE	FormRIFF(LONG newbuf,LONG oldbuf);

BOOL	OpenAnim(LONG file,struct BitMap *bm,WORD pageW,WORD pageH,WORD *colorMap,ULONG modes,BYTE *buffer,LONG bufsize);
BOOL	AddAnim(struct BitMap *bm,WORD pageW,WORD pageH,WORD pop,BYTE *buffer,LONG bufsize);
BOOL	AddAnim2(LONG *data,LONG ndata,LONG pop);
BOOL	CloseAnim(LONG file);

BYTE	OpenAnimationFile(LONG nbuf,UBYTE *cc,struct ColorMap *cm,struct ViewPort *vp);
BYTE	AddAnimationFrame(LONG nbuf);
BYTE	AddAnimationFrame2(LONG *data,LONG ndata,LONG pop);
VOID	CloseAnimationFile(VOID);

WORD	skip_count_line(UBYTE *in,UBYTE *last_in,WORD count);
UBYTE *	skip_comp_plane(UBYTE *in,UBYTE *last_in,UBYTE *out,WORD next_line,WORD rows);

BYTE
AnimOpen(UBYTE *Name,struct ViewPort *VPort,struct RastPort *RPort)
{
	DeltaData = NULL;

	mybitmap[0] = RPort -> BitMap;

	if(OpenBitmaps(RPort -> BitMap -> BytesPerRow << 3,RPort -> BitMap -> Rows,RPort -> BitMap -> Depth))
	{
		GenViewCopy(0,1);
		GenViewCopy(1,2);

		if(OpenAnimationFile(1,Name,VPort -> ColorMap,VPort))
			return(TRUE);

		FreeBitmaps();
	}

	return(FALSE);
}

BYTE
AnimAdd(struct RastPort *RPort)
{
	mybitmap[0] = RPort -> BitMap;

	GenViewCopy(2,3);
	GenViewCopy(1,2);
	GenViewCopy(0,1);

	if(FormRIFF(1,3))
	{
		if(AddAnimationFrame2(DeltaData,nDeltaData,5))
		{
			if(DeltaData)
				FreeMem(DeltaData,nDeltaData);

			DeltaData = NULL;

			return(TRUE);
		}
	}

	if(DeltaData)
		FreeMem(DeltaData,nDeltaData);

	DeltaData = NULL;

	return(FALSE);
}

VOID
AnimClose()
{
	FreeBitmaps();

	CloseAnimationFile();
}

VOID
GenViewCopy(LONG sbuf,LONG nbuf)
{
	LONG ip,Size,Depth;

	Depth	= mybitmap[sbuf] -> Depth;
	Size	= mybitmap[sbuf] -> BytesPerRow * mybitmap[sbuf] -> Rows;

	for(ip = 0 ; ip < Depth ; ip++)
		CopyMem(mybitmap[sbuf] -> Planes[ip],mybitmap[nbuf] -> Planes[ip],Size);
}

VOID
FreeBitmaps()
{
	LONG i;

	if(DeltaData)
	{
		FreeMem(DeltaData,mxDeltaData);

		DeltaData = NULL;
	}

	for(i = 0 ; i < 6 ; i++)
	{
		if(bitmap2 . Planes[i])
		{
			FreeMem(bitmap2 . Planes[i],rastersize);

			bitmap2 . Planes[i] = NULL;
		}

		if(bitmap3 . Planes[i])
		{
			FreeMem(bitmap3 . Planes[i],rastersize);

			bitmap3 . Planes[i] = NULL;
		}

		if(bitmap4 . Planes[i])
		{
			FreeMem(bitmap4 . Planes[i],rastersize);

			bitmap4 . Planes[i] = NULL;
		}
	}
}

BYTE
OpenBitmaps(LONG Width,LONG Height,LONG Depth)
{
	LONG i;

	for(i = 0 ; i < 6 ; i++)
	{
		bitmap2 . Planes[i] = NULL;
		bitmap3 . Planes[i] = NULL;
		bitmap4 . Planes[i] = NULL;
	}

	InitBitMap(&bitmap2,Depth,Width,Height);

	rastersize = bitmap2 . BytesPerRow * bitmap2 . Rows;

	for(i = 0 ; i < Depth ; i++)
	{
		if(!(bitmap2 . Planes[i] = (PLANEPTR)AllocMem(rastersize,MEMF_PUBLIC|MEMF_CLEAR)))
			return(FALSE);
	}

	InitBitMap(&bitmap3,Depth,Width,Height);

	for(i = 0 ; i < Depth ; i++)
	{
		if(!(bitmap3 . Planes[i] = (PLANEPTR)AllocMem(rastersize,MEMF_PUBLIC|MEMF_CLEAR)))
			return(FALSE);
	}

	InitBitMap(&bitmap4,Depth,Width,Height);

	for(i = 0 ; i < Depth ; i++)
	{
		if(!(bitmap4 . Planes[i] = (PLANEPTR)AllocMem(rastersize,MEMF_PUBLIC|MEMF_CLEAR)))
			return(FALSE);
	}

	mybitmap[1] = &bitmap2;
	mybitmap[2] = &bitmap3;
	mybitmap[3] = &bitmap4;

	return(TRUE);
}

BYTE
FormRIFF(LONG newbuf,LONG oldbuf)
{
	UBYTE *outstuff;
	LONG j,jj[8],nBpP,ib,nb,i,nBpR,nRpP;
	UBYTE *skip_comp_plane();

	nBpR = mybitmap[newbuf]->BytesPerRow;
	nRpP = mybitmap[newbuf]->Rows;
	nBpP = nBpR * nRpP;

	j = 64;

	for(i = 0 ; i < mybitmap[newbuf] -> Depth ; i++)
	{
		nb = 0;

		for(ib = 0 ; ib < nBpP ; ib++)
			if(*(mybitmap[newbuf] -> Planes[i] + ib) != *(mybitmap[oldbuf] -> Planes[i] + ib))
				nb++;

		if(nb)
		{
			jj[i] = skip_count_plane(mybitmap[newbuf] -> Planes[i],mybitmap[oldbuf] -> Planes[i],nBpR,nRpP);

			j += jj[i];
		}
		else
			jj[i] = 0;
	}

	if(!(DeltaData = (LONG *)AllocMem(j,MEMF_PUBLIC|MEMF_CLEAR)))
		return(FALSE);

	mxDeltaData = j;

	outstuff = (UBYTE *)&DeltaData[16];

	for(i = 0 ; i < 16 ; i++)
		DeltaData[i] = 0;

	nDeltaData = 64;

	for(i = 0 ; i < mybitmap[newbuf] -> Depth ; i++)
	{
		if(jj[i])
		{
			DeltaData[i] = nDeltaData;

			nDeltaData += jj[i];

			outstuff = skip_comp_plane(mybitmap[newbuf] -> Planes[i],mybitmap[oldbuf] -> Planes[i],outstuff,nBpR,nRpP);
		}
		else
			DeltaData[i] = 0;
	}

	return(TRUE);
}
