fractmod.c
上传用户:sycq158
上传日期:2008-10-22
资源大小:15361k
文件大小:18k
源码类别:

游戏

开发平台:

Visual C++

  1. /*
  2.  Written by: Paul E. Martz
  3.  
  4.  Copyright 1997 by Paul E. Martz, all right reserved
  5.  Non-commercial use by individuals is permitted.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include "math.h"
  10. #include "fractmod.h"
  11. #ifdef __cplusplus
  12. extern "C" {
  13. #endif
  14. /* Compiling with DEBUG defined can produce enormous amounts of output
  15.    to stdout. Beware.
  16. #define DEBUG
  17.    */
  18. #ifdef _WINDOWS
  19. /* Was written for HPUX. Handle Win32 compiles */
  20. #define random() rand()
  21. #define srandom(x) srand(x)
  22. #endif
  23. /*
  24.  * randNum - Return a random floating point number such that
  25.  *      (min <= return-value <= max)
  26.  * 32,767 values are possible for any given range.
  27.  */
  28. static float randnum (float min, float max)
  29. {
  30. int r;
  31.     float x;
  32.     
  33. r = random ();
  34.     x = (float)(r & 0x7fff) /
  35. (float)0x7fff;
  36.     return (x * (max - min) + min);
  37. /*
  38.  * fractRand is a useful interface to randnum.
  39.  */
  40. #define fractRand(v) randnum (-v, v)
  41. /*
  42.  * avgEndpoints - Given the i location and a stride to the data
  43.  * values, return the average those data values. "i" can be thought of
  44.  * as the data value in the center of two line endpoints. We use
  45.  * "stride" to get the values of the endpoints. Averaging them yields
  46.  * the midpoint of the line.
  47.  *
  48.  * Called by fill1DFractArray.
  49.  */
  50. static float avgEndpoints (int i, int stride, float *fa)
  51. {
  52.     return ((float) (fa[i-stride] +
  53.      fa[i+stride]) * .5f);
  54. }
  55. /*
  56.  * avgDiamondVals - Given the i,j location as the center of a diamond,
  57.  * average the data values at the four corners of the diamond and
  58.  * return it. "Stride" represents the distance from the diamond center
  59.  * to a diamond corner.
  60.  *
  61.  * Called by fill2DFractArray.
  62.  */
  63. static float avgDiamondVals (int i, int j, int stride,
  64.      int size, int subSize, float *fa)
  65. {
  66.     /* In this diagram, our input stride is 1, the i,j location is
  67.        indicated by "X", and the four value we want to average are
  68.        "*"s:
  69.            .   *   .
  70.            *   X   *
  71.            .   *   .
  72.        */
  73.     /* In order to support tiled surfaces which meet seamless at the
  74.        edges (that is, they "wrap"), We need to be careful how we
  75.        calculate averages when the i,j diamond center lies on an edge
  76.        of the array. The first four 'if' clauses handle these
  77.        cases. The final 'else' clause handles the general case (in
  78.        which i,j is not on an edge).
  79.      */
  80.     if (i == 0)
  81. return ((float) (fa[(i*size) + j-stride] +
  82.  fa[(i*size) + j+stride] +
  83.  fa[((subSize-stride)*size) + j] +
  84.  fa[((i+stride)*size) + j]) * .25f);
  85.     else if (i == size-1)
  86. return ((float) (fa[(i*size) + j-stride] +
  87.  fa[(i*size) + j+stride] +
  88.  fa[((i-stride)*size) + j] +
  89.  fa[((0+stride)*size) + j]) * .25f);
  90.     else if (j == 0)
  91. return ((float) (fa[((i-stride)*size) + j] +
  92.  fa[((i+stride)*size) + j] +
  93.  fa[(i*size) + j+stride] +
  94.  fa[(i*size) + subSize-stride]) * .25f);
  95.     else if (j == size-1)
  96. return ((float) (fa[((i-stride)*size) + j] +
  97.  fa[((i+stride)*size) + j] +
  98.  fa[(i*size) + j-stride] +
  99.  fa[(i*size) + 0+stride]) * .25f);
  100.     else
  101. return ((float) (fa[((i-stride)*size) + j] +
  102.  fa[((i+stride)*size) + j] +
  103.  fa[(i*size) + j-stride] +
  104.  fa[(i*size) + j+stride]) * .25f);
  105. }
  106. /*
  107.  * avgSquareVals - Given the i,j location as the center of a square,
  108.  * average the data values at the four corners of the square and return
  109.  * it. "Stride" represents half the length of one side of the square.
  110.  *
  111.  * Called by fill2DFractArray.
  112.  */
  113. static float avgSquareVals (int i, int j, int stride, int size, float *fa)
  114. {
  115.     /* In this diagram, our input stride is 1, the i,j location is
  116.        indicated by "*", and the four value we want to average are
  117.        "X"s:
  118.            X   .   X
  119.            .   *   .
  120.            X   .   X
  121.        */
  122.     return ((float) (fa[((i-stride)*size) + j-stride] +
  123.      fa[((i-stride)*size) + j+stride] +
  124.      fa[((i+stride)*size) + j-stride] +
  125.      fa[((i+stride)*size) + j+stride]) * .25f);
  126. }
  127. #ifdef DEBUG
  128. /*
  129.  * dump1DFractArray - Use for debugging.
  130.  */
  131. void dump1DFractArray (float *fa, int size)
  132. {
  133.     int i;
  134.     for (i=0; i<size; i++)
  135. printf ("(%.2f)   ", fa[i]);
  136.     printf ("n");
  137. }
  138. /*
  139.  * dump2DFractArray - Use for debugging.
  140.  */
  141. void dump2DFractArray (float *fa, int size)
  142. {
  143.     int i, j;
  144.     for (i=0; i<size; i++) {
  145. j=0;
  146. printf ("[%d,%d]: ", i, j);
  147. for (; j<size; j++) {
  148.     printf ("(%.2f)   ",
  149.     fa[(i*size)+j]);
  150. }
  151. printf ("n");
  152.     }
  153. }
  154. #endif
  155. /*
  156.  * powerOf2 - Returns 1 if size is a power of 2. Returns 0 if size is
  157.  * not a power of 2, or is zero.
  158.  */
  159. static int powerOf2 (int size)
  160. {
  161.     int i, bitcount = 0;
  162.     /* Note this code assumes that (sizeof(int)*8) will yield the
  163.        number of bits in an int. Should be portable to most
  164.        platforms. */
  165.     for (i=0; i<sizeof(int)*8; i++)
  166. if (size & (1<<i))
  167.     bitcount++;
  168.     if (bitcount == 1)
  169. /* One bit. Must be a power of 2. */
  170. return (1);
  171.     else
  172. /* either size==0, or size not a power of 2. Sorry, Charlie. */
  173. return (0);
  174. }
  175. /*
  176.  * fill1DFractArray - Tessalate an array of values into an
  177.  * approximation of fractal Brownian motion.
  178.  */
  179. void fill1DFractArray (float *fa, int size,
  180.        int seedValue, float heightScale, float h)
  181. {
  182.     int i;
  183.     int stride;
  184.     int subSize;
  185. float ratio, scale;
  186.     if (!powerOf2(size) || (size==1)) {
  187. /* We can't tesselate the array if it is not a power of 2. */
  188. #ifdef DEBUG
  189. printf ("Error: fill1DFractArray: size %d is not a power of 2.n");
  190. #endif /* DEBUG */
  191. return;
  192.     }
  193.     /* subSize is the dimension of the array in terms of connected line
  194.        segments, while size is the dimension in terms of number of
  195.        vertices. */
  196.     subSize = size;
  197.     size++;
  198.     
  199.     /* initialize random number generator */
  200.     srandom (seedValue);
  201. #ifdef DEBUG
  202.     printf ("initializedn");
  203.     dump1DFractArray (fa, size);
  204. #endif
  205. /* Set up our roughness constants.
  206.    Random numbers are always generated in the range 0.0 to 1.0.
  207.    'scale' is multiplied by the randum number.
  208.    'ratio' is multiplied by 'scale' after each iteration
  209.    to effectively reduce the randum number range.
  210.    */
  211. ratio = (float) pow (2.,-h);
  212. scale = heightScale * ratio;
  213.     /* Seed the endpoints of the array. To enable seamless wrapping,
  214.        the endpoints need to be the same point. */
  215.     stride = subSize / 2;
  216.     fa[0] =
  217.       fa[subSize] = 0.f;
  218. #ifdef DEBUG
  219.     printf ("seededn");
  220.     dump1DFractArray (fa, size);
  221. #endif
  222.     while (stride) {
  223. for (i=stride; i<subSize; i+=stride) {
  224. fa[i] = scale * fractRand (.5f) +
  225. avgEndpoints (i, stride, fa);
  226. /* reduce random number range */
  227. scale *= ratio;
  228. i+=stride;
  229. }
  230. stride >>= 1;
  231.     }
  232. #ifdef DEBUG
  233.     printf ("completen");
  234.     dump1DFractArray (fa, size);
  235. #endif
  236. }
  237. /*
  238.  * fill2DFractArray - Use the diamond-square algorithm to tessalate a
  239.  * grid of float values into a fractal height map.
  240.  */
  241. void fill2DFractArray (float *fa, int size,
  242.        int seedValue, float heightScale, float h)
  243. {
  244.     int i, j;
  245.     int stride;
  246.     int oddline;
  247.     int subSize;
  248. float ratio, scale;
  249.     if (!powerOf2(size) || (size==1)) {
  250. /* We can't tesselate the array if it is not a power of 2. */
  251. #ifdef DEBUG
  252. printf ("Error: fill2DFractArray: size %d is not a power of 2.n");
  253. #endif /* DEBUG */
  254. return;
  255.     }
  256.     /* subSize is the dimension of the array in terms of connected line
  257.        segments, while size is the dimension in terms of number of
  258.        vertices. */
  259.     subSize = size;
  260.     size++;
  261.     
  262.     /* initialize random number generator */
  263.     srandom (seedValue);
  264.     
  265. #ifdef DEBUG
  266.     printf ("initializedn");
  267.     dump2DFractArray (fa, size);
  268. #endif
  269. /* Set up our roughness constants.
  270.    Random numbers are always generated in the range 0.0 to 1.0.
  271.    'scale' is multiplied by the randum number.
  272.    'ratio' is multiplied by 'scale' after each iteration
  273.    to effectively reduce the randum number range.
  274.    */
  275. ratio = (float) pow (2.,-h);
  276. scale = heightScale * ratio;
  277.     /* Seed the first four values. For example, in a 4x4 array, we
  278.        would initialize the data points indicated by '*':
  279.            *   .   .   .   *
  280.            .   .   .   .   .
  281.            .   .   .   .   .
  282.            .   .   .   .   .
  283.            *   .   .   .   *
  284.        In terms of the "diamond-square" algorithm, this gives us
  285.        "squares".
  286.        We want the four corners of the array to have the same
  287.        point. This will allow us to tile the arrays next to each other
  288.        such that they join seemlessly. */
  289.     stride = subSize / 2;
  290.     fa[(0*size)+0] =
  291.       fa[(subSize*size)+0] =
  292.         fa[(subSize*size)+subSize] =
  293.           fa[(0*size)+subSize] = 0.f;
  294.     
  295. #ifdef DEBUG
  296.     printf ("seededn");
  297.     dump2DFractArray (fa, size);
  298. #endif
  299.     /* Now we add ever-increasing detail based on the "diamond" seeded
  300.        values. We loop over stride, which gets cut in half at the
  301.        bottom of the loop. Since it's an int, eventually division by 2
  302.        will produce a zero result, terminating the loop. */
  303.     while (stride) {
  304. /* Take the existing "square" data and produce "diamond"
  305.    data. On the first pass through with a 4x4 matrix, the
  306.    existing data is shown as "X"s, and we need to generate the
  307.        "*" now:
  308.                X   .   .   .   X
  309.                .   .   .   .   .
  310.                .   .   *   .   .
  311.                .   .   .   .   .
  312.                X   .   .   .   X
  313.       It doesn't look like diamonds. What it actually is, for the
  314.       first pass, is the corners of four diamonds meeting at the
  315.       center of the array. */
  316. for (i=stride; i<subSize; i+=stride) {
  317. for (j=stride; j<subSize; j+=stride) {
  318. fa[(i * size) + j] =
  319. scale * fractRand (.5f) +
  320. avgSquareVals (i, j, stride, size, fa);
  321. j += stride;
  322. }
  323. i += stride;
  324. }
  325. #ifdef DEBUG
  326. printf ("Diamonds:n");
  327. dump2DFractArray (fa, size);
  328. #endif
  329. /* Take the existing "diamond" data and make it into
  330.        "squares". Back to our 4X4 example: The first time we
  331.        encounter this code, the existing values are represented by
  332.        "X"s, and the values we want to generate here are "*"s:
  333.                X   .   *   .   X
  334.                .   .   .   .   .
  335.                *   .   X   .   *
  336.                .   .   .   .   .
  337.                X   .   *   .   X
  338.        i and j represent our (x,y) position in the array. The
  339.        first value we want to generate is at (i=2,j=0), and we use
  340.        "oddline" and "stride" to increment j to the desired value.
  341.        */
  342. oddline = 0;
  343. for (i=0; i<subSize; i+=stride) {
  344.     oddline = (oddline == 0);
  345. for (j=0; j<subSize; j+=stride) {
  346. if ((oddline) && !j) j+=stride;
  347. /* i and j are setup. Call avgDiamondVals with the
  348.    current position. It will return the average of the
  349.    surrounding diamond data points. */
  350. fa[(i * size) + j] =
  351. scale * fractRand (.5f) +
  352. avgDiamondVals (i, j, stride, size, subSize, fa);
  353. /* To wrap edges seamlessly, copy edge values around
  354.    to other side of array */
  355. if (i==0)
  356. fa[(subSize*size) + j] =
  357. fa[(i * size) + j];
  358. if (j==0)
  359. fa[(i*size) + subSize] =
  360. fa[(i * size) + j];
  361. j+=stride;
  362. }
  363. }
  364. #ifdef DEBUG
  365. printf ("Squares:n");
  366. dump2DFractArray (fa, size);
  367. #endif
  368. /* reduce random number range. */
  369. scale *= ratio;
  370. stride >>= 1;
  371.     }
  372. #ifdef DEBUG
  373.     printf ("completen");
  374.     dump2DFractArray (fa, size);
  375. #endif
  376. }
  377. /*
  378.  * alloc1DFractArray - Allocate float-sized data points for a 1D strip
  379.  * containing size line segments.
  380.  */
  381. float *alloc1DFractArray (int size)
  382. {
  383.     /* Increment size (see comment in alloc2DFractArray, below, for an
  384.        explanation). */
  385.     size++;
  386.     return ((float *) malloc (sizeof(float) * size));
  387. }
  388. /*
  389.  * alloc2DFractArray - Allocate float-sized data points for a sizeXsize
  390.  * mesh.
  391.  */
  392. float *alloc2DFractArray (int size)
  393. {
  394.     /* For a sizeXsize array, we need (size+1)X(size+1) space. For
  395.        example, a 2x2 mesh needs 3x3=9 data points: 
  396.            *   *   *
  397.            *   *   *
  398.            *   *   *
  399.        To account for this, increment 'size'. */
  400.     size++;
  401.     return ((float *) malloc (sizeof(float) * size * size));
  402. }
  403. /*
  404.  * freeFractArray - Takes a pointer to float and frees it. Can be used
  405.  * to free data that was allocated by either alloc1DFractArray or
  406.  * alloc2DFractArray.
  407.  */
  408. void freeFractArray (float *fa)
  409. {
  410.     free (fa);
  411. }
  412. extern void draw2DLine (float, float, float, float);
  413. /*
  414.  * draw1DFractArrayAsLines - Draws the height map as a single set of
  415.  * connected line segments.
  416.  *
  417.  * This is a simplified routine intended for getting things up and
  418.  * running quickly, and as a demonstration of how to walk through the
  419.  * array.
  420.  *
  421.  * To use this routine, you MUST define your own "draw2DLine" function
  422.  * according to the extern definition below. It takes 4 parameters,
  423.  * the X and Y world coordinates of the first endpoint followed by the
  424.  * X and Y world coordinates of the second endpoint.
  425.  *
  426.  * The X coordinates will be distributed evenly from -1.0 to
  427.  * 1.0. Corresponding Y coordinates will be extracted from the fract
  428.  * array.
  429.  */
  430. void draw1DFractArrayAsLines (float *fa, int size)
  431. {
  432.     int i;
  433.     float x, inc;
  434.     inc = 2.f / size;
  435.     x = -1.f;
  436.     for (i=0; i<size; i++) {
  437. draw2DLine (x, fa[i],
  438.     x+inc, fa[i+1]);
  439. x += inc;
  440.     }
  441. }
  442. /*
  443.  * draw2DFractArrayAsLines - Draws the height map as a set of line
  444.  * segments comprising a grid.
  445.  *
  446.  * This is a simplified routine intended for getting things up and
  447.  * running quickly, and as a demonstration of how to walk through the
  448.  * array.
  449.  *
  450.  * To use this routine, you MUST define your own "draw3DLine" function
  451.  * according to the extern definition below. It takes 6 parameters,
  452.  * the X, Y, and Z world coordinates of the first endpoint followed by
  453.  * the X, Y, and Z world coordinates of the second endpoint.
  454.  *
  455.  * X and Z coordinates will be distributed evenly over a grid from
  456.  * -1.0 to 1.0 along both axes. Corresponding Y coordinates will be
  457.  * extracted from the fract array.
  458.  */
  459. void draw2DFractArrayAsLines (float *fa, int size)
  460. {
  461.     extern void draw3DLine (float, float, float, float, float, float);
  462.     int i, j;
  463.     float x, z, inc;
  464.     const int subSize = size;
  465.     size++;
  466.     inc = 2.f / subSize;
  467.     z = -1.f;
  468.     for (i=0; i<size; i++) {
  469. x = -1.f;
  470. for (j=0; j<subSize; j++) {
  471.     draw3DLine (x, fa[(i*size)+j], z,
  472. x+inc, fa[(i*size+j+1)], z);
  473.     if (i<subSize)
  474. draw3DLine (x, fa[(i*size)+j], z,
  475.     x, fa[((i+1)*size+j)], z+inc);
  476.     x += inc;
  477. }
  478. if (i<subSize)
  479.     draw3DLine (x, fa[(i*size)+j], z,
  480. x, fa[((i+1)*size+j)], z+inc);
  481. z += inc;
  482.     }
  483. }
  484. static void genNormal (float x1, float y1, float z1,
  485.        float x2, float y2, float z2,
  486.        float x3, float y3, float z3,
  487.        float *normal)
  488. {
  489.     float len;
  490.     float v1x, v1y, v1z;
  491.     float v2x, v2y, v2z;
  492.     v1x = x2 - x1;
  493.     v1y = y2 - y1;
  494.     v1z = z2 - z1;
  495.     v2x = x3 - x1;
  496.     v2y = y3 - y1;
  497.     v2z = z3 - z1;
  498.     normal[0] = v1y*v2z - v1z*v2y;
  499.     normal[1] = v1z*v2x - v1x*v2z;
  500.     normal[2] = v1x*v2y - v1y*v2x;
  501.     len = (float) sqrt (normal[0]*normal[0] + normal[1]*normal[1] +
  502. normal[2]*normal[2]);
  503.     normal[0] /= len;
  504.     normal[1] /= len;
  505.     normal[2] /= len;
  506. }
  507. /*
  508.  * draw2DFractArrayAsTriangles - Draws the height map as a set of
  509.  * triangular facets with a corresponding facet normal.
  510.  *
  511.  * This is a simplified routine intended for getting things up and
  512.  * running quickly, and as a demonstration of how to walk through the
  513.  * array.
  514.  *
  515.  * To use this routine, you MUST define your own "draw3DTriangle"
  516.  * function according to the extern definition below. It takes 12
  517.  * (ugh!) parameters: the first 9 are the X, Y, and Z world
  518.  * coordinates of the three vertices, and the last three parameters
  519.  * are the X, Y, and Z cartesian components of the unit-length facet
  520.  * normal.
  521.  *
  522.  * X and Z coordinates will be distributed evenly over a grid from
  523.  * -1.0 to 1.0 along both axes. Corresponding Y coordinates will be
  524.  * extracted from the fract array. Normals will be gererated favoring
  525.  * the "UP" or positive Y direction, and vertex order will use the
  526.  * right hand rule to match the normal. ("Right hand rule": When
  527.  * viewed from the direction the normal is pointing, the vertex
  528.  * ordering will be counter-clockwise.)
  529.  */
  530. void draw2DFractArrayAsTriangles (float *fa, int size)
  531. {
  532.     extern void draw3DTriangle (float, float, float, float, float, float,
  533. float, float, float, float, float, float);
  534.     int i, j;
  535.     float x, z, inc;
  536.     const int subSize = size;
  537.     size++;
  538.     inc = 2.f / subSize;
  539.     z = -1.f;
  540.     for (i=0; i<subSize; i++) {
  541. x = -1.f;
  542. for (j=0; j<subSize; j++) {
  543.     float normal[3];
  544.     genNormal (x, fa[(i*size)+j], z,
  545.        x, fa[((i+1)*size)+j], z+inc,
  546.        x+inc, fa[(i*size+j+1)], z,
  547.        normal);
  548.     draw3DTriangle (x, fa[(i*size)+j], z,
  549.     x, fa[((i+1)*size)+j], z+inc,
  550.     x+inc, fa[(i*size+j+1)], z,
  551.     normal[0], normal[1], normal[2]);
  552.     genNormal (x, fa[((i+1)*size)+j], z+inc,
  553.        x+inc, fa[((i+1)*size)+j+1], z+inc,
  554.        x+inc, fa[(i*size+j+1)], z,
  555.        normal);
  556.     draw3DTriangle (x, fa[((i+1)*size)+j], z+inc,
  557.     x+inc, fa[((i+1)*size)+j+1], z+inc,
  558.     x+inc, fa[(i*size+j+1)], z,
  559.     normal[0], normal[1], normal[2]);
  560.     x += inc;
  561. }
  562. z += inc;
  563.     }
  564. }
  565. #ifdef __cplusplus
  566. }
  567. #endif