/*
	NAME	SavePubScreen256 - find the given (public-)screen and save it to a file.

>>>	WHY FOR GOD'S SAKE A ``NEW'' SAVER ?

	ADVANTAGES

	- this one handles big screens, 1280x1024x8 is *NO*
	  problem ( if you have enough HD space, ofcourse )

	- this one could handle 256 colors (8bit)

	DISADVANTAGES

	- this one could **ONLY** handle 256 colors (8bit)

	- its neither fast in chunky->planar converting nor 
	  has it fast buffered file i/o. this one is only
	  functional NOT efficient.
	
	- because of its slowlyness the grabber freezes the
	  publicscreen via a global ILock().
	  this could cause system damage in several cases.

	EXAMPLE USAGE
	
	SavePubScreen256 FILE Media:Pictures/Workbench/today.IFF PUBSCREEN Workbench
	PackIFF FILE Media:Pictures/Workbench/today.IFF COMPRESSION 1 [*]
	
								[*] not included in this package

	COPYRIGHT NOTICE AND AUTHOR

	this program was written by
	
>>>	dbalster@uni-paderborn.de (Daniel Balster)

	just finger me and my .plan tells you WHERE i am
	right now. <try out one of the following computers:
	elba,hawaii,jamaika,...,london,madrid,...,donald,
	dagobert,daisy,... etc.>
	
	DISCLAIMER
	
	if you dislike this program and its agreements
	DO NOT USE it. i will not be responsible for any
	kind of damage the usage of this program will
	cause. this could be a massive dataloss if this
	program fails, be warned. (i never experienced
	this case, anyhow)

	MARKETING AND SPREADING	NOTICE
	
	this source is limited freeware, this means:
	
	- it is allowed to change portions of the sourcecode to
	  fit personal purposes
	
	- it is allowed to reuse portions of the sourcecode in
	  personal applications
	  
	- if you reuse portions of the sourcecode and your application
	  is going to be published under the concepts of freeware,giftware,
	  etc. everything is ok if you put it onto archives like aminet.
	
	- if you reuse portions of the sourcecode and your application
	  is going to be published under the concepts of shareware,testware,
	  etc. you must give me a registered copy, i will send you a request.

	- any commercial usage is not prohibited - i will send you a request
	  to get a free copy of your program.

	- if you put this program on some kind of compilation archived media
	  like DISKs, CDs, TAPEs or ROMs you MUST send me a copy on request.
	  important note: i know aminet offers this service - i don't want
	  a CD for this little hack - i will upload better programs (which are
	  already forming). ALL others (mainly ripping their packages out of
	  the aminet) HAVE TO send me a ``freebie''.

	sorry for this std disclaimer... 
*/

#include <string.h>

#include <exec/exec.h>
#include <dos/dos.h>
#include <intuition/intuition.h>
#include <datatypes/pictureclass.h>
#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/intuition.h>
#include <proto/graphics.h>

#define DOSTEMPLATE "FILE/A,PUBSCREEN/A"

struct {
	STRPTR	file;
	STRPTR	pubscreen;
	ULONG	pad[14];
} args;

BPTR file;

ULONG iffsize;

BOOL writeBODY (struct Screen *scr)
{
	int i,j,k;
	UBYTE *line,*zeile;
	struct RastPort *rp, tmprp;
	struct BitMap *bmp;
	BOOL erg=FALSE;
	struct Layer_Info *li;

	rp = &(scr->RastPort);

	li = &scr->LayerInfo;
	LockLayers(li);

	if(bmp = AllocBitMap(scr->Width,1,8,0,NULL))
	{

	CopyMem(rp,&tmprp,sizeof(struct RastPort));
	tmprp.Layer = NULL;
	tmprp.BitMap = bmp;
	
	/* ich glaube nicht das jemand einen 777x555 Screen hat, also
	   gehe ich immer von 8-teilbaren Breiten aus */
	
	if(zeile = AllocVec (scr->Width/8,MEMF_PUBLIC|MEMF_CLEAR))
	{
	if(line = AllocVec (scr->Width,MEMF_PUBLIC))
	{
		ULONG sizeBODY = scr->Width*scr->Height;

		Write(file,"BODY",4);
		Write(file,&(sizeBODY),4);

		for (i=0;i<scr->Height;i++)
		{
			/* mit readpixel umgeht man das ätzende poken */
			/* ausserdem bleibe ich gfxcard-unabhängig */
			/* und man kann sogar amiga-aa screens damit speichern */
		
			ReadPixelArray8(rp,0,i,scr->Width-1,i,line,&tmprp);
			
			/* den folgenden teil bitte überlesen... ;( */
			/* ich hatte keine lust/zeit einen effizienteren */
			/* chunky2planar algorithmus hier einzubauen, ausserdem */
			/* fehlt das packing usw. das stück ``algorithmus'' ist */
			/* in wenigen minuten entstanden und scheint zu funktionieren */
			
			for (k=7;k>-1;k--)
			{
				UBYTE mask = 128>>k;
			
				memset(zeile,0,scr->Width/8);
			
				for (j=0;j<scr->Width;j++)	/* for each bit... */
				{
					if (line[j] & mask)
					{
						zeile[j/8] |= (128>>(j%8));
					}
				}
				Write(file,zeile,scr->Width/8);
			}
			
			erg=TRUE;
		}
		
		iffsize += 8 + sizeBODY;

		FreeVec(line);
	}
	else PutStr("could not allocate memory for a temporary line #1\n");

		FreeVec(zeile);
	}
	else PutStr("could not allocate memory for a temporary line #2\n");
	
		FreeBitMap(bmp);
	}
	else PutStr("could not allocate memory for a temporary BitMap\n");

	UnlockLayers(li);

	return erg;
}

