/*******************************
*   TURBOMANDEL 1.0            *
*           by Philip Marivoet *
*              Nico Francois   *
*******************************/

#include <exec/types.h>
#include <exec/memory.h>
#include <exec/execbase.h>
#include <intuition/intuition.h>
#include <intuition/intuitionbase.h>
#include <hardware/custom.h>
#include <graphics/copper.h>
#include <graphics/gfxmacros.h>
#include <stdio.h>
#include <math.h>
#include <libraries/arpbase.h>
#include <proto/arp.h>
#include <proto/intuition.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/graphics.h>

extern struct Custom __far custom;

#define ISCHECKED(x) (x.Flags & CHECKED)
#define CHECK(x)     (x.Flags |=CHECKED)
#define UNCHECK(x)   (x.Flags &=~CHECKED)
#define TITLECHECK   ShowTitle(ManScr,(ISCHECKED(TitleItem) ? TRUE : FALSE))

/* assembler function call structure */
extern LONG __asm Int32Mand_asm(register __a0 LONG,register __a1 LONG,register __d0 LONG);
extern LONG __asm FloatMand_asm(register __a0 float,register __a1 float,register __d0 LONG);
extern void __asm DoCycle_asm();
extern void __asm PaletteLeft();
extern void __asm PaletteRight();
extern void __asm F2I(register __a0 ULONG *,register __d0 float);
extern float __asm I2F(register __a0 ULONG *);

/**********
* Palette *
**********/

#define OK        10
#define CANCEL    11
#define RED       12
#define GREEN     13
#define BLUE      14
#define INTPLUS   15
#define INTMIN    16
#define SLOPEPLUS 17
#define SLOPEMIN  18
#define TOPRIGHT  19
#define TOPLEFT   20

SHORT BorderVectors1[] = { 0,0,26,0,26,11,0,11,0,0 };
SHORT BorderVectors2[] = { 0,0,52,0,52,12,0,12,0,0 };
struct Border Border26x11 = { -2,-1,3,0,JAM1,5,BorderVectors1,NULL };
struct Border Border52x12 = { -2,-1,3,0,JAM1,5,BorderVectors2,NULL };

#define MakeGText(n,x,y,t) struct IntuiText n =\
   { 1,0,JAM1,x,y,NULL,(UBYTE *)t,NULL }
MakeGText (DecrText,8,1,"-");
MakeGText (IncrText,8,1,"+");
MakeGText (RightText,8,1,">");
MakeGText (LeftText,8,1,"<");
MakeGText (GreenText,8,1,"G");
MakeGText (RedText,8,1,"R");
MakeGText (BlueText,8,1,"B");
MakeGText (CancelText,1,2,"CANCEL");
MakeGText (OkText,17,2,"OK");

#define MakeRText(n,x,y,t) struct IntuiText n =\
   { 2,0,JAM1,x,y,NULL,(UBYTE *)t,NULL}
MakeRText (BodyText,5,5,"");
MakeRText (YesText,5,3,"");
MakeRText (NoText,5,3,"");

struct IntuiText PText = { 1,0,JAM1,35,58,NULL,(UBYTE *)"P",NULL };
struct IntuiText SText = { 1,0,JAM1,75,63,NULL,(UBYTE *)"S",&PText };
struct IntuiText IText = { 1,0,JAM1,151,63,NULL,(UBYTE *)"I",&SText };

#define MakeGBox(n,p,x,y,t,id) struct Gadget n = {p,x,y,23,10,NULL\
   ,RELVERIFY,BOOLGADGET,(APTR)&Border26x11,NULL,&t,NULL,NULL,id,NULL}
MakeGBox (DecrIntG,NULL,123,69,DecrText,INTMIN);
MakeGBox (IncrIntG,&DecrIntG,123,54,IncrText,INTPLUS);
MakeGBox (DecrSlopeG,&IncrIntG,88,69,DecrText,SLOPEMIN);
MakeGBox (IncrSlopeG,&DecrSlopeG,88,54,IncrText,SLOPEPLUS);
MakeGBox (RightTopG,&IncrSlopeG,43,69,RightText,TOPRIGHT);
MakeGBox (LeftTopG,&RightTopG,11,69,LeftText,TOPLEFT);
MakeGBox (GreenG,&LeftTopG,219,54,GreenText,GREEN);
MakeGBox (BlueG,&GreenG,261,54,BlueText,BLUE);
MakeGBox (RedG,&BlueG,178,54,RedText,RED);

struct Gadget CancelGb = { &RedG,235,69,49,11,NULL,RELVERIFY,BOOLGADGET,
   (APTR)&Border52x12,NULL,&CancelText,NULL,NULL,CANCEL,NULL };
struct Gadget OkGb = { &CancelGb,178,69,49,11,NULL,RELVERIFY,BOOLGADGET,
   (APTR)&Border52x12,NULL,&OkText,NULL,NULL,OK,NULL };
struct NewWindow NewPalWin = { 14,88,292,85,0,1,RAWKEY+GADGETDOWN+GADGETUP,
   WINDOWDRAG+ACTIVATE+RMBTRAP+NOCAREREFRESH,&OkGb,NULL,(UBYTE *)"Palette",
   NULL,NULL,5,5,640,200,CUSTOMSCREEN };

/*********
* Coords *
*********/

SHORT Vectors1[] = { 0,0,187,0,187,9,0,9,0,0 };
struct Border Border187x9 = { -1,-1,1,0,JAM1,5,Vectors1,NULL};

/* GADGETS */
struct Gadget CancelG = { NULL,125,86,49,11,NULL,RELVERIFY,BOOLGADGET,
   (APTR)&Border52x12,NULL,&CancelText,NULL,NULL,CANCEL,NULL };
struct Gadget OkG = { &CancelG,23,86,49,11,NULL,RELVERIFY,BOOLGADGET,
   (APTR)&Border52x12,NULL,&OkText,NULL,NULL,OK,NULL };

UBYTE bottomrighty[22], bottomrightx[22], toplefty[22], topleftx[22];
struct StringInfo BRyGInfo = { bottomrighty,NULL,0,22,0,0,0,0,0,0,0,0,NULL };
struct StringInfo BRxGInfo = { bottomrightx,NULL,0,22,0,0,0,0,0,0,0,0,NULL };
struct StringInfo TLyGInfo = { toplefty,NULL,0,22,0,0,0,0,0,0,0,0,NULL };
struct StringInfo TLxGInfo = { topleftx,NULL,0,22,0,0,0,0,0,0,0,0,NULL };

