1 | /* -*- Mode: C; c-basic-offset: 4; tab-width: 4 -*- |
---|
2 | * speedmine, Copyright (C) 2001 Conrad Parker <conrad@deephackmode.org> |
---|
3 | * |
---|
4 | * Permission to use, copy, modify, distribute, and sell this software and its |
---|
5 | * documentation for any purpose is hereby granted without fee, provided that |
---|
6 | * the above copyright notice appear in all copies and that both that |
---|
7 | * copyright notice and this permission notice appear in supporting |
---|
8 | * documentation. No representations are made about the suitability of this |
---|
9 | * software for any purpose. It is provided "as is" without express or |
---|
10 | * implied warranty. |
---|
11 | */ |
---|
12 | |
---|
13 | /* |
---|
14 | * Written mostly over the Easter holiday, 2001. Psychedelic option due to |
---|
15 | * a night at Home nightclub, Sydney. Three all-nighters of solid partying |
---|
16 | * were involved in the week this hack was written. |
---|
17 | * |
---|
18 | * Happy Birthday to WierdArms (17 April) and Pat (18 April) |
---|
19 | */ |
---|
20 | |
---|
21 | /* |
---|
22 | * Hacking notes |
---|
23 | * |
---|
24 | * This program generates a rectangular terrain grid and maps this onto |
---|
25 | * a semi-circular tunnel. The terrain has length TERRAIN_LENGTH, which |
---|
26 | * corresponds to length along the tunnel, and breadth TERRAIN_BREADTH, |
---|
27 | * which corresponds to circumference around the tunnel. For each frame, |
---|
28 | * the tunnel is perspective mapped onto a set of X and Y screen values. |
---|
29 | * |
---|
30 | * Throughout this code the following temporary variable names are used: |
---|
31 | * |
---|
32 | * i iterates along the tunnel in the direction of travel |
---|
33 | * j iterates around the tunnel clockwise |
---|
34 | * t iterates along the length of the perspective mapped values |
---|
35 | * from the furthest to the nearest |
---|
36 | * |
---|
37 | * Thus, the buffers are used with these iterators: |
---|
38 | * |
---|
39 | * terrain[i][j] terrain map |
---|
40 | * worldx[i][j], worldy[i][j] world coordinates (after wrapping) |
---|
41 | * {x,y,z}curvature[i] tunnel curvature |
---|
42 | * wideness[i] tunnel wideness |
---|
43 | * bonuses[i] bonus values |
---|
44 | * |
---|
45 | * xvals[t][j], yvals[t][j] screen coordinates |
---|
46 | * {min,max}{x,y}[t] bounding boxes of screen coords |
---|
47 | */ |
---|
48 | |
---|
49 | /* Define or undefine NDEBUG to turn assert and abort debugging off or on */ |
---|
50 | #define NDEBUG |
---|
51 | #include <assert.h> |
---|
52 | |
---|
53 | #include <math.h> |
---|
54 | |
---|
55 | #include "screenhack.h" |
---|
56 | #include "erase.h" |
---|
57 | |
---|
58 | #define MIN(a,b) ((a)<(b)?(a):(b)) |
---|
59 | #define MAX(a,b) ((a)>(b)?(a):(b)) |
---|
60 | |
---|
61 | #define RAND(r) (int)(((r)>0)?(random() % (long)(r)): -(random() % (long)(-r))) |
---|
62 | |
---|
63 | #define SIGN3(a) ((a)>0?1:((a)<0?-1:0)) |
---|
64 | |
---|
65 | #define MODULO(a,b) while ((a)<0) (a)+=(b); (a) %= (b); |
---|
66 | |
---|
67 | static Display * display; |
---|
68 | static Pixmap dbuf, stars_mask; |
---|
69 | static Colormap cmap; |
---|
70 | static unsigned int default_fg_pixel; |
---|
71 | static GC draw_gc, erase_gc, tunnelend_gc, stars_gc, stars_erase_gc; |
---|
72 | |
---|
73 | /* No. of shades of each color (ground, walls, bonuses) */ |
---|
74 | #define MAX_COLORS 32 |
---|
75 | static int ncolors, nr_ground_colors, nr_wall_colors, nr_bonus_colors; |
---|
76 | static XColor ground_colors[MAX_COLORS], wall_colors[MAX_COLORS]; |
---|
77 | static XColor bonus_colors[MAX_COLORS]; |
---|
78 | static GC ground_gcs[MAX_COLORS], wall_gcs[MAX_COLORS], bonus_gcs[MAX_COLORS]; |
---|
79 | |
---|
80 | static int be_wormy; |
---|
81 | |
---|
82 | static int width, height; |
---|
83 | static int delay; |
---|
84 | |
---|
85 | static int smoothness; |
---|
86 | static int verbose_flag; |
---|
87 | static int wire_flag; |
---|
88 | static int terrain_flag; |
---|
89 | static int widening_flag; |
---|
90 | static int bumps_flag; |
---|
91 | static int bonuses_flag; |
---|
92 | static int crosshair_flag; |
---|
93 | static int psychedelic_flag; |
---|
94 | |
---|
95 | #ifdef NDEBUG |
---|
96 | #define DEBUG_FLAG 0 |
---|
97 | #else |
---|
98 | #define DEBUG_FLAG 1 |
---|
99 | #endif |
---|
100 | |
---|
101 | static double maxspeed; |
---|
102 | |
---|
103 | static double thrust, gravity; |
---|
104 | |
---|
105 | static double vertigo; |
---|
106 | static double curviness; |
---|
107 | static double twistiness; |
---|
108 | |
---|
109 | static double pos=0.0; |
---|
110 | static double speed=-1.1; |
---|
111 | static double accel=0.00000001; |
---|
112 | static double step=0.0; |
---|
113 | |
---|
114 | |
---|
115 | #define FORWARDS 1 |
---|
116 | #define BACKWARDS -1 |
---|
117 | static int direction = FORWARDS; |
---|
118 | |
---|
119 | /* Apparently AIX's math.h bogusly defines `nearest' as a function, |
---|
120 | in violation of the ANSI C spec. */ |
---|
121 | #undef nearest |
---|
122 | #define nearest n3arest |
---|
123 | |
---|
124 | static int pindex=0, nearest=0; |
---|
125 | static int flipped_at=0; |
---|
126 | static int xoffset=0, yoffset=0; |
---|
127 | |
---|
128 | static int bonus_bright = 0; |
---|
129 | static int wire_bonus=0; |
---|
130 | #define wireframe (wire_flag||wire_bonus>8||wire_bonus%2==1) |
---|
131 | |
---|
132 | static double speed_bonus=0.0; |
---|
133 | #define effective_speed (direction*(speed+speed_bonus)) |
---|
134 | |
---|
135 | static int spin_bonus = 0; |
---|
136 | static int backwards_bonus = 0; |
---|
137 | |
---|
138 | /* No. of levels of interpolation, for perspective */ |
---|
139 | #define INTERP 32 |
---|
140 | |
---|
141 | /* These must be powers of 2 */ |
---|
142 | #define TERRAIN_LENGTH 256 |
---|
143 | #define TERRAIN_BREADTH 32 |
---|
144 | |
---|
145 | /* total "perspective distance" of terrain */ |
---|
146 | #define TERRAIN_PDIST (INTERP*TERRAIN_LENGTH) |
---|
147 | |
---|
148 | #define ROTS 1024 |
---|
149 | #define TB_MUL (ROTS/TERRAIN_BREADTH) |
---|
150 | static double sintab[ROTS], costab[ROTS]; |
---|
151 | |
---|
152 | static int orientation = (17*ROTS)/22; |
---|
153 | |
---|
154 | static int terrain[TERRAIN_LENGTH][TERRAIN_BREADTH]; |
---|
155 | static double xcurvature[TERRAIN_LENGTH]; |
---|
156 | static double ycurvature[TERRAIN_LENGTH]; |
---|
157 | static double zcurvature[TERRAIN_LENGTH]; |
---|
158 | static int wideness[TERRAIN_LENGTH]; |
---|
159 | static int bonuses[TERRAIN_LENGTH]; |
---|
160 | static int xvals[TERRAIN_LENGTH][TERRAIN_BREADTH]; |
---|
161 | static int yvals[TERRAIN_LENGTH][TERRAIN_BREADTH]; |
---|
162 | static double worldx[TERRAIN_LENGTH][TERRAIN_BREADTH]; |
---|
163 | static double worldy[TERRAIN_LENGTH][TERRAIN_BREADTH]; |
---|
164 | static int minx[TERRAIN_LENGTH], maxx[TERRAIN_LENGTH]; |
---|
165 | static int miny[TERRAIN_LENGTH], maxy[TERRAIN_LENGTH]; |
---|
166 | |
---|
167 | #define random_elevation() (terrain_flag?(random() % 200):0) |
---|
168 | #define random_curvature() (curviness>0.0?((double)(random() % 40)-20)*curviness:0.0) |
---|
169 | #define random_twist() (twistiness>0.0?((double)(random() % 40)-20)*twistiness:0.0) |
---|
170 | #define random_wideness() (widening_flag?(int)(random() % 1200):0) |
---|
171 | |
---|
172 | #define STEEL_ELEVATION 300 |
---|
173 | |
---|
174 | /* a forward declaration ... */ |
---|
175 | static void change_colors(void); |
---|
176 | |
---|
177 | #if HAVE_GETTIMEOFDAY |
---|
178 | static int total_nframes = 0; |
---|
179 | static int nframes = 0; |
---|
180 | static double fps = 0.0; |
---|
181 | static double fps_start, fps_end; |
---|
182 | static struct timeval start_time; |
---|
183 | |
---|
184 | /* |
---|
185 | * get_time () |
---|
186 | * |
---|
187 | * returns the total time elapsed since the beginning of the demo |
---|
188 | */ |
---|
189 | static double get_time(void) { |
---|
190 | struct timeval t; |
---|
191 | float f; |
---|
192 | #if GETTIMEOFDAY_TWO_ARGS |
---|
193 | gettimeofday(&t, NULL); |
---|
194 | #else |
---|
195 | gettimeofday(&t); |
---|
196 | #endif |
---|
197 | t.tv_sec -= start_time.tv_sec; |
---|
198 | f = ((double)t.tv_sec) + t.tv_usec*1e-6; |
---|
199 | return f; |
---|
200 | } |
---|
201 | |
---|
202 | /* |
---|
203 | * init_time () |
---|
204 | * |
---|
205 | * initialises the timing structures |
---|
206 | */ |
---|
207 | static void init_time(void) { |
---|
208 | #if GETTIMEOFDAY_TWO_ARGS |
---|
209 | gettimeofday(&start_time, NULL); |
---|
210 | #else |
---|
211 | gettimeofday(&start_time); |
---|
212 | #endif |
---|
213 | fps_start = get_time(); |
---|
214 | } |
---|
215 | #endif |
---|
216 | |
---|
217 | /* |
---|
218 | * perspective() |
---|
219 | * |
---|
220 | * perspective map the world coordinates worldx[i][j], worldy[i][j] onto |
---|
221 | * screen coordinates xvals[t][j], yvals[t][j] |
---|
222 | */ |
---|
223 | static void |
---|
224 | perspective (void) |
---|
225 | { |
---|
226 | static int rotation_offset=0; |
---|
227 | |
---|
228 | int i, j, jj, t=0, depth, view_pos; |
---|
229 | int rotation_bias, r; |
---|
230 | double xc=0.0, yc=0.0, zc=0.0; |
---|
231 | double xcc=0.0, ycc=0.0, zcc=0.0; |
---|
232 | double xx, yy; |
---|
233 | double zfactor, zf; |
---|
234 | |
---|
235 | zf = 8.0*28.0 / (double)(width*TERRAIN_LENGTH); |
---|
236 | if (be_wormy) zf *= 3.0; |
---|
237 | |
---|
238 | depth = TERRAIN_PDIST - INTERP + pindex; |
---|
239 | |
---|
240 | view_pos = (nearest+3*TERRAIN_LENGTH/4)%TERRAIN_LENGTH; |
---|
241 | |
---|
242 | xoffset += - xcurvature[view_pos]*curviness/8; |
---|
243 | xoffset /= 2; |
---|
244 | |
---|
245 | yoffset += - ycurvature[view_pos]*curviness/4; |
---|
246 | yoffset /= 2; |
---|
247 | |
---|
248 | rotation_offset += (int)((zcurvature[view_pos]-zcurvature[nearest])*ROTS/8); |
---|
249 | rotation_offset /= 2; |
---|
250 | rotation_bias = orientation + spin_bonus - rotation_offset; |
---|
251 | |
---|
252 | if (bumps_flag) { |
---|
253 | if (be_wormy) { |
---|
254 | yoffset -= ((terrain[view_pos][TERRAIN_BREADTH/4] * width /(8*1600))); |
---|
255 | rotation_bias += (terrain[view_pos][TERRAIN_BREADTH/4+2] - |
---|
256 | terrain[view_pos][TERRAIN_BREADTH/4-2])/8; |
---|
257 | } else { |
---|
258 | yoffset -= ((terrain[view_pos][TERRAIN_BREADTH/4] * width /(2*1600))); |
---|
259 | rotation_bias += (terrain[view_pos][TERRAIN_BREADTH/4+2] - |
---|
260 | terrain[view_pos][TERRAIN_BREADTH/4-2])/16; |
---|
261 | } |
---|
262 | } |
---|
263 | |
---|
264 | MODULO(rotation_bias, ROTS); |
---|
265 | |
---|
266 | for (t=0; t < TERRAIN_LENGTH; t++) { |
---|
267 | i = nearest + t; MODULO(i, TERRAIN_LENGTH); |
---|
268 | xc += xcurvature[i]; yc += ycurvature[i]; zc += zcurvature[i]; |
---|
269 | xcc += xc; ycc += yc; zcc += zc; |
---|
270 | maxx[i] = maxy[i] = 0; |
---|
271 | minx[i] = width; miny[i] = height; |
---|
272 | } |
---|
273 | |
---|
274 | for (t=0; t < TERRAIN_LENGTH; t++) { |
---|
275 | i = nearest - 1 - t; MODULO(i, TERRAIN_LENGTH); |
---|
276 | |
---|
277 | zfactor = (double)depth* (12.0 - TERRAIN_LENGTH/8.0) * zf; |
---|
278 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
279 | jj = direction * j; MODULO(jj, TERRAIN_BREADTH); |
---|
280 | /* jwz: not totally sure if this is right, but it avoids div0 */ |
---|
281 | if (zfactor != 0) { |
---|
282 | xx = (worldx[i][jj]-(vertigo*xcc))/zfactor; |
---|
283 | yy = (worldy[i][j]-(vertigo*ycc))/zfactor; |
---|
284 | } else { |
---|
285 | xx = 0; |
---|
286 | yy = 0; |
---|
287 | } |
---|
288 | r = rotation_bias + (int)(vertigo*zcc); MODULO(r, ROTS); |
---|
289 | |
---|
290 | xvals[t][j] = xoffset + width/2 + |
---|
291 | (int)(xx * costab[r] - yy * sintab[r]); |
---|
292 | maxx[t] = MAX(maxx[t], xvals[t][j]); |
---|
293 | minx[t] = MIN(minx[t], xvals[t][j]); |
---|
294 | |
---|
295 | yvals[t][j] = yoffset + height/2 + |
---|
296 | (int)(xx * sintab[r] + yy * costab[r]); |
---|
297 | maxy[t] = MAX(maxy[t], yvals[t][j]); |
---|
298 | miny[t] = MIN(miny[t], yvals[t][j]); |
---|
299 | } |
---|
300 | xcc -= xc; ycc -= yc; zcc -= zc; |
---|
301 | xc -= xcurvature[i]; yc -= ycurvature[i]; zc -= zcurvature[i]; |
---|
302 | depth -= INTERP; |
---|
303 | } |
---|
304 | } |
---|
305 | |
---|
306 | /* |
---|
307 | * wrap_tunnel (start, end) |
---|
308 | * |
---|
309 | * wrap the terrain terrain[i][j] around the semi-circular tunnel function |
---|
310 | * |
---|
311 | * x' = x/2 * cos(theta) - (y-k) * x * sin(theta) |
---|
312 | * y' = x/4 * sin(theta) + y * cos(theta) |
---|
313 | * |
---|
314 | * between i=start and i=end inclusive, producing world coordinates |
---|
315 | * worldx[i][j], worldy[i][j] |
---|
316 | */ |
---|
317 | static void |
---|
318 | wrap_tunnel (int start, int end) |
---|
319 | { |
---|
320 | int i, j, v; |
---|
321 | double x, y; |
---|
322 | |
---|
323 | assert (start < end); |
---|
324 | |
---|
325 | for (i=start; i <= end; i++) { |
---|
326 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
327 | x = j * (1.0/TERRAIN_BREADTH); |
---|
328 | v = terrain[i][j]; |
---|
329 | y = (double)(v==STEEL_ELEVATION?200:v) - wideness[i] - 1200; |
---|
330 | |
---|
331 | /* lower road */ |
---|
332 | if (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8) y -= 300; |
---|
333 | |
---|
334 | worldx[i][j] = x/2 * costab[j*TB_MUL] - |
---|
335 | (y-height/4.0)*x*sintab[j*TB_MUL]; |
---|
336 | worldy[i][j] = x/4 * sintab[j*TB_MUL] + |
---|
337 | y * costab[j*TB_MUL]; |
---|
338 | } |
---|
339 | } |
---|
340 | } |
---|
341 | |
---|
342 | /* |
---|
343 | * flip_direction() |
---|
344 | * |
---|
345 | * perform the state transitions and terrain transformation for the |
---|
346 | * "look backwards/look forwards" bonus |
---|
347 | */ |
---|
348 | static void |
---|
349 | flip_direction (void) |
---|
350 | { |
---|
351 | int i, ip, in, j, t; |
---|
352 | |
---|
353 | direction = -direction; |
---|
354 | |
---|
355 | bonus_bright = 20; |
---|
356 | |
---|
357 | for (i=0; i < TERRAIN_LENGTH; i++) { |
---|
358 | in = nearest + i; MODULO(in, TERRAIN_BREADTH); |
---|
359 | ip = nearest - i; MODULO(ip, TERRAIN_BREADTH); |
---|
360 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
361 | t = terrain[ip][j]; |
---|
362 | terrain[ip][j] = terrain[in][j]; |
---|
363 | terrain[in][j] = t; |
---|
364 | } |
---|
365 | } |
---|
366 | } |
---|
367 | |
---|
368 | /* |
---|
369 | * generate_smooth (start, end) |
---|
370 | * |
---|
371 | * generate smooth terrain between i=start and i=end inclusive |
---|
372 | */ |
---|
373 | static void |
---|
374 | generate_smooth (int start, int end) |
---|
375 | { |
---|
376 | int i,j, ii; |
---|
377 | |
---|
378 | assert (start < end); |
---|
379 | |
---|
380 | for (i=start; i <= end; i++) { |
---|
381 | ii = i; MODULO(ii, TERRAIN_LENGTH); |
---|
382 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
383 | terrain[i][j] = STEEL_ELEVATION; |
---|
384 | } |
---|
385 | } |
---|
386 | } |
---|
387 | |
---|
388 | /* |
---|
389 | * generate_straight (start, end) |
---|
390 | * |
---|
391 | * zero the curvature and wideness between i=start and i=end inclusive |
---|
392 | */ |
---|
393 | static void |
---|
394 | generate_straight (int start, int end) |
---|
395 | { |
---|
396 | int i,j, ii; |
---|
397 | |
---|
398 | assert (start < end); |
---|
399 | |
---|
400 | for (i=start; i <= end; i++) { |
---|
401 | ii = i; MODULO(ii, TERRAIN_LENGTH); |
---|
402 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
403 | xcurvature[ii] = 0; |
---|
404 | ycurvature[ii] = 0; |
---|
405 | zcurvature[ii] = 0; |
---|
406 | wideness[ii] = 0; |
---|
407 | } |
---|
408 | } |
---|
409 | } |
---|
410 | |
---|
411 | /* |
---|
412 | * int generate_terrain_value (v1, v2, v3, v4, w) |
---|
413 | * |
---|
414 | * generate terrain value near the average of v1, v2, v3, v4, with |
---|
415 | * perturbation proportional to w |
---|
416 | */ |
---|
417 | static int |
---|
418 | generate_terrain_value (int v1, int v2, int v3, int v4, int w) |
---|
419 | { |
---|
420 | int sum, ret; |
---|
421 | int rval; |
---|
422 | |
---|
423 | if (!terrain_flag) return 0; |
---|
424 | |
---|
425 | sum = v1 + v2 + v3 + v4; |
---|
426 | |
---|
427 | rval = w*sum/smoothness; |
---|
428 | if (rval == 0) rval = 2; |
---|
429 | |
---|
430 | ret = (sum/4 -(rval/2) + RAND(rval)); |
---|
431 | |
---|
432 | if (ret < -400 || ret > 400) { |
---|
433 | ret = sum/4; |
---|
434 | } |
---|
435 | |
---|
436 | return ret; |
---|
437 | } |
---|
438 | |
---|
439 | /* |
---|
440 | * generate_terrain (start, end, final) |
---|
441 | * |
---|
442 | * generate terrain[i][j] between i=start and i=end inclusive |
---|
443 | * |
---|
444 | * This is performed by successive subdivision of the terrain into |
---|
445 | * rectangles of decreasing size. Subdivision continues until the |
---|
446 | * the minimum width or height of these rectangles is 'final'; ie. |
---|
447 | * final=1 indicates to subdivide as far as possible, final=2 indicates |
---|
448 | * to stop one subdivision before that (leaving a checkerboard pattern |
---|
449 | * uncalculated) etc. |
---|
450 | */ |
---|
451 | static void |
---|
452 | generate_terrain (int start, int end, int final) |
---|
453 | { |
---|
454 | int i,j,w,l; |
---|
455 | int ip, jp, in, jn; /* prev, next values */ |
---|
456 | int diff; |
---|
457 | |
---|
458 | assert (start < end); |
---|
459 | assert (start >= 0 && start < TERRAIN_LENGTH); |
---|
460 | assert (end >= 0 && end < TERRAIN_LENGTH); |
---|
461 | |
---|
462 | diff = end - start + 1; |
---|
463 | |
---|
464 | terrain[end][0] = random_elevation(); |
---|
465 | terrain[end][TERRAIN_BREADTH/2] = random_elevation(); |
---|
466 | |
---|
467 | for (w= diff/2, l=TERRAIN_BREADTH/4; |
---|
468 | w >= final || l >= final; w /= 2, l /= 2) { |
---|
469 | |
---|
470 | if (w<1) w=1; if (l<1) l=1; |
---|
471 | |
---|
472 | for (i=start+w-1; i < end; i += (w*2)) { |
---|
473 | ip = i-w; MODULO(ip, TERRAIN_LENGTH); |
---|
474 | in = i+w; MODULO(in, TERRAIN_LENGTH); |
---|
475 | for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) { |
---|
476 | jp = j-1; MODULO(jp, TERRAIN_BREADTH); |
---|
477 | jn = j+1; MODULO(jn, TERRAIN_BREADTH); |
---|
478 | terrain[i][j] = |
---|
479 | generate_terrain_value (terrain[ip][jp], terrain[in][jp], |
---|
480 | terrain[ip][jn], terrain[in][jn], w); |
---|
481 | } |
---|
482 | } |
---|
483 | |
---|
484 | for (i=start+(w*2)-1; i < end; i += (w*2)) { |
---|
485 | ip = i-w; MODULO(ip, TERRAIN_LENGTH); |
---|
486 | in = i+w; MODULO(in, TERRAIN_LENGTH); |
---|
487 | for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) { |
---|
488 | jp = j-1; MODULO(jp, TERRAIN_BREADTH); |
---|
489 | jn = j+1; MODULO(jn, TERRAIN_BREADTH); |
---|
490 | terrain[i][j] = |
---|
491 | generate_terrain_value (terrain[ip][j], terrain[in][j], |
---|
492 | terrain[i][jp], terrain[i][jn], w); |
---|
493 | } |
---|
494 | } |
---|
495 | |
---|
496 | for (i=start+w-1; i < end; i += (w*2)) { |
---|
497 | ip = i-w; MODULO(ip, TERRAIN_LENGTH); |
---|
498 | in = i+w; MODULO(in, TERRAIN_LENGTH); |
---|
499 | for (j=2*l-1; j < TERRAIN_BREADTH; j += (l*2)) { |
---|
500 | jp = j-1; MODULO(jp, TERRAIN_BREADTH); |
---|
501 | jn = j+1; MODULO(jn, TERRAIN_BREADTH); |
---|
502 | terrain[i][j] = |
---|
503 | generate_terrain_value (terrain[ip][j], terrain[in][j], |
---|
504 | terrain[i][jp], terrain[i][jn], w); |
---|
505 | } |
---|
506 | } |
---|
507 | } |
---|
508 | } |
---|
509 | |
---|
510 | /* |
---|
511 | * double generate_curvature_value (v1, v2, w) |
---|
512 | * |
---|
513 | * generate curvature value near the average of v1 and v2, with perturbation |
---|
514 | * proportional to w |
---|
515 | */ |
---|
516 | static double |
---|
517 | generate_curvature_value (double v1, double v2, int w) |
---|
518 | { |
---|
519 | double sum, avg, diff, ret; |
---|
520 | int rval; |
---|
521 | |
---|
522 | assert (!isnan(v1) && !isnan(v2)); |
---|
523 | |
---|
524 | sum = v1+v2; |
---|
525 | avg = sum/2.0; |
---|
526 | |
---|
527 | diff = MIN(v1 - avg, v2 - avg); |
---|
528 | |
---|
529 | rval = (int)diff * w; |
---|
530 | if (rval == 0.0) return avg; |
---|
531 | |
---|
532 | ret = (avg -((double)rval)/500.0 + ((double)RAND(rval))/1000.0); |
---|
533 | |
---|
534 | assert (!isnan(ret)); |
---|
535 | |
---|
536 | return ret; |
---|
537 | } |
---|
538 | |
---|
539 | /* |
---|
540 | * generate_curves (start, end) |
---|
541 | * |
---|
542 | * generate xcurvature[i], ycurvature[i], zcurvature[i] and wideness[i] |
---|
543 | * between start and end inclusive |
---|
544 | */ |
---|
545 | static void |
---|
546 | generate_curves (int start, int end) |
---|
547 | { |
---|
548 | int i, diff, ii, in, ip, w; |
---|
549 | |
---|
550 | assert (start < end); |
---|
551 | |
---|
552 | diff = end - start + 1; MODULO (diff, TERRAIN_LENGTH); |
---|
553 | |
---|
554 | if (random() % 100 == 0) |
---|
555 | xcurvature[end] = 30 * random_curvature(); |
---|
556 | else if (random() % 10 == 0) |
---|
557 | xcurvature[end] = 20 * random_curvature(); |
---|
558 | else |
---|
559 | xcurvature[end] = 10 * random_curvature(); |
---|
560 | |
---|
561 | if (random() % 50 == 0) |
---|
562 | ycurvature[end] = 20 * random_curvature(); |
---|
563 | else if (random() % 25 == 0) |
---|
564 | ycurvature[end] = 30 * random_curvature(); |
---|
565 | else |
---|
566 | ycurvature[end] = 10 * random_curvature(); |
---|
567 | |
---|
568 | if (random() % 3 == 0) |
---|
569 | zcurvature[end] = random_twist(); |
---|
570 | else |
---|
571 | zcurvature[end] = |
---|
572 | generate_curvature_value (zcurvature[end], random_twist(), 1); |
---|
573 | |
---|
574 | if (be_wormy) |
---|
575 | wideness[end] = random_wideness(); |
---|
576 | else |
---|
577 | wideness[end] = |
---|
578 | generate_curvature_value (wideness[end], random_wideness(), 1); |
---|
579 | |
---|
580 | for (w=diff/2; w >= 1; w /= 2) { |
---|
581 | for (i=start+w-1; i < end; i+=(w*2)) { |
---|
582 | ii = i; MODULO (ii, TERRAIN_LENGTH); |
---|
583 | ip = i-w; MODULO (ip, TERRAIN_LENGTH); |
---|
584 | in = i+w; MODULO (in, TERRAIN_LENGTH); |
---|
585 | xcurvature[ii] = |
---|
586 | generate_curvature_value (xcurvature[ip], xcurvature[in], w); |
---|
587 | ycurvature[ii] = |
---|
588 | generate_curvature_value (ycurvature[ip], ycurvature[in], w); |
---|
589 | zcurvature[ii] = |
---|
590 | generate_curvature_value (zcurvature[ip], zcurvature[in], w); |
---|
591 | wideness[ii] = |
---|
592 | generate_curvature_value (wideness[ip], wideness[in], w); |
---|
593 | } |
---|
594 | } |
---|
595 | } |
---|
596 | |
---|
597 | /* |
---|
598 | * do_bonus () |
---|
599 | * |
---|
600 | * choose a random bonus and perform its state transition |
---|
601 | */ |
---|
602 | static void |
---|
603 | do_bonus (void) |
---|
604 | { |
---|
605 | static int jamming=0; |
---|
606 | |
---|
607 | bonus_bright = 20; |
---|
608 | |
---|
609 | if (jamming > 0) { |
---|
610 | jamming--; |
---|
611 | nearest -= 2; MODULO(nearest, TERRAIN_LENGTH); |
---|
612 | return; |
---|
613 | } |
---|
614 | |
---|
615 | if (psychedelic_flag) change_colors(); |
---|
616 | |
---|
617 | switch (random() % 7) { |
---|
618 | case 0: /* switch to or from wireframe */ |
---|
619 | wire_bonus = (wire_bonus?0:300); |
---|
620 | break; |
---|
621 | case 1: /* speedup */ |
---|
622 | speed_bonus = 40.0; |
---|
623 | break; |
---|
624 | case 2: |
---|
625 | spin_bonus += ROTS; |
---|
626 | break; |
---|
627 | case 3: |
---|
628 | spin_bonus -= ROTS; |
---|
629 | break; |
---|
630 | case 4: /* look backwards / look forwards */ |
---|
631 | flipped_at = nearest; |
---|
632 | flip_direction (); |
---|
633 | backwards_bonus = (backwards_bonus?0:10); |
---|
634 | break; |
---|
635 | case 5: |
---|
636 | change_colors(); |
---|
637 | break; |
---|
638 | case 6: /* jam against the bonus a few times; deja vu! */ |
---|
639 | nearest -= 2; MODULO(nearest, TERRAIN_LENGTH); |
---|
640 | jamming = 3; |
---|
641 | break; |
---|
642 | default: |
---|
643 | assert(0); |
---|
644 | break; |
---|
645 | } |
---|
646 | } |
---|
647 | |
---|
648 | /* |
---|
649 | * check_bonus () |
---|
650 | * |
---|
651 | * check if a bonus has been passed in the last frame, and handle it |
---|
652 | */ |
---|
653 | static void |
---|
654 | check_bonuses (void) |
---|
655 | { |
---|
656 | int i, ii, start, end; |
---|
657 | |
---|
658 | if (!bonuses_flag) return; |
---|
659 | |
---|
660 | if (step >= 0.0) { |
---|
661 | start = nearest; end = nearest + (int)floor(step); |
---|
662 | } else { |
---|
663 | end = nearest; start = nearest + (int)floor(step); |
---|
664 | } |
---|
665 | |
---|
666 | if (be_wormy) { |
---|
667 | start += TERRAIN_LENGTH/4; |
---|
668 | end += TERRAIN_LENGTH/4; |
---|
669 | } |
---|
670 | |
---|
671 | for (i=start; i < end; i++) { |
---|
672 | ii = i; MODULO(ii, TERRAIN_LENGTH); |
---|
673 | if (bonuses[ii] == 1) do_bonus (); |
---|
674 | } |
---|
675 | } |
---|
676 | |
---|
677 | /* |
---|
678 | * decrement_bonuses (double time_per_frame) |
---|
679 | * |
---|
680 | * decrement timers associated with bonuses |
---|
681 | */ |
---|
682 | static void |
---|
683 | decrement_bonuses (double time_per_frame) |
---|
684 | { |
---|
685 | if (!bonuses_flag) return; |
---|
686 | |
---|
687 | if (bonus_bright > 0) bonus_bright-=4; |
---|
688 | if (wire_bonus > 0) wire_bonus--; |
---|
689 | if (speed_bonus > 0) speed_bonus -= 2.0; |
---|
690 | |
---|
691 | if (spin_bonus > 10) spin_bonus -= (int)(step*13.7); |
---|
692 | else if (spin_bonus < -10) spin_bonus += (int)(step*11.3); |
---|
693 | |
---|
694 | if (backwards_bonus > 1) backwards_bonus--; |
---|
695 | else if (backwards_bonus == 1) { |
---|
696 | nearest += 2*(MAX(flipped_at, nearest) - MIN(flipped_at,nearest)); |
---|
697 | MODULO(nearest, TERRAIN_LENGTH); |
---|
698 | flip_direction (); |
---|
699 | backwards_bonus = 0; |
---|
700 | } |
---|
701 | } |
---|
702 | |
---|
703 | /* |
---|
704 | * set_bonuses (start, end) |
---|
705 | * |
---|
706 | * choose if to and where to set a bonus between i=start and i=end inclusive |
---|
707 | */ |
---|
708 | static void |
---|
709 | set_bonuses (int start, int end) |
---|
710 | { |
---|
711 | int i, diff, ii; |
---|
712 | |
---|
713 | if (!bonuses_flag) return; |
---|
714 | |
---|
715 | assert (start < end); |
---|
716 | |
---|
717 | diff = end - start; |
---|
718 | |
---|
719 | for (i=start; i <= end; i++) { |
---|
720 | ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; |
---|
721 | bonuses[ii] = 0; |
---|
722 | } |
---|
723 | if (random() % 4 == 0) { |
---|
724 | i = start + RAND(diff-3); |
---|
725 | ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; |
---|
726 | bonuses[ii] = 2; /* marker */ |
---|
727 | ii = i+3; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH; |
---|
728 | bonuses[ii] = 1; /* real thing */ |
---|
729 | } |
---|
730 | } |
---|
731 | |
---|
732 | /* |
---|
733 | * regenerate_terrain () |
---|
734 | * |
---|
735 | * regenerate a portion of the terrain map of length TERRAIN_LENGTH/4 iff |
---|
736 | * we just passed between two quarters of the terrain. |
---|
737 | * |
---|
738 | * choose the kind of terrain to produce, produce it and wrap the tunnel |
---|
739 | */ |
---|
740 | static void |
---|
741 | regenerate_terrain (void) |
---|
742 | { |
---|
743 | int start, end; |
---|
744 | int passed; |
---|
745 | |
---|
746 | passed = nearest % (TERRAIN_LENGTH/4); |
---|
747 | |
---|
748 | if (speed == 0.0 || |
---|
749 | (speed > 0.0 && passed > (int)step) || |
---|
750 | (speed < 0.0 && (TERRAIN_LENGTH/4)-passed > (int)fabs(step))) { |
---|
751 | |
---|
752 | return; |
---|
753 | } |
---|
754 | |
---|
755 | end = nearest - passed - 1; MODULO(end, TERRAIN_LENGTH); |
---|
756 | start = end - TERRAIN_LENGTH/4 + 1; MODULO(start, TERRAIN_LENGTH); |
---|
757 | |
---|
758 | if (DEBUG_FLAG) printf ("Regenerating [%d - %d]\n", start, end); |
---|
759 | |
---|
760 | set_bonuses (start, end); |
---|
761 | |
---|
762 | switch (random() % 64) { |
---|
763 | case 0: |
---|
764 | case 1: |
---|
765 | generate_terrain (start, end, 1); |
---|
766 | generate_smooth (start, |
---|
767 | start + TERRAIN_LENGTH/8 + (random() % TERRAIN_LENGTH/8)); |
---|
768 | break; |
---|
769 | case 2: |
---|
770 | generate_smooth (start, end); |
---|
771 | generate_terrain (start, end, 4); break; |
---|
772 | case 3: |
---|
773 | generate_smooth (start, end); |
---|
774 | generate_terrain (start, end, 2); break; |
---|
775 | default: |
---|
776 | generate_terrain (start, end, 1); |
---|
777 | } |
---|
778 | |
---|
779 | if (random() % 16 == 0) { |
---|
780 | generate_straight (start, end); |
---|
781 | } else { |
---|
782 | generate_curves (start, end); |
---|
783 | } |
---|
784 | |
---|
785 | wrap_tunnel (start, end); |
---|
786 | } |
---|
787 | |
---|
788 | /* |
---|
789 | * init_terrain () |
---|
790 | * |
---|
791 | * initialise the terrain map for the beginning of the demo |
---|
792 | */ |
---|
793 | static void |
---|
794 | init_terrain (void) |
---|
795 | { |
---|
796 | int i, j; |
---|
797 | |
---|
798 | for (i=0; i < TERRAIN_LENGTH; i++) { |
---|
799 | for (j=0; j < TERRAIN_BREADTH; j++) { |
---|
800 | terrain[i][j] = 0; |
---|
801 | } |
---|
802 | } |
---|
803 | |
---|
804 | terrain[TERRAIN_LENGTH-1][0] = - (random() % 300); |
---|
805 | terrain[TERRAIN_LENGTH-1][TERRAIN_BREADTH/2] = - (random() % 300); |
---|
806 | |
---|
807 | generate_smooth (0, TERRAIN_LENGTH-1); |
---|
808 | generate_terrain (0, TERRAIN_LENGTH/4 -1, 4); |
---|
809 | generate_terrain (TERRAIN_LENGTH/4, TERRAIN_LENGTH/2 -1, 2); |
---|
810 | generate_terrain (TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4 -1, 1); |
---|
811 | generate_smooth (3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1); |
---|
812 | } |
---|
813 | |
---|
814 | /* |
---|
815 | * init_curves () |
---|
816 | * |
---|
817 | * initialise the curvatures and wideness for the beginning of the demo. |
---|
818 | */ |
---|
819 | static void |
---|
820 | init_curves (void) |
---|
821 | { |
---|
822 | int i; |
---|
823 | |
---|
824 | for (i=0; i < TERRAIN_LENGTH-1; i++) { |
---|
825 | xcurvature[i] = 0.0; |
---|
826 | ycurvature[i] = 0.0; |
---|
827 | zcurvature[i] = 0.0; |
---|
828 | } |
---|
829 | |
---|
830 | xcurvature[TERRAIN_LENGTH-1] = random_curvature(); |
---|
831 | ycurvature[TERRAIN_LENGTH-1] = random_curvature(); |
---|
832 | zcurvature[TERRAIN_LENGTH-1] = random_twist(); |
---|
833 | |
---|
834 | generate_straight (0, TERRAIN_LENGTH/4-1); |
---|
835 | generate_curves (TERRAIN_LENGTH/4, TERRAIN_LENGTH/2-1); |
---|
836 | generate_curves (TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4-1); |
---|
837 | generate_straight (3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1); |
---|
838 | |
---|
839 | } |
---|
840 | |
---|
841 | /* |
---|
842 | * render_quads (dpy, d, t, dt, i) |
---|
843 | * |
---|
844 | * renders the quadrilaterals from perspective depth t to t+dt. |
---|
845 | * i is passed as a hint, where i corresponds to t as asserted. |
---|
846 | */ |
---|
847 | static void |
---|
848 | render_quads (Display * dpy, Drawable d, int t, int dt, int i) |
---|
849 | { |
---|
850 | int j, t2, j2, in; |
---|
851 | int index; |
---|
852 | XPoint points[4]; |
---|
853 | GC gc; |
---|
854 | |
---|
855 | assert (i == (nearest - (t + dt) + TERRAIN_LENGTH) % TERRAIN_LENGTH); |
---|
856 | |
---|
857 | in = i + 1; MODULO(in, TERRAIN_LENGTH); |
---|
858 | |
---|
859 | for (j=0; j < TERRAIN_BREADTH; j+=dt) { |
---|
860 | t2 = t+dt; if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH; |
---|
861 | j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH; |
---|
862 | points[0].x = xvals[t][j]; points[0].y = yvals[t][j]; |
---|
863 | points[1].x = xvals[t2][j]; points[1].y = yvals[t2][j]; |
---|
864 | points[2].x = xvals[t2][j2]; points[2].y = yvals[t2][j2]; |
---|
865 | points[3].x = xvals[t][j2]; points[3].y = yvals[t][j2]; |
---|
866 | |
---|
867 | index = bonus_bright + ncolors/3 + |
---|
868 | t*(t*INTERP + pindex) * ncolors / |
---|
869 | (3*TERRAIN_LENGTH*TERRAIN_PDIST); |
---|
870 | if (!wireframe) { |
---|
871 | index += (int)((points[0].y - points[3].y) / 8); |
---|
872 | index += (int)((worldx[i][j] - worldx[in][j]) / 40); |
---|
873 | index += (int)((terrain[in][j] - terrain[i][j]) / 100); |
---|
874 | } |
---|
875 | if (be_wormy && psychedelic_flag) index += ncolors/4; |
---|
876 | |
---|
877 | index = MIN (index, ncolors-1); |
---|
878 | index = MAX (index, 0); |
---|
879 | |
---|
880 | if (bonuses[i]) { |
---|
881 | XSetClipMask (dpy, bonus_gcs[index], None); |
---|
882 | } |
---|
883 | |
---|
884 | if (wireframe) { |
---|
885 | if (bonuses[i]) gc = bonus_gcs[index]; |
---|
886 | else gc = ground_gcs[index]; |
---|
887 | XDrawLines (dpy, d, gc, points, 4, CoordModeOrigin); |
---|
888 | } else { |
---|
889 | if (bonuses[i]) |
---|
890 | gc = bonus_gcs[index]; |
---|
891 | else if ((direction>0 && j < TERRAIN_BREADTH/8) || |
---|
892 | (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) || |
---|
893 | (direction < 0 && j > 3*TERRAIN_BREADTH/8-1 && |
---|
894 | j < TERRAIN_BREADTH/2) || |
---|
895 | terrain[i][j] == STEEL_ELEVATION || |
---|
896 | wideness[in] - wideness[i] > 200) |
---|
897 | gc = ground_gcs[index]; |
---|
898 | else |
---|
899 | gc = wall_gcs[index]; |
---|
900 | |
---|
901 | XFillPolygon (dpy, d, gc, points, 4, Nonconvex, CoordModeOrigin); |
---|
902 | } |
---|
903 | } |
---|
904 | } |
---|
905 | |
---|
906 | /* |
---|
907 | * render_pentagons (dpy, d, t, dt, i) |
---|
908 | * |
---|
909 | * renders the pentagons from perspective depth t to t+dt. |
---|
910 | * i is passed as a hint, where i corresponds to t as asserted. |
---|
911 | */ |
---|
912 | static void |
---|
913 | render_pentagons (Display *dpy, Drawable d, int t, int dt, int i) |
---|
914 | { |
---|
915 | int j, t2, j2, j3, in; |
---|
916 | int index; |
---|
917 | XPoint points[5]; |
---|
918 | GC gc; |
---|
919 | |
---|
920 | assert (i == (nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH); |
---|
921 | |
---|
922 | in = i + 1; MODULO(in, TERRAIN_LENGTH); |
---|
923 | |
---|
924 | for (j=0; j < TERRAIN_BREADTH; j+=dt*2) { |
---|
925 | t2 = t+(dt*2); if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH; |
---|
926 | j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH; |
---|
927 | j3 = j+dt+dt; if (j3 >= TERRAIN_BREADTH) j3 -= TERRAIN_BREADTH; |
---|
928 | points[0].x = xvals[t][j]; points[0].y = yvals[t][j]; |
---|
929 | points[1].x = xvals[t2][j]; points[1].y = yvals[t2][j]; |
---|
930 | points[2].x = xvals[t2][j2]; points[2].y = yvals[t2][j2]; |
---|
931 | points[3].x = xvals[t2][j3]; points[3].y = yvals[t2][j3]; |
---|
932 | points[4].x = xvals[t][j3]; points[4].y = yvals[t][j3]; |
---|
933 | |
---|
934 | index = bonus_bright + ncolors/3 + |
---|
935 | t*(t*INTERP + pindex) * ncolors / |
---|
936 | (3*TERRAIN_LENGTH*TERRAIN_PDIST); |
---|
937 | if (!wireframe) { |
---|
938 | index += (int)((points[0].y - points[3].y) / 8); |
---|
939 | index += (int)((worldx[i][j] - worldx[in][j]) / 40); |
---|
940 | index += (int)((terrain[in][j] - terrain[i][j]) / 100); |
---|
941 | } |
---|
942 | if (be_wormy && psychedelic_flag) index += ncolors/4; |
---|
943 | |
---|
944 | index = MIN (index, ncolors-1); |
---|
945 | index = MAX (index, 0); |
---|
946 | |
---|
947 | if (bonuses[i]) { |
---|
948 | XSetClipMask (dpy, bonus_gcs[index], None); |
---|
949 | } |
---|
950 | |
---|
951 | if (wireframe) { |
---|
952 | if (bonuses[i]) gc = bonus_gcs[index]; |
---|
953 | else gc = ground_gcs[index]; |
---|
954 | XDrawLines (dpy, d, gc, points, 5, CoordModeOrigin); |
---|
955 | } else { |
---|
956 | if (bonuses[i]) |
---|
957 | gc = bonus_gcs[index]; |
---|
958 | else if (j < TERRAIN_BREADTH/8 || |
---|
959 | (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) || |
---|
960 | terrain[i][j] == STEEL_ELEVATION || |
---|
961 | wideness[in] - wideness[i] > 200) |
---|
962 | gc = ground_gcs[index]; |
---|
963 | else |
---|
964 | gc = wall_gcs[index]; |
---|
965 | |
---|
966 | XFillPolygon (dpy, d, gc, points, 5, Complex, CoordModeOrigin); |
---|
967 | } |
---|
968 | } |
---|
969 | } |
---|
970 | |
---|
971 | /* |
---|
972 | * render_block (dpy, d, gc, t) |
---|
973 | * |
---|
974 | * render a filled polygon at perspective depth t using the given GC |
---|
975 | */ |
---|
976 | static void |
---|
977 | render_block (Display * dpy, Drawable d, GC gc, int t) |
---|
978 | { |
---|
979 | int i; |
---|
980 | |
---|
981 | XPoint erase_points[TERRAIN_BREADTH/2]; |
---|
982 | |
---|
983 | for (i=0; i < TERRAIN_BREADTH/2; i++) { |
---|
984 | erase_points[i].x = xvals[t][i*2]; |
---|
985 | erase_points[i].y = yvals[t][i*2]; |
---|
986 | } |
---|
987 | |
---|
988 | XFillPolygon (dpy, d, gc, erase_points, |
---|
989 | TERRAIN_BREADTH/2, Complex, CoordModeOrigin); |
---|
990 | } |
---|
991 | |
---|
992 | /* |
---|
993 | * regenerate_stars_mask (dpy, t) |
---|
994 | * |
---|
995 | * regenerate the clip mask 'stars_mask' for drawing the bonus stars at |
---|
996 | * random positions within the bounding box at depth t |
---|
997 | */ |
---|
998 | static void |
---|
999 | regenerate_stars_mask (Display * dpy, int t) |
---|
1000 | { |
---|
1001 | int i, w, h, a, b, l1, l2; |
---|
1002 | const int lim = width*TERRAIN_LENGTH/(300*(TERRAIN_LENGTH-t)); |
---|
1003 | |
---|
1004 | w = maxx[t] - minx[t]; |
---|
1005 | h = maxy[t] - miny[t]; |
---|
1006 | |
---|
1007 | if (w<6||h<6) return; |
---|
1008 | |
---|
1009 | XFillRectangle (dpy, stars_mask, stars_erase_gc, |
---|
1010 | 0, 0, width, height); |
---|
1011 | |
---|
1012 | l1 = (t>3*TERRAIN_LENGTH/4?2:1); |
---|
1013 | l2 = (t>7*TERRAIN_LENGTH/8?2:1); |
---|
1014 | |
---|
1015 | for (i=0; i < lim; i++) { |
---|
1016 | a = RAND(w); b = RAND(h); |
---|
1017 | XDrawLine (dpy, stars_mask, stars_gc, |
---|
1018 | minx[t]+a-l1, miny[t]+b, minx[t]+a+l1, miny[t]+b); |
---|
1019 | XDrawLine (dpy, stars_mask, stars_gc, |
---|
1020 | minx[t]+a, miny[t]+b-l1, minx[t]+a, miny[t]+b+l1); |
---|
1021 | } |
---|
1022 | for (i=0; i < lim; i++) { |
---|
1023 | a = RAND(w); b = RAND(h); |
---|
1024 | XDrawLine (dpy, stars_mask, stars_gc, |
---|
1025 | minx[t]+a-l2, miny[t]+b, minx[t]+a+l2, miny[t]+b); |
---|
1026 | XDrawLine (dpy, stars_mask, stars_gc, |
---|
1027 | minx[t]+a, miny[t]+b-l2, minx[t]+a, miny[t]+b+l2); |
---|
1028 | } |
---|
1029 | } |
---|
1030 | |
---|
1031 | /* |
---|
1032 | * render_bonus_block (dpy, d, t, i) |
---|
1033 | * |
---|
1034 | * draw the bonus stars at depth t. |
---|
1035 | * i is passed as a hint, where i corresponds to t as asserted. |
---|
1036 | */ |
---|
1037 | static void |
---|
1038 | render_bonus_block (Display * dpy, Drawable d, int t, int i) |
---|
1039 | { |
---|
1040 | int bt; |
---|
1041 | |
---|
1042 | assert (i == (nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH); |
---|
1043 | |
---|
1044 | if (!bonuses[i] || wireframe) return; |
---|
1045 | |
---|
1046 | regenerate_stars_mask (dpy, t); |
---|
1047 | |
---|
1048 | bt = t * nr_bonus_colors / (2*TERRAIN_LENGTH); |
---|
1049 | |
---|
1050 | XSetClipMask (dpy, bonus_gcs[bt], stars_mask); |
---|
1051 | |
---|
1052 | render_block (dpy, d, bonus_gcs[bt], t); |
---|
1053 | } |
---|
1054 | |
---|
1055 | static int |
---|
1056 | begin_at (void) |
---|
1057 | { |
---|
1058 | int t; |
---|
1059 | int max_minx=0, min_maxx=width, max_miny=0, min_maxy=height; |
---|
1060 | |
---|
1061 | for (t=TERRAIN_LENGTH-1; t > 0; t--) { |
---|
1062 | max_minx = MAX (max_minx, minx[t]); |
---|
1063 | min_maxx = MIN (min_maxx, maxx[t]); |
---|
1064 | max_miny = MAX (max_miny, miny[t]); |
---|
1065 | min_maxy = MIN (min_maxy, maxy[t]); |
---|
1066 | |
---|
1067 | if (max_miny >= min_maxy || max_minx >= min_maxx) break; |
---|
1068 | } |
---|
1069 | |
---|
1070 | return t; |
---|
1071 | } |
---|
1072 | |
---|
1073 | /* |
---|
1074 | * render_speedmine (dpy, d) |
---|
1075 | * |
---|
1076 | * render the current frame. |
---|
1077 | */ |
---|
1078 | static void |
---|
1079 | render_speedmine (Display * dpy, Drawable d) |
---|
1080 | { |
---|
1081 | int t, i=nearest, dt=1; |
---|
1082 | GC gc; |
---|
1083 | |
---|
1084 | assert (nearest >= 0 && nearest < TERRAIN_LENGTH); |
---|
1085 | |
---|
1086 | if (be_wormy || wireframe) { |
---|
1087 | XFillRectangle (dpy, d, erase_gc, 0, 0, width, height); |
---|
1088 | |
---|
1089 | dt=4; |
---|
1090 | for (t=0; t < TERRAIN_LENGTH/4; t+=dt) { |
---|
1091 | render_bonus_block (dpy, d, t, i); |
---|
1092 | i -= dt; MODULO(i, TERRAIN_LENGTH); |
---|
1093 | render_quads (dpy, d, t, dt, i); |
---|
1094 | } |
---|
1095 | |
---|
1096 | assert (t == TERRAIN_LENGTH/4); |
---|
1097 | } else { |
---|
1098 | t = MAX(begin_at(), TERRAIN_LENGTH/4); |
---|
1099 | /*t = TERRAIN_LENGTH/4; dt = 2; */ |
---|
1100 | dt = (t >= 3*TERRAIN_LENGTH/4 ? 1 : 2); |
---|
1101 | i = (nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH; |
---|
1102 | render_block (dpy, d, tunnelend_gc, t); |
---|
1103 | } |
---|
1104 | |
---|
1105 | dt=2; |
---|
1106 | |
---|
1107 | if (t == TERRAIN_LENGTH/4) |
---|
1108 | render_pentagons (dpy, d, t, dt, i); |
---|
1109 | |
---|
1110 | for (; t < 3*TERRAIN_LENGTH/4; t+=dt) { |
---|
1111 | render_bonus_block (dpy, d, t, i); |
---|
1112 | i -= dt; MODULO(i, TERRAIN_LENGTH); |
---|
1113 | render_quads (dpy, d, t, dt, i); |
---|
1114 | } |
---|
1115 | |
---|
1116 | dt=1; |
---|
1117 | if (be_wormy) { |
---|
1118 | for (; t < TERRAIN_LENGTH-(1+(pindex<INTERP/2)); t+=dt) { |
---|
1119 | render_bonus_block (dpy, d, t, i); |
---|
1120 | i -= dt; MODULO(i, TERRAIN_LENGTH); |
---|
1121 | } |
---|
1122 | } else { |
---|
1123 | if (wireframe) {assert (t == 3*TERRAIN_LENGTH/4);} |
---|
1124 | |
---|
1125 | if (t == 3*TERRAIN_LENGTH/4) |
---|
1126 | render_pentagons (dpy, d, t, dt, i); |
---|
1127 | |
---|
1128 | for (; t < TERRAIN_LENGTH-(1+(pindex<INTERP/2)); t+=dt) { |
---|
1129 | render_bonus_block (dpy, d, t, i); |
---|
1130 | i -= dt; MODULO(i, TERRAIN_LENGTH); |
---|
1131 | render_quads (dpy, d, t, dt, i); |
---|
1132 | } |
---|
1133 | } |
---|
1134 | |
---|
1135 | /* Draw crosshair */ |
---|
1136 | if (crosshair_flag) { |
---|
1137 | gc = (wireframe ? bonus_gcs[nr_bonus_colors/2] : erase_gc); |
---|
1138 | XFillRectangle (dpy, d, gc, |
---|
1139 | width/2+(xoffset)-8, height/2+(yoffset*2)-1, 16, 3); |
---|
1140 | XFillRectangle (dpy, d, gc, |
---|
1141 | width/2+(xoffset)-1, height/2+(yoffset*2)-8, 3, 16); |
---|
1142 | } |
---|
1143 | |
---|
1144 | } |
---|
1145 | |
---|
1146 | /* |
---|
1147 | * move (step) |
---|
1148 | * |
---|
1149 | * move to the position for the next frame, and modify the state variables |
---|
1150 | * nearest, pindex, pos, speed |
---|
1151 | */ |
---|
1152 | static void |
---|
1153 | move (double step) |
---|
1154 | { |
---|
1155 | double dpos; |
---|
1156 | |
---|
1157 | pos += step; |
---|
1158 | dpos = SIGN3(pos) * floor(fabs(pos)); |
---|
1159 | |
---|
1160 | pindex += SIGN3(effective_speed) + INTERP; |
---|
1161 | while (pindex >= INTERP) { |
---|
1162 | nearest --; |
---|
1163 | pindex -= INTERP; |
---|
1164 | } |
---|
1165 | while (pindex < 0) { |
---|
1166 | nearest ++; |
---|
1167 | pindex += INTERP; |
---|
1168 | } |
---|
1169 | |
---|
1170 | nearest += dpos; MODULO(nearest, TERRAIN_LENGTH); |
---|
1171 | |
---|
1172 | pos -= dpos; |
---|
1173 | |
---|
1174 | accel = thrust + ycurvature[nearest] * gravity; |
---|
1175 | speed += accel; |
---|
1176 | if (speed > maxspeed) speed = maxspeed; |
---|
1177 | if (speed < -maxspeed) speed = -maxspeed; |
---|
1178 | } |
---|
1179 | |
---|
1180 | /* |
---|
1181 | * speedmine (dpy, window) |
---|
1182 | * |
---|
1183 | * do everything required for one frame of the demo |
---|
1184 | */ |
---|
1185 | static void |
---|
1186 | speedmine (Display *dpy, Window window) |
---|
1187 | { |
---|
1188 | double elapsed, time_per_frame = 0.04; |
---|
1189 | |
---|
1190 | regenerate_terrain (); |
---|
1191 | |
---|
1192 | perspective (); |
---|
1193 | |
---|
1194 | render_speedmine (dpy, dbuf); |
---|
1195 | XCopyArea (dpy, dbuf, window, draw_gc, 0, 0, width, height, 0, 0); |
---|
1196 | |
---|
1197 | #if HAVE_GETTIMEOFDAY |
---|
1198 | fps_end = get_time(); |
---|
1199 | nframes++; |
---|
1200 | total_nframes++; |
---|
1201 | |
---|
1202 | if (fps_end > fps_start + 0.5) { |
---|
1203 | elapsed = fps_end - fps_start; |
---|
1204 | fps_start = get_time(); |
---|
1205 | |
---|
1206 | time_per_frame = elapsed / nframes - delay*1e-6; |
---|
1207 | fps = nframes / elapsed; |
---|
1208 | if (DEBUG_FLAG) { |
---|
1209 | printf ("%f s elapsed\t%3f s/frame\t%.1f FPS\n", elapsed, |
---|
1210 | time_per_frame, fps); |
---|
1211 | } |
---|
1212 | step = effective_speed * elapsed; |
---|
1213 | |
---|
1214 | nframes = 0; |
---|
1215 | } |
---|
1216 | #else |
---|
1217 | time_per_frame = 0.04; |
---|
1218 | step = effective_speed; |
---|
1219 | #endif |
---|
1220 | |
---|
1221 | move (step); |
---|
1222 | |
---|
1223 | decrement_bonuses (time_per_frame); |
---|
1224 | |
---|
1225 | check_bonuses (); |
---|
1226 | } |
---|
1227 | |
---|
1228 | /* |
---|
1229 | * speedmine_color_ramp (dpy, cmap, gcs, colors, ncolors, s1, s2, v1, v2) |
---|
1230 | * |
---|
1231 | * generate a color ramp of up to *ncolors between randomly chosen hues, |
---|
1232 | * varying from saturation s1 to s2 and value v1 to v2, placing the colors |
---|
1233 | * in 'colors' and creating corresponding GCs in 'gcs'. |
---|
1234 | * |
---|
1235 | * The number of colors actually allocated is returned in ncolors. |
---|
1236 | */ |
---|
1237 | static void |
---|
1238 | speedmine_color_ramp (Display * dpy, Colormap cmap, GC *gcs, XColor * colors, |
---|
1239 | int *ncolors, double s1, double s2, double v1, double v2) |
---|
1240 | { |
---|
1241 | XGCValues gcv; |
---|
1242 | int h1, h2; |
---|
1243 | unsigned long flags; |
---|
1244 | int i; |
---|
1245 | |
---|
1246 | assert (*ncolors >= 0); |
---|
1247 | assert (s1 >= 0.0 && s1 <= 1.0 && v1 >= 0.0 && v2 <= 1.0); |
---|
1248 | |
---|
1249 | if (psychedelic_flag) { |
---|
1250 | h1 = RAND(360); h2 = (h1 + 180) % 360; |
---|
1251 | } else { |
---|
1252 | h1 = h2 = RAND(360); |
---|
1253 | } |
---|
1254 | |
---|
1255 | make_color_ramp (dpy, cmap, h1, s1, v1, h2, s2, v2, |
---|
1256 | colors, ncolors, False, True, False); |
---|
1257 | |
---|
1258 | flags = GCForeground; |
---|
1259 | for (i=0; i < *ncolors; i++) { |
---|
1260 | gcv.foreground = colors[i].pixel; |
---|
1261 | gcs[i] = XCreateGC (dpy, dbuf, flags, &gcv); |
---|
1262 | } |
---|
1263 | |
---|
1264 | } |
---|
1265 | |
---|
1266 | /* |
---|
1267 | * change_colors () |
---|
1268 | * |
---|
1269 | * perform the color changing bonus. New colors are allocated for the |
---|
1270 | * walls and bonuses, and if the 'psychedelic' option is set then new |
---|
1271 | * colors are also chosen for the ground. |
---|
1272 | */ |
---|
1273 | static void |
---|
1274 | change_colors (void) |
---|
1275 | { |
---|
1276 | double s1, s2; |
---|
1277 | |
---|
1278 | if (psychedelic_flag) { |
---|
1279 | free_colors (display, cmap, bonus_colors, nr_bonus_colors); |
---|
1280 | free_colors (display, cmap, wall_colors, nr_wall_colors); |
---|
1281 | free_colors (display, cmap, ground_colors, nr_ground_colors); |
---|
1282 | ncolors = MAX_COLORS; |
---|
1283 | |
---|
1284 | s1 = 0.4; s2 = 0.9; |
---|
1285 | |
---|
1286 | speedmine_color_ramp (display, cmap, ground_gcs, ground_colors, |
---|
1287 | &ncolors, 0.0, 0.8, 0.0, 0.9); |
---|
1288 | nr_ground_colors = ncolors; |
---|
1289 | } else { |
---|
1290 | free_colors (display, cmap, bonus_colors, nr_bonus_colors); |
---|
1291 | free_colors (display, cmap, wall_colors, nr_wall_colors); |
---|
1292 | ncolors = nr_ground_colors; |
---|
1293 | |
---|
1294 | s1 = 0.0; s2 = 0.6; |
---|
1295 | } |
---|
1296 | |
---|
1297 | speedmine_color_ramp (display, cmap, wall_gcs, wall_colors, &ncolors, |
---|
1298 | s1, s2, 0.0, 0.9); |
---|
1299 | nr_wall_colors = ncolors; |
---|
1300 | |
---|
1301 | speedmine_color_ramp (display, cmap, bonus_gcs, bonus_colors, &ncolors, |
---|
1302 | 0.6, 0.9, 0.4, 1.0); |
---|
1303 | nr_bonus_colors = ncolors; |
---|
1304 | } |
---|
1305 | |
---|
1306 | /* |
---|
1307 | * init_psychedelic_colors (dpy, window, cmap) |
---|
1308 | * |
---|
1309 | * initialise a psychedelic colormap |
---|
1310 | */ |
---|
1311 | static void |
---|
1312 | init_psychedelic_colors (Display * dpy, Window window, Colormap cmap) |
---|
1313 | { |
---|
1314 | XGCValues gcv; |
---|
1315 | |
---|
1316 | gcv.foreground = get_pixel_resource ("tunnelend", "TunnelEnd", dpy, cmap); |
---|
1317 | tunnelend_gc = XCreateGC (dpy, window, GCForeground, &gcv); |
---|
1318 | |
---|
1319 | ncolors = MAX_COLORS; |
---|
1320 | |
---|
1321 | speedmine_color_ramp (dpy, cmap, ground_gcs, ground_colors, &ncolors, |
---|
1322 | 0.0, 0.8, 0.0, 0.9); |
---|
1323 | nr_ground_colors = ncolors; |
---|
1324 | |
---|
1325 | speedmine_color_ramp (dpy, cmap, wall_gcs, wall_colors, &ncolors, |
---|
1326 | 0.0, 0.6, 0.0, 0.9); |
---|
1327 | nr_wall_colors = ncolors; |
---|
1328 | |
---|
1329 | speedmine_color_ramp (dpy, cmap, bonus_gcs, bonus_colors, &ncolors, |
---|
1330 | 0.6, 0.9, 0.4, 1.0); |
---|
1331 | nr_bonus_colors = ncolors; |
---|
1332 | } |
---|
1333 | |
---|
1334 | /* |
---|
1335 | * init_colors (dpy, window, cmap) |
---|
1336 | * |
---|
1337 | * initialise a normal colormap |
---|
1338 | */ |
---|
1339 | static void |
---|
1340 | init_colors (Display * dpy, Window window, Colormap cmap) |
---|
1341 | { |
---|
1342 | XGCValues gcv; |
---|
1343 | XColor dark, light; |
---|
1344 | int h1, h2; |
---|
1345 | double s1, s2, v1, v2; |
---|
1346 | unsigned long flags; |
---|
1347 | int i; |
---|
1348 | |
---|
1349 | gcv.foreground = get_pixel_resource ("tunnelend", "TunnelEnd", dpy, cmap); |
---|
1350 | tunnelend_gc = XCreateGC (dpy, window, GCForeground, &gcv); |
---|
1351 | |
---|
1352 | ncolors = MAX_COLORS; |
---|
1353 | |
---|
1354 | dark.pixel = get_pixel_resource ("darkground", "DarkGround", dpy, cmap); |
---|
1355 | XQueryColor (dpy, cmap, &dark); |
---|
1356 | |
---|
1357 | light.pixel = get_pixel_resource ("lightground", "LightGround", dpy, cmap); |
---|
1358 | XQueryColor (dpy, cmap, &light); |
---|
1359 | |
---|
1360 | rgb_to_hsv (dark.red, dark.green, dark.blue, &h1, &s1, &v1); |
---|
1361 | rgb_to_hsv (light.red, light.green, light.blue, &h2, &s2, &v2); |
---|
1362 | make_color_ramp (dpy, cmap, h1, s1, v1, h2, s2, v2, |
---|
1363 | ground_colors, &ncolors, False, True, False); |
---|
1364 | nr_ground_colors = ncolors; |
---|
1365 | |
---|
1366 | flags = GCForeground; |
---|
1367 | for (i=0; i < ncolors; i++) { |
---|
1368 | gcv.foreground = ground_colors[i].pixel; |
---|
1369 | ground_gcs[i] = XCreateGC (dpy, dbuf, flags, &gcv); |
---|
1370 | } |
---|
1371 | |
---|
1372 | speedmine_color_ramp (dpy, cmap, wall_gcs, wall_colors, &ncolors, |
---|
1373 | 0.0, 0.6, 0.0, 0.9); |
---|
1374 | nr_wall_colors = ncolors; |
---|
1375 | |
---|
1376 | speedmine_color_ramp (dpy, cmap, bonus_gcs, bonus_colors, &ncolors, |
---|
1377 | 0.6, 0.9, 0.4, 1.0); |
---|
1378 | nr_bonus_colors = ncolors; |
---|
1379 | } |
---|
1380 | |
---|
1381 | /* |
---|
1382 | * print_stats () |
---|
1383 | * |
---|
1384 | * print out average FPS stats for the demo |
---|
1385 | */ |
---|
1386 | static void |
---|
1387 | print_stats (void) |
---|
1388 | { |
---|
1389 | if (total_nframes >= 1) |
---|
1390 | printf ("Rendered %d frames averaging %f FPS\n", total_nframes, |
---|
1391 | total_nframes / get_time()); |
---|
1392 | } |
---|
1393 | |
---|
1394 | /* |
---|
1395 | * init_speedmine (dpy, window) |
---|
1396 | * |
---|
1397 | * initialise the demo |
---|
1398 | */ |
---|
1399 | static void |
---|
1400 | init_speedmine (Display *dpy, Window window) |
---|
1401 | { |
---|
1402 | XGCValues gcv; |
---|
1403 | XWindowAttributes xgwa; |
---|
1404 | int i; |
---|
1405 | double th; |
---|
1406 | int wide; |
---|
1407 | |
---|
1408 | display = dpy; |
---|
1409 | |
---|
1410 | XGetWindowAttributes (dpy, window, &xgwa); |
---|
1411 | cmap = xgwa.colormap; |
---|
1412 | width = xgwa.width; |
---|
1413 | height = xgwa.height; |
---|
1414 | |
---|
1415 | verbose_flag = get_boolean_resource ("verbose", "Boolean"); |
---|
1416 | |
---|
1417 | dbuf = XCreatePixmap (dpy, window, width, height, xgwa.depth); |
---|
1418 | stars_mask = XCreatePixmap (dpy, window, width, height, 1); |
---|
1419 | |
---|
1420 | gcv.foreground = default_fg_pixel = |
---|
1421 | get_pixel_resource ("foreground", "Foreground", dpy, cmap); |
---|
1422 | draw_gc = XCreateGC (dpy, window, GCForeground, &gcv); |
---|
1423 | stars_gc = XCreateGC (dpy, stars_mask, GCForeground, &gcv); |
---|
1424 | |
---|
1425 | gcv.foreground = get_pixel_resource ("background", "Background", dpy, cmap); |
---|
1426 | erase_gc = XCreateGC (dpy, dbuf, GCForeground, &gcv); |
---|
1427 | stars_erase_gc = XCreateGC (dpy, stars_mask, GCForeground, &gcv); |
---|
1428 | |
---|
1429 | wire_flag = get_boolean_resource ("wire", "Boolean"); |
---|
1430 | |
---|
1431 | psychedelic_flag = get_boolean_resource ("psychedelic", "Boolean"); |
---|
1432 | |
---|
1433 | delay = get_integer_resource("delay", "Integer"); |
---|
1434 | |
---|
1435 | smoothness = get_integer_resource("smoothness", "Integer"); |
---|
1436 | if (smoothness < 1) smoothness = 1; |
---|
1437 | |
---|
1438 | maxspeed = get_float_resource("maxspeed", "Float"); |
---|
1439 | maxspeed *= 0.01; |
---|
1440 | maxspeed = fabs(maxspeed); |
---|
1441 | |
---|
1442 | thrust = get_float_resource("thrust", "Float"); |
---|
1443 | thrust *= 0.2; |
---|
1444 | |
---|
1445 | gravity = get_float_resource("gravity", "Float"); |
---|
1446 | gravity *= 0.002/9.8; |
---|
1447 | |
---|
1448 | vertigo = get_float_resource("vertigo", "Float"); |
---|
1449 | vertigo *= 0.2; |
---|
1450 | |
---|
1451 | curviness = get_float_resource("curviness", "Float"); |
---|
1452 | curviness *= 0.25; |
---|
1453 | |
---|
1454 | twistiness = get_float_resource("twistiness", "Float"); |
---|
1455 | twistiness *= 0.125; |
---|
1456 | |
---|
1457 | terrain_flag = get_boolean_resource ("terrain", "Boolean"); |
---|
1458 | widening_flag = get_boolean_resource ("widening", "Boolean"); |
---|
1459 | bumps_flag = get_boolean_resource ("bumps", "Boolean"); |
---|
1460 | bonuses_flag = get_boolean_resource ("bonuses", "Boolean"); |
---|
1461 | crosshair_flag = get_boolean_resource ("crosshair", "Boolean"); |
---|
1462 | |
---|
1463 | be_wormy = get_boolean_resource ("worm", "Boolean"); |
---|
1464 | if (be_wormy) { |
---|
1465 | maxspeed *= 1.43; |
---|
1466 | thrust *= 10; |
---|
1467 | gravity *= 3; |
---|
1468 | vertigo *= 0.5; |
---|
1469 | smoothness *= 2; |
---|
1470 | curviness *= 2; |
---|
1471 | twistiness *= 2; |
---|
1472 | psychedelic_flag = True; |
---|
1473 | crosshair_flag = False; |
---|
1474 | } |
---|
1475 | |
---|
1476 | if (psychedelic_flag) init_psychedelic_colors (dpy, window, cmap); |
---|
1477 | else init_colors (dpy, window, cmap); |
---|
1478 | |
---|
1479 | for (i=0; i<ROTS; i++) { |
---|
1480 | th = M_PI * 2.0 * i / ROTS; |
---|
1481 | costab[i] = cos(th); |
---|
1482 | sintab[i] = sin(th); |
---|
1483 | } |
---|
1484 | |
---|
1485 | wide = random_wideness(); |
---|
1486 | |
---|
1487 | for (i=0; i < TERRAIN_LENGTH; i++) { |
---|
1488 | wideness[i] = wide; |
---|
1489 | bonuses[i] = 0; |
---|
1490 | } |
---|
1491 | |
---|
1492 | init_terrain (); |
---|
1493 | init_curves (); |
---|
1494 | wrap_tunnel (0, TERRAIN_LENGTH-1); |
---|
1495 | |
---|
1496 | if (DEBUG_FLAG || verbose_flag) atexit(print_stats); |
---|
1497 | |
---|
1498 | step = effective_speed; |
---|
1499 | |
---|
1500 | #ifdef HAVE_GETTIMEOFDAY |
---|
1501 | init_time (); |
---|
1502 | #endif |
---|
1503 | |
---|
1504 | } |
---|
1505 | |
---|
1506 | |
---|
1507 | /* |
---|
1508 | * Down the speedmine, you'll find speed |
---|
1509 | * to satisfy your moving needs; |
---|
1510 | * So if you're looking for a blast |
---|
1511 | * then hit the speedmine, really fast. |
---|
1512 | */ |
---|
1513 | |
---|
1514 | /* |
---|
1515 | * Speedworm likes to choke and spit |
---|
1516 | * and chase his tail, and dance a bit |
---|
1517 | * he really is a funky friend; |
---|
1518 | * he's made of speed from end to end. |
---|
1519 | */ |
---|
1520 | |
---|
1521 | char *progclass = "Speedmine"; |
---|
1522 | |
---|
1523 | char *defaults [] = { |
---|
1524 | ".verbose: False", |
---|
1525 | "*worm: False", |
---|
1526 | "*wire: False", |
---|
1527 | ".background: black", |
---|
1528 | ".foreground: white", |
---|
1529 | "*darkground: #101010", |
---|
1530 | "*lightground: #a0a0a0", |
---|
1531 | "*tunnelend: #000000", |
---|
1532 | "*delay: 30000", |
---|
1533 | "*maxspeed: 700", |
---|
1534 | "*thrust: 1.0", |
---|
1535 | "*gravity: 9.8", |
---|
1536 | "*vertigo: 1.0", |
---|
1537 | "*terrain: True", |
---|
1538 | "*smoothness: 6", |
---|
1539 | "*curviness: 1.0", |
---|
1540 | "*twistiness: 1.0", |
---|
1541 | "*widening: True", |
---|
1542 | "*bumps: True", |
---|
1543 | "*bonuses: True", |
---|
1544 | "*crosshair: True", |
---|
1545 | "*psychedelic: False", |
---|
1546 | 0 |
---|
1547 | }; |
---|
1548 | |
---|
1549 | XrmOptionDescRec options [] = { |
---|
1550 | { "-verbose", ".verbose", XrmoptionNoArg, "True"}, |
---|
1551 | { "-worm", ".worm", XrmoptionNoArg, "True"}, |
---|
1552 | { "-wire", ".wire", XrmoptionNoArg, "True"}, |
---|
1553 | { "-nowire", ".wire", XrmoptionNoArg, "False"}, |
---|
1554 | { "-darkground", ".darkground", XrmoptionSepArg, 0 }, |
---|
1555 | { "-lightground", ".lightground", XrmoptionSepArg, 0 }, |
---|
1556 | { "-tunnelend", ".tunnelend", XrmoptionSepArg, 0 }, |
---|
1557 | { "-delay", ".delay", XrmoptionSepArg, 0 }, |
---|
1558 | { "-maxspeed", ".maxspeed", XrmoptionSepArg, 0 }, |
---|
1559 | { "-thrust", ".thrust", XrmoptionSepArg, 0 }, |
---|
1560 | { "-gravity", ".gravity", XrmoptionSepArg, 0 }, |
---|
1561 | { "-vertigo", ".vertigo", XrmoptionSepArg, 0 }, |
---|
1562 | { "-terrain", ".terrain", XrmoptionNoArg, "True"}, |
---|
1563 | { "-noterrain", ".terrain", XrmoptionNoArg, "False"}, |
---|
1564 | { "-smoothness", ".smoothness", XrmoptionSepArg, 0 }, |
---|
1565 | { "-curviness", ".curviness", XrmoptionSepArg, 0 }, |
---|
1566 | { "-twistiness", ".twistiness", XrmoptionSepArg, 0 }, |
---|
1567 | { "-widening", ".widening", XrmoptionNoArg, "True"}, |
---|
1568 | { "-nowidening", ".widening", XrmoptionNoArg, "False"}, |
---|
1569 | { "-bumps", ".bumps", XrmoptionNoArg, "True"}, |
---|
1570 | { "-nobumps", ".bumps", XrmoptionNoArg, "False"}, |
---|
1571 | { "-bonuses", ".bonuses", XrmoptionNoArg, "True"}, |
---|
1572 | { "-nobonuses", ".bonuses", XrmoptionNoArg, "False"}, |
---|
1573 | { "-crosshair", ".crosshair", XrmoptionNoArg, "True"}, |
---|
1574 | { "-nocrosshair", ".crosshair", XrmoptionNoArg, "False"}, |
---|
1575 | { "-psychedelic", ".psychedelic", XrmoptionNoArg, "True"}, |
---|
1576 | { "-nopsychedelic", ".psychedelic", XrmoptionNoArg, "False"}, |
---|
1577 | { 0, 0, 0, 0 } |
---|
1578 | }; |
---|
1579 | |
---|
1580 | |
---|
1581 | void |
---|
1582 | screenhack (Display *dpy, Window window) |
---|
1583 | { |
---|
1584 | #ifndef NDEBUG |
---|
1585 | atexit (abort); |
---|
1586 | #endif |
---|
1587 | |
---|
1588 | init_speedmine (dpy, window); |
---|
1589 | |
---|
1590 | while (1) { |
---|
1591 | speedmine (dpy, window); |
---|
1592 | XSync (dpy, False); |
---|
1593 | screenhack_handle_events (dpy); |
---|
1594 | if (delay) usleep(delay); |
---|
1595 | } |
---|
1596 | } |
---|
1597 | |
---|
1598 | /* vim: ts=4 |
---|
1599 | */ |
---|