1 /* -*- Mode: C; c-basic-offset: 4; tab-width: 4 -*-
2 * speedmine, Copyright (C) 2001 Conrad Parker <conrad@deephackmode.org>
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
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.
18 * Happy Birthday to WierdArms (17 April) and Pat (18 April)
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.
30 * Throughout this code the following temporary variable names are used:
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
37 * Thus, the buffers are used with these iterators:
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
45 * xvals[t][j], yvals[t][j] screen coordinates
46 * {min,max}{x,y}[t] bounding boxes of screen coords
49 /* Define or undefine NDEBUG to turn assert and abort debugging off or on */
55 #include "screenhack.h"
58 #define MIN(a,b) ((a)<(b)?(a):(b))
59 #define MAX(a,b) ((a)>(b)?(a):(b))
61 #define RAND(r) (int)(((r)>0)?(random() % (long)(r)): -(random() % (long)(-r)))
63 #define SIGN3(a) ((a)>0?1:((a)<0?-1:0))
65 #define MODULO(a,b) while ((a)<0) (a)+=(b); (a) %= (b);
67 /* No. of shades of each color (ground, walls, bonuses) */
79 /* Apparently AIX's math.h bogusly defines `nearest' as a function,
80 in violation of the ANSI C spec. */
82 #define nearest n3arest
84 #define wireframe (st->wire_flag||st->wire_bonus>8||st->wire_bonus%2==1)
85 #define effective_speed (st->direction*(st->speed+st->speed_bonus))
87 /* No. of levels of interpolation, for perspective */
90 /* These must be powers of 2 */
91 #define TERRAIN_LENGTH 256
92 #define TERRAIN_BREADTH 32
94 /* total "perspective distance" of terrain */
95 #define TERRAIN_PDIST (INTERP*TERRAIN_LENGTH)
98 #define TB_MUL (ROTS/TERRAIN_BREADTH)
100 #define random_elevation() (st->terrain_flag?(random() % 200):0)
101 #define random_curvature() (st->curviness>0.0?((double)(random() % 40)-20)*st->curviness:0.0)
102 #define random_twist() (st->twistiness>0.0?((double)(random() % 40)-20)*st->twistiness:0.0)
103 #define random_wideness() (st->widening_flag?(int)(random() % 1200):0)
105 #define STEEL_ELEVATION 300
111 Pixmap dbuf, stars_mask;
115 unsigned int default_fg_pixel;
116 GC draw_gc, erase_gc, tunnelend_gc, stars_gc, stars_erase_gc;
118 int ncolors, nr_ground_colors, nr_wall_colors, nr_bonus_colors;
119 XColor ground_colors[MAX_COLORS], wall_colors[MAX_COLORS];
120 XColor bonus_colors[MAX_COLORS];
121 GC ground_gcs[MAX_COLORS], wall_gcs[MAX_COLORS], bonus_gcs[MAX_COLORS];
136 int psychedelic_flag;
140 double thrust, gravity;
155 int xoffset, yoffset;
165 double sintab[ROTS], costab[ROTS];
169 int terrain[TERRAIN_LENGTH][TERRAIN_BREADTH];
170 double xcurvature[TERRAIN_LENGTH];
171 double ycurvature[TERRAIN_LENGTH];
172 double zcurvature[TERRAIN_LENGTH];
173 int wideness[TERRAIN_LENGTH];
174 int bonuses[TERRAIN_LENGTH];
175 int xvals[TERRAIN_LENGTH][TERRAIN_BREADTH];
176 int yvals[TERRAIN_LENGTH][TERRAIN_BREADTH];
177 double worldx[TERRAIN_LENGTH][TERRAIN_BREADTH];
178 double worldy[TERRAIN_LENGTH][TERRAIN_BREADTH];
179 int minx[TERRAIN_LENGTH], maxx[TERRAIN_LENGTH];
180 int miny[TERRAIN_LENGTH], maxy[TERRAIN_LENGTH];
185 double fps_start, fps_end;
186 struct timeval start_time;
192 /* a forward declaration ... */
193 static void change_colors(struct state *st);
200 * returns the total time elapsed since the beginning of the demo
202 static double get_time(struct state *st) {
205 #if GETTIMEOFDAY_TWO_ARGS
206 gettimeofday(&t, NULL);
210 t.tv_sec -= st->start_time.tv_sec;
211 f = ((double)t.tv_sec) + t.tv_usec*1e-6;
218 * initialises the timing structures
220 static void init_time(struct state *st) {
221 #if GETTIMEOFDAY_TWO_ARGS
222 gettimeofday(&st->start_time, NULL);
224 gettimeofday(&st->start_time);
226 st->fps_start = get_time(st);
233 * perspective map the world coordinates worldx[i][j], worldy[i][j] onto
234 * screen coordinates xvals[t][j], yvals[t][j]
237 perspective (struct state *st)
239 int i, j, jj, t=0, depth, view_pos;
240 int rotation_bias, r;
241 double xc=0.0, yc=0.0, zc=0.0;
242 double xcc=0.0, ycc=0.0, zcc=0.0;
246 zf = 8.0*28.0 / (double)(st->width*TERRAIN_LENGTH);
247 if (st->be_wormy) zf *= 3.0;
249 depth = TERRAIN_PDIST - INTERP + st->pindex;
251 view_pos = (st->nearest+3*TERRAIN_LENGTH/4)%TERRAIN_LENGTH;
253 st->xoffset += - st->xcurvature[view_pos]*st->curviness/8;
256 st->yoffset += - st->ycurvature[view_pos]*st->curviness/4;
259 st->rotation_offset += (int)((st->zcurvature[view_pos]-st->zcurvature[st->nearest])*ROTS/8);
260 st->rotation_offset /= 2;
261 rotation_bias = st->orientation + st->spin_bonus - st->rotation_offset;
263 if (st->bumps_flag) {
265 st->yoffset -= ((st->terrain[view_pos][TERRAIN_BREADTH/4] * st->width /(8*1600)));
266 rotation_bias += (st->terrain[view_pos][TERRAIN_BREADTH/4+2] -
267 st->terrain[view_pos][TERRAIN_BREADTH/4-2])/8;
269 st->yoffset -= ((st->terrain[view_pos][TERRAIN_BREADTH/4] * st->width /(2*1600)));
270 rotation_bias += (st->terrain[view_pos][TERRAIN_BREADTH/4+2] -
271 st->terrain[view_pos][TERRAIN_BREADTH/4-2])/16;
275 MODULO(rotation_bias, ROTS);
277 for (t=0; t < TERRAIN_LENGTH; t++) {
278 i = st->nearest + t; MODULO(i, TERRAIN_LENGTH);
279 xc += st->xcurvature[i]; yc += st->ycurvature[i]; zc += st->zcurvature[i];
280 xcc += xc; ycc += yc; zcc += zc;
281 st->maxx[i] = st->maxy[i] = 0;
282 st->minx[i] = st->width; st->miny[i] = st->height;
285 for (t=0; t < TERRAIN_LENGTH; t++) {
286 i = st->nearest - 1 - t; MODULO(i, TERRAIN_LENGTH);
288 zfactor = (double)depth* (12.0 - TERRAIN_LENGTH/8.0) * zf;
289 for (j=0; j < TERRAIN_BREADTH; j++) {
290 jj = st->direction * j; MODULO(jj, TERRAIN_BREADTH);
291 /* jwz: not totally sure if this is right, but it avoids div0 */
293 xx = (st->worldx[i][jj]-(st->vertigo*xcc))/zfactor;
294 yy = (st->worldy[i][j]-(st->vertigo*ycc))/zfactor;
299 r = rotation_bias + (int)(st->vertigo*zcc); MODULO(r, ROTS);
301 st->xvals[t][j] = st->xoffset + (st->width>>1) +
302 (int)(xx * st->costab[r] - yy * st->sintab[r]);
303 st->maxx[t] = MAX(st->maxx[t], st->xvals[t][j]);
304 st->minx[t] = MIN(st->minx[t], st->xvals[t][j]);
306 st->yvals[t][j] = st->yoffset + st->height/2 +
307 (int)(xx * st->sintab[r] + yy * st->costab[r]);
308 st->maxy[t] = MAX(st->maxy[t], st->yvals[t][j]);
309 st->miny[t] = MIN(st->miny[t], st->yvals[t][j]);
311 xcc -= xc; ycc -= yc; zcc -= zc;
312 xc -= st->xcurvature[i]; yc -= st->ycurvature[i]; zc -= st->zcurvature[i];
318 * wrap_tunnel (start, end)
320 * wrap the terrain terrain[i][j] around the semi-circular tunnel function
322 * x' = x/2 * cos(theta) - (y-k) * x * sin(theta)
323 * y' = x/4 * sin(theta) + y * cos(theta)
325 * between i=start and i=end inclusive, producing world coordinates
326 * worldx[i][j], worldy[i][j]
329 wrap_tunnel (struct state *st, int start, int end)
334 assert (start < end);
336 for (i=start; i <= end; i++) {
337 for (j=0; j < TERRAIN_BREADTH; j++) {
338 x = j * (1.0/TERRAIN_BREADTH);
339 v = st->terrain[i][j];
340 y = (double)(v==STEEL_ELEVATION?200:v) - st->wideness[i] - 1200;
343 if (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8) y -= 300;
345 st->worldx[i][j] = x/2 * st->costab[j*TB_MUL] -
346 (y-st->height/4.0)*x*st->sintab[j*TB_MUL];
347 st->worldy[i][j] = x/4 * st->sintab[j*TB_MUL] +
348 y * st->costab[j*TB_MUL];
356 * perform the state transitions and terrain transformation for the
357 * "look backwards/look forwards" bonus
360 flip_direction (struct state *st)
364 st->direction = -st->direction;
366 st->bonus_bright = 20;
368 for (i=0; i < TERRAIN_LENGTH; i++) {
369 in = st->nearest + i; MODULO(in, TERRAIN_BREADTH);
370 ip = st->nearest - i; MODULO(ip, TERRAIN_BREADTH);
371 for (j=0; j < TERRAIN_BREADTH; j++) {
372 t = st->terrain[ip][j];
373 st->terrain[ip][j] = st->terrain[in][j];
374 st->terrain[in][j] = t;
380 * generate_smooth (start, end)
382 * generate smooth terrain between i=start and i=end inclusive
385 generate_smooth (struct state *st, int start, int end)
389 assert (start < end);
391 for (i=start; i <= end; i++) {
392 ii = i; MODULO(ii, TERRAIN_LENGTH);
393 for (j=0; j < TERRAIN_BREADTH; j++) {
394 st->terrain[i][j] = STEEL_ELEVATION;
400 * generate_straight (start, end)
402 * zero the curvature and wideness between i=start and i=end inclusive
405 generate_straight (struct state *st, int start, int end)
409 assert (start < end);
411 for (i=start; i <= end; i++) {
412 ii = i; MODULO(ii, TERRAIN_LENGTH);
413 for (j=0; j < TERRAIN_BREADTH; j++) {
414 st->xcurvature[ii] = 0;
415 st->ycurvature[ii] = 0;
416 st->zcurvature[ii] = 0;
417 st->wideness[ii] = 0;
423 * int generate_terrain_value (v1, v2, v3, v4, w)
425 * generate terrain value near the average of v1, v2, v3, v4, with
426 * perturbation proportional to w
429 generate_terrain_value (struct state *st, int v1, int v2, int v3, int v4, int w)
434 if (!st->terrain_flag) return 0;
436 sum = v1 + v2 + v3 + v4;
438 rval = w*sum/st->smoothness;
439 if (rval == 0) rval = 2;
441 ret = (sum/4 -(rval/2) + RAND(rval));
443 if (ret < -400 || ret > 400) {
451 * generate_terrain (start, end, final)
453 * generate terrain[i][j] between i=start and i=end inclusive
455 * This is performed by successive subdivision of the terrain into
456 * rectangles of decreasing size. Subdivision continues until the
457 * the minimum width or height of these rectangles is 'final'; ie.
458 * final=1 indicates to subdivide as far as possible, final=2 indicates
459 * to stop one subdivision before that (leaving a checkerboard pattern
463 generate_terrain (struct state *st, int start, int end, int final)
466 int ip, jp, in, jn; /* prev, next values */
469 assert (start < end);
470 assert (start >= 0 && start < TERRAIN_LENGTH);
471 assert (end >= 0 && end < TERRAIN_LENGTH);
473 diff = end - start + 1;
475 st->terrain[end][0] = random_elevation();
476 st->terrain[end][TERRAIN_BREADTH/2] = random_elevation();
478 for (w= diff/2, l=TERRAIN_BREADTH/4;
479 w >= final || l >= final; w /= 2, l /= 2) {
481 if (w<1) w=1; if (l<1) l=1;
483 for (i=start+w-1; i < end; i += (w*2)) {
484 ip = i-w; MODULO(ip, TERRAIN_LENGTH);
485 in = i+w; MODULO(in, TERRAIN_LENGTH);
486 for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) {
487 jp = j-1; MODULO(jp, TERRAIN_BREADTH);
488 jn = j+1; MODULO(jn, TERRAIN_BREADTH);
490 generate_terrain_value (st, st->terrain[ip][jp], st->terrain[in][jp],
491 st->terrain[ip][jn], st->terrain[in][jn], w);
495 for (i=start+(w*2)-1; i < end; i += (w*2)) {
496 ip = i-w; MODULO(ip, TERRAIN_LENGTH);
497 in = i+w; MODULO(in, TERRAIN_LENGTH);
498 for (j=l-1; j < TERRAIN_BREADTH; j += (l*2)) {
499 jp = j-1; MODULO(jp, TERRAIN_BREADTH);
500 jn = j+1; MODULO(jn, TERRAIN_BREADTH);
502 generate_terrain_value (st, st->terrain[ip][j], st->terrain[in][j],
503 st->terrain[i][jp], st->terrain[i][jn], w);
507 for (i=start+w-1; i < end; i += (w*2)) {
508 ip = i-w; MODULO(ip, TERRAIN_LENGTH);
509 in = i+w; MODULO(in, TERRAIN_LENGTH);
510 for (j=2*l-1; j < TERRAIN_BREADTH; j += (l*2)) {
511 jp = j-1; MODULO(jp, TERRAIN_BREADTH);
512 jn = j+1; MODULO(jn, TERRAIN_BREADTH);
514 generate_terrain_value (st, st->terrain[ip][j], st->terrain[in][j],
515 st->terrain[i][jp], st->terrain[i][jn], w);
522 * double generate_curvature_value (v1, v2, w)
524 * generate curvature value near the average of v1 and v2, with perturbation
528 generate_curvature_value (double v1, double v2, int w)
530 double sum, avg, diff, ret;
533 assert (!isnan(v1) && !isnan(v2));
538 diff = MIN(v1 - avg, v2 - avg);
540 rval = (int)diff * w;
541 if (rval == 0.0) return avg;
543 ret = (avg -((double)rval)/500.0 + ((double)RAND(rval))/1000.0);
545 assert (!isnan(ret));
551 * generate_curves (start, end)
553 * generate xcurvature[i], ycurvature[i], zcurvature[i] and wideness[i]
554 * between start and end inclusive
557 generate_curves (struct state *st, int start, int end)
559 int i, diff, ii, in, ip, w;
561 assert (start < end);
563 diff = end - start + 1; MODULO (diff, TERRAIN_LENGTH);
565 if (random() % 100 == 0)
566 st->xcurvature[end] = 30 * random_curvature();
567 else if (random() % 10 == 0)
568 st->xcurvature[end] = 20 * random_curvature();
570 st->xcurvature[end] = 10 * random_curvature();
572 if (random() % 50 == 0)
573 st->ycurvature[end] = 20 * random_curvature();
574 else if (random() % 25 == 0)
575 st->ycurvature[end] = 30 * random_curvature();
577 st->ycurvature[end] = 10 * random_curvature();
579 if (random() % 3 == 0)
580 st->zcurvature[end] = random_twist();
582 st->zcurvature[end] =
583 generate_curvature_value (st->zcurvature[end], random_twist(), 1);
586 st->wideness[end] = random_wideness();
589 generate_curvature_value (st->wideness[end], random_wideness(), 1);
591 for (w=diff/2; w >= 1; w /= 2) {
592 for (i=start+w-1; i < end; i+=(w*2)) {
593 ii = i; MODULO (ii, TERRAIN_LENGTH);
594 ip = i-w; MODULO (ip, TERRAIN_LENGTH);
595 in = i+w; MODULO (in, TERRAIN_LENGTH);
597 generate_curvature_value (st->xcurvature[ip], st->xcurvature[in], w);
599 generate_curvature_value (st->ycurvature[ip], st->ycurvature[in], w);
601 generate_curvature_value (st->zcurvature[ip], st->zcurvature[in], w);
603 generate_curvature_value (st->wideness[ip], st->wideness[in], w);
611 * choose a random bonus and perform its state transition
614 do_bonus (struct state *st)
616 st->bonus_bright = 20;
618 if (st->jamming > 0) {
620 st->nearest -= 2; MODULO(st->nearest, TERRAIN_LENGTH);
624 if (st->psychedelic_flag) change_colors(st);
626 switch (random() % 7) {
627 case 0: /* switch to or from wireframe */
628 st->wire_bonus = (st->wire_bonus?0:300);
630 case 1: /* speedup */
631 st->speed_bonus = 40.0;
634 st->spin_bonus += ROTS;
637 st->spin_bonus -= ROTS;
639 case 4: /* look backwards / look forwards */
640 st->flipped_at = st->nearest;
642 st->backwards_bonus = (st->backwards_bonus?0:10);
647 case 6: /* jam against the bonus a few times; deja vu! */
648 st->nearest -= 2; MODULO(st->nearest, TERRAIN_LENGTH);
660 * check if a bonus has been passed in the last frame, and handle it
663 check_bonuses (struct state *st)
665 int i, ii, start, end;
667 if (!st->bonuses_flag) return;
669 if (st->step >= 0.0) {
670 start = st->nearest; end = st->nearest + (int)floor(st->step);
672 end = st->nearest; start = st->nearest + (int)floor(st->step);
676 start += TERRAIN_LENGTH/4;
677 end += TERRAIN_LENGTH/4;
680 for (i=start; i < end; i++) {
681 ii = i; MODULO(ii, TERRAIN_LENGTH);
682 if (st->bonuses[ii] == 1) do_bonus (st);
687 * decrement_bonuses (double time_per_frame)
689 * decrement timers associated with bonuses
692 decrement_bonuses (struct state *st, double time_per_frame)
694 if (!st->bonuses_flag) return;
696 if (st->bonus_bright > 0) st->bonus_bright-=4;
697 if (st->wire_bonus > 0) st->wire_bonus--;
698 if (st->speed_bonus > 0) st->speed_bonus -= 2.0;
700 if (st->spin_bonus > 10) st->spin_bonus -= (int)(st->step*13.7);
701 else if (st->spin_bonus < -10) st->spin_bonus += (int)(st->step*11.3);
703 if (st->backwards_bonus > 1) st->backwards_bonus--;
704 else if (st->backwards_bonus == 1) {
705 st->nearest += 2*(MAX(st->flipped_at, st->nearest) - MIN(st->flipped_at,st->nearest));
706 MODULO(st->nearest, TERRAIN_LENGTH);
708 st->backwards_bonus = 0;
713 * set_bonuses (start, end)
715 * choose if to and where to set a bonus between i=start and i=end inclusive
718 set_bonuses (struct state *st, int start, int end)
722 if (!st->bonuses_flag) return;
724 assert (start < end);
728 for (i=start; i <= end; i++) {
729 ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH;
732 if (random() % 4 == 0) {
733 i = start + RAND(diff-3);
734 ii = i; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH;
735 st->bonuses[ii] = 2; /* marker */
736 ii = i+3; if (ii>=TERRAIN_LENGTH) ii -= TERRAIN_LENGTH;
737 st->bonuses[ii] = 1; /* real thing */
742 * regenerate_terrain ()
744 * regenerate a portion of the terrain map of length TERRAIN_LENGTH/4 iff
745 * we just passed between two quarters of the terrain.
747 * choose the kind of terrain to produce, produce it and wrap the tunnel
750 regenerate_terrain (struct state *st)
755 passed = st->nearest % (TERRAIN_LENGTH/4);
757 if (st->speed == 0.0 ||
758 (st->speed > 0.0 && passed > (int)st->step) ||
759 (st->speed < 0.0 && (TERRAIN_LENGTH/4)-passed > (int)fabs(st->step))) {
764 end = st->nearest - passed - 1; MODULO(end, TERRAIN_LENGTH);
765 start = end - TERRAIN_LENGTH/4 + 1; MODULO(start, TERRAIN_LENGTH);
767 if (DEBUG_FLAG) printf ("Regenerating [%d - %d]\n", start, end);
769 set_bonuses (st, start, end);
771 switch (random() % 64) {
774 generate_terrain (st, start, end, 1);
775 generate_smooth (st, start,
776 start + TERRAIN_LENGTH/8 + (random() % TERRAIN_LENGTH/8));
779 generate_smooth (st, start, end);
780 generate_terrain (st, start, end, 4); break;
782 generate_smooth (st, start, end);
783 generate_terrain (st, start, end, 2); break;
785 generate_terrain (st, start, end, 1);
788 if (random() % 16 == 0) {
789 generate_straight (st, start, end);
791 generate_curves (st, start, end);
794 wrap_tunnel (st, start, end);
800 * initialise the terrain map for the beginning of the demo
803 init_terrain (struct state *st)
807 for (i=0; i < TERRAIN_LENGTH; i++) {
808 for (j=0; j < TERRAIN_BREADTH; j++) {
809 st->terrain[i][j] = 0;
813 st->terrain[TERRAIN_LENGTH-1][0] = - (random() % 300);
814 st->terrain[TERRAIN_LENGTH-1][TERRAIN_BREADTH/2] = - (random() % 300);
816 generate_smooth (st, 0, TERRAIN_LENGTH-1);
817 generate_terrain (st, 0, TERRAIN_LENGTH/4 -1, 4);
818 generate_terrain (st, TERRAIN_LENGTH/4, TERRAIN_LENGTH/2 -1, 2);
819 generate_terrain (st, TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4 -1, 1);
820 generate_smooth (st, 3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1);
826 * initialise the curvatures and wideness for the beginning of the demo.
829 init_curves (struct state *st)
833 for (i=0; i < TERRAIN_LENGTH-1; i++) {
834 st->xcurvature[i] = 0.0;
835 st->ycurvature[i] = 0.0;
836 st->zcurvature[i] = 0.0;
839 st->xcurvature[TERRAIN_LENGTH-1] = random_curvature();
840 st->ycurvature[TERRAIN_LENGTH-1] = random_curvature();
841 st->zcurvature[TERRAIN_LENGTH-1] = random_twist();
843 generate_straight (st, 0, TERRAIN_LENGTH/4-1);
844 generate_curves (st, TERRAIN_LENGTH/4, TERRAIN_LENGTH/2-1);
845 generate_curves (st, TERRAIN_LENGTH/2, 3*TERRAIN_LENGTH/4-1);
846 generate_straight (st, 3*TERRAIN_LENGTH/4, TERRAIN_LENGTH-1);
851 * render_quads (dpy, d, t, dt, i)
853 * renders the quadrilaterals from perspective depth t to t+dt.
854 * i is passed as a hint, where i corresponds to t as asserted.
857 render_quads (struct state *st, Drawable d, int t, int dt, int i)
864 assert (i == (st->nearest - (t + dt) + TERRAIN_LENGTH) % TERRAIN_LENGTH);
866 in = i + 1; MODULO(in, TERRAIN_LENGTH);
868 for (j=0; j < TERRAIN_BREADTH; j+=dt) {
869 t2 = t+dt; if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH;
870 j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH;
871 points[0].x = st->xvals[t][j]; points[0].y = st->yvals[t][j];
872 points[1].x = st->xvals[t2][j]; points[1].y = st->yvals[t2][j];
873 points[2].x = st->xvals[t2][j2]; points[2].y = st->yvals[t2][j2];
874 points[3].x = st->xvals[t][j2]; points[3].y = st->yvals[t][j2];
876 index = st->bonus_bright + st->ncolors/3 +
877 t*(t*INTERP + st->pindex) * st->ncolors /
878 (3*TERRAIN_LENGTH*TERRAIN_PDIST);
880 index += (int)((points[0].y - points[3].y) / 8);
881 index += (int)((st->worldx[i][j] - st->worldx[in][j]) / 40);
882 index += (int)((st->terrain[in][j] - st->terrain[i][j]) / 100);
884 if (st->be_wormy && st->psychedelic_flag) index += st->ncolors/4;
886 if (st->ncolors > MAX_COLORS) abort();
887 index = MIN (index, st->ncolors-1);
888 index = MAX (index, 0);
890 if (st->bonuses[i]) {
891 XSetClipMask (st->dpy, st->bonus_gcs[index], None);
895 if (st->bonuses[i]) gc = st->bonus_gcs[index];
896 else gc = st->ground_gcs[index];
897 XDrawLines (st->dpy, d, gc, points, 4, CoordModeOrigin);
900 gc = st->bonus_gcs[index];
901 else if ((st->direction>0 && j < TERRAIN_BREADTH/8) ||
902 (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) ||
903 (st->direction < 0 && j > 3*TERRAIN_BREADTH/8-1 &&
904 j < TERRAIN_BREADTH/2) ||
905 st->terrain[i][j] == STEEL_ELEVATION ||
906 st->wideness[in] - st->wideness[i] > 200)
907 gc = st->ground_gcs[index];
909 gc = st->wall_gcs[index];
911 XFillPolygon (st->dpy, d, gc, points, 4, Nonconvex, CoordModeOrigin);
917 * render_pentagons (dpy, d, t, dt, i)
919 * renders the pentagons from perspective depth t to t+dt.
920 * i is passed as a hint, where i corresponds to t as asserted.
923 render_pentagons (struct state *st, Drawable d, int t, int dt, int i)
925 int j, t2, j2, j3, in;
930 assert (i == (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH);
932 in = i + 1; MODULO(in, TERRAIN_LENGTH);
934 for (j=0; j < TERRAIN_BREADTH; j+=dt*2) {
935 t2 = t+(dt*2); if (t2 >= TERRAIN_LENGTH) t2 -= TERRAIN_LENGTH;
936 j2 = j+dt; if (j2 >= TERRAIN_BREADTH) j2 -= TERRAIN_BREADTH;
937 j3 = j+dt+dt; if (j3 >= TERRAIN_BREADTH) j3 -= TERRAIN_BREADTH;
938 points[0].x = st->xvals[t][j]; points[0].y = st->yvals[t][j];
939 points[1].x = st->xvals[t2][j]; points[1].y = st->yvals[t2][j];
940 points[2].x = st->xvals[t2][j2]; points[2].y = st->yvals[t2][j2];
941 points[3].x = st->xvals[t2][j3]; points[3].y = st->yvals[t2][j3];
942 points[4].x = st->xvals[t][j3]; points[4].y = st->yvals[t][j3];
944 index = st->bonus_bright + st->ncolors/3 +
945 t*(t*INTERP + st->pindex) * st->ncolors /
946 (3*TERRAIN_LENGTH*TERRAIN_PDIST);
948 index += (int)((points[0].y - points[3].y) / 8);
949 index += (int)((st->worldx[i][j] - st->worldx[in][j]) / 40);
950 index += (int)((st->terrain[in][j] - st->terrain[i][j]) / 100);
952 if (st->be_wormy && st->psychedelic_flag) index += st->ncolors/4;
954 index = MIN (index, st->ncolors-1);
955 index = MAX (index, 0);
957 if (st->bonuses[i]) {
958 XSetClipMask (st->dpy, st->bonus_gcs[index], None);
962 if (st->bonuses[i]) gc = st->bonus_gcs[index];
963 else gc = st->ground_gcs[index];
964 XDrawLines (st->dpy, d, gc, points, 5, CoordModeOrigin);
967 gc = st->bonus_gcs[index];
968 else if (j < TERRAIN_BREADTH/8 ||
969 (j > TERRAIN_BREADTH/8 && j < 3*TERRAIN_BREADTH/8-1) ||
970 st->terrain[i][j] == STEEL_ELEVATION ||
971 st->wideness[in] - st->wideness[i] > 200)
972 gc = st->ground_gcs[index];
974 gc = st->wall_gcs[index];
976 XFillPolygon (st->dpy, d, gc, points, 5, Complex, CoordModeOrigin);
982 * render_block (dpy, d, gc, t)
984 * render a filled polygon at perspective depth t using the given GC
987 render_block (struct state *st, Drawable d, GC gc, int t)
991 XPoint erase_points[TERRAIN_BREADTH/2];
993 for (i=0; i < TERRAIN_BREADTH/2; i++) {
994 erase_points[i].x = st->xvals[t][i*2];
995 erase_points[i].y = st->yvals[t][i*2];
998 XFillPolygon (st->dpy, d, gc, erase_points,
999 TERRAIN_BREADTH/2, Complex, CoordModeOrigin);
1003 * regenerate_stars_mask (dpy, t)
1005 * regenerate the clip mask 'stars_mask' for drawing the bonus stars at
1006 * random positions within the bounding box at depth t
1009 regenerate_stars_mask (struct state *st, int t)
1011 int i, w, h, a, b, l1, l2;
1012 const int lim = st->width*TERRAIN_LENGTH/(300*(TERRAIN_LENGTH-t));
1014 w = st->maxx[t] - st->minx[t];
1015 h = st->maxy[t] - st->miny[t];
1017 if (w<6||h<6) return;
1019 XFillRectangle (st->dpy, st->stars_mask, st->stars_erase_gc,
1020 0, 0, st->width, st->height);
1022 l1 = (t>3*TERRAIN_LENGTH/4?2:1);
1023 l2 = (t>7*TERRAIN_LENGTH/8?2:1);
1025 for (i=0; i < lim; i++) {
1026 a = RAND(w); b = RAND(h);
1027 XDrawLine (st->dpy, st->stars_mask, st->stars_gc,
1028 st->minx[t]+a-l1, st->miny[t]+b, st->minx[t]+a+l1, st->miny[t]+b);
1029 XDrawLine (st->dpy, st->stars_mask, st->stars_gc,
1030 st->minx[t]+a, st->miny[t]+b-l1, st->minx[t]+a, st->miny[t]+b+l1);
1032 for (i=0; i < lim; i++) {
1033 a = RAND(w); b = RAND(h);
1034 XDrawLine (st->dpy, st->stars_mask, st->stars_gc,
1035 st->minx[t]+a-l2, st->miny[t]+b, st->minx[t]+a+l2, st->miny[t]+b);
1036 XDrawLine (st->dpy, st->stars_mask, st->stars_gc,
1037 st->minx[t]+a, st->miny[t]+b-l2, st->minx[t]+a, st->miny[t]+b+l2);
1042 * render_bonus_block (dpy, d, t, i)
1044 * draw the bonus stars at depth t.
1045 * i is passed as a hint, where i corresponds to t as asserted.
1048 render_bonus_block (struct state *st, Drawable d, int t, int i)
1052 assert (i == (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH);
1054 if (!st->bonuses[i] || wireframe) return;
1056 regenerate_stars_mask (st, t);
1058 bt = t * st->nr_bonus_colors / (2*TERRAIN_LENGTH);
1060 XSetClipMask (st->dpy, st->bonus_gcs[bt], st->stars_mask);
1062 render_block (st, d, st->bonus_gcs[bt], t);
1066 begin_at (struct state *st)
1069 int max_minx=0, min_maxx=st->width, max_miny=0, min_maxy=st->height;
1071 for (t=TERRAIN_LENGTH-1; t > 0; t--) {
1072 max_minx = MAX (max_minx, st->minx[t]);
1073 min_maxx = MIN (min_maxx, st->maxx[t]);
1074 max_miny = MAX (max_miny, st->miny[t]);
1075 min_maxy = MIN (min_maxy, st->maxy[t]);
1077 if (max_miny >= min_maxy || max_minx >= min_maxx) break;
1084 * render_speedmine (dpy, d)
1086 * render the current frame.
1089 render_speedmine (struct state *st, Drawable d)
1091 int t, i=st->nearest, dt=1;
1094 assert (st->nearest >= 0 && st->nearest < TERRAIN_LENGTH);
1096 if (st->be_wormy || wireframe) {
1097 XFillRectangle (st->dpy, d, st->erase_gc, 0, 0, st->width, st->height);
1100 for (t=0; t < TERRAIN_LENGTH/4; t+=dt) {
1101 render_bonus_block (st, d, t, i);
1102 i -= dt; MODULO(i, TERRAIN_LENGTH);
1103 render_quads (st, d, t, dt, i);
1106 assert (t == TERRAIN_LENGTH/4);
1108 t = MAX(begin_at(st), TERRAIN_LENGTH/4);
1109 /*t = TERRAIN_LENGTH/4; dt = 2; */
1110 /*dt = (t >= 3*TERRAIN_LENGTH/4 ? 1 : 2);*/
1111 i = (st->nearest -t + TERRAIN_LENGTH) % TERRAIN_LENGTH;
1112 render_block (st, d, st->tunnelend_gc, t);
1117 if (t == TERRAIN_LENGTH/4)
1118 render_pentagons (st, d, t, dt, i);
1120 for (; t < 3*TERRAIN_LENGTH/4; t+=dt) {
1121 render_bonus_block (st, d, t, i);
1122 i -= dt; MODULO(i, TERRAIN_LENGTH);
1123 render_quads (st, d, t, dt, i);
1128 for (; t < TERRAIN_LENGTH-(1+(st->pindex<INTERP/2)); t+=dt) {
1129 render_bonus_block (st, d, t, i);
1130 i -= dt; MODULO(i, TERRAIN_LENGTH);
1133 if (wireframe) {assert (t == 3*TERRAIN_LENGTH/4);}
1135 if (t == 3*TERRAIN_LENGTH/4)
1136 render_pentagons (st, d, t, dt, i);
1138 for (; t < TERRAIN_LENGTH-(1+(st->pindex<INTERP/2)); t+=dt) {
1139 render_bonus_block (st, d, t, i);
1140 i -= dt; MODULO(i, TERRAIN_LENGTH);
1141 render_quads (st, d, t, dt, i);
1145 /* Draw crosshair */
1146 if (st->crosshair_flag) {
1147 gc = (wireframe ? st->bonus_gcs[st->nr_bonus_colors/2] : st->erase_gc);
1148 XFillRectangle (st->dpy, d, gc,
1149 st->width/2+(st->xoffset)-8, st->height/2+(st->yoffset*2)-1, 16, 3);
1150 XFillRectangle (st->dpy, d, gc,
1151 st->width/2+(st->xoffset)-1, st->height/2+(st->yoffset*2)-8, 3, 16);
1159 * move to the position for the next frame, and modify the state variables
1160 * st->nearest, pindex, pos, speed
1163 move (struct state *st)
1167 st->pos += st->step;
1168 dpos = SIGN3(st->pos) * floor(fabs(st->pos));
1170 st->pindex += SIGN3(effective_speed) + INTERP;
1171 while (st->pindex >= INTERP) {
1173 st->pindex -= INTERP;
1175 while (st->pindex < 0) {
1177 st->pindex += INTERP;
1180 st->nearest += dpos; MODULO(st->nearest, TERRAIN_LENGTH);
1184 st->accel = st->thrust + st->ycurvature[st->nearest] * st->gravity;
1185 st->speed += st->accel;
1186 if (st->speed > st->maxspeed) st->speed = st->maxspeed;
1187 if (st->speed < -st->maxspeed) st->speed = -st->maxspeed;
1191 * speedmine (dpy, window)
1193 * do everything required for one frame of the demo
1195 static unsigned long
1196 speedmine_draw (Display *dpy, Window window, void *closure)
1198 struct state *st = (struct state *) closure;
1199 double elapsed, time_per_frame = 0.04;
1201 regenerate_terrain (st);
1205 render_speedmine (st, st->dbuf);
1206 if (st->dbuf != st->window)
1207 XCopyArea (st->dpy, st->dbuf, st->window, st->draw_gc, 0, 0, st->width, st->height, 0, 0);
1209 st->fps_end = get_time(st);
1211 st->total_nframes++;
1213 if (st->fps_end > st->fps_start + 0.5) {
1214 elapsed = st->fps_end - st->fps_start;
1215 st->fps_start = get_time(st);
1217 time_per_frame = elapsed / st->nframes - st->delay*1e-6;
1218 st->fps = st->nframes / elapsed;
1220 printf ("%f s elapsed\t%3f s/frame\t%.1f FPS\n", elapsed,
1221 time_per_frame, st->fps);
1223 st->step = effective_speed * elapsed;
1231 decrement_bonuses (st, time_per_frame);
1239 * speedmine_color_ramp (dpy, gcs, colors, ncolors, s1, s2, v1, v2)
1241 * generate a color ramp of up to *ncolors between randomly chosen hues,
1242 * varying from saturation s1 to s2 and value v1 to v2, placing the colors
1243 * in 'colors' and creating corresponding GCs in 'gcs'.
1245 * The number of colors actually allocated is returned in ncolors.
1248 speedmine_color_ramp (struct state *st, GC *gcs, XColor * colors,
1249 int *ncolors, double s1, double s2, double v1, double v2)
1253 unsigned long flags;
1256 assert (*st->ncolors >= 0);
1257 assert (s1 >= 0.0 && s1 <= 1.0 && v1 >= 0.0 && v2 <= 1.0);
1259 if (st->psychedelic_flag) {
1260 h1 = RAND(360); h2 = (h1 + 180) % 360;
1262 h1 = h2 = RAND(360);
1265 make_color_ramp (st->screen, st->visual, st->cmap,
1266 h1, s1, v1, h2, s2, v2,
1267 colors, ncolors, False, True, False);
1269 flags = GCForeground;
1270 for (i=0; i < *ncolors; i++) {
1271 gcv.foreground = colors[i].pixel;
1272 if (gcs[i]) XFreeGC (st->dpy, gcs[i]);
1273 gcs[i] = XCreateGC (st->dpy, st->dbuf, flags, &gcv);
1281 * perform the color changing bonus. New colors are allocated for the
1282 * walls and bonuses, and if the 'psychedelic' option is set then new
1283 * colors are also chosen for the ground.
1286 change_colors (struct state *st)
1290 if (st->psychedelic_flag) {
1291 free_colors (st->screen, st->cmap, st->bonus_colors, st->nr_bonus_colors);
1292 free_colors (st->screen, st->cmap, st->wall_colors, st->nr_wall_colors);
1293 free_colors (st->screen, st->cmap, st->ground_colors, st->nr_ground_colors);
1296 st->ncolors = MAX_COLORS;
1297 speedmine_color_ramp (st, st->ground_gcs, st->ground_colors,
1298 &st->ncolors, 0.0, 0.8, 0.0, 0.9);
1299 st->nr_ground_colors = st->ncolors;
1301 free_colors (st->screen, st->cmap, st->bonus_colors, st->nr_bonus_colors);
1302 free_colors (st->screen, st->cmap, st->wall_colors, st->nr_wall_colors);
1303 st->ncolors = st->nr_ground_colors;
1308 st->ncolors = MAX_COLORS;
1309 speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors,
1311 st->nr_wall_colors = st->ncolors;
1313 st->ncolors = MAX_COLORS;
1314 speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors,
1315 0.6, 0.9, 0.4, 1.0);
1316 st->nr_bonus_colors = st->ncolors;
1320 * init_psychedelic_colors (dpy, window, cmap)
1322 * initialise a psychedelic colormap
1325 init_psychedelic_colors (struct state *st)
1329 gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "tunnelend", "TunnelEnd");
1330 st->tunnelend_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
1332 st->ncolors = MAX_COLORS;
1333 speedmine_color_ramp (st, st->ground_gcs, st->ground_colors, &st->ncolors,
1334 0.0, 0.8, 0.0, 0.9);
1335 st->nr_ground_colors = st->ncolors;
1337 st->ncolors = MAX_COLORS;
1338 speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors,
1339 0.0, 0.6, 0.0, 0.9);
1340 st->nr_wall_colors = st->ncolors;
1342 st->ncolors = MAX_COLORS;
1343 speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors,
1344 0.6, 0.9, 0.4, 1.0);
1345 st->nr_bonus_colors = st->ncolors;
1349 * init_colors (dpy, window, cmap)
1351 * initialise a normal colormap
1354 init_colors (struct state *st)
1359 double s1, s2, v1, v2;
1360 unsigned long flags;
1363 gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "tunnelend", "TunnelEnd");
1364 st->tunnelend_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
1366 st->ncolors = MAX_COLORS;
1368 dark.pixel = get_pixel_resource (st->dpy, st->cmap, "darkground", "DarkGround");
1369 XQueryColor (st->dpy, st->cmap, &dark);
1371 light.pixel = get_pixel_resource (st->dpy, st->cmap, "lightground", "LightGround");
1372 XQueryColor (st->dpy, st->cmap, &light);
1374 rgb_to_hsv (dark.red, dark.green, dark.blue, &h1, &s1, &v1);
1375 rgb_to_hsv (light.red, light.green, light.blue, &h2, &s2, &v2);
1376 make_color_ramp (st->screen, st->visual, st->cmap,
1377 h1, s1, v1, h2, s2, v2,
1378 st->ground_colors, &st->ncolors, False, True, False);
1379 st->nr_ground_colors = st->ncolors;
1381 flags = GCForeground;
1382 for (i=0; i < st->ncolors; i++) {
1383 gcv.foreground = st->ground_colors[i].pixel;
1384 st->ground_gcs[i] = XCreateGC (st->dpy, st->dbuf, flags, &gcv);
1387 st->ncolors = MAX_COLORS;
1388 speedmine_color_ramp (st, st->wall_gcs, st->wall_colors, &st->ncolors,
1389 0.0, 0.6, 0.0, 0.9);
1390 st->nr_wall_colors = st->ncolors;
1392 st->ncolors = MAX_COLORS;
1393 speedmine_color_ramp (st, st->bonus_gcs, st->bonus_colors, &st->ncolors,
1394 0.6, 0.9, 0.4, 1.0);
1395 st->nr_bonus_colors = st->ncolors;
1401 * print out average FPS stats for the demo
1405 print_stats (struct state *st)
1407 if (st->total_nframes >= 1)
1408 printf ("Rendered %d frames averaging %f FPS\n", st->total_nframes,
1409 st->total_nframes / get_time(st));
1414 * init_speedmine (dpy, window)
1416 * initialise the demo
1419 speedmine_init (Display *dpy, Window window)
1421 struct state *st = (struct state *) calloc (1, sizeof(*st));
1423 XWindowAttributes xgwa;
1429 st->window = window;
1432 st->accel = 0.00000001;
1433 st->direction = FORWARDS;
1434 st->orientation = (17*ROTS)/22;
1436 XGetWindowAttributes (st->dpy, st->window, &xgwa);
1437 st->cmap = xgwa.colormap;
1438 st->visual = xgwa.visual;
1439 st->screen = xgwa.screen;
1440 st->width = xgwa.width;
1441 st->height = xgwa.height;
1443 st->verbose_flag = get_boolean_resource (st->dpy, "verbose", "Boolean");
1445 # ifdef HAVE_COCOA /* Don't second-guess Quartz's double-buffering */
1446 st->dbuf = st->window;
1448 st->dbuf = XCreatePixmap (st->dpy, st->window, st->width, st->height, xgwa.depth);
1450 st->stars_mask = XCreatePixmap (st->dpy, st->window, st->width, st->height, 1);
1452 gcv.foreground = st->default_fg_pixel =
1453 get_pixel_resource (st->dpy, st->cmap, "foreground", "Foreground");
1454 st->draw_gc = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
1456 st->stars_gc = XCreateGC (st->dpy, st->stars_mask, GCForeground, &gcv);
1458 gcv.foreground = get_pixel_resource (st->dpy, st->cmap, "background", "Background");
1459 st->erase_gc = XCreateGC (st->dpy, st->dbuf, GCForeground, &gcv);
1461 st->stars_erase_gc = XCreateGC (st->dpy, st->stars_mask, GCForeground, &gcv);
1463 st->wire_flag = get_boolean_resource (st->dpy, "wire", "Boolean");
1465 st->psychedelic_flag = get_boolean_resource (st->dpy, "psychedelic", "Boolean");
1467 st->delay = get_integer_resource(st->dpy, "delay", "Integer");
1469 st->smoothness = get_integer_resource(st->dpy, "smoothness", "Integer");
1470 if (st->smoothness < 1) st->smoothness = 1;
1472 st->maxspeed = get_float_resource(st->dpy, "maxspeed", "Float");
1473 st->maxspeed *= 0.01;
1474 st->maxspeed = fabs(st->maxspeed);
1476 st->thrust = get_float_resource(st->dpy, "thrust", "Float");
1479 st->gravity = get_float_resource(st->dpy, "gravity", "Float");
1480 st->gravity *= 0.002/9.8;
1482 st->vertigo = get_float_resource(st->dpy, "vertigo", "Float");
1485 st->curviness = get_float_resource(st->dpy, "curviness", "Float");
1486 st->curviness *= 0.25;
1488 st->twistiness = get_float_resource(st->dpy, "twistiness", "Float");
1489 st->twistiness *= 0.125;
1491 st->terrain_flag = get_boolean_resource (st->dpy, "terrain", "Boolean");
1492 st->widening_flag = get_boolean_resource (st->dpy, "widening", "Boolean");
1493 st->bumps_flag = get_boolean_resource (st->dpy, "bumps", "Boolean");
1494 st->bonuses_flag = get_boolean_resource (st->dpy, "bonuses", "Boolean");
1495 st->crosshair_flag = get_boolean_resource (st->dpy, "crosshair", "Boolean");
1497 st->be_wormy = get_boolean_resource (st->dpy, "worm", "Boolean");
1499 st->maxspeed *= 1.43;
1503 st->smoothness *= 2;
1505 st->twistiness *= 2;
1506 st->psychedelic_flag = True;
1507 st->crosshair_flag = False;
1510 if (st->psychedelic_flag) init_psychedelic_colors (st);
1511 else init_colors (st);
1513 for (i=0; i<ROTS; i++) {
1514 th = M_PI * 2.0 * i / ROTS;
1515 st->costab[i] = cos(th);
1516 st->sintab[i] = sin(th);
1519 wide = random_wideness();
1521 for (i=0; i < TERRAIN_LENGTH; i++) {
1522 st->wideness[i] = wide;
1528 wrap_tunnel (st, 0, TERRAIN_LENGTH-1);
1531 if (DEBUG_FLAG || st->verbose_flag) atexit(print_stats);
1534 st->step = effective_speed;
1543 speedmine_reshape (Display *dpy, Window window, void *closure,
1544 unsigned int w, unsigned int h)
1546 struct state *st = (struct state *) closure;
1549 if (st->dbuf != st->window) {
1550 XWindowAttributes xgwa;
1551 XGetWindowAttributes (st->dpy, st->window, &xgwa);
1552 XFreePixmap (dpy, st->dbuf);
1553 st->dbuf = XCreatePixmap (st->dpy, st->window,
1554 st->width, st->height, xgwa.depth);
1559 speedmine_event (Display *dpy, Window window, void *closure, XEvent *event)
1565 speedmine_free (Display *dpy, Window window, void *closure)
1567 struct state *st = (struct state *) closure;
1574 * Down the speedmine, you'll find speed
1575 * to satisfy your moving needs;
1576 * So if you're looking for a blast
1577 * then hit the speedmine, really fast.
1581 * Speedworm likes to choke and spit
1582 * and chase his tail, and dance a bit
1583 * he really is a funky friend;
1584 * he's made of speed from end to end.
1588 static const char *speedmine_defaults [] = {
1592 ".background: black",
1593 ".foreground: white",
1594 "*darkground: #101010",
1595 "*lightground: #a0a0a0",
1596 "*tunnelend: #000000",
1610 "*psychedelic: False",
1614 static XrmOptionDescRec speedmine_options [] = {
1615 { "-verbose", ".verbose", XrmoptionNoArg, "True"},
1616 { "-worm", ".worm", XrmoptionNoArg, "True"},
1617 { "-wireframe", ".wire", XrmoptionNoArg, "True"},
1618 { "-no-wireframe", ".wire", XrmoptionNoArg, "False"},
1619 { "-darkground", ".darkground", XrmoptionSepArg, 0 },
1620 { "-lightground", ".lightground", XrmoptionSepArg, 0 },
1621 { "-tunnelend", ".tunnelend", XrmoptionSepArg, 0 },
1622 { "-delay", ".delay", XrmoptionSepArg, 0 },
1623 { "-maxspeed", ".maxspeed", XrmoptionSepArg, 0 },
1624 { "-thrust", ".thrust", XrmoptionSepArg, 0 },
1625 { "-gravity", ".gravity", XrmoptionSepArg, 0 },
1626 { "-vertigo", ".vertigo", XrmoptionSepArg, 0 },
1627 { "-terrain", ".terrain", XrmoptionNoArg, "True"},
1628 { "-no-terrain", ".terrain", XrmoptionNoArg, "False"},
1629 { "-smoothness", ".smoothness", XrmoptionSepArg, 0 },
1630 { "-curviness", ".curviness", XrmoptionSepArg, 0 },
1631 { "-twistiness", ".twistiness", XrmoptionSepArg, 0 },
1632 { "-widening", ".widening", XrmoptionNoArg, "True"},
1633 { "-no-widening", ".widening", XrmoptionNoArg, "False"},
1634 { "-bumps", ".bumps", XrmoptionNoArg, "True"},
1635 { "-no-bumps", ".bumps", XrmoptionNoArg, "False"},
1636 { "-bonuses", ".bonuses", XrmoptionNoArg, "True"},
1637 { "-no-bonuses", ".bonuses", XrmoptionNoArg, "False"},
1638 { "-crosshair", ".crosshair", XrmoptionNoArg, "True"},
1639 { "-no-crosshair", ".crosshair", XrmoptionNoArg, "False"},
1640 { "-psychedelic", ".psychedelic", XrmoptionNoArg, "True"},
1641 { "-no-psychedelic", ".psychedelic", XrmoptionNoArg, "False"},
1646 XSCREENSAVER_MODULE ("SpeedMine", speedmine)