#if 0
#include <exec/types.h>
#include <graphics/gfx.h>
#include <graphics/display.h>
#include <graphics/gfxbase.h>
#include <libraries/dosextens.h>
#endif

#include "welcome.h"

struct AsyncFile *OpenAsync(char *name,long mode,long bufsize);
long CloseAsync(struct AsyncFile *afh);
long ReadAsync(struct AsyncFile *afh, void *buf,long bytes);

/* #define DEBUG */

#define ReadFileLong(a,b)		ReadFile(a,b,4L)

#define LEAVE goto exitit;

/* brushcon.c - converts a DeluxePaint brush to a bitmap array */

#define FORM	'FORM'
#define ILBM	'ILBM'
#define BMHD	'BMHD'
#define CMAP	'CMAP'
#define BODY	'BODY'
#define CAMG	'CAMG'

#define EVEN(x)		((x) + 1 & ~1)

void *unpack_row(void *,void *,long,long);
void bltbmap(struct BitMap *,LONG,LONG,struct BitMap *,LONG,LONG,LONG,LONG);

struct PicBuffer {
	void	*data;
	long	size;
	UBYTE	depth;
	UBYTE	masking;
	UBYTE	compression;
	UBYTE	pad;
};

long	file_length;
AFILE	myfile;
long	header;
long	blocklength;

long	CATsize;
long 	flength;
AFILE	CATfile;

LONG					lastcamg;				/* last loaded CAMG mode		*/

#define	cmpNone		0
#define	cmpByteRun1	1
#define	cmpVertRun	'V'
#define mskHasMask	1

typedef struct _BitMapHeader
{	short	width,height,xpic,ypic;
	UBYTE	nPlanes,masking,compression,pad1;
	short	transcolor;
	UBYTE	xAspect,yAspect;
	WORD	pageWidth,pageHeight;
} BitMapHeader;

BitMapHeader bmhd;

#define BMHDSIZE	sizeof(BitMapHeader)
#define CAMGSIZE	sizeof(LONG)

typedef struct {
	UBYTE		operation;
	UBYTE		mask;
	UWORD		w,h;
	UWORD		x,y;
	ULONG		abstime;
	ULONG		reltime;
	UBYTE		interleave;
	UBYTE		pad0;
	ULONG		bits;
} ANIMHdr;

typedef struct {
	unsigned char colors[32][3];
} ColorMap;

#define MAXCMAPSIZE		(32*3)
#define CMAPMAX			(32*3)

ColorMap cmap = {
	0x00,0x00,0x00,0xF0,0xF0,0xF0,0xF0,0x00,
	0x00,0x50,0x20,0x00,0x40,0x10,0x00,0x90,
	0x40,0x00,0xA0,0x30,0x00,0xF0,0x60,0x30,
	0xF0,0xA0,0x00,0x00,0xD0,0xD0,0x00,0xA0,
	0xF0,0x00,0x50,0xE0,0x00,0x00,0xD0,0x00,
	0x00,0x80,0xF0,0x00,0xF0,0xD0,0x60,0x50,
	0x60,0x20,0x00,0xC0,0x80,0x50,0x90,0x50,
	0x30,0xF0,0xC0,0xA0,0x30,0x30,0x30,0x40,
	0x40,0x40,0x10,0x50,0xA0,0x60,0x60,0x60,
	0x00,0xA0,0x00,0x90,0x80,0x80,0x00,0x60,
	0x00,0xF0,0xF0,0x00,0xB0,0xB0,0xB0,0x90,
	0x00,0x00,0x00,0xD0,0x00,0x00,0x80,0x00 };

/* ==================================================================== */
/*						Buffered Read Routines							*/
/* ==================================================================== */

#define BUFFERSIZE		1024

UBYTE					read_buffer[BUFFERSIZE];
UBYTE					*read_ptr,
						*endbuf_ptr;

	/* open the file and initialize the buffer */

AFILE OpenFile(char *name, int mode)
{	AFILE fh;

	read_ptr = endbuf_ptr = read_buffer;
	fh = Open(name,mode);
	if (!fh)
	{	putcon("Couldn't open file ");
		putcon(name);
		putcon("\n");
	}
/*	else Printf("%s\n",name); */
	return fh;
}

	/* read the file, buffered */

long ReadFile(AFILE fh, void *buffer, long size)
{	int					actual,
						final = 0;

	while (size > 0)							/* while data to be read		*/
	{	if (read_ptr < endbuf_ptr)				/* first read chars in buffer	*/
		{	int copysize =						/* calc size of data to be copied */
				clamp(0,size,endbuf_ptr - read_ptr);
			CopyMem(read_ptr,buffer,copysize);	/* copy the data				*/
			read_ptr += copysize;				/* add to read pointer			*/
			buffer = (UBYTE *)buffer + copysize;/* add to buffer pointer		*/
			final += copysize;					/* add to final size			*/
			size -= copysize;					/* subtract from size needed	*/
		}
		else if (size > BUFFERSIZE)				/* if a really big read			*/
		{	actual = Read(fh,buffer,size);		/* then read it directly		*/
			if (actual >= 0)					/* if we read data OK			*/
				return final + actual;			/* then return size read		*/
			else return actual;					/* else return the error		*/
		}
		else									/* else re-fill the buffer		*/
		{	actual = Read(fh,read_ptr = read_buffer,BUFFERSIZE);
			if (actual < 0) return actual;		/* if error, return it			*/
			endbuf_ptr = read_buffer + actual;
		}
	}
	return final;
}

	/* skip "size" bytes in the file, including the bytes in the buffer */

long SeekFile(AFILE fh, long size)
{	int					actual,
						final = 0;

	while (size > 0)							/* while data to be read		*/
	{	if (read_ptr < endbuf_ptr)				/* first read chars in buffer	*/
		{	int skipsize =						/* calc # chars in buffer to skip */
				clamp(0,size,endbuf_ptr - read_ptr);
			read_ptr += skipsize;				/* add size to read pointer		*/
			size -= skipsize;					/* subtract from skip size		*/
			final += skipsize;					/* add to final size			*/
		}
		else									/* else re-fill the buffer		*/
		{	actual = Read(fh,read_ptr = read_buffer,BUFFERSIZE);
			if (actual < 0) return actual;		/* if error, return it			*/
			endbuf_ptr = read_buffer + actual;	/* set buffer pointers			*/
		}
	}
	return final;
}
	

#ifdef DEBUG

LONG PackRow(BYTE *source, BYTE *dest, LONG rowSize);
WriteLong(AFILE fh, long value);
WritePad(AFILE fh);
WriteBitMap(AFILE fh, register struct BitMap *bm);
WriteBitMapCmp(AFILE fh, register struct BitMap *bm);
CalcBitMapCmp(register struct BitMap *bm);

