/*
			MAND3.C - Control routines
		Mandelbrot Self-Squared Dragon Generator
			For the Commodore Amiga
			    Version 2.05
		Copyright (C) 1985, Robert S. French
		Vastly Enhanced by =RJ Mical=  1985/86
		Copyright (C) 1986,  =Robert J. Mical=
	Further feached and even considerably optimized by >>SDB<<
		Copyright (C) 1986, Scott D. Ballantyne
		     Placed in the Public Domain

This program may be distributed free of charge as long as the above
notice is retained.
*/

#include "mand.h"

extern struct Menu	MainMenu[MENU_COUNT];
extern struct MenuItem	OptionsItems[OPTIONS_COUNT];
extern SHORT		Color0, Color1, Color2;
extern SHORT		UserPalette[29];
extern BOOL		SavePicture();

/*----------------------*/
/* Graphics definitions */
extern struct GfxBase		*GfxBase;
extern struct IntuitionBase	*IntuitionBase;
 
struct	RastPort	*rp;
struct	ViewPort	*vp;
 
struct	TextAttr TextFont = {
	(UBYTE *)"topaz.font",	/* Standard system font */
	8,	0,	0
};
 
struct	Window		*w, ColorWindow;
struct	Screen		*screen;
struct	IntuiMessage	*message;
 
struct NewScreen ns = {
	0, 0,			/* start position                */
	320, 200, 6,		/* width, height, depth          */
	0, 1,			/* detail pen, block pen         */
	HAM,			/* Hold and Modify ViewMode      */
	CUSTOMSCREEN,		/* screen type                   */
	&TextFont,		/* font to use                   */
	(UBYTE *)"",		/* default title for screen      */
	NULL			/* pointer to additional gadgets */
};
 
struct NewWindow nw = {
	0, 0,			/* start position                */
	320, 200,		/* width, height                 */
	-1, -1,			/* detail pen, block pen         */
	MOUSEBUTTONS | MENUPICK | INTUITICKS,
				/* IDCMP flags                   */
	ACTIVATE | BORDERLESS | BACKDROP,
				/* window flags                  */
	NULL,			/* pointer to first user gadget  */
	NULL,			/* pointer to user checkmark     */
	NULL,			/* window title                  */
	NULL,			/* pointer to screen (set below) */
	NULL,			/* pointer to superbitmap        */
	0, 0, 320, 200,		/* ignored since not sizeable    */
	CUSTOMSCREEN		/* type of screen desired        */
};


SHORT	last_color;
BOOL	SettingCenter, SettingBoxSize, SetBoxProportional;

/*----------------------------------*/
/* Miscellaneous Global Definitions */
extern FLOAT	start_r, end_r, start_i, end_i;	/* Block bounds for set */
extern int	max_x, max_y;			/* Graphics window size */
extern int	max_count, color_inc, color_offset, color_set;
extern int	color_mode,color_div;
extern int	color_inset, func_num;
extern UWORD	*color_table;
extern FILE	*console, *redir_fp;
extern SHORT	y_coord;
extern BOOL	Resume;
 
extern SHORT	ZoomCenterX, ZoomCenterY, ZoomBoxSizeX, ZoomBoxSizeY;
extern SHORT	ZoomBoxStartX, ZoomBoxStartY;

