/************************************************************************/
/* Apfel.c --- Generates an image of the Mandelbrot-set			*/
/*									*/
/* Author:	M. Böhnisch (BillySoft)					*/
/*		Löher Str. 2						*/
/*		D-4790 Paderborn					*/
/*									*/
/*		billy@uni-paderborn.de.pbinfo				*/
/*======================================================================*/
/* 06.11.89	iterative version with fixed box sizes (10 by 10),	*/
/*		adapted a GFA-BASIC program from a german magazine	*/
/*									*/
/* 08.11.89	complete own version with recursive algorithm		*/
/*		(divide & conquer)					*/
/*									*/
/* 10.11.89	added user input of picture size and borders		*/
/*									*/
/* 11.11.89	minor bug fixing					*/
/*									*/
/* 20.11.89	added fix-point arithmetik written in assembler		*/
/*		format:							*/
/*									*/
/*			[sgn|xxx xxxx xxxx xxxx.xxxx xxxx xxxx xxxx]	*/
/*									*/
/*		not accurate enough.					*/
/*									*/
/* 21.11.89	rewrote fix-point format to:				*/
/*									*/
/*			[sgn|xxx xxxx.xxxx xxxx xxxx xxxx xxxx xxxx]	*/
/*									*/
/*		nice! (I'll try to use 26 bit after the point sometime) */
/*									*/
/* 28.11.89	found IFF-Library on Fish #173. save picture option	*/
/*		added.							*/
/*									*/
/* 04.12.89	improved assembly program				*/
/*									*/
/* 07.12.89	slight optimization in recursion scheme			*/
/*									*/
/* 09.12.89	added input requester					*/
/*									*/
/* 21.07.90	review for Aztek-C5.0a					*/
/*									*/
/* 23.09.90	print option added (color printers)			*/
/*									*/
/* 25.09.90	added color requester					*/
/*                                                                      */
/* 27.09.90     optimization of assembly program                        */
/*									*/
/* 15.11.90	review for SAS C5.10					*/
/*									*/
/* 19.11.90	added a little retrying in case of an error by closing	*/
/*		screens. Might recover some problems with Amigas short	*/
/*		on memory or when really *BIG* screens are requested.	*/
/*									*/
/* 25.11.90	added s'more source code comments and translated all	*/
/*		strings from german to english				*/
/*									*/
/* 30.01.91	removed a bug causing to save no colormap along with a	*/
/*		picture							*/
/*									*/
/* 01.02.91	removed a bug doing strange things while colorcycling	*/
/*		pictures with more than 5 BitPlanes			*/
/*									*/
/* 01.02.91	added configuration facilities				*/
/*									*/
/* 17.04.91	removed a bug preventing the "Multitasking OFF" to work	*/
/*									*/
/* 18.04.91	some cast - operators added in "printersupport.h" to	*/
/*		compile without warnings.				*/
/*									*/
/* 08.06.91	added 68030/68881 support				*/
/*									*/
/* 09.06.91	replaced lattice fp by fast floating point functions	*/
/*		(faster only if FLOAT is used. shorter object, though)	*/
/************************************************************************/
/*                         W A R N I N G  ! ! !				*/
/*									*/
/* From now on ALL versions of Apfelkiste will need KS 2.0 and the new	*/
/* set of include files. This applies to version 28 and above.		*/
/************************************************************************/
/*									*/
/* 12.06.91	switched to 2.0 at last. removed ARP routines, not	*/
/*		because they're bad (THEY AREN'T!), but because of	*/
/*		naming conflicts of arp.h to 2.0 include files.		*/
/*									*/
/* 12.06.91	added some all *new* facilities:			*/
/*			o automatic overscan adaption			*/
/*			o autoscrolling screen				*/
/*									*/
/* 22.07.91	2.0 style gadgets provided				*/
/*									*/
/* 23.07.91	located a bug in SAS's fscanf() (!!!), %hx does NOT     */
/*		read 16 Bit integers but 32 Bit longs. Thus lead into	*/
/*		a strange error that occurred with pictures >3		*/
/*		bitplanes only: all colors above #8 are set to 0(black) */
/*		Fixed by scanning into a temporary long first.		*/
/*									*/
/* 23.10.91	changed names of OpenIFF() and CloseIFF() to xOpenIFF()	*/
/*		and xCloseIFF() for KS 2.0 include file compatibility	*/
/*									*/
/*		updated docs for inclusion in AmigaLibDisk pool		*/
/*									*/
/*		last-minute review for SAS C5.10b			*/
/************************************************************************/

