home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
gondwana.ecr.mu.oz.au/pub/
/
Graphics.tar
/
Graphics
/
SPD.3.0.shar.gz
/
SPD.3.0.shar
/
mount.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-01-13
|
8KB
|
245 lines
/*
* mount.c - creates a fractal mountain, using Carpenter's method with a
* different extension to square grids. A pyramid of 4 glass spheres
* is added in front of the mountain. One light source.
*
* NOTE: the hashing function used to generate the database originally is
* faulty. The function causes repetition to occur within the fractal
* mountain (obviously not very fractal behavior!). A new hashing
* function is included immediately after the old one: merely define
* NEW_HASH if you want to use a better hashing function. To perform ray
* tracing comparison tests you should still use the old, faulty database
* (it may have repetition, but it's still a good test image).
*
* Author: Eric Haines, 3D/Eye, Inc.
*
* SizeFactor determines the number of objects output.
* Total triangular polygons = 2 * (4**SizeFactor)
*
* SizeFactor # triangles # spheres
* 1 8 4
* 2 32 4
* 3 128 4
*
* 6 8192 4
*/
#include <stdio.h>
#include <math.h>
#include "def.h"
#include "lib.h"
static int SizeFactor = 6 ;
#define OUTPUT_FORMAT OUTPUT_CURVES
/* to use the corrected hashing function, uncomment this next line */
/* #define NEW_HASH */
/* fractal dimension - affects variance of z. Between 2 and 3 */
#define FRACTAL_DIMENSION 2.2
/* change MOUNTAIN_NO to get a different mountain */
#define MOUNTAIN_NO 21
/* lower left corner and width of mountain definitions */
#define X_CORNER -1.0
#define Y_CORNER -1.0
#define WIDTH 2.0
#ifndef NEW_HASH
/* Hashing function to get a seed for the random number generator. */
/* This is the old, buggy hashing function - use it if you wish to
* obtain the same image as in the November 1987 IEEE CG&A article. */
#define hash_rand(A,B,C) ( ( (((unsigned long)(A))<<(23-(C))) + \
(((unsigned long)(B))<<(15-(C))) \
+ (((unsigned long)(A))<<(7-(C))) ) & 0xffff)
#else
/* New, corrected hashing function. Use for a true fractal mountain */
/* 134456 is M1 in routine lib_gauss_rand() */
#define hash_rand(A,B,C) ( ( C <= 15 ) ? \
( ABSOLUTE( \
(((unsigned long)(A))<<(31-(C))) + \
(((unsigned long)(B))<<(15-(C))) ) \
% 134456 ) : \
( ABSOLUTE( \
(((unsigned long)(A))<<(31-(C))) + \
(((unsigned long)(B))>>((C)-15)) ) \
% 134456 ) )
)
#endif
static double Roughness ;
main(argc,argv)
int argc ;
char *argv[] ;
{
int num_pts ;
double ratio ;
COORD3 back_color, obj_color ;
COORD3 from, at, up, light ;
COORD4 center ;
if ( !lib_get_size( argc, argv, &SizeFactor ) ) {
fprintf( stderr, "usage: %s [size]\n", *argv ) ;
exit(EXIT_FAIL) ;
}
/* output viewpoint */
SET_COORD3( from, -1.6, 1.6, 1.7 ) ;
SET_COORD3( at, 0.0, 0.0, 0.0 ) ;
SET_COORD3( up, 0.0, 0.0, 1.0 ) ;
lib_output_viewpoint( from, at, up, 45.0, 0.5, 512, 512 ) ;
/* output background color - UNC sky blue */
SET_COORD3( back_color, 0.078, 0.361, 0.753 ) ;
lib_output_background_color( back_color ) ;
/* output light sources */
SET_COORD3( light, -100.0, -100.0, 100.0 ) ;
lib_output_light( light ) ;
/* set up crystal sphere color - clear white */
SET_COORD3( obj_color, 1.0, 1.0, 1.0 ) ;
lib_output_color( obj_color, 0.1, 0.9, 100.0, 0.9, 1.5 ) ;
/* output crystal spheres */
SET_COORD4( center, -0.8, 0.8, 1.00, 0.17 ) ;
create_spheres( center ) ;
/* set up mountain color - grey */
SET_COORD3( obj_color, 0.5, 0.45, 0.35 ) ;
lib_output_color( obj_color, 1.0, 0.0, 0.0, 0.0, 0.0 ) ;
/* grow mountain */
num_pts = 1<<SizeFactor ;
ratio = 2.0 /
exp( (double)( log( (double)2.0 ) / (FRACTAL_DIMENSION-1.0) ) ) ;
Roughness = sqrt( (double)( SQR(ratio) - 1.0 ) ) ;
grow_mountain( (double)num_pts, num_pts, 0, 0, 0.0, 0.0, 0.0, 0.0 ) ;
exit(EXIT_SUCCESS) ;
}
/* create a pyramid of crystal spheres */
create_spheres( center )
COORD4 center ;
{
int i ;
double angle ;
COORD3 axis, pt, new_pt ;
COORD4 sphere ;
MATRIX mx ;
SET_COORD3( axis, 1.0, 1.0, 0.0 ) ;
(void)lib_normalize_vector( axis ) ;
angle = acos( (double)( -1.0/3.0 ) ) ;
/* set center of pyramid */
SET_COORD3( pt, 0.0, 0.0, center[W] * sqrt( (double)( 3.0/2.0 ) ) ) ;
COPY_COORD4( sphere, center ) ;
ADD2_COORD3( sphere, pt ) ;
lib_output_sphere( sphere, OUTPUT_FORMAT ) ;
lib_create_axis_rotate_matrix( mx, axis, angle ) ;
lib_transform_vector( new_pt, pt, mx ) ;
for ( i = 0 ; i < 3 ; ++i ) {
lib_create_rotate_matrix( mx, Z_AXIS, (double)i * 2.0 * PI / 3.0 ) ;
lib_transform_vector( sphere, new_pt, mx ) ;
ADD2_COORD3( sphere, center ) ;
lib_output_sphere( sphere, OUTPUT_FORMAT ) ;
}
}
/*
* Build mountain section. If at width > 1, split quadrilateral into four
* parts. Else if at width == 1, output quadrilateral as two triangles.
*/
grow_mountain( fnum_pts, width, ll_x, ll_y, ll_fz, lr_fz, ur_fz, ul_fz )
double fnum_pts ;
int width ;
int ll_x ;
int ll_y ;
double ll_fz ;
double lr_fz ;
double ur_fz ;
double ul_fz ;
{
int half_width, iz, num_tri, num_tri_vert, num_vert ;
double l_fx, r_fx, l_fy, u_fy ;
double lower_fz, right_fz, upper_fz, left_fz, middle_fz ;
double rise_height, hside_length ;
COORD3 tri_vert[3] ;
if ( width == 1 ) {
/* calculate x and y coordinates of corners */
l_fx = X_CORNER + (double)ll_x * WIDTH / fnum_pts ;
r_fx = X_CORNER + (double)(ll_x+1) * WIDTH / fnum_pts ;
l_fy = Y_CORNER + (double)ll_y * WIDTH / fnum_pts ;
u_fy = Y_CORNER + (double)(ll_y+1) * WIDTH / fnum_pts ;
/* output two triangles for section */
for ( num_tri = 0 ; num_tri < 2 ; ++num_tri ) {
for ( num_vert = 0 ; num_vert < 3 ; ++num_vert ) {
num_tri_vert = ( num_vert + num_tri * 2 ) % 4 ;
switch ( num_tri_vert ) {
case 0:
SET_COORD3( tri_vert[num_vert], l_fx, l_fy, ll_fz ) ;
break ;
case 1:
SET_COORD3( tri_vert[num_vert], r_fx, l_fy, lr_fz ) ;
break ;
case 2:
SET_COORD3( tri_vert[num_vert], r_fx, u_fy, ur_fz ) ;
break ;
case 3:
SET_COORD3( tri_vert[num_vert], l_fx, u_fy, ul_fz ) ;
break ;
}
}
lib_output_polygon( 3, tri_vert ) ;
}
}
else {
/* subdivide edges and move in z direction */
half_width = width>>1 ;
hside_length = (double)half_width * WIDTH / fnum_pts ;
rise_height = hside_length * Roughness ;
/* for each midpoint, find z */
iz = MOUNTAIN_NO + hash_rand( ll_x + half_width, ll_y, SizeFactor ) ;
lower_fz = ( ll_fz + lr_fz ) / 2.0 +
rise_height * lib_gauss_rand( iz ) ;
iz = MOUNTAIN_NO +
hash_rand( ll_x + width, ll_y + half_width, SizeFactor ) ;
right_fz = ( lr_fz + ur_fz ) / 2.0 +
rise_height * lib_gauss_rand( iz ) ;
iz = MOUNTAIN_NO +
hash_rand( ll_x + half_width, ll_y + width, SizeFactor ) ;
upper_fz = ( ur_fz + ul_fz ) / 2.0 +
rise_height * lib_gauss_rand( iz ) ;
iz = MOUNTAIN_NO + hash_rand( ll_x, ll_y + half_width, SizeFactor ) ;
left_fz = ( ul_fz + ll_fz ) / 2.0 +
rise_height * lib_gauss_rand( iz ) ;
iz = MOUNTAIN_NO +
hash_rand( ll_x + half_width, ll_y + half_width, SizeFactor ) ;
middle_fz = ( ll_fz + lr_fz + ur_fz + ul_fz ) / 4.0 +
1.4142136 * rise_height * lib_gauss_rand( iz ) ;
/* check subsections for subdivision or output */
grow_mountain( fnum_pts, half_width, ll_x, ll_y,
ll_fz, lower_fz, middle_fz, left_fz ) ;
grow_mountain( fnum_pts, half_width, ll_x+half_width, ll_y,
lower_fz, lr_fz, right_fz, middle_fz ) ;
grow_mountain( fnum_pts, half_width, ll_x+half_width, ll_y+half_width,
middle_fz, right_fz, ur_fz, upper_fz ) ;
grow_mountain( fnum_pts, half_width, ll_x, ll_y+half_width,
left_fz, middle_fz, upper_fz, ul_fz ) ;
}
}