BOOL SavePic(char *filename, struct BitMap *bm, UWORD *palette, WORD count)
{
	BitMapHeader		bmhd;
	ColorMap			cmap;
	long 				camg,
						sizeNone,
						sizeCmp1,
						sizeMin,
						temp;
	BOOL				result = FALSE;
	register UWORD		i;
	register AFILE		fh;

		/* set up BitMapHeader structure */

	bmhd.width = bm->BytesPerRow * 8;
	bmhd.height = bm->Rows;
	bmhd.pageWidth = 320;
	bmhd.pageHeight = 200;
	bmhd.xpic = bmhd.ypic = 0;
	bmhd.nPlanes = bm->Depth;
	bmhd.masking = bmhd.transcolor = 0;

		/* get aspect ratios right */

	bmhd.xAspect = 10;
	bmhd.yAspect = 11;

		/* make CAMG viewmodes chunk */

	camg = 0;

		/* create ColorMap */

	if (palette)
	{
		for (i=0;i<count;i++)
		{	cmap.colors[i][0] = (palette[i] & 0x0f00) >> 4;
			cmap.colors[i][1] = palette[i] & 0x00f0;
			cmap.colors[i][2] = (palette[i] & 0x000f) << 4;
		}
	}

		/* calc uncompressed size */

	sizeNone = (UWORD)(bm->BytesPerRow * bm->Depth) * bm->Rows;

		/* calc compressed size */

	sizeCmp1 = CalcBitMapCmp(bm);

	sizeMin = MIN(sizeNone,sizeCmp1);

	bmhd.compression = (sizeCmp1 < sizeNone ? cmpByteRun1 : cmpNone);

		/* start saving out file */

	fh = OpenFile(filename,MODE_NEWFILE);
	if (fh == NULL) goto error;

	if (!WriteLong(fh,FORM)) goto error;		/* write out FORM */

	temp = 4 + (8 + BMHDSIZE) + (8 + CAMGSIZE) + (8 + EVEN(sizeMin));
	if (palette) temp += 8 + EVEN(3 * count);
	if (!WriteLong(fh,temp)) goto error;		/* write out form size */

	if (!WriteLong(fh,ILBM)) goto error;		/* write out ILBM */

	if (!WriteLong(fh,BMHD)) goto error;		/* write out BMHD */
	if (!WriteLong(fh,BMHDSIZE)) goto error;	/* write out BMHDSIZE */
	if (Write(fh,&bmhd,BMHDSIZE) != BMHDSIZE)	/* write BitMapHeader */
		goto error;

	if (palette)
	{	if ( !WriteLong(fh,CMAP) ) goto error;			/* write out CMAP */
		temp = 3 * count;
		if ( !WriteLong(fh,temp) ) goto error;			/* write size */
		if ( Write(fh,&cmap,temp) != temp ) goto error;	/* write ColorMap */
		if (temp & 1) if ( !WritePad(fh) ) goto error;  /* possible pad */
	}

	if (!WriteLong(fh,CAMG)) goto error;		/* write out CAMG */
	if (!WriteLong(fh,CAMGSIZE)) goto error;	/* write out CAMGSIZE */
	if (Write(fh,&camg,CAMGSIZE) != CAMGSIZE)	/* write viewmodes */
		goto error;

	if (!WriteLong(fh,BODY)) goto error;		/* write out BODY */
	if (!WriteLong(fh,sizeMin)) goto error;		/* write out BODY size */
	if (sizeCmp1 < sizeNone)
	{		/* compressed image smaller */
		if (!WriteBitMapCmp(fh,bm)) goto error;
	}
	else
	{		/* uncompressed image bigger */
		if (!WriteBitMap(fh,bm)) goto error;
	}

	if (sizeMin & 1) if (!WritePad(fh)) goto error;		/* possible pad */
	result = TRUE;

error:
	if (fh) Close(fh);
	return result;		
}

WriteLong(AFILE fh,long value)
{	return ( Write(fh,&value,4) == 4 );
}

WritePad(AFILE fh)
{	short nil = 0;
	return ( Write(fh,&nil,1) == 1 );
}

WriteBitMap(AFILE fh,struct BitMap *bm)
{	PLANEPTR plane[12];
	register WORD i,j;

	for (i=0; i < bm->Depth; i++) plane[i] = bm->Planes[i];

	for (i=0;i<bm->Rows;i++)
		for (j=0;j<bm->Depth;j++)
	{	if (Write(fh,plane[j],bm->BytesPerRow) != bm->BytesPerRow) return 0;
		plane[j] += bm->BytesPerRow;
	}

	return 1;
}

WriteBitMapCmp(AFILE fh,struct BitMap *bm)
{	BYTE buf[256];
	PLANEPTR plane[12];
	long size;
	register WORD i,j;

	for (i=0; i < bm->Depth; i++) plane[i] = bm->Planes[i];

	for (i=0;i<bm->Rows;i++)
		for (j=0;j<bm->Depth;j++)
	{	size = PackRow((BYTE *)plane[j],(BYTE *)buf,bm->BytesPerRow);
		if (Write(fh,buf,size) != size) return 0;
		plane[j] += bm->BytesPerRow;
	}

	return 1;
}

CalcBitMapCmp(bm) register struct BitMap *bm;
{	BYTE buf[256];
	PLANEPTR plane[12];
	long size = 0;
	register WORD i,j;

	for (i=0; i < bm->Depth; i++) plane[i] = bm->Planes[i];

	for (i=0;i<bm->Rows;i++)
		for (j=0;j<bm->Depth;j++)
	{	size += PackRow((BYTE *)plane[j],(BYTE *)buf,bm->BytesPerRow);
		plane[j] += bm->BytesPerRow;
	}

	return size;
}

/*----------------------------------------------------------------------*
 * packer.c Convert data to "cmpByteRun1" run compression.     11/15/85
 *
 * By Jerry Morrison and Steve Shaw, Electronic Arts.
 * This software is in the public domain.
 *
 *	control bytes:
 *	 [0..127]   : followed by n+1 bytes of data.
 *	 [-1..-127] : followed by byte to be repeated (-n)+1 times.
 *	 -128       : NOOP.
 *
 * This version for the Commodore-Amiga computer.
 *----------------------------------------------------------------------*/

#define DUMP	0
#define RUN	1

#define MinRun 3	
#define MaxRun 128
#define MaxDat 128

#define GetByte()	(*source++)
#define PutByte(c)	{ *dest++ = (c); }

BYTE *PutDump(char *buf, BYTE *dest,  short nn)
{
	int i;

	PutByte(nn-1);
	for(i = 0;  i < nn;  i++)   PutByte(buf[i]);
	return(dest);
}