#define MakeCoordBox(n,p,x,y,info) struct Gadget n = {p,x,y,184,8,NULL,\
   RELVERIFY+STRINGCENTER,STRGADGET,(APTR)&Border187x9,NULL,NULL,NULL,\
   (APTR)&info,NULL,NULL }
MakeCoordBox(BRyG,&OkG, 8,72,BRyGInfo);
MakeCoordBox(BRxG,&BRyG,8,60,BRxGInfo);
MakeCoordBox(TLyG,&BRxG,8,36,TLyGInfo);
MakeCoordBox(TLxG,&TLyG,8,24,TLxGInfo);

struct IntuiText BRText =
   { 1,0,JAM1,10,49,NULL,(UBYTE *)"Bottom right:",NULL };
struct IntuiText TLText =
   { 1,0,JAM1,10,13,NULL,(UBYTE *)"Top left:",&BRText };

struct NewWindow newcoowin = { 60,79,200,100,0,1,GADGETDOWN+GADGETUP,
   WINDOWDRAG+ACTIVATE+RMBTRAP+NOCAREREFRESH,&TLxG,NULL,
   (UBYTE *)"Enter Coordinates",NULL,NULL,5,5,640,200,CUSTOMSCREEN };

/***************
 * filenamereq *
 ***************/

#define STRING 180

SHORT BorderVectors3[] = { 0,0,165,0,165,12,0,12,0,1 };
struct Border Border12x165 = { -3,-2,3,0,COMPLEMENT,5,BorderVectors3,NULL };
struct StringInfo StringGInfo = { NULL,NULL,0,64,0,0,0,0,0,0,0,0,NULL };
struct Gadget StringG = { NULL,20,20,160,9,NULL,RELVERIFY+STRINGCENTER,
   STRGADGET,(APTR)&Border12x165,NULL,NULL,NULL,(APTR)&StringGInfo,STRING,NULL };
struct NewWindow NewStringWin = { 0,0,200,40,0,1,GADGETUP,
   WINDOWDRAG+ACTIVATE+NOCAREREFRESH,&StringG,NULL,
   (UBYTE *)"Enter Filename",NULL,NULL,5,5,640,200,CUSTOMSCREEN };

/********
* Menus *
********/

#define makeMenuText(x,s,off) struct IntuiText x = {\
   3,1,COMPLEMENT,0,off,NULL,(UBYTE *)s,NULL }
#define makeMenuTextCheck(x,s,o) struct IntuiText x = {\
   3,1,COMPLEMENT,19,o,NULL,(UBYTE *)s,NULL }
#define makeITEM(x,y,h,w,t) struct MenuItem x = { y,0,h,w,9,ITEMTEXT\
   +ITEMENABLED+HIGHCOMP,0,(APTR)&t,NULL,NULL,NULL,MENUNULL }
#define makeITEMCheckME(x,y,h,w,t,me) struct MenuItem x = { y,0,h,w,9,CHECKIT\
   +ITEMTEXT+ITEMENABLED+HIGHCOMP,me,(APTR)&t,NULL,NULL,NULL,MENUNULL }
#define makeITEMc(x,y,h,w,t,c) struct MenuItem x = { y,0,h,w,9,ITEMTEXT+\
   ITEMENABLED+HIGHCOMP+COMMSEQ,0,(APTR)&t,NULL,c,NULL,MENUNULL }
#define makeITEMcCheckT(x,y,h,w,t,c) struct MenuItem x = {\
   y,0,h,w,9,CHECKIT+ITEMTEXT+MENUTOGGLE+ITEMENABLED+HIGHCOMP+COMMSEQ,\
   NULL,(APTR)&t,NULL,c,NULL,MENUNULL }
#define makeSUBCheckME(x,y,h,w,l,t,me) struct MenuItem x = { y,l,h,w,9,\
   CHECKIT+ITEMTEXT+ITEMENABLED+HIGHCOMP,me,(APTR)&t,NULL,NULL,NULL,MENUNULL }
#define makeITEMCheckT(x,y,h,w,t) struct MenuItem x = { y,0,h,w,9,CHECKIT+\
   ITEMTEXT+MENUTOGGLE+ITEMENABLED+HIGHCOMP,0,(APTR)&t,NULL,NULL,NULL,MENUNULL }
#define makeITEMCheckTME(x,y,h,w,t,me) struct MenuItem x = { y,0,h,w,9,CHECKIT+\
   ITEMTEXT+MENUTOGGLE+ITEMENABLED+HIGHCOMP,me,(APTR)&t,NULL,NULL,NULL,MENUNULL}
#define makeITEMSub(x,y,h,w,t,s) struct MenuItem x = {\
   y,0,h,w,9,ITEMTEXT+ITEMENABLED+HIGHCOMP,0,(APTR)&t,NULL,NULL,&s,MENUNULL }
#define makeSUBItem(x,y,h,w,l,t) struct MenuItem x = {\
   y,l,h,w,9,ITEMTEXT+ITEMENABLED+HIGHCOMP,0,(APTR)&t,NULL,NULL,NULL,MENUNULL }
#define makeMENU(m,n,x,w,s,i) struct Menu m = { n,x,0,w,0,MENUENABLED,s,i }

/*************
* Screenmenu *
*************/

makeMenuTextCheck (HiresText,"Hires",1);
makeMenuTextCheck (InterText,"Interlace",1);
makeMenuTextCheck (EHBText,"EHB",1);
makeMenuTextCheck (TurboText,"Turbo",1);
makeMenuTextCheck (ThreeDText,"3-D",1);
makeMenuText (NewScrText,"New Screen",1);
makeMenuText (PaletteText,"Palette",1);

makeITEMc (PalItem,NULL,54,95,PaletteText,'P');
makeITEM (NewScrItem,&PalItem,45,95,NewScrText);
makeITEMCheckT (ThreeDItem,&NewScrItem,36,95,ThreeDText);
makeITEMCheckTME (EHBItem,&ThreeDItem,27,95,EHBText,0x0002);
makeITEMcCheckT (TurboItem,&EHBItem,18,95,TurboText,'T');
makeITEMCheckTME (HiresItem,&TurboItem,9,95,HiresText,0x0008);
makeITEMCheckT (InterItem,&HiresItem,0,95,InterText);

makeMENU (ScreenMenu,NULL,164,66,"Screen",&InterItem);

/***************
 * fractalmenu *
 ***************/

makeMenuTextCheck (SuperText,"Super",1);
makeMenuTextCheck (BestText,"Best",1);
makeMenuTextCheck (GoodText,"Good",1);
makeMenuTextCheck (NormalText,"Normal",1);
makeMenuTextCheck (LowText,"Low",1);

