home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 September / macformat-041.iso / mac / Shareware City / Graphics / MacSPD / Sources / mount.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-30  |  8.4 KB  |  261 lines  |  [TEXT/MMCC]

  1. /*
  2.  * mount.c - creates a fractal mountain, using Carpenter's method with a
  3.  *      different extension to square grids.  A pyramid of 4 glass spheres
  4.  *      is added in front of the mountain.  One light source.
  5.  *
  6.  *      NOTE: the hashing function used to generate the database originally is
  7.  *      faulty.  The function causes repetition to occur within the fractal
  8.  *      mountain (obviously not very fractal behavior!).  A new hashing
  9.  *      function is included immediately after the old one:  merely define
  10.  *      NEW_HASH if you want to use a better hashing function.  To perform ray
  11.  *      tracing comparison tests you should still use the old, faulty database
  12.  *      (it may have repetition, but it's still a good test image).
  13.  *
  14.  * Author:  Eric Haines, 3D/Eye, Inc.
  15.  *
  16.  * size_factor determines the number of objects output.
  17.  *      Total triangular polygons = 2 * (4**size_factor)
  18.  *
  19.  *      size_factor     # triangles     # spheres
  20.  *           1               8               4
  21.  *           2              32               4
  22.  *           3             128               4
  23.  *
  24.  *           6            8192               4
  25.  */
  26.  
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include <stdlib.h>     /* atoi */
  30. #include "def.h"
  31. #include "drv.h"        /* display_close() */
  32. #include "lib.h"
  33.  
  34. /* Determine which raytracer we will use */
  35. static int raytracer_format = OUTPUT_RT_DEFAULT;
  36. /* output format determines if polygons or true surfaces are used */
  37. static int output_format = OUTPUT_CURVES;
  38.  
  39.  
  40. /* Complexity of the image */
  41. static int size_factor = 6;
  42.  
  43.  
  44. /* to use the corrected hashing function, uncomment this next line */
  45. /* #define NEW_HASH */
  46.  
  47. /* fractal dimension - affects variance of z.  Between 2 and 3 */
  48. #define FRACTAL_DIMENSION       2.2
  49. /* change MOUNTAIN_NO to get a different mountain */
  50. #define MOUNTAIN_NO             21
  51.  
  52. /* lower left corner and width of mountain definitions */
  53. #define X_CORNER        -1.0
  54. #define Y_CORNER        -1.0
  55. #define WIDTH            2.0
  56.  
  57. #ifndef NEW_HASH
  58.  
  59. /* Hashing function to get a seed for the random number generator. */
  60. /* This is the old, buggy hashing function - use it if you wish to
  61.  * obtain the same image as in the November 1987 IEEE CG&A article. */
  62. #define hash_rand(A,B,C)        ( ( (((unsigned long)(A))<<(23-(C))) +  \
  63.                     (((unsigned long)(B))<<(15-(C)))    \
  64.                   + (((unsigned long)(A))<<(7-(C))) ) & 0xffff)
  65. #else
  66.  
  67. /* New, corrected hashing function.  Use for a true fractal mountain */
  68. /* 134456 is M1 in routine lib_gauss_rand() */
  69. #define hash_rand(A,B,C)        ( ( C <= 15 ) ?                         \
  70.                   ( ABSOLUTE(                           \
  71.                     (((unsigned long)(A))<<(31-(C))) +  \
  72.                     (((unsigned long)(B))<<(15-(C))) )  \
  73.                   % 134456 ) :                          \
  74.                   ( ABSOLUTE(                           \
  75.                     (((unsigned long)(A))<<(31-(C))) +  \
  76.                     (((unsigned long)(B))>>((C)-15)) )  \
  77.                   % 134456 ) )
  78.                   )
  79. #endif
  80.  
  81. static  double  Roughness ;
  82.  
  83. /* create a pyramid of crystal spheres */
  84. static void
  85. create_spheres(center)
  86.     COORD4 center;
  87. {
  88.     int i;
  89.     double angle;
  90.     COORD3 axis, pt, new_pt;
  91.     COORD4 sphere;
  92.     MATRIX mx;
  93.  
  94.     SET_COORD3(axis, 1.0, 1.0, 0.0);
  95.     (void)lib_normalize_vector(axis);
  96.     angle = acos((double)(-1.0/3.0));
  97.  
  98.     /* set center of pyramid */
  99.     SET_COORD3(pt, 0.0, 0.0, center[W] * sqrt((double)(3.0/2.0)));
  100.  
  101.     COPY_COORD4(sphere, center);
  102.     ADD2_COORD3(sphere, pt);
  103.     lib_output_sphere(sphere, output_format);
  104.  
  105.     lib_create_axis_rotate_matrix(mx, axis, angle);
  106.     lib_transform_vector(new_pt, pt, mx);
  107.  
  108.     for (i = 0; i < 3; i++) {
  109.     lib_create_rotate_matrix(mx, Z_AXIS, (double)i * 2.0 * PI / 3.0);
  110.     lib_transform_vector(sphere, new_pt, mx);
  111.     ADD2_COORD3(sphere, center);
  112.     lib_output_sphere(sphere, output_format);
  113.     }
  114. }
  115.  
  116. /*
  117.  * Build mountain section.  If at width > 1, split quadrilateral into four
  118.  * parts.  Else if at width == 1, output quadrilateral as two triangles.
  119.  */
  120. static void
  121. grow_mountain(fnum_pts, width, ll_x, ll_y, ll_fz, lr_fz, ur_fz, ul_fz)
  122.     double fnum_pts;
  123.     int width;
  124.     int ll_x;
  125.     int ll_y ;
  126.     double ll_fz;
  127.     double lr_fz;
  128.     double ur_fz;
  129.     double ul_fz;
  130. {
  131.     long iz;
  132.     int half_width, num_tri, num_tri_vert, num_vert;
  133.     double l_fx, r_fx, l_fy, u_fy;
  134.     double lower_fz, right_fz, upper_fz, left_fz, middle_fz;
  135.     double rise_height, hside_length;
  136.     COORD3 tri_vert[3];
  137.  
  138.     if ( width == 1 ) {
  139.     /* calculate x and y coordinates of corners */
  140.     l_fx = X_CORNER + (double)ll_x * WIDTH / fnum_pts;
  141.     r_fx = X_CORNER + (double)(ll_x+1) * WIDTH / fnum_pts;
  142.     l_fy = Y_CORNER + (double)ll_y * WIDTH / fnum_pts;
  143.     u_fy = Y_CORNER + (double)(ll_y+1) * WIDTH / fnum_pts;
  144.  
  145.     /* output two triangles for section */
  146.     for (num_tri = 0; num_tri < 2; num_tri++) {
  147.         for (num_vert = 0; num_vert < 3; num_vert++) {
  148.         num_tri_vert = (num_vert + num_tri * 2) % 4;
  149.         switch (num_tri_vert) {
  150.             case 0:
  151.             SET_COORD3(tri_vert[num_vert], l_fx, l_fy, ll_fz);
  152.             break;
  153.             case 1:
  154.             SET_COORD3(tri_vert[num_vert], r_fx, l_fy, lr_fz);
  155.             break;
  156.             case 2:
  157.             SET_COORD3(tri_vert[num_vert], r_fx, u_fy, ur_fz);
  158.             break;
  159.             case 3:
  160.             SET_COORD3(tri_vert[num_vert], l_fx, u_fy, ul_fz);
  161.             break;
  162.         }
  163.         }
  164.         lib_output_polygon(3, tri_vert);
  165.     }
  166.     } else {
  167.     /* subdivide edges and move in z direction */
  168.     half_width = width>>1;
  169.     hside_length = (double)half_width * WIDTH / fnum_pts;
  170.     rise_height = hside_length * Roughness;
  171.  
  172.     /* for each midpoint, find z */
  173.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y, size_factor);
  174.     lower_fz = (ll_fz + lr_fz) / 2.0 + rise_height * lib_gauss_rand(iz);
  175.     iz = MOUNTAIN_NO + hash_rand(ll_x + width, ll_y + half_width,
  176.                           size_factor);
  177.     right_fz = ( lr_fz + ur_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  178.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y + width,
  179.                           size_factor);
  180.     upper_fz = ( ur_fz + ul_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  181.     iz = MOUNTAIN_NO + hash_rand( ll_x, ll_y + half_width, size_factor);
  182.     left_fz = ( ul_fz + ll_fz ) / 2.0 + rise_height * lib_gauss_rand(iz);
  183.     iz = MOUNTAIN_NO + hash_rand(ll_x + half_width, ll_y + half_width,
  184.                           size_factor);
  185.     middle_fz = ( ll_fz + lr_fz + ur_fz + ul_fz ) / 4.0 +
  186.               1.4142136 * rise_height * lib_gauss_rand(iz);
  187.  
  188.     /* check subsections for subdivision or output */
  189.     PLATFORM_MULTITASK();
  190.     grow_mountain(fnum_pts, half_width, ll_x, ll_y,
  191.               ll_fz, lower_fz, middle_fz, left_fz);
  192.     grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y,
  193.               lower_fz, lr_fz, right_fz, middle_fz);
  194.     grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y+half_width,
  195.               middle_fz, right_fz, ur_fz, upper_fz);
  196.     grow_mountain(fnum_pts, half_width, ll_x, ll_y+half_width,
  197.               left_fz, middle_fz, upper_fz, ul_fz);
  198.     }
  199. }
  200.  
  201. int
  202. main(argc,argv)
  203.     int argc;
  204.     char *argv[];
  205. {
  206.     int num_pts;
  207.     double ratio;
  208.     COORD3 back_color, obj_color;
  209.     COORD3 from, at, up;
  210.     COORD4 light, center;
  211.  
  212.     PLATFORM_INIT(SPD_MOUNT);
  213.  
  214.     /* Start by defining which raytracer we will be using */
  215.     if ( lib_gen_get_opts( argc, argv,
  216.             &size_factor, &raytracer_format, &output_format )) {
  217.     return EXIT_FAIL;
  218.     }
  219.     if ( lib_open( raytracer_format, "Mount.out" ) ) {
  220.     return EXIT_FAIL;
  221.     }
  222.  
  223.     /* output background color - UNC sky blue */
  224.     /* NOTE: Do this BEFORE lib_output_viewpoint(), for display_init() */
  225.     SET_COORD3(back_color, 0.078, 0.361, 0.753);
  226.     lib_output_background_color(back_color);
  227.  
  228.     /* output viewpoint */
  229.     SET_COORD3(from, -1.6, 1.6, 1.7);
  230.     SET_COORD3(at, 0.0, 0.0, 0.0);
  231.     SET_COORD3(up, 0.0, 0.0, 1.0);
  232.     lib_output_viewpoint(from, at, up, 45.0, 1.0, 0.01, 512, 512);
  233.  
  234.     /* output light sources */
  235.     SET_COORD4(light, -100.0, -100.0, 100.0, 1.0);
  236.     lib_output_light(light);
  237.  
  238.     /* set up crystal sphere color - clear white */
  239.     SET_COORD3(obj_color, 1.0, 1.0, 1.0);
  240.     lib_output_color(NULL, obj_color, 0.0, 0.1, 0.1, 0.4, 5.0, 0.9, 1.5);
  241.  
  242.     /* output crystal spheres */
  243.     SET_COORD4(center, -0.8, 0.8, 1.00, 0.17);
  244.     create_spheres(center);
  245.  
  246.     /* set up mountain color - grey */
  247.     SET_COORD3(obj_color, 0.5, 0.45, 0.35);
  248.     lib_output_color(NULL, obj_color, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
  249.  
  250.     /* grow mountain */
  251.     num_pts = 1<<size_factor;
  252.     ratio = 2.0 / exp((double)(log((double)2.0) / (FRACTAL_DIMENSION-1.0)));
  253.     Roughness = sqrt((double)(SQR(ratio) - 1.0));
  254.     grow_mountain((double)num_pts, num_pts, 0, 0, 0.0, 0.0, 0.0, 0.0);
  255.  
  256.     lib_close();
  257.  
  258.     PLATFORM_SHUTDOWN();
  259.     return EXIT_SUCCESS;
  260. }
  261.