BYTE *PutRun(BYTE *dest,short nn,short cc)
{
	PutByte(-(nn-1));
	PutByte(cc);
	return(dest);
}

#define OutDump(nn)   dest = PutDump(buf, dest, nn)
#define OutRun(nn,cc) dest = PutRun(dest, nn, cc)

/*----------- PackRow --------------------------------------------------*/
/* Given POINTERS TO POINTERS, packs one row, updating the source and
   destination pointers.  RETURNs count of packed bytes.*/

LONG PackRow(source, dest, rowSize)
    BYTE *source, *dest;   LONG rowSize;
{
    char c,lastc = '\0';
    BOOL mode = DUMP;
    short nbuf = 0;		/* number of chars in buffer */
    short rstart = 0;		/* buffer index current run starts */
	char buf[256];
	BYTE *start = dest;

    buf[0] = lastc = c = GetByte();  /* so have valid lastc */
    nbuf = 1;
	rowSize--;	/* since one byte eaten.*/

    for (;  rowSize;  --rowSize) {
		buf[nbuf++] = c = GetByte();
		switch (mode) {
			case DUMP: 
			/* If the buffer is full, write the length byte,
				   then the data */
			if (nbuf > MaxDat) {
				OutDump(nbuf-1);  
				buf[0] = c; 
				nbuf = 1;
				rstart = 0; 
				break;
			}

			if (c == lastc) {
			    if (nbuf-rstart >= MinRun) {
					if (rstart > 0) OutDump(rstart);
					mode = RUN;
				}
			    else if (rstart == 0)
				mode = RUN;	/* no dump in progress,
					so can't lose by making these 2 a run.*/
			}
			else  rstart = nbuf-1;		/* first of run */ 
			break;

			case RUN:
			if ( (c != lastc)|| ( nbuf-rstart > MaxRun)) {
	    		/* output run */
	   			OutRun(nbuf-1-rstart,lastc);
	    		buf[0] = c;
		    	nbuf = 1; rstart = 0;
		    	mode = DUMP;
	    	}
			break;
		}

		lastc = c;
	}

    switch (mode) {
		case DUMP: OutDump(nbuf); break;
		case RUN: OutRun(nbuf-rstart,lastc); break;
	}

    return (dest - start);
}
#endif

ReadHeader()
{	ReadFile(myfile,(char *)(&header),4);
	file_length -= 4;
}

ReadLength()
{	ReadFile(myfile,(char *)(&blocklength),4);
	file_length = file_length - 4 - blocklength;
}

char	*plane0, *plane1, *plane2, *plane3, *plane4;
int		bytecount;
char	*packdata;
extern struct ViewPort *vport;

unpackpicform(struct BitMap *bitmap,UWORD *colors)
{	int		result = FALSE;
	int		i;
	char	*membuffer;

	if (myfile == NULL) return FALSE;

	ReadHeader();
	if (header != 'FORM') goto exit_it;
	ReadLength();
	flength = file_length = blocklength;

	ReadHeader();
	if (header != 'ILBM') goto exit_it;

	while (file_length)
	{	ReadHeader();
		ReadLength(); 

		switch (header)
		{	case BMHD:
			ReadFile(myfile,(char *)(&bmhd),blocklength);
			break;

			case 'CAMG':
			ReadFile(myfile,(char *)&lastcamg,4);
			break;

			case CMAP:
			if (blocklength > MAXCMAPSIZE)
			{	ReadFile(myfile,(char *)&cmap,MAXCMAPSIZE);
				SeekFile(myfile,blocklength-MAXCMAPSIZE);
				if (colors) UnpackCMAP(&cmap,colors,32);
			}
			else
			{	ReadFile(myfile,(char *)&cmap,blocklength);
				if (colors) UnpackCMAP(&cmap,colors,blocklength/3);
			}
			break;

			default:
			SeekFile(myfile,blocklength);
			break;

			case BODY:
			membuffer = (char *)AllocMem(blocklength,0);
			if (!membuffer) goto exit_it;

			ReadFile(myfile,membuffer,blocklength);
			result = ilbm2bm(&bmhd,(PLANEPTR)membuffer,bitmap);
			FreeMem(membuffer,blocklength);
			if (blocklength & 1) SeekFile(myfile,1L);
			goto exit_it;
		}

		if (blocklength & 1) { SeekFile(myfile,1L); file_length--; }
	}

exit_it:
	return result;
}

unpackpic(char *filename,struct BitMap *bitmap,UWORD *colors)
{	int		result;

	myfile = OpenFile(filename,MODE_OLDFILE);
	if (myfile == NULL) return FALSE;

	result = unpackpicform(bitmap,colors);

	Close(myfile);
	myfile = NULL;

	return result;
}


#if 0
AFILE OpenCat(char *name)
{
	myfile = CATfile = OpenFile(name,MODE_OLDFILE);
	if (CATfile == NULL) return NULL;

	ReadHeader();
	if (header != 'CAT ') goto exit_it;
	ReadLength();
	CATsize = blocklength;
	ReadHeader();			/* should by '    ', but don't really care... */
	return CATfile;

exit_it:
	Close(myfile);
	CATfile = NULL;
	return NULL;
}

void CloseCat(void)
{
	if (CATfile) { Close(CATfile); CATfile = NULL; }
}
#endif

#if 0
cat_unpackpic(struct BitMap *bitmap,UWORD *colors)
{	long	result;

	if ( !(myfile = CATfile) ) return NULL;

	if (CATsize <= 0)
	{	CloseCat();
		return NULL;
	}

	if (result = unpackpicform(bitmap,colors)) CATsize -= flength + 8;
	else CloseCat();

	return result;
}
#endif

struct BitMap *ResetAnim(struct AnimHandle *ahndl,UWORD mode)
{
	ahndl->mode = mode;
	ahndl->current = ahndl->first;
	ahndl->num = 0;
	ahndl->dir = 1;
	return &ahndl->current->bm;
}

struct BitMap *NextAnimFrame(struct AnimHandle *ahndl)
{
	switch (ahndl->mode)
	{	case ANIM_ONCE:		/* once */
		if (ahndl->num == ahndl->count - ahndl->interleave - 1) return NULL;
		ahndl->current = ahndl->current->next;
		ahndl->num++;
		break;

		case ANIM_PONG:		/* ping-pong */
		if (ahndl->dir == 1)
		{	if (ahndl->num < ahndl->count - ahndl->interleave)
			{
				ahndl->current = ahndl->current->next;
				ahndl->num++;
			}
			else
			{
				ahndl->current = ahndl->current->prev;
				ahndl->dir = -1;
				ahndl->num--;
			}
		}
		else
		{	if (ahndl->num == 0)
			{	
				ahndl->current = ahndl->current->next;
				ahndl->dir = 1;
				ahndl->num++;
			}
			else
			{
				ahndl->current = ahndl->current->prev;
				ahndl->num--;
			}
		}
		break;

		case 2:		/* continuous */
		if (ahndl->num < ahndl->count - ahndl->interleave - 1)
		{
			ahndl->current = ahndl->current->next;
			ahndl->num++;
		}
		else
		{
			ahndl->current = ahndl->first;
			ahndl->num = 0;
		}
		break;
	}