makeSUBCheckME (SuperItem, NULL,24,67,73,SuperText,0x000F);
makeSUBCheckME (BestItem,&SuperItem,16,67,73,BestText,0x0017);
makeSUBCheckME (GoodItem,&BestItem,8,67,73,GoodText,0x001B);
makeSUBCheckME (NormItem,&GoodItem,0,67,73,NormalText,0x001D);
makeSUBCheckME (LowItem,&NormItem,-8,67,73,LowText,0x001E); 

makeMenuTextCheck (D32Text,"32",1);
makeMenuTextCheck (D64Text,"64",1);
makeMenuTextCheck (D128Text,"128",1);
makeMenuTextCheck (D256Text,"256",1);
makeMenuTextCheck (D512Text,"512",1);
makeMenuTextCheck (D1024Text,"1024",1);
makeMenuTextCheck (DCustText,"Custom",1);

makeSUBCheckME (DCustItem,NULL,40,68,73,DCustText,0x3F);
makeSUBCheckME (D1024Item,&DCustItem,32,68,73,D1024Text,0x5F);
makeSUBCheckME (D512Item,&D1024Item,24,68,73,D512Text,0x6F);
makeSUBCheckME (D256Item,&D512Item,16,68,73,D256Text,0x77);
makeSUBCheckME (D128Item,&D256Item, 8,68,73,D128Text,0x7B);
makeSUBCheckME (D64Item,&D128Item, 0,68,73,D64Text,0x7D);
makeSUBCheckME (D32Item,&D64Item,-8,68,73,D32Text,0x7E);

makeMenuTextCheck (IntText,"Integer",1);
makeMenuTextCheck (FloatText,"Float",1);

makeSUBCheckME (FloatItem,NULL,0,75,73,FloatText,0x0001);
makeSUBCheckME (IntItem,&FloatItem,-8,75,73,IntText,0x0002);

makeMenuText (AccText,"Accuracy",1);
makeMenuText (DepthText,"Depth",1);
makeMenuText (CalcText,"Calculation",1);
makeMenuText (CoordText,"Coords",1);
makeMenuText (ResetText,"Reset",1);
makeMenuText (RestText,"Restart",1);

makeITEM (RestItem,NULL,45,88,RestText);
makeITEM (ResetItem,&RestItem,36,88,ResetText);
makeITEMc (CoordItem,&ResetItem,27,88,CoordText,'C');
makeITEMSub (CalcItem,&CoordItem,18,88,CalcText,IntItem);
makeITEMSub (DepthItem,&CalcItem,9,88,DepthText,D32Item);
makeITEMSub (AccItem,&DepthItem,0,88,AccText,LowItem);

makeMENU (MandelMenu,&ScreenMenu,82,75,"Mandel",&AccItem);

/***************
 * ProjectMenu *
 ***************/

makeMenuText (AboutText,"About",1);
makeMenuText (LoadText,"Load",1);
makeMenuText (SaveText,"Save",1);
makeMenuTextCheck (TitleText,"Title",1);
makeMenuText (QuitText,"Quit",1);

makeITEMc (QuitItem,NULL,36,80,QuitText,'Q');
makeITEMCheckT (TitleItem,&QuitItem,27,80,TitleText);
makeITEMc (AboutItem,&TitleItem,18,80,AboutText,'A');
makeITEMc (SaveItem,&AboutItem,9,80,SaveText,'S');
makeITEMc (LoadItem,&SaveItem,0,80,LoadText,'L'); 

makeMENU (ProjectMenu,&MandelMenu,0,75,"Project",&LoadItem);

#define PROJECT    0
#define LOAD          0
#define SAVE          1
#define ABOUT         2
#define TITLE         3
#define QUIT          4
#define MANDEL     1
#define ACCURACY      0
#define SUPER             4
#define DEPTH         1
#define CUSTOMD           6
#define CALCULATION   2
#define INTCALC           0
#define FLOATCALC         1
#define COORD         3
#define RESET         4
#define RESTART       5
#define SCREEN     2
#define TURBO         2
#define NEWSCR        5
#define PALETTE       6

struct TextAttr TOPAZ80 = { (STRPTR)"topaz.font",TOPAZ_EIGHTY,0,0 };
struct NewScreen ScrStruct = { 0,0,320,256,5,0,1,NULL,CUSTOMSCREEN,&TOPAZ80,
   (UBYTE *)"TurboMandel V1.0",NULL,NULL};
struct NewWindow WinStruct = { 0,0,320,256,0,1,RAWKEY+MENUPICK+MOUSEBUTTONS
   +MOUSEMOVE,BORDERLESS+NOCAREREFRESH+ACTIVATE+BACKDROP,NULL,NULL,NULL,
   NULL,NULL,640,512,640,512,CUSTOMSCREEN};
USHORT Palette[32] = { 0x3a,0xfff,0x2,0xf00 };



/* for IFF read/write */

struct BitMapHeader {
   UWORD w, h, x, y;
   UBYTE nPlanes, masking, compression, pad1;
   UWORD transparentColor;
   UBYTE xAspect, yAspect;
   WORD pageWidth, pageHeight;
   };
struct ILBM_info {
   struct BitMapHeader header;
   struct BitMap bitmap;
   UBYTE cmap[32*3];
   };
extern BOOL iff_read(), iff_write();
struct ILBM_info myILBMinfo;


#define CALC_FFP     0
#define CALC_INT32   1
#define MAND_3D      1

struct MandelChunk {
   ULONG XCoo[2], YCoo[2], XSide[2], YSide[2];
   UWORD Iteration;
   UBYTE Calculation, Flags;
   SHORT TopPos[3], DecrStep[3], ColInt[3];      /* for Palette */
   } MandChunk;


struct FileRequester *req = NULL;

extern struct Library *MathTransBase;
extern struct Library *MathBase;
extern struct ExecBase *SysBase;
struct ArpBase *ArpBase;
struct IntuitionBase *IntuitionBase;
struct GfxBase *GfxBase;

struct Screen *ManScr = NULL;
struct Window *ManWin = NULL,*PalWin,*CoordWin,*StringWin;
struct ViewPort *Manvp;
struct RastPort *Manrp,*Palrp,*Coordrp;

