home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume10 / tec / part02 < prev    next >
Text File  |  1990-02-20  |  64KB  |  1,619 lines

  1. Newsgroups: comp.sources.misc
  2. organization: MIT Lincoln Laboratory, Lexington MA
  3. subject: v10i078: Continental Drift Simulator part 2/2
  4. from: davea@ll-vlsi.arpa (Dave Allen)
  5. Sender: allbery@uunet.UU.NET (Brandon S. Allbery - comp.sources.misc)
  6.  
  7. Posting-number: Volume 10, Issue 78
  8. Submitted-by: davea@ll-vlsi.arpa (Dave Allen)
  9. Archive-name: tec/part02
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of shell archive."
  18. # Contents:  tec-v3/var.h tec-v3/ibmpc.c tec-v3/tec.mak tec-v3/tec1.c
  19. #   tec-v3/tec2.c
  20. # Wrapped by davea@vdd on Fri Feb 16 08:39:20 1990
  21. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  22. if test -f 'tec-v3/var.h' -a "${1}" != "-c" ; then 
  23.   echo shar: Will not clobber existing file \"'tec-v3/var.h'\"
  24. else
  25. echo shar: Extracting \"'tec-v3/var.h'\" \(440 characters\)
  26. sed "s/^X//" >'tec-v3/var.h' <<'END_OF_FILE'
  27. X/* These variables are the adjustable parameters; they are described and
  28. given default values in tec3.c */
  29. X
  30. extern long XSIZE,    YSIZE,        MAXSTEP;
  31. extern long MAXLIFE,    MAXBUMP,    BUMPTOL;
  32. extern long DRAWEVERY,    BLOBLEVEL,    DRAWMODE;
  33. extern long ZINIT,    ZSUBSUME,    ZCOAST;
  34. extern long ZSHELF,    ZMOUNTAIN;
  35. extern long RIFTPCT,    DOERODE,    ERODERND;
  36. extern long MAXCTRTRY,    RIFTDIST,    BENDEVERY;
  37. extern long BENDBY,    SPEEDBASE,    SPEEDRNG;
  38. extern double MR[];
  39. END_OF_FILE
  40. if test 440 -ne `wc -c <'tec-v3/var.h'`; then
  41.     echo shar: \"'tec-v3/var.h'\" unpacked with wrong size!
  42. fi
  43. # end of 'tec-v3/var.h'
  44. fi
  45. if test -f 'tec-v3/ibmpc.c' -a "${1}" != "-c" ; then 
  46.   echo shar: Will not clobber existing file \"'tec-v3/ibmpc.c'\"
  47. else
  48. echo shar: Extracting \"'tec-v3/ibmpc.c'\" \(22685 characters\)
  49. sed "s/^X//" >'tec-v3/ibmpc.c' <<'END_OF_FILE'
  50. X/* Modified for IBM PC/XT/AT, 9/12/89..9/01/90 from file ami.c:
  51. X             Peter C. Lind, M.Sc.,   lind@maccs.ca
  52. X             McMaster University,
  53. X             1280 Main St. W.,
  54. X             Hamilton, ON
  55. X             Canada   L8S 4K1
  56. X
  57. X   This file contains only functions which are specific to the IBM PC/XT/AT
  58. X   under Turbo C 2.00+.  It connects to the other source files via a small
  59. X   number of functions. main() is here.  It calls init() and onestep().
  60. X   The other source files can call rnd(), draw() and panic() from this file;
  61. X   these are at the end of the file. */
  62. X
  63. X#include "const.h"
  64. X#include "var.h"
  65. X
  66. X#include <conio.h>
  67. X#include <dos.h>
  68. X#include <graphics.h>
  69. X#include <stdlib.h>
  70. X#include <stdio.h>
  71. X#include <time.h>
  72. X
  73. X#define TRUE !0
  74. X#define FALSE 0
  75. X
  76. X#define STDOUT_HANDLE 1                  /* DOS file handle for stdout */
  77. X
  78. extern unsigned long RangeSeed;          /* TC random number generator */
  79. extern unsigned char t[2][MAXX][MAXY];   /* Defined in tec1.c */
  80. extern short step;                       /* Also defined in tec1.c */
  81. X
  82. unsigned long         class;
  83. unsigned short        code;
  84. X
  85. X/* EGA: 16 colors used: Black, 2 shades of blue (dark, light), 2 of green,
  86. X        2 of red, 2 of purple (magenta), 2 white (light gray, white), and
  87. X    2 yellow (brown, yellow). */
  88. X#define NUMCOLORS 13
  89. X#define MAXCOLOR 12
  90. unsigned short colors [NUMCOLORS] = {
  91. X                                     BLACK,
  92. X                                     BLUE,LIGHTBLUE,GREEN,LIGHTGREEN,
  93. X                                     YELLOW,MAGENTA,LIGHTMAGENTA,
  94. X                                     RED,LIGHTRED,BROWN,
  95. X                                     LIGHTGRAY,WHITE
  96. X                                    };
  97. X
  98. unsigned short CellXsize,CellYsize;   /* Size of a tec pixel */
  99. int MaxX,MaxY,CentX,CentY;            /* Screen parameters */
  100. int LastVideoMode;                    /* Video mode at program start up */
  101. int gdriver;                          /* Graphics driver used for plotting */
  102. int BrightColor,DimColor,BorderColor,BackgroundColor,BarColor;
  103. int Bar3Dcolor,PlotBackColor;
  104. int wx1,wy1,wx2,wy2,winMaxX,winMaxY,origY2;  /* Map window coords */
  105. X
  106. int LegCellWid,LegCellHgt,LegHalfWid; /* Legend parameters */
  107. int legX1,legY1,legX2,legY2,legCY;
  108. X
  109. short InColor;                        /* TRUE if mode is EGA or VGA */
  110. short Mode3D;                         /* TRUE when plotting in 3d mode */
  111. short Slow3D;                         /* TRUE for slow 3d plotting */
  112. short AllStop;                        /* TRUE if user wants to quit */
  113. short WantPrint;                      /* TRUE if user wants to print */
  114. short WantPause;                      /* TRUE if user wants to pause */
  115. short WantChangePlot;                 /* TRUE if user wants to change
  116. X                                          plotting style */
  117. short NeedLegend;                     /* TRUE if legend should be drawn */
  118. short NoLegend;                       /* TRUE if legend should be erased */
  119. X
  120. int msgY;                             /* Y coord of message line top */
  121. X
  122. X#define xaddon 5                      /* Width of 3-d bars */
  123. int ix;                               /* Initial X coord for 3-d */
  124. int iy;                               /* Initial Y coord for 3-d */
  125. int yaddon;                           /* Y increment for 3-d plotting */
  126. X
  127. X#define ESC 27                        /* ASCII code for ESC */
  128. X
  129. X#define NUM_CREDITS 5
  130. static char title[]   = "TEC   Continental Drift Simulator";
  131. static char credit[NUM_CREDITS][42] =
  132. X             {
  133. X              "Version  3",
  134. X              "originally written by David Allen",
  135. X              "adapted for IBM PC/XT/AT by Peter C. Lind",
  136. X              "Copyright (c) 1989,1990",
  137. X              "press any key to begin"
  138. X             };
  139. int CredFont,TitleSize,CredSize;
  140. X
  141. void TakeMax (a,b)
  142. X /* `a' gets maximum of `a' and `b'. */
  143. X int *a,b;
  144. X  {
  145. X   if (b > *a)
  146. X      *a = b;
  147. X  }
  148. X
  149. void panic (s)
  150. X char *s;
  151. X /* Used when some fatal inconsistency is found in the database;
  152. X    its function is to immediately free all graphics memory and exit. */
  153. X  {
  154. X   closegraph();
  155. X   textmode(LastVideoMode);
  156. X   printf("TEC PANIC: %s\n",s);
  157. X   exit(0);
  158. X  }
  159. X
  160. void message (s)
  161. X char *s;
  162. X /* Displays message `s' at the bottom of the screen. */
  163. X  {
  164. X   struct viewporttype ov;
  165. X
  166. X   getviewsettings(&ov);                       /* Save current viewport */
  167. X   setviewport(0,0,MaxX,MaxY,TRUE);            /* Select entire screen */
  168. X   setfillstyle(SOLID_FILL,BarColor);
  169. X   bar(0,msgY,MaxX,MaxY);                      /* Blank bottom line */
  170. X   settextjustify(CENTER_TEXT,TOP_TEXT);
  171. X   setcolor(DimColor);
  172. X   outtextxy(CentX,msgY+1,s);                  /* Output message */
  173. X   setviewport(ov.left,ov.top,ov.right,        /* Select old viewport */
  174. X               ov.bottom,ov.clip);
  175. X  }
  176. X
  177. void WaitKeyPress ()
  178. X /* Wait for user to press a key. */
  179. X  {
  180. X   while (!kbhit())
  181. X         ;
  182. X   if (!(getch()))              /* Consume any extended code */
  183. X      getch();
  184. X  }
  185. X
  186. void Intro ()
  187. X /* Displays the introductory credits panel. */
  188. X  {
  189. X   int th,tw,x1,y1,x2,y2,y,ht,hc,cx,i,TwoEms;
  190. X
  191. X   /* Calculate dimensions of panel required */
  192. X   settextstyle(CredFont,HORIZ_DIR,TitleSize);    /* Measure title line */
  193. X   ht = textheight(title); th = (ht * 3);
  194. X   tw = textwidth(title) + (textwidth("M") << 1);
  195. X   settextstyle(CredFont,HORIZ_DIR,CredSize);     /* Measure credit lines */
  196. X   TwoEms = textwidth("M") << 1;
  197. X   hc = 0;
  198. X   for (i = 0; i < NUM_CREDITS; i++)              /* Find max. height, width */
  199. X       {
  200. X    TakeMax(&hc,textheight(credit[i]));
  201. X        TakeMax(&tw,textwidth(credit[i])+TwoEms);
  202. X       }
  203. X   hc <<= 1;
  204. X   th += (hc * NUM_CREDITS);
  205. X   x1 = (MaxX - tw) >> 1; x2 = x1 + tw - 1;
  206. X   y1 = (MaxY - th) >> 1; y2 = y1 + th - 1;
  207. X   cx = (tw >> 1) - 1;
  208. X
  209. X   /* Draw panel and display title and credits */
  210. X   setfillstyle(SOLID_FILL,BarColor); setcolor(BarColor);
  211. X   bar3d(x1,y1,x2,y2,4,TRUE);
  212. X   setviewport(x1+1,y1+1,x2-1,y2-1,TRUE);
  213. X   y = ht;
  214. X   settextstyle(CredFont,HORIZ_DIR,TitleSize);
  215. X   settextjustify(CENTER_TEXT,TOP_TEXT);
  216. X   setcolor(BrightColor);
  217. X   outtextxy(cx,y,title);
  218. X   y += (ht << 1);
  219. X   settextstyle(CredFont,HORIZ_DIR,CredSize);
  220. X   for (i = 0; i < NUM_CREDITS; i++, y += hc)
  221. X       outtextxy(cx,y,credit[i]);
  222. X   WaitKeyPress();
  223. X   setviewport(0,0,MaxX,MaxY,TRUE);
  224. X   cleardevice();
  225. X  }
  226. X
  227. void CGAdefaults ()
  228. X /* Common routine to set CGA/MCGA defaults. */
  229. X  {
  230. X   BarColor = 1; BrightColor = 0; DimColor = 0;
  231. X   BorderColor = 1; BackgroundColor = 0; Bar3Dcolor = 1; PlotBackColor = 0;
  232. X   InColor = FALSE; Mode3D = TRUE; Slow3D = FALSE;
  233. X  }
  234. X
  235. int initCGA ()
  236. X /* Initialize CGA mode. */
  237. X  {
  238. X   CGAdefaults();
  239. X   CredFont = SMALL_FONT; TitleSize = 6; CredSize = 4;
  240. X   return(CGAHI);
  241. X  }
  242. X
  243. int initMCGA ()
  244. X /* Initialize MCGA mode. */
  245. X  {
  246. X   CGAdefaults();
  247. X   CredFont = SMALL_FONT; TitleSize = 6; CredSize = 4;
  248. X   return(MCGAHI);
  249. X  }
  250. X
  251. void EGAdefaults ()
  252. X /* Common routine to set EGA/VGA defaults. */
  253. X  {
  254. X   BarColor = DARKGRAY; BrightColor = WHITE; DimColor = LIGHTGRAY;
  255. X   PlotBackColor = BLACK;
  256. X   BorderColor = DARKGRAY; BackgroundColor = BLACK; Bar3Dcolor = LIGHTGRAY;
  257. X   InColor = TRUE; Mode3D = FALSE;
  258. X   LegCellWid = 20; LegHalfWid = 10;
  259. X   NeedLegend = TRUE;
  260. X  }
  261. X
  262. int initEGA ()
  263. X /* Initialize EGA */
  264. X  {
  265. X   EGAdefaults();
  266. X   CellXsize = 7; CellYsize = 3;
  267. X   CredFont = TRIPLEX_FONT; TitleSize = 3; CredSize = 2;
  268. X   LegCellHgt = 16;
  269. X   return(EGAHI);
  270. X  }
  271. X
  272. int initVGA ()
  273. X /* Initialize VGA */
  274. X  {
  275. X   EGAdefaults();
  276. X   CellXsize = 7; CellYsize = 5;
  277. X   CredFont = TRIPLEX_FONT; TitleSize = 4; CredSize = 3;
  278. X   LegCellHgt = 16;
  279. X   return(VGAHI);
  280. X  }
  281. X
  282. void grafinit ()
  283. X /* Detect the video hardware and configure accordingly; display credits */
  284. X  {
  285. X   int gm,tw,th,rc;
  286. X
  287. X   LastVideoMode = LASTMODE;
  288. X   detectgraph(&gdriver,&gm);
  289. X   switch (gdriver)
  290. X      {
  291. X           case CGA: gm = initCGA();   /* CGA high-res mode: 640 x 200, 2 colors */
  292. X                     break;
  293. X           case MCGA: gm = initMCGA(); /* MCGA high-res mode: 640 x 480, 2 colors */
  294. X                      break;
  295. X       case EGA: gm = initEGA();   /* EGA high-res mode: 640 x 350, 16 colors */
  296. X                     break;
  297. X       case VGA: gm = initVGA();   /* VGA high-res mode: 640 x 480, 16 colors */
  298. X                     break;
  299. X           default: printf("TEC 3:\n");
  300. X                    printf("Unable to operate with detected display type\n");
  301. X                    printf("Require CGA, MCGA, EGA or VGA to run\n");
  302. X                    exit(0);
  303. X      }
  304. X   initgraph(&gdriver,&gm,"");
  305. X   if ((rc = graphresult()))
  306. X      {
  307. X       printf("TEC 3:\n");
  308. X       printf("BGI Error #%d: %s\n",rc,grapherrormsg(rc));
  309. X       textmode(LastVideoMode);
  310. X       exit(0);
  311. X      }
  312. X   MaxX = getmaxx(); MaxY = getmaxy();
  313. X   CentX = MaxX >> 1; CentY = MaxY >> 1;
  314. X   Intro();                                             /* Intro panel */
  315. X   settextstyle(DEFAULT_FONT,HORIZ_DIR,1);              /* Choose font */
  316. X   tw = textwidth("M"); th = textheight("M");           /* Font's dimensions */
  317. X   msgY = MaxY - th - 2;
  318. X
  319. X   setfillstyle(SOLID_FILL,BarColor); bar(0,0,MaxX,th+1); /* Top bar */
  320. X   bar(0,msgY,MaxX,MaxY);                                 /* Bottom bar */
  321. X   setcolor(BrightColor);
  322. X   settextjustify(LEFT_TEXT,TOP_TEXT);
  323. X   moveto(tw,1); outtext("TEC ");
  324. X   setcolor(DimColor); outtext("Continental Drift Simulator");
  325. X   settextjustify(RIGHT_TEXT,TOP_TEXT);
  326. X   outtextxy(MaxX-tw,1,"David Allen, Peter C. Lind");
  327. X
  328. X   setcolor(BorderColor); rectangle(0,th+1,MaxX,msgY);    /* Map border */
  329. X   wx1 = 2; wy1 = th + 3; wx2 = MaxX - 2; wy2 = msgY - 2;
  330. X   winMaxX = wx2 - wx1; winMaxY = wy2 - wy1; origY2 = wy2;
  331. X
  332. X   legX2 = winMaxX; legX1 = legX2 - (LegCellWid * NUMCOLORS); /* Legend coords */
  333. X   legY2 = winMaxY - 1; legY1 = legY2 - LegCellHgt;
  334. X   legCY = (legY2 + legY1) >> 1;
  335. X
  336. X   setviewport(wx1,wy1,wx2,wy2,TRUE);
  337. X
  338. X   ix = (wx2 - wx1) - (XSIZE * xaddon);
  339. X   yaddon = ((wy2 - wy1 + 1) / YSIZE) + 1;
  340. X   iy = (wy2 - wy1 + 1) - (YSIZE * yaddon);
  341. X  }
  342. X
  343. void grafexit ()
  344. X /* Just close all the things that were opened, then exit(). */
  345. X  {
  346. X   closegraph();
  347. X   textmode(LastVideoMode);
  348. X   printf("TEC ended. Bye\n");
  349. X   exit(0);
  350. X  }
  351. X
  352. unsigned GetIOCTL (fh)
  353. X /* Returns the IOCTL word for file handle `fh'. */
  354. X int fh;
  355. X  {
  356. X   struct REGPACK regs;
  357. X
  358. X   regs.r_ax = 0x4400;            /* DOS Int. sub-function: "Get IOCTL info" */
  359. X   regs.r_bx = fh;                /* File handle in BX */
  360. X   intr(33,®s);                /* Call DOS */
  361. X   return(regs.r_dx);             /* IOCTL info in DX */
  362. X  }
  363. X
  364. void PrintMenu ()
  365. X /* Displays the print menu. */
  366. X  {
  367. X   message("Print to stdout:  G)eneric  T)ext  P)ostscript  ESC=No print");
  368. X  }
  369. X
  370. void TryToPrint ()
  371. X /* Attempts to initiate printing, but first warns the user that stdout
  372. X    must have been redirected on the DOS command line. Also allows the
  373. X    user to choose the print format:
  374. X
  375. X                   G    Generic
  376. X                   T    Text
  377. X                   P    Postscript
  378. X                  ESC   No print
  379. X */
  380. X  {
  381. X   /* Disallow printing if stdout is still directed to the console screen,
  382. X      (ie. IOCTL for stdout indicates device with standard console output). */
  383. X   if ((GetIOCTL(STDOUT_HANDLE) & 0x0082) == 0x0082)
  384. X      {
  385. X       message("*** stdout not redirected.  [ Press any key ] ***");
  386. X       do {                        /* Wait for keypress */
  387. X          } while (!kbhit());
  388. X       if (!getch())               /* Consume character */
  389. X          getch();                 /*   and extended code, if any */
  390. X       return;
  391. X      }
  392. X
  393. X   PrintMenu();
  394. X   do {
  395. X       char c;
  396. X
  397. X       if (!(c = getch()))
  398. X          getch();
  399. X         else
  400. X          switch (c)
  401. X                 {
  402. X                  case ESC: return;
  403. X                            break;
  404. X                  case 'g':
  405. X                  case 'G': message("Sending Generic Mode to stdout...");
  406. X                            tecst(step % 2,DRAWMODE_GENERIC);
  407. X                            PrintMenu();
  408. X                            break;
  409. X                  case 't':
  410. X                  case 'T': message("Sending Text Mode to stdout...");
  411. X                            tecst(step % 2,DRAWMODE_TEXT);
  412. X                            PrintMenu();
  413. X                            break;
  414. X                  case 'p':
  415. X                  case 'P': message("Sending Postscript Mode to stdout...");
  416. X                            tecst(step % 2,DRAWMODE_GRAY);
  417. X                            PrintMenu();
  418. X                            break;
  419. X                  default: break;
  420. X                 }
  421. X      } while (TRUE);
  422. X  }
  423. X
  424. void Set3Dstyle ()
  425. X /* Allows user to choose fast or slow 3-D plotting. */
  426. X  {
  427. X   short OK;
  428. X
  429. X   Mode3D = TRUE;
  430. X   message("3-D Style: S)low  F)ast");
  431. X   do {
  432. X       OK = TRUE;
  433. X       switch (getch())
  434. X              {
  435. X               case 's':
  436. X               case 'S': Slow3D = TRUE;
  437. X                         break;
  438. X               case 'f':
  439. X               case 'F': Slow3D = FALSE;
  440. X                         break;
  441. X               default: OK = FALSE;
  442. X                        break;
  443. X              }
  444. X      } while (!OK);
  445. X  }
  446. X
  447. void ChangePlotStyle ()
  448. X /* Allows user to switch between standard plotting and 3-D plotting. Should
  449. X    only be called if program is running under EGA/VGA. */
  450. X  {
  451. X   short OK;
  452. X
  453. X   message("Switch plotting style:  S)tandard  3)D");
  454. X   do {
  455. X       OK = TRUE;
  456. X       switch (getch())
  457. X              {
  458. X               case '\0': getch();
  459. X                          break;
  460. X               case '3': NoLegend = !Mode3D;
  461. X                         Set3Dstyle();
  462. X                         break;
  463. X               case 's':
  464. X               case 'S': NeedLegend = Mode3D;
  465. X                         Mode3D = FALSE;
  466. X                         break;
  467. X               default: OK = FALSE;
  468. X                        break;
  469. X              }
  470. X      } while (!OK);
  471. X  }
  472. X
  473. void checkmouse ()
  474. X /* Standard event handler. Currently on the IBM PC/XT/AT, can only poll the
  475. X    keyboard for user actions (no mouse support [yet!]):
  476. X
  477. X           <ESC>      Quit program right away
  478. X          <SPACE>     Pause
  479. X          g or G      Change plotting style
  480. X          p or P      Print out the current values of t[src]
  481. X                      using tecst() in tec1.c. */
  482. X  {
  483. X   short i,j,k;
  484. X   char c;
  485. X
  486. X   if (!kbhit())                  /* Key pressed? */
  487. X      return;                     /*   No: Exit */
  488. X   if (!(c = getch()))            /* Read the key. Is it '\0'? */
  489. X      {
  490. X       getch(); return;           /*   Yes: Consume extended code and exit */
  491. X      }
  492. X   switch (c)                     /*   No: Look at key pressed */
  493. X          {
  494. X           case ESC: grafexit();
  495. X                     break;
  496. X           case ' ': WantPause = TRUE;
  497. X                     break;
  498. X           case 'g':
  499. X           case 'G': if (InColor)
  500. X                        ChangePlotStyle();
  501. X                       else
  502. X                        Set3Dstyle();
  503. X                     break;
  504. X           case 'p':
  505. X           case 'P': TryToPrint();
  506. X                     break;
  507. X           default: break;
  508. X          }
  509. X  }
  510. X
  511. int rnd (top)
  512. X int top;
  513. X /* Returns a random number in the range 0..`top'-1. */
  514. X  {
  515. X   return(random(top));
  516. X  }
  517. X
  518. void ResetPlotSettings ()
  519. X /* Resets the 3-D plot settings (used after message() calls). */
  520. X  {
  521. X   if (Mode3D)
  522. X      {
  523. X       setfillstyle(SOLID_FILL,PlotBackColor);
  524. X       setcolor(Bar3Dcolor);
  525. X      }
  526. X  }
  527. X
  528. void PlotMessage ()
  529. X /* Prints the plot message */
  530. X  {
  531. X   message("Plotting...  G)raphing style  P)rint  CR=Skip  SP=Pause  ESC=Quit");
  532. X  }
  533. X
  534. int PlotKeyCheck ()
  535. X /* Called when a key is pressed while plotting. If the key was ESC or
  536. X    SPACE, then TRUE is returned. Otherwise, FALSE is returned. If the
  537. X    key pressed was ESC, 'p' or 'P', the key is not consumed. */
  538. X  {
  539. X   char c;
  540. X
  541. X   switch (c = getch())
  542. X          {
  543. X           case '\0': getch();            /* Discard extended code */
  544. X                      break;
  545. X           case ESC: AllStop = TRUE;      /* Set quit flag... */
  546. X           case '\r': return(TRUE);       /* Exit plot routine */
  547. X                      break;
  548. X           case ' ': WantPause = TRUE;
  549. X                     break;
  550. X           case 'g':
  551. X           case 'G': if (InColor)         /* Defer in EGA/VGA */
  552. X                        WantChangePlot = TRUE;
  553. X                       else
  554. X                        {                 /* Change on the fly in CGA/MCGA */
  555. X                         Set3Dstyle();
  556. X                         PlotMessage();
  557. X                         ResetPlotSettings();
  558. X                        }
  559. X                     break;
  560. X           case 'p':
  561. X           case 'P': WantPrint = TRUE;    /* Set print request flag */
  562. X                     break;
  563. X           default: break;                /* Ignore all else */
  564. X          }
  565. X   return(FALSE);
  566. X  }
  567. X
  568. void draw3d (src)
  569. X /* Draws a 3-D picture of the t[src] in the center of the current viewport
  570. X    using Turbo C's bar3d() function. When `Slow3D' is TRUE, each "pixel" of
  571. X    t[src] is printed as a standing 3-D block; when `Slow3D' is FALSE,
  572. X    adjacent "pixels" in the same row with equal heights are merged and
  573. X    plotted as a wider standing 3-D block, thereby speeding up the plotting
  574. X    process (with a loss of attractiveness). */
  575. X short src;
  576. X  {
  577. X   int boty,x1,x2,x3,x,y,cx,cy,h,nh,c;
  578. X
  579. X   ResetPlotSettings();
  580. X
  581. X   x = ix; y = iy;
  582. X   top: for (cx = 0; cx < XSIZE; cx++, y += yaddon)
  583. X            {
  584. X             x1 = x; x2 = x1 + xaddon; x3 = x + (xaddon * XSIZE);
  585. X             h = -1; c = 0;
  586. X             for (cy = 0; cy < YSIZE; cy++)
  587. X                 {
  588. X                  nh = t[src][cx][cy] >> 3;
  589. X                  if ((nh != h) || Slow3D)
  590. X                     {
  591. X                      if ((c || Slow3D) && (h >= 0))
  592. X                         bar3d(x1,y,x2,y-h,3,TRUE);
  593. X                      h = nh; x1 = x2; c = 1;
  594. X                      if (Slow3D || 1)
  595. X                         x2 += xaddon;
  596. X                     }
  597. X                    else
  598. X                     {
  599. X                      x2 += xaddon; c++;
  600. X                     }
  601. X                 }
  602. X             if (c)
  603. X                bar3d(x1,y,x3,y-nh,3,TRUE);
  604. X             x -= (xaddon >> 1);
  605. X
  606. X             if (kbhit())
  607. X                if (PlotKeyCheck())
  608. X                   return;
  609. X            }
  610. X  }
  611. X
  612. void DisplayLegend ()
  613. X /* Draws the colors legend for EGA/VGA modes. */
  614. X  {
  615. X   int i,x;
  616. X   char num[3];
  617. X
  618. X   settextstyle(DEFAULT_FONT,HORIZ_DIR,1);
  619. X   settextjustify(CENTER_TEXT,CENTER_TEXT);
  620. X
  621. X   /* Special case for black color */
  622. X   x = legX1;
  623. X   setcolor(DARKGRAY);
  624. X   setfillstyle(SOLID_FILL,colors[0]);
  625. X   bar3d(x,legY1,x+LegCellWid,legY2,0,FALSE);
  626. X   outtextxy(x+LegHalfWid,legCY,"0");
  627. X   x += LegCellWid;
  628. X
  629. X   /* Draw other colors in a loop, with black numbers */
  630. X   setcolor(BLACK);
  631. X   for (i = 1; i < NUMCOLORS; i++, x += LegCellWid)
  632. X       {
  633. X        setfillstyle(SOLID_FILL,colors[i]);
  634. X        bar3d(x,legY1,x+LegCellWid,legY2,0,FALSE);
  635. X        sprintf(num,"%d",i);
  636. X        outtextxy(x+LegHalfWid,legCY,num);
  637. X       };
  638. X   wy2 = origY2 - LegCellHgt - 2;       /* Resize viewport to protect legend */
  639. X   setviewport(wx1,wy1,wx2,wy2,TRUE);
  640. X  }
  641. X
  642. void RemoveLegend ()
  643. X /* Effectively removes the colors legend by resetting the map viewport to
  644. X    full size. */
  645. X  {
  646. X   wy2 = origY2; setviewport(wx1,wy1,wx2,wy2,TRUE);
  647. X  }
  648. X
  649. void draw (src)
  650. X short src;
  651. X /* When `Mode3D' is TRUE, this function calls draw3d() and exits. Otherwise,
  652. X    this function takes the array m[src] and draws it on the screen, in a
  653. X    hopefully efficient way.  The function tries to make long horizontal
  654. X    patches that are all the same color.  Then they can be rendered by a
  655. X    graphics function that draws arbitrary rectangles quickly. */
  656. X  {
  657. X   register short i,j,k,x;
  658. X
  659. X   checkmouse();
  660. X   PlotMessage();
  661. X
  662. X   /* Erase the viewport first */
  663. X   if (NoLegend)
  664. X      {
  665. X       RemoveLegend(); NoLegend = FALSE;
  666. X      }
  667. X   setcolor(BackgroundColor); clearviewport();
  668. X
  669. X   if (Mode3D)                  /* If in 3-D mode, then call draw3d() */
  670. X      {
  671. X       draw3d(src); return;
  672. X      }
  673. X
  674. X   /* Draw color legend whenever it needs to be displayed. */
  675. X   if (NeedLegend)
  676. X      {
  677. X       DisplayLegend(); NeedLegend = FALSE;
  678. X      }
  679. X
  680. X   /* For each scan line, start at the left edge */
  681. X   for (j = 0, i = 0; j < YSIZE; j++, i = 0)
  682. X       {
  683. X        int x1,y1,x2,y2;
  684. X
  685. X    /* If the current square is not ocean, set x to its color */
  686. X    top: if ((x = t[src][i][j] >> 2) > 1)
  687. X                {
  688. X                 /* Go as far along to the right as you can in this color */
  689. X                 k = i + 1;
  690. X                 while (((t[src][k][j] >> 2) == x) && (k < XSIZE-1))
  691. X                       k++;
  692. X
  693. X                 /* Draw a short, wide rectangle */
  694. X                 if (x > 27)
  695. X                    x = 27;
  696. X                 x1 = i * CellXsize; y1 = j * CellYsize;
  697. X                 x2 = k * CellXsize; y2 = y1 + CellYsize - 1;
  698. X                 setfillstyle(SOLID_FILL,colors[x]);
  699. X                 bar(x1,y1,x2,y2);
  700. X                 i = k-1;
  701. X
  702. X                 if (kbhit())
  703. X                    if (PlotKeyCheck())
  704. X                       return;
  705. X                }
  706. X
  707. X        /* If not at end of scanline, do more; else start next scanline */
  708. X        if (i < XSIZE-1)
  709. X           {
  710. X            i++;
  711. X            goto top;
  712. X           }
  713. X       }
  714. X  }
  715. X
  716. void main (argc,argv)
  717. X /* Initializes everything and enters a (finite) loop that repeatedly calls
  718. X    onestep() and checkmouse() until the maximum step is reached or the user
  719. X    quits. */
  720. X int argc;
  721. X char **argv;
  722. X  {
  723. X   char menu[80];
  724. X
  725. X   randomize();     /* Randomize random number generator using DOS time */
  726. X
  727. X   /* Initialize everything */
  728. X   AllStop = WantPrint = WantPause = WantChangePlot = FALSE; /* Clear deferrals */
  729. X   NoLegend = FALSE;
  730. X   grafinit();
  731. X   message("Setting up...");
  732. X   init(*++argv);                 /* Perform major initialization */
  733. X   checkmouse();                  /* Give user a chance to do something */
  734. X
  735. X   /* Call onestep() once per step; then check for user key actions */
  736. X   for (step = 0; step < MAXSTEP; step++)
  737. X       {
  738. X        /* Check for deferred commands */
  739. X        if (AllStop)
  740. X           grafexit();
  741. X        if (WantPrint)
  742. X           TryToPrint();
  743. X        if (WantChangePlot)
  744. X           ChangePlotStyle();
  745. X        if (WantPause)
  746. X           {
  747. X            message("[ Pausing -- Press any Key ]");
  748. X            WaitKeyPress();
  749. X           }
  750. X        WantPrint = WantPause = WantChangePlot = FALSE;  /* Clear deferrals */
  751. X
  752. X        /* Do some work */
  753. X        sprintf(menu,"Thinking [%d]... G)raphing style  P)rint  SP=Pause  ESC=Quit",
  754. X                     step);
  755. X    message(menu);
  756. X        onestep();
  757. X        checkmouse();
  758. X       }
  759. X
  760. X   /* Reached end of simulation without error or user quit signal. */
  761. X   message("Execution terminated -- Press any key");
  762. X
  763. X   WaitKeyPress();              /* Loop forever until user pressed a key */
  764. X
  765. X   closegraph();                /* Shut down */
  766. X   textmode(LastVideoMode);
  767. X  }
  768. END_OF_FILE
  769. if test 22685 -ne `wc -c <'tec-v3/ibmpc.c'`; then
  770.     echo shar: \"'tec-v3/ibmpc.c'\" unpacked with wrong size!
  771. fi
  772. # end of 'tec-v3/ibmpc.c'
  773. fi
  774. if test -f 'tec-v3/tec.mak' -a "${1}" != "-c" ; then 
  775.   echo shar: Will not clobber existing file \"'tec-v3/tec.mak'\"
  776. else
  777. echo shar: Extracting \"'tec-v3/tec.mak'\" \(1500 characters\)
  778. sed "s/^X//" >'tec-v3/tec.mak' <<'END_OF_FILE'
  779. X# Make file for TEC under Turbo C 2.0
  780. X# Peter C. Lind, Elec. & Comp. Eng., McMaster University, Hamilton, ON., 1990.
  781. X# NOTE: Read the comments in this file before proceeding; the macros defining
  782. X#       directories may need to be modified to work properly on your system;
  783. X#       also, certain macros may be altered to produce 80186/80286 code and/or
  784. X#       80x87 code.
  785. X
  786. X# Turbo C Directory (Change as needed; DOS path \ must be specified
  787. X#                    as \\ at the end of a line)
  788. TCD=\TC\\
  789. X
  790. X# Memory Model (Change c to l for large, or h for huge)
  791. MDL=c
  792. X
  793. X# Path to libraries (Change as needed; DOS path \ must be specified
  794. X#                    as \\ at the end of a line)
  795. LIB=\TC\LIB\\
  796. X
  797. X# Instruction Set (Add -1 after = to enable 80186/80286)
  798. INST=
  799. X
  800. X# 80x87 Support (Add -f87 after = to enable 80x87 code generation, and...)
  801. XFLP=
  802. X
  803. X# 80x87 Support (...change emu to fp87)
  804. XFLT=emu
  805. X
  806. X# Compiler options:
  807. X#      -c      Compile to OBJ
  808. X#      -G      Optimize for speed
  809. X#      -w-     Suppress warnings
  810. X#      -a      Align on word boundary
  811. OPTS=-c -m$(MDL) -G -w- -a $(INST) $(FLP)
  812. X
  813. X
  814. tec.exe: ibmpc.obj tec1.obj tec2.obj tec3.obj
  815. X  $(TCD)tlink $(LIB)c0$(MDL) ibmpc tec1 tec2 tec3, tec, , \
  816. X        $(LIB)graphics $(LIB)$(FLT) $(LIB)math$(MDL) $(LIB)c$(MDL)
  817. X
  818. ibmpc.obj: ibmpc.c const.h var.h
  819. X  $(TCD)tcc $(OPTS) ibmpc.c
  820. X
  821. tec1.obj: tec1.c const.h var.h
  822. X  $(TCD)tcc $(OPTS) tec1.c
  823. X
  824. tec2.obj: tec2.c const.h var.h
  825. X  $(TCD)tcc $(OPTS) tec2.c
  826. X
  827. tec3.obj: tec3.c const.h var.h
  828. X  $(TCD)tcc $(OPTS) tec3.c
  829. END_OF_FILE
  830. if test 1500 -ne `wc -c <'tec-v3/tec.mak'`; then
  831.     echo shar: \"'tec-v3/tec.mak'\" unpacked with wrong size!
  832. fi
  833. # end of 'tec-v3/tec.mak'
  834. fi
  835. if test -f 'tec-v3/tec1.c' -a "${1}" != "-c" ; then 
  836.   echo shar: Will not clobber existing file \"'tec-v3/tec1.c'\"
  837. else
  838. echo shar: Extracting \"'tec-v3/tec1.c'\" \(21292 characters\)
  839. sed "s/^X//" >'tec-v3/tec1.c' <<'END_OF_FILE'
  840. X/* This program is Copyright (c) 1990 David Allen.  It may be freely
  841. X   distributed as long as you leave my name and copyright notice on it.
  842. X   I'd really like your comments and feedback; send e-mail to
  843. X   davea@vlsi.ll.mit.edu, or send us-mail to David Allen, 10 O'Moore Ave,
  844. X   Maynard, MA 01754. */
  845. X
  846. X/* This is the file containing all of the important functions except for
  847. X   trysplit (), which splits a continent into pieces.  Also, all of the main
  848. X   arrays are declared here, even a couple that are only used by functions in
  849. X   tec2.c.  The array declarations are first, followed by the sequencing
  850. X   function onestep () and some miscellaneous routines including the text
  851. X   output routines; initialization routines and the routines that do all
  852. X   the interesting stuff are last. */
  853. X
  854. X
  855. X#include "const.h"
  856. X#include "var.h"
  857. X
  858. X#include <stdio.h>
  859. X
  860. X/* These defines are used for the PostScript output section of tecst(). */
  861. X#define D ((double) 432 / ((XSIZE > YSIZE) ? XSIZE : YSIZE))
  862. X#define ZMAX 128
  863. X#define XX(x) (108 + ((x) * D))
  864. X#define YY(y) (612 - ((y) * D))
  865. X#define ZZ(z) (1 - (float) ((z > ZMAX) ? ZMAX : z) / (ZMAX))
  866. X/* The following arrays are global and most are used by functions in both
  867. X   source files.  The two main ones are m and t.  Each is set up to be two
  868. X   2-d arrays, where each array is the size of the whole world.  M is the
  869. X   map; elements in m are indices of plates, showing which squares are
  870. X   covered by which plate.  T is the topography; elements in t are altitudes. */
  871. char m[2][MAXX][MAXY]; unsigned char t[2][MAXX][MAXY];
  872. X/* Several arrays are used by the binary blob segmenter, segment() in tec2.c.
  873. X   These include r, which is used to store fragment indices; many fragments
  874. X   make up one region during a segmentation.  Kid is a lookup table; fragment
  875. X   k belongs to region kid[k] after a segmentation is finished.  Karea[k]
  876. X   is the area of fragment k. */
  877. char r[MAXX][MAXY], kid[MAXFRAG]; short karea [MAXFRAG];
  878. X/* The merge routine gets information from the move routine; when the move
  879. X   routine puts a square of one plate on top of another plate, that information
  880. X   is recorded in the merge matrix mm. */
  881. char mm[MAXPLATE][MAXPLATE];
  882. X/* The erosion routine needs an array to store delta information; during an
  883. X   erosion, the increases or decreases in elevation are summed in e and then
  884. X   applied all at once to the topography. */
  885. char e[MAXX][MAXY];
  886. X/* Several routines need temporary storage for areas and plate identifiers. */
  887. short tarea[MAXPLATE]; short ids[MAXPLATE];
  888. X/* The plates in use are stored in this data structure.  Dx,dy are the
  889. X   values to move by THIS STEP ONLY; odx,ody are the permanent move
  890. X   values; rx,ry are the remainder x and y values used by newdxy() to
  891. X   determine dx,dy; age is the age of the plate, in steps; area is the
  892. X   area of the plate, in squares; id is the value in the m array which
  893. X   corresponds to this plate; next is a pointer to the next occupied
  894. X   element of the plate array. */
  895. struct plate p [MAXPLATE];
  896. X/* The linked list header for available plates and used plates are global,
  897. X   as is the step counter.  */
  898. short pavail, phead, step;
  899. onestep () {
  900. X   /* This is the sequencing routine called by main once per step.
  901. X   It just calls the important subfunctions in order:
  902. X   - trysplit   finds a plate to break up, and computes new velocities
  903. X   - newdxy     computes the deltas to move each plate this step
  904. X   - move       moves the plates
  905. X   - merge      determines results when plates rub together
  906. X   - erode      erodes the terrain, adding or subtracting at the margins
  907. X   - draw       draw the resulting array once every DRAWEVERY steps
  908. X   The m and t arrays are double-buffered in the sense that operations go
  909. X   from m[0] to m[1] or vice-versa; src and dest determine which is which. */
  910. X   short src, dest;
  911. X   src = step % 2; dest = 1 - src;
  912. X   if (rnd (100) < RIFTPCT) trysplit (src);
  913. X   newdxy ();
  914. X   move (src, dest);
  915. X   merge (dest);
  916. X   if (DOERODE) erode (dest);
  917. X   if (step && !(step % DRAWEVERY)) draw (dest); }
  918. palloc () {
  919. X   /* Allocate a plate from the array and return its index.  All the fields
  920. X   of the plate are initialized to 0, except `next'.  That field is used to
  921. X   link together the plate structures in use.  */
  922. X   short x;
  923. X
  924. X   if (!pavail) panic ("No more objects");
  925. X   x = pavail; pavail = p[x].next;
  926. X   p[x].next = phead; phead = x;
  927. X   p[x].area = 0; p[x].age = 0;
  928. X   p[x].rx = 0; p[x].ry = 0;
  929. X   p[x].odx = 0; p[x].ody = 0;
  930. X   p[x].dx = 0; p[x].dy = 0;
  931. X   return ((int) x); }
  932. pfree (n) short n; {
  933. X   /* Return a plate array element to the pool of available elements.
  934. X      To check for infinite loops, the variable guard is incremented
  935. X      at each operation; if the number of operations exceeds the maximum
  936. X      possible number, the program panics. */
  937. X   short i, guard = 0;
  938. X   if (phead == n) phead = p[n].next;
  939. X   else {
  940. X      for (i=phead; p[i].next!=n; i=p[i].next)
  941. X         if (++guard > MAXPLATE) panic ("Infinite loop in pfree");
  942. X      p[i].next = p[n].next; }
  943. X   p[n].next = pavail; pavail = n; }
  944. X
  945. tecst (src, drawmode) short src, drawmode; {
  946. X   /* This function is called whenever map output is called for.  It looks
  947. X   at the parameter `drawmode' to decide between long text, simple text,
  948. X   and PostScript output formats.  Note that the default for this
  949. X   function is no output at all, corresponding to DRAWMODE_NONE. */
  950. X  
  951. X   register short i,j,k;
  952. X
  953. X   if (drawmode == DRAWMODE_GENERIC) 
  954. X      for (j=0; j<YSIZE; j++) for (i=0, k=0; i<XSIZE; i++) {
  955. X         printf ("%4d", t[src][i][j]);
  956. X         if (!(++k % 18)) printf ("\n"); }
  957. X   else if (drawmode == DRAWMODE_TEXT) {
  958. X      for (j=0; j<YSIZE; j++) {
  959. X         for (i=0; i<XSIZE; i++) {
  960. X            if ((k = t[src][i][j]) < ZCOAST) k = 0;
  961. X            else if (k > ZMOUNTAIN) k = 2; else k = 1;
  962. X            printf ("%d", k); }
  963. X         printf ("\n"); }
  964. X      printf ("\n"); }
  965. X   else if (drawmode == DRAWMODE_GRAY) {
  966. X      printf ("%%!PS-Adobe-1.0\n/d %4.2f def\n", D);
  967. X      printf ("37.5 45 { dup mul exch dup mul add 1 exch sub } setscreen\n");
  968. X      printf ("/r { setgray moveto d 0 rlineto 0 d rlineto ");
  969. X      printf ("d neg 0 rlineto fill } bind def\n");
  970. X      printf ("%6.2f %6.2f moveto\n",         XX(-1),    YY(-1));
  971. X      printf ("%6.2f %6.2f lineto\n",         XX(XSIZE), YY(-1));
  972. X      printf ("%6.2f %6.2f lineto\n",         XX(XSIZE), YY(YSIZE));
  973. X      printf ("%6.2f %6.2f lineto\n",         XX(-1),    YY(YSIZE));
  974. X      printf ("%6.2f %6.2f lineto\nstroke\n", XX(-1),    YY(-1));
  975. X   
  976. X      for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++)
  977. X         if ((k = t[src][i][j]) > ZCOAST)
  978. X            printf ("%6.2f %6.2f %5.4f r\n", XX(i), YY(j), ZZ(k));
  979. X      printf ("\nshowpage\n"); } }
  980. X
  981. X
  982. init (s) char *s; {
  983. X   /* This is the catchall function that initializes everything.  First,
  984. X   it calls getparams() in tec3.c to allow the user to set parameters.  Next,
  985. X   it links together the plates onto the free list and starts the used list
  986. X   at empty.  The first plate is created by a fractal technique and then
  987. X   improved.  Finally, the fractal is copied to the data array and drawn.
  988. X   There are two kinds of improvement done here.  First, islands are
  989. X   eliminated by segmenting the blob and erasing all the regions except
  990. X   for the biggest.  Second, oceans inside the blob (holes) are eliminated
  991. X   by segmenting the _ocean_ and filling in all regions except the biggest. */
  992. X   short besti, x; register short i, j;
  993. X   if (s) if (*s) getparams (s);
  994. X   for (i=1; i<MAXPLATE; i++) p[i].next = i + 1;
  995. X   p[MAXPLATE-1].next = 0;
  996. X   pavail = 1; phead = 0;
  997. X   /* Allocate a plate structure for the first plate and make a blob */
  998. X   x = palloc (); makefrac (0, x);
  999. X   /* Segment m[0] looking for x, set besti to the largest region, */
  1000. X   /* and zero out all the other regions.  This eliminates islands. */
  1001. X   besti = singlefy (0, x);
  1002. X   if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
  1003. X      if (kid[r[i][j]] != besti) m[0][i][j] = 0;
  1004. X   /* Segment m[0] looking for 0 (ocean), set besti to the largest region, */
  1005. X   /* and fill in all the other regions.  This eliminates holes in the blob. */
  1006. X   besti = singlefy (0, 0);
  1007. X   if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
  1008. X      if (kid[r[i][j]] != besti) m[0][i][j] = x;
  1009. X   /* Fill the topo structure with the blob shape while finding its area */
  1010. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
  1011. X      if (m[0][i][j]) { t[0][i][j] = ZINIT; p[x].area++; }
  1012. X   /* Draw the blob */
  1013. X   draw (0); }
  1014. makefrac (src, match) short src, match; {
  1015. X   /* This function uses a very simple fractal technique to draw a blob.  Four
  1016. X   one-dimensional fractals are created and stored in array x, then the
  1017. X   fractals are superimposed on a square array, summed and thresholded to
  1018. X   produce a binary blob.  Squares in the blob are set to the value in `match'.
  1019. X   A one-dimensional fractal of length n is computed like this.  First,
  1020. X   set x [n/2] to some height and set the endpoints (x[0] and x[n]) to 0.
  1021. X   Then do log-n iterations.  The first iteration computes 2 more values:
  1022. X   x[n/4] = average of x[0] and x[n/2], plus some random number, and
  1023. X   x[3n/4] = average of x[n/2] and x[n], plus some random number.  The second
  1024. X   iteration computes 4 more values (x[n/8], x[3n/8], ...) and so on.  The
  1025. X   random number gets smaller by a factor of two each time also.
  1026. X   Anyway, you wind up with a number sequence that looks like the cross-section
  1027. X   of a mountain.  If you sum two fractals, one horizontal and one vertical,
  1028. X   you get a 3-d mountain; but it looks too symmetric.  If you sum four,
  1029. X   including the two 45 degree diagonals, you get much better results. */
  1030. X   register short xy, dist, n, inc, i, j, k; char x[4][65];
  1031. X   short xofs, yofs, xmin, ymin, xmax, ymax;
  1032. X   /* Compute offsets to put center of blob in center of the world, and
  1033. X      compute array limits to clip blob to world size */
  1034. X   xofs = (XSIZE - 64) >> 1; yofs = (YSIZE - 64) >> 1;
  1035. X   if (xofs < 0) { xmin = -xofs; xmax = 64 + xofs; }
  1036. X   else { xmin = 0; xmax = 64; }
  1037. X   if (yofs < 0) { ymin = -yofs; ymax = 64 + yofs; }
  1038. X   else { ymin = 0; ymax = 64; }
  1039. X   for (xy=0; xy<4; xy++) {
  1040. X      /* Initialize loop values and fractal endpoints */
  1041. X      x [xy] [0] = 0; x [xy] [64] = 0; dist = 32;
  1042. X      x [xy] [32] = 24 + rnd (16); n = 2; inc = 16;
  1043. X      /* Loop log-n times, each time halving distance and doubling iterations */
  1044. X      for (i=0; i<5; i++, dist>>=1, n<<=1, inc>>=1)
  1045. X         for (j=0, k=0; j<n; j++, k+=dist)
  1046. X            x[xy][k+inc] = ((x[xy][k]+x[xy][k+dist])>>1) + rnd (dist) - inc; }
  1047. X   /* Superimpose fractals; if sum is greater than BLOBLEVEL, there will be */
  1048. X   /* land there.  x[0] is horizontal, x[1] vertical, x[2] diagonal from */
  1049. X   /* top left to bottom right, x[3] diagonal from TR to BL. */
  1050. X   for (i=xmin; i<xmax; i++) for (j=ymin; j<ymax; j++) {
  1051. X      k = x[0][i] + x[1][j] + x[2][(i - j + 64) >> 1] + x[3][(i + j) >> 1];
  1052. X      if (k > BLOBLEVEL) m[src][i+xofs][j+yofs] = match; } }
  1053. singlefy (src, match) short src, match; {
  1054. X   /* This is a subfunction of init() which is called twice to improve the
  1055. X   fractal blob.  It calls segment() and then interprets the result.  If
  1056. X   only one region was found, no improvement is needed; otherwise, the
  1057. X   area of each region must be computed by summing the areas of all its
  1058. X   fragments, and the index of the largest region is returned. */
  1059. X   short i, reg, frag, besti, besta;
  1060. X   segment (src, match, &frag, ®);
  1061. X   if (reg == 1) return (-1); /* No improvement needed */
  1062. X   /* Initialize the areas to zero, then sum frag areas */
  1063. X   for (i=1; i<=reg; i++) tarea[i] = 0;
  1064. X   for (i=1; i<=frag; i++) tarea [kid[i]] += karea [i];
  1065. X   /* Pick largest area of all regions and return it */
  1066. X   for (i=1, besta=0, besti=0; i<=reg; i++)
  1067. X      if (besta < tarea[i]) { besti = i; besta = tarea[i]; }
  1068. X   return ((int) besti); }
  1069. newdxy () {
  1070. X   /* For each plate, compute how many squares it should move this step.
  1071. X   Multiply the plate's basic movement vector odx,ody by the age modifier
  1072. X   MR[], then add the remainders rx,ry from the last move to get some large
  1073. X   integers.  Then turn the large integers into small ones by dividing by
  1074. X   REALSCALE and putting the remainders back into rx,ry.  This function also
  1075. X   increases the age of each plate, but doesn't let the age of any plate
  1076. X   go above MAXLIFE.  This is done to make sure that MR[] does not need to
  1077. X   be a long vector. */
  1078. X   register short i, a;
  1079. X   for (i=phead; i; i=p[i].next) {
  1080. X      a = (p[i].odx * MR[p[i].age]) + p[i].rx;
  1081. X      p[i].dx = a / REALSCALE; p[i].rx = a % REALSCALE;
  1082. X      a = (p[i].ody * MR[p[i].age]) + p[i].ry;
  1083. X      p[i].dy = a / REALSCALE; p[i].ry = a % REALSCALE;
  1084. X      if (p[i].age < MAXLIFE-1) (p[i].age)++; } }
  1085. move (src, dest) short src, dest; {
  1086. X   /* This function moves all the plates that are drifting.  The amount to
  1087. X   move by is determined in newdxy().  The function simply steps through
  1088. X   every square in the array; if there's a plate in a square, its new location
  1089. X   is found and the topography is moved there.  Overlaps between plates are
  1090. X   detected and recorded so that merge() can resolve the collision; mountain
  1091. X   growing is performed.  If two land squares wind up on top of each other,
  1092. X   folded mountains are produced.  If a land square winds up where ocean was
  1093. X   previously, that square is the leading edge of a continent and grows a
  1094. X   mountain by subsuming the ocean basin. */
  1095. X   register short i, j; short a, b, c, x, y;
  1096. X   /* Clear out the merge matrix and the destination arrays */
  1097. X   for (i=1; i<MAXPLATE; i++) for (j=1; j<MAXPLATE; j++) mm[i][j] = 0;
  1098. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  1099. X      m[dest][i][j] = 0; t[dest][i][j] = 0; }
  1100. X   /* Look at every square which belongs to a plate */
  1101. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) if ((a = m[src][i][j]) > 0) {
  1102. X      /* Add the plate's dx,dy to the position to get the square's new */
  1103. X      /* location; if it is off the map, throw it away */
  1104. X      x = p[a].dx + i; y = p[a].dy + j;
  1105. X      if ((x >= XSIZE) || (x < 0) || (y >= YSIZE) || (y < 0)) p[a].area--;
  1106. X      else { /* It IS on the map */
  1107. X         /* If the destination is occupied, remove the other guy but */
  1108. X         /* remember that the two plates overlapped; set the new height */
  1109. X         /* to the larger height plus half the smaller. */
  1110. X         if (c = m[dest][x][y]) {
  1111. X            (mm[a][c])++; (p[c].area)--;
  1112. X            b = t[src][i][j]; c = t[dest][x][y];
  1113. X            t[dest][x][y] = (b > c) ? b + (c>>1) : c + (b>>1); }
  1114. X         /* The destination isn't occupied.  Just copy the height. */
  1115. X         else t[dest][x][y] = t[src][i][j];
  1116. X         /* If this square is over ocean, increase its height. */
  1117. X         if (t[src][x][y] < ZCOAST) t[dest][x][y] += ZSUBSUME;
  1118. X         /* Plate A now owns this square */
  1119. X         m[dest][x][y] = a; } } }
  1120. merge (dest) short dest; {
  1121. X   /* Since move has set up the merge matrix, most of the work is done.  This
  1122. X   function calls bump once for each pair of plates which are rubbing; note
  1123. X   that a and b below loop through the lower diagonal part of the matrix.
  1124. X   One subtle feature is that a plate can bump with several other plates in
  1125. X   a step; suppose that the plate is merged with the first plate it bumped.
  1126. X   The loop will try to bump the vanished plate with the other plates, which
  1127. X   would be wrong.  To avoid this, the lookup table lut is used to provide
  1128. X   a level of indirection.  When a plate is merged with another, its lut
  1129. X   entry is changed to indicate that future merges with the vanished plate
  1130. X   should be applied to the plate it has just been merged with. */
  1131. X   char lut[MAXPLATE]; short a, aa, b, bb, i;
  1132. X   for (a=1; a<MAXPLATE; a++) lut[a] = a;
  1133. X   for (a=2; a<MAXPLATE; a++) for (b=1; b<a; b++) if (mm[a][b] || mm[b][a]) {
  1134. X      aa = lut [a]; bb = lut[b];
  1135. X      if (aa != bb) if (bump (dest, aa, bb)) {
  1136. X         lut[aa] = bb;
  1137. X         for (i=1; i<MAXPLATE; i++) if (lut[i] == aa) lut[i] = bb; } } }
  1138. bump (dest, a, b) short dest, a, b; {
  1139. X   /* Plates a and b have been moved on top of each other by some amount;
  1140. X   alter their movement rates for a slow collision, possibly merging them.
  1141. X   The collision "strength" is a ratio of the area overlap (provided by
  1142. X   move ()) to the total area of the plates involved.  A fraction of each
  1143. X   plate's current movement vector is subtracted from the movement vector
  1144. X   of the other plate.  If the two vectors are now within some tolerance
  1145. X   of each other, they are almost at rest so merge them with each other. */
  1146. X   double maa, mab, ta, tb, rat, area; register short i, j, x;
  1147. X   /* Find a ratio describing how strong the collision is */
  1148. X   x = mm[a][b] + mm[b][a]; area = p[a].area + p[b].area;
  1149. X   rat = x / (MAXBUMP + (area / 20)); if (rat > 1.0) rat = 1.0;
  1150. X   /* Do some math to update the move vectors.  This looks complicated */
  1151. X   /* because a plate's actual movement vector must be multiplied by */
  1152. X   /* MR[age], and because I have rewritten the equations to maximize */
  1153. X   /* use of common factors.  Trust me, it's just inelastic collision. */
  1154. X   maa = p[a].area * MR[p[a].age]; mab = p[b].area * MR[p[b].age];
  1155. X   ta = MR[p[a].age] * area;
  1156. X   p[a].odx = (p[a].odx * maa + p[b].odx * mab * rat) / ta;
  1157. X   p[a].ody = (p[a].ody * maa + p[b].ody * mab * rat) / ta;
  1158. X   tb = MR[p[b].age] * area;
  1159. X   p[b].odx = (p[b].odx * mab + p[a].odx * maa * rat) / tb;
  1160. X   p[b].ody = (p[b].ody * mab + p[a].ody * maa * rat) / tb;
  1161. X   /* For each axis, compute the remaining relative velocity.  If it is */
  1162. X   /* too large, return without merging the plates */
  1163. X   if (ABS (p[a].odx*MR[p[a].age] - p[b].odx*MR[p[b].age]) > BUMPTOL) return(0);
  1164. X   if (ABS (p[a].ody*MR[p[a].age] - p[b].ody*MR[p[b].age]) > BUMPTOL) return(0);
  1165. X   /* The relative velocity is small enough, so merge the plates.  Replace */
  1166. X   /* all references to a with b, free a, and tell merge() a was freed. */
  1167. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
  1168. X      if (m[dest][i][j] == a) m[dest][i][j] = b;
  1169. X   p[b].area += p[a].area; pfree (a);
  1170. X   return ((int) a); }
  1171. X/* The following is defined as a macro for efficiency; erosion is still
  1172. X   the slowest function in the simulation.  ERODE is called four times per
  1173. X   pixel by erode. A and b are altitudes of two adjacent squares, while c
  1174. X   and d are the corresponding delta values for those squares.  The amount
  1175. X   each square loses to an adjacent but lower square in each step is
  1176. X   one-eighth the difference in altitude.  This is coded as a shift right 3
  1177. X   bits, but since -1 >> 3 is still -1, the code must be repeated to avoid
  1178. X   negative deltas. */
  1179. X#define ERODE(a,b,c,d) \
  1180. if (((a > ZSHELF) || (b > ZSHELF))) { \
  1181. X   if ( a > b) { x = (a - b + ERODERND) >> 3; c -= x; d += x; } \
  1182. X   else { x = (b - a + ERODERND) >> 3; c += x; d -= x; } }
  1183. erode (dest) short dest; {
  1184. X   /* This function takes the topography in t[dest] and smooths it, lowering
  1185. X   mountains and raising lowlands and continental margins.  It does this by
  1186. X   stepping across the entire array and doing a computation once for each
  1187. X   pair of 8-connected pixels.  The computation is done by ERODE, above.
  1188. X   The computation result for a pair is a small delta for each square, which
  1189. X   is summed in the array e.  When the computation is finished, the delta
  1190. X   is applied; if this pushes an ocean square high enough, it is added to
  1191. X   an adjacent plate if one can be found.  Also, if a land square is eroded
  1192. X   low enough, it is turned into ocean and removed from its plate. */
  1193. X   register short i, j, t1, x, z; short ii, jj, xx;
  1194. X   /* Zero out the array for the deltas first */
  1195. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) e[i][j] = 0;
  1196. X   /* Step across the entire array; each pixel is adjacent to 8 others, and */
  1197. X   /* it turns out that if four pairs are considered for each pixel, each */
  1198. X   /* pair is considered exactly once.  This is important for even erosion */
  1199. X   for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++) {
  1200. X      t1 = t[dest][i][j];
  1201. X      ERODE (t1, t[dest][i][j-1],   e[i][j], e[i][j-1])
  1202. X      ERODE (t1, t[dest][i-1][j-1], e[i][j], e[i-1][j-1])
  1203. X      ERODE (t1, t[dest][i-1][j],   e[i][j], e[i-1][j])
  1204. X      if (j < YSIZE-1) {
  1205. X         ERODE (t1, t[dest][i-1][j+1], e[i][j], e[i-1][j+1]) } }
  1206. X   /* Now go back across the array, applying the delta values from e[][] */
  1207. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  1208. X      z = t[dest][i][j] + e[i][j]; if (z < 0) z = 0; if (z > 255) z = 255;
  1209. X      /* If the square just rose above shelf level, look at the four */
  1210. X      /* adjacent squares.  If one is a plate, add the square to that plate */
  1211. X      if ((z >= ZSHELF) && (t[dest][i][j] < ZSHELF)) {
  1212. X         if (i > 1)      if (xx = m[dest][i-1][j]) { ii = i-1; jj = j; }
  1213. X         if (i < XSIZE-1) if (xx = m[dest][i-1][j]) { ii = i+1; jj = j; }
  1214. X         if (j > 1)      if (xx = m[dest][i][j-1]) { ii = i; jj = j-1; }
  1215. X         if (j < YSIZE-1) if (xx = m[dest][i][j+1]) { ii = i; jj = j+1; }
  1216. X         p[xx].area++; m[dest][i][j] = xx; }
  1217. X      /* If the square is lower than shelf level but belongs to a plate, */
  1218. X      /* remove it from the plate */
  1219. X      if (((t[dest][i][j] = z) < ZSHELF) && (x = m[dest][i][j])) {
  1220. X         p[x].area--; m[dest][i][j] = 0; } } }
  1221. X
  1222. X
  1223. X
  1224. X
  1225. END_OF_FILE
  1226. if test 21292 -ne `wc -c <'tec-v3/tec1.c'`; then
  1227.     echo shar: \"'tec-v3/tec1.c'\" unpacked with wrong size!
  1228. fi
  1229. # end of 'tec-v3/tec1.c'
  1230. fi
  1231. if test -f 'tec-v3/tec2.c' -a "${1}" != "-c" ; then 
  1232.   echo shar: Will not clobber existing file \"'tec-v3/tec2.c'\"
  1233. else
  1234. echo shar: Extracting \"'tec-v3/tec2.c'\" \(14274 characters\)
  1235. sed "s/^X//" >'tec-v3/tec2.c' <<'END_OF_FILE'
  1236. X/* This program is Copyright (c) 1990 David Allen.  It may be freely
  1237. X   distributed as long as you leave my name and copyright notice on it.
  1238. X   I'd really like your comments and feedback; send e-mail to
  1239. X   davea@vlsi.ll.mit.edu, or send us-mail to David Allen, 10 O'Moore Ave,
  1240. X   Maynard, MA 01754. */
  1241. X
  1242. X/* This file contains the function trysplit(), which is called from
  1243. X   onestep() in tec1.c, and its subfunctions.  One of its subfunctions,
  1244. X   segment(), is also called from init() in tec1.c.   Trysplit is the
  1245. X   function in charge of splitting one plate into smaller plates. */
  1246. X
  1247. X
  1248. X#include "const.h"
  1249. X#include "var.h"
  1250. X
  1251. X#define PI 3.14159
  1252. X#define TWOPI 6.28318
  1253. X#define TWOMILLIPI 0.00628318
  1254. X
  1255. X/* RIFTMARK is the temporary indicator placed in the arrays to indicate
  1256. X   the squares a rift has just appeared.  The function stoprift() puts
  1257. X   them in, and trysplit() takes them out before anybody can see them. */
  1258. X#define RIFTMARK -1
  1259. X
  1260. X/* These are all defined in tec1.c */
  1261. extern char m[2][MAXX][MAXY], r[MAXX][MAXY], kid[MAXFRAG];
  1262. extern unsigned char t[2][MAXX][MAXY];
  1263. extern short karea[MAXFRAG], tarea[MAXPLATE], ids[MAXPLATE], step;
  1264. extern struct plate p [MAXPLATE];
  1265. X
  1266. X
  1267. trysplit (src) short src; {
  1268. X   /* Trysplit is called at most once per step in only 40% of the steps.
  1269. X   It first draws a rift on one of the plates, then it segments the result
  1270. X   into some number of new plates and some splinters.  If exactly two new
  1271. X   non-splinter plates are found, new plate structures are allocated, new
  1272. X   dx and dy values are computed, and the old plate is freed.  If anything
  1273. X   goes wrong, the rift is erased from the array, returning the array to its
  1274. X   previous state.  The functions newrift, segment and newplates do most
  1275. X   of the work. */
  1276. X
  1277. X   register short i, j, a; short count, old, frag, reg;
  1278. X
  1279. X   if (old = newrift (src)) if (segment (src, old, &frag, ®)) if (reg > 1) {
  1280. X
  1281. X      /* Set tarea[i] to areas of the final segmented regions */
  1282. X      for (i=0; i<=MAXPLATE; i++) tarea[i] = 0;
  1283. X      for (i=1; i<=frag; i++) tarea[kid[i]] += karea[i];
  1284. X
  1285. X      /* Give up unless exactly two regions are large enough */
  1286. X      for (i=1, count=0; i<=reg; i++) if (tarea[i] > MAXSPLINTER) count++; 
  1287. X      if (count == 2) {
  1288. X
  1289. X         /* Compute new dx,dy, then update m with the ids of the new plates */
  1290. X         newplates (src, old);
  1291. X         for (i=0, count=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  1292. X            if (a = r[i][j]) m[src][i][j] = ids[kid[a]];
  1293. X            if (m[src][i][j] == RIFTMARK) {
  1294. X               m[src][i][j] = 0; t[src][i][j] = 0; } }
  1295. X         pfree (old); return (0); } }
  1296. X
  1297. X   /* If execution reaches here, the split operation failed; remove rift */
  1298. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
  1299. X      if (m[src][i][j] == RIFTMARK) m[src][i][j] = old; }
  1300. X
  1301. X
  1302. newrift (src) short src; {
  1303. X   /* This function randomly picks a center for a new rift, and draws in
  1304. X   a curving line until the line hits either the coast or another plate.
  1305. X   If another plate is hit, the rift is invalid and the function returns 0.
  1306. X   To find a center, the function generates random x,y values until it
  1307. X   finds one that is at least RIFTDIST squares from any ocean square.  If a
  1308. X   center is found, a random angle is generated; the rift will pass through
  1309. X   the center at that angle.  Next, halfrift() is called twice.  Each call
  1310. X   generates the rift leaving the center in one direction.  If everything
  1311. X   works out, the function returns the id of the plate the rift is on. */
  1312. X
  1313. X   short x, y, lx, rx, ty, by, i, j, tries = 0, which; double t;
  1314. X
  1315. X   /* Generate a random x, y value */
  1316. X   getctr: if (tries > MAXCTRTRY) return (0);
  1317. X   x = rnd (XSIZE); y = rnd (YSIZE);
  1318. X
  1319. X   /* If the location is ocean, try again */
  1320. X   if (!m[src][x][y]) { tries++; goto getctr; }
  1321. X
  1322. X   /* Set lx,rx,ty,by to the coordinate values of a box 2*RIFTDIST on a side */
  1323. X   /* centered on the center.  Clip the values to make sure they are on the */
  1324. X   /* array.  Loop through the box; if a point is ocean, try another center. */
  1325. X   lx = (x < RIFTDIST) ? 0 : x - RIFTDIST;
  1326. X   rx = (x > XSIZE - RIFTDIST - 1) ? XSIZE - 1 : x + RIFTDIST;
  1327. X   ty = (y < RIFTDIST) ? 0 : y - RIFTDIST;
  1328. X   by = (y > YSIZE - RIFTDIST - 1) ? YSIZE - 1 : y + RIFTDIST;
  1329. X   for (i=lx; i<rx; i++) for (j=ty; j<by; j++)
  1330. X      if (!m[src][i][j]) { tries++; goto getctr; }
  1331. X
  1332. X   /* Found a good center, on plate `which'.  Put a rift indicator in the */
  1333. X   /* center.  Generate a random angle t, which is really an integer in the */
  1334. X   /* range 0-499 multiplied by 2 PI / 1000.  Call halfrift once for each */
  1335. X   /* half of the rift; t is the initial angle for the first call, and */
  1336. X   /* t + PI is the initial angle for the second call.  If halfrift() */
  1337. X   /* returns zero, abort and return 0; otherwise, return the plate id. */
  1338. X   which = m[src][x][y]; m[src][x][y] = RIFTMARK;
  1339. X   t = rnd (500) * TWOMILLIPI;
  1340. X   if (!halfrift (src, x, y, which, t)) return (0);
  1341. X   t += PI; if (t > TWOPI) t -= TWOPI;
  1342. X   if (!halfrift (src, x, y, which, t)) return (0);
  1343. X   return ((int) which); }
  1344. X
  1345. X
  1346. halfrift (src, cx, cy, which, t) short src, cx, cy, which; double t; {
  1347. X   /* Draw a rift from cx,cy on plate `which' at angle t.  At the beginning,
  1348. X   digitize the angle using Bresenham's algorithm; once in a while thereafter,
  1349. X   modify the angle randomly and digitize it again.  For each square travelled,
  1350. X   call stoprift() to see if the rift has left the plate. */
  1351. X
  1352. X   short ddx, ddy, rdx, rdy, draw, i, a; double dx, dy, adx, ady;
  1353. X
  1354. X   /* For-loop against SIZE to guard against infinite loops */
  1355. X   for (i=0; i<XSIZE; i++) {
  1356. X
  1357. X      /* If first square or 1/6 chance at each step, digitize */
  1358. X      if (!i || !rnd (BENDEVERY)) {
  1359. X
  1360. X         /* If not first step, modify angle a little */
  1361. X         if (i) t = t + (rnd (BENDBY<<1) * TWOMILLIPI) - (BENDBY * TWOMILLIPI);
  1362. X         if (t > TWOPI) t -= TWOPI; if (t < 0) t += TWOPI;
  1363. X
  1364. X         /* Compute dx and dy, scaled so that larger is exactly +1.0 or -1.0 */
  1365. X         dy = sin (t); dx = cos (t); adx = ABS(dx); ady = ABS(dy);
  1366. X         if (adx > ady) { dy = dy / adx; dx = (dx < 0) ? -1.0: 1.0; }
  1367. X         else { dx = dx / ady; dy = (dy < 0) ? -1.0: 1.0; }
  1368. X
  1369. X         /* Convert to integer value and initialize remainder */
  1370. X         /* for each coordinate to half value */
  1371. X         ddx = REALSCALE * dx; ddy = REALSCALE * dy;
  1372. X         rdx = ddx >> 1; rdy = ddy >> 1; }
  1373. X
  1374. X      /* Main part of loop, draws one square along line.  The basic idea */
  1375. X      /* of Bresenham's algorithm is that if the slope of the line is less */
  1376. X      /* than 45 degrees, each time you step one square in X and maybe step */
  1377. X      /* one square in Y.  If the slope is greater than 45, step one square */
  1378. X      /* in Y and maybe one square in X.  Here, if the slope is less than 45 */
  1379. X      /* then ddx == REALSCALE (or -REALSCALE) and the first call to */
  1380. X      /* stoprift() is guaranteed.  If stoprift returns <0, all is ok; */
  1381. X      /* if zero, the rift ran into the ocean, so stop now; if positive, the */
  1382. X      /*  rift ran into another plate, which is a perverse condition and the */
  1383. X      /* rift must be abandoned.  */
  1384. X      rdx += ddx; rdy += ddy;
  1385. X      if (rdx >=  REALSCALE) { cx++; rdx -= REALSCALE; draw = 1; }
  1386. X      if (rdx <= -REALSCALE) { cx--; rdx += REALSCALE; draw = 1; }
  1387. X      if (draw == 1) {
  1388. X         a = stoprift (src, cx, cy, which); if (a >= 0) return (a == 0); }
  1389. X      if (rdy >=  REALSCALE) { cy++; rdy -= REALSCALE; draw = 2; }
  1390. X      if (rdy <= -REALSCALE) { cy--; rdy += REALSCALE; draw = 2; }
  1391. X      if (draw == 2) {
  1392. X         a = stoprift (src, cx, cy, which); if (a >= 0) return (a == 0); } }
  1393. X   return (1); }
  1394. X
  1395. X
  1396. stoprift (src, x, y, which) short src, x, y, which; {
  1397. X   /* This function is called once for each square the rift enters.  It
  1398. X   puts a rift marker into m[src] and decides whether the rift can go on.
  1399. X   It looks at all four adjacent squares.  If one of them contains ocean
  1400. X   or another plate, return immediately so that the rift stops (if ocean)
  1401. X   or aborts (if another plate).  If none of them do, then return ok. */
  1402. X
  1403. X   register short w, a;
  1404. X
  1405. X   w = which; p[w].area--; m[src][x][y] = RIFTMARK;
  1406. X   a = m[src][x][y+1]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
  1407. X   a = m[src][x][y-1]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
  1408. X   a = m[src][x+1][y]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
  1409. X   a = m[src][x-1][y]; if ((a != w) && (a!= RIFTMARK)) return ((int) a);
  1410. X   return (-1); }
  1411. X
  1412. X
  1413. segment (src, match, frag, reg) short src, match, *frag, *reg; {
  1414. X   /* This routine implements a standard binary-blob segmentation.  It looks
  1415. X   at the array m[src]; match is the value of the blob, and everything else
  1416. X   is background.  The result is placed into array r and vectors kid and karea.
  1417. X   One 8-connected region can be made up of many fragments; each fragment is
  1418. X   assigned a unique index.  Array r contains the frag indices k, while kid[k]
  1419. X   is the region frag k belongs to and karea[k] is the area of frag k.
  1420. X   Variables frag and reg are set on output to the number of fragments and
  1421. X   regions found during the segmentation.  The private vector kk provides one
  1422. X   level of indirection for merging fragments; fragment k is merged with
  1423. X   fragment kk[k] where kk[k] is the smallest frag index in the region. */
  1424. X
  1425. X   register short i, j, k, k1, k2, k3, l;
  1426. X   char kk [MAXFRAG];
  1427. X
  1428. X   /* Initialize all frag areas to zero and every frag to merge with itself */
  1429. X   for (k=0; k<MAXFRAG; k++) { kk[k] = k; karea[k] = 0; }
  1430. X
  1431. X   /* Look at every point in the array */
  1432. X   for (k=0, i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  1433. X      /* If too many fragments, give up */
  1434. X      if (k == MAXFRAG) return (0);
  1435. X
  1436. X      /* If this square isn't part of the blob, try the next square */
  1437. X      if (m[src][i][j] != match) { r[i][j] = 0; goto bottom; }
  1438. X
  1439. X      /* It is part of the blob.  Set k1 to the frag id of the square to */
  1440. X      /* its left, and set k2 to the frag id of the square above it.  Note */
  1441. X      /* that because of the for-loop direction, both of these squares have */
  1442. X      /* already been processed. */
  1443. X      k1 = i ? kk [r [i-1] [j]] : 0; k2 = j ? kk [r [i] [j-1]] : 0;
  1444. X
  1445. X      /* If k1 and k2 are both background, start a new fragment */
  1446. X      if (!k1 && !k2) { r[i][j] = ++k; karea[k]++; goto bottom; }
  1447. X
  1448. X      /* If k1 and k2 are part of the same frag, add this square to it */
  1449. X      if (k1 && (k1 == k2)) { r[i][j] = k1; karea[k1]++; goto bottom; }
  1450. X
  1451. X      /* If k1 and k2 belong to different frags, merge them by finding */
  1452. X      /* all the frags merged with max(k1,k2) and merging them instead */
  1453. X      /* with min(k1,k2).  Add k to that fragment as well. */
  1454. X      if (k1 && k2) {
  1455. X         if (k2 < k1) { k3 = k1; k1 = k2; k2 = k3; }
  1456. X         for (l=1; l<=k; l++) if (kk[l] == k2) kk[l] = k1;
  1457. X         r[i][j] = k1; karea[k1]++; goto bottom; }
  1458. X
  1459. X      /* Default case is that one of k1,k2 is a fragment and the other is */
  1460. X      /* background.  Add k to the fragment. */
  1461. X      k3 = (k1) ? k1 : k2; r[i][j] = k3; karea[k3]++;
  1462. X   bottom: continue; }
  1463. X
  1464. X   /* Set up vector kid to map from fragments to regions by using i to count */
  1465. X   /* unique groups of fragments.  A unique group of fragments is */
  1466. X   /* characterized by kk[k] == k; otherwise, frag k is merged with some */
  1467. X   /* other fragment. */
  1468. X   for (i=0, j=1; j<=k; j++) {
  1469. X      if (j == kk[j]) kid[j] = ++i;
  1470. X      else kid[j] = kid [kk [j]]; }
  1471. X
  1472. X   /* Make sure the id of the background is zero; set up return values */
  1473. X   kid[0] = 0; *frag = k; *reg = i; return (1); }
  1474. X
  1475. X
  1476. X
  1477. newplates (src, old) short src, old; {
  1478. X   /* Compute new dx and dy values for plates right after fragmentation.  This
  1479. X   function looks at the rift markers in m[src]; variable old is the index of
  1480. X   the plate from which the new plates were created.  For each plate adjacent
  1481. X   to the rift, this function subtracts the number of plate squares to the left
  1482. X   of the rift from the number to the right; this gives some indication of
  1483. X   whether the plate should move left or right, and how fast.  The same is done
  1484. X   for squares above and below the rift.  The results are put into dx[] and
  1485. X   dy[].  At this point some unscaled movement vector is available for both of
  1486. X   the new plates.  The vectors are then scaled by the relative sizes of the
  1487. X   plates.  The idea is that if one plate is much larger than the other, the
  1488. X   small one should move faster.  New plate structures are allocated for the
  1489. X   new plates, and the computed dx and dy values are put in them. */
  1490. X
  1491. X   short dx[MAXPLATE], dy[MAXPLATE];
  1492. X   register short i, j, a; short totarea=0, maxmag=0; double scale, b;
  1493. X
  1494. X   for (i=1; i<MAXPLATE; i++) { dx[i] = 0; dy[i] = 0; ids[i] = 0; }
  1495. X
  1496. X   /* For every point in the array, set a to the region id (kid is the */
  1497. X   /* lookup table and r contains frag indices); if a is nonzero and */
  1498. X   /* the rift is adjacent, adjust counters appropriately */
  1499. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) if (a = kid[r[i][j]]) {
  1500. X      if ((i-1 > -1)    && (m[src][i-1][j] == RIFTMARK)) (dx[a])++;
  1501. X      if ((i+1 < XSIZE) && (m[src][i+1][j] == RIFTMARK)) (dx[a])--;
  1502. X      if ((j-1 > -1)    && (m[src][i][j-1] == RIFTMARK)) (dy[a])++;
  1503. X      if ((j+1 < XSIZE) && (m[src][i][j+1] == RIFTMARK)) (dy[a])--; }
  1504. X
  1505. X   /* For those regions larger than splinters (tarea is set up in trysplit), */
  1506. X   /* allocate a new plate structure and initialize its area; compute the */
  1507. X   /* magnitude of the dx dy vector and remember the maximum magnitude; also */
  1508. X   /* record the total area of new regions */
  1509. X   for (i=1; i<MAXPLATE; i++) if (tarea[i] > MAXSPLINTER) {
  1510. X      ids[i] = palloc (); p[ids[i]].area = tarea[i];
  1511. X      totarea += tarea[i];
  1512. X      a =sqrt ((double) ((dx[i]*dx[i]) + (dy[i]*dy[i])));
  1513. X      if (a > maxmag) maxmag = a; }
  1514. X
  1515. X   /* Generate a random speed and predivide so that all speeds computed */
  1516. X   /* below are less than the random speed. */
  1517. X   scale = (double) (rnd (SPEEDRNG) + SPEEDBASE) / (maxmag * totarea);
  1518. X
  1519. X   /* Compute the dx and dy for each new plate; note that the speed the */
  1520. X   /* plate was moving at before splitting is given by p[old].odx,ody */
  1521. X   /* but those must be multiplied by MR to get the actual values */
  1522. X   for (i=1; i<MAXPLATE; i++) if (ids[i]) {
  1523. X      b = scale * (totarea - tarea[i]);
  1524. X      p[ids[i]].odx = p[old].odx * MR [p[old].age] + dx[i] * b;
  1525. X      p[ids[i]].ody = p[old].ody * MR [p[old].age] + dy[i] * b; } }
  1526. END_OF_FILE
  1527. if test 14274 -ne `wc -c <'tec-v3/tec2.c'`; then
  1528.     echo shar: \"'tec-v3/tec2.c'\" unpacked with wrong size!
  1529. fi
  1530. # end of 'tec-v3/tec2.c'
  1531. fi
  1532. echo shar: End of shell archive.
  1533. exit 0
  1534.  
  1535.