/* -------------------------------------------------------------------- */
/* Some defininitions to take advantage of Lattice's LSR-code:		*/
/* -------------------------------------------------------------------- */
long	 _stack		= 20000;	/* Stack space for this task 	*/
char	*_procname	= "Apfelkiste";	/* Name of process created	*/
long	 _priority	= 0;		/* Process priority		*/
long	 _BackgroundIO	= 0;		/* No stdio required		*/
/* -------------------------------------------------------------------- */

#define APFEL_VERSION	"30"

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

#include <intuition/intuition.h>

#include <graphics/gfx.h>
#include <graphics/gfxmacros.h>

#include <libraries/iff.h>
#include <libraries/asl.h>
#include <libraries/color.h>

#include <proto/exec.h>
#include <proto/dos.h>
#include <proto/graphics.h>
#include <proto/intuition.h>
#include <proto/asl.h>
#include <proto/gadtools.h>

#include <printersupport.h>
#include <clib/macros.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <dos.h>
#include <mffp.h>
#include <math.h>
#include "Apf0.h"
#include "Apf2.h"

/* -------------------------------------------------------------------- */
/* Prototypes for the functions in the other modules			*/
/* -------------------------------------------------------------------- */

void FixPoint(	double rmin, double rmax, double imin, double imax,
		double dx, double dy,
		int maxiter, double divergenz, int gx, int gy, int depth);
void __regargs	Apfel_Alert(long number);
void __regargs	Activate_Gadget(struct Window *w, USHORT ID);
void __regargs	Apfel_FLOAT(int x1, int y1, int x2, int y2);
long 		Iter_FLOAT(double r, double i);
void		FreeGads(void);
struct Gadget	*InitGads(struct Screen *scr);

/* --------------------------------------------------------------------- */

struct IntuitionBase	*IntuitionBase;
struct GfxBase		*GfxBase;
struct IFFBase		*IFFBase;
struct Library		*AslBase;
struct ColorBase	*ColorBase;
struct Library		*GadToolsBase;

struct Screen		*s;
struct Window		*w, *u;
struct RastPort		*rp, *up;
struct ViewPort		*vp;
struct Gadget		*glist;

char			 DefBuf_REAL0[40];
char			 DefBuf_REAL1[40];
char			 DefBuf_IMAG0[40];
char			 DefBuf_IMAG1[40];
char			 DefBuf_MAXITER[40];
char			 DefBuf_DIV[40];
char			 DefBuf_XSIZE[40];
char			 DefBuf_YSIZE[40];
char			 DefBuf_DEPTH[40]; 

extern long		 SelNo_TASK;
extern long		 SelNo_CYCLE;
extern char		*Buf_REAL0;
extern char		*Buf_REAL1;
extern char		*Buf_IMAG0;
extern char		*Buf_IMAG1;
extern char		*Buf_MAXITER;
extern char		*Buf_DIV;
extern char		*Buf_XSIZE;
extern char		*Buf_YSIZE;
extern char		*Buf_DEPTH;
extern char		*DefText_REAL0;
extern char		*DefText_REAL1;
extern char		*DefText_IMAG0;
extern char		*DefText_IMAG1;
extern char		*DefText_MAXITER;
extern char		*DefText_DIV;
extern char		*DefText_XSIZE;
extern char		*DefText_YSIZE;
extern char		*DefText_DEPTH;  

int			 cycle, task = TRUE;
APTR			 IFFfile = NULL;
struct FileRequester	*FReq;
union printerIO		*request;
struct MsgPort		*printerPort;

int			 gx, gy, xsize, ysize, depth, hide;
short			 maxcol;
int			 maxiter;
double			 divergenz, rmin, rmax, imin, imax, dx, dy;

/* -------------------------------------------------------------------- */
/* All the stuff needed to comfortably get IntuitionMessages		*/
/* -------------------------------------------------------------------- */

ULONG			 CLASS, CODE, GAD_ID;
APTR			 ADDR;
struct IntuiMessage	*Message	= NULL;

ULONG GetMessage(struct Window *MW)
{
	CLASS = CODE = 0;
	ADDR = NULL;
	if ( Message = (struct IntuiMessage *) GetMsg(MW->UserPort) ) {
		CLASS	= Message->Class;
		CODE	= Message->Code;
		ADDR	= Message->IAddress;
		ReplyMsg((struct Message *) Message);
	}
	return CLASS;
}

ULONG GT_GetMessage(struct Window *MW)
{
	CLASS = CODE = GAD_ID = 0;
	ADDR = NULL;
	if ( Message = GT_GetIMsg(MW->UserPort) ) {
		CLASS	= Message->Class;
		CODE	= Message->Code;		
		ADDR	= Message->IAddress;
		if ( CLASS == IDCMP_GADGETUP ) {
			GAD_ID = ((struct Gadget *) ADDR)->GadgetID;
		}
		GT_ReplyIMsg(Message);
	}
	return CLASS;
}