void (*Dot)(), Dot2D(), Dot3D(), (*Box)(), Box2D(), Box3D();
LONG (*Mand)(), FloatMand(), Int32Mand();
LONG (*CalcMandel)(), CalcMandel2D(), CalcMandel3D();
void AdjustArpReq (ULONG, struct NewWindow *);
UBYTE *GetName ();
double cos();
LONG MaxIter, Depth, TurboDepth, DotsH, DotsV, ColorMax;
LONG XOffset, YOffset, NumCol, XRes, YRes, Factor;
SHORT StopCalc, Stopped, Restart = TRUE, CalcAllPoints, DivDegree, DivNumber;
SHORT i, BoxOn = FALSE, CycleOn = FALSE, CycleTemp, CycleLeft = TRUE;
SHORT PaletteOn = FALSE, CycleSpeed = 4, CurrSpeed = 4, NoZoom = FALSE;
UBYTE fname[64], ItBuffer[64];
float xmin, xmax, ymin, ymax, dx, dy;
LONG ScrH;

#define PI2    1.570796327
#define R      0
#define G      1
#define B      2
SHORT toppos[3] = { 7,14,21 }, decrstep[3] = { 17,17,17 };
SHORT colint[3] = { 15,15,15 };

main()
{
	if (ArpBase = (struct ArpBase *)OpenLibrary ("arp.library",0L)) {
		if (req = ArpAllocFreq()) {
			req->fr_Function = AdjustArpReq;
			req->fr_FuncFlags = FRF_NewWindFunc;
			req->fr_Window = 0;
			}
		}

	if (!(MathTransBase=(struct Library *)OpenLibrary("mathtrans.library",0L))) {
      puts ("No mathtrans.library !");
      exit (20);
      }
	if (!(MathBase=(struct Library *)OpenLibrary("mathffp.library",0L))) {
		CloseLibrary (MathTransBase);
      puts ("No math.library !");
      exit (20);
      }
   IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",0L);
   GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",0L);

	/* PAL or NTSC ? */
	ScrH = (SysBase->VBlankFrequency == 60) ? 200 : 256;

   PalSinus (R); PalSinus (G); PalSinus (B);
   xmax = 1.25; xmin = -2.25; ymax = 1.5; ymin = -1.5;
   MaxIter = 64 ; CHECK (D64Item);
   DivNumber = 2 ; CHECK (NormItem);
   Mand = Int32Mand; CHECK (IntItem);

   while (Restart) {
      if (!OpenDisplay()) {
         UNCHECK(HiresItem); UNCHECK(InterItem);
         if (! OpenDisplay()) CloseStuff();
         Message("Not enough memory for screen ",NULL,"Proceed");
      }
      StopCalc = Stopped = Restart = FALSE;
      dx = (xmax-xmin) / DotsH; dy = (ymax-ymin) / DotsV;
      NoZoom = ISCHECKED(ThreeDItem) != NULL;
      SubDivide (0L,0L,(LONG)(DotsH-1),(LONG)(DotsV-1));
      UNCHECK(TurboItem); SetDepth();
      while (!Stopped && !Restart) {
         WaitPort(ManWin->UserPort);
         TestInput();
      }
   }
   CloseStuff();
}

/* General routines */

CloseStuff()
{
   DisableCycle();
   if (ManWin) {
      ClearMenuStrip (ManWin);
      CloseWindow (ManWin);
   }
   if (ManScr) CloseScreen (ManScr);
   if (MathTransBase) CloseLibrary ((struct Library *)MathTransBase);
   if (MathBase) CloseLibrary ((struct Library *)MathBase);
   CloseLibrary ((struct Library *)GfxBase);
   CloseLibrary ((struct Library *)IntuitionBase);
   if (ArpBase) CloseLibrary ((struct Library *)ArpBase);
}

OpenDisplay()
{
   CycleTemp = CycleOn; DisableCycle();
   if (ManWin != NULL) {
      ClearMenuStrip(ManWin);
      CloseWindow(ManWin);
      ManWin = NULL;
   }
   if (ManScr != NULL) {
      CloseScreen(ManScr);
      ManScr = NULL;
   }
   ScrStruct.ViewModes = (ISCHECKED(InterItem) ? LACE  : NULL) 
      + (ISCHECKED(HiresItem)  ? HIRES : NULL)
      + (ISCHECKED(EHBItem) ? EXTRA_HALFBRITE : NULL);
   YRes = WinStruct.Height = ScrStruct.Height = (ISCHECKED(InterItem) ? (ScrH * 2) : ScrH);
   XRes = WinStruct.Width = ScrStruct.Width = (ISCHECKED(HiresItem) ? 640 : 320);
   Factor = (YRes == (ScrH * 2) ? 1 : 2) * (XRes == 640 ? 2 : 1);
   Depth = ScrStruct.Depth =
      ((ISCHECKED(HiresItem) ? 4:5) + (ISCHECKED(EHBItem) ? 1 : 0));
   TurboDepth = (ISCHECKED(HiresItem) ? 2 : 4);

   /* screen and window */
   if (!(ManScr = OpenScreen(&ScrStruct))) return(FALSE);
   WinStruct.Screen = ManScr;
   if (!(ManWin = OpenWindow(&WinStruct))) return(FALSE);
   Manrp = ManWin->RPort;   
   Manvp = &(ManScr->ViewPort);
   LoadRGB4(Manvp,Palette,(NumCol = ISCHECKED(HiresItem) ? 16L: 32L));
   ColorMax = NumCol * (ISCHECKED(EHBItem) ? 2:1);
   SetDepth();
   UNCHECK(TitleItem); TITLECHECK;
   SetMenuStrip (ManWin,&ProjectMenu);
   if (CycleTemp) EnableCycle();
   if (ISCHECKED(ThreeDItem)) {
      XOffset = (DotsH = XRes/2)/2; YOffset = (DotsV = YRes/2)/2;
      Dot = Dot3D; Box = Box3D;
      CalcMandel = CalcMandel3D;
   }
   else {
      DotsH = XRes; DotsV = YRes;
      Dot = Dot2D; Box = Box2D;
      CalcMandel = CalcMandel2D;
   }
   return(TRUE);
}

SetDepth()            /* Turbo */
{
   struct UCopList *cl;
   long dispconreg;

   CycleTemp = CycleOn; DisableCycle();
   FreeVPortCopLists(Manvp);
   dispconreg = (Manvp->Modes & ~EXTRA_HALFBRITE) & 0x8fff;
   dispconreg |= (ISCHECKED(TurboItem)? TurboDepth : Depth) << 12;
   cl = (struct UCopList *)AllocMem ((LONG)sizeof(struct UCopList)
      ,MEMF_PUBLIC|MEMF_CLEAR);
   CWAIT (cl, 0L, 1L); CMOVE (cl, custom.bplcon0, dispconreg); CEND (cl);
   Manvp->UCopIns = cl;
   MakeScreen(ManScr); RethinkDisplay();
   if (CycleTemp) EnableCycle();
}