BOOL writeANNO (VOID)
{
	UBYTE *string =	"File was written by ChunkyScreenSaver V1.0 \n";
	ULONG sizeANNO = strlen(string);

	if(Write(file,"ANNO",4)!=4)goto ANNOerror;
	if(Write(file,&(sizeANNO),4)!=4)goto ANNOerror;
	if(Write(file,string,sizeANNO)!=sizeANNO)goto ANNOerror;

	iffsize += 8 + sizeANNO;

	return TRUE;
ANNOerror:
	return FALSE;
}

BOOL writeCAMG (struct Screen *scr)
{
	ULONG sizeCAMG = 4, CAMG = 0;

	if(Write(file,"CAMG",4)!=4)goto CAMGerror;
	if(Write(file,&(sizeCAMG),4)!=4)goto CAMGerror;
	if(Write(file,&(CAMG),4)!=4)goto CAMGerror;
	
	iffsize += 8 + sizeCAMG;
	
	return TRUE;
CAMGerror:	
	return FALSE;
}

BOOL writeCMAP (struct Screen *scr)
{
	int i;
	ULONG sizeCMAP = 256*3;
	ULONG table[256*3];
	UBYTE red,green,blue;

	Write(file,"CMAP",4);
	Write(file,&(sizeCMAP),4);

	GetRGB32(scr->ViewPort.ColorMap,0,256,(ULONG*)&(table));

	for (i=0;i<256;i++) /* save 256 color image... */
	{
		red	= table[(i*3)+0] >> 24;
		green	= table[(i*3)+1] >> 24;
		blue	= table[(i*3)+2] >> 24;
		
		if (Write(file,&(red),1)!=1) goto CMAPerror;
		if (Write(file,&(green),1)!=1) goto CMAPerror;
		if (Write(file,&(blue),1)!=1) goto CMAPerror;
	}

	iffsize += 8 + sizeCMAP;

	return TRUE;

CMAPerror:
	return FALSE;
}

BOOL writeBMHD (struct Screen *scr)
{
	struct BitMapHeader BMHD;
	ULONG sizeBMHD = sizeof(struct BitMapHeader);

	BMHD.bmh_Width		=	scr->Width;
	BMHD.bmh_Height		=	scr->Height;
	BMHD.bmh_Left		=	0;
	BMHD.bmh_Top		=	0;
	BMHD.bmh_Depth		=	8;
	BMHD.bmh_Masking	=	mskNone;
	BMHD.bmh_Compression	=	cmpNone;
	BMHD.bmh_Pad		=	0;
	BMHD.bmh_Transparent	=	0;
	BMHD.bmh_XAspect	=	0;
	BMHD.bmh_YAspect	=	0;
	BMHD.bmh_PageWidth	=	scr->Width;
	BMHD.bmh_PageHeight	=	scr->Height;

	if(Write(file,"BMHD",4)!=4) goto BMHDerror;
	if(Write(file,&(sizeBMHD),4)!=4) goto BMHDerror;
	if(Write(file,&(BMHD),sizeof(struct BitMapHeader))!=sizeof(struct BitMapHeader)) goto BMHDerror;

	iffsize += 8 + sizeBMHD;

	return TRUE;

BMHDerror:
	return FALSE;
}

BOOL writeFORM (VOID)
{
	iffsize = 4;

	if(Write(file,"FORM",4)!=4)goto FORMerror;
	if(Write(file,&(iffsize),4)!=4)goto FORMerror;
	if(Write(file,"ILBM",4)!=4)goto FORMerror;

	return TRUE;
FORMerror:	
	return FALSE;
}

int main (void)
{
	struct Screen *scr;
	struct RDArgs *rdargs;

	if (rdargs = ReadArgs ((UBYTE*)DOSTEMPLATE,(LONG*)&args,NULL))
	{
		if (file = Open(args.file,MODE_NEWFILE))
		{
			if (scr = LockPubScreen(args.pubscreen))
			{
				if (writeFORM())
				if (writeBMHD(scr))
				if (writeCMAP(scr))
				if (writeCAMG(scr))
				if (writeANNO())
				if (writeBODY(scr)) { /* beep ? */ }
				else PutStr("BODY error\n");
				else PutStr("ANNO error\n");
				else PutStr("CAMG error\n");
				else PutStr("CMAP error\n");
				else PutStr("BMHD error\n");
				else PutStr("FORM error\n");
			
				Seek(file,4,OFFSET_BEGINNING);
				Write(file,&(iffsize),4);
			
				UnlockPubScreen(NULL,scr);
			}
			else PutStr("could not lock requested public screen\n");
		
			Close(file);
		}
		else PrintFault (IoErr(),NULL);
	}
	else PrintFault (IoErr(),NULL);

	return RETURN_OK;
}
