/* * MandelVroom 2.0 * * (c) Copyright 1987,1989 Kevin L. Clague, San Jose, CA * * All rights reserved. * * Permission is hereby granted to distribute this program's source * executable, and documentation for non-comercial purposes, so long as the * copyright notices are not removed from the sources, executable or * documentation. This program may not be distributed for a profit without * the express written consent of the author Kevin L. Clague. * * This program is not in the public domain. * * Fred Fish is expressly granted permission to distribute this program's * source and executable as part of the "Fred Fish freely redistributable * Amiga software library." * * Permission is expressly granted for this program and it's source to be * distributed as part of the Amicus Amiga software disks, and the * First Amiga User Group's Hot Mix disks. * * contents: this file contains funtions to create, maintain and delete * Mandelbrot and Julia projects (including spawning off child generator * tasks.) */ #include "mandp.h" struct NewWindow NewMand = { 0,12, /* start position */ 80,80, /* width, height */ (UBYTE) 0, (UBYTE) NORMALPEN, NULL, /* IDCMP flags */ /* MandWind flags */ WINDOWCLOSE | WINDOWDEPTH | WINDOWSIZING | WINDOWDRAG | ACTIVATE | REPORTMOUSE | NOCAREREFRESH | SMART_REFRESH, (struct Gadget *) NULL, /* first gadget */ (struct Image *) NULL, /* user checkmark */ (UBYTE *) NULL, /* Title */ (struct Screen *) NULL, /* pointer to screen */ (struct BitMap *) NULL, /* pointer to superbitmap */ 20,20,-1,-1, /* sizing */ CUSTOMSCREEN /* type of screen */ }; LONG TopMarg = 10; LONG BotMarg = 2; LONG LeftMarg = 2; LONG RightMarg; ULONG CalcTime; extern LONG TaskPri, MainPri; extern LONG pSigMask; extern struct ExecBase *ExecBase; static struct Picture *GenNPict; /* Toggle generation of project */ GenerateCmd(Msg) struct IntuiMessage *Msg; { switch(Msg->Class) { case GADGETDOWN: ToggleGen((struct Picture *) Msg->IDCMPWindow->UserData); break; case MENUPICK: switch( SUBNUM(Msg->Code) ) { case STARTGEN: CurPict->GenState = GENPENDSTATE; Generate( CurPict ); break; case STOPGEN: ThrowTask(CurPict); break; case CONTGEN: CurPict->GenState = CONTINUESTATE; Generate( CurPict ); break; } break; } } ToggleGen( Pict ) struct Picture *Pict; { if ( Pict->gTask ) { ThrowTask( Pict ); } else { Pict->GenState = GENPENDSTATE; Generate( Pict ); } SetGenGad( Pict ); } /* * Generate It */ Generate( Pict ) register struct Picture *Pict; { register char *t; int GenTask(); extern struct MenuItem LensSub[]; if ( Pict->gTask ) { return; } if (Pict->Flags & SCROLL_HAPPENED) { /* create a new counts array with unclipped data in it */ /* adjust the real and imaginary upper left */ ScrollComplex(Pict); if (Pict->Counts == NULL) return; } else { FreeScrollTemp(Pict); if (Pict->GenState == CONTINUESTATE ){ if ( Pict->CurLine < Pict->CountY ) { if (Pict->Counts == NULL) return; } else { return; } } if (Pict->GenState == GENPENDSTATE) { InitNewGen( Pict ); if (Pict->Counts == NULL) return; } } ResetScrollRects(Pict); Pict->GenState = GENERATESTATE; if ( Pict->MathMode == INTIIGENERATOR && (ExecBase->AttnFlags & (1 << AFB_68020)) == 0 ) { Pict->MathMode = INTGENERATOR; } if ( Pict->MathMode == _81GENERATOR && (ExecBase->AttnFlags & (1 << AFB_68881)) == 0 ) { Pict->MathMode = IEEEGENERATOR; } MakeColorXlate( Pict ); if (Pict->MathMode == 1) { if (OpenFFPLibs() != 0) return; } /* Spawn off the generator as a task */ DateStamp( Pict->TimeStamp ); /* GenNPict is pointer to Picture that task needs to generate */ GenNPict = Pict; #define KAY (1024L) #ifdef MULTI Pict->gTask = CreateTask( Pict->Title+2, MainPri, GenTask, KAY); if ( Pict->gTask == NULL ) { DispErrMsg("Could not create task",0); } SetGenGad( Pict ); /* Do this so we are sure child is done with GenNPict */ Wait( pSigMask ); #else GenTask(); #endif } InitNewGen( Pict ) register struct Picture *Pict; { if (Pict->Flags & BORDERLESS_PROJ) { Pict->LeftMarg = 0; Pict->RightMarg = 0; Pict->TopMarg = 0; Pict->BotMarg = 0; } /* figure out new picture size */ Pict->CountX = Pict->Window->Width-(Pict->LeftMarg+Pict->RightMarg); Pict->CountY = Pict->Window->Height-(Pict->TopMarg+Pict->BotMarg); /* free up old counts memory, get new picture size, get new counts memory */ GetCountsMemory( Pict ); if (Pict->Counts == NULL) { DispErrMsg("Can't generate. Out of RAM!!",0); return; } if (Pict->Flags & NO_RAM_GENERATE ) { DispErrMsg("Can't save counts. Out of RAM!!",0); } /* calculate new picture's coordinates from zoom box */ ZoomIn( Pict ); Pict->CurLine = 0; /* clear the picture area */ if (!(Pict->Flags & LENS_DISPLAYED)) { SetAPen( Pict->Window->RPort, NORMALPEN ); RectFill( Pict->Window->RPort, Pict->LeftMarg, Pict->TopMarg, Pict->Window->Width - Pict->RightMarg - 1, Pict->Window->Height - Pict->BotMarg - 1); } } GenTask() { register struct Picture *Pict; int MandelbrotInt32(); int MandelbrotInt32II(); int MandelbrotIEEE(); int MandelbrotFFP(); int JuliaInt32(); int JuliaIEEE(); int JuliaFFP(); LONG SPFieee(); #ifdef MULTI geta4(); #endif Pict = GenNPict; /* Signal Parent that we have accessed GenNPict */ Signal( mTask, pSigMask ); /* Lower our priority while we generate */ SetTaskPri( FindTask(0), TaskPri ); Pict->GenChildState = GENINCOMPLETE; if (GetTaskSig( Pict ) == UNSUCCESSFUL) { Pict->GenChildState = NOSIGSTATE; } else { Pict->GenChildState = GENINCOMPLETE; if ( Pict->pNode.ln_Type == MANDPICT ) { switch ( Pict->MathMode ) { case 0: MandelbrotInt32( Pict ); break; case 2: case 4: MandelbrotIEEE( Pict ); break; case 3: MandelbrotInt32II( Pict ); break; case 1: { /* * Constraints for IEEE to FFP conversion * * 1. SPFieee() expects 32 bit IEEE floats * 2. The C language always promotes floats to doubles for * parameter passing. * 3. doubles are 64 bits wide * * Therefore I must do the following: * * 1. Convert double parameters to float * 2. Take the address of the floats and cast them to *ULONG * 3. Indirect off the ULONG pointers that are pointing to * 32 IEEE format floats (gross eh?) as parameters to FFP * Mandelbrot function. */ /* 32 bit IEEE float variables */ float StartX_float, StartY_float, GapX_float, GapY_float; /* convert 64 bit IEEE variables into 32 bit IEEE variables */ StartX_float = Pict->RealLow; StartY_float = Pict->ImagLow + Pict->CurLine*Pict->RealGap; GapX_float = Pict->RealGap; GapY_float = Pict->ImagGap; /* * calculate pointers and convert them to pointers to ULONG * so that when we indirect off of these and pass the results * as parameters they are not promoted to doubles. */ MandelbrotFFP( Pict, *( (ULONG *) &StartX_float ), *( (ULONG *) &StartY_float ), *( (ULONG *) &GapX_float ), *( (ULONG *) &GapY_float )); } break; } } else { switch ( Pict->MathMode ) { case 0: case 3: JuliaInt32( Pict ); break; case 2: case 4: JuliaIEEE( Pict ); break; case 1: { /* * Constraints for IEEE to FFP conversion * * 1. SPFieee() expects 32 bit IEEE float * 2. The C language always promotes floats to doubles for * parameter passing. * 3. doubles are 64 bits wide * * Therefore I must do the following: * * 1. Convert double parameters to float * 2. Take the address of the floats and cast them to *ULONG * 3. Indirect off the ULONG pointers that are pointing to * 32 IEEE format floats (gross eh?) as parameters to FFP * Julia function. */ /* 32 bit IEEE float variables */ float JuliaX_float, JuliaY_float; float StartX, StartY, GapX, GapY; /* convert 64 bit IEEE variables into 32 bit IEEE variables */ JuliaX_float = Pict->Real; JuliaY_float = Pict->Imag; StartX = Pict->RealLow; StartY = Pict->ImagLow; GapX = Pict->RealGap; GapY = Pict->ImagGap; /* * calculate pointers and convert them to pointers to ULONG * so that when we indirect off of these and pass the results * as parameters they are not promoted to doubles. */ JuliaFFP( Pict, *( (ULONG *) &JuliaX_float ), *( (ULONG *) &JuliaY_float ), *( (ULONG *) &StartX ), *( (ULONG *) &StartY ), *( (ULONG *) &GapX ), *( (ULONG *) &GapY ) ); } break; } } Pict->GenChildState = GENCOMPLETE; } #ifdef MULTI /* Indicate that generation has finished for this task */ Signal( mTask, mSigMask ); /* signal parent as to change */ while (Pict->GenState != KILLSTATE) { /* Wait for task to be removed */ while (Pict->GenState == GENERATESTATE) { /* spin 'till parent kills us */ } /* accept any pauses that the parent may send too late */ if (Pict->GenState == PAUSESTATE) { ChildSignal(Pict); /* signal back so parent doesn't hang */ } } /* We've been informed that we will die, so free up resources */ FreeSignal( Pict->gSigBit ); Signal( mTask, pSigMask ); /* signal death O.K. */ Wait( 0L ); /* stop here forever */ #endif } InitMand( Pict ) register struct Picture *Pict; { Pict->Real = 0.0; Pict->Imag = 0.0; } SetWindowActive( Window, Active ) register struct Window *Window; char Active; { struct Picture *Pict; if ( Window ) { Pict = (struct Picture *) Window->UserData; if ( ! (Pict->Flags & BORDERLESS_PROJ)) { Window->Title[0] = Active; SetWindowTitles( Window, Window->Title, -1 ); } } } /* * Free up old memory and get memory for new picture */ GetCountsMemory( Pict ) register struct Picture *Pict; { /* free up old pictures iteration count pile */ FreeCounts( Pict ); /* Allocate memory for new picture */ Pict->CountsSize = Pict->CountX * Pict->CountY * sizeof(SHORT); Pict->Counts = (SHORT *) safeAllocMem(Pict->CountsSize, MEMF_CLEAR ); if (Pict->Counts == NULL) { Pict->CountsSize = Pict->CountX * sizeof(SHORT); Pict->Counts = (SHORT *) safeAllocMem(Pict->CountsSize, MEMF_CLEAR); if (Pict->Counts != NULL) Pict->Flags |= NO_RAM_GENERATE; } else { Pict->Flags &= ~NO_RAM_GENERATE; } } FreeCounts( Pict ) register struct Picture *Pict; { if ( Pict->Counts ) { FreeMem( Pict->Counts, Pict->CountsSize ); Pict->Counts = NULL; } } struct Gadget * MakePictGads( Type ) register int Type; { register struct Gadget *gadget; register struct Gadget *Newgadget; register struct Gadget *Firstgadget; register struct IntuiText *Intui; register char *str; struct Border *Border, *MakeShadow(); register int i,j,k; struct IntuiText *ShadowIntui(); j = TOPMARG; if ( Type == MANDPICT ) { k = 4; } else { k = 5; } Firstgadget = NULL; for (i = 0; i < k; i++) { Newgadget = MakeBool(-15,j, 12,12, 0,(PICTTYPE<NextGadget = Newgadget; } Newgadget->Flags |= GRELRIGHT; Newgadget->Activation |= RIGHTBORDER; gadget = Newgadget; j += 14; switch( i ) { case 0: str = "C"; break; case 1: str = "G"; break; case 2: str = "I"; break; case 3: str = "O"; break; case 4: str = "J"; break; } Intui = ShadowIntui( str, 3, 3); if (Intui == NULL) { FreeGadgets( Firstgadget ); } gadget->GadgetText = Intui; #define NUMPATCHCORNERS 5 Border = MakeShadow( NORMALPEN, NUMPATCHCORNERS ); if ( Border ) { InitPatch( Border ); Border->NextBorder = (struct Border *) gadget->GadgetRender; gadget->GadgetRender = (APTR) Border; } } else { if (Firstgadget) FreeGadgets( Firstgadget ); return( NULL ); } } return( Firstgadget ); } SetGenGad( Pict ) register struct Picture *Pict; { register struct Window *Window; register struct Gadget *Gadget; register struct IntuiText *Intui; register char c; register int place; if (Pict == NULL) return; if (Pict->Flags & BORDERLESS_PROJ) return; Window = Pict->Window; if (Window) { if ( Pict->gTask ) c = 'S'; else c = 'G'; Gadget = Pict->Gadgets->NextGadget; place = RemoveGadget( Window, Gadget ); Intui = Gadget->GadgetText; Intui = Intui->NextText; Intui->IText[0] = c; Intui = Intui->NextText; Intui->IText[0] = c; AddGadget( Window, Gadget, place ); RefreshGadgets( Pict->Gadgets, Window, NULL ); } } InitPatch( Border ) register struct Border *Border; { register SHORT *NewCounts; NewCounts = Border->XY; *NewCounts++ = 3; *NewCounts++ = 11; *NewCounts++ = 2; *NewCounts++ = 11; *NewCounts++ = 2; *NewCounts++ = 2; *NewCounts++ = 11; *NewCounts++ = 2; *NewCounts++ = 11; *NewCounts++ = 3; } /* InitPatch */ /* * Open the Picture window */ OpenPicture( Pict ) struct Picture *Pict; { extern struct Window *OpenMyWind(); register struct Window *Window; register struct NewWindow *NewWind; register LONG width, height; register LONG extrax,extray; struct Gadget *gadgets, *MakePictGads(); if ( Pict->Window == NULL ) { width = Pict->CountX; height = Pict->CountY; NewWind = Pict->NewWind; if (Pict->Flags & BORDERLESS_PROJ) { NewWind->Flags = ACTIVATE | REPORTMOUSE | NOCAREREFRESH | SMART_REFRESH | BORDERLESS; NewWind->Title = NULL; Pict->Gadgets = gadgets = NULL; if (Pict->LeftEdge+Pict->CountX+LEFTMARG+RIGHTMARG == screen->Width && Pict->TopEdge +Pict->CountY+TOPMARG+BOTMARG == screen->Height) { Pict->LeftMarg = LEFTMARG; Pict->RightMarg = RIGHTMARG; Pict->TopMarg = TOPMARG; Pict->BotMarg = BOTMARG; } else { Pict->LeftMarg = 0; Pict->RightMarg = 0; Pict->TopMarg = 0; Pict->BotMarg = 0; } } else { NewWind->Flags = WINDOWCLOSE | WINDOWDEPTH | WINDOWSIZING | WINDOWDRAG | ACTIVATE | REPORTMOUSE | NOCAREREFRESH | SMART_REFRESH; NewWind->Title = (UBYTE *) Pict->Title; Pict->Gadgets = gadgets = MakePictGads( Pict->pNode.ln_Type ); Pict->LeftMarg = LEFTMARG; Pict->RightMarg = RIGHTMARG; Pict->TopMarg = TOPMARG; Pict->BotMarg = BOTMARG; } width += Pict->LeftMarg + Pict->RightMarg; height += Pict->TopMarg + Pict->BotMarg; extrax = width - screen->Width; extray = height - screen->Height; if ( extrax > 0 || extray > 0 ) { ThrowTask( Pict); FreeCounts( Pict); DispErrMsg("Picture too big. Regenerate",0); if ( extrax > 0 ) { Pict->CountX -= extrax; width -= extrax; } if ( extray > 0 ) { Pict->CountY -= extray; height -= extray; } } NewWind->LeftEdge = Pict->LeftEdge; NewWind->TopEdge = Pict->TopEdge; Window = OpenMyWind(NewWind, screen, gadgets, width, height ); Pict->Window = Window; if (Window == NULL) { DispErrMsg("Can't open picture window",0); FreeGadgets( Pict->Gadgets ); ThrowPict(Pict); return( -1 ); } else { CurWind = Window; DisplayMsg(); SetAPen( Window->RPort, NORMALPEN ); if (Pict->Flags & BORDERLESS_PROJ) { RectFill( Window->RPort, Pict->LeftMarg, Pict->TopMarg, NewWind->Width-Pict->RightMarg-1, NewWind->Height-Pict->BotMarg-1); } else { RectFill( Window->RPort, Pict->LeftMarg, Pict->TopMarg, NewWind->Width, NewWind->Height); } Window->UserData = (BYTE *) Pict; MoveResize( Pict->Window, &Pict->SizingGadget ); BorderWindow( Window ); if (Pict->CycleOn) { CreateCycle(); } } } SetGenGad( Pict ); return( 0 ); } /* OpenPicture */ MoveResize( Window, RetGadget ) register struct Window *Window; register struct Gadget **RetGadget; { register struct Gadget *Gadget; register int place; Gadget = Window->FirstGadget; while ( Gadget && !(Gadget->GadgetType & SIZING)) { Gadget = Gadget->NextGadget; } if (Gadget) { *RetGadget = Gadget; place = RemoveGadget( Window, Gadget ); if (XScale == 0) Gadget->LeftEdge -= 2; if (YScale == 0) Gadget->TopEdge -= 3; else Gadget->TopEdge -= 1; AddGadget( Window, Gadget, place ); RefreshGList( Gadget, Window, NULL, 1); } } /* * Close the Mandelbrot Window */ ClosePicture( Pict ) register struct Picture *Pict; { register struct Window *Window; register struct NewWindow *NewWindow; if ( (Window = Pict->Window) != NULL) { KillCycle(); FreeScrollTemp(Pict); Pict->LeftEdge = Window->LeftEdge; Pict->TopEdge = Window->TopEdge; CloseMyWind(Window, Pict->Gadgets ); Pict->Window = NULL; Pict->Gadgets = NULL; Pict->Flags &= ~LENS_DISPLAYED; } }