/* -------------------------------------------------------------------- */
/* Simple routine to draw a rectangular shape. Used for the Mouse Opt	*/
/* -------------------------------------------------------------------- */

void DrawRect(struct RastPort *rp, short x1, short y1, short x2, short y2)
{
	Move(rp, x1, y1);
	Draw(rp, x2, y1);
	Draw(rp, x2, y2);
	Draw(rp, x1, y2);
	Draw(rp, x1, y1);
}

/* -------------------------------------------------------------------- */
/* Pre-initialized structures for main screen and window		*/
/* -------------------------------------------------------------------- */

UWORD PenSpec[] = { ~0 };		/* Minimal pen specifikation array */

struct TextAttr TOPAZ80 = { (STRPTR) "topaz.font", TOPAZ_EIGHTY, 0, 0 };

struct NewScreen NS = {
	0, 0,				/* screen XY origin relative to View */
	0, 0,				/* screen width and height */
	0,				/* screen depth (number of bitplanes) */
	0, 1,				/* detail and block pens */
	NULL,				/* display modes for this screen */
	CUSTOMSCREEN | SCREENQUIET,	/* screen type */
	&TOPAZ80,			/* pointer to default screen font */
	NULL,				/* screen title */
	NULL,				/* first in list of custom screen gadgets */
	NULL				/* pointer to custom BitMap structure */
};

struct NewWindow NW = {
	0, 0,		/* window XY origin relative to TopLeft of screen */
	0, 0,		/* window width and height */
	0, 1,		/* detail and block pens */
	NULL,		/* IDCMP flags */
	SMART_REFRESH |
	ACTIVATE      |
	BORDERLESS,	/* other window flags */
	NULL,		/* first gadget in gadget list */
	NULL,		/* custom CHECKMARK imagery */
	NULL,		/* window title */
	NULL,		/* custom screen pointer */
	NULL,		/* custom bitmap */
	5, 5,		/* minimum width and height */
	-1, -1,		/* maximum width and height */
	CUSTOMSCREEN	/* destination screen type */                          
};

struct NewWindow NW2 = {
	  0,   0,	/* window XY origin relative to TopLeft of screen */
	320, 196,	/* window width and height */
	  0,   1,	/* detail and block pens */
	GADGETUP,	/* IDCMP flags */
	WINDOWDRAG |
	ACTIVATE   |
	NOCAREREFRESH,	/* other window flags */
	NULL,		/* first gadget in gadget list */
	NULL,		/* custom CHECKMARK imagery */
	NULL,		/* window title */
	NULL,		/* custom screen pointer */
	NULL,		/* custom bitmap */
	  5,   5,	/* minimum width and height */
         -1,  -1,	/* maximum width and height */
	CUSTOMSCREEN	/* destination screen type */                        
};

/* -------------------------------------------------------------------- */
/* Default palette. Change this if you don't like the colors provided	*/
/* by me. Versions 25 and higher are supporting a custom default file.	*/
/* -------------------------------------------------------------------- */

USHORT Palette[128] = {
	0x0000,	/* color #0 */
	0x0F90,	/* color #1 */
	0x0F20,	/* color #2 */
	0x0840,	/* color #3 */
	0x0580,	/* color #4 */
	0x0589,	/* color #5 */
	0x055F,	/* color #6 */
	0x0A0F,	/* color #7 */
	0x0F08,	/* color #8 */
	0x0777,	/* color #9 */
	0x0080,	/* color #10 */
	0x00A0,	/* color #11 */
	0x00C0,	/* color #12 */
	0x00E0,	/* color #13 */
	0x08E0,	/* color #14 */
	0x0FF0,	/* color #15 */
	0x0000,	/* color #16 */
	0x0F90,	/* color #17 */
	0x0F20,	/* color #18 */
	0x0840,	/* color #19 */
	0x0580,	/* color #20 */
	0x0589,	/* color #21 */
	0x055F,	/* color #22 */
	0x0A0F,	/* color #23 */
	0x0F08,	/* color #24 */
	0x0777,	/* color #25 */
	0x0080,	/* color #26 */
	0x00A0,	/* color #27 */
	0x00C0,	/* color #28 */
	0x00E0,	/* color #29 */
	0x08E0,	/* color #30 */
	0x0FF0	/* color #31 */
#define PaletteColorCount 32
};

/* -------------------------------------------------------------------- */
/* Close everything opened at runtime					*/
/* -------------------------------------------------------------------- */

