-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmount.c
295 lines (257 loc) · 8.95 KB
/
mount.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
/*
* 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
*
* size_factor determines the number of objects output.
* Total triangular polygons = 2 * (4**size_factor)
*
* size_factor # triangles # spheres
* 1 8 4
* 2 32 4
* 3 128 4
*
* 6 8192 4
*/
#include <stdio.h>
#include <math.h>
#include <stdlib.h> /* atoi */
#include "def.h"
#include "drv.h" /* display_close() */
#include "lib.h"
/* Determine which raytracer we will use */
static int raytracer_format = OUTPUT_RT_DEFAULT;
/* output format determines if polygons or true surfaces are used */
static int output_format = OUTPUT_CURVES;
/* Complexity of the image */
static int size_factor = 6;
#ifdef OUTPUT_TO_FILE
static FILE * stdout_file = NULL;
#else
#define stdout_file stdout
#endif /* OUTPUT_TO_FILE */
/* to use a much better hashing function, uncomment this next line */
/* #define JENKINS_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 JENKINS_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
/*
* Bob Jenkins invented this great, reasonably fast, very nice
* has function. Check out his web page:
* http://ourworld.compuserve.com/homepages/bob_jenkins/blockcip.htm
*/
#define mix(a,b,c) \
{ \
a -= b; a -= c; a ^= (c>>13); \
b -= c; b -= a; b ^= (a<<8); \
c -= a; c -= b; c ^= (b>>13); \
a -= b; a -= c; a ^= (c>>12); \
b -= c; b -= a; b ^= (a<<16); \
c -= a; c -= b; c ^= (b>>5); \
a -= b; a -= c; a ^= (c>>3); \
b -= c; b -= a; b ^= (a<<10); \
c -= a; c -= b; c ^= (b>>15); \
}
int
hash_rand(int A, int B, int C)
{
mix(A,B,C) ;
return C & 0xffff ;
}
#endif
static double Roughness ;
/* create a pyramid of crystal spheres */
static void
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.
*/
static void
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;
{
long iz;
int half_width, 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, size_factor);
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,
size_factor);
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,
size_factor);
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, size_factor);
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,
size_factor);
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 */
PLATFORM_MULTITASK();
if (width == 1<<size_factor)
PLATFORM_PROGRESS(0, 0, 3);
grow_mountain(fnum_pts, half_width, ll_x, ll_y,
ll_fz, lower_fz, middle_fz, left_fz);
if (width == 1<<size_factor)
PLATFORM_PROGRESS(0, 1, 3);
grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y,
lower_fz, lr_fz, right_fz, middle_fz);
if (width == 1<<size_factor)
PLATFORM_PROGRESS(0, 2, 3);
grow_mountain(fnum_pts, half_width, ll_x+half_width, ll_y+half_width,
middle_fz, right_fz, ur_fz, upper_fz);
if (width == 1<<size_factor)
PLATFORM_PROGRESS(0, 3, 3);
grow_mountain(fnum_pts, half_width, ll_x, ll_y+half_width,
left_fz, middle_fz, upper_fz, ul_fz);
}
}
int
main(argc,argv)
int argc;
char *argv[];
{
int num_pts;
double ratio;
double lscale;
COORD3 back_color, obj_color;
COORD3 from, at, up;
COORD4 light, center;
PLATFORM_INIT(SPD_MOUNT);
/* Start by defining which raytracer we will be using */
if ( lib_gen_get_opts( argc, argv,
&size_factor, &raytracer_format, &output_format )) {
return EXIT_FAIL;
}
if ( lib_open( raytracer_format, "Mount" ) ) {
return EXIT_FAIL;
}
/* output background color - UNC sky blue */
/* NOTE: Do this BEFORE lib_output_viewpoint(), for display_init() */
SET_COORD3(back_color, 0.078, 0.361, 0.753);
lib_output_background_color(back_color);
/* 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, 1.0, 0.01, 512, 512);
/* output light sources */
/*
* For raytracers that don't scale the light intensity,
* we will do it for them
*/
#define NUM_LIGHTS 1
lscale = ( ((raytracer_format==OUTPUT_NFF) || (raytracer_format==OUTPUT_RTRACE))
? 1.0 : 1.0 / sqrt(NUM_LIGHTS));
SET_COORD4(light, -100.0, -100.0, 100.0, lscale);
lib_output_light(light);
/* set up crystal sphere color - clear white */
SET_COORD3(obj_color, 1.0, 1.0, 1.0);
lib_output_color(NULL, obj_color, 0.0, 0.1, 0.1, 0.4, 6.7, 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(NULL, obj_color, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0);
/* grow mountain */
num_pts = 1<<size_factor;
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);
lib_close();
PLATFORM_SHUTDOWN();
return EXIT_SUCCESS;
}