keithr@hercules.UUCP (08/12/85)
[] This is the source to Fractal Contours that I promised to post. Sorry for the delay in posting this but the power supply in my mac died. This program was written in Aztec C by Jim Cathey. Jim has moved onto other projects so he probably won't be releasing any improvements in this program. Enjoy Keith Rule tektronix!teklds!keithr ---------------------------- Cut Here ------------------------------ #!/bin/sh # This is a shell archive, meaning: # 1. Remove everything above the #!/bin/sh line. # 2. Save the resulting text in a file. # 3. Execute the file with /bin/sh (not csh) to create the files: # Makefile # fractal.c # fractal.h # fractal.r # fractal2.c # This archive created: Sun Aug 11 21:32:45 1985 # By: Keith Rule tektronix!teklds!keithr (Tektronix, Inc.) export PATH; PATH=/bin:$PATH if test -f 'Makefile' then echo shar: over-writing existing file "'Makefile'" fi cat << \SHAR_EOF > 'Makefile' # # Dependency Rules # #fractal.res: fractal.r # rmaker fractal.r fractal.o: fractal.c fractal.h fractal2.o: fractal2.c fractal.h fractal: fractal.o fractal2.o ln -m -o fractal sys:lib/sacroot.o fractal.o fractal2.o sys:lib/m.lib -lc SHAR_EOF if test -f 'fractal.c' then echo shar: over-writing existing file "'fractal.c'" fi cat << \SHAR_EOF > 'fractal.c' /* ** Three-dimensional Fractal Contour Map generator. ** Program originally in MicroSoft BASIC for the Macintosh. ** Taken from July 1985 Creative Computing. ** ** Used as an example BASIC-C comparison. */ #include <memory.h> #include <quickdraw.h> #include <font.h> #include <window.h> #include <osutil.h> #include <menu.h> #include <event.h> #include <textedit.h> #include <dialog.h> #include <desk.h> #include <control.h> #include <toolutil.h> #define watchCursor 4 /* Should be in TOOLUTIL.H but isn't. JEC */ #include <resource.h> #include <stdio.h> #include "fractal.h" GrafPtr screenport; /* A port for the whole screen. */ WindowPtr mywindow; /* Our one window. */ WindowRecord wrecord; /* Storage for window record. */ MenuHandle mymenus[LASTMENU + 1]; /* Our menus. */ PicHandle thepicture; BitMap savepix; /* Storage for the update bitmap. */ EventRecord myevent; WindowPtr whichwindow; /* Points to window of MouseDown. */ int windowcode; /* What mouse was in when event posted. */ Boolean userdone; /* True when user wants to exit program. */ int ispicture; /* True if there is a Picture definition of the contour available. */ int isbitmap; /* True if there is a bitmap copy of the contour available. Saves time in update events. */ int usebitmap; /* True if the bitmap should be used to update. */ main() { setup(); maineventloop(); } /*############################ MainEventLoop ########################*/ maineventloop() { FlushEvents(everyEvent, 0);/* discard leftover events */ /* get next event, and handle it appropriately, until user QUITs */ userdone = 0; do { SystemTask(); /* Handle desk accessories. */ if (GetNextEvent(everyEvent, &myevent)) { /* get event; if for us... */ switch (myevent.what) {/* handle each kind of event */ case mouseDown: /* find out what window the mouse went down in, and where in it */ windowcode = FindWindow(pass(myevent.where), &whichwindow); switch (windowcode) { /* handle mouse-down for each place */ case inSysWindow: /* handle the desk accessories */ SystemClick(&myevent, whichwindow); break;/* insyswindow */ case inMenuBar: /* handle the command */ userdone = docommand(MenuSelect(&myevent.where)); break;/* inmenubar */ case inDrag: /* No Drag Region, treat as Content. */ case inContent: /* includes inGrow if window inactive. Activate window */ if (whichwindow == mywindow) /* make sure it's for mine */ if (whichwindow != FrontWindow()) SelectWindow(whichwindow); /* make it active */ break; case inGrow: /* No Grow Region */ break; case inGoAway: /* we don't have a GoAway region */ break; } break; /* switch */ case keyDown: case autoKey: /* if command key, pass the char to MenuKey */ if ((myevent.modifiers & cmdKey) != 0) userdone = docommand(MenuKey((char) (myevent.message & charCodeMask))); case updateEvt: /* if it's for our window, update it */ if ((WindowPtr) (myevent.message) == mywindow) updatewindow(mywindow); /* redraw the window contents */ break; case activateEvt: /* if for our window, set port as nec. */ if ((WindowPtr) (myevent.message) == mywindow) { /* my window */ if (myevent.modifiers & 1) { /* odd means an activate event */ SetPort(mywindow); /* activate evt: work in our own port */ DisableItem(mymenus[EDITMENU], 0); EnableItem(mymenus[FILEMENU], 0); EnableItem(mymenus[SETUPMENU], 0); DrawMenuBar(); } else { SetPort(screenport); /* deactivate evt: our port is gone; keep port from dangling */ EnableItem(mymenus[EDITMENU], 0); DisableItem(mymenus[FILEMENU], 0); DisableItem(mymenus[SETUPMENU], 0); DrawMenuBar(); } } break; } } } while (userdone == 0); } /* handle a command given through a menu selection ############################ DoCommand ############################## We carry out the command indicated by mResult. If it was Quit, we return true, else false. Since the menu was highlighted by MenuSelect, we must finish by unhighlighting it to indicate we're done. */ int docommand(mresult) long mresult; { int refnum; int themenu, theitem; char name[255]; GrafPtr saveport; /* for saving current port in when opening a desk accessory */ int returns; returns = 0; /* assume Quit not selected */ themenu = HiWord(mresult); /* get the menu selected */ theitem = LoWord(mresult); /* ... and the item of that menu */ switch (themenu) { case 0: break; /* user made no selection; do nothing */ case APPLEMENU: if (theitem == 1) /* Tell about FracCont */ report(); else { /* run a desk accessory; make sure port is preserved */ GetPort(&saveport); GetItem(mymenus[APPLEMENU], theitem, name); /* get name */ refnum = OpenDeskAcc(name);/* run the desk accessory */ SetPort(saveport); } break; case FILEMENU: switch (theitem) { case ANOTHER: /* New Surface */ calcsurf(contlevl); InvalRect(&mywindow -> portRect); usebitmap = FALSE; break; case SAVEPAINT: /* Not yet. */ break; case IQUIT: returns = 1;/* Quit */ break; } /* FILEMENU case */ break; case SETUPMENU: switch (theitem) { case SETUP: /* Setup */ setupDlg(); break; } /* SETUPMENU case */ } /* menu case */ HiliteMenu(0); /* turn off hilighting on the menu just used */ return (returns); } /* DoCommand */ /*############################ Setup Dialog ######################*/ TerrainBTN(ptr, oncontrl, offcontrl) DialogPtr ptr; int oncontrl, offcontrl; { int itemtype; ControlHandle item; Rect itembox; GetDItem(ptr, offcontrl, &itemtype, &item, &itembox); SetCtlVal(item, 0); /* Turn off old Default Button. */ GetDItem(ptr, oncontrl, &itemtype, &item, &itembox); SetCtlVal(item, 1); /* Turn on Default Button. */ return oncontrl; } setupDlg() /* Do the SETUP menu dialog. */ { int newtype; /* Selected Contour type. */ int newlevel; /* Selected Level of Detail. */ int userexit; int doanother; /* True if we need to recalc. */ int itemhit; /* Item # of punched button (or whatever) */ DialogPtr setupptr; char asciibufr[10]; int itemtype; ControlHandle item; Rect itembox; newtype = conttype; /* SETUPMTN, SETUPHIL, or SETUPWATR */ newlevel = contlevl; doanother = FALSE; setupptr = GetNewDialog(STPDLGID, NULL, (long) -1); TerrainBTN(setupptr, conttype, conttype); asciibufr[1] = newlevel + '0'; /* Only good for 0..9, OK here. */ asciibufr[0] = 1; GetDItem(setupptr, SETUPLEVL, &itemtype, &item, &itembox); SetIText(item, asciibufr); SelIText(setupptr, SETUPLEVL, 0, 100); /* Hilite text field. */ userexit = FALSE; do { ModalDialog(NULL, &itemhit); /* carry out dialog; NIL => no FilterProc; return item Hit when done */ GetDItem(setupptr, SETUPLEVL, &itemtype, &item, &itembox); GetIText(item, asciibufr); /* Get Level field */ if (asciibufr[0] != 1) /* Only good for 1..9, OK here. */ newlevel = 100; else newlevel = asciibufr[1] - '0'; if (newlevel < 1 || newlevel > MAXLEVEL) SelIText(setupptr, SETUPLEVL, 0, 100); /* Hilite text field. */ if (itemhit == SETUPMTN) newtype = TerrainBTN(setupptr, itemhit, newtype); if (itemhit == SETUPHIL) newtype = TerrainBTN(setupptr, itemhit, newtype); if (itemhit == SETUPWATR) newtype = TerrainBTN(setupptr, itemhit, newtype); if (itemhit == SETUPOK && ((newlevel > 0) & (newlevel <= MAXLEVEL))) { if (conttype != newtype || contlevl != newlevel) { if (contlevl != newlevel) doanother = TRUE; InvalRect(&mywindow -> portRect); usebitmap = FALSE; } contlevl = newlevel; conttype = newtype; userexit = TRUE; } if (itemhit == SETUPCAN) userexit = TRUE; } while (!userexit); DisposDialog(setupptr); /* release storage and remove dialog from screen */ if (doanother) calcsurf(newlevel); /* Removes dialog first. */ } /* Setup */ /* ############################ Report ################################# */ report() { int itemhit; DialogPtr reportptr; reportptr = GetNewDialog(INFOSCR1, NULL, (long) -1); /* Get from Resource file; NIL => use heap storage; -1 => make dlg frontmost */ ModalDialog(NULL, &itemhit); /* carry out dialog; NIL => no FilterProc; return item Hit when done */ DisposDialog(reportptr); /* release storage and remove dialog from screen */ if (itemhit == INFOMORE) { reportptr = GetNewDialog(INFOSCR2, NULL, (long) -1); ModalDialog(NULL, &itemhit); DisposDialog(reportptr); } } /* SetUps for handling memory ########################## SetUpMemory ############################ */ setupmemory() { #define maxStackSize 8192 /* max size of stack; the heap gets the rest */ typedef long *lomemptr; /* a pointer to low memory locations */ lomemptr nilptr; /* will have value NIL */ lomemptr stackbaseptr; /* points to current stack base */ /* If you define a GrowZone function to handle bad memory problems, you should define it at the top level (not nested), and set it here. We don't. */ /* SetGrowZone(&mygrowzone); */ /* Place a longint -1 (an odd and therefore illegal address) in the memory location that would be referenced by an accidentally-NULL handle, so the error will be caught at handle-reference time (as an Address error, ID=02) instead of later on. */ nilptr = NULL; *nilptr = -1; /* If you needed to use an Application heap limit other than the default (which allows 8K for the stack), you'd set it here, possible using this technique of explicitly specifying the maximum stack size and allocating the rest to the heap. Should be independent of memory size. */ stackbaseptr = (lomemptr) 0x908; /* CurStackBase from Tlasm/sysequ.text */ SetApplLimit((Ptr) (*stackbaseptr - maxStackSize)); /* Expand the application heap zone to its maximum size, without purging any purgeable resources. This saves memory compactions and heap expansions later. */ MaxApplZone(); /* get plenty of master pointers now; if we let the Memory Manager allocate them as needed, they'd form non-relocatable islands in the heap. */ MoreMasters(); MoreMasters(); } /* SetUpMemory */ /* ############################ SetUpMenus ############################# Once-only initialization for menus We read in all menus from the resource file, and install them, and all desk accessories (drivers). */ setupmenus() { int i; for (i = 1; i <= LASTMENU; i++)/* get all my menus in */ mymenus[i] = GetMenu(i);/* use the fact that our menu ID's start at 1 */ AddResMenu(mymenus[APPLEMENU], 'DRVR'); /* pull in all desk accessories */ for (i = 1; i <= LASTMENU; i++) InsertMenu(mymenus[i], 0);/* insert menus; 0 => put at end */ DrawMenuBar(); } /* body of SetUp Once-only initialization. ############################ SetUp ############################## Initialize our program. It seems best to handle: Memory inits first, ToolBox inits second, then the program variables' inits. Note that the order of inits is important; see "Using the Dialog Manager" in the Dialog Mgr section. */ setup() { char *ctop(); setupmemory(); /* init memory layout and protection */ /* init QuickDraw, and everybody else */ InitGraf(&thePort); InitFonts(); InitWindows(); InitMenus(); TEInit(); InitDialogs(NULL); /* NULL => no Restart proc; see Dialog Mgr and System Error Handler */ InitCursor(); /* Init the system event mask, in case the previous program left it in a bad state. If you set it non-standard here, FIX IT BEFORE EXITING, because the Finder (1.1g) does NOT set it. */ SetEventMask(everyEvent - keyUpMask);/* standard setting */ /* Get the port which is the whole screen, to use when deactivating our window. This prevents the current grafPort pointer from ever dangling. */ GetWMgrPort(&screenport); /* get whole screen port that window mgr uses */ SetPort(screenport); /* and start off with it */ /* get window: use wRecord storage. Port is set to that of the new window. GetNewWindow posts an update event for the new window, so it will be redrawn right away. */ #ifdef DEVELOP OpenResFile(ctop(DEVELOP)); #endif mywindow = GetNewWindow(WINDOWID, &wrecord, (long) -1); /* -1 => frontmost window */ /* pull in and set up our menus */ setupmenus(); CouldDialog(STPDLGID); /* Preload the Setup Dialog. */ conttype = DEFLTTYP; /* Default style */ contlevl = DEFLTLEV; /* Default Level */ isbitmap = FALSE; /* Allocate the data array. */ points = NewPtr((long) XDIM*YDIM*(sizeof(int))); /* Non-reloc, but so what. */ calcsurf(contlevl); /* Do at least one first. */ } /* Update the contents of the given window ############################ UpdateWindow ########################## This is our response to receipt of an update event for myWindow. Since the window is likely to be inactive, the current grafPort will be elsewhere. We must change it for drawing, yet leave it as it was. */ updatewindow(awindow) WindowPtr awindow; { GrafPtr saveport; /* to save and restore the old port */ BeginUpdate(awindow); /* reset ClipRgn etc to only redraw what's necessary. */ GetPort(&saveport); /* don't trash the port; we might be updating an inactive window */ SetPort(awindow); /* work in the specified window */ drawwindow(); /* redraw contents of window */ SetPort(saveport); /* all nice and tidy as before */ EndUpdate(awindow); } /* UpdateWindow */ /* Redraw my window ############################ DrawWindow ############################# We draw all the contents of our one window, myWindow. */ drawwindow() { /* Possibly save the drawing contents in a picture. This will allow much faster update events than calling plotdata() repeatedly. This is only to speed up Desk Accessory movement and the re-painting after the Options Dialog is removed. */ CursHandle ticktock; ticktock = GetCursor(watchCursor); if (ticktock) SetCursor(*ticktock); /* Show watch (wait) */ if (usebitmap) { CopyBits(&savepix, &mywindow->portBits, &savepix.bounds, &mywindow->portRect, srcCopy, 0L); } else { if (isbitmap) DisposPtr(savepix.baseAddr); savepix.bounds.top = mywindow->portRect.top; savepix.bounds.bottom = mywindow->portRect.bottom; savepix.bounds.left = mywindow->portRect.left; savepix.bounds.right = mywindow->portRect.right; savepix.rowBytes = mywindow->portBits.rowBytes; savepix.baseAddr = NewPtr((long) savepix.rowBytes * (savepix.bounds.bottom - savepix.bounds.top)); EraseRect(&mywindow->portRect); plotdata(); CopyBits(&mywindow->portBits, &savepix, &mywindow->portRect, &savepix.bounds, srcCopy, 0L); isbitmap = usebitmap = TRUE; } #ifdef not_defined if (ispicture) KillPicture(thepicture); thepicture = OpenPicture(&mywindow -> portRect); ShowPen(); /* We want the picture shown while being drawn. */ EraseRect(&mywindow -> portRect); plotdata(); HidePen(); /* Balance the ShowPen() above. */ ClosePicture(); ispicture = TRUE; #endif InitCursor(); } /* DrawWindow */ /* * The following routine was used while debugging and testing the program. * The routine is called just like "printf()", but the output is * directed to the printer port. Use -7 for the modem port. The * port must already be opened. Use MIXCROOT and do a 2> .b(a)out * to easily do this. */ #ifdef DEBUG debug(fmt, arg) char *fmt; unsigned arg; { int put(); format(put, fmt, &arg); } put(c) char c; { long i; i = 1; if (c=='\n') put('\r'); FSWrite(DEBUG, &i, &c); if (c=='\n') for (i=2000; i; i--) ; } #endif SHAR_EOF if test -f 'fractal.h' then echo shar: over-writing existing file "'fractal.h'" fi cat << \SHAR_EOF > 'fractal.h' #define DEBUG -7 /* Includes debugging printer. */ /* Use -7 for modem port, -9 for printer. */ #define DEVELOP "Frac:Fractal Contours" /* Resource file to open for faster program development. */ #define LASTMENU 4 /* Number of menus. */ #define APPLEMENU 1 /* Menu ID for Apple menu. */ #define FILEMENU 2 /* Menu ID for File menu. */ #define EDITMENU 3 /* Menu ID for Edit menu. */ #define SETUPMENU 4 /* Menu ID for parameter setting. */ #define ANOTHER 1 /* Items in the File menu. */ /*-------*/ #define SAVEPAINT 3 /*-------*/ #define IQUIT 5 #define SETUP 1 /* Items in the Setup menu. */ #define INFOSCR1 256 /* Resource ID for info dialog. */ #define INFOSCR2 257 /* " info #2 dialog. */ #define INFOOK 1 /* OK Button */ #define INFOMORE 2 /* More Info Button */ #define WINDOWID 260 /* Resource ID for my window. */ /* Setup Dialog Stuff */ #define STPDLGID 258 /* ID of our setup dialog in resource fork. */ #define SETUPOK 1 /* OK Button */ #define SETUPCAN 2 /* CANCEL Button */ #define SETUPLEVL 4 /* Level Text field */ #define SETUPMTN 5 /* Mountain RadButton */ #define SETUPHIL 6 /* Hills RadButton */ #define SETUPWATR 7 /* Water RadButton */ #define MAXLEVEL 7 /* Maximum level of detail. */ #define DEFLTLEV 4 /* Default level. */ #define DEFLTTYP SETUPWATR /* Default type. */ #define XDIM 129 /* 2^MAXLEVEL+1 */ #define YDIM 65 /* 2^(MAXLEVEL-1)+1 */ int (*points)[XDIM][YDIM]; /* The array of points to be subdivided. */ int xmax, ymax; int conttype; /* Contour type. */ int contlevl; /* Level of detail. */ SHAR_EOF if test -f 'fractal.r' then echo shar: over-writing existing file "'fractal.r'" fi cat << \SHAR_EOF > 'fractal.r' * Fractal.r -- Resource definition file for fractal contour map * application. * Tell RMAKER what to name the resource file !fractal APPLfrak * Version data for the finder * Our signature is "frak" * res. ID = 0, by convention * finder version data * Note that the blank in 'STR ' is significant 3/8/85 WHJ TYPE frak = STR ,0 Frac 1.0 -- July 13, 1985 * Menus * ID (4 => pre-load the resource; MUST NOT be purgeable!) * menu title: an Apple symbol (in hex) for the Apple menu. * menu entries, one per line. ( means it's initially disabled. * An entry of (- means a disabled line of dashes. * A trailing /Q means a command-key equivalent. * blank line at end of menu. Type MENU ,1(4) \14 About Fractal Contours (- Type MENU ,2(4) File New/N (- (Save as Paint FileI (- Quit/Q ,3(4) Edit (Undo (- Cut/X Copy/C Paste/V Clear ,4(4) Options Contour ParametersI * A Window template * ID,(4 => pre-load the resource; 32 => purgeable) * title * BoundsRect (global Top, Left, Bottom, Right): where it appears on the screen * Vis NoGo: it's visible, does not have close box * ProcId: this is a standard type of window * Refcon, for program's use. Frac doesn't use it. Type WIND ,260(36) Fractal Contours 39 1 341 511 Visible NoGoAway 0 0 * Picture declarations. * For the Information screens. * Since RMaker doesn't know how to use these in * DITL's, we have to get in and patch it up with * ResEdit later. Suck city! * Type PICT = GNRL * ,128 * .R * Draw:Scrapbook PICT -32753 * * ,129 * .R * Draw:Scrapbook PICT -32752 * dialog box for About Fractal Contours * ID (4 => pre-load the resource; MUST NOT be purgeable!) * title * BoundsRect(global: TLBR) * Vis NoGo: it's visible, but has no close box * ProcID: Window type is modal dialog * RefCon: Unused user variable * res. ID of item list Type DLOG ,256(4) Information Box 28 24 328 485 Visible NoGoAway 1 0 256 ,257(4) Information Box #2 28 24 328 485 Visible NoGoAway 1 0 257 ,258(4) Contour Parameters 44 109 221 397 Visible NoGoAway 0 0 258 * dialog item list for About Fractal * ID (4 => pre-loaded; 32 => purgeable - it should always be purgeable.) * # Items * the first item: * a Button you can select * display rect (local coords) * title Type DITL ,256(36) 3 Button Enabled 97 14 118 99 OK Button Enabled 96 114 118 201 More Info StatText Disabled 20 10 300 400 Picture here ,257(36) 2 Button Enabled 273 205 294 290 OK StatText Disabled 20 10 300 400 Picture here * dialog item list for Setup * ID (4 => pre-loaded; 32 => purgeable - it should always be purgeable.) ,258(36) 8 * 1 BtnItem Enabled 144 32 164 92 OK * 2 BtnItem Enabled 144 184 164 244 CANCEL * 3 StatText Disabled 32 16 48 128 Level of Detail: * 4 EditText Disabled 32 128 49 162 * 5 RadioItem Enabled 64 120 80 240 Mountainous * 6 RadioItem Enabled 88 120 104 224 Foothills * 7 RadioItem Enabled 112 120 128 264 Foothills & Water * 8 StatText Disabled 64 16 83 116 Contour type: *** * Finder's Information follows. *** Type BNDL ,128(32) FRAC 0 ICN# 0 0 128 1 129 FREF 0 0 128 1 129 * a File Reference * ID, (32 => purgeable) * "APPL" : a file of type APPL (FRAC itself) gets the following icon (a mountain); * local icon ID; maps to global ID as specified in BNDL * name of file that must accompany application if transferred; omit if none. Type FREF ,128(32) APPL 0 * An icon list for the application icon (a mountain) * ID (the application icon), (32 => purgeable) * Data is Hex data (.H) * the icon data: 32 lines of 8 hex chars each * the icon mask: 32 lines of 8 hex chars each Type ICN# = GNRL ,128(32) .H 0000 0000 0000 0000 0000 0000 0000 0000 0000 E000 0003 E000 0006 1000 0006 1000 000C 0800 003C 0C00 007C 7A00 0047 E300 01C6 1100 030C 1080 0278 10C0 06EE 3CE0 0583 47F0 1F00 C118 3303 820C 61BE 1C1E 4063 FFF7 7FFF 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 * 0000 0000 0000 0000 0000 0000 0000 0000 0000 E000 0003 E000 0007 F000 0007 F000 000F F800 003F FC00 007F FE00 007F FF00 01FF FF00 03FF FF80 03FF FFC0 07FF FFE0 07FF FFF0 1FFF FFF8 3FFF FFFC 7FFF FFFE 7FFF FFFF 7FFF 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 **** end of information for the finder **** *********************************************************************** *INCLUDE fractal.code SHAR_EOF if test -f 'fractal2.c' then echo shar: over-writing existing file "'fractal2.c'" fi cat << \SHAR_EOF > 'fractal2.c' /* ' 3-Dimensional Fractal surface generating program ' From July '85 Creative Computing. */ #include <quickdraw.h> #include <toolutil.h> #define watchCursor 4 /* Should be in TOOLUTIL.H but isn't. JEC */ double ran(); /* Should be in MATH.H but isn't. JEC */ #include "fractal.h" #define TRUE (-1) #define FALSE 0 int linestart; /* True at the first of the line. */ int color; /* True when plotting land, else false. */ calcsurf(level) int level; { int i, j, length, incrby, sk; float power; CursHandle ticktock; if (!points) return; ticktock = GetCursor(watchCursor); if (ticktock) SetCursor(*ticktock); /* Show watch (wait) */ xmax = 1 << level; ymax = xmax/2; for (i=0; i<=xmax; i++) /* Clear the Array. Use i & incrby as temps. */ for (incrby=0; incrby<=ymax; incrby++) (*points)[i][incrby] = 0; for (i=1; i<= level; i++) { for (power=1.0, j=0; j<i; j++) power *= 1.8; length = 10000/power; /* = 10000/(1.8^i) */ incrby = xmax/(1 << i); /* # of line segments in a side of the triangle. */ sk = incrby * 2; calcxs(length, incrby, sk); calcys(length, incrby, sk); calcdiags(length, incrby, sk); } InitCursor(); /* Put back the arrow. */ } calcxs(len, incr, sk) /* Assign heights along x in array. */ int len; register int incr, sk; { register int y, x; int d1, d2; for (y=0; y < xmax; y += sk) { for (x = incr+y; x <= xmax; x += sk) { d1 = getdata(x-incr, y); d2 = getdata(x+incr, y); stuffdata(((d1+d2)>>1) + (int)(ran()*(len>>1)) - (len>>2), x, y); } } } calcys(len, incr, sk) /* Assign heights along y in array. */ int len; register int incr, sk; { register int y, x; int d1, d2; for (x=xmax; x >= 1; x -= sk) for (y = incr; y <= x; y += sk) { d1 = getdata(x, y+incr); d2 = getdata(x, y-incr); stuffdata(((d1+d2)>>1) + (int)(ran()*(len>>1)) - (len>>2), x, y); } } calcdiags(len, incr, sk) /* Assign heights along diagonal in array. */ int len; register int incr, sk; { register int y, x; int d1, d2; for (x=0; x < xmax; x += sk) for (y = incr; y <= xmax-x; y += sk) { d1 = getdata(x+y-incr, y-incr); d2 = getdata(x+y+incr, y+incr); stuffdata(((d1+d2)>>1) + (int)(ran()*(len>>1)) - (len>>2), x+y, y); } } getdata(x, y) register int x, y; { if (y <= ymax) return (*points)[x][y]; else return (*points)[xmax-x][xmax+1-y]; } stuffdata(d, x, y) register int d, x, y; { if (y <= ymax) (*points)[x][y] = d; else (*points)[xmax-x][xmax+1-y] = d; } /* ** Our window is already open at this point, and it is cleared, ** all we have to do now is fill it. ** Draw the 2D projection of the triangular database on the screen. */ plotdata() { register int xindex, yindex; if (!points) return; color = TRUE; /* On land to start. */ for (xindex=0; xindex<=xmax; xindex++) { /* Plot along X axis. */ linestart = TRUE; for (yindex=0; yindex<=xindex; yindex++) doplot(xindex, yindex); } for (yindex=0; yindex<=xmax; yindex++) { /* Plot along Y axis. */ linestart = TRUE; for (xindex=yindex; xindex<=xmax; xindex++) doplot(xindex, yindex); } for (xindex=0; xindex<=xmax; xindex++) { /* Plot along the diagonal. */ linestart = TRUE; for (yindex=0; yindex<=xmax-xindex; yindex++) doplot(xindex+yindex, yindex); } } doplot(xindex, yindex) int xindex, yindex; { int xcoord, ycoord, zcoord; zcoord = getdata(xindex, yindex); ycoord = scaler(yindex, 10000, xmax); xcoord = scaler(xindex, 10000, xmax) - ycoord/2; if (conttype == SETUPWATR) sealevel(&xcoord, &ycoord, &zcoord); plotto(xcoord, ycoord, zcoord); } sealevel(newx, newy, newz) int *newx, *newy, *newz; { static int oldx, oldy, oldz; /* The starting point for the next call. */ int waterx, watery, waterz; /* Where the vector hits the waterline. */ float scratch; if (linestart) { /* If at the beginning of the line */ if ((oldz = *newz) < 0) { /* and if we're underwater. */ color = FALSE; *newz = 0; /* Clip to the waterline. */ } else color = TRUE; /* Otherwise we're on land from the start. */ } else { /* Else we're in the middle of a line and ... */ if (oldz > 0 && *newz > 0) { /* start & end points both above water.. */ oldz = *newz; } else if (oldz < 0 && *newz < 0) { /* start & end points both under water... */ oldz = *newz; *newz = 0; /* Clip at the waterline */ } else { /* We're now crossing the waterline, */ /* so calculate the exact point where it dives under. */ scratch = (float) (*newz)/(*newz-oldz); /* Proportion of the line that's */ waterx = (int) ((oldx - *newx)*scratch) + *newx; /* below the water. */ watery = (int) ((oldy - *newy)*scratch) + *newy; waterz = 0; plotto(waterx, watery, waterz); /* Draw to the waterline first. */ /* The plot from the waterline to the endpoint in the new color is done elsewhere. */ if (*newz > 0) { /* Emerging from the water. */ color = TRUE; /* Set new color to 'land'. */ oldz = *newz; } else { /* Diving into the water. */ color = FALSE; /* Set new color to 'sea'. */ oldz = *newz; *newz = 0; } } } oldx = *newx; /* Save the real endpoint of the vector */ oldy = *newy; /* to use as the start of the next call. */ /* (Z taken care of individually above). */ } scaler(base, numer, denom) /* Computes base*numer/denom with long intermediate. */ register int base, numer, denom; { register long temp; temp = (long) base * (long) numer; temp /= (long) denom; return (int) temp; } plotto(x, y, z) /* Convert 3-D line to a 2-D line and plot it. */ int x, y, z; { rotate(&x, &y); /* Rotate 30 deg. towards Y in the XY plane */ tiltdown(&x, &z); /* Tip 36 deg. down in the ZX plane */ x /= 25; /* Scale 10K to 400. */ y /= 25; z /= 25; drawline(y, z); /* Show the YZ planar projection. */ } rotate(x, y) /* Rotate XY plane 30 deg positive. */ int *x, *y; { cordic(x, y, 5, 17); } tiltdown(x, z) /* Rotate XZ plane 36 deg negative (+?). */ int *x, *z; { cordic(x, z, 5, (conttype == SETUPMTN) ? 20 : -20); } drawline(x, y) /* Draw either a line from the last endpoint */ int x, y; /* to the given point, or only a point at x,y. */ { static int lastx, lasty; x += x/10 + 10; /* Quick x1.1 + tiny offset. */ if (conttype == SETUPMTN) y = 220 - y; /* Move the baseline for mountains. */ else y = 80 - y; if (linestart || !color) /* Only a point then. */ MoveTo(x, y); LineTo(x, y); lastx = x; lasty = y; linestart = FALSE; /* Stuck in the middle with you... */ } cordic(x, y, scale, count) /* Spin XY vector 'count' steps to the left using */ int *x, *y; /* CORDIC algorithm with a shift factor of 'scale'. */ register int scale, count; /* Rotates atan(1/(2^scale)) degrees/step. */ /* (Scale of 5 is 1.79 deg/step; 4 = 3.57 d/s...) */ /* *x & *y should be large for accuracy. */ { register int tempx, tempy; tempx = *x; tempy = *y; if (count>0) /* Positive count is CCW (left) */ for (; count; count--) { tempx -= (tempy>>scale); tempy += (tempx>>scale); } else /* Negative is CW (right) */ for (; count; count++) { tempx += (tempy>>scale); tempy -= (tempx>>scale); } *x = tempx; *y = tempy; } SHAR_EOF # End of shell archive exit 0