/************************************************************************
*  Version 3.00  MANDELBROT - Self-Squared Dragon Generator  29-May-86  *
*  Commodore Amiga       Miscellaneous Project Options         MAND7.C  *
*************************************************************************
*         Copyright (c) 1986, Robert S. French and R. J. Mical          *
* --------------------------------------------------------------------- *
*  This program has been placed in the public domain.  A limited        *
*  license is hereby granted for the unlimited use and distribution of  *
*  this program, provided it is not used for commercial or profit-      *
*  making purposes.  Thank you.                                         *
*************************************************************************
*  Author information:            | Name:   R. J. Mical                 *
*                                 | USnail: Commodore-Amiga, Inc.       *
*  Name:   Robert S. French       |         983 University Avenue       *
*  USnail: 2740 Frankfort Avenue  |         Los Gatos, CA  95030        *
*          Louisville, KY  40206  \-------------------------------------*
*  Phone:  (502) 897-5096              UUCP: ihnp4!ptsfa!well!french    *
*  ARPA:   French#Robert%d@LLL-MFE or RFrench@MIT-MULTICS               *
*************************************************************************
*  Please send any comments, suggestions, or bugs to one of the above   *
*  addresses.                                                           *
************************************************************************/

#include "mand.h"
#include "globals.h"

/* Definitions for Save Picture in IFF */

struct  BitMapHeader
{
	USHORT  w;
	USHORT  h;
	SHORT   x, y;
	UBYTE   nPlanes, masking, compression, pad1;
	USHORT  TransparentColor;
	UBYTE   xAspect, yAspect;
	SHORT   PageWidth, PageHeight;
};

struct  PaintingHeader
{
	LONG    IFFID, FileLength, ILBMID, BMHDID, BitMapSize;
	struct  BitMapHeader BitMapHeader;
	LONG    CMAP, CMAPlength;
};

#define MakeID(a,b,c,d)  ( (a)<<24 | (b)<<16 | (c)<<8 | (d) )
#define FORM MakeID('F','O','R','M')            
#define ILBM MakeID('I','L','B','M')
#define BMHD MakeID('B','M','H','D')
#define BODY MakeID('B','O','D','Y')
#define CMAP MakeID('C','M','A','P')
#define CAMG MakeID('C','A','M','G')
#define CRNG MakeID('C','R','N','G')

/* === variables defined here ============================================= */

UBYTE *FriendlyTools[] =
{
	"FILETYPE=Graphicraft",
};

UWORD ProjectObjectData[] =
{
	0x1FF0, 0x0000,
	0x783C, 0x6000,
	0xE00F, 0xF800,
	0xE00F, 0xF800,
	0x783C, 0x6000,
	0x1FF0, 0x0000,
	/* */
	0x0000, 0x0000,
	0x07C0, 0x0000,
	0x1FF0, 0x0000,
	0x1FF0, 0x0000,
	0x07C0, 0x0000,
	0x0000, 0x0000,
};

struct Image ProjectObjectImage =
{
	0, 0,
	21, 6, 2,
	&ProjectObjectData[0],
	3, 0,
	NULL,
};


struct DiskObject ProjectObject =
{
	WB_DISKMAGIC,
	WB_DISKVERSION,
	{
		/* the Gadget structure */
		NULL,
		0, 0,
		25, 12,
		GADGHBOX | GADGIMAGE,
		RELVERIFY | GADGIMMEDIATE,
		BOOLGADGET,
		(APTR)&ProjectObjectImage,
		NULL,
		NULL,
		0, 0, 0, 0,
	},
	WBPROJECT,
	":Graphicraft",
	FriendlyTools,
	NO_ICON_POSITION, NO_ICON_POSITION,
	NULL,
	NULL,
	PROCESS_STACKSIZE,
};

LONG PictModes[3] =
{
	CAMG,
	0,		/* Gets filled in */
	NULL,
};

LONG PictBody[2] =
{
	BODY,
	0,		/* Gets filled in */
};

LONG PictCycle[] =
{
	CRNG,
	8,
	0,
	0x00010101,
	CRNG,
	8,
	0x2e001200,
	0x0001031f,
	CRNG,
	8,
	0x00000024,
	0x00010101,
	CRNG,
	8,
	0x00000024,
	0x00010101,
};

struct PaintingHeader PaintingHeader =
{
	FORM,
	0,		/* Gets filled in */
	ILBM,
	BMHD,
	sizeof(struct BitMapHeader),
	{               /* start of the BitMapHeader structure */
		0, 0,
		0, 0,
		5,
		0,
		1,
		0,
		0,
		10, 11,
		0, 0,       /* end of BitMapHead */
	},
	CMAP,
	0,
};

/* Definitions for Print Screen */

struct IODRPReq  request;
struct MsgPort   *pport;


