/* putanim.c
 *   opens an animation iff file by outputing the starting
 *   bitmap.  Then successive change frames may be output
 *   followed by closing the file.
 *
 *   written by G. Bonham      May 1986
 *              SPARTA, Inc.
 *              Laguna Hills, Calif
 */

#include <intuition/intuitionbase.h>
#include <graphics/gfxbase.h>
#include <dos/dosextens.h>
#include <exec/memory.h>

#include <iff/iff.h>
#include <iff/ilbm.h>
#include <iff/gio.h>
#include <stdio.h>

typedef struct
{
	UBYTE	operation;	/* =5 for RIFF style */
	UBYTE	mask;
	UWORD	w,h;
	WORD	x,y;
	ULONG	abstime;	/* for timing w.r.t. start of anim file in jiffies (notused)*/
	ULONG	reltime;	/* for timing w.r.t. last frame in jiffies */
	UBYTE	interleave;	/* =0 for XORing to two frames back, =1 for last frame
				   (not used yet)  */
	UBYTE	pad0;
	ULONG	bits;
	UBYTE	pad[16];
} AnimationHeader;

#define BODY_BUFSIZE	512
#define MaxDepth	6

#define CkErr(exp) {if(ifferror == IFF_OKAY) ifferror = (exp);}

GroupContext fileC, form1C, form2C;

LONG Pop;

static IFFP ifferror = 0;

static UWORD bHw,bHh;
static WORD bHx,bHy;
 
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);
VOID	InitAnimHdr(AnimationHeader *aH,WORD op);

/* =================================================== */

BOOL
OpenAnim(LONG file,struct BitMap *bm,WORD pageW,WORD pageH,WORD *colorMap,ULONG modes,BYTE *buffer,LONG bufsize)
{
	UBYTE		depth;
	BitMapHeader	bmHdr;

	if((ifferror = InitBMHdr(&bmHdr,bm,(WORD)mskNone,(WORD)cmpByteRun1,0,pageW,pageH)) == IFF_OKAY)
	{
		if(bufsize > 2 * BODY_BUFSIZE)
		{
			if(GWriteDeclare(file,buffer + BODY_BUFSIZE,(long)(bufsize - BODY_BUFSIZE)) < 0)
				ifferror = DOS_ERROR;

			bufsize = BODY_BUFSIZE;
		}
	}

	depth = bm -> Depth;

	if(depth > MaxDepth)
		depth = MaxDepth;

	CkErr(OpenWIFF(file,&fileC,(long)szNotYetKnown));

	CkErr(StartWGroup(&fileC,(ID)FORM,(long)szNotYetKnown,ID_ANIM,&form1C));
	CkErr(StartWGroup(&form1C,(ID)FORM,(long)szNotYetKnown,ID_ILBM,&form2C));
	CkErr(PutCk(&form2C,ID_BMHD,(long)sizeof(BitMapHeader),(BYTE *)&bmHdr));

	if(colorMap)
		CkErr(PutCMAP(&form2C,colorMap,depth));

	CkErr(PutCk(&form2C,ID_CAMG,(long)sizeof(CamgChunk),(BYTE *)&modes));
	CkErr(PutBODY(&form2C,bm,(long)NULL,&bmHdr,buffer,(long)bufsize));
	CkErr(EndWGroup(&form2C));
	CkErr(CloseWGroup(&form1C));

	return((BOOL)(ifferror == IFF_OKAY));
}

BOOL
AddAnim(struct BitMap *bm,WORD pageW,WORD pageH,WORD pop,BYTE *buffer,LONG bufsize)
{
	AnimationHeader	animHdr;
	BitMapHeader	bmHdr;

	/* InitBMHdr sets w and h and x and y in bmHdr */

	Pop = pop;

	ifferror = InitBMHdr(&bmHdr,bm,(WORD)mskNone,(WORD)cmpByteRun1,0,pageW,pageH);

	bHx = bmHdr.x;
	bHy = bmHdr.y;
	bHw = bmHdr.w;
	bHh = bmHdr.h;

	InitAnimHdr(&animHdr,pop);

	CkErr(OpenWGroup(&fileC,&form1C));
	CkErr(StartWGroup(&form1C,(ID)FORM,(long)szNotYetKnown,ID_ILBM,&form2C));
	CkErr(PutCk(&form2C,ID_ANHD,(long)sizeof(AnimationHeader),(BYTE *)&animHdr));
	CkErr(PutBODY(&form2C,bm,(long)NULL,&bmHdr,buffer,(long)bufsize));
	CkErr(EndWGroup(&form2C));
	CkErr(CloseWGroup(&form1C));

	return((BOOL)(ifferror == IFF_OKAY));
}

BOOL
AddAnim2(LONG *data,LONG ndata,LONG pop)
{
	AnimationHeader animHdr;

	InitAnimHdr(&animHdr,pop);

	CkErr(OpenWGroup(&fileC,&form1C));
	CkErr(StartWGroup(&form1C,(ID)FORM,(long)szNotYetKnown,ID_ILBM,&form2C));
	CkErr(PutCk(&form2C,ID_ANHD,(long)sizeof(AnimationHeader),(BYTE *)&animHdr));
	CkErr(PutCk(&form2C,ID_DLTA,ndata,data));
	CkErr(EndWGroup(&form2C));
	CkErr(CloseWGroup(&form1C));

	return((BOOL)(ifferror == IFF_OKAY));
}

BOOL
CloseAnim(LONG file)
{
	Pop = 0;

	CkErr(PutCkEnd(&fileC));
	CkErr(CloseWGroup(&fileC));

	if(GWriteUndeclare(file) < 0 && ifferror == IFF_OKAY)
		ifferror = DOS_ERROR;

	return((BOOL)(ifferror == IFF_OKAY));
}

VOID
InitAnimHdr(AnimationHeader *aH,WORD op)
{
	memset(aH,0,sizeof(AnimationHeader));

	aH -> operation	= op;
}