open_winds()
{
	REGISTER	i, color;

	nw.Width = max_x;
	nw.Height = max_y;
	if (color_mode & NOT_HOLDANDMODIFY)
	{
		ns.ViewModes = NULL;
		ns.Depth = 5;
	}
	else
	{
		ns.ViewModes = HAM;
		ns.Depth = 6;
	}
	if (color_mode & INTERLACE_MODE)
	{
		ns.ViewModes |= INTERLACE;
		ns.Height = 400;
	}
	else
		ns.Height = 200;
	if (color_mode & HIRES_MODE)
	{
		ns.Width = 640;
		ns.ViewModes |= HIRES;
		ns.Depth = 4;
	}
	else
		ns.Width = 320;
	if (color_mode & HALFBRITE_MODE)
	{
		ns.Width = 320;
		ns.Height = 200;
		ns.Depth = 6;
		ns.ViewModes = EXTRA_HALFBRITE;
	}
	if ( !(screen = OpenScreen(&ns)))
	{
		fputs("Can't open screen!\n", console);
		return(1);
	}
 
	ShowTitle(screen, (LONG)FALSE);
	nw.Screen = screen;
	if( !(w = OpenWindow(&nw)))
	{
		CloseScreen(screen);
		fputs("Can't open new window!\n",console);
		return (1);
	}
	/* Until we're done drawing the primary display, cripple the menus. */
	MainMenu[MENU_OPTIONS].NextMenu = NULL;
	MainMenu[MENU_OPTIONS].FirstItem = &OptionsItems[OPTIONS_STOP];
	SetMenuStrip(w, &MainMenu[MENU_OPTIONS]);
	vp = &screen->ViewPort;
	rp = w->RPort;
	SetDrMd(rp,JAM1);
	SetBPen(rp, 0L);
	/* leave registers 0 and 1 alone, set two to black, set the others
	 * according to the user's design
	 */
	SetRGB4(vp, 0L, 
		(LONG)((Color0 >> 8) & 0xf), 
		(LONG)((Color0 >> 4) & 0xf), 
		(LONG)(Color0 & 0xf));
	SetRGB4(vp, 1L,
		(LONG)((Color1 >> 8) & 0xf), 
		(LONG)((Color1 >> 4) & 0xf), 
		(LONG)(Color1 & 0xf));
	SetRGB4(vp, 2L, 
		(LONG)((Color2 >> 8) & 0xf), 
		(LONG)((Color2 >> 4) & 0xf), 
		(LONG)(Color2 & 0xf));
	for (i = 3; i <= 31; i++)
	{
		UserPalette[i - 3] = 
			color = *(color_table + color_offset+(i-2)*color_inc);
	SetRGB4(vp, (LONG)i, 
		(LONG)((color >> 8) & 0xf), 
		(LONG)((color >> 4) & 0xf), 
		(LONG)(color & 0xf));
	}
	return (0);
}

void wait_close()
{
	REGISTER ULONG	class;
	REGISTER USHORT	code;

	if (redir_fp) {
		Delay(600L);
		CloseDisplay();
		return;
	}
	SettingCenter = SettingBoxSize = FALSE;
	FOREVER
	{
		Wait((1L << w->UserPort->mp_SigBit));
		while (message = GetMsg(w->UserPort))
		{
			class = message->Class;
			code  = message->Code;
			ReplyMsg(message);
 
			switch (class)
			{
				case MENUPICK:
				switch MENUNUM(code)
				{
					case MENU_PROJECT:
						if (ProjectMenu(code))
							return;
						break;
					case MENU_OPTIONS:
						if (DisplayMenu(code))
							return;
						break;
					case MENU_ZOOM:
						if (ZoomMenu(code))
							return;
						break;
				}
				break; /* breaks MENUPICK switch statement */
				case INTUITICKS:
					code = NULL;
				case MOUSEBUTTONS:
					if (SettingCenter)
					{
						DrawZoomCenter();
						if (code == SELECTDOWN)
						{
							SettingCenter = FALSE;
							DrawDisplayCenter();
						}
						else
						{
							ZoomCenterX=w->MouseX;
							ZoomCenterY=w->MouseY;
							DrawZoomCenter();
						}
					}
					else if (SettingBoxSize)
					{
						DrawZoomBox();
						if (code == SELECTDOWN)
							SettingBoxSize=FALSE;
						else
						{
							RecalcZoomBox();
							DrawZoomBox();
						}
					}
					break;
			}
		}
	}
}

ZoomAlongDarling(rzoom, izoom)
FLOAT rzoom, izoom;
{
	FLOAT	center, distance, scale;

	scale = rzoom;
	distance = (end_r - start_r) /  2.0;
	center = distance + start_r; 
	scale = distance * scale;
	start_r = center - scale;
	end_r = center + scale;

	scale = izoom;
	distance = (end_i - start_i) / 2.0; 
	center = distance + start_i; 
	scale = distance * scale; 
	start_i = center - scale; 
	end_i = center + scale; 
}

int ProjectMenu(code)
USHORT code;
/* if this function calls gen_mand() and it returns non-zero, return a
 * non-zero to the caller, else return zero
 */
{
	UBYTE	namebuffer[31];

	switch ITEMNUM(code)
	{
		case PROJECT_SAVEPICTURE:
			ScreenToBack(screen);
			fprintf(console, "Click in window, then enter filename\n");
			fprintf(console, "Filename? ");
			fgets(namebuffer, 31, console);
			namebuffer[strlen(namebuffer) - 1] = '\0';
			if (SavePicture(&namebuffer[0]))
				ScreenToFront(screen);
			else
				fprintf(console,
				  "LeftAMIGA-M will redisplay your picture\n");
			break;
		case PROJECT_READPICTURE:
			CloseDisplay();
			fprintf(console, "Filename? ");
			fgets(namebuffer, 31, console);
			namebuffer[strlen(namebuffer) - 1] = '\0';
			if (!(ReadPicture(&namebuffer[0])))
				return(1);
			break;
		case PROJECT_PRINTPICTURE:
			PrintMand();
			break;
		}
		
	return(0);
}

