/*****************************************************************************
 *			MAND5.C - Color Window
 *		Mandelbrot Self-Squared Dragon Generator
 *			For the Commodore Amiga
 *			    Version 2.05
 *
 *		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.  You may extract any or all information contained
 *	in this file for use in your own programs
 *
 ****************************************************************************/

#include "mand.h"

extern struct Menu	MainMenu[MENU_COUNT];
extern struct MenuItem	OptionsItems[OPTIONS_COUNT];
extern SHORT		Color0, Color1, Color2;
extern SHORT		UserPalette[29];
/*----------------------*/
/* Graphics definitions */

extern struct	GfxBase		*GfxBase;
extern struct	IntuitionBase	*IntuitionBase;
 
extern struct	RastPort	*rp;
extern struct	ViewPort	*vp;
 
extern struct	Window		*w, *ColorWindow;
extern struct	Screen		*screen;
extern struct	IntuiMessage	*message;
 
extern SHORT	last_color;
extern BOOL	SettingCenter, SettingBoxSize;
/*----------------------------------*/
/* Miscellaneous Global Definitions */

extern FLOAT	start_r, end_r, start_i, end_i;	/* Block bounds for set */
extern int	max_x, max_y;
extern int	max_count, color_inc, color_offset;
extern int	color_set, color_mode, color_div;
extern int	color_inset, func_num;
extern UWORD	*color_table;
extern FILE	*console, *redir_fp;
 
extern SHORT	ZoomCenterX, ZoomCenterY, ZoomBoxSizeX, ZoomBoxSizeY;
extern SHORT	ZoomBoxStartX, ZoomBoxStartY;

/*****************************************************************************
 *
 * Color initialization and routines
 *
 ****************************************************************************/

#define COPYCOLOR	1
#define RANGE_FIRST	2
#define RANGE_SECOND	3

USHORT	ColorMode;

extern struct Gadget	ColorTemplateGadgets[COLOR_GADGETS_COUNT];
extern struct Image	ColorPropsImages[3];
extern struct PropInfo	ColorPropsInfos[3];
extern struct IntuiText	ColorClusterText[4];

USHORT	SavePalette[32];

extern struct Image	SuperColorImages[32];

#define COLOR_IDCMP_FLAGS (GADGETDOWN | GADGETUP | MOUSEBUTTONS \
		| MENUPICK | MOUSEMOVE | ACTIVEWINDOW | INACTIVEWINDOW)

struct NewWindow ColorNewWindow = {
	/*  SHORT LeftEdge, TopEdge;	/* screen dimensions of window */
	/*  SHORT Width, Height;	/* screen dimensions of window */
	DEFAULT_WINDOW_LEFT, DEFAULT_WINDOW_TOP,
	COLORWINDOW_WIDTH, COLORWINDOW_HEIGHT,
	/*  UBYTE DetailPen, BlockPen;	/* for bar/border/gadget rendering */
	-1, -1,
	/*  ULONG IDCMPFlags;		/* User-selected IDCMP flags */
	NULL,
	/*  ULONG Flags;		/* see Window struct for defines */
	BORDERLESS | SMART_REFRESH | NOCAREREFRESH,
	NULL,				/* struct Gadget *FirstGadget; */
	NULL,				/* struct Image *CheckMark; */
	NULL,				/* the title text for this window */
	NULL,				/* struct Screen *Screen; */
	NULL,				/* struct BitMap *BitMap; */
	/*  SHORT MinWidth, MinHeight;	/* minimums */
	0, 0,
	/*  SHORT MaxWidth, MaxHeight;	/* maximums */
	0, 0,
	CUSTOMSCREEN,			/* USHORT Type; */
};

USHORT	RangeFirst;	/* the first selection of the range-color pair */

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

BOOL OpenColorWindow()
{
	REGISTER LONG	i;

	if (ColorWindow)
		return(TRUE);
	ClearMenuStrip(w);
	ColorNewWindow.Screen = screen;
	ColorNewWindow.IDCMPFlags = NULL;
	ColorNewWindow.FirstGadget
			= &ColorTemplateGadgets[COLOR_GADGETS_COUNT - 1];
	SetColorProps();
	InitSuperColors();
	ColorMode = NULL;
	if ( ! (ColorWindow = OpenWindow(&ColorNewWindow))) {
		fputs("no memory!\n", console);
		return(FALSE);
	}
	ColorWindow->UserPort = w->UserPort;
	ModifyIDCMP(ColorWindow, COLOR_IDCMP_FLAGS);
	SetMenuStrip(w, &MainMenu[0]);
	for (i = 0; i < 32; i++) 
		SavePalette[i] = GetRGB4(vp->ColorMap, i);
	DrawColorWindow();
	return(TRUE);
}