SavePicture(filename)
UBYTE *filename;
{
	SHORT i,j,k,x,offset,dlen;
	ULONG length,bodypos,pos1,pos2;
	FILE *fp;
	UBYTE *p, component, rgbbyte;
	BYTE bfr[256],*q,padbyte=0;
	USHORT rgb;
	int written;

	written = FALSE;

	fp = fopen(filename,"w");
	if (fp == NULL)
		goto EXIT_ERROR;

	/***********************************************************************
	* to write the buffer to the disk, we need to write:
	*      "FORM"
	*      file length
	*      "ILBM"
	*      "BMHD"
	*      BMHD length
	*      BitMapHeader structure
	*      "CMAP"
	*      CMAP length
	*      colors
	*      pad byte if needed
	*      "BODY"
	*      BODY length
	*      body data
	*      "CAMG"
	*      CAMG length
	*      VP mode
	**********************************************************************/

	/* First, write out the header */

	PaintingHeader.CMAPlength = 3*(1<<ns.Depth);
	PaintingHeader.BitMapHeader.w = ns.Width;
	PaintingHeader.BitMapHeader.h = ns.Height;
	PaintingHeader.BitMapHeader.PageWidth = ns.Width;
	PaintingHeader.BitMapHeader.PageHeight = ns.Height;
	PaintingHeader.BitMapHeader.nPlanes = ns.Depth;

	length = sizeof(struct PaintingHeader);
	if (fwrite(&PaintingHeader,length,1,fp) != 1)
		goto WRITE_ERROR;

	/* also, enough bytes for each color register */
	for (i = 0; i < (1 << ns.Depth); i++) {
		for (component = 0; component < 3; component++) {
			rgb = (GetRGB4(vp->ColorMap, i));
			rgbbyte = (rgb >> (4 * (2 - component)));
			rgbbyte <<= 4;
			if (fwrite(&rgbbyte,1,1,fp) != 1)
				goto WRITE_ERROR;
		}
	}
	if (ns.Depth == 4)
		PictCycle[7] = 0x0001030f;
	else
		PictCycle[7] = 0x0001031f;
	if (fwrite(PictCycle,64,1,fp) != 1)
			goto WRITE_ERROR;
	bodypos = ftell(fp)+4;
	if (fwrite(PictBody,8,1,fp) != 1)
		goto WRITE_ERROR;

	/* Finally, the data (compressed with ByteRun1) */
	/* First, get the bytelength per line */
	length = (((ns.Width + 15) >> 4) << 1);

	ShowTitle(screen,FALSE);

	/* For every line ... */
	for (j = 0; j < ns.Height; j++) {
		offset = length * j;
		/* For every bit plane ... */
		for (k = 0;k < ns.Depth;k++) {
			/* p is set to the start of the line in this bit plane */
			p = (screen->BitMap.Planes[k]) + offset;
			for (i=0;i<length;i++)
				bfr[i] = p[i];
			dlen = length;
			for (i=0;i<dlen;) {
				if ((bfr[i] == bfr[i+1]) && (i != dlen-1)) {
					for (x=i+1;x<dlen;x++)
						if (bfr[x] != bfr[i])
							break;
					bfr[i] = i+1-x;
					for (q=bfr+x;q<bfr+dlen;q++)
						*(q-x+i+2) = *q;
					dlen -= x-i-2;
					i += 2;
				}
				else {
					if (i == dlen-1)
						x = i+2;
					else
						for (x=i+1;x<dlen;x++)
							if (bfr[x] == bfr[x-1])
								break;
					for (q=bfr+dlen;q>bfr+i;q--)
						*q = *(q-1);
					bfr[i] = x-i-2;
					i += x-i;
					dlen++;
				}
			}
			if (fwrite(bfr,dlen,1,fp) != 1)
				goto WRITE_ERROR;
		}
	}
	pos1 = ftell(fp)-bodypos-4;

	if (ftell(fp) & 1)
		if (fwrite(&padbyte,1,1,fp) != 1)
			goto WRITE_ERROR;
	PictModes[2] = vp->Modes;
	if (fwrite(PictModes,12,1,fp) != 1)
		goto WRITE_ERROR;
	pos2 = ftell(fp)-8;
	fseek(fp,4,0);
	fwrite(&pos2,4,1,fp);
	fseek(fp,bodypos,0);
	fwrite(&pos1,4,1,fp);
	/* if (PutDiskObject(filename, &ProjectObject) == FALSE)
		goto WRITE_ERROR;
*/	written = TRUE;

WRITE_ERROR:
	fclose(fp);

EXIT_ERROR:
	if (NOT written) {
		puts("*** Couldn't write your file! ***\n");
		DisplayBeep(NULL);
		DeleteFile(filename);
	}

	ShowTitle(screen,title_displayed);

	return(written);
}

dump_screen()
{
	struct MsgPort *CreatePort();

	struct IODRPReq *req = &request;
	ULONG class;
	USHORT code;

	if ((pport = CreatePort(NULL , 0L)) == NULL) {
		DisplayBeep(screen);
		reset_menus();
		return(0);
	}
	if (OpenDevice("printer.device",0L,req,0L)) {
		DisplayBeep(screen);
		DeletePort(pport);
		reset_menus();
		return(0);
	}
/*  Reenable when you can abort a raster dump!
	reset_print();
*/
	disable_some(~0,~0,~0);

	ShowTitle(screen,FALSE);
	req->io_Message.mn_ReplyPort = pport;
	req->io_Command = PRD_DUMPRPORT;
	req->io_RastPort = rp;
	req->io_ColorMap = screen->ViewPort.ColorMap;
	req->io_Modes    = screen->ViewPort.Modes;
	req->io_SrcX = 0;
	req->io_SrcY = STARTY;
	req->io_DestCols = req->io_SrcWidth = max_x;
	req->io_DestRows = req->io_SrcHeight = max_y;
	req->io_Special = 0x8C;
	BeginIO(req);
	for (EVER) {
		while (message = (struct IntuiMessage *)GetMsg(w->UserPort)) {
			class = message->Class;
			code  = message->Code;
			ReplyMsg(message);
			if (class == MENUPICK)
				if (MENUNUM(code) == MENU_PROJECT &&
				ITEMNUM(code) == PROJECT_PRINT) {
					AbortIO(req);		/* Doesn't do anything right now! */
					if (CheckIO(req))
						WaitIO(req);
					goto abort_print;
				}
			Delay(40L);
			if (CheckIO(req))
				break;
		}
abort_print:
/*
		done_print();
*/
		reset_menus();
		CloseDevice(req);
		DeletePort(pport);
		ShowTitle(screen,title_displayed);
	}
}
