home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-02-20 | 63.0 KB | 1,619 lines |
- Newsgroups: comp.sources.misc
- organization: MIT Lincoln Laboratory, Lexington MA
- subject: v10i078: Continental Drift Simulator part 2/2
- from: davea@ll-vlsi.arpa (Dave Allen)
- Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
-
- Posting-number: Volume 10, Issue 78
- Submitted-by: davea@ll-vlsi.arpa (Dave Allen)
- Archive-name: tec/part02
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of shell archive."
- # Contents: tec-v3/var.h tec-v3/ibmpc.c tec-v3/tec.mak tec-v3/tec1.c
- # tec-v3/tec2.c
- # Wrapped by davea@vdd on Fri Feb 16 08:39:20 1990
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'tec-v3/var.h' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tec-v3/var.h'\"
- else
- echo shar: Extracting \"'tec-v3/var.h'\" \(440 characters\)
- sed "s/^X//" >'tec-v3/var.h' <<'END_OF_FILE'
- X/* These variables are the adjustable parameters; they are described and
- given default values in tec3.c */
- X
- extern long XSIZE, YSIZE, MAXSTEP;
- extern long MAXLIFE, MAXBUMP, BUMPTOL;
- extern long DRAWEVERY, BLOBLEVEL, DRAWMODE;
- extern long ZINIT, ZSUBSUME, ZCOAST;
- extern long ZSHELF, ZMOUNTAIN;
- extern long RIFTPCT, DOERODE, ERODERND;
- extern long MAXCTRTRY, RIFTDIST, BENDEVERY;
- extern long BENDBY, SPEEDBASE, SPEEDRNG;
- extern double MR[];
- END_OF_FILE
- if test 440 -ne `wc -c <'tec-v3/var.h'`; then
- echo shar: \"'tec-v3/var.h'\" unpacked with wrong size!
- fi
- # end of 'tec-v3/var.h'
- fi
- if test -f 'tec-v3/ibmpc.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tec-v3/ibmpc.c'\"
- else
- echo shar: Extracting \"'tec-v3/ibmpc.c'\" \(22685 characters\)
- sed "s/^X//" >'tec-v3/ibmpc.c' <<'END_OF_FILE'
- X/* Modified for IBM PC/XT/AT, 9/12/89..9/01/90 from file ami.c:
- X Peter C. Lind, M.Sc., lind@maccs.ca
- X McMaster University,
- X 1280 Main St. W.,
- X Hamilton, ON
- X Canada L8S 4K1
- X
- X This file contains only functions which are specific to the IBM PC/XT/AT
- X under Turbo C 2.00+. It connects to the other source files via a small
- X number of functions. main() is here. It calls init() and onestep().
- X The other source files can call rnd(), draw() and panic() from this file;
- X these are at the end of the file. */
- X
- X#include "const.h"
- X#include "var.h"
- X
- X#include <conio.h>
- X#include <dos.h>
- X#include <graphics.h>
- X#include <stdlib.h>
- X#include <stdio.h>
- X#include <time.h>
- X
- X#define TRUE !0
- X#define FALSE 0
- X
- X#define STDOUT_HANDLE 1 /* DOS file handle for stdout */
- X
- extern unsigned long RangeSeed; /* TC random number generator */
- extern unsigned char t[2][MAXX][MAXY]; /* Defined in tec1.c */
- extern short step; /* Also defined in tec1.c */
- X
- unsigned long class;
- unsigned short code;
- X
- X/* EGA: 16 colors used: Black, 2 shades of blue (dark, light), 2 of green,
- X 2 of red, 2 of purple (magenta), 2 white (light gray, white), and
- X 2 yellow (brown, yellow). */
- X#define NUMCOLORS 13
- X#define MAXCOLOR 12
- unsigned short colors [NUMCOLORS] = {
- X BLACK,
- X BLUE,LIGHTBLUE,GREEN,LIGHTGREEN,
- X YELLOW,MAGENTA,LIGHTMAGENTA,
- X RED,LIGHTRED,BROWN,
- X LIGHTGRAY,WHITE
- X };
- X
- unsigned short CellXsize,CellYsize; /* Size of a tec pixel */
- int MaxX,MaxY,CentX,CentY; /* Screen parameters */
- int LastVideoMode; /* Video mode at program start up */
- int gdriver; /* Graphics driver used for plotting */
- int BrightColor,DimColor,BorderColor,BackgroundColor,BarColor;
- int Bar3Dcolor,PlotBackColor;
- int wx1,wy1,wx2,wy2,winMaxX,winMaxY,origY2; /* Map window coords */
- X
- int LegCellWid,LegCellHgt,LegHalfWid; /* Legend parameters */
- int legX1,legY1,legX2,legY2,legCY;
- X
- short InColor; /* TRUE if mode is EGA or VGA */
- short Mode3D; /* TRUE when plotting in 3d mode */
- short Slow3D; /* TRUE for slow 3d plotting */
- short AllStop; /* TRUE if user wants to quit */
- short WantPrint; /* TRUE if user wants to print */
- short WantPause; /* TRUE if user wants to pause */
- short WantChangePlot; /* TRUE if user wants to change
- X plotting style */
- short NeedLegend; /* TRUE if legend should be drawn */
- short NoLegend; /* TRUE if legend should be erased */
- X
- int msgY; /* Y coord of message line top */
- X
- X#define xaddon 5 /* Width of 3-d bars */
- int ix; /* Initial X coord for 3-d */
- int iy; /* Initial Y coord for 3-d */
- int yaddon; /* Y increment for 3-d plotting */
- X
- X#define ESC 27 /* ASCII code for ESC */
- X
- X#define NUM_CREDITS 5
- static char title[] = "TEC Continental Drift Simulator";
- static char credit[NUM_CREDITS][42] =
- X {
- X "Version 3",
- X "originally written by David Allen",
- X "adapted for IBM PC/XT/AT by Peter C. Lind",
- X "Copyright (c) 1989,1990",
- X "press any key to begin"
- X };
- int CredFont,TitleSize,CredSize;
- X
- void TakeMax (a,b)
- X /* `a' gets maximum of `a' and `b'. */
- X int *a,b;
- X {
- X if (b > *a)
- X *a = b;
- X }
- X
- void panic (s)
- X char *s;
- X /* Used when some fatal inconsistency is found in the database;
- X its function is to immediately free all graphics memory and exit. */
- X {
- X closegraph();
- X textmode(LastVideoMode);
- X printf("TEC PANIC: %s\n",s);
- X exit(0);
- X }
- X
- void message (s)
- X char *s;
- X /* Displays message `s' at the bottom of the screen. */
- X {
- X struct viewporttype ov;
- X
- X getviewsettings(&ov); /* Save current viewport */
- X setviewport(0,0,MaxX,MaxY,TRUE); /* Select entire screen */
- X setfillstyle(SOLID_FILL,BarColor);
- X bar(0,msgY,MaxX,MaxY); /* Blank bottom line */
- X settextjustify(CENTER_TEXT,TOP_TEXT);
- X setcolor(DimColor);
- X outtextxy(CentX,msgY+1,s); /* Output message */
- X setviewport(ov.left,ov.top,ov.right, /* Select old viewport */
- X ov.bottom,ov.clip);
- X }
- X
- void WaitKeyPress ()
- X /* Wait for user to press a key. */
- X {
- X while (!kbhit())
- X ;
- X if (!(getch())) /* Consume any extended code */
- X getch();
- X }
- X
- void Intro ()
- X /* Displays the introductory credits panel. */
- X {
- X int th,tw,x1,y1,x2,y2,y,ht,hc,cx,i,TwoEms;
- X
- X /* Calculate dimensions of panel required */
- X settextstyle(CredFont,HORIZ_DIR,TitleSize); /* Measure title line */
- X ht = textheight(title); th = (ht * 3);
- X tw = textwidth(title) + (textwidth("M") << 1);
- X settextstyle(CredFont,HORIZ_DIR,CredSize); /* Measure credit lines */
- X TwoEms = textwidth("M") << 1;
- X hc = 0;
- X for (i = 0; i < NUM_CREDITS; i++) /* Find max. height, width */
- X {
- X TakeMax(&hc,textheight(credit[i]));
- X TakeMax(&tw,textwidth(credit[i])+TwoEms);
- X }
- X hc <<= 1;
- X th += (hc * NUM_CREDITS);
- X x1 = (MaxX - tw) >> 1; x2 = x1 + tw - 1;
- X y1 = (MaxY - th) >> 1; y2 = y1 + th - 1;
- X cx = (tw >> 1) - 1;
- X
- X /* Draw panel and display title and credits */
- X setfillstyle(SOLID_FILL,BarColor); setcolor(BarColor);
- X bar3d(x1,y1,x2,y2,4,TRUE);
- X setviewport(x1+1,y1+1,x2-1,y2-1,TRUE);
- X y = ht;
- X settextstyle(CredFont,HORIZ_DIR,TitleSize);
- X settextjustify(CENTER_TEXT,TOP_TEXT);
- X setcolor(BrightColor);
- X outtextxy(cx,y,title);
- X y += (ht << 1);
- X settextstyle(CredFont,HORIZ_DIR,CredSize);
- X for (i = 0; i < NUM_CREDITS; i++, y += hc)
- X outtextxy(cx,y,credit[i]);
- X WaitKeyPress();
- X setviewport(0,0,MaxX,MaxY,TRUE);
- X cleardevice();
- X }
- X
- void CGAdefaults ()
- X /* Common routine to set CGA/MCGA defaults. */
- X {
- X BarColor = 1; BrightColor = 0; DimColor = 0;
- X BorderColor = 1; BackgroundColor = 0; Bar3Dcolor = 1; PlotBackColor = 0;
- X InColor = FALSE; Mode3D = TRUE; Slow3D = FALSE;
- X }
- X
- int initCGA ()
- X /* Initialize CGA mode. */
- X {
- X CGAdefaults();
- X CredFont = SMALL_FONT; TitleSize = 6; CredSize = 4;
- X return(CGAHI);
- X }
- X
- int initMCGA ()
- X /* Initialize MCGA mode. */
- X {
- X CGAdefaults();
- X CredFont = SMALL_FONT; TitleSize = 6; CredSize = 4;
- X return(MCGAHI);
- X }
- X
- void EGAdefaults ()
- X /* Common routine to set EGA/VGA defaults. */
- X {
- X BarColor = DARKGRAY; BrightColor = WHITE; DimColor = LIGHTGRAY;
- X PlotBackColor = BLACK;
- X BorderColor = DARKGRAY; BackgroundColor = BLACK; Bar3Dcolor = LIGHTGRAY;
- X InColor = TRUE; Mode3D = FALSE;
- X LegCellWid = 20; LegHalfWid = 10;
- X NeedLegend = TRUE;
- X }
- X
- int initEGA ()
- X /* Initialize EGA */
- X {
- X EGAdefaults();
- X CellXsize = 7; CellYsize = 3;
- X CredFont = TRIPLEX_FONT; TitleSize = 3; CredSize = 2;
- X LegCellHgt = 16;
- X return(EGAHI);
- X }
- X
- int initVGA ()
- X /* Initialize VGA */
- X {
- X EGAdefaults();
- X CellXsize = 7; CellYsize = 5;
- X CredFont = TRIPLEX_FONT; TitleSize = 4; CredSize = 3;
- X LegCellHgt = 16;
- X return(VGAHI);
- X }
- X
- void grafinit ()
- X /* Detect the video hardware and configure accordingly; display credits */
- X {
- X int gm,tw,th,rc;
- X
- X LastVideoMode = LASTMODE;
- X detectgraph(&gdriver,&gm);
- X switch (gdriver)
- X {
- X case CGA: gm = initCGA(); /* CGA high-res mode: 640 x 200, 2 colors */
- X break;
- X case MCGA: gm = initMCGA(); /* MCGA high-res mode: 640 x 480, 2 colors */
- X break;
- X case EGA: gm = initEGA(); /* EGA high-res mode: 640 x 350, 16 colors */
- X break;
- X case VGA: gm = initVGA(); /* VGA high-res mode: 640 x 480, 16 colors */
- X break;
- X default: printf("TEC 3:\n");
- X printf("Unable to operate with detected display type\n");
- X printf("Require CGA, MCGA, EGA or VGA to run\n");
- X exit(0);
- X }
- X initgraph(&gdriver,&gm,"");
- X if ((rc = graphresult()))
- X {
- X printf("TEC 3:\n");
- X printf("BGI Error #%d: %s\n",rc,grapherrormsg(rc));
- X textmode(LastVideoMode);
- X exit(0);
- X }
- X MaxX = getmaxx(); MaxY = getmaxy();
- X CentX = MaxX >> 1; CentY = MaxY >> 1;
- X Intro(); /* Intro panel */
- X settextstyle(DEFAULT_FONT,HORIZ_DIR,1); /* Choose font */
- X tw = textwidth("M"); th = textheight("M"); /* Font's dimensions */
- X msgY = MaxY - th - 2;
- X
- X setfillstyle(SOLID_FILL,BarColor); bar(0,0,MaxX,th+1); /* Top bar */
- X bar(0,msgY,MaxX,MaxY); /* Bottom bar */
- X setcolor(BrightColor);
- X settextjustify(LEFT_TEXT,TOP_TEXT);
- X moveto(tw,1); outtext("TEC ");
- X setcolor(DimColor); outtext("Continental Drift Simulator");
- X settextjustify(RIGHT_TEXT,TOP_TEXT);
- X outtextxy(MaxX-tw,1,"David Allen, Peter C. Lind");
- X
- X setcolor(BorderColor); rectangle(0,th+1,MaxX,msgY); /* Map border */
- X wx1 = 2; wy1 = th + 3; wx2 = MaxX - 2; wy2 = msgY - 2;
- X winMaxX = wx2 - wx1; winMaxY = wy2 - wy1; origY2 = wy2;
- X
- X legX2 = winMaxX; legX1 = legX2 - (LegCellWid * NUMCOLORS); /* Legend coords */
- X legY2 = winMaxY - 1; legY1 = legY2 - LegCellHgt;
- X legCY = (legY2 + legY1) >> 1;
- X
- X setviewport(wx1,wy1,wx2,wy2,TRUE);
- X
- X ix = (wx2 - wx1) - (XSIZE * xaddon);
- X yaddon = ((wy2 - wy1 + 1) / YSIZE) + 1;
- X iy = (wy2 - wy1 + 1) - (YSIZE * yaddon);
- X }
- X
- void grafexit ()
- X /* Just close all the things that were opened, then exit(). */
- X {
- X closegraph();
- X textmode(LastVideoMode);
- X printf("TEC ended. Bye\n");
- X exit(0);
- X }
- X
- unsigned GetIOCTL (fh)
- X /* Returns the IOCTL word for file handle `fh'. */
- X int fh;
- X {
- X struct REGPACK regs;
- X
- X regs.r_ax = 0x4400; /* DOS Int. sub-function: "Get IOCTL info" */
- X regs.r_bx = fh; /* File handle in BX */
- X intr(33,®s); /* Call DOS */
- X return(regs.r_dx); /* IOCTL info in DX */
- X }
- X
- void PrintMenu ()
- X /* Displays the print menu. */
- X {
- X message("Print to stdout: G)eneric T)ext P)ostscript ESC=No print");
- X }
- X
- void TryToPrint ()
- X /* Attempts to initiate printing, but first warns the user that stdout
- X must have been redirected on the DOS command line. Also allows the
- X user to choose the print format:
- X
- X G Generic
- X T Text
- X P Postscript
- X ESC No print
- X */
- X {
- X /* Disallow printing if stdout is still directed to the console screen,
- X (ie. IOCTL for stdout indicates device with standard console output). */
- X if ((GetIOCTL(STDOUT_HANDLE) & 0x0082) == 0x0082)
- X {
- X message("*** stdout not redirected. [ Press any key ] ***");
- X do { /* Wait for keypress */
- X } while (!kbhit());
- X if (!getch()) /* Consume character */
- X getch(); /* and extended code, if any */
- X return;
- X }
- X
- X PrintMenu();
- X do {
- X char c;
- X
- X if (!(c = getch()))
- X getch();
- X else
- X switch (c)
- X {
- X case ESC: return;
- X break;
- X case 'g':
- X case 'G': message("Sending Generic Mode to stdout...");
- X tecst(step % 2,DRAWMODE_GENERIC);
- X PrintMenu();
- X break;
- X case 't':
- X case 'T': message("Sending Text Mode to stdout...");
- X tecst(step % 2,DRAWMODE_TEXT);
- X PrintMenu();
- X break;
- X case 'p':
- X case 'P': message("Sending Postscript Mode to stdout...");
- X tecst(step % 2,DRAWMODE_GRAY);
- X PrintMenu();
- X break;
- X default: break;
- X }
- X } while (TRUE);
- X }
- X
- void Set3Dstyle ()
- X /* Allows user to choose fast or slow 3-D plotting. */
- X {
- X short OK;
- X
- X Mode3D = TRUE;
- X message("3-D Style: S)low F)ast");
- X do {
- X OK = TRUE;
- X switch (getch())
- X {
- X case 's':
- X case 'S': Slow3D = TRUE;
- X break;
- X case 'f':
- X case 'F': Slow3D = FALSE;
- X break;
- X default: OK = FALSE;
- X break;
- X }
- X } while (!OK);
- X }
- X
- void ChangePlotStyle ()
- X /* Allows user to switch between standard plotting and 3-D plotting. Should
- X only be called if program is running under EGA/VGA. */
- X {
- X short OK;
- X
- X message("Switch plotting style: S)tandard 3)D");
- X do {
- X OK = TRUE;
- X switch (getch())
- X {
- X case '\0': getch();
- X break;
- X case '3': NoLegend = !Mode3D;
- X Set3Dstyle();
- X break;
- X case 's':
- X case 'S': NeedLegend = Mode3D;
- X Mode3D = FALSE;
- X break;
- X default: OK = FALSE;
- X break;
- X }
- X } while (!OK);
- X }
- X
- void checkmouse ()
- X /* Standard event handler. Currently on the IBM PC/XT/AT, can only poll the
- X keyboard for user actions (no mouse support [yet!]):
- X
- X <ESC> Quit program right away
- X <SPACE> Pause
- X g or G Change plotting style
- X p or P Print out the current values of t[src]
- X using tecst() in tec1.c. */
- X {
- X short i,j,k;
- X char c;
- X
- X if (!kbhit()) /* Key pressed? */
- X return; /* No: Exit */
- X if (!(c = getch())) /* Read the key. Is it '\0'? */
- X {
- X getch(); return; /* Yes: Consume extended code and exit */
- X }
- X switch (c) /* No: Look at key pressed */
- X {
- X case ESC: grafexit();
- X break;
- X case ' ': WantPause = TRUE;
- X break;
- X case 'g':
- X case 'G': if (InColor)
- X ChangePlotStyle();
- X else
- X Set3Dstyle();
- X break;
- X case 'p':
- X case 'P': TryToPrint();
- X break;
- X default: break;
- X }
- X }
- X
- int rnd (top)
- X int top;
- X /* Returns a random number in the range 0..`top'-1. */
- X {
- X return(random(top));
- X }
- X
- void ResetPlotSettings ()
- X /* Resets the 3-D plot settings (used after message() calls). */
- X {
- X if (Mode3D)
- X {
- X setfillstyle(SOLID_FILL,PlotBackColor);
- X setcolor(Bar3Dcolor);
- X }
- X }
- X
- void PlotMessage ()
- X /* Prints the plot message */
- X {
- X message("Plotting... G)raphing style P)rint CR=Skip SP=Pause ESC=Quit");
- X }
- X
- int PlotKeyCheck ()
- X /* Called when a key is pressed while plotting. If the key was ESC or
- X SPACE, then TRUE is returned. Otherwise, FALSE is returned. If the
- X key pressed was ESC, 'p' or 'P', the key is not consumed. */
- X {
- X char c;
- X
- X switch (c = getch())
- X {
- X case '\0': getch(); /* Discard extended code */
- X break;
- X case ESC: AllStop = TRUE; /* Set quit flag... */
- X case '\r': return(TRUE); /* Exit plot routine */
- X break;
- X case ' ': WantPause = TRUE;
- X break;
- X case 'g':
- X case 'G': if (InColor) /* Defer in EGA/VGA */
- X WantChangePlot = TRUE;
- X else
- X { /* Change on the fly in CGA/MCGA */
- X Set3Dstyle();
- X PlotMessage();
- X ResetPlotSettings();
- X }
- X break;
- X case 'p':
- X case 'P': WantPrint = TRUE; /* Set print request flag */
- X break;
- X default: break; /* Ignore all else */
- X }
- X return(FALSE);
- X }
- X
- void draw3d (src)
- X /* Draws a 3-D picture of the t[src] in the center of the current viewport
- X using Turbo C's bar3d() function. When `Slow3D' is TRUE, each "pixel" of
- X t[src] is printed as a standing 3-D block; when `Slow3D' is FALSE,
- X adjacent "pixels" in the same row with equal heights are merged and
- X plotted as a wider standing 3-D block, thereby speeding up the plotting
- X process (with a loss of attractiveness). */
- X short src;
- X {
- X int boty,x1,x2,x3,x,y,cx,cy,h,nh,c;
- X
- X ResetPlotSettings();
- X
- X x = ix; y = iy;
- X top: for (cx = 0; cx < XSIZE; cx++, y += yaddon)
- X {
- X x1 = x; x2 = x1 + xaddon; x3 = x + (xaddon * XSIZE);
- X h = -1; c = 0;
- X for (cy = 0; cy < YSIZE; cy++)
- X {
- X nh = t[src][cx][cy] >> 3;
- X if ((nh != h) || Slow3D)
- X {
- X if ((c || Slow3D) && (h >= 0))
- X bar3d(x1,y,x2,y-h,3,TRUE);
- X h = nh; x1 = x2; c = 1;
- X if (Slow3D || 1)
- X x2 += xaddon;
- X }
- X else
- X {
- X x2 += xaddon; c++;
- X }
- X }
- X if (c)
- X bar3d(x1,y,x3,y-nh,3,TRUE);
- X x -= (xaddon >> 1);
- X
- X if (kbhit())
- X if (PlotKeyCheck())
- X return;
- X }
- X }
- X
- void DisplayLegend ()
- X /* Draws the colors legend for EGA/VGA modes. */
- X {
- X int i,x;
- X char num[3];
- X
- X settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
- X settextjustify(CENTER_TEXT,CENTER_TEXT);
- X
- X /* Special case for black color */
- X x = legX1;
- X setcolor(DARKGRAY);
- X setfillstyle(SOLID_FILL,colors[0]);
- X bar3d(x,legY1,x+LegCellWid,legY2,0,FALSE);
- X outtextxy(x+LegHalfWid,legCY,"0");
- X x += LegCellWid;
- X
- X /* Draw other colors in a loop, with black numbers */
- X setcolor(BLACK);
- X for (i = 1; i < NUMCOLORS; i++, x += LegCellWid)
- X {
- X setfillstyle(SOLID_FILL,colors[i]);
- X bar3d(x,legY1,x+LegCellWid,legY2,0,FALSE);
- X sprintf(num,"%d",i);
- X outtextxy(x+LegHalfWid,legCY,num);
- X };
- X wy2 = origY2 - LegCellHgt - 2; /* Resize viewport to protect legend */
- X setviewport(wx1,wy1,wx2,wy2,TRUE);
- X }
- X
- void RemoveLegend ()
- X /* Effectively removes the colors legend by resetting the map viewport to
- X full size. */
- X {
- X wy2 = origY2; setviewport(wx1,wy1,wx2,wy2,TRUE);
- X }
- X
- void draw (src)
- X short src;
- X /* When `Mode3D' is TRUE, this function calls draw3d() and exits. Otherwise,
- X this function takes the array m[src] and draws it on the screen, in a
- X hopefully efficient way. The function tries to make long horizontal
- X patches that are all the same color. Then they can be rendered by a
- X graphics function that draws arbitrary rectangles quickly. */
- X {
- X register short i,j,k,x;
- X
- X checkmouse();
- X PlotMessage();
- X
- X /* Erase the viewport first */
- X if (NoLegend)
- X {
- X RemoveLegend(); NoLegend = FALSE;
- X }
- X setcolor(BackgroundColor); clearviewport();
- X
- X if (Mode3D) /* If in 3-D mode, then call draw3d() */
- X {
- X draw3d(src); return;
- X }
- X
- X /* Draw color legend whenever it needs to be displayed. */
- X if (NeedLegend)
- X {
- X DisplayLegend(); NeedLegend = FALSE;
- X }
- X
- X /* For each scan line, start at the left edge */
- X for (j = 0, i = 0; j < YSIZE; j++, i = 0)
- X {
- X int x1,y1,x2,y2;
- X
- X /* If the current square is not ocean, set x to its color */
- X top: if ((x = t[src][i][j] >> 2) > 1)
- X {
- X /* Go as far along to the right as you can in this color */
- X k = i + 1;
- X while (((t[src][k][j] >> 2) == x) && (k < XSIZE-1))
- X k++;
- X
- X /* Draw a short, wide rectangle */
- X if (x > 27)
- X x = 27;
- X x1 = i * CellXsize; y1 = j * CellYsize;
- X x2 = k * CellXsize; y2 = y1 + CellYsize - 1;
- X setfillstyle(SOLID_FILL,colors[x]);
- X bar(x1,y1,x2,y2);
- X i = k-1;
- X
- X if (kbhit())
- X if (PlotKeyCheck())
- X return;
- X }
- X
- X /* If not at end of scanline, do more; else start next scanline */
- X if (i < XSIZE-1)
- X {
- X i++;
- X goto top;
- X }
- X }
- X }
- X
- void main (argc,argv)
- X /* Initializes everything and enters a (finite) loop that repeatedly calls
- X onestep() and checkmouse() until the maximum step is reached or the user
- X quits. */
- X int argc;
- X char **argv;
- X {
- X char menu[80];
- X
- X randomize(); /* Randomize random number generator using DOS time */
- X
- X /* Initialize everything */
- X AllStop = WantPrint = WantPause = WantChangePlot = FALSE; /* Clear deferrals */
- X NoLegend = FALSE;
- X grafinit();
- X message("Setting up...");
- X init(*++argv); /* Perform major initialization */
- X checkmouse(); /* Give user a chance to do something */
- X
- X /* Call onestep() once per step; then check for user key actions */
- X for (step = 0; step < MAXSTEP; step++)
- X {
- X /* Check for deferred commands */
- X if (AllStop)
- X grafexit();
- X if (WantPrint)
- X TryToPrint();
- X if (WantChangePlot)
- X ChangePlotStyle();
- X if (WantPause)
- X {
- X message("[ Pausing -- Press any Key ]");
- X WaitKeyPress();
- X }
- X WantPrint = WantPause = WantChangePlot = FALSE; /* Clear deferrals */
- X
- X /* Do some work */
- X sprintf(menu,"Thinking [%d]... G)raphing style P)rint SP=Pause ESC=Quit",
- X step);
- X message(menu);
- X onestep();
- X checkmouse();
- X }
- X
- X /* Reached end of simulation without error or user quit signal. */
- X message("Execution terminated -- Press any key");
- X
- X WaitKeyPress(); /* Loop forever until user pressed a key */
- X
- X closegraph(); /* Shut down */
- X textmode(LastVideoMode);
- X }
- END_OF_FILE
- if test 22685 -ne `wc -c <'tec-v3/ibmpc.c'`; then
- echo shar: \"'tec-v3/ibmpc.c'\" unpacked with wrong size!
- fi
- # end of 'tec-v3/ibmpc.c'
- fi
- if test -f 'tec-v3/tec.mak' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tec-v3/tec.mak'\"
- else
- echo shar: Extracting \"'tec-v3/tec.mak'\" \(1500 characters\)
- sed "s/^X//" >'tec-v3/tec.mak' <<'END_OF_FILE'
- X# Make file for TEC under Turbo C 2.0
- X# Peter C. Lind, Elec. & Comp. Eng., McMaster University, Hamilton, ON., 1990.
- X# NOTE: Read the comments in this file before proceeding; the macros defining
- X# directories may need to be modified to work properly on your system;
- X# also, certain macros may be altered to produce 80186/80286 code and/or
- X# 80x87 code.
- X
- X# Turbo C Directory (Change as needed; DOS path \ must be specified
- X# as \\ at the end of a line)
- TCD=\TC\\
- X
- X# Memory Model (Change c to l for large, or h for huge)
- MDL=c
- X
- X# Path to libraries (Change as needed; DOS path \ must be specified
- X# as \\ at the end of a line)
- LIB=\TC\LIB\\
- X
- X# Instruction Set (Add -1 after = to enable 80186/80286)
- INST=
- X
- X# 80x87 Support (Add -f87 after = to enable 80x87 code generation, and...)
- XFLP=
- X
- X# 80x87 Support (...change emu to fp87)
- XFLT=emu
- X
- X# Compiler options:
- X# -c Compile to OBJ
- X# -G Optimize for speed
- X# -w- Suppress warnings
- X# -a Align on word boundary
- OPTS=-c -m$(MDL) -G -w- -a $(INST) $(FLP)
- X
- X
- tec.exe: ibmpc.obj tec1.obj tec2.obj tec3.obj
- X $(TCD)tlink $(LIB)c0$(MDL) ibmpc tec1 tec2 tec3, tec, , \
- X $(LIB)graphics $(LIB)$(FLT) $(LIB)math$(MDL) $(LIB)c$(MDL)
- X
- ibmpc.obj: ibmpc.c const.h var.h
- X $(TCD)tcc $(OPTS) ibmpc.c
- X
- tec1.obj: tec1.c const.h var.h
- X $(TCD)tcc $(OPTS) tec1.c
- X
- tec2.obj: tec2.c const.h var.h
- X $(TCD)tcc $(OPTS) tec2.c
- X
- tec3.obj: tec3.c const.h var.h
- X $(TCD)tcc $(OPTS) tec3.c
- END_OF_FILE
- if test 1500 -ne `wc -c <'tec-v3/tec.mak'`; then
- echo shar: \"'tec-v3/tec.mak'\" unpacked with wrong size!
- fi
- # end of 'tec-v3/tec.mak'
- fi
- if test -f 'tec-v3/tec1.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tec-v3/tec1.c'\"
- else
- echo shar: Extracting \"'tec-v3/tec1.c'\" \(21292 characters\)
- sed "s/^X//" >'tec-v3/tec1.c' <<'END_OF_FILE'
- X/* This program is Copyright (c) 1990 David Allen. It may be freely
- X distributed as long as you leave my name and copyright notice on it.
- X I'd really like your comments and feedback; send e-mail to
- X davea@vlsi.ll.mit.edu, or send us-mail to David Allen, 10 O'Moore Ave,
- X Maynard, MA 01754. */
- X
- X/* This is the file containing all of the important functions except for
- X trysplit (), which splits a continent into pieces. Also, all of the main
- X arrays are declared here, even a couple that are only used by functions in
- X tec2.c. The array declarations are first, followed by the sequencing
- X function onestep () and some miscellaneous routines including the text
- X output routines; initialization routines and the routines that do all
- X the interesting stuff are last. */
- X
- X
- X#include "const.h"
- X#include "var.h"
- X
- X#include <stdio.h>
- X
- X/* These defines are used for the PostScript output section of tecst(). */
- X#define D ((double) 432 / ((XSIZE > YSIZE) ? XSIZE : YSIZE))
- X#define ZMAX 128
- X#define XX(x) (108 + ((x) * D))
- X#define YY(y) (612 - ((y) * D))
- X#define ZZ(z) (1 - (float) ((z > ZMAX) ? ZMAX : z) / (ZMAX))
- X
- X
- X/* The following arrays are global and most are used by functions in both
- X source files. The two main ones are m and t. Each is set up to be two
- X 2-d arrays, where each array is the size of the whole world. M is the
- X map; elements in m are indices of plates, showing which squares are
- X covered by which plate. T is the topography; elements in t are altitudes. */
- X
- char m[2][MAXX][MAXY]; unsigned char t[2][MAXX][MAXY];
- X
- X/* Several arrays are used by the binary blob segmenter, segment() in tec2.c.
- X These include r, which is used to store fragment indices; many fragments
- X make up one region during a segmentation. Kid is a lookup table; fragment
- X k belongs to region kid[k] after a segmentation is finished. Karea[k]
- X is the area of fragment k. */
- X
- char r[MAXX][MAXY], kid[MAXFRAG]; short karea [MAXFRAG];
- X
- X/* The merge routine gets information from the move routine; when the move
- X routine puts a square of one plate on top of another plate, that information
- X is recorded in the merge matrix mm. */
- X
- char mm[MAXPLATE][MAXPLATE];
- X
- X/* The erosion routine needs an array to store delta information; during an
- X erosion, the increases or decreases in elevation are summed in e and then
- X applied all at once to the topography. */
- X
- char e[MAXX][MAXY];
- X
- X/* Several routines need temporary storage for areas and plate identifiers. */
- X
- short tarea[MAXPLATE]; short ids[MAXPLATE];
- X
- X/* The plates in use are stored in this data structure. Dx,dy are the
- X values to move by THIS STEP ONLY; odx,ody are the permanent move
- X values; rx,ry are the remainder x and y values used by newdxy() to
- X determine dx,dy; age is the age of the plate, in steps; area is the
- X area of the plate, in squares; id is the value in the m array which
- X corresponds to this plate; next is a pointer to the next occupied
- X element of the plate array. */
- X
- struct plate p [MAXPLATE];
- X
- X/* The linked list header for available plates and used plates are global,
- X as is the step counter. */
- X
- short pavail, phead, step;
- X
- X
- onestep () {
- X /* This is the sequencing routine called by main once per step.
- X It just calls the important subfunctions in order:
- X - trysplit finds a plate to break up, and computes new velocities
- X - newdxy computes the deltas to move each plate this step
- X - move moves the plates
- X - merge determines results when plates rub together
- X - erode erodes the terrain, adding or subtracting at the margins
- X - draw draw the resulting array once every DRAWEVERY steps
- X The m and t arrays are double-buffered in the sense that operations go
- X from m[0] to m[1] or vice-versa; src and dest determine which is which. */
- X
- X short src, dest;
- X
- X src = step % 2; dest = 1 - src;
- X if (rnd (100) < RIFTPCT) trysplit (src);
- X newdxy ();
- X move (src, dest);
- X merge (dest);
- X if (DOERODE) erode (dest);
- X if (step && !(step % DRAWEVERY)) draw (dest); }
- X
- X
- palloc () {
- X /* Allocate a plate from the array and return its index. All the fields
- X of the plate are initialized to 0, except `next'. That field is used to
- X link together the plate structures in use. */
- X
- X short x;
- X
- X if (!pavail) panic ("No more objects");
- X x = pavail; pavail = p[x].next;
- X p[x].next = phead; phead = x;
- X p[x].area = 0; p[x].age = 0;
- X p[x].rx = 0; p[x].ry = 0;
- X p[x].odx = 0; p[x].ody = 0;
- X p[x].dx = 0; p[x].dy = 0;
- X return ((int) x); }
- X
- X
- pfree (n) short n; {
- X /* Return a plate array element to the pool of available elements.
- X To check for infinite loops, the variable guard is incremented
- X at each operation; if the number of operations exceeds the maximum
- X possible number, the program panics. */
- X
- X short i, guard = 0;
- X
- X if (phead == n) phead = p[n].next;
- X else {
- X for (i=phead; p[i].next!=n; i=p[i].next)
- X if (++guard > MAXPLATE) panic ("Infinite loop in pfree");
- X p[i].next = p[n].next; }
- X p[n].next = pavail; pavail = n; }
- X
- X
- tecst (src, drawmode) short src, drawmode; {
- X /* This function is called whenever map output is called for. It looks
- X at the parameter `drawmode' to decide between long text, simple text,
- X and PostScript output formats. Note that the default for this
- X function is no output at all, corresponding to DRAWMODE_NONE. */
- X
- X register short i,j,k;
- X
- X if (drawmode == DRAWMODE_GENERIC)
- X for (j=0; j<YSIZE; j++) for (i=0, k=0; i<XSIZE; i++) {
- X printf ("%4d", t[src][i][j]);
- X if (!(++k % 18)) printf ("\n"); }
- X else if (drawmode == DRAWMODE_TEXT) {
- X for (j=0; j<YSIZE; j++) {
- X for (i=0; i<XSIZE; i++) {
- X if ((k = t[src][i][j]) < ZCOAST) k = 0;
- X else if (k > ZMOUNTAIN) k = 2; else k = 1;
- X printf ("%d", k); }
- X printf ("\n"); }
- X printf ("\n"); }
- X else if (drawmode == DRAWMODE_GRAY) {
- X printf ("%%!PS-Adobe-1.0\n/d %4.2f def\n", D);
- X printf ("37.5 45 { dup mul exch dup mul add 1 exch sub } setscreen\n");
- X printf ("/r { setgray moveto d 0 rlineto 0 d rlineto ");
- X printf ("d neg 0 rlineto fill } bind def\n");
- X printf ("%6.2f %6.2f moveto\n", XX(-1), YY(-1));
- X printf ("%6.2f %6.2f lineto\n", XX(XSIZE), YY(-1));
- X printf ("%6.2f %6.2f lineto\n", XX(XSIZE), YY(YSIZE));
- X printf ("%6.2f %6.2f lineto\n", XX(-1), YY(YSIZE));
- X printf ("%6.2f %6.2f lineto\nstroke\n", XX(-1), YY(-1));
- X
- X for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++)
- X if ((k = t[src][i][j]) > ZCOAST)
- X printf ("%6.2f %6.2f %5.4f r\n", XX(i), YY(j), ZZ(k));
- X printf ("\nshowpage\n"); } }
- X
- X
- init (s) char *s; {
- X /* This is the catchall function that initializes everything. First,
- X it calls getparams() in tec3.c to allow the user to set parameters. Next,
- X it links together the plates onto the free list and starts the used list
- X at empty. The first plate is created by a fractal technique and then
- X improved. Finally, the fractal is copied to the data array and drawn.
- X There are two kinds of improvement done here. First, islands are
- X eliminated by segmenting the blob and erasing all the regions except
- X for the biggest. Second, oceans inside the blob (holes) are eliminated
- X by segmenting the _ocean_ and filling in all regions except the biggest. */
- X
- X short besti, x; register short i, j;
- X
- X if (s) if (*s) getparams (s);
- X
- X for (i=1; i<MAXPLATE; i++) p[i].next = i + 1;
- X p[MAXPLATE-1].next = 0;
- X pavail = 1; phead = 0;
- X
- X /* Allocate a plate structure for the first plate and make a blob */
- X x = palloc (); makefrac (0, x);
- X
- X /* Segment m[0] looking for x, set besti to the largest region, */
- X /* and zero out all the other regions. This eliminates islands. */
- X besti = singlefy (0, x);
- X if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
- X if (kid[r[i][j]] != besti) m[0][i][j] = 0;
- X
- X /* Segment m[0] looking for 0 (ocean), set besti to the largest region, */
- X /* and fill in all the other regions. This eliminates holes in the blob. */
- X besti = singlefy (0, 0);
- X if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
- X if (kid[r[i][j]] != besti) m[0][i][j] = x;
- X
- X /* Fill the topo structure with the blob shape while finding its area */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
- X if (m[0][i][j]) { t[0][i][j] = ZINIT; p[x].area++; }
- X
- X /* Draw the blob */
- X draw (0); }
- X
- X
- makefrac (src, match) short src, match; {
- X /* This function uses a very simple fractal technique to draw a blob. Four
- X one-dimensional fractals are created and stored in array x, then the
- X fractals are superimposed on a square array, summed and thresholded to
- X produce a binary blob. Squares in the blob are set to the value in `match'.
- X A one-dimensional fractal of length n is computed like this. First,
- X set x [n/2] to some height and set the endpoints (x[0] and x[n]) to 0.
- X Then do log-n iterations. The first iteration computes 2 more values:
- X x[n/4] = average of x[0] and x[n/2], plus some random number, and
- X x[3n/4] = average of x[n/2] and x[n], plus some random number. The second
- X iteration computes 4 more values (x[n/8], x[3n/8], ...) and so on. The
- X random number gets smaller by a factor of two each time also.
- X
- X Anyway, you wind up with a number sequence that looks like the cross-section
- X of a mountain. If you sum two fractals, one horizontal and one vertical,
- X you get a 3-d mountain; but it looks too symmetric. If you sum four,
- X including the two 45 degree diagonals, you get much better results. */
- X
- X register short xy, dist, n, inc, i, j, k; char x[4][65];
- X short xofs, yofs, xmin, ymin, xmax, ymax;
- X
- X /* Compute offsets to put center of blob in center of the world, and
- X compute array limits to clip blob to world size */
- X xofs = (XSIZE - 64) >> 1; yofs = (YSIZE - 64) >> 1;
- X if (xofs < 0) { xmin = -xofs; xmax = 64 + xofs; }
- X else { xmin = 0; xmax = 64; }
- X if (yofs < 0) { ymin = -yofs; ymax = 64 + yofs; }
- X else { ymin = 0; ymax = 64; }
- X
- X for (xy=0; xy<4; xy++) {
- X /* Initialize loop values and fractal endpoints */
- X x [xy] [0] = 0; x [xy] [64] = 0; dist = 32;
- X x [xy] [32] = 24 + rnd (16); n = 2; inc = 16;
- X
- X /* Loop log-n times, each time halving distance and doubling iterations */
- X for (i=0; i<5; i++, dist>>=1, n<<=1, inc>>=1)
- X for (j=0, k=0; j<n; j++, k+=dist)
- X x[xy][k+inc] = ((x[xy][k]+x[xy][k+dist])>>1) + rnd (dist) - inc; }
- X
- X /* Superimpose fractals; if sum is greater than BLOBLEVEL, there will be */
- X /* land there. x[0] is horizontal, x[1] vertical, x[2] diagonal from */
- X /* top left to bottom right, x[3] diagonal from TR to BL. */
- X for (i=xmin; i<xmax; i++) for (j=ymin; j<ymax; j++) {
- X k = x[0][i] + x[1][j] + x[2][(i - j + 64) >> 1] + x[3][(i + j) >> 1];
- X if (k > BLOBLEVEL) m[src][i+xofs][j+yofs] = match; } }
- X
- X
- singlefy (src, match) short src, match; {
- X /* This is a subfunction of init() which is called twice to improve the
- X fractal blob. It calls segment() and then interprets the result. If
- X only one region was found, no improvement is needed; otherwise, the
- X area of each region must be computed by summing the areas of all its
- X fragments, and the index of the largest region is returned. */
- X
- X short i, reg, frag, besti, besta;
- X
- X segment (src, match, &frag, ®);
- X if (reg == 1) return (-1); /* No improvement needed */
- X
- X /* Initialize the areas to zero, then sum frag areas */
- X for (i=1; i<=reg; i++) tarea[i] = 0;
- X for (i=1; i<=frag; i++) tarea [kid[i]] += karea [i];
- X
- X /* Pick largest area of all regions and return it */
- X for (i=1, besta=0, besti=0; i<=reg; i++)
- X if (besta < tarea[i]) { besti = i; besta = tarea[i]; }
- X return ((int) besti); }
- X
- X
- newdxy () {
- X /* For each plate, compute how many squares it should move this step.
- X Multiply the plate's basic movement vector odx,ody by the age modifier
- X MR[], then add the remainders rx,ry from the last move to get some large
- X integers. Then turn the large integers into small ones by dividing by
- X REALSCALE and putting the remainders back into rx,ry. This function also
- X increases the age of each plate, but doesn't let the age of any plate
- X go above MAXLIFE. This is done to make sure that MR[] does not need to
- X be a long vector. */
- X
- X register short i, a;
- X
- X for (i=phead; i; i=p[i].next) {
- X a = (p[i].odx * MR[p[i].age]) + p[i].rx;
- X p[i].dx = a / REALSCALE; p[i].rx = a % REALSCALE;
- X a = (p[i].ody * MR[p[i].age]) + p[i].ry;
- X p[i].dy = a / REALSCALE; p[i].ry = a % REALSCALE;
- X if (p[i].age < MAXLIFE-1) (p[i].age)++; } }
- X
- X
- move (src, dest) short src, dest; {
- X /* This function moves all the plates that are drifting. The amount to
- X move by is determined in newdxy(). The function simply steps through
- X every square in the array; if there's a plate in a square, its new location
- X is found and the topography is moved there. Overlaps between plates are
- X detected and recorded so that merge() can resolve the collision; mountain
- X growing is performed. If two land squares wind up on top of each other,
- X folded mountains are produced. If a land square winds up where ocean was
- X previously, that square is the leading edge of a continent and grows a
- X mountain by subsuming the ocean basin. */
- X
- X register short i, j; short a, b, c, x, y;
- X
- X /* Clear out the merge matrix and the destination arrays */
- X for (i=1; i<MAXPLATE; i++) for (j=1; j<MAXPLATE; j++) mm[i][j] = 0;
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
- X m[dest][i][j] = 0; t[dest][i][j] = 0; }
- X
- X /* Look at every square which belongs to a plate */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) if ((a = m[src][i][j]) > 0) {
- X
- X /* Add the plate's dx,dy to the position to get the square's new */
- X /* location; if it is off the map, throw it away */
- X x = p[a].dx + i; y = p[a].dy + j;
- X if ((x >= XSIZE) || (x < 0) || (y >= YSIZE) || (y < 0)) p[a].area--;
- X else { /* It IS on the map */
- X
- X /* If the destination is occupied, remove the other guy but */
- X /* remember that the two plates overlapped; set the new height */
- X /* to the larger height plus half the smaller. */
- X if (c = m[dest][x][y]) {
- X (mm[a][c])++; (p[c].area)--;
- X b = t[src][i][j]; c = t[dest][x][y];
- X t[dest][x][y] = (b > c) ? b + (c>>1) : c + (b>>1); }
- X
- X /* The destination isn't occupied. Just copy the height. */
- X else t[dest][x][y] = t[src][i][j];
- X
- X /* If this square is over ocean, increase its height. */
- X if (t[src][x][y] < ZCOAST) t[dest][x][y] += ZSUBSUME;
- X
- X /* Plate A now owns this square */
- X m[dest][x][y] = a; } } }
- X
- X
- merge (dest) short dest; {
- X /* Since move has set up the merge matrix, most of the work is done. This
- X function calls bump once for each pair of plates which are rubbing; note
- X that a and b below loop through the lower diagonal part of the matrix.
- X One subtle feature is that a plate can bump with several other plates in
- X a step; suppose that the plate is merged with the first plate it bumped.
- X The loop will try to bump the vanished plate with the other plates, which
- X would be wrong. To avoid this, the lookup table lut is used to provide
- X a level of indirection. When a plate is merged with another, its lut
- X entry is changed to indicate that future merges with the vanished plate
- X should be applied to the plate it has just been merged with. */
- X
- X char lut[MAXPLATE]; short a, aa, b, bb, i;
- X
- X for (a=1; a<MAXPLATE; a++) lut[a] = a;
- X for (a=2; a<MAXPLATE; a++) for (b=1; b<a; b++) if (mm[a][b] || mm[b][a]) {
- X aa = lut [a]; bb = lut[b];
- X if (aa != bb) if (bump (dest, aa, bb)) {
- X lut[aa] = bb;
- X for (i=1; i<MAXPLATE; i++) if (lut[i] == aa) lut[i] = bb; } } }
- X
- X
- bump (dest, a, b) short dest, a, b; {
- X /* Plates a and b have been moved on top of each other by some amount;
- X alter their movement rates for a slow collision, possibly merging them.
- X The collision "strength" is a ratio of the area overlap (provided by
- X move ()) to the total area of the plates involved. A fraction of each
- X plate's current movement vector is subtracted from the movement vector
- X of the other plate. If the two vectors are now within some tolerance
- X of each other, they are almost at rest so merge them with each other. */
- X
- X double maa, mab, ta, tb, rat, area; register short i, j, x;
- X
- X /* Find a ratio describing how strong the collision is */
- X x = mm[a][b] + mm[b][a]; area = p[a].area + p[b].area;
- X rat = x / (MAXBUMP + (area / 20)); if (rat > 1.0) rat = 1.0;
- X
- X /* Do some math to update the move vectors. This looks complicated */
- X /* because a plate's actual movement vector must be multiplied by */
- X /* MR[age], and because I have rewritten the equations to maximize */
- X /* use of common factors. Trust me, it's just inelastic collision. */
- X maa = p[a].area * MR[p[a].age]; mab = p[b].area * MR[p[b].age];
- X ta = MR[p[a].age] * area;
- X p[a].odx = (p[a].odx * maa + p[b].odx * mab * rat) / ta;
- X p[a].ody = (p[a].ody * maa + p[b].ody * mab * rat) / ta;
- X tb = MR[p[b].age] * area;
- X p[b].odx = (p[b].odx * mab + p[a].odx * maa * rat) / tb;
- X p[b].ody = (p[b].ody * mab + p[a].ody * maa * rat) / tb;
- X
- X /* For each axis, compute the remaining relative velocity. If it is */
- X /* too large, return without merging the plates */
- X if (ABS (p[a].odx*MR[p[a].age] - p[b].odx*MR[p[b].age]) > BUMPTOL) return(0);
- X if (ABS (p[a].ody*MR[p[a].age] - p[b].ody*MR[p[b].age]) > BUMPTOL) return(0);
- X
- X /* The relative velocity is small enough, so merge the plates. Replace */
- X /* all references to a with b, free a, and tell merge() a was freed. */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
- X if (m[dest][i][j] == a) m[dest][i][j] = b;
- X p[b].area += p[a].area; pfree (a);
- X return ((int) a); }
- X
- X
- X/* The following is defined as a macro for efficiency; erosion is still
- X the slowest function in the simulation. ERODE is called four times per
- X pixel by erode. A and b are altitudes of two adjacent squares, while c
- X and d are the corresponding delta values for those squares. The amount
- X each square loses to an adjacent but lower square in each step is
- X one-eighth the difference in altitude. This is coded as a shift right 3
- X bits, but since -1 >> 3 is still -1, the code must be repeated to avoid
- X negative deltas. */
- X#define ERODE(a,b,c,d) \
- if (((a > ZSHELF) || (b > ZSHELF))) { \
- X if ( a > b) { x = (a - b + ERODERND) >> 3; c -= x; d += x; } \
- X else { x = (b - a + ERODERND) >> 3; c += x; d -= x; } }
- X
- X
- erode (dest) short dest; {
- X /* This function takes the topography in t[dest] and smooths it, lowering
- X mountains and raising lowlands and continental margins. It does this by
- X stepping across the entire array and doing a computation once for each
- X pair of 8-connected pixels. The computation is done by ERODE, above.
- X The computation result for a pair is a small delta for each square, which
- X is summed in the array e. When the computation is finished, the delta
- X is applied; if this pushes an ocean square high enough, it is added to
- X an adjacent plate if one can be found. Also, if a land square is eroded
- X low enough, it is turned into ocean and removed from its plate. */
- X
- X register short i, j, t1, x, z; short ii, jj, xx;
- X
- X /* Zero out the array for the deltas first */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) e[i][j] = 0;
- X
- X /* Step across the entire array; each pixel is adjacent to 8 others, and */
- X /* it turns out that if four pairs are considered for each pixel, each */
- X /* pair is considered exactly once. This is important for even erosion */
- X for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++) {
- X t1 = t[dest][i][j];
- X ERODE (t1, t[dest][i][j-1], e[i][j], e[i][j-1])
- X ERODE (t1, t[dest][i-1][j-1], e[i][j], e[i-1][j-1])
- X ERODE (t1, t[dest][i-1][j], e[i][j], e[i-1][j])
- X if (j < YSIZE-1) {
- X ERODE (t1, t[dest][i-1][j+1], e[i][j], e[i-1][j+1]) } }
- X
- X /* Now go back across the array, applying the delta values from e[][] */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
- X z = t[dest][i][j] + e[i][j]; if (z < 0) z = 0; if (z > 255) z = 255;
- X
- X /* If the square just rose above shelf level, look at the four */
- X /* adjacent squares. If one is a plate, add the square to that plate */
- X if ((z >= ZSHELF) && (t[dest][i][j] < ZSHELF)) {
- X if (i > 1) if (xx = m[dest][i-1][j]) { ii = i-1; jj = j; }
- X if (i < XSIZE-1) if (xx = m[dest][i-1][j]) { ii = i+1; jj = j; }
- X if (j > 1) if (xx = m[dest][i][j-1]) { ii = i; jj = j-1; }
- X if (j < YSIZE-1) if (xx = m[dest][i][j+1]) { ii = i; jj = j+1; }
- X p[xx].area++; m[dest][i][j] = xx; }
- X
- X /* If the square is lower than shelf level but belongs to a plate, */
- X /* remove it from the plate */
- X if (((t[dest][i][j] = z) < ZSHELF) && (x = m[dest][i][j])) {
- X p[x].area--; m[dest][i][j] = 0; } } }
- X
- X
- X
- X
- END_OF_FILE
- if test 21292 -ne `wc -c <'tec-v3/tec1.c'`; then
- echo shar: \"'tec-v3/tec1.c'\" unpacked with wrong size!
- fi
- # end of 'tec-v3/tec1.c'
- fi
- if test -f 'tec-v3/tec2.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'tec-v3/tec2.c'\"
- else
- echo shar: Extracting \"'tec-v3/tec2.c'\" \(14274 characters\)
- sed "s/^X//" >'tec-v3/tec2.c' <<'END_OF_FILE'
- X/* This program is Copyright (c) 1990 David Allen. It may be freely
- X distributed as long as you leave my name and copyright notice on it.
- X I'd really like your comments and feedback; send e-mail to
- X davea@vlsi.ll.mit.edu, or send us-mail to David Allen, 10 O'Moore Ave,
- X Maynard, MA 01754. */
- X
- X/* This file contains the function trysplit(), which is called from
- X onestep() in tec1.c, and its subfunctions. One of its subfunctions,
- X segment(), is also called from init() in tec1.c. Trysplit is the
- X function in charge of splitting one plate into smaller plates. */
- X
- X
- X#include "const.h"
- X#include "var.h"
- X
- X#define PI 3.14159
- X#define TWOPI 6.28318
- X#define TWOMILLIPI 0.00628318
- X
- X/* RIFTMARK is the temporary indicator placed in the arrays to indicate
- X the squares a rift has just appeared. The function stoprift() puts
- X them in, and trysplit() takes them out before anybody can see them. */
- X#define RIFTMARK -1
- X
- X/* These are all defined in tec1.c */
- extern char m[2][MAXX][MAXY], r[MAXX][MAXY], kid[MAXFRAG];
- extern unsigned char t[2][MAXX][MAXY];
- extern short karea[MAXFRAG], tarea[MAXPLATE], ids[MAXPLATE], step;
- extern struct plate p [MAXPLATE];
- X
- X
- trysplit (src) short src; {
- X /* Trysplit is called at most once per step in only 40% of the steps.
- X It first draws a rift on one of the plates, then it segments the result
- X into some number of new plates and some splinters. If exactly two new
- X non-splinter plates are found, new plate structures are allocated, new
- X dx and dy values are computed, and the old plate is freed. If anything
- X goes wrong, the rift is erased from the array, returning the array to its
- X previous state. The functions newrift, segment and newplates do most
- X of the work. */
- X
- X register short i, j, a; short count, old, frag, reg;
- X
- X if (old = newrift (src)) if (segment (src, old, &frag, ®)) if (reg > 1) {
- X
- X /* Set tarea[i] to areas of the final segmented regions */
- X for (i=0; i<=MAXPLATE; i++) tarea[i] = 0;
- X for (i=1; i<=frag; i++) tarea[kid[i]] += karea[i];
- X
- X /* Give up unless exactly two regions are large enough */
- X for (i=1, count=0; i<=reg; i++) if (tarea[i] > MAXSPLINTER) count++;
- X if (count == 2) {
- X
- X /* Compute new dx,dy, then update m with the ids of the new plates */
- X newplates (src, old);
- X for (i=0, count=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
- X if (a = r[i][j]) m[src][i][j] = ids[kid[a]];
- X if (m[src][i][j] == RIFTMARK) {
- X m[src][i][j] = 0; t[src][i][j] = 0; } }
- X pfree (old); return (0); } }
- X
- X /* If execution reaches here, the split operation failed; remove rift */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
- X if (m[src][i][j] == RIFTMARK) m[src][i][j] = old; }
- X
- X
- newrift (src) short src; {
- X /* This function randomly picks a center for a new rift, and draws in
- X a curving line until the line hits either the coast or another plate.
- X If another plate is hit, the rift is invalid and the function returns 0.
- X To find a center, the function generates random x,y values until it
- X finds one that is at least RIFTDIST squares from any ocean square. If a
- X center is found, a random angle is generated; the rift will pass through
- X the center at that angle. Next, halfrift() is called twice. Each call
- X generates the rift leaving the center in one direction. If everything
- X works out, the function returns the id of the plate the rift is on. */
- X
- X short x, y, lx, rx, ty, by, i, j, tries = 0, which; double t;
- X
- X /* Generate a random x, y value */
- X getctr: if (tries > MAXCTRTRY) return (0);
- X x = rnd (XSIZE); y = rnd (YSIZE);
- X
- X /* If the location is ocean, try again */
- X if (!m[src][x][y]) { tries++; goto getctr; }
- X
- X /* Set lx,rx,ty,by to the coordinate values of a box 2*RIFTDIST on a side */
- X /* centered on the center. Clip the values to make sure they are on the */
- X /* array. Loop through the box; if a point is ocean, try another center. */
- X lx = (x < RIFTDIST) ? 0 : x - RIFTDIST;
- X rx = (x > XSIZE - RIFTDIST - 1) ? XSIZE - 1 : x + RIFTDIST;
- X ty = (y < RIFTDIST) ? 0 : y - RIFTDIST;
- X by = (y > YSIZE - RIFTDIST - 1) ? YSIZE - 1 : y + RIFTDIST;
- X for (i=lx; i<rx; i++) for (j=ty; j<by; j++)
- X if (!m[src][i][j]) { tries++; goto getctr; }
- X
- X /* Found a good center, on plate `which'. Put a rift indicator in the */
- X /* center. Generate a random angle t, which is really an integer in the */
- X /* range 0-499 multiplied by 2 PI / 1000. Call halfrift once for each */
- X /* half of the rift; t is the initial angle for the first call, and */
- X /* t + PI is the initial angle for the second call. If halfrift() */
- X /* returns zero, abort and return 0; otherwise, return the plate id. */
- X which = m[src][x][y]; m[src][x][y] = RIFTMARK;
- X t = rnd (500) * TWOMILLIPI;
- X if (!halfrift (src, x, y, which, t)) return (0);
- X t += PI; if (t > TWOPI) t -= TWOPI;
- X if (!halfrift (src, x, y, which, t)) return (0);
- X return ((int) which); }
- X
- X
- halfrift (src, cx, cy, which, t) short src, cx, cy, which; double t; {
- X /* Draw a rift from cx,cy on plate `which' at angle t. At the beginning,
- X digitize the angle using Bresenham's algorithm; once in a while thereafter,
- X modify the angle randomly and digitize it again. For each square travelled,
- X call stoprift() to see if the rift has left the plate. */
- X
- X short ddx, ddy, rdx, rdy, draw, i, a; double dx, dy, adx, ady;
- X
- X /* For-loop against SIZE to guard against infinite loops */
- X for (i=0; i<XSIZE; i++) {
- X
- X /* If first square or 1/6 chance at each step, digitize */
- X if (!i || !rnd (BENDEVERY)) {
- X
- X /* If not first step, modify angle a little */
- X if (i) t = t + (rnd (BENDBY<<1) * TWOMILLIPI) - (BENDBY * TWOMILLIPI);
- X if (t > TWOPI) t -= TWOPI; if (t < 0) t += TWOPI;
- X
- X /* Compute dx and dy, scaled so that larger is exactly +1.0 or -1.0 */
- X dy = sin (t); dx = cos (t); adx = ABS(dx); ady = ABS(dy);
- X if (adx > ady) { dy = dy / adx; dx = (dx < 0) ? -1.0: 1.0; }
- X else { dx = dx / ady; dy = (dy < 0) ? -1.0: 1.0; }
- X
- X /* Convert to integer value and initialize remainder */
- X /* for each coordinate to half value */
- X ddx = REALSCALE * dx; ddy = REALSCALE * dy;
- X rdx = ddx >> 1; rdy = ddy >> 1; }
- X
- X /* Main part of loop, draws one square along line. The basic idea */
- X /* of Bresenham's algorithm is that if the slope of the line is less */
- X /* than 45 degrees, each time you step one square in X and maybe step */
- X /* one square in Y. If the slope is greater than 45, step one square */
- X /* in Y and maybe one square in X. Here, if the slope is less than 45 */
- X /* then ddx == REALSCALE (or -REALSCALE) and the first call to */
- X /* stoprift() is guaranteed. If stoprift returns <0, all is ok; */
- X /* if zero, the rift ran into the ocean, so stop now; if positive, the */
- X /* rift ran into another plate, which is a perverse condition and the */
- X /* rift must be abandoned. */
- X rdx += ddx; rdy += ddy;
- X if (rdx >= REALSCALE) { cx++; rdx -= REALSCALE; draw = 1; }
- X if (rdx <= -REALSCALE) { cx--; rdx += REALSCALE; draw = 1; }
- X if (draw == 1) {
- X a = stoprift (src, cx, cy, which); if (a >= 0) return (a == 0); }
- X if (rdy >= REALSCALE) { cy++; rdy -= REALSCALE; draw = 2; }
- X if (rdy <= -REALSCALE) { cy--; rdy += REALSCALE; draw = 2; }
- X if (draw == 2) {
- X a = stoprift (src, cx, cy, which); if (a >= 0) return (a == 0); } }
- X return (1); }
- X
- X
- stoprift (src, x, y, which) short src, x, y, which; {
- X /* This function is called once for each square the rift enters. It
- X puts a rift marker into m[src] and decides whether the rift can go on.
- X It looks at all four adjacent squares. If one of them contains ocean
- X or another plate, return immediately so that the rift stops (if ocean)
- X or aborts (if another plate). If none of them do, then return ok. */
- X
- X register short w, a;
- X
- X w = which; p[w].area--; m[src][x][y] = RIFTMARK;
- X a = m[src][x][y+1]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
- X a = m[src][x][y-1]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
- X a = m[src][x+1][y]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
- X a = m[src][x-1][y]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
- X return (-1); }
- X
- X
- segment (src, match, frag, reg) short src, match, *frag, *reg; {
- X /* This routine implements a standard binary-blob segmentation. It looks
- X at the array m[src]; match is the value of the blob, and everything else
- X is background. The result is placed into array r and vectors kid and karea.
- X One 8-connected region can be made up of many fragments; each fragment is
- X assigned a unique index. Array r contains the frag indices k, while kid[k]
- X is the region frag k belongs to and karea[k] is the area of frag k.
- X Variables frag and reg are set on output to the number of fragments and
- X regions found during the segmentation. The private vector kk provides one
- X level of indirection for merging fragments; fragment k is merged with
- X fragment kk[k] where kk[k] is the smallest frag index in the region. */
- X
- X register short i, j, k, k1, k2, k3, l;
- X char kk [MAXFRAG];
- X
- X /* Initialize all frag areas to zero and every frag to merge with itself */
- X for (k=0; k<MAXFRAG; k++) { kk[k] = k; karea[k] = 0; }
- X
- X /* Look at every point in the array */
- X for (k=0, i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
- X /* If too many fragments, give up */
- X if (k == MAXFRAG) return (0);
- X
- X /* If this square isn't part of the blob, try the next square */
- X if (m[src][i][j] != match) { r[i][j] = 0; goto bottom; }
- X
- X /* It is part of the blob. Set k1 to the frag id of the square to */
- X /* its left, and set k2 to the frag id of the square above it. Note */
- X /* that because of the for-loop direction, both of these squares have */
- X /* already been processed. */
- X k1 = i ? kk [r [i-1] [j]] : 0; k2 = j ? kk [r [i] [j-1]] : 0;
- X
- X /* If k1 and k2 are both background, start a new fragment */
- X if (!k1 && !k2) { r[i][j] = ++k; karea[k]++; goto bottom; }
- X
- X /* If k1 and k2 are part of the same frag, add this square to it */
- X if (k1 && (k1 == k2)) { r[i][j] = k1; karea[k1]++; goto bottom; }
- X
- X /* If k1 and k2 belong to different frags, merge them by finding */
- X /* all the frags merged with max(k1,k2) and merging them instead */
- X /* with min(k1,k2). Add k to that fragment as well. */
- X if (k1 && k2) {
- X if (k2 < k1) { k3 = k1; k1 = k2; k2 = k3; }
- X for (l=1; l<=k; l++) if (kk[l] == k2) kk[l] = k1;
- X r[i][j] = k1; karea[k1]++; goto bottom; }
- X
- X /* Default case is that one of k1,k2 is a fragment and the other is */
- X /* background. Add k to the fragment. */
- X k3 = (k1) ? k1 : k2; r[i][j] = k3; karea[k3]++;
- X bottom: continue; }
- X
- X /* Set up vector kid to map from fragments to regions by using i to count */
- X /* unique groups of fragments. A unique group of fragments is */
- X /* characterized by kk[k] == k; otherwise, frag k is merged with some */
- X /* other fragment. */
- X for (i=0, j=1; j<=k; j++) {
- X if (j == kk[j]) kid[j] = ++i;
- X else kid[j] = kid [kk [j]]; }
- X
- X /* Make sure the id of the background is zero; set up return values */
- X kid[0] = 0; *frag = k; *reg = i; return (1); }
- X
- X
- X
- newplates (src, old) short src, old; {
- X /* Compute new dx and dy values for plates right after fragmentation. This
- X function looks at the rift markers in m[src]; variable old is the index of
- X the plate from which the new plates were created. For each plate adjacent
- X to the rift, this function subtracts the number of plate squares to the left
- X of the rift from the number to the right; this gives some indication of
- X whether the plate should move left or right, and how fast. The same is done
- X for squares above and below the rift. The results are put into dx[] and
- X dy[]. At this point some unscaled movement vector is available for both of
- X the new plates. The vectors are then scaled by the relative sizes of the
- X plates. The idea is that if one plate is much larger than the other, the
- X small one should move faster. New plate structures are allocated for the
- X new plates, and the computed dx and dy values are put in them. */
- X
- X short dx[MAXPLATE], dy[MAXPLATE];
- X register short i, j, a; short totarea=0, maxmag=0; double scale, b;
- X
- X for (i=1; i<MAXPLATE; i++) { dx[i] = 0; dy[i] = 0; ids[i] = 0; }
- X
- X /* For every point in the array, set a to the region id (kid is the */
- X /* lookup table and r contains frag indices); if a is nonzero and */
- X /* the rift is adjacent, adjust counters appropriately */
- X for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) if (a = kid[r[i][j]]) {
- X if ((i-1 > -1) && (m[src][i-1][j] == RIFTMARK)) (dx[a])++;
- X if ((i+1 < XSIZE) && (m[src][i+1][j] == RIFTMARK)) (dx[a])--;
- X if ((j-1 > -1) && (m[src][i][j-1] == RIFTMARK)) (dy[a])++;
- X if ((j+1 < XSIZE) && (m[src][i][j+1] == RIFTMARK)) (dy[a])--; }
- X
- X /* For those regions larger than splinters (tarea is set up in trysplit), */
- X /* allocate a new plate structure and initialize its area; compute the */
- X /* magnitude of the dx dy vector and remember the maximum magnitude; also */
- X /* record the total area of new regions */
- X for (i=1; i<MAXPLATE; i++) if (tarea[i] > MAXSPLINTER) {
- X ids[i] = palloc (); p[ids[i]].area = tarea[i];
- X totarea += tarea[i];
- X a =sqrt ((double) ((dx[i]*dx[i]) + (dy[i]*dy[i])));
- X if (a > maxmag) maxmag = a; }
- X
- X /* Generate a random speed and predivide so that all speeds computed */
- X /* below are less than the random speed. */
- X scale = (double) (rnd (SPEEDRNG) + SPEEDBASE) / (maxmag * totarea);
- X
- X /* Compute the dx and dy for each new plate; note that the speed the */
- X /* plate was moving at before splitting is given by p[old].odx,ody */
- X /* but those must be multiplied by MR to get the actual values */
- X for (i=1; i<MAXPLATE; i++) if (ids[i]) {
- X b = scale * (totarea - tarea[i]);
- X p[ids[i]].odx = p[old].odx * MR [p[old].age] + dx[i] * b;
- X p[ids[i]].ody = p[old].ody * MR [p[old].age] + dy[i] * b; } }
- END_OF_FILE
- if test 14274 -ne `wc -c <'tec-v3/tec2.c'`; then
- echo shar: \"'tec-v3/tec2.c'\" unpacked with wrong size!
- fi
- # end of 'tec-v3/tec2.c'
- fi
- echo shar: End of shell archive.
- exit 0
-
-