VOID CloseColorWindow(accept)
BOOL accept;
{
	REGISTER LONG	i;

	if ( NOT ColorWindow)
		return;
	ClearMenuStrip(ColorWindow);
	ColorWindow->UserPort = NULL;
	CloseWindow(ColorWindow);
	ColorWindow = NULL;
	if (NOT accept) 
		LoadRGB4(vp, &SavePalette[0], 32L);
	else {
		color_set = 2;
		Color0 = GetRGB4(vp->ColorMap, 0L);
		Color1 = GetRGB4(vp->ColorMap, 1L);
		Color2 = GetRGB4(vp->ColorMap, 2L);
		for (i = 2; i <= 31; i++) {
			if (i == 2) 
				*(color_table) = GetRGB4(vp->ColorMap, 2L);
			else 
				*(color_table + color_offset + (i-2)*color_inc)
					= GetRGB4(vp->ColorMap, i);
		}
	}
}

VOID ColorRange(first, last)
SHORT first, last;
{
	REGISTER SHORT	i;
	LONG		whole, redfraction, greenfraction, bluefraction;
	REGISTER USHORT	rgb;
	SHORT		firstred, firstgreen, firstblue;
	SHORT		lastred, lastgreen, lastblue;
	SHORT		workred, workgreen, workblue;

	if (first > last) {
		i = first;
		first = last;
		last = i;
	}
	/* I need to see a spread of at least two, where there's at least one
	 * spot between the endpoints, else there's no work to do so I
	 * might as well just return now.
	 */
	if (first >= last - 1)
		return;
	rgb = GetRGB4(vp->ColorMap, (LONG)first);
	firstred = (rgb >> 8) & 0xF;
	firstgreen = (rgb >> 4) & 0xF;
	firstblue = (rgb >> 0) & 0xF;
	rgb = GetRGB4(vp->ColorMap, (LONG)last);
	lastred = (rgb >> 8) & 0xF;
	lastgreen = (rgb >> 4) & 0xF;
	lastblue = (rgb >> 0) & 0xF;
	whole = ((LONG) (lastred - firstred)) << 16;
	redfraction = whole / (last - first);
	whole = ((LONG)(lastgreen - firstgreen)) << 16;
	greenfraction = whole / (last - first);
	whole = ((LONG)(lastblue - firstblue)) << 16;
	bluefraction = whole / (last - first);
	for (i = first + 1; i < last; i++) {
		lastred = (redfraction * (i - first) + 0x8000) >> 16;
		workred = firstred + lastred;
		lastgreen = (greenfraction * (i - first) + 0x8000) >> 16;
		workgreen = firstgreen + lastgreen;
		lastblue = (bluefraction * (i - first) + 0x8000) >> 16;
		workblue = firstblue + lastblue;
		SetRGB4(vp, (LONG) i,
			(LONG) workred,
			(LONG) workgreen,
			(LONG) workblue  );
	}
}

BOOL ColorGadgetGotten(gadget)
struct Gadget *gadget;
{
	REGISTER USHORT	rgb, pen;
	struct RastPort	*RPort;
	SHORT		greenpos, redpos, bluepos;

	RPort = ColorWindow->RPort;
	/* Have we got a color specifier? */
	if (gadget->GadgetID < 32) {
		/* Yes, it's a color gadget.  Set this pen number */
		pen = gadget->GadgetID;
		/* first, were we in COPY COLOR mode? */
		if (ColorMode == COPYCOLOR) {
			rgb = GetRGB4(vp->ColorMap, (LONG)rp->FgPen);
			SetRGB4(vp, (LONG) pen,
				(LONG) (rgb >> 8),
				(LONG) (rgb >> 4),
				(LONG) rgb );
			ColorMode = NULL;
		}
		if (ColorMode == RANGE_FIRST) {
			ColorMode = RANGE_SECOND;
			RangeFirst = pen;
		}
		else if (ColorMode == RANGE_SECOND) {
			ColorMode = NULL;
			ColorRange(RangeFirst, pen);
		}
		SetAPen(rp, (LONG)pen);
		rgb = GetRGB4(vp->ColorMap, (LONG)pen);
		ColorRectFill(RPort, (LONG)pen);
		redpos = RemoveGadget(ColorWindow,
					&ColorTemplateGadgets[COLOR_RED]);
		greenpos = RemoveGadget(ColorWindow,
					&ColorTemplateGadgets[COLOR_GREEN]);
		bluepos = RemoveGadget(ColorWindow,
					&ColorTemplateGadgets[COLOR_BLUE]);
		SetColorProps();
		AddGadget(ColorWindow,
			&ColorTemplateGadgets[COLOR_BLUE], (LONG)bluepos);
		AddGadget(ColorWindow,
			&ColorTemplateGadgets[COLOR_GREEN], (LONG)greenpos);
		AddGadget(ColorWindow,
			&ColorTemplateGadgets[COLOR_RED], (LONG)redpos);
		RefreshGadgets(&ColorTemplateGadgets[COLOR_GADGETS_COUNT - 1], 
			ColorWindow);
	}
	else switch (gadget->GadgetID) {
		case COLOR_OK:
			CloseColorWindow(TRUE);
			return(FALSE);
		case COLOR_CANCEL:
			CloseColorWindow(FALSE);
			return(FALSE);
		case COLOR_COPY:
			ColorMode = COPYCOLOR;
			break;
		case COLOR_RANGE:
			ColorMode = RANGE_FIRST;
			break;
	}
	return(TRUE);
}

