1 /* xscreensaver, Copyright (c) 1992, 1995 Jamie Zawinski <jwz@netscape.com>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 /* Flying through an asteroid field. Based on TI Explorer Lisp code by
13 John Nguyen <johnn@hx.lcs.mit.edu>
18 #include "screenhack.h"
20 #define MIN_DEPTH 2 /* rocks disappar when they get this close */
21 #define MAX_DEPTH 60 /* this is where rocks appear */
22 #define MAX_WIDTH 100 /* how big (in pixels) rocks are at depth 1 */
23 #define DEPTH_SCALE 100 /* how many ticks there are between depths */
24 #define SIN_RESOLUTION 1000
26 /* there's not much point in the above being user-customizable, but those
27 numbers might want to be tweaked for displays with an order of magnitude
28 higher resolution or compute power.
31 static double sins [SIN_RESOLUTION];
32 static double coss [SIN_RESOLUTION];
33 static double depths [(MAX_DEPTH + 1) * DEPTH_SCALE];
37 static int width, height, midx, midy;
38 static GC draw_gc, erase_gc;
39 static Bool rotate_p ;
51 static struct rock *rocks;
53 static Pixmap pixmaps [MAX_WIDTH];
56 static void rock_reset(), rock_tick(), rock_compute(), rock_draw();
57 static void init_pixmaps(), init_rocks(), tick_rocks(), rocks_once();
64 rock->real_size = MAX_WIDTH;
65 rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION));
66 rock->theta = random () % SIN_RESOLUTION;
67 rock->depth = MAX_DEPTH * DEPTH_SCALE;
69 rock_draw (rock, True);
79 rock_draw (rock, False);
83 rock->theta = (rock->theta + d) % SIN_RESOLUTION;
85 while (rock->theta < 0)
86 rock->theta += SIN_RESOLUTION;
87 if (rock->depth < (MIN_DEPTH * DEPTH_SCALE))
92 rock_draw (rock, True);
95 else if ((random () % 40) == 0)
103 double factor = depths [rock->depth];
104 rock->size = (int) ((rock->real_size * factor) + 0.5);
105 rock->x = midx + (coss [rock->theta] * rock->r * factor);
106 rock->y = midy + (sins [rock->theta] * rock->r * factor);
110 rock_draw (rock, draw_p)
114 GC gc = draw_p ? draw_gc : erase_gc;
115 if (rock->x <= 0 || rock->y <= 0 || rock->x >= width || rock->y >= height)
117 /* this means that if a rock were to go off the screen at 12:00, but
118 would have been visible at 3:00, it won't come back once the observer
119 rotates around so that the rock would have been visible again.
126 XDrawPoint (dpy, window, gc, rock->x, rock->y);
127 else if (rock->size <= 3 || !draw_p)
128 XFillRectangle (dpy, window, gc,
129 rock->x - rock->size/2, rock->y - rock->size/2,
130 rock->size, rock->size);
131 else if (rock->size < MAX_WIDTH)
132 XCopyPlane (dpy, pixmaps [rock->size], window, gc,
133 0, 0, rock->size, rock->size,
134 rock->x - rock->size/2, rock->y - rock->size/2,
142 init_pixmaps (dpy, window)
148 GC fg_gc = 0, bg_gc = 0;
149 pixmaps [0] = pixmaps [1] = 0;
150 for (i = MIN_DEPTH; i < MAX_WIDTH; i++)
152 int w = (1+(i/32))<<5; /* server might be faster if word-aligned */
154 Pixmap p = XCreatePixmap (dpy, window, w, h, 1);
159 fprintf (stderr, "%s: couldn't allocate pixmaps", progname);
163 { /* must use drawable of pixmap, not window (fmh) */
165 fg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
167 bg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
169 XFillRectangle (dpy, p, bg_gc, 0, 0, w, h);
170 points [0].x = i * 0.15; points [0].y = i * 0.85;
171 points [1].x = i * 0.00; points [1].y = i * 0.20;
172 points [2].x = i * 0.30; points [2].y = i * 0.00;
173 points [3].x = i * 0.40; points [3].y = i * 0.10;
174 points [4].x = i * 0.90; points [4].y = i * 0.10;
175 points [5].x = i * 1.00; points [5].y = i * 0.55;
176 points [6].x = i * 0.45; points [6].y = i * 1.00;
177 XFillPolygon (dpy, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin);
179 XFreeGC (dpy, fg_gc);
180 XFreeGC (dpy, bg_gc);
192 XWindowAttributes xgwa;
196 XGetWindowAttributes (dpy, window, &xgwa);
197 cmap = xgwa.colormap;
198 delay = get_integer_resource ("delay", "Integer");
199 if (delay < 0) delay = 0;
200 speed = get_integer_resource ("speed", "Integer");
201 if (speed < 1) speed = 1;
202 if (speed > 100) speed = 100;
203 rotate_p = get_boolean_resource ("rotate", "Boolean");
204 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
205 bg = get_pixel_resource ("background", "Background", dpy, cmap);
208 draw_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
211 erase_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
213 for (i = 0; i < SIN_RESOLUTION; i++)
215 sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
216 coss [i] = cos ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
218 /* we actually only need i/speed of these, but wtf */
219 for (i = 1; i < (sizeof (depths) / sizeof (depths[0])); i++)
220 depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE));
221 depths [0] = M_PI/2; /* avoid division by 0 */
223 nrocks = get_integer_resource ("count", "Count");
224 if (nrocks < 1) nrocks = 1;
225 rocks = (struct rock *) calloc (nrocks, sizeof (struct rock));
226 init_pixmaps (dpy, window);
227 XClearWindow (dpy, window);
236 for (i = 0; i < nrocks; i++)
237 rock_tick (&rocks [i], d);
243 static int current_delta = 0; /* observer Z rotation */
244 static int window_tick = 50;
246 if (window_tick++ == 50)
248 XWindowAttributes xgwa;
249 XGetWindowAttributes (dpy, window, &xgwa);
252 height = xgwa.height;
257 if ((random () % 50) == 0)
259 int d = current_delta;
260 int new_delta = ((random () % 11) - 5);
261 if ((random () % 10) == 0)
264 while (d == current_delta)
267 for (i = 0; i < 3; i++)
269 if (current_delta < new_delta) d++;
272 current_delta = new_delta;
274 tick_rocks (current_delta);
278 char *progclass = "Rocks";
280 char *defaults [] = {
281 "Rocks.background: black", /* to placate SGI */
282 "Rocks.foreground: white",
290 XrmOptionDescRec options [] = {
291 { "-count", ".count", XrmoptionSepArg, 0 },
292 { "-norotate", ".rotate", XrmoptionNoArg, "false" },
293 { "-delay", ".delay", XrmoptionSepArg, 0 },
294 { "-speed", ".speed", XrmoptionSepArg, 0 }
296 int options_size = (sizeof (options) / sizeof (options[0]));
299 screenhack (dpy, window)
303 init_rocks (dpy, window);
308 if (delay) usleep (delay);