1 /* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@mcom.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>
16 #include "screenhack.h"
20 #include <math.h> /* for M_PI */
23 #define MIN_DEPTH 2 /* rocks disappar when they get this close */
24 #define MAX_DEPTH 60 /* this is where rocks appear */
25 #define MAX_WIDTH 100 /* how big (in pixels) rocks are at depth 1 */
26 #define DEPTH_SCALE 100 /* how many ticks there are between depths */
27 #define SIN_RESOLUTION 1000
29 /* there's not much point in the above being user-customizable, but those
30 numbers might want to be tweaked for displays with an order of magnitude
31 higher resolution or compute power.
34 static double sins [SIN_RESOLUTION];
35 static double coss [SIN_RESOLUTION];
36 static double depths [(MAX_DEPTH + 1) * DEPTH_SCALE];
40 static int width, height, midx, midy;
41 static GC draw_gc, erase_gc;
42 static Bool rotate_p ;
54 static struct rock *rocks;
56 static Pixmap pixmaps [MAX_WIDTH];
59 static void rock_reset(), rock_tick(), rock_compute(), rock_draw();
60 static void init_pixmaps(), init_rocks(), tick_rocks(), rocks_once();
67 rock->real_size = MAX_WIDTH;
68 rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION));
69 rock->theta = random () % SIN_RESOLUTION;
70 rock->depth = MAX_DEPTH * DEPTH_SCALE;
72 rock_draw (rock, True);
82 rock_draw (rock, False);
86 rock->theta = (rock->theta + d) % SIN_RESOLUTION;
88 while (rock->theta < 0)
89 rock->theta += SIN_RESOLUTION;
90 if (rock->depth < (MIN_DEPTH * DEPTH_SCALE))
95 rock_draw (rock, True);
98 else if ((random () % 40) == 0)
106 double factor = depths [rock->depth];
107 rock->size = (int) ((rock->real_size * factor) + 0.5);
108 rock->x = midx + (coss [rock->theta] * rock->r * factor);
109 rock->y = midy + (sins [rock->theta] * rock->r * factor);
113 rock_draw (rock, draw_p)
117 GC gc = draw_p ? draw_gc : erase_gc;
118 if (rock->x <= 0 || rock->y <= 0 || rock->x >= width || rock->y >= height)
120 /* this means that if a rock were to go off the screen at 12:00, but
121 would have been visible at 3:00, it won't come back once the observer
122 rotates around so that the rock would have been visible again.
129 XDrawPoint (dpy, window, gc, rock->x, rock->y);
130 else if (rock->size <= 3 || !draw_p)
131 XFillRectangle (dpy, window, gc,
132 rock->x - rock->size/2, rock->y - rock->size/2,
133 rock->size, rock->size);
134 else if (rock->size < MAX_WIDTH)
135 XCopyPlane (dpy, pixmaps [rock->size], window, gc,
136 0, 0, rock->size, rock->size,
137 rock->x - rock->size/2, rock->y - rock->size/2,
145 init_pixmaps (dpy, window)
152 pixmaps [0] = pixmaps [1] = 0;
153 for (i = MIN_DEPTH; i < MAX_WIDTH; i++)
155 int w = (1+(i/32))<<5; /* server might be faster if word-aligned */
157 Pixmap p = XCreatePixmap (dpy, window, w, h, 1);
162 fprintf (stderr, "%s: couldn't allocate pixmaps", progname);
166 { /* must use drawable of pixmap, not window (fmh) */
168 fg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
170 bg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
172 XFillRectangle (dpy, p, bg_gc, 0, 0, w, h);
173 points [0].x = i * 0.15; points [0].y = i * 0.85;
174 points [1].x = i * 0.00; points [1].y = i * 0.20;
175 points [2].x = i * 0.30; points [2].y = i * 0.00;
176 points [3].x = i * 0.40; points [3].y = i * 0.10;
177 points [4].x = i * 0.90; points [4].y = i * 0.10;
178 points [5].x = i * 1.00; points [5].y = i * 0.55;
179 points [6].x = i * 0.45; points [6].y = i * 1.00;
180 XFillPolygon (dpy, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin);
182 XFreeGC (dpy, fg_gc);
183 XFreeGC (dpy, bg_gc);
195 XWindowAttributes xgwa;
199 XGetWindowAttributes (dpy, window, &xgwa);
200 cmap = xgwa.colormap;
201 delay = get_integer_resource ("delay", "Integer");
202 if (delay < 0) delay = 0;
203 speed = get_integer_resource ("speed", "Integer");
204 if (speed < 1) speed = 1;
205 if (speed > 100) speed = 100;
206 rotate_p = get_boolean_resource ("rotate", "Boolean");
207 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
208 bg = get_pixel_resource ("background", "Background", dpy, cmap);
211 draw_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
214 erase_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
216 for (i = 0; i < SIN_RESOLUTION; i++)
218 sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
219 coss [i] = cos ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
221 /* we actually only need i/speed of these, but wtf */
222 for (i = 1; i < (sizeof (depths) / sizeof (depths[0])); i++)
223 depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE));
224 depths [0] = M_PI/2; /* avoid division by 0 */
226 nrocks = get_integer_resource ("count", "Count");
227 if (nrocks < 1) nrocks = 1;
228 rocks = (struct rock *) calloc (nrocks, sizeof (struct rock));
229 init_pixmaps (dpy, window);
230 XClearWindow (dpy, window);
239 for (i = 0; i < nrocks; i++)
240 rock_tick (&rocks [i], d);
246 static int current_delta = 0; /* observer Z rotation */
247 static int window_tick = 50;
249 if (window_tick++ == 50)
251 XWindowAttributes xgwa;
252 XGetWindowAttributes (dpy, window, &xgwa);
255 height = xgwa.height;
260 if ((random () % 50) == 0)
262 int d = current_delta;
263 int new_delta = ((random () % 11) - 5);
264 if ((random () % 10) == 0)
267 while (d == current_delta)
270 for (i = 0; i < 3; i++)
272 if (current_delta < new_delta) d++;
275 current_delta = new_delta;
277 tick_rocks (current_delta);
281 char *progclass = "Rocks";
283 char *defaults [] = {
284 "Rocks.background: black", /* to placate SGI */
285 "Rocks.foreground: white",
293 XrmOptionDescRec options [] = {
294 { "-count", ".count", XrmoptionSepArg, 0 },
295 { "-norotate", ".rotate", XrmoptionNoArg, "false" },
296 { "-delay", ".delay", XrmoptionSepArg, 0 },
297 { "-speed", ".speed", XrmoptionSepArg, 0 }
299 int options_size = (sizeof (options) / sizeof (options[0]));
302 screenhack (dpy, window)
306 init_rocks (dpy, window);
311 if (delay) usleep (delay);