CalcNewPar(x1,y1,x2,y2)
LONG x1,y1,x2,y2;
{
   LONG res;

   if (x2<x1) { res=x1; x1=x2; x2=res; }
   if (y2<y1) { res=y1; y1=y2; y2=res; }
   xmax = xmin + x2*dx; xmin = xmin + x1*dx;
   ymin = ymax - y2*dy; ymax = ymax - y1*dy;
}

Message(Text,Yes,No)
UBYTE *Text,*Yes,*No;
{
   ULONG width;

   width = 40L + TextLength (Manrp,Text,(LONG)strlen(Text));
   BodyText.IText = Text; BodyText.LeftEdge = 10L;
   YesText.IText = Yes; NoText.IText = No;
   return (AutoRequest(ManWin,&BodyText,Yes ? &YesText:NULL,&NoText,
      NULL,NULL,width,50L));
}

CompBox(x,y,Distx,Disty)
LONG x,y,Distx,Disty;
{
   SetDrMd (Manrp,COMPLEMENT);
   BoxOn = !BoxOn;
   Move(Manrp,x-Distx,y-Disty);
   Draw(Manrp,x+Distx,y-Disty); Draw(Manrp,x+Distx,y+Disty);
   Draw(Manrp,x-Distx,y+Disty); Draw(Manrp,x-Distx,y-Disty);
   SetDrMd (Manrp,JAM1);
}

/* Change coordinates */

SetCoords ()
{
   SHORT Exit = FALSE,RCode = FALSE;
   UWORD id;
   float res;
   struct IntuiMessage *msg,im;
   struct Gadget *ActG;

   newcoowin.LeftEdge = (XRes-200)/2; newcoowin.TopEdge =  (YRes-100)/2;
   newcoowin.Screen = ManScr;
   if (!(CoordWin = OpenWindow (&newcoowin))) {
      Message ("Can't open window !",NULL,"Proceed");
      return (FALSE);
   }
   Coordrp = CoordWin->RPort;
   PrintIText(Coordrp,&TLText,0L,0L);
   sprintf (topleftx, "%f", xmin); sprintf (toplefty, "%f", ymax);
   sprintf (bottomrightx, "%f", xmax); sprintf (bottomrighty, "%f", ymin);
   RefreshGList (&TLxG, CoordWin, NULL, 4L);
   ActivateGadget (&TLxG, CoordWin, NULL);
   ActG = &TLxG;

   while (!Exit) {
      WaitPort (CoordWin->UserPort);
      msg = (struct IntuiMessage *)GetMsg(CoordWin->UserPort);
         im = *msg;
         ReplyMsg (msg);
         id = ((struct Gadget *)im.IAddress)->GadgetID;
         switch (im.Class) {
            case GADGETUP:
               switch (id) {
                  case OK:
                     sscanf (topleftx, "%f", &xmin);
                     sscanf (toplefty, "%f", &ymax);
                     sscanf (bottomrightx, "%f", &xmax);
                     sscanf (bottomrighty, "%f", &ymin);
                     Exit = RCode = TRUE;
                  break;
                  case CANCEL:
                     Exit = TRUE;
                     RCode = FALSE;
                     break;
                  default:
                     ActG = (ActG == &BRyG ? &TLxG : ActG->NextGadget);
                     ActivateGadget (ActG, CoordWin, NULL);
                     break;
               }
         }
   }
   if (xmax < xmin) { res=xmax; xmax=xmin; xmin=res; }
   if (ymax < ymin) { res=ymax; ymax=ymin; ymin=res; }
   CloseWindow (CoordWin);
   return ((int)RCode);
}

/* Palette */

SetPalette()
{
   struct IntuiMessage *msg, im;
   UBYTE exit = FALSE,TurboOn;
   int i, id, oldpos[3], oldstep[3], oldint[3];
   ULONG colw, lcol;
   static int color = R;

   CycleTemp = CycleOn; DisableCycle();
   PaletteOn = TRUE;
   TurboOn = ISCHECKED(TurboItem);
   UNCHECK(TurboItem); SetDepth();
   NewPalWin.LeftEdge = (XRes - 292) / 2;
   NewPalWin.TopEdge = (YRes - 85) / 2;
   NewPalWin.Screen = ManScr;
   if (!(PalWin = OpenWindow(&NewPalWin))) {
      Message ("Can't open window !",NULL,"Proceed");
      return;
   }
   Palrp = PalWin->RPort;
   PrintIText (Palrp,&IText,0L,0L);
   colw = (NumCol == 16) ? 23 : 10; lcol = (NumCol == 16) ? 8 : 6;
   for (i = 0; i < NumCol - 4; i++ ) {
      SetAPen (Palrp,(LONG)i + 4L);
      RectFill (Palrp, lcol + i * colw, 15L, lcol - 1 + (i + 1) * colw, 47L);
   }
   SelectRGB (color);
   for (i = 0; i < 3; i++) {
      oldint[i] = colint[i]; oldstep[i] = decrstep[i]; oldpos[i] = toppos[i];
   }
   while (!exit) {
      WaitPort (PalWin->UserPort);
      msg = (struct IntuiMessage *)(GetMsg (PalWin->UserPort));
      im = *msg;
      ReplyMsg (msg);
      switch (im.Class) {
         case RAWKEY: HandleRawkey (&im); break;
         case GADGETUP:
            id = ((struct Gadget *)im.IAddress)->GadgetID;
            switch (id) {
               case CANCEL:
                  for (i = 0; i < 3; i++) {
                     colint[i] = oldint[i];
                     decrstep[i] = oldstep[i];
                     toppos[i] = oldpos[i];
                     }
                  PalSinus (R); PalSinus (G); PalSinus (B);
               case OK:
                  exit = TRUE;
                  break;
               case RED:
                  color = R; SelectRGB (color);
                  break;
               case GREEN:
                  color = G; SelectRGB (color);
                  break;
               case BLUE:
                  color = B; SelectRGB (color);
                  break;
               case TOPLEFT:
                  toppos[color] = (--toppos[color] < 4) ? 31 : toppos[color];
                  break;
               case TOPRIGHT:
                  toppos[color] = (++toppos[color] > 31) ? 4 : toppos[color];
                  break;
               case SLOPEMIN:
                  if (--decrstep[color] < 15) {
                     decrstep[color] = 15; DisplayBeep (ManScr);
                     }
                  break;
               case SLOPEPLUS:
                  if (++decrstep[color] > 40) {
                     decrstep[color] = 40; DisplayBeep (ManScr);
                     }
                  break;
               case INTPLUS:
                  if (++colint[color] > 0xf) {
                     colint[color] = 0xf; DisplayBeep (ManScr);
                     }
                  break;
               case INTMIN:
                  if (--colint[color] < 0) {
                     colint[color] = 0; DisplayBeep (ManScr);
                  }
                  break;
               }
            PalSinus (color);
            LoadRGB4 (&ManScr->ViewPort, &Palette[0], 32L);
            break;
         }
      }
   if (TurboOn) { CHECK(TurboItem); SetDepth(); }
   PaletteOn = FALSE;
   if (CycleTemp) EnableCycle();
   CloseWindow (PalWin);
}