	return &ahndl->current->bm;
}

void FreeAnim(struct AnimHandle *ahndl)
{	struct AnimFrame	*next,
						*frame = ahndl->first;

	while (frame)
	{	next = frame->next;

		UnMakeBitMap(&frame->bm);
		FreeMem(frame,sizeof *frame);

		frame = next;
	}
}

	/* type 5 deltas only for now */

void adecomp_delta5(struct BitMap *bitmap,LONG width,UBYTE *buffer,LONG xormode);
#pragma regcall( adecomp_delta5(a0,d0,a1,d1) )

BOOL LoadAnim(struct AnimHandle *ahndl,char *name)
{	AFILE				file;
	ANIMHdr				ahdr;
	BitMapHeader		bmhd;
	ColorMap			cmap;
	WORD				colors;
	struct AnimFrame	*frame = NULL,
						*frame1, *frame2, *from;
	long				i, size, chkID,
						filelength, formlength, blocklength,
						length;
	void				*body = NULL;

	bmhd.nPlanes = 0;

	if (file = OpenFile(name,MODE_OLDFILE))
	{
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadFileLong(file,&filelength) < 4) LEAVE;
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'ANIM') LEAVE;

		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadFileLong(file,&formlength) < 4) LEAVE;
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'ILBM') LEAVE;

		filelength -= 16;
		formlength -= 4;
		if (formlength > filelength) LEAVE;

		while (formlength > 0)
		{
			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (ReadFileLong(file,&blocklength) < 4) LEAVE;

			switch (chkID)
			{	case 'BMHD':
				if (blocklength != BMHDSIZE) LEAVE;
				ReadFile(file,&bmhd,BMHDSIZE);
				break;

				case 'CMAP':
				i = blocklength;
				if (i > CMAPMAX) i = CMAPMAX;
				ReadFile(file,&cmap,i);
				colors = i / 3;
				UnpackCMAP(&cmap,ahndl->colors,colors);
				if (i < blocklength) SeekFile(file,blocklength-i);
				break;

				case 'BODY':
				if (bmhd.nPlanes == 0) LEAVE;

				if (body = AllocMem(blocklength,0))
				{
					frame = AllocMem(sizeof *frame,MEMF_CLEAR);
					if (frame == NULL) LEAVE;

					if (!MakeBitMap(&frame->bm,bmhd.nPlanes,bmhd.width,bmhd.height))
						LEAVE;

					if (ReadFile(file,body,blocklength) != blocklength) LEAVE;

					if (!ilbm2bm(&bmhd,(void *)body,&frame->bm)) LEAVE;

					ahndl->first = ahndl->current = frame;
					frame = NULL;

					FreeMem(body,blocklength);
					body = NULL;

					if (blocklength & 1) SeekFile(file,1);
					filelength -= blocklength + 9 & (~1);
					formlength -= blocklength + 9 & (~1);

					goto got_frame1;
				}
				LEAVE;

				default: SeekFile(file,blocklength); break;
			}

			if (blocklength & 1) SeekFile(file,1);
			filelength -= blocklength + 9 & (~1);
			formlength -= blocklength + 9 & (~1);
		}
		LEAVE;

got_frame1:

		ahndl->count = 1;
		ahndl->num = 0;

			/*	handle two cases: 1 or 2(0) interleave */
		frame1 = NULL;

		while (filelength > 0)
		{
			frame2 = frame1;
			frame1 = ahndl->current;

			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (chkID != 'FORM') LEAVE;

			if (ReadFileLong(file,&formlength) < 4) LEAVE;
			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (chkID != 'ILBM') LEAVE;

			filelength -= 12;
			formlength -= 4;
			if (formlength > filelength) LEAVE;

			while (formlength > 0)
			{
				if (ReadFileLong(file,&chkID) < 4) LEAVE;
				if (ReadFileLong(file,&blocklength) < 4) LEAVE;

				switch (chkID)
				{	case 'ANHD':
					if (blocklength < sizeof ahdr) LEAVE;
					ReadFile(file,&ahdr,sizeof ahdr);
					if (blocklength > sizeof ahdr)
						SeekFile(file,blocklength - sizeof ahdr);
					if (ahdr.interleave > 2) LEAVE;
					break;

					case 'DLTA':
					body = AllocMem(blocklength,0);
					if (body == NULL) LEAVE;

					from = (frame2 == NULL || ahdr.interleave == 1 ?
						frame1 : frame2);

					frame = AllocMem(sizeof *frame,MEMF_CLEAR);
					if (frame == NULL) LEAVE;

					if (!MakeBitMap(&frame->bm,bmhd.nPlanes,bmhd.width,bmhd.height))
						LEAVE;

					if (ReadFile(file,body,blocklength) != blocklength) LEAVE;

					BltBitMap(&from->bm,0,0,&frame->bm,0,0,bmhd.width,bmhd.height,
						0xc0,0xff,NULL);
					WaitBlit();

					adecomp_delta5(&frame->bm,bmhd.width,body,ahdr.bits & 2);

					FreeMem(body,blocklength);
					body = NULL;

					frame->prev = ahndl->current;
					ahndl->current->next = frame;
					ahndl->current = frame;
					ahndl->count++;
					break;

					default: SeekFile(file,blocklength); break;
				}

				if (blocklength & 1) SeekFile(file,1);
				filelength -= blocklength + 9 & (~1);
				formlength -= blocklength + 9 & (~1);
			}
		}

		ahndl->interleave = ahdr.interleave;
		if (ahndl->interleave == 0) ahndl->interleave = 2;

		ahndl->width = bmhd.width;

		Close(file);
		return TRUE;
	}

exitit:
	if (body) FreeMem(body,blocklength);
	if (frame)
	{	UnMakeBitMap(&frame->bm);
		FreeMem(frame,sizeof *frame);
	}
	if (file) Close(file);
	FreeAnim(ahndl);
	return FALSE;
}