void CleanUp(void)
{
	if ( FReq )		FreeAslRequest(FReq);
	if ( request )		DeleteExtIO((struct IORequest *) request);
	if ( printerPort )	DeletePort(printerPort);
	if ( IFFfile )		xCloseIFF(IFFfile);
	if ( w )		CloseWindow(w);
	if ( u )		CloseWindow(u);
	if ( glist )		FreeGads();
	if ( s )		CloseScreen(s);
	if ( GadToolsBase )	CloseLibrary(GadToolsBase);
	if ( ColorBase )	CloseLibrary(ColorBase);
	if ( AslBase )		CloseLibrary(AslBase);
	if ( IFFBase )		CloseLibrary(IFFBase);
	if ( GfxBase )		CloseLibrary(GfxBase);
	if ( IntuitionBase )	CloseLibrary(IntuitionBase);
	exit(0);
}

/* -------------------------------------------------------------------- */
/* Open all used libraries, ports, etc. If this routine fails you are	*/
/* probably not up-to-date with one or several of the shared libraries	*/
/* used by me. Copy the provided libraries to your LIBS: directory,	*/
/* reboot (!) and try again.						*/
/* -------------------------------------------------------------------- */

void OpenLibs(void)
{
	IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 36);
	if ( ! IntuitionBase ) {
		Apfel_Alert(1);
		CleanUp();
	}

	GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 36);
	if ( ! GfxBase ) {
		Apfel_Alert(2);
		CleanUp();
	}

	IFFBase = (struct IFFBase *) OpenLibrary(IFFNAME, IFFVERSION);
	if ( ! IFFBase ) {
		Apfel_Alert(3);
		CleanUp();
	}

	AslBase = OpenLibrary(AslName, 0);
	if ( ! AslBase ) {
		Apfel_Alert(4);
		CleanUp();
	}

	ColorBase = (struct ColorBase *) OpenLibrary(COLORNAME, COLORVERSION);
	if ( ! ColorBase ) {
		Apfel_Alert(5);
		CleanUp();
	}

	GadToolsBase = (struct GadToolsBase *) OpenLibrary("gadtools.library", 0);
	if ( ! GadToolsBase ) {
		Apfel_Alert(15);
		CleanUp();
	}

	FReq = AllocFileRequest();
	if ( ! FReq ) {
		Apfel_Alert(6);
		CleanUp();
	}

	printerPort = CreatePort("Apfel-01.port",0L);
	if ( ! printerPort ) {
		Apfel_Alert(7);
		CleanUp();
	}

	request = (union printerIO *) CreateExtIO(printerPort, sizeof(union printerIO));
	if ( ! request ) {
		Apfel_Alert(8);
		CleanUp();
	}
}

/* -------------------------------------------------------------------- */
/* Open the control window and set gadget texts to appropriate values	*/
/* -------------------------------------------------------------------- */

void OpenRW(void)
{
	int wbflag = FALSE;

	NW2.Screen = s;
	if ( ! s ) {
		NW2.Type = WBENCHSCREEN;
	}
	else {
		NW2.Type = CUSTOMSCREEN;
	}

	if ( task ) {
		SelNo_TASK = 1;
	}
	else {
		SelNo_TASK = 0;
	}

	if ( cycle ) {
		SelNo_CYCLE = 1;
	}
	else {
		SelNo_CYCLE = 0;
	}

	if ( ! s ) {
		s	= LockPubScreen("Workbench");
		wbflag	= TRUE;
	}

	glist = InitGads(s);

	if ( ! glist ) CleanUp();

	u = OpenWindowTags(&NW2, WA_Gadgets, glist, TAG_END);
	if ( wbflag ) {
		UnlockPubScreen(NULL, s);
		s	= NULL;
	}
					/* open control window 		*/
	if ( ! u ) {			/* if something goes wrong...	*/
		Apfel_Alert(9);		/* give message.		*/
		if ( s ) {		/* is the screen open, then ?	*/
			CloseScreen(s);	/* close it...			*/
			s = NULL;
			OpenRW();	/* and retry on WB Screen...	*/
		}
		else {			/* No screen, no hope...	*/
			CleanUp();	/* exiting...			*/
		}
	}

	up = u->RPort;
	GT_RefreshWindow(u, NULL);
}