ModifyColors()
{
	USHORT		pen;
	REGISTER USHORT	newred, newgreen, newblue;

	pen = w->RPort->FgPen;
	newred = ((struct PropInfo *)
		ColorTemplateGadgets[COLOR_RED].SpecialInfo)->HorizPot >> 12;
	newgreen = ((struct PropInfo *)
		ColorTemplateGadgets[COLOR_GREEN].SpecialInfo)->HorizPot >> 12;
	newblue = ((struct PropInfo *)
		ColorTemplateGadgets[COLOR_BLUE].SpecialInfo)->HorizPot >> 12;
	SetRGB4(vp, (LONG)pen, (LONG)newred, (LONG)newgreen, (LONG)newblue);
}

DrawColorWindow()
{
	REGISTER struct RastPort	*RPort;

	RPort = ColorWindow->RPort;
	ColorRectFill(RPort, (LONG)rp->FgPen);
	SetAPen(RPort, 1L);
	DrawBox(RPort,	1L, 1L,
			(LONG)(COLORWINDOW_WIDTH - 2),
			(LONG)(COLORWINDOW_HEIGHT - 2));
	DrawBox(RPort,	(LONG)(COLOR_BOX_LEFT - 2),
			(LONG)(COLOR_BOX_TOP - 2),
			(LONG)(COLOR_BOX_RIGHT + 2),
			(LONG)(COLOR_BOX_BOTTOM + 2));
	DrawBox(RPort,	(LONG)(COLOR_BOX_LEFT - 2),
			(LONG)(COLOR_COLOR_TOP - 2),
			(LONG)(COLOR_BOX_LEFT + (8 * 15) + 1),
			(LONG)(COLOR_COLOR_TOP + (4 * 10) + 1));
}

SetColorProps()
{
	USHORT		rgb;
	REGISTER USHORT	red, green, blue;

	rgb = GetRGB4(vp->ColorMap, (LONG)rp->FgPen);
	red = (rgb >> 8) & 0xF;
	green = (rgb >> 4) & 0xF;
	blue = (rgb >> 0) & 0xF;

	((struct PropInfo *)ColorTemplateGadgets[COLOR_RED]
		.SpecialInfo)->HorizPot
			= (red << 12) | (red << 8) | (red << 4) | red;
	((struct PropInfo *)ColorTemplateGadgets[COLOR_GREEN]
		.SpecialInfo)->HorizPot
			= (green << 12) | (green << 8) | (green << 4) | green;
	((struct PropInfo *)ColorTemplateGadgets[COLOR_BLUE]
		.SpecialInfo)->HorizPot
			= (blue << 12) | (blue << 8) | (blue << 4) | blue;
}

ColorRectFill(RPort, pen)
struct RastPort	*RPort;
LONG pen;
{
	SetAPen(RPort, pen);
	SetDrMd(RPort, JAM2);
	WaitBOVP(vp);
	RectFill(RPort,	(LONG)COLOR_BOX_LEFT, (LONG)COLOR_BOX_TOP, 
			(LONG)COLOR_BOX_RIGHT, (LONG)COLOR_BOX_BOTTOM);
}

VOID DoColorWindow()
{
	BOOL				ColorGadgetGotten(), OpenColorWindow();
	REGISTER struct IntuiMessage	*message;
	REGISTER ULONG			class;
	REGISTER struct Gadget		*gadget;

	if (NOT OpenColorWindow())
		return;
	FOREVER {
		Wait((1L << ColorWindow->UserPort->mp_SigBit));
		while (message = GetMsg(ColorWindow->UserPort)) {
			class = message->Class;
			gadget = (struct Gadget *)(message->IAddress);
			ReplyMsg(message);
			switch (class) {
				case GADGETDOWN:
				case GADGETUP:
					if ( NOT ColorGadgetGotten(gadget))
						return;
					break;
				case MOUSEMOVE:
					ModifyColors();
					break;
			}
		}
	}
}

InitSuperColors() /* OK, initialize those Super Color Gadgets! */
{
	REGISTER SHORT	i;

	for (i = 0; i < 32; i++) {
		SuperColorImages[i].LeftEdge = 0;
		SuperColorImages[i].TopEdge = 0;
		SuperColorImages[i].Width = 15;
		SuperColorImages[i].Height = 10;
		SuperColorImages[i].Depth = 0;
		SuperColorImages[i].ImageData = NULL;
		SuperColorImages[i].PlanePick = 0;
		SuperColorImages[i].PlaneOnOff = i;
		SuperColorImages[i].NextImage = NULL;
	}
}