void ResetCompAnim(struct CompAnimHandle *ahndl,struct BitMap *bm)
{
	ahndl->current = ahndl->first;
	ahndl->pass = 0;
#if 0
	BltBitMap(&ahndl->bm,0,0,bm,0,0,ahndl->width,ahndl->bm.Rows,0xc0,0xff,NULL);
	WaitBlit();
#endif
}

void NextCompFrame(struct CompAnimHandle *ahndl,struct BitMap *bm)
{
	if (ahndl->pass == 0)
	{
		BltBitMap(&ahndl->bm,0,0,bm,0,0,ahndl->width,ahndl->bm.Rows,0xc0,0xff,NULL);
		ahndl->pass = 1;
		WaitBlit();
	}
	else if (ahndl->current == NULL)
	{
		ahndl->current = ahndl->first->next;
	}

	adecomp_delta5(bm,ahndl->width,ahndl->current->data,ahndl->bits & 2);
	ahndl->current = ahndl->current->next;
}

void FreeCompAnim(struct CompAnimHandle *ahndl)
{	struct DeltaFrame	*next,
						*frame = ahndl->first;

	while (frame)
	{	next = frame->next;

		FreeMem(frame->data,frame->size);
		FreeMem(frame,sizeof *frame);

		frame = next;
	}

	/* UnMakeBitMap(&ahndl->bm); */
}

BOOL LoadCompAnim(struct CompAnimHandle *ahndl,char *name,struct BitMap *bm)
{	AFILE				file;
	ANIMHdr				ahdr;
	BitMapHeader		bmhd;
	ColorMap			cmap;
	WORD				colors;
	struct DeltaFrame	*frame = NULL;
	long				i, size, chkID,
						filelength, formlength, blocklength,
						length;
	void				*body = NULL;

	bmhd.nPlanes = 0;

	if (file = OpenFile(name,MODE_OLDFILE))
	{
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadFileLong(file,&filelength) < 4) LEAVE;
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'ANIM') LEAVE;

		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadFileLong(file,&formlength) < 4) LEAVE;
		if (ReadFileLong(file,&chkID) < 4) LEAVE;
		if (chkID != 'ILBM') LEAVE;

		filelength -= 16;
		formlength -= 4;
		if (formlength > filelength) LEAVE;

		while (formlength > 0)
		{
			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (ReadFileLong(file,&blocklength) < 4) LEAVE;

			switch (chkID)
			{	case 'BMHD':
				if (blocklength != BMHDSIZE) LEAVE;
				ReadFile(file,&bmhd,BMHDSIZE);
				break;

				case 'CMAP':
				i = blocklength;
				if (i > CMAPMAX) i = CMAPMAX;
				ReadFile(file,&cmap,i);
				colors = i / 3;
				UnpackCMAP(&cmap,ahndl->colors,colors);
				if (i < blocklength) SeekFile(file,blocklength-i);
				break;

				case 'BODY':
				if (bmhd.nPlanes == 0) LEAVE;

				if (body = AllocMem(blocklength,0))
				{
#if 0
					if (!MakeBitMap(&ahndl->bm,bmhd.nPlanes,bmhd.width,bmhd.height))
						LEAVE;
#endif
					ahndl->bm = *bm;

					if (ReadFile(file,body,blocklength) != blocklength) LEAVE;

					if (!ilbm2bm(&bmhd,(void *)body,&ahndl->bm)) LEAVE;

					ahndl->first = ahndl->current = NULL;

					FreeMem(body,blocklength);
					body = NULL;

					if (blocklength & 1) SeekFile(file,1);
					filelength -= blocklength + 9 & (~1);
					formlength -= blocklength + 9 & (~1);

					goto got_frame1;
				}
				LEAVE;

				default: SeekFile(file,blocklength); break;
			}

			if (blocklength & 1) SeekFile(file,1);
			filelength -= blocklength + 9 & (~1);
			formlength -= blocklength + 9 & (~1);
		}
		LEAVE;

got_frame1:

		ahndl->count = 1;

		while (filelength > 0)
		{
			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (chkID != 'FORM') LEAVE;

			if (ReadFileLong(file,&formlength) < 4) LEAVE;
			if (ReadFileLong(file,&chkID) < 4) LEAVE;
			if (chkID != 'ILBM') LEAVE;

			filelength -= 12;
			formlength -= 4;
			if (formlength > filelength) LEAVE;

			while (formlength > 0)
			{
				if (ReadFileLong(file,&chkID) < 4) LEAVE;
				if (ReadFileLong(file,&blocklength) < 4) LEAVE;

				switch (chkID)
				{	case 'ANHD':
					if (blocklength < sizeof ahdr) LEAVE;
					ReadFile(file,&ahdr,sizeof ahdr);
					if (blocklength > sizeof ahdr)
						SeekFile(file,blocklength - sizeof ahdr);
					if (ahdr.interleave > 2) LEAVE;
					break;

					case 'DLTA':
					body = AllocMem(blocklength,0);
					if (body == NULL) LEAVE;

					frame = AllocMem(sizeof *frame,MEMF_CLEAR);
					if (frame == NULL) LEAVE;

					if (ReadFile(file,body,blocklength) != blocklength) LEAVE;

					frame->data = body;
					frame->size = blocklength;
					if (ahndl->current) ahndl->current->next = frame;
					else ahndl->first = frame;
					ahndl->current = frame;
					ahndl->count++;

					frame = NULL;
					body = NULL;
					break;

					default: SeekFile(file,blocklength); break;
				}

				if (blocklength & 1) SeekFile(file,1);
				filelength -= blocklength + 9 & (~1);
				formlength -= blocklength + 9 & (~1);
			}
		}

		ahndl->interleave = ahdr.interleave;
		if (ahndl->interleave == 0) ahndl->interleave = 2;

		ahndl->width = bmhd.width;
		ahndl->bits = ahdr.bits;

		Close(file);
		return TRUE;
	}

exitit:
	if (body) FreeMem(body,blocklength);
	if (frame) FreeMem(frame,sizeof *frame);
	if (file) Close(file);
	FreeCompAnim(ahndl);
	return FALSE;
}