int DisplayMenu(code)
USHORT code;
/* if this function calls gen_mand() and it returns non-zero, return a
 * non-zero to the caller, else return zero
 */
{
	switch ITEMNUM(code) {
		case OPTIONS_QUARTER:
			if (NOT Resume)
			{
				DisplayBeep(NULL);
				return(0);
			}
			if (color_mode & HIRES_MODE)
				max_x = 640 / 4;
			else
				max_x = 320 / 4;
			if (color_mode & INTERLACE_MODE)
				max_y = 400 / 4;
			else
				max_y = 200 / 4;
			return(gen_mand(0));
		case OPTIONS_FULL:
			if (NOT Resume)
			{
				DisplayBeep(NULL);
				return(0);
			}
			if (color_mode & HIRES_MODE)
				max_x = 640;
			else
				max_x = 320;
			if (color_mode & INTERLACE_MODE)
				max_y = 400;
			else
				max_y = 200;
			/* intentionally fall into GENERATE */
		case OPTIONS_GENERATE:
			if (NOT Resume)
			{
				DisplayBeep(NULL);
				return(0);
			}
			return(gen_mand(0));
		case OPTIONS_RESUME:	/* Start again after STOP or LOAD */
			if (NOT Resume)
			{
				DisplayBeep(NULL);
				return(0);
			}
			return(gen_mand(y_coord));
		case OPTIONS_CLOSE:
			CloseDisplay();
			return(1);
		case OPTIONS_COLORS:
			DoColorWindow();
			break;
	}
	return(0);
}

int ZoomMenu(code)
USHORT code;
/* if this function calls gen_mand() and it returns non-zero, return a
 * non-zero to the caller, else return zero
 */
{
	FLOAT	center, distance, scale;

	if (NOT Resume)
	{
		DisplayBeep(NULL);
		return(0);
	}

	switch ITEMNUM(code)
	{
		case ZOOM_SETCENTER:
			if (NOT SettingCenter)
			{
				ZoomCenterX = w->MouseX;
				ZoomCenterY = w->MouseY;
				DrawDisplayCenter();
				DrawZoomCenter();
				SettingCenter = TRUE;
			}
			break;
		case ZOOM_SIZEBOX:
		case ZOOM_SIZEPROP:
			if (NOT SettingBoxSize)
			{
				if (ITEMNUM(code) == ZOOM_SIZEPROP)
					SetBoxProportional = TRUE;
				else
					SetBoxProportional = FALSE;
				SettingBoxSize = TRUE;
				RecalcZoomBox();
				DrawZoomBox();
			}
			break;
		case ZOOM_ZOOMIN:
		case ZOOM_ZOOMIN10:
			/* first, get distance equal to the current size 
			 * of a single pixel width 
			 */
			distance = end_r - start_r;
			distance = ( (FLOAT) distance) /  max_x;
			/* center equals the number of pixels from the
			 * center of the display to the zoom center
			 */
			center =  ( (FLOAT) ZoomCenterX) - (max_x >> 1);
			/* scale equals the real displacement from the
			 * center of the display to the zoom center
			 */
			scale = center * distance;
			/* move the real origin to here */
			start_r = start_r + scale;
			end_r = end_r + scale;
			/* now do it all again for the irrational axis */
			distance = end_i - start_i;
			distance = ( (FLOAT) distance) /  max_y;
			/* the signs are reversed to swap the sign */
			center =  ( (FLOAT) (max_y >> 1)) -  ZoomCenterY;
			scale = distance * center;
			/* move the real origin to here */
			start_i = scale + start_i;
  			end_i = scale + end_i;
			/* next, get the zoom-in scale
			 * if we're using the frame, then get the 
			 * proportion of the box to the display;
			 * else if we're zooming in by 10, get that scale
			 */
			if (ITEMNUM(code) == ZOOM_ZOOMIN)
				scale =  ((FLOAT) ZoomBoxSizeX) /  max_x;
			else
				scale =  0.1;
			ZoomAlongDarling(scale,  1.0); 
			if (ITEMNUM(code) == ZOOM_ZOOMIN)
				scale =  ((FLOAT) ZoomBoxSizeY) / max_y;
			else
				scale =  0.1;
			ZoomAlongDarling(1.0, scale);
			return(gen_mand(0));
		case ZOOM_ZOOMOUT2:
			ZoomAlongDarling(2.0, 2.0);
			return(gen_mand(0));
		case ZOOM_ZOOMOUT10:
			ZoomAlongDarling(10.0,  10.0);
			return(gen_mand(0));
	}
	return(0);
}