void CloseRW(void)
{
	if ( u ) {
		strcpy(DefBuf_REAL0  ,Buf_REAL0);
		strcpy(DefBuf_REAL1  ,Buf_REAL1);
		strcpy(DefBuf_IMAG0  ,Buf_IMAG0);
		strcpy(DefBuf_IMAG1  ,Buf_IMAG1);
		strcpy(DefBuf_MAXITER,Buf_MAXITER);
		strcpy(DefBuf_DIV    ,Buf_DIV);
		strcpy(DefBuf_XSIZE  ,Buf_XSIZE);
		strcpy(DefBuf_YSIZE  ,Buf_YSIZE);
		strcpy(DefBuf_DEPTH  ,Buf_DEPTH);
		DefText_REAL0	= DefBuf_REAL0; 
		DefText_REAL1	= DefBuf_REAL1;
		DefText_IMAG0	= DefBuf_IMAG0;
		DefText_IMAG1	= DefBuf_IMAG1;
		DefText_MAXITER	= DefBuf_MAXITER;
		DefText_DIV	= DefBuf_DIV;
		DefText_XSIZE	= DefBuf_XSIZE;
		DefText_YSIZE	= DefBuf_YSIZE;
		DefText_DEPTH	= DefBuf_DEPTH;
		CloseWindow(u);
		FreeGads();
		u	= NULL;
		glist	= NULL;
	}
}

/* -------------------------------------------------------------------- */
/* Open screen & window for graphics rendition trying to evaluate a	*/
/* "best match" for the view modes for both PAL and NTSC. Maybe this	*/
/* needs a little work for optimal results on NTSC machines.		*/
/* I plan to rework this completely after CBM pops out Kick 2.0 for	*/
/* the A2000 in an official version.					*/
/* -------------------------------------------------------------------- */

void OpenAll(void)
{
	USHORT	Modes = 0;
	int	cnt;

	NS.Width	= xsize;
	NS.Height	= ysize;
	NS.Depth	= depth;
	maxcol		= cnt		= 1 << depth;

	if ( xsize > 350 )		Modes  = HIRES;
	if ( ! Modes && depth == 6 ) {
		Modes	= EXTRA_HALFBRITE;
		cnt	= 32;
	}
	if ( ysize > 262 )		Modes |= LACE;

	NS.ViewModes = Modes;

	s = OpenScreenTags(&NS,
				SA_Overscan,	OSCAN_STANDARD,
				SA_AutoScroll,	TRUE,
				SA_FullPalette,	TRUE,
				SA_SysFont,	0,
				SA_Pens,	PenSpec,
				TAG_DONE);
	if ( ! s ) {
		Apfel_Alert(10);
	}
	else {
		NW.Screen	= s;
		NW.Width	= gx;
		NW.Height	= gy;
		NW.LeftEdge	= (xsize - gx) / 2;
		NW.TopEdge	= (ysize - gy) / 2;
		w = OpenWindow(&NW);
		if ( ! w ) {
			Apfel_Alert(9);
		}
		else {
			rp = w->RPort;
			vp = &(s->ViewPort);
			LoadRGB4(vp, Palette, cnt);
		}
	}
}

/* -------------------------------------------------------------------- */
/* Load an IFF ILBM file and get it displayed on the graphics screen.	*/
/* I have not put too much work into this, e.g. there is no chunk for	*/
/* the data needed to re-calculate the loaded Mandelbrot image.		*/
/* Comments and help are welcome, just send me a message to my E-Mail	*/
/* adress.								*/
/* -------------------------------------------------------------------- */

BOOL LoadFile(char *Name)
{
	struct BitMapHeader *bmhd;
	ULONG cnt;

	IFFfile = xOpenIFF(Name);
	if ( ! IFFfile ) {
		Apfel_Alert(12);
	}
	else {
		bmhd = GetBMHD(IFFfile);
		if ( ! bmhd ) {
			Apfel_Alert(13);
		}
		else {
			NS.Width	= gx	= xsize	= bmhd->w;
			NS.Height	= gy	= ysize	= bmhd->h;
			NS.Depth	= depth	= bmhd->nPlanes;
			maxcol		= 1 << depth;
			NS.ViewModes	= GetViewModes(IFFfile);
			s		=
				OpenScreenTags(&NS,
					SA_Overscan,	OSCAN_STANDARD,
					SA_AutoScroll,	TRUE,
					SA_SysFont,	1,
					TAG_DONE);
			if ( ! s ) {
				Apfel_Alert(10);
			}
			else {
				vp		= &(s->ViewPort);
				cnt		= GetColorTab(IFFfile, (WORD *) Palette);
				NW.Screen	= s;
				NW.Width	= gx;
				NW.Height	= gy;
				w		= OpenWindow(&NW);
				if ( ! w ) {
					Apfel_Alert(9);
					CloseScreen(s);
					s = NULL;
				}
				else {
					rp		= w->RPort;
					LoadRGB4(vp, Palette, cnt);
					if ( ! DecodePic(IFFfile, rp->BitMap) ) {
						Apfel_Alert(14);
						CloseWindow(w);
						w = NULL;
						CloseScreen(s);
						s = NULL;
					}
				}
			}
		}
		xCloseIFF(IFFfile);
		IFFfile		= NULL;
	}
	return ( w != NULL );		/* All OK if window still open */
}