UWORD colmask[3] = { 0x0ff, 0x0f0f, 0xff0 };

PalSinus (color)
int color;
{
   double x, xstep;
   int pos1, pos2, i;
   UWORD col, mask;

   x = 0; xstep = PI2 / decrstep[color];
   pos1 = pos2 = toppos[color];
   for (i = 0; i < 16; i++) {
      col = cos (x) * colint[color];
      mask = colmask[color];
      if (color == R) col <<= 8; else if (color == G) col <<= 4;
      Palette[pos1] = (Palette[pos1] & mask) | col;
      Palette[pos2] = (Palette[pos2] & mask) | col;
      x += xstep;
      pos1 = (++pos1 > 31) ? 4 : pos1; pos2 = (--pos2 < 4) ? 31 : pos2;
      }
}

SelectRGB (color)
int color;
{
   RedG.Flags &= ~SELECTED; BlueG.Flags &= ~SELECTED; GreenG.Flags &= ~SELECTED;
   switch (color) {
      case R: RedG.Flags |= SELECTED;break;
      case G: GreenG.Flags |= SELECTED;break;
      case B: BlueG.Flags |= SELECTED;break;
   }
   SetAPen (Palrp, 0L);
   RectFill (Palrp, 174L, 52L, 286L, 66L);
   RefreshGList (&RedG, PalWin, NULL, 3L);
}

/* intuition event handling */

#define TAB    0x42
#define UP     0x4c
#define DOWN   0x4d
#define LEFT   0x4f
#define RIGHT  0x4e

HandleRawkey (msg)
struct IntuiMessage *msg;
{
   switch (msg->Code) {
      case TAB:
         if (!PaletteOn) {
            if (msg->Qualifier & (IEQUALIFIER_LSHIFT+IEQUALIFIER_RSHIFT))
               CycleLeft = !CycleLeft;
            else if (CycleOn) DisableCycle();
            else EnableCycle();
            }
         break;
      case UP:
         if (CycleOn) if (CycleSpeed > 1) CurrSpeed = --CycleSpeed;
         else DisplayBeep (ManScr);
         break;
      case DOWN:
         if (CycleOn) CurrSpeed = ++CycleSpeed;
         break;
      case LEFT:
         if (!CycleOn) {
				PaletteLeft();				
            LoadRGB4 (Manvp, Palette, 32L);
         }
         break;
      case RIGHT:
         if (!CycleOn) {
				PaletteRight();
            LoadRGB4 (Manvp, Palette, 32L);
         }
         break;
      }
}

TestInput()
{
   struct IntuiMessage *msg,im;
   short DoLoop= TRUE, Zooming = FALSE;
   LONG XCoord,YCoord,Distx,Disty;

   while (DoLoop){
      if (msg=(struct IntuiMessage *)(GetMsg(ManWin->UserPort))) {
         im = *msg;
         ReplyMsg(msg);
         switch (im.Class) {
            case RAWKEY: HandleRawkey (&im); break;
            case MENUPICK: switch (MENUNUM(im.Code)) {
               case PROJECT:
                  switch (ITEMNUM(im.Code)) {
                     case LOAD: GetIff(); break;
                     case SAVE: SaveIff(); break;
                     case TITLE: TITLECHECK; break;
                     case ABOUT:
                        Message ("Programmed by Ph.Marivoet, N.Francois", NULL, "Proceed");
                        break;
                     case QUIT:
                        if (Message("Do you want to quit","Yes","No"))
                           Stopped = StopCalc = TRUE;
                        break;
                  }
                  break;
               case MANDEL:
                  switch (ITEMNUM(im.Code)) {
                     case COORD:
                        if (SetCoords()) Restart = StopCalc = TRUE;
                        break;
                     case RESET:
                        if (Message("Reset Mandel","Yes","No")) {
                           xmax = 1.25; xmin = -2.25;
                           ymax = 1.5; ymin = -1.5;
                           StopCalc = Restart = TRUE;
                        }
                        break;
                     case RESTART:
                        if (Message("Restart Calculation","Yes","No"))
                           StopCalc = Restart = TRUE;
                        break;
                     case ACCURACY:
                        CalcAllPoints=((DivDegree=SUBNUM(im.Code))==SUPER);
                        DivNumber = 1<<DivDegree;
                        break;
                     case DEPTH:
                        if (SUBNUM(im.Code)==CUSTOMD) {
                           if (GetName("Iteration",ItBuffer,FALSE))
                              sscanf(ItBuffer,"%ld",&MaxIter);
                        }
                        else MaxIter = 1 << (SUBNUM(im.Code)+5);
                        break;
                     case CALCULATION:
                        if (ISCHECKED(FloatItem)) Mand = FloatMand;
                        else Mand = Int32Mand;
                        break;
                  }
                  break;
               case SCREEN:
                  switch(ITEMNUM(im.Code)) {
                     case NEWSCR:
                        if (Message("New Screen","Yes","No"))
                           StopCalc=Restart=TRUE;
                        break;
                     case TURBO: SetDepth(); break;
                     case PALETTE: SetPalette(); break;
                  }
                  break;
               } 
               break;
            case MOUSEBUTTONS:
               if (!NoZoom)
                  switch (im.Code) {
                     case SELECTDOWN:
                        Zooming = TRUE;
                        XCoord = im.MouseX;
                        YCoord = im.MouseY;
                        Distx = Disty = 0;
                        ReportMouse (ManWin , TRUE);
                        break;
                     case SELECTUP:
                        Zooming = FALSE;
                        ReportMouse (ManWin , TRUE);
                        if (Distx != 0 && Disty != 0)
                           if (Message("Zoom area in ?","Yes","No")) {
                              CalcNewPar(XCoord-Distx,YCoord-Disty,
                                         XCoord+Distx,YCoord+Disty);   
                              StopCalc = Restart = TRUE;
                           }
                        if (BoxOn) CompBox(XCoord,YCoord,Distx,Disty);
                        break;
                  }
               break;   
            case MOUSEMOVE:
               if (Zooming) {
                  if (BoxOn) CompBox(XCoord,YCoord,Distx,Disty);
                  Distx = XCoord-im.MouseX;
                  Disty = YCoord-im.MouseY;
                  CompBox(XCoord,YCoord,Distx,Disty);
                  }
               break;
         }
      }
   DoLoop = Zooming;
   }
}