BOOL NextDiskFrame(struct DiskAnimHandle *ahndl,struct BitMap *bm)
{	struct AsyncFile	*file = ahndl->file;
	long				formlength, blocklength, chkID;
	ANIMHdr				ahdr;
	void				*body;

	if (ahndl->filelength == 0) return FALSE;

	if (ahndl->count == 0)
	{
		BltBitMap(&ahndl->bm,0,0,bm,0,0,ahndl->width,ahndl->bm.Rows,0xc0,0xff,NULL);
		WaitBlit();
		ahndl->count = 1;
		return TRUE;
	}

	if (ReadAsync(file,&chkID,4L) < 4L) LEAVE;
	if (chkID != 'FORM') LEAVE;

	if (ReadAsync(file,&formlength,4L) < 4L) LEAVE;
	if (ReadAsync(file,&chkID,4L) < 4L) LEAVE;
	if (chkID != 'ILBM') LEAVE;

	ahndl->filelength -= 12;
	formlength -= 4;
	if (formlength > ahndl->filelength) LEAVE;

	while (formlength > 0)
	{
		if (ReadAsync(file,&chkID,4L) < 4L) LEAVE;
		if (ReadAsync(file,&blocklength,4L) < 4L) LEAVE;

		switch (chkID)
		{	case 'ANHD':
			if (blocklength < sizeof ahdr) LEAVE;
			ReadAsync(file,&ahdr,sizeof ahdr);
			if (blocklength > sizeof ahdr)
				ReadAsync(file,NULL,blocklength - sizeof ahdr);
			if (ahdr.interleave > 2) LEAVE;

			ahndl->interleave = ahdr.interleave;
			if (ahndl->interleave == 0) ahndl->interleave = 2;
			ahndl->bits = ahdr.bits;
			break;

			case 'DLTA':
			body = AllocMem(blocklength,0);
			if (body == NULL) LEAVE;

			if (ReadAsync(file,body,blocklength) != blocklength) LEAVE;

			if (ahndl->count == 1)
			{
				BltBitMap(&ahndl->bm,0,0,bm,0,0,ahndl->width,ahndl->bm.Rows,0xc0,0xff,NULL);
				WaitBlit();
			}

			adecomp_delta5(bm,ahndl->width,body,ahndl->bits & 2);

			FreeMem(body,blocklength);

			if (blocklength & 1) ReadAsync(file,NULL,1);
			ahndl->filelength -= blocklength + 9 & (~1);
			formlength -= blocklength + 9 & (~1);

			ahndl->count++;
			return TRUE;

			default: ReadAsync(file,NULL,blocklength); break;
		}

		if (blocklength & 1) ReadAsync(file,NULL,1);
		ahndl->filelength -= blocklength + 9 & (~1);
		formlength -= blocklength + 9 & (~1);
	}

exitit:
	if (body) FreeMem(body,blocklength);
	return FALSE;
}

void FreeDiskAnim(struct DiskAnimHandle *ahndl)
{
	UnMakeBitMap(&ahndl->bm);
	if (ahndl->file) CloseAsync(ahndl->file);
}

BOOL LoadDiskAnim(struct DiskAnimHandle *ahndl,char *name)
{	struct AsyncFile	*file;
	BitMapHeader		bmhd;
	ColorMap			cmap;
	WORD				colors;
	long				i, size, chkID,
						formlength, blocklength;
	void				*body = NULL;

	bmhd.nPlanes = 0;

	if (file = OpenAsync(name,MODE_OLDFILE,16000L))
	{
		ahndl->file = file;

		if (ReadAsync(file,&chkID,4L) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadAsync(file,&ahndl->filelength,4L) < 4) LEAVE;
		if (ReadAsync(file,&chkID,4L) < 4) LEAVE;
		if (chkID != 'ANIM') LEAVE;

		if (ReadAsync(file,&chkID,4L) < 4) LEAVE;
		if (chkID != 'FORM') LEAVE;

		if (ReadAsync(file,&formlength,4L) < 4) LEAVE;
		if (ReadAsync(file,&chkID,4L) < 4) LEAVE;
		if (chkID != 'ILBM') LEAVE;

		ahndl->filelength -= 16;
		formlength -= 4;
		if (formlength > ahndl->filelength) LEAVE;

		while (formlength > 0)
		{
			if (ReadAsync(file,&chkID,4L) < 4) LEAVE;
			if (ReadAsync(file,&blocklength,4L) < 4) LEAVE;

			switch (chkID)
			{	case 'BMHD':
				if (blocklength != BMHDSIZE) LEAVE;
				ReadAsync(file,&bmhd,BMHDSIZE);
				break;

				case 'CMAP':
				i = blocklength;
				if (i > CMAPMAX) i = CMAPMAX;
				ReadAsync(file,&cmap,i);
				colors = i / 3;
				UnpackCMAP(&cmap,ahndl->colors,colors);
				if (i < blocklength) ReadAsync(file,NULL,blocklength-i);
				break;

				case 'BODY':
				if (bmhd.nPlanes == 0) LEAVE;

				if (body = AllocMem(blocklength,0))
				{
					if (!MakeBitMap(&ahndl->bm,bmhd.nPlanes,bmhd.width,bmhd.height))
						LEAVE;

					if (ReadAsync(file,body,blocklength) != blocklength) LEAVE;

					if (!ilbm2bm(&bmhd,(void *)body,&ahndl->bm)) LEAVE;

					FreeMem(body,blocklength);
					body = NULL;

					if (blocklength & 1) ReadAsync(file,NULL,1);
					ahndl->filelength -= blocklength + 9 & (~1);
					formlength -= blocklength + 9 & (~1);

					ahndl->count = 0;
					ahndl->width = bmhd.width;
					return TRUE;
				}
				LEAVE;

				default: ReadAsync(file,NULL,blocklength); break;
			}

			if (blocklength & 1) ReadAsync(file,NULL,1);
			ahndl->filelength -= blocklength + 9 & (~1);
			formlength -= blocklength + 9 & (~1);
		}
	}

exitit:
	if (body) FreeMem(body,blocklength);
	FreeDiskAnim(ahndl);
	return FALSE;
}

fade_palettes(UWORD *p1, UWORD *p2, int speed)
{	UWORD				temp_colors[32],
						count;
	long				i;

	count = vport->ColorMap->Count;

	for (i=0; i<0x10000; i += speed)
	{	InterpolateColors(p1,p2,temp_colors,count,i);
		LoadRGB4(vport,temp_colors,count);
		WaitTOF();
		WaitTOF();
	}
	LoadRGB4(vport,p2,count);
}

#if 0
fade_map(level) int level;
{	UWORD colors[32], red, green, blue, i, count;

	count = vport->ColorMap->Count;
	for (i=0;i<count;i++)
	{	red   = (level * cmap.colors[i][0])/(16*160);
		green = (level * cmap.colors[i][1])/(16*160);
		blue  = (level * cmap.colors[i][2])/(16*160);
		colors[i] = (red << 8) + (green << 4) + blue;
	}
	LoadRGB4(vport,colors,count);
}

void fade_palette(struct ViewPort *vp,UWORD *colors,int count,int level)
{	UWORD red, green, blue, i;
	UWORD hues[32];

	for (i=0; i < count; i++)
	{	red   = (level * (colors[i] >> 8 & 0x0f))/160;
		green = (level * (colors[i] >> 4 & 0x0f))/160;
		blue  = (level * (colors[i] & 0x0f))/160;
		hues[i] = (red << 8) + (green << 4) + blue;
	}
	LoadRGB4(vp,hues,count);
}