/* -------------------------------------------------------------------- */
/* Set default values for the control window. Load the default image to	*/
/* comfortably get zoomed into this wonderful world of chaos.		*/
/* -------------------------------------------------------------------- */

void SetDefault(void)
{
	FILE	*fp;
	char	 defpic[FMSIZE];
	int	 i;
	int	 omt;
	long	 tmp;

	omt = task;

	fp = fopen("Apfelkiste.config", "r");
	if ( ! fp ) fopen("DEVS:Apfelkiste.config", "r");
	if ( ! fp ) fopen("S:Apfelkiste.config", "r");
	if ( ! fp ) {
		Apfel_Alert(11);
		strcpy(defpic, "Apfel0.IFF");
		rmin		= -2.3;
		imin		= -1.25;
		rmax		=  0.825;
		imax		=  1.25;
		maxiter		= 30;
		divergenz	=  6.0;
		cycle		= FALSE;
		task		= TRUE;
	}
	else {
		fscanf(fp, "FNAME=%s", defpic);
		fscanf(fp, "RMIN=%lf", &rmin);
		fscanf(fp, "RMAX=%lf", &rmax);
		fscanf(fp, "IMIN=%lf", &imin);
		fscanf(fp, "IMAX=%lf", &imax);
		fscanf(fp, "MAXITER=%d", &maxiter);
		fscanf(fp, "DIVERGENZ=%lf", &divergenz);
		fscanf(fp, "TASK=%d", &task);
		fscanf(fp, "CYCLE=%d", &cycle);
		for ( i = 0; i < PaletteColorCount; i++ ) {
			fscanf(fp, "COLOR=%x", &tmp);
			Palette[i] = (UWORD) tmp;
		}
		fclose(fp);
	}

	if ( ! LoadFile("Apfel0.IFF") ) {
		xsize	= gx	= 320;
		ysize	= gy	= 200;
		depth	= 2;
		maxcol	= 1 << depth;
	}

	dx = (rmax - rmin) / (double) gx;
	dy = (imax - imin) / (double) gy;

	sprintf(DefBuf_REAL0  , "%lf", rmin);
	sprintf(DefBuf_REAL1  , "%lf", rmax);
	sprintf(DefBuf_IMAG0  , "%lf", imin);
	sprintf(DefBuf_IMAG1  , "%lf", imax);
	sprintf(DefBuf_MAXITER, "%d" , maxiter);
	sprintf(DefBuf_DIV    , "%lf", divergenz);
	sprintf(DefBuf_XSIZE  , "%d" , gx);
	sprintf(DefBuf_YSIZE  , "%d" , gy);
	sprintf(DefBuf_DEPTH  , "%d" , depth);
	DefText_REAL0	= DefBuf_REAL0; 
	DefText_REAL1	= DefBuf_REAL1;
	DefText_IMAG0	= DefBuf_IMAG0;
	DefText_IMAG1	= DefBuf_IMAG1;
	DefText_MAXITER	= DefBuf_MAXITER;
	DefText_DIV	= DefBuf_DIV;
	DefText_XSIZE	= DefBuf_XSIZE;
	DefText_YSIZE	= DefBuf_YSIZE;
	DefText_DEPTH	= DefBuf_DEPTH;

	if ( omt != task ) {
		if ( task ) {
			Permit();
		}
		else {
			Forbid();
		}
	}
}

/* -------------------------------------------------------------------- */
/* Used by load/save routines to get filenames.				*/
/* -------------------------------------------------------------------- */

BOOL GetFileName(char *Name, char *Hail)
{
	if ( AslRequestTags(FReq,
				ASL_Hail,	Hail,
				ASL_Window,	w,
				TAG_DONE) ) {
		strmfp(Name, FReq->rf_Dir, FReq->rf_File);
		return TRUE;
	}
	else {
		return FALSE;
	}
}

/************************************************************************/
/* The main() function, at last...					*/
/* Contains the handling to react on gadget activation and manage the	*/
/* call of the diverse subroutines.					*/
/* Not commented at all, but shouldn't be too difficult to read anyway.	*/
/************************************************************************/