/* Function for ARP filerequester (requester on our screen) */

void AdjustArpReq (ULONG Mask, struct NewWindow *win)
{
	win->Screen = ManScr;
	win->Type = CUSTOMSCREEN;
	win->LeftEdge = (XRes-win->Width)/2;
	win->TopEdge = (YRes-win->Height)/2;
}



UBYTE *GetName (title, str, FileReq)
UBYTE *title, *str;
BOOL FileReq;
{
	static UBYTE Path[108];
	UBYTE File[256];

	if (req && FileReq) {
		req->fr_Hail = title;
		req->fr_Dir = Path;
		strcpy (str,FileRequest (req));
		if (*str) {
			strcpy (File,Path);
			TackOn (File,str);
			strcpy (str,File);
			return (str);
			}
		else return (NULL);
	}

   StringGInfo.Buffer = str;
   NewStringWin.LeftEdge = (XRes-200)/2; NewStringWin.TopEdge = (YRes-40)/2;
   NewStringWin.Screen = ManScr;
   NewStringWin.Title = title;
   if (!(StringWin = OpenWindow (&NewStringWin))) {
      Message ("Can't open window !",NULL,"Proceed");
      return (NULL);
   }
   ActivateGadget (&StringG, StringWin, NULL);
   WaitPort (StringWin->UserPort);
   CloseWindow (StringWin);
	if (*str) return (str);
	else return (NULL);
}

/* IFF load/save */

GetIff()
{
   LONG d, i;
   struct IntuiMessage *msg;

   if (!GetName("Load file", fname, TRUE)) return;
   MandChunk.XSide[0] = NULL;
   if (read_iff (&myILBMinfo,fname,1)) {
      if (!MandChunk.XSide[0])
         if (!Message ("MANDEL chunk not found, load anyway ?","Yes","No"))
            return;
		if ((myILBMinfo.header.h > (ScrH * 2)) || (myILBMinfo.header.w > 640)) {
			Message ("Picture too large, can't load",NULL,"Ok");
			return;
		}
		if ((myILBMinfo.header.w > 320) && (myILBMinfo.header.nPlanes > 5)) {
			Message ("Picture too large, can't load",NULL,"Ok");
			return;
		}		
      NoZoom = StopCalc = TRUE;
      UNCHECK(TurboItem);
      if ((d = myILBMinfo.header.nPlanes) > 5) { d = 5; CHECK(EHBItem); }
      for (i = 0; i < 1<<d; i++)
         Palette[i] = ((myILBMinfo.cmap[3 * i] & 0xf0) << 4)
                     + (myILBMinfo.cmap[3 * i + 1] & 0xf0)
                     +((myILBMinfo.cmap[3 * i + 2] & 0xf0) >> 4);
      if (myILBMinfo.header.h > ScrH) CHECK (InterItem);
      else UNCHECK (InterItem);
      if (myILBMinfo.header.w > 320) CHECK (HiresItem);
      else UNCHECK (HiresItem);
      if (!OpenDisplay()) {
         UNCHECK (HiresItem); UNCHECK (InterItem);
         if (!OpenDisplay()) Stopped = TRUE;
         else Message ("No memory for screen !",NULL,"Proceed");
         }
      else {
         ModifyIDCMP (ManWin, MENUVERIFY);
         if (MandChunk.XSide[0]) {
            xmax = (xmin = I2F(MandChunk.XCoo)) + I2F(MandChunk.XSide);
            ymax = (ymin = I2F(MandChunk.YCoo)) + I2F(MandChunk.YSide);
            dx = (xmax-xmin) / DotsH;
            dy = (ymax-ymin) / DotsV;
            UNCHECK (D32Item); UNCHECK (D64Item); UNCHECK (D128Item);
            UNCHECK (D256Item); UNCHECK (D512Item); UNCHECK (D1024Item);
            UNCHECK (DCustItem);
            switch (MaxIter = MandChunk.Iteration) {
               case 32:   CHECK (D32Item); break;
               case 64:   CHECK (D64Item); break;
               case 128:  CHECK (D128Item); break;
               case 256:  CHECK (D256Item); break;
               case 512:  CHECK (D512Item); break;
               case 1024: CHECK (D1024Item); break;
               default:
                  CHECK (DCustItem);
                  sprintf (ItBuffer, "%ld", MaxIter);
                  break;
            }
            UNCHECK (FloatItem); UNCHECK (IntItem);
            if (MandChunk.Calculation == CALC_INT32) {
               CHECK (IntItem); Mand = Int32Mand;
            }
            else {
               CHECK (FloatItem); Mand = FloatMand;
            }
            if (MandChunk.Flags & MAND_3D)
               CHECK (ThreeDItem);
            else {
               UNCHECK (ThreeDItem); NoZoom = FALSE;
               }
            for (i = 0; i < 3; i++) {
               toppos[i] = MandChunk.TopPos[i];
               decrstep[i] = MandChunk.DecrStep[i];
               colint[i] = MandChunk.ColInt[i];
            }
         }
         myILBMinfo.bitmap = ManScr->BitMap;
         myILBMinfo.bitmap.BytesPerRow = ((myILBMinfo.header.w+15)>>4)<<1;
         myILBMinfo.bitmap.Rows = myILBMinfo.header.h;
         myILBMinfo.bitmap.Depth = myILBMinfo.header.nPlanes;
         if (!read_iff (&myILBMinfo,fname, 0))
            Message ("Error loading file !",NULL,"Proceed");
      }
   }
   else Message ("Can't load IFF file !",NULL,"Proceed");
   while (msg = (struct IntuiMessage *)GetMsg (ManWin->UserPort))
      ReplyMsg (msg);
   ModifyIDCMP (ManWin, RAWKEY+MOUSEMOVE+MENUPICK+MOUSEBUTTONS);
}