low_fade(level) int level;
{	UWORD colors[32];
	unsigned red, green, blue, i;

	for (i=0; i < 16; i++)
	{	red   = (level * cmap.colors[i][0])/(16*160);
		green = (level * cmap.colors[i][1])/(16*160);
		blue  = (level * cmap.colors[i][2])/(16*160);
		colors[i] = (red << 8) + (green << 4) + blue;
		colors[i+16] = (red << 8) + (green << 4) + blue;
	}
	LoadRGB4(vport,colors,32L);
}

high_fade(level) int level;
{	unsigned red, green, blue, i;
	for (i=0; i < 16; i++)
	{	red   = 15 - (level * (255 - cmap.colors[i][0]) ) / (16*160);
		green = 15 - (level * (255 - cmap.colors[i][1]) ) / (16*160);
		blue  = 15 - (level * (255 - cmap.colors[i][2]) ) / (16*160);
		SetRGB4(vport,i+16,red,green,blue);
	}
}
#endif

ilbm2bm(BitMapHeader *pic, PLANEPTR body, struct BitMap *bitmap)
{
	WORD i,j,a,h;
	WORD k,lwm;
	PLANEPTR plane[8],temp,mask = NULL,lbm = (PLANEPTR)&lwm;
 	LONG modulo,bytecount;

	bytecount = (pic->width + 15)/16 << 1; /* I guess... */
	lwm = 0xffff << 15 - (pic->width - 1 & 15);
	modulo = bitmap->BytesPerRow - bytecount;

	for (i=0; i < pic->nPlanes; i++) plane[i] = bitmap->Planes[i];
	h = (pic->height > bitmap->Rows ? bitmap->Rows : pic->height);
	k = (pic->compression == cmpVertRun ? bytecount : h);

	for (i=0; i < k; i++)
	{	
		for (j=0; j < pic->nPlanes; j++)
		{	
			switch (pic->compression)
			{	case cmpNone:
				for (a=0; a<bytecount; a++) *plane[j]++ = *body++;
				plane[j][-2] &= lbm[0];
				plane[j][-1] &= lbm[1];
				plane[j] += modulo;
				break;

				case cmpByteRun1:
				body = unpack_row(body,plane[j],bytecount,0L);
				plane[j] += bytecount;
				plane[j][-2] &= lbm[0];
				plane[j][-1] &= lbm[1];
				plane[j] += modulo;
				break;

				case cmpVertRun:
				body = unpack_row(body,plane[j],pic->height,
					bitmap->BytesPerRow-1);
				plane[j]++;
				break;

				default:
				return 0;
			}
		}
	}

	return 1;
}

/* ======================= New IFF Subs ================================== */

struct IFFPic *MakePicture(int width, int height, int depth, struct MinList *track)
{	struct IFFPic		*newpic;

	unless (newpic = AllocMem(sizeof *newpic,MEMF_CLEAR)) return FALSE;
	newpic->width = width;
	newpic->height = height;
	if (MakeBitMap(&newpic->bmap,depth,width,height))
	{	AddHead((struct List *)track,(struct Node *)newpic);
		return newpic;
	}
	
	FreeMem(newpic,sizeof *newpic);
	return NULL;
}

struct IFFPic *MakeMask(struct IFFPic *source, struct MinList *track)
{	struct IFFPic		*newpic;
	int i, j, size;

	unless (newpic = MakePicture(source->width,source->height,1,track)) return NULL;

	size = newpic->bmap.Rows * newpic->bmap.BytesPerRow;

	for (i=0; i<source->bmap.Depth; i++)
	{	char		*src, *dest;

		src = source->bmap.Planes[i];
		dest = newpic->bmap.Planes[0];

		if (i)
		{	for (j=0; j < size; j++) *dest++ |= *src++;
		}
		else
		{	for (j=0; j < size; j++) *dest++ = *src++;
		}
	}
	return newpic;
}

void InvertMask(struct IFFPic *pic)
{	int 				j, size;
	char				*dest;

	size = pic->bmap.Rows * pic->bmap.BytesPerRow;
	dest = pic->bmap.Planes[0];
	for (j=0; j < size; j++) { *dest = ~*dest; dest++; }
}

	/* gets a picture and allocates the planes for it, returns a structure
		which has the planes, the width, etc.
	*/

struct IFFPic *GetPictureForm(UWORD *colors, UWORD maxcolors, struct MinList *track)
{	int					i;
	ColorMap 			text_cmap;
	char				*membuffer;
	long				count;
	struct IFFPic		*newpic, *result=NULL;

	unless (newpic = AllocMem(sizeof *newpic,MEMF_CLEAR)) return FALSE;

	ReadHeader(); if (header != 'FORM') LEAVE;
	ReadLength(); flength = file_length = blocklength;
	ReadHeader(); if (header != 'ILBM') LEAVE;

	while (file_length)
	{	ReadHeader();
		ReadLength(); 

		switch (header)
		{	case 'BMHD':
			ReadFile(myfile,(char *)(&bmhd),blocklength);
			newpic->width = bmhd.width;
			newpic->height = bmhd.height;
			break;

			case 'CMAP':
			if (blocklength > MAXCMAPSIZE)
			{	ReadFile(myfile,(char *)&text_cmap,count = MAXCMAPSIZE);
				SeekFile(myfile,blocklength-MAXCMAPSIZE);
			}
			else ReadFile(myfile,(char *)&text_cmap,count = blocklength);
			if (colors) UnpackCMAP(&text_cmap,colors,MIN(count/3,maxcolors));
			break;

			default:
			SeekFile(myfile,blocklength);
			break;

			case 'CAMG':
			ReadFile(myfile,(char *)&lastcamg,4);
			break;

			case 'BODY':
			unless (membuffer = (char *)AllocMem(blocklength,0)) LEAVE;

			ReadFile(myfile,(char *)(membuffer),blocklength);
			if (MakeBitMap(&newpic->bmap,bmhd.nPlanes,bmhd.width,bmhd.height) &&
				ilbm2bm(&bmhd,(PLANEPTR)membuffer,&newpic->bmap) )
					result = newpic;
			FreeMem(membuffer,blocklength);
			if (blocklength & 1) SeekFile(myfile,1L);
			LEAVE;
		}

		if (blocklength & 1) { SeekFile(myfile,1L); file_length--; }
	}

exitit:
	if (newpic && !result)
	{	UnMakeBitMap(&newpic->bmap);
		FreeMem(newpic,sizeof *newpic);
	}
	else
	{	AddHead((struct List *)track,(struct Node *)newpic);
	}
	return result;
}