void main(int argc, char *argv[])
{
	char	fname[80];
	int	i, x, y;
	double	help;
	int	mx1, my1, mx2, my2;
	UWORD	c_palette[128];

	OpenLibs();
	SetDefault();
	OpenRW();

	do {
		WaitPort(u -> UserPort);
		GT_GetMessage(u);

		switch ( CLASS ) {
		case IDCMP_REFRESHWINDOW:
			GT_BeginRefresh(u);
			GT_EndRefresh(u, TRUE);
			break;
		case IDCMP_GADGETUP:
			switch ( GAD_ID ) {
			case GAD_FLOAT:
			case GAD_FXP:
				sscanf(Buf_REAL0  , "%lf", &rmin);
				sscanf(Buf_REAL1  , "%lf", &rmax);
				sscanf(Buf_IMAG0  , "%lf", &imin);
				sscanf(Buf_IMAG1  , "%lf", &imax);
				sscanf(Buf_MAXITER, "%d" , &maxiter);
				sscanf(Buf_DIV    , "%lf", &divergenz);
				sscanf(Buf_XSIZE  , "%d" , &gx);
				sscanf(Buf_YSIZE  , "%d" , &gy);
				sscanf(Buf_DEPTH  , "%d" , &depth);

				xsize = gx;
				if ( gx <= 736 ) xsize = 736;	/* Max. Overscan Hires	*/
				if ( gx <= 640 ) xsize = 640;	/* Nor. Size Hires	*/
				if ( gx <= 368 ) xsize = 368;	/* Max. Overscan Lores	*/
				if ( gx <= 320 ) xsize = 320;	/* Nor. Size Lores	*/

				ysize = gy;
				if ( gy <= 564 ) ysize = 564;	/* Max. Overscan Lace   PAL	*/
				if ( gy <= 512 ) ysize = 512;	/* Nor. Size Lace       PAL	*/
				if ( gy <= 400 ) ysize = 400;	/* Nor. Size Lace       NTSC	*/
				if ( gy <= 282 ) ysize = 282;	/* Max. Overscan NoLace PAL	*/
				if ( gy <= 256 ) ysize = 256;	/* Nor. Size NoLace	PAL	*/ 
				if ( gy <= 200 ) ysize = 200;	/* Nor. Size NoLace     NTSC	*/
				if ( w ) CloseWindow(w);
				w = NULL;
				CloseRW();
				if ( s ) CloseScreen(s);
				s = NULL;
				OpenAll();
				if (  w && s ) {
					dx   = (rmax - rmin) / (double) gx;
					dy   = (imax - imin) / (double) gy;

					switch ( GAD_ID ) {
					case GAD_FLOAT:
						help = rmin;
						for ( x = 0; x < gx; x++ ) {
							SetAPen(rp, Iter_FLOAT(help, imin));
							WritePixel(rp, x, 0);
							SetAPen(rp, Iter_FLOAT(help, imax));
							WritePixel(rp, x, gy-1);
							help += dx;
						}

						help = imin;
						for ( y = 0; y < gy; y++ ) {
							SetAPen(rp, Iter_FLOAT(rmin, help));
							WritePixel(rp, 0, y);
							SetAPen(rp, Iter_FLOAT(rmax, help));
							WritePixel(rp, gx-1, y);
							help += dy;
						}

						Apfel_FLOAT(0, 0, gx - 1, gy - 1);
						break;
					case GAD_FXP:
 						FixPoint(rmin, rmax, imin, imax, dx, dy,
							 maxiter, divergenz,
							 gx, gy, depth);
						break;
					}
				}
				else {
					if ( s ) {
						CloseScreen(s);
						s = NULL;
					}
				}
				OpenRW();
				break;
			case GAD_QUIT:
				CleanUp();
				break;
			case GAD_SAVE:
				CloseRW();
				if ( GetFileName(fname, "Save Picture") ) {
					SaveBitMap(fname, &(s->BitMap), Palette, 0x1L);
				}
				OpenRW();
				break;
			case GAD_LOAD:
				CloseRW();
				if ( GetFileName(fname, "Load Picture") ) {
					if ( w ) CloseWindow(w);
					w = NULL;
					if ( s ) CloseScreen(s);
					s = NULL;
					if ( ! LoadFile(fname) ) {;}
				}
				OpenRW();
				break;
			case GAD_REAL0:
				Activate_Gadget(u, GAD_REAL1);
				break;
			case GAD_REAL1:
				Activate_Gadget(u, GAD_IMAG0);
				break;
			case GAD_IMAG0:
				Activate_Gadget(u, GAD_IMAG1);
				break;
			case GAD_IMAG1:
				Activate_Gadget(u, GAD_MAXITER);
				break;
			case GAD_MAXITER:
				Activate_Gadget(u, GAD_DIV);
				break;
			case GAD_DIV:
				Activate_Gadget(u, GAD_XSIZE);
				break;
			case GAD_XSIZE:
				Activate_Gadget(u, GAD_YSIZE);
				break;
			case GAD_YSIZE:
				Activate_Gadget(u, GAD_DEPTH);
				break;
			case GAD_DEPTH:
				Activate_Gadget(u, GAD_REAL0);
				break;
			case GAD_MOUSE:
				if ( s && w ) {
					CloseRW();
					ModifyIDCMP(w, MOUSEBUTTONS | INTUITICKS);
					do {
						WaitPort(w->UserPort);
						GetMessage(w);
					} while ( CLASS != MOUSEBUTTONS || CODE != SELECTDOWN );

					mx2 = mx1 = w->MouseX;
					my2 = my1 = w->MouseY;
					SetDrMd(rp, JAM2 | COMPLEMENT);
					SetAPen(rp, 1L);
					DrawRect(rp, mx1, my1, mx2, my2);

					do {
						if ( mx2 != w->MouseX || my2 != w->MouseY ) {
							DrawRect(rp, mx1, my1, mx2, my2);
							mx2 = w->MouseX;
							my2 = w->MouseY;
							DrawRect(rp, mx1, my1, mx2, my2);
						}
						Wait(1L << w->UserPort->mp_SigBit);
						GetMessage(w);
					} while ( CLASS != MOUSEBUTTONS || CODE != SELECTUP );

					DrawRect(rp, mx1, my1, mx2, my2);
					if ( mx1 > mx2 ) {
						i	= mx1;
						mx1	= mx2;
						mx2	= i;
					}
					if ( my1 > my2 ) {
						i	= my1;
						my1	= my2;
						my2	= i;
					}
					ModifyIDCMP(w, NULL);

					sprintf(DefBuf_REAL0, "%lf", mx1*dx+rmin);
					sprintf(DefBuf_REAL1, "%lf", mx2*dx+rmin);
					sprintf(DefBuf_IMAG0, "%lf", my1*dy+imin);
					sprintf(DefBuf_IMAG1, "%lf", my2*dy+imin);
					DefText_REAL0 = DefBuf_REAL0;
					DefText_REAL1 = DefBuf_REAL1;
					DefText_IMAG0 = DefBuf_IMAG0;
					DefText_IMAG1 = DefBuf_IMAG1;
					OpenRW();
				}
				break;
			case GAD_VIEW:
				if ( s && w ) {
					CloseRW();
					memcpy(c_palette, Palette, sizeof(UWORD) * MIN(32, maxcol));
					ModifyIDCMP(w, MOUSEBUTTONS | INTUITICKS);
					while ( GetMessage(w) != MOUSEBUTTONS ) {
						if ( cycle ) {
							i = c_palette[MIN(31, maxcol-1)];
							movmem(c_palette+1, c_palette+2, sizeof(UWORD) * MIN(30, maxcol-2 ));
							c_palette[1] = i;
							LoadRGB4(vp, c_palette, MIN(32, maxcol));
							Delay(10L);
						}
						WaitPort(w->UserPort);
					}
					ModifyIDCMP(w, NULL);
					LoadRGB4(vp, Palette, MIN(32,maxcol));
					OpenRW();
				}
				break;
			case GAD_PRINT:
				if ( s && w ) {
					if ( ! OpenPrinter(request) ) {
						DumpRPort(request, rp, vp->ColorMap,
						vp->Modes, 0, 0, s->Width, s->Height, 0, 0,
						SPECIAL_FULLCOLS | SPECIAL_ASPECT);
						ClosePrinter(request);
					}
				}
				break;
			case GAD_CYCLE:
				cycle = CODE;
				break;
			case GAD_DEFAULT:
				if ( w ) CloseWindow(w);
				w = NULL;
				CloseRW();
				if ( s ) CloseScreen(s);
				s = NULL;
				SetDefault();
				OpenRW();
				break;
			case GAD_TASK:
				task = CODE;
				if ( task ) {
					Permit();
				}
				else {
					Forbid();
				}
				break;
			case GAD_ABOUT:
				CloseRW();
				EasyRequest(w, &ES1, NULL, NULL);
				OpenRW();
				break;
			case GAD_COLOR:
				if ( s ) {
					CloseRW();
					if ( ! DoColor(Palette, s) ) {
						for ( i = 0; i < MIN(32, maxcol); i++ ) {
							Palette[i] = GetRGB4(vp->ColorMap, i);
						}
					}
					OpenRW();
				}
				break;
			}
		}
	} while ( TRUE );
}
