/* * M A N D E L B R O T C O N S T R U C T I O N S E T * * (C) Copyright 1989 by Olaf Seibert. * Mandel may be freely distributed. See file 'doc/Notice' for details. * * Main Program, including some general routines */ #include #include #ifdef DEBUG # include # undef STATIC # define STATIC /* EMPTY */ #endif #include "mandel.h" extern struct NewWindow XYNWindow; extern struct Window *XYwindow; #define BORDERLEFT 3 #define BORDERTOP 11 #define BORDERBOTTOM 3 #define CHARS 16 /* Change UpdateXYwindow also with this */ struct NewWindow XYNWindow = { 2 * BORDERLEFT, 2 * BORDERTOP, CHARS*8+BORDERLEFT*2, 2*8+BORDERTOP+BORDERBOTTOM, 2, 1, /* DetailPen, BlockPen */ 0, /* CLOSEWINDOW */ WINDOWCLOSE | WINDOWDRAG | WINDOWDEPTH | NOCAREREFRESH | SIMPLE_REFRESH, NULL, /* FirstGadget */ NULL, /* default CheckMark */ (UBYTE *) "Re and Im", /* Title */ NULL, /* Screen */ NULL, /* BitMap */ 0, 0, /* MinWidth, MinHeight */ 0, 0, /* MaxWidth, MaxHeight */ CUSTOMSCREEN /* Screen type */ }; double ReMouse, ImMouse; /* * We always ask for INTUITICKS, since this window will only be open * as long as we have the flashing lines. */ void OpenXYwindow() { if (XYwindow == NULL) { XYNWindow.Screen = MandelScreen; if (XYwindow = OpenWindow(&XYNWindow)) { XYwindow->UserPort = MainWindow->UserPort; ModifyIDCMP(XYwindow, (long)CLOSEWINDOW | MOUSEBUTTONS | INTUITICKS); SetDrMd(XYwindow->RPort, (long)JAM2); SetAPen(XYwindow->RPort, (long)1); SetBPen(XYwindow->RPort, (long)0); } } } void CloseXYwindow() { if (XYwindow) { CloseWindowSafely(XYwindow); XYwindow = NULL; } } void UpdateXYwindow(x, y) /* corrected: 0..max */ int x, y; { register int chars; register struct RastPort *rp; register long left, top; char buffer[CHARS+2]; /* 1 extra for \0, and 1 for safety */ static char format[] = "%-16.10g"; /* 16 == CHARS */ /* -1.234567890e-99 is 16 chars with a precision of 10 digits */ ReMouse = LeftEdge + CXStep * x; ImMouse = TopEdge - CYStep * y; if (XYwindow) { rp = XYwindow->RPort; left = XYwindow->BorderLeft; top = XYwindow->BorderTop; chars = sprintf(buffer, format, ReMouse); Move(rp, left, top+7); Text(rp, buffer, (long)chars); chars = sprintf(buffer, format, ImMouse); Move(rp, left, top+15); Text(rp, buffer, (long)chars); } } void MyExit(status) char *status; { static char message[] = "\ \0\144\25Mandelbrot Construction Set -- By KosmoSoft Productions\0a\ \0\144\41 \0"; /* 3^5^ 10^ ^ 20^ ^ 30^ ^ 40^ ^ 50^ 55^58^ */ register char *c=message+63; #ifdef AREXX dnRexxPort(); #endif if (status) { /* Center the message. */ { register int halfway = 320 - (strlen(status) << 2); message[60] = halfway >> 8; /* High byte */ message[61] = halfway; /* Low byte */ } while ((*(c++) = *(status++)) && c < message + 127); *c = 0; /* Let's be paranoid for a change... */ if (!IntuitionBase) IntuitionBase = (struct IntuitionBase *) OpenLibrary ("intuition.library", 0L); if (IntuitionBase) DisplayAlert(RECOVERY_ALERT, message, 50L); else { /* AT_Recovery | AG_OpenLib | AO_Intuition */ CPTR AlertParameter = (CPTR) FindTask(NULL); Alert(0x00038004L, &AlertParameter); } status=1; } CleanupDisplay((bool) TRUE); if (DrawSigBit != -1) FreeSignal((long)DrawSigBit); if (IntuitionBase) CloseLibrary(IntuitionBase); if (LayersBase) CloseLibrary(LayersBase); if (GfxBase) CloseLibrary(GfxBase); exit ((int) (status != NULL)); } void _abort() { MyExit("_abort() called..."); } bool Sure() { bool Result; ULONG OldIDCMP = MainWindow->IDCMPFlags; static struct IntuiText Body[] = { { MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 25, 10, NULL, (UBYTE *) "You are going to", &Body[1] }, { MYFRONTPEN+1, AUTOBACKPEN, AUTODRAWMODE, 57, 25, &Topaz60, (UBYTE *) "destroy", &Body[2] }, { MYFRONTPEN, AUTOBACKPEN, AUTODRAWMODE, 33, 40, NULL, (UBYTE *) "your picture !", NULL } }; if (Saved) return TRUE; ModifyIDCMP(MainWindow, OldIDCMP &~ (MENUVERIFY | SIZEVERIFY | REQVERIFY)); Result = AutoRequest(MainWindow, &Body[0], &PositiveText, &NegativeText, NULL, NULL, 200L, 90L); ModifyIDCMP(MainWindow, OldIDCMP); return Result; } /* * Render a requester in a window. If it won't fit, open a new window. * This new window will share the IDCMP port with the original * window. This is to save memory, signal bits and VERIFY deadlocks. * Returns the window in which the requester actually appears. */ struct Window *MyRequest(request, window) struct Requester *request; struct Window *window; { static struct NewWindow newwindow = { 0, 0, 0, 0, 2, 1, NULL, /* IDCMP flags -- port shared with main window */ WINDOWDEPTH | WINDOWDRAG | ACTIVATE | SIMPLE_REFRESH | NOCAREREFRESH, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, NULL }; int width, height; int borderleft, borderright, bordertop, borderbottom; struct Window *oldwindow = window; borderleft = window->WScreen->WBorLeft; borderright = window->BorderRight; bordertop = window->WScreen->BarHeight + 1; borderbottom = window->BorderBottom; /* Center the requester in the given window. * If impossible, open a new window to the place the requester in. */ width = window->GZZWidth; height = window->GZZHeight; if (width < request->Width || height < request-> Height) { /* Window too small. Open a new one */ newwindow.Screen = window->WScreen; newwindow.Type = window->WScreen->Flags & SCREENTYPE; newwindow.Title = window->Title; newwindow.Width = request->Width + 2 * borderleft; newwindow.Height = request->Height + bordertop + borderbottom; newwindow.LeftEdge = (newwindow.Screen->Width - newwindow.Width) / 2; newwindow.TopEdge = (newwindow.Screen->Height - newwindow.Height) / 2; if (window = OpenWindow(&newwindow)) { window->UserPort = oldwindow->UserPort; /* Upen up the other port */ ModifyIDCMP(window, GADGETUP); } request->LeftEdge = borderleft; request->TopEdge = bordertop; } else { /* The requester fits. Center it! */ request->LeftEdge = ((width - request->Width) >> 1); request->TopEdge = ((height - request->Height) >> 1); if (!(window->Flags & GIMMEZEROZERO)) { request->LeftEdge += borderleft; request->TopEdge += bordertop; } } if (window && Request(request, window)) return window; if (window) CloseWindowSafely(window); return NULL; } void EndMyRequest(request, window, original) struct Requester *request; struct Window *window, *original; { EndRequest(request, window); if (window != original) CloseWindowSafely(window); } /* * Wait on a request posted by MyRequest. * Returns when a gadget with GadgetID >= POSGADGETID is released, * so Gadgets with an ID < POSGADGETID will be ignored. * NEGGADID > POSGADID. * Any messages other than GADGETUP will be ignored. */ int WaitMyRequest(window) struct Window *window; { int ID = 0; struct IntuiMessage *message; struct Gadget *Gadget; ULONG Class; ULONG OldIDCMP = window->IDCMPFlags; ULONG SigMask; if (!window) return NEGGADGETID; ModifyIDCMP(window, GADGETUP); #ifdef AREXX SigMask = RexxMask | (1L << MainWindow->UserPort->mp_SigBit); #else SigMask = (1L << MainWindow->UserPort->mp_SigBit); #endif while (ID < POSGADGETID) { Wait(SigMask); #ifdef AREXX dispRexxPort(); #endif while (message = (struct IntuiMessage *) GetMsg(window->UserPort) ) { Class = message->Class; Gadget = (struct Gadget *)message->IAddress; ReplyMsg(message); if (Class != GADGETUP) continue; ID = Gadget->GadgetID; if (ID >= POSGADGETID) break; /* Also gets out of outer loop */ } } ModifyIDCMP(window, OldIDCMP); return ID; } void RectDraw(rp, x1, y1, x2, y2) struct RastPort *rp; SHORT x1, y1, x2,y2; { Move(rp, (long) x1, (long) y1); Draw(rp, (long) x2, (long) y1); Draw(rp, (long) x2, (long) y2); Draw(rp, (long) x1, (long) y2); if (y2 > y1) y1++; else y1--; /* Don't XOR the first pixel twice */ Draw(rp, (long) x1, (long) y1); } void CrossDraw(rp, x, y, left, right, top, bottom) struct RastPort *rp; SHORT x, y, top, bottom, left, right; { Move(rp, (long) left, (long) y); Draw(rp, (long) right, (long) y); Move(rp, (long) x, (long) top); Draw(rp, (long) x, (long) bottom); } void DisableSystemGadgets(gadget) struct Gadget *gadget; { while (gadget) { if (gadget->GadgetType & SYSGADGET) { /* Ghost everything except the Title/Dragbar */ if ((gadget->GadgetType & 0x00F0) != WDRAGGING) OffGadget(gadget, MainWindow, NULL); gadget->Flags |= GADGDISABLED; } gadget = gadget->NextGadget; } } void EnableSystemGadgets(gadget) struct Gadget *gadget; { USHORT Flags = 0; while (gadget) { if (gadget->GadgetType & SYSGADGET) { Flags |= gadget->Flags; gadget->Flags &= ~GADGDISABLED; } gadget = gadget->NextGadget; } /* Unghost everthing if necessary */ if (Flags & GADGDISABLED) RefreshWindowFrame(MainWindow); } void StopFraming() { if (MainWindow) { EnableSystemGadgets(MainWindow->FirstGadget); ModifyIDCMP(MainWindow, MainWindow->IDCMPFlags & ~INTUITICKS); } MouseStatus = NOTFRAMING; CloseXYwindow(); } void CheckMouse(Message) register struct IntuiMessage *Message; { register SHORT top = MainWindow->BorderTop, bottom = MainWindow->Height - MainWindow->BorderBottom - 1, left = MainWindow->BorderLeft, right = MainWindow->Width - MainWindow->BorderRight - 1; static ULONG OldSecs, OldMicros; static SHORT MidX, MidY; USHORT MouseX, MouseY; if (Message->IDCMPWindow == MainWindow) { MouseX = Message->MouseX; MouseY = Message->MouseY; } else { MouseX = MainWindow->MouseX; MouseY = MainWindow->MouseY; } if (StillDrawing || MouseStatus != FLASHING && (MouseX < left || MouseX > right || MouseY < top || MouseY > bottom)) return; MouseX -= left; MouseY -= top; if (Message->Class == MOUSEBUTTONS) { if (Message->Code == SELECTDOWN) { /* We selected a point */ switch (MouseStatus) { case NOTFRAMING: case FLASHING: MouseStatus = NOPOINT; DisableSystemGadgets(MainWindow->FirstGadget); ModifyIDCMP(MainWindow, MainWindow->IDCMPFlags | INTUITICKS); OpenXYwindow(); /* Now we can select our first corner */ break; case NOPOINT: FrameX1 = FrameX2 = MouseX; FrameY1 = FrameY2 = MouseY; MouseStatus = POINT1; OldMicros = Message->Micros; OldSecs = Message->Seconds; /* We have the first point. Now go for the second */ break; case POINT1: if (DoubleClick(OldSecs, OldMicros, Message->Seconds, Message->Micros)) { /* Did we double-click? Then we have selected a center */ MouseStatus = CENTERFRAMING; MidX = FrameX1; MidY = FrameY1; break; } FrameX2 = MouseX; FrameY2 = MouseY; /* Fall through to CENTERFRAMING */ case CENTERFRAMING: if (FrameX1 == FrameX2 || FrameY1 == FrameY2) break; EnableSystemGadgets(MainWindow->FirstGadget); MouseStatus = FLASHING; /* Point 1 should be upper left */ if (FrameX2 < FrameX1) { /* I DO know I am reusing a variable here. Sorry! */ left=FrameX2; FrameX2=FrameX1; FrameX1=left; } if (FrameY2 < FrameY1) { left=FrameY2; FrameY2=FrameY1; FrameY1=left; } break; } /* End switch MouseStatus */ } /* End if Code == SELECTDOWN */ return; } /* End if Class == MOUSEBUTTONS */ /* We are moving the mouse. Show something! */ UpdateXYwindow(MouseX, MouseY); SetDrMd(MainWindow->RPort, (ULONG) COMPLEMENT); switch (MouseStatus) { /* case NOTFRAMING: */ /* return; */ case NOPOINT: FrameX1 = FrameX2 = MouseX; FrameY1 = FrameY2 = MouseY; WaitTOF(); CrossDraw(MainWindow->RPort, FrameX1, FrameY1, 0, MainWindow->GZZWidth-1, 0, MainWindow->GZZHeight-1); WaitTOF(); CrossDraw(MainWindow->RPort, FrameX1, FrameY1, 0, MainWindow->GZZWidth-1, 0, MainWindow->GZZHeight-1); break; case CENTERFRAMING: FrameX1 = MouseX; FrameY1 = MouseY; FrameX2 = 2*MidX - FrameX1; FrameY2 = 2*MidY - FrameY1; skipto flashing; case POINT1: FrameX2 = MouseX; FrameY2 = MouseY; /* Deliberate Fall-Through to FLASHING */ case FLASHING: flashing: WaitTOF(); RectDraw(MainWindow->RPort, FrameX1, FrameY1, FrameX2, FrameY2); WaitTOF(); RectDraw(MainWindow->RPort, FrameX1, FrameY1, FrameX2, FrameY2); } } void InitPenTable() { register int i; switch (PenTableMode) { case MODULO: PenTable[0] = 0; for (i=1; iFlags |= CHECKED; else Item->Flags &= ~CHECKED; SetMenuStrip(MainWindow, MandelMenu); } void MakeMAND(mand) struct Mand *mand; { int i; mand->MandID = MAND; mand->Size = sizeof(struct Mand) - 2 * sizeof(LONG); mand->MaxDepth = MaxDepth; mand->RangeWidth = RangeWidth; mand->RainDist = RainbowDistance; mand->RainRMax = RainbowRMax; mand->RainGMax = RainbowGMax; mand->RainBMax = RainbowBMax; for (i=0; i < sizeof(mand->Coords); i++) mand->Coords[i] = '\0'; sprintf(&mand->Coords[0], "%1.10g %1.10g %1.10g %1.10g", LeftEdge, RightEdge, TopEdge, BottomEdge); mand->FunctionNr = FunctionNr; mand->PenTableMode = PenTableMode; mand->WBWidth = WBWidth; mand->WBHeight = WBHeight; } bool InterpretMAND(mand, ilbminfo) struct Mand *mand; struct ILBM_info *ilbminfo; { double NewLeftEdge, NewRightEdge, NewTopEdge, NewBottomEdge; double Ratio; /* Perform some checks on correctness of the chunk */ if (mand->MandID != MAND || mand->Size > sizeof(struct Mand) - 2 * sizeof(LONG) || mand->MaxDepth > MAXDEPTH || mand->RangeWidth > MAXDEPTH) return FALSE; if (sscanf(&mand->Coords[0], "%lf %lf %lf %lf", &NewLeftEdge, &NewRightEdge, &NewTopEdge, &NewBottomEdge) < 4) return FALSE; MaxDepth = mand->MaxDepth; RangeWidth = mand->RangeWidth; /* Compensate for different sized windows */ Ratio = (double)MainWindow->GZZWidth / (double)ilbminfo->header.w; LeftEdge = NewLeftEdge; if (Ratio != 1.0) RightEdge = NewLeftEdge + Ratio * (NewRightEdge - NewLeftEdge); else /* avoid round-off when almost exactly 1.0000 */ RightEdge = NewRightEdge; Ratio = (double)MainWindow->GZZHeight / (double)ilbminfo->header.h; TopEdge = NewTopEdge; if (Ratio != 1.0) BottomEdge = NewTopEdge - Ratio * (NewTopEdge - NewBottomEdge); else /* avoid round-off when almost exactly 1.0000 */ BottomEdge = NewBottomEdge; CalcCSteps(); RainbowDistance = mand->RainDist; RainbowRMax = mand->RainRMax; RainbowGMax = mand->RainGMax; RainbowBMax = mand->RainBMax; if (mand->Size > OFFSETOF(FunctionNr, Mand) - 2*sizeof(long)) { SetDrawingFunction(mand->FunctionNr); PenTableMode = mand->PenTableMode; WBWidth = mand->WBWidth; WBHeight = mand->WBHeight; InitPenTable(); } UpdateCheckmarks(); return TRUE; }