home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 13 / 13.iso / p / p024 / 12.img / ADS3.LIB / MOUNTAIN.C < prev    next >
Encoding:
Text File  |  1993-02-17  |  39.0 KB  |  1,243 lines

  1. /* Next available MSG number is  34 */
  2.  
  3. /*    MOUNTAIN.C
  4.       ¬⌐┼v (C) 1990-1992  Autodesk ñ╜Ñq
  5.  
  6.       Ñ╗│n┼ΘºK╢O¿╤▒z╢iªµÑ⌠ª≤Ñ╬│~╗▌¿D¬║½■¿⌐íB¡╫º∩ñ╬╡oªµ, ª²¼O░╚╜╨┐φ┤`ñU¡z
  7.       ¡∞½h :
  8.  
  9.       1)  ñWªC¬║¬⌐┼v│qºi░╚╗▌ÑX▓{ªb¿Cñ@Ñ≈½■¿⌐∙╪íC
  10.       2)  ¼█├÷¬║╗í⌐·ñσÑ≤ñ]Ñ▓╢╖⌐·╕ⁿ¬⌐┼v│qºiñ╬Ñ╗╢╡│\Ñi│qºiíC
  11.  
  12.       Ñ╗│n┼Θ╢╚┤ú¿╤º@¼░└│Ñ╬ñW¬║░╤ª╥, ª╙Ñ╝┴n⌐·⌐╬┴⌠ºtÑ⌠ª≤½O├╥; ╣∩⌐≤Ñ⌠ª≤»S«φ
  13.       Ñ╬│~ñº╛A║┘⌐╩, ÑHñ╬░╙╖~╛P░Γ⌐╥┴⌠ºtÑX¿π¬║½O├╥, ªbª╣ñ@╖ºñ⌐ÑHº_╗{íC
  14.  
  15.  
  16.  
  17.       DESCRIPTION:
  18.  
  19.         Fractal mountain landscape generator
  20.  
  21.         Designed and implemented in November of 1989 by John Walker
  22.  
  23.         This  program generates fractal mountain landscapes by Fourier
  24.         filtering of random data.  The landscapes are  represented  as
  25.         pface  meshes  within  an  AutoCAD  drawing.   To  run the
  26.         program, first load the ADS application with the command:
  27.  
  28.             (xload "mountain")
  29.  
  30.         and enter the command:
  31.  
  32.             MOUNTAIN
  33.  
  34.         You're  asked the to specify the parameters of the mountain as
  35.         follows:
  36.  
  37.             Mesh size (power of 2) <32>:
  38.             Fractal dimension (typically between 1 and 3) <2.15>:
  39.             Power law scaling exponent <1>:
  40.  
  41.         The  mountain  range is  modeled as a square  pface  mesh with
  42.         edge size given by the first prompt.  The mesh size must be  a
  43.         power  of  two (this limitation is imposed by the fast Fourier
  44.         transform algorithm; if you specify a mesh size that's  not  a
  45.         power  of two it will be rounded up to the next larger power).
  46.  
  47.         The  fractal dimension controls the roughness of the generated
  48.         landscape by applying a low-pass spatial filter to the  random
  49.         frequency  domain  data  before performing the inverse Fourier
  50.         transform.  The higher the fractal dimension the  rougher  the
  51.         terrain;  values  between  2  and  3  are typical.  Dimensions
  52.         between 1.7 and  2  generate  Appalachian-type  hills;  values
  53.         between  2 and 2.5 yield Sierra Nevada like peaks; and numbers
  54.         close to 3 result in fantasy landscapes of spires (which  look
  55.         good only at high mesh densities).
  56.  
  57.         The output of the mountain generation algorithm is a table  of
  58.         heights.   Negative  heights  are  set to zero and coloured as
  59.         water.  You can scale elevations above sea  level  by  raising
  60.         the  raw  values to a power specified by the power law scaling
  61.         exponent.  The default value of 1 simply uses  the  elevations
  62.         as generated.  Powers of less than 1 mimic eroded terrain (try
  63.         0.33--cube root scaling often produces  landscapes  that  look
  64.         glacially sculpted like Yosemite).  Powers greater than 1 make
  65.         increasingly forbidding peaks.  Again, if you use large  power
  66.         law  exponents,  the  results  will  look  best at higher mesh
  67.         densities.
  68.  
  69.         Every time  you  enter  the  MOUNTAIN  command  you'll  get  a
  70.         different  landscape.   The random number generator is started
  71.         from the time and date, so a given result will normally  never
  72.         recur.   If  you  use  the  command several times, remember to
  73.         ERASE the previous mesh to keep the new mountains  from  being
  74.         drawn  over  top of the old ones.  If you want to generate the
  75.         same terrain repeatedly (for example, to experiment  with  the
  76.         effects of fractal dimension and power law exponent settings),
  77.         you can set the random sequence used to generate  the  terrain
  78.         with the SEED command.  This command prompts:
  79.  
  80.             Random number seed (0 to reseed) <0xNNNN>:
  81.  
  82.         where  0xNNNN is the current starting seed in hexadecimal.  If
  83.         you enter a nonzero value it is used as the seed by  the  next
  84.         MOUNTAIN  command.   Subsequent commands advance the generator
  85.         and continue  to  generate  different  terrain,  so  you  must
  86.         re-enter  the SEED before each MOUNTAIN command if you want to
  87.         repeat the last output.  The default for the SEED  command  is
  88.         the  last seed entered, so simply entering a blank response to
  89.         the command resets the seed to the last value, making it  easy
  90.         to  repeatedly generate from the same seed.  If a seed of 0 is
  91.         entered, a new random value is generated  from  the  time  and
  92.         date.
  93.  
  94.         The  faces  of  the pface mesh  are  coloured  individually to
  95.         represent their elevation.  The WORLD command  allows  you  to
  96.         choose  between  two  different  colour  schemes.  The command
  97.         prompts you:
  98.  
  99.                 World:  0 = Landscape (8 colours)
  100.                         1 = Landscape (256 colours)
  101.                         2 = Clouds
  102.                 World type <0>:
  103.  
  104.         The default world, 0, colours negative elevations as different
  105.         shades of blue (to indicate "water depth"), and terrain  on  a
  106.         scale  from  green through yellows to white for "snowy peaks".
  107.         World type 1 restricts the palette of colours to  the  default
  108.         AutoCAD  8  colour  set;  the  resulting  pictures  are not as
  109.         attractive but will display properly on systems with 8  colour
  110.         capability   or  above.   World  type  2  selects  colours  to
  111.         illustrate affinity between fractal clouds and mountains.  All
  112.         negative  elevations  in  the  clouds world are coloured blue;
  113.         other faces are assigned shades from dark grey to  white  with
  114.         increasing  elevation.   Pictures  generated  with  the clouds
  115.         colouring are  intended  to  be  viewed  in  plan  view,  from
  116.         directly  above,  and  look  best in shaded renderings at high
  117.         resolution.  Cloud colouring requires a  256  colour  display.
  118.  
  119.         The  mountains are generated on a dark grey (cyan for 8 colour
  120.         landscapes) base, drawn with invisible edges, which serves  to
  121.         obscure the underside of the terrain in hidden line and shaded
  122.         renderings.
  123.  
  124.         The  MOUNTAIN  command  always  generates  a pface  mesh; this
  125.         mesh  can  be  created  either  by  invocation  of  the  PFACE
  126.         command  through  the  ads_command() facility or directly with
  127.         ads_entmake().  The MAKEMODE command lets you specify how  the
  128.         mesh  is  to  be created, allowing you to try both methods and
  129.         compare their relative performance.  You're prompted:
  130.  
  131.                 Mesh generation:  0 = Directly with ads_entmake()
  132.                                   1 = PFACE command via ads_command()
  133.                 Generation type <0>:
  134.  
  135.         Enter  the  generation  mode  you prefer.  Subsequent MOUNTAIN
  136.         commands will  use  the  mode  you  chose.   If  the  mesh  is
  137.         generated with ads_entmake(), extended entity data is attached
  138.         to it that records the  world  type,  fractal  dimension,  and
  139.         power factor used to create the mesh.
  140.  
  141.         References:
  142.  
  143.             Peitgen, H.-O., and Saupe, D. eds., The Science Of Fractal
  144.                 Images, New York: Springer Verlag, 1988.
  145.  
  146.             Press, W. H., Flannery, B. P., Teukolsky, S. A., Vetterling,
  147.                 W. T., Numerical Recipes In C, New Rochelle; Cambridge
  148.                 University Press, 1988.
  149.  
  150. */
  151.  
  152. #include <stdio.h>
  153. #include <math.h>
  154. #include <assert.h>
  155. #include <string.h>
  156. #ifdef UNIX
  157. #include <memory.h>
  158. #endif
  159.  
  160. #include "adslib.h"
  161.  
  162. #define AppName  /*MSG1*/"AUTODESK_FRACTAL_MOUNTAINS"
  163.  
  164. #ifndef M_PI
  165. #define M_PI    3.14159265358979323846
  166. #endif
  167.  
  168. #ifdef __WATCOMC__
  169. #undef max
  170. #undef min
  171. #endif
  172.  
  173. #define max(a,b) ((a) >  (b) ? (a) : (b))
  174. #define min(a,b) ((a) <= (b) ? (a) : (b))
  175.  
  176. /* Definitions used to address real and imaginary parts in a two-dimensional
  177.    array of complex numbers as stored by fourn(). */
  178.  
  179. #define Real(v, x, y)  v[1 + (((x) * n) + (y)) * 2]
  180. #define Imag(v, x, y)  v[2 + (((x) * n) + (y)) * 2]
  181.  
  182. /*  Data types  */
  183.  
  184. typedef enum {False = 0, True = 1} Boolean;
  185.  
  186. /* Definitions  to  wrap  around  submission  of  AutoCAD commands to
  187.    prevent their being echoed.  */
  188.  
  189. #define Cmdecho  False                /* Make True for debug command output */
  190.  
  191. #define CommandB()  { struct resbuf rBc, rBb, rBu, rBh; \
  192.         ads_getvar(/*MSG0*/"CMDECHO", &rBc); \
  193.         ads_getvar(/*MSG0*/"BLIPMODE", &rBb); \
  194.         ads_getvar(/*MSG0*/"HIGHLIGHT", &rBh); \
  195.         rBu.restype = RTSHORT; \
  196.         rBu.resval.rint = (int) Cmdecho; \
  197.         ads_setvar(/*MSG0*/"CMDECHO", &rBu); \
  198.         rBu.resval.rint = (int) False; \
  199.         ads_setvar(/*MSG0*/"BLIPMODE", &rBu); \
  200.         ads_setvar(/*MSG0*/"HIGHLIGHT", &rBu)
  201.  
  202. #define CommandE()  ads_setvar(/*MSG0*/"CMDECHO", &rBc); \
  203.                     ads_setvar(/*MSG0*/"BLIPMODE", &rBb); \
  204.                     ads_setvar(/*MSG0*/"HIGHLIGHT", &rBh); }
  205.  
  206. /*  Definitions  that permit you to push and pop system variables with
  207.     minimal complexity.  These don't work  (and  will  cause  horrible
  208.     crashes  if  used)  with  string  variables,  but since all string
  209.     variables are read-only, they cannot be saved and restored in  any
  210.     case.  */
  211.  
  212. #define PushVar(var, cell, newval, newtype) { struct resbuf cell, cNeW; \
  213.         ads_getvar(var, &cell); cNeW.restype = cell.restype;             \
  214.         cNeW.resval.newtype = newval; ads_setvar(var, &cNeW)
  215.  
  216. #define PopVar(var, cell) ads_setvar(var, &cell); }
  217.  
  218. /* Set point variable from three co-ordinates */
  219.  
  220. #define Spoint(pt, x, y, z)  pt[X] = (x);  pt[Y] = (y);  pt[Z] = (z)
  221.  
  222. /* Copy point from another */
  223.  
  224. #define Cpoint(d, s)   d[X] = s[X];  d[Y] = s[Y];  d[Z] = s[Z]
  225.  
  226. /* Definitions for building result buffer chains. */
  227.  
  228. #define tacky()     struct resbuf *rb, *rbtail, *ri
  229. #define tackrb(t)   ri=ads_newrb(t);  rbtail->rbnext=ri;  rbtail=ri
  230. #define defent(e)   rb=ri=rbtail=ads_newrb(0); ri->resval.rstring = strsave(e)
  231. #define Xed(g)     (1000 + (g))       /* Generate extended entity data code */
  232. #define makent() { int stat=ads_entmake(rb); if (stat!=RTNORM) { \
  233.                    ads_printf(/*MSG2*/"½╪Ñ▀íu%sív╣╧ñ╕┐∙╗~\n", \
  234.                    rb->resval.rstring); } ads_relrb(rb); }
  235. #define tackint(code, val) tackrb(code); ri->resval.rint = (val)
  236. #define tackreal(code, val) tackrb(code); ri->resval.rreal = (val)
  237. #define tackpoint(code, x, y, z) tackrb(code); \
  238.         Spoint(ri->resval.rpoint, (x), (y), (z))
  239. #define tackvec(code, vec) tackrb(code); Cpoint(ri->resval.rpoint, vec)
  240. #define tackstring(code, s) tackrb(code), ri->resval.rstring = strsave(s)
  241.  
  242. #define V  (void)
  243.  
  244. /* Utility definition to get an  array's  element  count  (at  compile
  245.    time).   For  example:
  246.  
  247.        int  arr[] = {1,2,3,4,5};
  248.        ...
  249.        printf("%d", ELEMENTS(arr));
  250.  
  251.    would print a five.  ELEMENTS("abc") can also be used to  tell  how
  252.    many  bytes are in a string constant INCLUDING THE TRAILING NULL. */
  253.  
  254. #define ELEMENTS(array) (sizeof(array)/sizeof((array)[0]))
  255.  
  256. /*  Display parameters  */
  257.  
  258. #define COL_BASE    (wtype == 0 ? 4 : 250) /* Baseplate colour */
  259. #define BASE_THICK  0.1               /* Baseplate thickness */
  260.  
  261. /*  Forward functions  */
  262.  
  263. long    time _((long *));
  264. void    fourn _((float *, int *, int, int));
  265. void    initgauss _((int));
  266. double  gauss _((void));
  267. void    spectralsynth _((float **, int, double));
  268. void    mtn_srand _((unsigned int));
  269. int     mtn_rand _((void));
  270. int     veryrandom _((void));
  271. void    main _((int, char **));
  272. Boolean funcload _((void));
  273. Boolean initacad _((Boolean));
  274. void    initseed _((void));
  275. int     calccol _((float *, int, int, int, ads_real, ads_real));
  276. void    meshcol _((float *, int, int, int, ads_real, ads_real));
  277. void    genmesh _((float *, int, ads_real, ads_real));
  278. char    *strsave _((char *));
  279. void    makevtx _((ads_point));
  280. void    makeface _((int, int, int, int, int));
  281. void    makemesh _((float *, int, ads_real, ads_real));
  282. void    mountain _((void));
  283. void    seed _((void));
  284. void    world _((void));
  285. void    makemode _((void));
  286.  
  287. #ifdef DEBUG
  288. void    test _((void));
  289. #endif
  290.  
  291. /*  Local variables  */
  292.  
  293. static int nrand;                     /* Gauss() sample count */
  294. static double arand, gaussadd, gaussfac; /* Gaussian random parameters */
  295. static int rseed;                     /* Current random seed */
  296. static Boolean seeded = False;        /* Initial seed computed ? */
  297. static Boolean forceseed = False;     /* Force seed on next computation ? */
  298. static int ccolour = -1;              /* Current face colour */
  299. static ads_real fracdim = 2.15;       /* Fractal dimension */
  300. static ads_real powscale = 1.0;       /* Elevation power factor */
  301. static int wtype = 0;                 /* World type */
  302. static Boolean entmake = True;        /* Use ads_entmake() to create mesh ? */
  303.  
  304. static Boolean functional;            /* C:command is returning result */
  305.  
  306. /* The following variables are used by the psuedo-random sequence generator
  307.    veryrandom() and must be unsigned so the right shift works properly */
  308.  
  309. static unsigned long regA = 1;
  310. static unsigned long regB = 1;
  311. static unsigned long regC = 1;
  312.  
  313. /*  Command definition and dispatch table.  */
  314.  
  315. struct {
  316.         char *cmdname;
  317.         void (*cmdfunc)();
  318. } cmdtab[] = {
  319. /*        Name         Function  */
  320. #ifdef DEBUG
  321. {/*MSG3*/"TEST",       test},
  322. #endif
  323. {/*MSG4*/"MAKEMODE",   makemode},
  324. {/*MSG5*/"MOUNTAIN",   mountain},
  325. {/*MSG6*/"SEED",       seed},
  326. {/*MSG7*/"WORLD",      world}
  327. };
  328.  
  329. /*      FOURN  --  Multi-dimensional fast Fourier transform
  330.  
  331.         Called with arguments:
  332.  
  333.            data       A  one-dimensional  array  of  floats  (NOTE!!!   NOT
  334.                       DOUBLES!!), indexed from one (NOTE!!!   NOT  ZERO!!),
  335.                       containing  pairs of numbers representing the complex
  336.                       valued samples.  The Fourier transformed results  are
  337.                       returned in the same array.
  338.  
  339.            nn         An  array specifying the edge size in each dimension.
  340.                       THIS ARRAY IS INDEXED FROM  ONE,  AND  ALL  THE  EDGE
  341.                       SIZES MUST BE POWERS OF TWO!!!
  342.  
  343.            ndim       Number of dimensions of FFT to perform.  Set to 2 for
  344.                       two dimensional FFT.
  345.  
  346.            isign      If 1, a Fourier transform is done, if -1 the  inverse
  347.                       transformation is performed.
  348.  
  349.         This  function  is essentially as given in Press et al., "Numerical
  350.         Recipes In C", Section 12.11, pp.  467-470.
  351. */
  352.  
  353. static void fourn(data, nn, ndim, isign)
  354.   float data[];
  355.   int nn[], ndim, isign;
  356. {
  357.     register int i1, i2, i3;
  358.     int i2rev, i3rev, ip1, ip2, ip3, ifp1, ifp2;
  359.     int ibit, idim, k1, k2, n, nprev, nrem, ntot;
  360.     float tempi, tempr;
  361.     double theta, wi, wpi, wpr, wr, wtemp;
  362.  
  363. #define SWAP(a,b) tempr=(a); (a) = (b); (b) = tempr
  364.  
  365.     ntot = 1;
  366.     for (idim = 1; idim <= ndim; idim++)
  367.         ntot *= nn[idim];
  368.     nprev = 1;
  369.     for (idim = ndim; idim >= 1; idim--) {
  370.         n = nn[idim];
  371.         nrem = ntot / (n * nprev);
  372.         ip1 = nprev << 1;
  373.         ip2 = ip1 * n;
  374.         ip3 = ip2 * nrem;
  375.         i2rev = 1;
  376.         for (i2 = 1; i2 <= ip2; i2 += ip1) {
  377.             if (i2 < i2rev) {
  378.                 for (i1 = i2; i1 <= i2 + ip1 - 2; i1 += 2) {
  379.                     for (i3 = i1; i3 <= ip3; i3 += ip2) {
  380.                         i3rev = i2rev + i3 - i2;
  381.                         SWAP(data[i3], data[i3rev]);
  382.                         SWAP(data[i3 + 1], data[i3rev + 1]);
  383.                     }
  384.                 }
  385.             }
  386.             ibit = ip2 >> 1;
  387.             while (ibit >= ip1 && i2rev > ibit) {
  388.                 i2rev -= ibit;
  389.                 ibit >>= 1;
  390.             }
  391.             i2rev += ibit;
  392.         }
  393.         ifp1 = ip1;
  394.         while (ifp1 < ip2) {
  395.             ifp2 = ifp1 << 1;
  396.             theta = isign * 6.28318530717959 / (ifp2 / ip1);
  397.             wtemp = sin(0.5 * theta);
  398.             wpr = -2.0 * wtemp * wtemp;
  399.             wpi = sin(theta);
  400.             wr = 1.0;
  401.             wi = 0.0;
  402.             for (i3 = 1; i3 <= ifp1; i3 += ip1) {
  403.                 for (i1 = i3; i1 <= i3 + ip1 - 2; i1 += 2) {
  404.                     for (i2 = i1; i2 <= ip3; i2 += ifp2) {
  405.                         k1 = i2;
  406.                         k2 = k1 + ifp1;
  407.                         tempr = wr * data[k2] - wi * data[k2 + 1];
  408.                         tempi = wr * data[k2 + 1] + wi * data[k2];
  409.                         data[k2] = data[k1] - tempr;
  410.                         data[k2 + 1] = data[k1 + 1] - tempi;
  411.                         data[k1] += tempr;
  412.                         data[k1 + 1] += tempi;
  413.                     }
  414.                 }
  415.                 wr = (wtemp = wr) * wpr - wi * wpi + wr;
  416.                 wi = wi * wpr + wtemp * wpi + wi;
  417.             }
  418.             ifp1 = ifp2;
  419.         }
  420.         nprev *= n;
  421.     }
  422. }
  423. #undef SWAP
  424.  
  425. /*  INITGAUSS  --  Initialise random number generators.  */
  426.  
  427. static void initgauss(seed)
  428.   int seed;
  429. {
  430.     nrand = 4;
  431.     arand = pow(2.0, (sizeof(int) * 8) - 1.0) - 1.0;
  432.     gaussadd = sqrt(3.0 * nrand);
  433.     gaussfac = 2 * gaussadd / (nrand * arand);
  434.     V mtn_srand(seed);
  435. }
  436.  
  437. /*  GAUSS  --  Return a Gaussian random number.  */
  438.  
  439. static double gauss()
  440. {
  441.     int i;
  442.     double sum = 0.0;
  443.  
  444.     for (i = 1; i <= nrand; i++) {
  445.         sum += mtn_rand();
  446.     }
  447.     return gaussfac * sum - gaussadd;
  448. }
  449.  
  450. /*  SPECTRALSYNTH  --  Spectrally synthesised fractal motion in two
  451.                        dimensions.  */
  452.  
  453. static void spectralsynth(x, n, h)
  454.   float **x;
  455.   int n;
  456.   double h;
  457. {
  458.     int i, j, i0, j0, nsize[3];
  459.     double rad, phase;
  460.     float *a;
  461.  
  462.     a = (float *) malloc((unsigned) (i =
  463.                                      (((n * n) + 1) * 2 * sizeof(float))));
  464.     if (a == NULL) {
  465.         V fprintf(stderr,
  466.                   /*MSG8*/"╡L¬k░t╕míu%d x %dív¬║íu╡▓¬G»x░}ív(%d bytes)íC\n",
  467.                   n, n, i);
  468.         exit(1);
  469.     }
  470.     *x = a;
  471.     V memset((char *) a, 0, i);       /* Clear array to zeroes */
  472.  
  473.     for (i = 0; i <= n / 2; i++) {
  474.         for (j = 0; j <= n / 2; j++) {
  475.             phase = 2 * M_PI * (mtn_rand() / arand);
  476.             if (i != 0 || j != 0) {
  477.                 rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
  478.             } else {
  479.                 rad = 0;
  480.             }
  481.             Real(a, i, j) = rad * cos(phase);
  482.             Imag(a, i, j) = rad * sin(phase);
  483.             i0 = (i == 0) ? 0 : n - i;
  484.             j0 = (j == 0) ? 0 : n - j;
  485.             Real(a, i0, j0) = rad * cos(phase);
  486.             Imag(a, i0, j0) = - rad * sin(phase);
  487.         }
  488.     }
  489.     Imag(a, n / 2, 0) = Imag(a, 0, n / 2) = Imag(a, n / 2, n / 2) = 0;
  490.     for (i = 1; i <= n / 2 - 1; i++) {
  491.         for (j = 1; j <= n / 2 - 1; j++) {
  492.             phase = 2 * M_PI * (mtn_rand() / arand);
  493.             rad = pow((double) (i * i + j * j), -(h + 1) / 2) * gauss();
  494.             Real(a, i, n - j) = rad * cos(phase);
  495.             Imag(a, i, n - j) = rad * sin(phase);
  496.             Real(a, n - i, j) = rad * cos(phase);
  497.             Imag(a, n - i, j) = - rad * sin(phase);
  498.         }
  499.     }
  500.  
  501.     nsize[0] = 0;
  502.     nsize[1] = nsize[2] = n;          /* Dimension of frequency domain array */
  503.     fourn(a, nsize, 2, -1);           /* Take inverse 2D Fourier transform */
  504. }
  505.  
  506. /*  MTN_SRAND  --  Seed the psuedo-random number generator.  */
  507.  
  508. static void
  509. /*FCN*/mtn_srand(seed)
  510.     unsigned int seed;
  511. {
  512.     regA = regB = regC = seed;
  513. }
  514.  
  515. /*  MTN_RAND  --  The psuedo-random number generator.  */
  516.  
  517. static int
  518. /*FCN*/mtn_rand()
  519. {
  520.     int i;
  521.     int rnum = 0;
  522.  
  523.     for (i=0; i < sizeof(int)*8; i++) {
  524.         rnum |= veryrandom();
  525.         rnum <<= 1;
  526.     }
  527.     return rnum;
  528. }
  529.  
  530. /*  VERYRANDOM  --  Psuedo-Random Sequence Generator for 32-Bit CPUs,
  531.                     by Bruce Schneier, Dr. Dobb's Journal, February 1992 */
  532.  
  533. static int
  534. /*FCN*/veryrandom()
  535. {
  536.     /* regA is a 32-bit Linear Feedback Shift Register (LFSR) */
  537.     /* regB is a 31-bit LFSR.  regC is a 29-bit LFSR. */
  538.     /* The feedback sequences are chosen to be maximum length. */
  539.     regA = ((((regA>>31)^(regA>>6)^(regA>>4)^(regA>>2)^(regA>>1)^regA)
  540.         & 0x00000001)<<31) | (regA>>1);
  541.     regB = ((((regB>>30)^(regB>>2)) & 0x00000001)<<30) | (regB>>1);
  542.     regC = ((((regC>>28)^(regC>>1)) & 0x00000001)<<28) | (regC>>1);
  543.     return ((regA & regB) | (!regA & regC)) & 0x00000001;
  544. }
  545.  
  546. /*  MAIN  --   Main ADS transaction processor.  */
  547.  
  548. void main(argc, argv)
  549.   int argc;
  550.   char *argv[];
  551. {
  552.     int stat, cindex, scode = RSRSLT;
  553.  
  554.     ads_init(argc, argv);             /* Initialise the application */
  555.  
  556.     /* Main dispatch loop. */
  557.  
  558.     while (True) {
  559.  
  560.         if ((stat = ads_link(scode)) < 0) {
  561.             V printf(/*MSG9*/"Ñ╤ ads_link() ╢╟ª^¬║ñú¿╬¬¼║A = %d\n", stat);
  562.             exit(1);
  563.         }
  564.  
  565.         scode = RSRSLT;               /* Default return code */
  566.  
  567.         switch (stat) {
  568.  
  569.         case RQXLOAD:                 /* Load functions.  Called at the start
  570.                                          of the drawing editor.  Re-initialise
  571.                                          the application here. */
  572.             scode = -(funcload() ? RSRSLT : RSERR);
  573.             break;
  574.  
  575.         case RQSUBR:                  /* Evaluate external lisp function */
  576.             cindex = ads_getfuncode();
  577.             functional = False;
  578.             if (!initacad(False)) {
  579.                 ads_printf(/*MSG10*/"\n╡L¬k▒╥⌐líu└│Ñ╬╡{ªíívíC\n");
  580.             } else {
  581.  
  582.                 /* Execute the command from the command table with
  583.                    the index associated with this function. */
  584.  
  585.                 if (cindex > 0) {
  586.                     cindex--;
  587.                     assert(cindex < ELEMENTS(cmdtab));
  588.                     (*cmdtab[cindex].cmdfunc)();
  589.                 }
  590.             }
  591.             if (!functional)
  592.                 ads_retvoid();        /* Void result */
  593.             break;
  594.  
  595.         default:
  596.             break;
  597.         }
  598.     }
  599. }
  600.  
  601. /* FUNCLOAD  --  Load external functions into AutoLISP */
  602.  
  603. static Boolean funcload()
  604. {
  605.     char ccbuf[40];
  606.     int i;
  607.  
  608.     V strcpy(ccbuf, /*MSG0*/"C:");
  609.     for (i = 0; i < ELEMENTS(cmdtab); i++) {
  610.         V strcpy(ccbuf + 2, cmdtab[i].cmdname);
  611.         ads_defun(ccbuf, i + 1);
  612.     }
  613.  
  614.     return initacad(True);            /* Reset AutoCAD initialisation */
  615. }
  616.  
  617. /*  INITACAD  --  Initialise the required modes in the AutoCAD
  618.                   drawing.  */
  619.  
  620. static Boolean initacad(reset)
  621.   Boolean reset;
  622. {
  623.     static Boolean initdone, initok;
  624.  
  625.     if (reset) {
  626.         initdone = False;
  627.         initok = True;
  628.     } else {
  629.         if (!initdone) {
  630.             struct resbuf *rp;
  631.             static char aname[] = AppName;  /* Static to keep compiler from
  632.                                                making making one copy of
  633.                                                constant string for every
  634.                                                reference below. */
  635.  
  636.             /* First of all, see if our application is registered
  637.                and register it if not. */
  638.  
  639.             if ((rp = ads_tblsearch(/*MSG0*/"APPID", aname, False)) == NULL) {
  640.                 if (ads_regapp(aname) != RTNORM) {
  641.                     ads_printf(/*MSG11*/"╡L¬k╡n░Oíu└│Ñ╬├■╢╡ív: %síC\n",
  642.                                aname);
  643.                     initdone = True;
  644.                     return (initok = False);
  645.                 }
  646.             } else {
  647.                 ads_relrb(rp);
  648.             }
  649.  
  650.             /* Reset the program modes to standard values upon
  651.                entry to the drawing editor. */
  652.  
  653.             initdone = initok = True;
  654.  
  655.             seeded = False;           /* No seed specified */
  656.             forceseed = False;        /* No seed stuck in its throat */
  657.             fracdim = 2.15;           /* Fractal dimension */
  658.             powscale = 1.0;           /* Elevation power factor */
  659.             wtype = 0;                /* World type */
  660.             entmake = True;           /* Use ads_entmake to create meshes */
  661.         }
  662.     }
  663.     return initok;
  664. }
  665.  
  666. #ifdef DEBUG
  667. /*  TEST  --  Verify that command invocation works.  */
  668.  
  669. static void test()
  670. {
  671.     ads_printf(/*MSG12*/"\níuTESTív½ⁿÑO!\n");
  672. #ifdef DEBUGDUMP
  673.     {   ads_name en;
  674.         struct resbuf *rb, *ri;
  675.  
  676.         ads_entnext(NULL, en);
  677.         rb = ri = ads_entget(en);
  678.  
  679.         while (ri != NULL) {
  680.             ads_printf(/*MSG13*/"┴ΣñJ %d\n", ri->restype);
  681.             ri = ri->rbnext;
  682.         }
  683.         ads_relrb(rb);
  684.     }
  685. #else
  686.     sleep(30);                        /* Delay to let debugger snag us */
  687. #endif
  688. }
  689. #endif
  690.  
  691. /*  INITSEED  --  Generate initial random seed, if needed.  */
  692.  
  693. static void initseed()
  694. {
  695.     if (!seeded) {
  696.         int i;
  697.  
  698.         V mtn_srand(((int) (time((long *) NULL) ^ 0x5B3CF37C) & ((int) ~0)));
  699.         for (i = 0; i < 7; i++)
  700.             V mtn_rand();
  701.         rseed = mtn_rand();
  702.         seeded = forceseed = True;
  703.     }
  704. }
  705.  
  706. /*  CALCCOL  --  Calculate colour of mesh item from its relative
  707.                  elevation.  */
  708.  
  709. static int calccol(a, n, x, y, rmax, rmin)
  710.   float *a;
  711.   int n, x, y;
  712.   ads_real rmax, rmin;
  713. {
  714.     ads_real h1 = Real(a, x, y),
  715.              h2 = Real(a, x + 1, y),
  716.              h3 = Real(a, x, y + 1),
  717.              h4 = Real(a, x + 1, y + 1),
  718.              h;
  719.     int rcol;
  720.  
  721.     static struct {
  722.        ads_real cthresh;
  723.        int tcolour;
  724.     } ctab[] = {
  725.        {0.25, 80},
  726.        {0.6, 90},
  727.        {0.75, 50},
  728.        {0.80, 40},
  729.        {0.90, 131},
  730.        {1.00, 255}
  731.       },
  732.       etab[] = {
  733.        {0.50, 3},
  734.        {0.60, 2},
  735.        {0.80, 1},
  736.        {0.90, 6},
  737.        {1.00, 7}
  738.       },
  739.       clouds[] = {
  740.        {0.1666, 250},
  741.        {0.3333, 251},
  742.        {0.5000, 252},
  743.        {0.6666, 253},
  744.        {0.8333, 254},
  745.        {1.0000, 255}
  746.       };
  747.  
  748.     h = max(h1, max(h2, max(h3, h4)));
  749.     if (h <= 0) {
  750.         int ih;
  751.  
  752.         if (wtype == 0 || wtype == 2) {
  753.             rcol = 5;                 /* Flat blue */
  754.         } else {
  755.             h = (h1 + h2 + h3 + h4) / 4;
  756.             if (rmin == 0)
  757.                 rmin = 1;
  758.             h = h / rmin;
  759.             ih = (h * 3) + 0.5;
  760.             rcol = 140 + min(3, ih) * 10;
  761.         }
  762.     } else {
  763.         int i;
  764.  
  765.         if (rmax == 0)
  766.             rmax = 1;
  767.         h = h / rmax;
  768.         if (wtype == 0) {
  769.             for (i = 0; i < ELEMENTS(etab); i++) {
  770.                 if (h <= etab[i].cthresh)
  771.                     break;
  772.             }
  773.             assert(i < ELEMENTS(etab));
  774.             rcol = etab[i].tcolour;
  775.         } else if (wtype == 2) {
  776.             for (i = 0; i < ELEMENTS(clouds); i++) {
  777.                 if (h <= clouds[i].cthresh)
  778.                     break;
  779.             }
  780.             assert(i < ELEMENTS(clouds));
  781.             rcol = clouds[i].tcolour;
  782.         } else {
  783.             for (i = 0; i < ELEMENTS(ctab); i++) {
  784.                 if (h <= ctab[i].cthresh)
  785.                     break;
  786.             }
  787.             assert(i < ELEMENTS(ctab));
  788.             rcol = ctab[i].tcolour;
  789.         }
  790.     }
  791.     return rcol;
  792. }
  793.  
  794.  
  795. /*  MESHCOL  --  Set colour of mesh item from its relative elevation.  */
  796.  
  797. static void meshcol(a, n, x, y, rmax, rmin)
  798.   float *a;
  799.   int n, x, y;
  800.   ads_real rmax, rmin;
  801. {
  802.     int rcol = calccol(a, n, x, y, rmax, rmin);
  803.  
  804.     if (ccolour != rcol) {
  805.         ccolour = rcol;
  806.         ads_command(RTSTR, /*MSG31*/"Colour", RTSHORT, ccolour, RTNONE);
  807.     }
  808. }
  809.  
  810. /*  GENMESH  --  Generate mesh from elevation array.  This version
  811.                  creates the mesh by submitting a PFACE command
  812.                  with the ads_command function.  */
  813.  
  814. static void genmesh(a, n, rmax, rmin)
  815.   float *a;
  816.   int n;
  817.   ads_real rmax, rmin;
  818. {
  819.     int i, j;
  820.  
  821.     CommandB();
  822.     ads_command(RTSTR, /*MSG32*/"Pface", RTNONE);
  823.  
  824.     /* Send the vertex table. */
  825.  
  826.     for (i = 0; i < n; i++) {
  827.         for (j = 0; j < n; j++) {
  828.             ads_point p;
  829.  
  830.             Spoint(p, i, j,
  831.                    BASE_THICK + (n / (rmax * 2)) * max(0, Real(a, i, j)));
  832.             ads_command(RT3DPOINT, p, RTNONE);
  833.         }
  834.     }
  835.  
  836.     /* Send the baseplate vertices.  We compute and store the
  837.        four edges of the baseplate, addressed by edge number from
  838.        0 to 3 and vertex number along the edge. */
  839.  
  840.     for (i = 0; i < n; i++) {
  841.         ads_point p1, p2, p3, p4;
  842.  
  843.         Spoint(p1, i, 0, 0);
  844.         Spoint(p2, i, n - 1, 0);
  845.         Spoint(p3, 0, i, 0);
  846.         Spoint(p4, n - 1, i, 0);
  847.         ads_command(RT3DPOINT, p1, RT3DPOINT, p2,
  848.                     RT3DPOINT, p3, RT3DPOINT, p4, RTNONE);
  849.     }
  850.  
  851.     ads_command(RTSTR, "", RTNONE);
  852.  
  853.     /* Send the mesh tiles. */
  854.  
  855.     ccolour = -1;
  856. #define Vtx(x, y) ((((x) * n) + (y)) + 1)     /* Address mesh vertex */
  857. #define Bpx(e, x) (((n * n) + 1) + (((x) * 4) + (e)))
  858.     for (i = 0; i < (n - 1); i++) {
  859.         for (j = 0; j < (n - 1); j++) {
  860.             meshcol(a, n, i, j, rmax, rmin);
  861.             ads_command(RTSHORT, Vtx(i, j),
  862.                         RTSHORT, Vtx(i, j + 1) * (j == n - 2 ? 1 : -1),
  863.                         RTSHORT, Vtx(i + 1, j + 1) * (i == n - 2 ? 1 : -1),
  864.                         RTSHORT, Vtx(i + 1, j),
  865.                         RTSTR, "", RTNONE);
  866.         }
  867.     }
  868.  
  869.  
  870.     /* Draw the baseplate */
  871.  
  872.     ads_command(RTSTR, /*MSG33*/"Colour", RTSHORT, COL_BASE, RTNONE);
  873.     ads_command(RTSHORT, -Bpx(0, 0), RTSHORT, -Bpx(1, 0),
  874.                 RTSHORT, -Bpx(1, n - 1), RTSHORT, -Bpx(0, n - 1),
  875.                 RTSTR, "", RTNONE);
  876.  
  877.     /* Build the "walls" that connect the baseplate to the edges
  878.        of the model. */
  879.  
  880.     for (i = 0; i < n - 1; i++) {
  881.         ads_command(RTSHORT, -Bpx(0, i),
  882.                     RTSHORT, -Vtx(i, 0),
  883.                     RTSHORT, -Vtx(i + 1, 0),
  884.                     RTSHORT, -Bpx(0, i + 1),
  885.                     RTSTR, "",
  886.  
  887.                     RTSHORT, -Bpx(1, i),
  888.                     RTSHORT, -Vtx(i, n - 1),
  889.                     RTSHORT, -Vtx(i + 1, n - 1),
  890.                     RTSHORT, -Bpx(1, i + 1),
  891.                     RTSTR, "",
  892.  
  893.                     RTSHORT, -Bpx(2, i),
  894.                     RTSHORT, -Vtx(0, i),
  895.                     RTSHORT, -Vtx(0, i + 1),
  896.                     RTSHORT, -Bpx(2, i + 1),
  897.                     RTSTR, "",
  898.  
  899.                     RTSHORT, -Bpx(3, i),
  900.                     RTSHORT, -Vtx(n - 1, i),
  901.                     RTSHORT, -Vtx(n - 1, i + 1),
  902.                     RTSHORT, -Bpx(3, i + 1),
  903.                     RTSTR, "", RTNONE);
  904.     }
  905.  
  906. #undef Vtx
  907. #undef Bpx
  908.     ads_command(RTSTR, "", RTNONE);
  909.     CommandE();
  910. }
  911.  
  912. /*  STRSAVE  --  Allocate a duplicate of a string.  */
  913.  
  914. static char *strsave(s)
  915.   char *s;
  916. {
  917.     char *c = malloc((unsigned) (strlen(s) + 1));
  918.  
  919.     if (c == NULL)
  920.         ads_abort(/*MSG15*/"╢WÑX░O╛╨«e╢q");
  921.     V strcpy(c, s);
  922.     return c;
  923. }
  924.  
  925. /*  MAKEVTX  --  Append vertex entity to the database. */
  926.  
  927. static void makevtx(p)
  928.   ads_point p;
  929. {
  930.     tacky();
  931.  
  932.     defent(/*MSG0*/"VERTEX");
  933.     tackvec(10, p);                   /* Vertex point */
  934.     tackint(70, 128 + 64);            /* Flags = Pface vertex point */
  935.     makent();
  936. }
  937.  
  938. /*  MAKEFACE  --  Append vertex entity representing a face in the mesh. */
  939.  
  940. static void makeface(colour, p1, p2, p3, p4)
  941.   int colour, p1, p2, p3, p4;
  942. {
  943.     tacky();
  944.  
  945.     defent(/*MSG0*/"VERTEX");
  946.     tackpoint(10, 0, 0, 0);           /* Vertex point */
  947.     tackint(62, colour);              /* Face colour */
  948.     tackint(70, 128);                 /* Vertex flags = Pface mesh face */
  949.     tackint(71, p1);                  /* Vertex 1 */
  950.     tackint(72, p2);                  /* Vertex 2 */
  951.     tackint(73, p3);                  /* Vertex 3 */
  952.     tackint(74, p4);                  /* Vertex 4 */
  953.     makent();
  954. }
  955.  
  956. /*  MAKEMESH  --  Create the mesh using the ads_entmake mechanism.  */
  957.  
  958. static void makemesh(a, n, rmax, rmin)
  959.   float *a;
  960.   int n;
  961.   ads_real rmax, rmin;
  962. {
  963.     int i, j;
  964.     tacky();
  965.  
  966.     defent(/*MSG0*/"POLYLINE");
  967.     tackint(66, 1);                   /* Complex entity flag */
  968.     tackint(70, 64);                  /* Polyline type flags: pface mesh */
  969.     tackint(71, n * n + 4 * n);       /* Vertex count = Mesh plus
  970.                                                         baseplate edges */
  971.     /*      Total faces = n^2 +                   mesh tiles
  972.                                 1 +               baseplate
  973.                                     4 * (n - 1)   wall tiles. */
  974.     tackint(72, n * n + 1 + 4 * (n - 1));
  975.  
  976.     /* Tack on extended entity data that records the generation
  977.        parameters of the mesh. */
  978.  
  979.     tackrb(-3);                       /* Emplace start of application data */
  980.  
  981.     tackstring(Xed(1), AppName);      /* Application name */
  982.     tackint(Xed(70), wtype);          /* World type */
  983.     tackreal(Xed(40), fracdim);       /* Fractal dimension */
  984.     tackreal(Xed(40), powscale);      /* Elevation power factor */
  985.     makent();
  986.  
  987.     /* Send the vertex table. */
  988.  
  989.     for (i = 0; i < n; i++) {
  990.         for (j = 0; j < n; j++) {
  991.             ads_point p;
  992.  
  993.             Spoint(p, i, j,
  994.                    BASE_THICK + (n / (rmax * 2)) * max(0, Real(a, i, j)));
  995.  
  996.             makevtx(p);
  997.         }
  998.     }
  999.  
  1000.     /* Send the baseplate vertices.  We compute and store the
  1001.        four edges of the baseplate, addressed by edge number from
  1002.        0 to 3 and vertex number along the edge. */
  1003.  
  1004.     for (i = 0; i < n; i++) {
  1005.         ads_point p;
  1006.  
  1007.         Spoint(p, i, 0, 0);
  1008.         makevtx(p);
  1009.         Spoint(p, i, n - 1, 0);
  1010.         makevtx(p);
  1011.         Spoint(p, 0, i, 0);
  1012.         makevtx(p);
  1013.         Spoint(p, n - 1, i, 0);
  1014.         makevtx(p);
  1015.     }
  1016.  
  1017.     /* Send the mesh tiles. */
  1018.  
  1019. #define Vtx(x, y) ((((x) * n) + (y)) + 1)     /* Address mesh vertex */
  1020. #define Bpx(e, x) (((n * n) + 1) + (((x) * 4) + (e)))
  1021.     for (i = 0; i < (n - 1); i++) {
  1022.         for (j = 0; j < (n - 1); j++) {
  1023.             makeface(calccol(a, n, i, j, rmax, rmin),
  1024.                      Vtx(i, j),
  1025.                      Vtx(i, j + 1) * (j == n - 2 ? 1 : -1),
  1026.                      Vtx(i + 1, j + 1) * (i == n - 2 ? 1 : -1),
  1027.                      Vtx(i + 1, j));
  1028.         }
  1029.     }
  1030.  
  1031.     /* Draw the baseplate */
  1032.  
  1033.     makeface(COL_BASE,  -Bpx(0, 0), -Bpx(1, 0),
  1034.              -Bpx(1, n - 1), -Bpx(0, n - 1));
  1035.  
  1036.     /* Build the "walls" that connect the baseplate to the edges
  1037.        of the model. */
  1038.  
  1039.     for (i = 0; i < n - 1; i++) {
  1040.         makeface(COL_BASE,
  1041.                  -Bpx(0, i),
  1042.                  -Vtx(i, 0),
  1043.                  -Vtx(i + 1, 0),
  1044.                  -Bpx(0, i + 1));
  1045.  
  1046.         makeface(COL_BASE,
  1047.                  -Bpx(1, i),
  1048.                  -Vtx(i, n - 1),
  1049.                  -Vtx(i + 1, n - 1),
  1050.                  -Bpx(1, i + 1));
  1051.  
  1052.         makeface(COL_BASE,
  1053.                  -Bpx(2, i),
  1054.                  -Vtx(0, i),
  1055.                  -Vtx(0, i + 1),
  1056.                  -Bpx(2, i + 1));
  1057.  
  1058.         makeface(COL_BASE,
  1059.                  -Bpx(3, i),
  1060.                  -Vtx(n - 1, i),
  1061.                  -Vtx(n - 1, i + 1),
  1062.                  -Bpx(3, i + 1));
  1063.     }
  1064. #undef Vtx
  1065. #undef Bpx
  1066.  
  1067.     /* Finally, tack on the SEQEND entity that triggers generation
  1068.        of the whole shebang. */
  1069.  
  1070.     defent(/*MSG0*/"SEQEND");
  1071.     makent();
  1072. }
  1073.  
  1074. #undef defent
  1075. #undef tackrb
  1076.  
  1077. /*  MOUNTAIN  --  Make a mountain.  */
  1078.  
  1079. static void mountain()
  1080. {
  1081.     float *a;
  1082.     int i, j, uds;
  1083.     static int n = 32;
  1084.     char tbuf[80];
  1085.     ads_real rmin = 1e50, rmax = -1e50;
  1086.  
  1087.     ads_initget(2 + 4, NULL);
  1088.     V sprintf(tbuf, /*MSG16*/"\n║⌠¡▒╝╞╢q (2 ¬║¡╝╛¡) <%d>: ", n);
  1089.     uds = ads_getint(tbuf, &n);
  1090.     if (uds == RTCAN)
  1091.         return;
  1092.     else if (uds != RTNONE) {
  1093.         if (n > 1)
  1094.             for (uds = n; (uds & 1) == 0; uds >>= 1) ;
  1095.         else
  1096.             n = 2;
  1097.         if (uds != 1) {
  1098.             for (uds = 2; uds < n; uds <<= 1) ;
  1099.             n = uds;
  1100.         }
  1101.     }
  1102.  
  1103.     while (True) {
  1104.         int uds;
  1105.  
  1106.         ads_initget(2 + 4, NULL);
  1107.         V sprintf(tbuf, /*MSG17*/"\n\
  1108. Fractal dimension (│q▒`ñ╢⌐≤ 1 í╨ 3) <%g>: ",
  1109.                   fracdim);
  1110.         uds = ads_getreal(tbuf, &fracdim);
  1111.         if (uds == RTCAN)
  1112.             return;
  1113.         else if (uds == RTNONE)
  1114.             break;
  1115.         if (fracdim >= 0.0 && fracdim <= 4.0) {
  1116.             break;
  1117.         }
  1118.         ads_printf(/*MSG18*/"▓╩▓ñ½╫ (Fractal dimension, │q▒`½Yñ╢⌐≤ 0í╨4)\n");
  1119.     }
  1120.  
  1121.     ads_initget(2, NULL);
  1122.     V sprintf(tbuf, /*MSG19*/"\n¡╝╛¡⌐w½híuº╬╢╒½ⁿ╝╞ív<%g>: ", powscale);
  1123.     uds = ads_getreal(tbuf, &powscale);
  1124.     if (uds == RTCAN)
  1125.         return;
  1126.  
  1127.     initseed();
  1128.     if (forceseed) {
  1129.         initgauss(rseed);
  1130.         forceseed = False;
  1131.     }
  1132.  
  1133.     spectralsynth(&a, n, 3.0 - fracdim);
  1134.  
  1135.     /* Apply power law scaling if non-unity scale is requested. */
  1136.  
  1137.     if (powscale != 1.0) {
  1138.         for (i = 0; i < n; i++) {
  1139.             for (j = 0; j < n; j++) {
  1140.                 if (Real(a, i, j) > 0) {
  1141.                     Real(a, i, j) = pow((double) Real(a, i, j), powscale);
  1142.                 }
  1143.             }
  1144.         }
  1145.     }
  1146.  
  1147.     /* Compute extrema for autoscaling. */
  1148.  
  1149.     for (i = 0; i < n; i++) {
  1150.         for (j = 0; j < n; j++) {
  1151.             rmin = min(rmin, Real(a, i, j));
  1152.             rmax = max(rmax, Real(a, i, j));
  1153.         }
  1154.     }
  1155.  
  1156.     if (entmake)
  1157.         makemesh(a, n, rmax, rmin);
  1158.     else
  1159.         genmesh(a, n, rmax, rmin);
  1160.  
  1161.     free((char *) a);
  1162. }
  1163.  
  1164. /*  SEED  --  Set seed for random numbers.  */
  1165.  
  1166. static void seed()
  1167. {
  1168.     int uds;
  1169.     char tbuf[80], ibuf[134];
  1170.  
  1171.     initseed();
  1172.  
  1173.     V sprintf(tbuf, /*MSG20*/"╢├╝╞íu║╪╖╜ív(0 ¬φÑ▄¡½╖s½ⁿ⌐wíu║╪╖╜ív) <0x%X>: ",
  1174.               rseed);
  1175.     uds = ads_getstring(False, tbuf, ibuf);
  1176.     if (uds == RTNORM) {
  1177.         if (strlen(ibuf) > 0)
  1178.             rseed = atoi(ibuf);
  1179.         if (rseed == 0) {
  1180.             seeded = False;
  1181.             initseed();
  1182.             ads_printf(/*MSG21*/"╖s¬║íu║╪╖╜ív¼░ 0x%X íC\n", rseed);
  1183.         }
  1184.         forceseed = True;
  1185.     }
  1186. }
  1187.  
  1188. /*  WORLD  --  Set world we're operating in.  */
  1189.  
  1190. static void world()
  1191. {
  1192.     int i;
  1193.     char tbuf[80];
  1194.  
  1195.     ads_textpage();
  1196.     ads_printf(/*MSG22*/"\nÑ@¼╔:   0 = Landscape (8 ªΓ)");
  1197.     ads_printf(/*MSG23*/"\n        1 = Landscape (256 ªΓ)");
  1198.     ads_printf(/*MSG24*/"\n        2 = Clouds");
  1199.     V sprintf(tbuf, /*MSG25*/"\nÑ@¼╔├■½¼ <%d>: ", wtype);
  1200.     if (ads_getint(tbuf, &i) == RTNORM) {
  1201.         if (i < 0 || i > 2) {
  1202.             ads_printf(/*MSG26*/"íuÑ@¼╔├■½¼ív╡L«─íC\n");
  1203.         } else {
  1204.             wtype = i;
  1205.         }
  1206.     }
  1207. }
  1208.  
  1209. /*  MAKEMODE  --  Set mesh generation method.  */
  1210.  
  1211. static void makemode()
  1212. {
  1213.     int i;
  1214.     char tbuf[80];
  1215.  
  1216.     ads_printf(
  1217.        /*MSG27*/"\n║⌠¡▒½╪Ñ▀ñΦªí:  0 = ¬╜▒╡╣BÑ╬ ads_entmake()");
  1218.     ads_printf(
  1219.        /*MSG28*/"\n               1 = ╕gÑ╤ ads_command() ¿╙ñ▐Ñ╬ PFACE ½ⁿÑO");
  1220.     V sprintf(tbuf, /*MSG29*/"\n½╪Ñ▀ñΦªí <%d>: ", entmake ? 0 : 1);
  1221.     if (ads_getint(tbuf, &i) == RTNORM) {
  1222.         if (i < 0 || i > 1) {
  1223.             ads_printf(/*MSG30*/"íu║⌠¡▒½╪Ñ▀ñΦªíív╡L«─íC\n");
  1224.         } else {
  1225.             entmake = i == 0 ? True : False;
  1226.         }
  1227.     }
  1228. }
  1229.  
  1230.  
  1231.  
  1232. #ifdef  HIGHC
  1233.  
  1234. /*  Early versions of High C put abort() in the same module with exit();
  1235.     ADS defines its own exit(), so we have to define our own abort().  */
  1236.  
  1237. static void abort()
  1238. {
  1239.     ads_abort("");
  1240. }
  1241.  
  1242. #endif  /* HIGHC */
  1243.