SaveIff()
{
   struct IntuiMessage *msg;

   if (!GetName("Save file", fname, TRUE)) return;
   ModifyIDCMP (ManWin, MENUVERIFY);
   UNCHECK (TitleItem); TITLECHECK;
   F2I(MandChunk.XCoo, xmin); F2I(MandChunk.XSide, xmax - xmin);
   F2I(MandChunk.YCoo, ymin); F2I(MandChunk.YSide, ymax - ymin);
   MandChunk.Iteration = MaxIter;
   if (ISCHECKED(IntItem)) MandChunk.Calculation = CALC_INT32;
   else MandChunk.Calculation = CALC_FFP;
   MandChunk.Flags = 0;
   if (CalcMandel == CalcMandel3D) MandChunk.Flags |= MAND_3D;
   for (i = 0; i < 3; i++) {
      MandChunk.TopPos[i] = toppos[i];
      MandChunk.DecrStep[i] = decrstep[i];
      MandChunk.ColInt[i] = colint[i];
   }
   if (!write_iff (fname,&Palette[0], ManScr, 1))
      Message ("Couldn't save IFF file !",NULL,"Proceed");
   while (msg = (struct IntuiMessage *)GetMsg (ManWin->UserPort))
      ReplyMsg (msg);
   ModifyIDCMP (ManWin, RAWKEY+MOUSEMOVE+MENUPICK+MOUSEBUTTONS);
   DisplayBeep (ManScr);
}

/* 2D-3D subroutines */

LONG CalcMandel2D(ix,iy)
LONG ix,iy;
{
   LONG color;
   float x,y;

   if (!(color = ReadPixel(Manrp,ix,iy))) {
      x = xmin+ix*dx;
      y = ymax-iy*dy;
      color = Mand(x,y,MaxIter);
      SetAPen(Manrp,color);
      WritePixel(Manrp,ix,iy);
   }
   return(color);
}

LONG CalcMandel3D(ix,iy)
LONG ix,iy;
{
   return (Mand ((float)xmin+ix*dx, (float)ymax-iy*dy, MaxIter));
}

void Dot2D(x,y,col)
LONG x,y,col;
{
   SetAPen(Manrp,col); WritePixel(Manrp,x,y);
}

void Dot3D(x,y,col)
LONG x,y,col;
{
   SetAPen (Manrp, col == 2L ? 2L : (col == 4L ? 31L : col-1L));
   Move (Manrp, x+XOffset+(YOffset-y)*Factor/2, y+YOffset-col);
   Draw (Manrp, x+XOffset+(YOffset-y)*Factor/2, y+YOffset);
   SetAPen (Manrp,col);
   WritePixel (Manrp, x+XOffset+(YOffset-y)*Factor/2, y+YOffset-col);
}

void Box2D(x1,y1,x2,y2,col)
LONG x1,y1,x2,y2,col;
{
   SetAPen(Manrp,col); RectFill(Manrp,x1,y1,x2,y2);
}

void Box3D(x1,y1,x2,y2,col)
LONG x1,y1,x2,y2,col;
{
   LONG i, bcol;

   bcol = (col == 2L ? 2L : (col == 4L ? 31L : col-1L));
   SetAPen (Manrp, bcol);
   RectFill (Manrp, x1+XOffset+(YOffset-y2)*Factor/2, y2+YOffset-col,
                    x2+XOffset+(YOffset-y2)*Factor/2, y2+YOffset);
   for (i=y1; i<=y2; i++) {
      SetAPen (Manrp, bcol);
      Move (Manrp, x2+XOffset+(YOffset-i)*Factor/2, i+YOffset);
      Draw (Manrp, x2+XOffset+(YOffset-i)*Factor/2, i+YOffset-col);
      SetAPen(Manrp,col);
      Draw (Manrp, x1+XOffset+(YOffset-i)*Factor/2, i+YOffset-col);
   }
}

/* Recursive calculation of mandelbrot */

SubDivide(x1,y1,x2,y2)
LONG x1,x2,y1,y2;
{
   static LONG i,TestColor;
   LONG mx1,my1,mx2,my2,SameColor = TRUE,Step;

   if (StopCalc) return;
   if ((x1==x2) && (y1==y2)) {
      Dot(x1,y1,CalcMandel(x1,y1)); return;
   }
   mx1 = mx2 = (x1+x2)/2;
   my1 = my2 = (y1+y2)/2;
   TestColor = CalcMandel (mx1,my1);

   if (CalcAllPoints || !(Step=(x2-x1)/DivNumber)) Step = 1;
   for (i = 0; (i <= x2-x1) && !StopCalc; i += Step) {
      SameColor &= TestColor == CalcMandel (x1+i,y1);
      SameColor &= TestColor == CalcMandel (x2-i,y2);
      TestInput();
   }

   if (CalcAllPoints || !(Step=(y2-y1)/DivNumber)) Step = 1;
   for (i = 0 ;(i <= y2-y1) && !StopCalc; i += Step) {
      SameColor &= TestColor == CalcMandel (x1,y2-i);
      SameColor &= TestColor == CalcMandel (x2,y1+i);
      TestInput();
   }
   if (SameColor && !StopCalc) Box(x1,y1,x2,y2,TestColor);
   else {
      if ((x2-x1) == 1) mx2 = mx1 +1; if ((y2-y1) == 1) my2 = my1 +1;
      SubDivide (x1 ,y1 ,mx1,my1); SubDivide (x1 ,my2,mx1,y2 );
      SubDivide (mx2,y1 ,x2 ,my1); SubDivide (mx2,my2,x2 ,y2 );
   }
}


float fixedfactor = (float)(1L << 27);

LONG Int32Mand (px, py, max_iter)
float px, py;
LONG max_iter;
{
   register LONG color = 2;
	LONG itcountint;

	itcountint = Int32Mand_asm((long)(px * fixedfactor),(long)(py * fixedfactor),max_iter);
   if (itcountint) color = (max_iter - itcountint) % (ColorMax-4) + 4;
   return (color);
}


LONG FloatMand (px,py,max_iter)
float px,py;
LONG max_iter;
{
   LONG color = 2,itcount;

	itcount = FloatMand_asm(px,py,max_iter);
   if (itcount) color = (max_iter - itcount) % (ColorMax-4) + 4;
   return(color);
}

/* Cycle subtask */
void __saveds DoCycle()
{
	DoCycle_asm();
}

EnableCycle()
{
   struct Task *CycleTask;

   if (!CycleOn)
      CycleTask = (struct Task *)CreateTask ("TM VBlank", 2L, DoCycle, 1000L);
   CycleOn = TRUE;
}

DisableCycle()
{
   CycleOn = FALSE; WaitTOF(); WaitTOF();
}