struct IFFPic *GetPicture(char *filename, UWORD *colors, UWORD maxcolors, struct MinList *track)
{	struct IFFPic		*result = NULL;

	unless (myfile = OpenFile(filename,MODE_OLDFILE)) return NULL;

	result = GetPictureForm(colors,maxcolors,track);

	Close(myfile);

	return result;
}

	/* frees the above object */

void FreePicture(struct IFFPic *pic)
{	if (pic)
	{	Remove((struct Node *)pic);
		UnMakeBitMap(&pic->bmap);
		FreeMem(pic,sizeof *pic);
	}
}

void FreePicList(struct MinList *l)
{	struct IFFPic		*pic;

	while (pic = (struct IFFPic *)RemHead((struct List *)l))
	{	UnMakeBitMap(&pic->bmap);
		FreeMem(pic, sizeof *pic);
	}
}

#if 0
struct IFFPic *CatGetPicture(UWORD *colors,UWORD maxcolors,struct MinList *track)
{	struct IFFPic	*result;

	if ( !(myfile = CATfile) ) return NULL;

	if (CATsize <= 0)
	{	CloseCat();
		return NULL;
	}

	if (result = GetPictureForm(colors,maxcolors,track)) CATsize -= flength + 8;
	else CloseCat();

	return result;
}
#endif

#asm

		include 'exec/types.i'
		include 'graphics/gfx.i'

		xdef	_decomp_delta5
		xdef	_adecomp_delta5

* register usage:
*	a0 - original bitmap pointer
*	d0 - real width if less than bitmap width
*	a1 - data buffer - used as delta data pointer
*	d1 - xormode flag
*	a2 - saved data buffer pointer
*	d2 - depth of bitmap
*	a3 - start of plane pointers
*	d3 - scratch
*	a4 - current plane pointer
*	d4 - width countdown
*	a5 - current data pointer
*	d5 - rows sanity check counter
*	a6 - column pointer
*	d6 - opcode counter
*	d7 - action counter

_decomp_delta5					; decomp_delta5(bitmap,width,buffer,xormode)
		move.l	4(sp),a0			; bitmap
		move.l	8(sp),d0			; width
		move.l	12(sp),a1			; buffer
		move.l	16(sp),d1			; xormode

_adecomp_delta5						; assemply language entry
		movem.l	a2-a6/d2-d7,-(sp)

		addq.w	#7,d0				; bytes = width + 7 >> 3
		lsr.w	#3,d0
		move.l	a1,a2				; buffer start saved
		lea		bm_Planes(a0),a3	; start of plane pointers
		moveq	#0,d2
		move.b	bm_Depth(a0),d2		; depth of bitmap
		bra.s	1$

2$		move.l	(a3)+,a4			; get a plane pointer
		move.l	(a1)+,d3			; get delta offset
		beq.s	1$					; if zero, skip plane

		move.l	a2,a5				; get buffer start
		add.l	d3,a5				; add delta

		move.w	d0,d4				; width count down
		bra.s	4$

5$		move.l	a4,a6				; start of column
		move.w	bm_Rows(a0),d5		; get # of rows to use as sanity check

		moveq	#0,d6
		move.b	(a5)+,d6			; get count
		bra.s	6$

7$		moveq	#0,d7
		move.b	(a5)+,d7			; get opcode
		beq.s	8$					; a RUN
		bmi.s	14$					; a DUMP

									; a SKIP
		sub.w	d7,d5				; rows_left = rows_left - total
		bmi.s	99$					; if rows_left < 0, error
		mulu.w	bm_BytesPerRow(a0),d7
		add.l	d7,a6				; adjust column pointer
		bra.s	6$

8$		move.b	(a5)+,d7			; get total
		move.b	(a5)+,d3			; run value
		sub.w	d7,d5				; rows_left = rows_left - total
		bmi.s	99$					; if rows_left < 0, error
		bra.s	13$

10$		tst.l	d1
		bne.s	11$
		move.b	d3,(a6)					; set a byte
		bra.s	12$
11$		eor.b	d3,(a6)					; eor a byte
12$		add.w	bm_BytesPerRow(a0),a6	; and increment to next byte

13$		dbra	d7,10$
		bra		6$

14$		bclr	#7,d7
		sub.w	d7,d5				; rows_left = rows_left - total
		bmi.s	99$					; if rows_left < 0, error
		bra.s	15$

16$		move.b	(a5)+,d3			; get a byte
		tst.l	d1
		bne.s	17$
		move.b	d3,(a6)					; set a byte
		bra.s	18$
17$		eor.b	d3,(a6)					; eor a byte
18$		add.w	bm_BytesPerRow(a0),a6	; and increment to next byte

15$		dbra	d7,16$

6$		dbra	d6,7$
		addq.w	#1,a4				; go to next column
4$		dbra	d4,5$

1$		dbra	d2,2$

99$		movem.l	(sp)+,a2-a6/d2-d7
		rts

;----------------------------------------------------------------
;	unpack_row(source,dest,count,modulo) - unpack a compressed byte stream
;		the number count is the expected destination size

		public _unpack_row
_unpack_row
		move.l	d2,-(sp)
		move.l	4+4(sp),a0			; source buffer
		move.l	8+4(sp),a1			; destination buffer
		move.l	12+4(sp),d0			; count of bytes
		move.l	16+4(sp),d2			; modulo
2$		moveq	#0,d1				; clear high bits
		move.b	(a0)+,d1			; get a byte
		cmp.b	#-128,d1			; is it a no-op?
		beq.s	3$					;   yes, skip ahead
		tst.b	d1					; is this a run?
		blt.s	4$					;	yes, so do as run
		addq.b	#1,d1				; was not a run, so bump value
		sub.l	d1,d0				; process d1 bytes
		bra.s	5$					; branch to dbra
6$		move.b	(a0)+,(a1)+			; copy byte
		add.l	d2,a1				; adjust by modulo
5$		dbra	d1,6$				; continue if bytes left
		bra.s	3$					; and skip to loop end
4$		neg.b	d1					; negate value
		addq.l	#1,d1				;   and increment
		sub.l	d1,d0				; process d1 bytes
		bra.s	7$					; branch to dbra
8$		move.b	(a0),(a1)+			; copy byte
		add.l	d2,a1				; adjust by modulo
7$		dbra	d1,8$				; continue if bytes left
		addq.l	#1,a0				; onto next byte
3$		tst.l	d0					; are all bytes processed
		bgt.s	2$					; no, so continue
		move.l	a0,d0				; return source pointer
		move.l	(sp)+,d2
		rts

#endasm
