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 #define M_PI 3.14159265358979323846
23 #include <math.h> /* for M_PI */
26 #define MIN_DEPTH 2 /* rocks disappar when they get this close */
27 #define MAX_DEPTH 60 /* this is where rocks appear */
28 #define MAX_WIDTH 100 /* how big (in pixels) rocks are at depth 1 */
29 #define DEPTH_SCALE 100 /* how many ticks there are between depths */
30 #define SIN_RESOLUTION 1000
32 /* there's not much point in the above being user-customizable, but those
33 numbers might want to be tweaked for displays with an order of magnitude
34 higher resolution or compute power.
37 static double sins [SIN_RESOLUTION];
38 static double coss [SIN_RESOLUTION];
39 static double depths [(MAX_DEPTH + 1) * DEPTH_SCALE];
43 static int width, height, midx, midy;
44 static GC draw_gc, erase_gc;
45 static Bool rotate_p ;
57 static struct rock *rocks;
59 static Pixmap pixmaps [MAX_WIDTH];
62 static void rock_reset(), rock_tick(), rock_compute(), rock_draw();
63 static void init_pixmaps(), init_rocks(), tick_rocks(), rocks_once();
70 rock->real_size = MAX_WIDTH;
71 rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION));
72 rock->theta = random () % SIN_RESOLUTION;
73 rock->depth = MAX_DEPTH * DEPTH_SCALE;
75 rock_draw (rock, True);
85 rock_draw (rock, False);
89 rock->theta = (rock->theta + d) % SIN_RESOLUTION;
91 while (rock->theta < 0)
92 rock->theta += SIN_RESOLUTION;
93 if (rock->depth < (MIN_DEPTH * DEPTH_SCALE))
98 rock_draw (rock, True);
101 else if ((random () % 40) == 0)
109 double factor = depths [rock->depth];
110 rock->size = (int) ((rock->real_size * factor) + 0.5);
111 rock->x = midx + (coss [rock->theta] * rock->r * factor);
112 rock->y = midy + (sins [rock->theta] * rock->r * factor);
116 rock_draw (rock, draw_p)
120 GC gc = draw_p ? draw_gc : erase_gc;
121 if (rock->x <= 0 || rock->y <= 0 || rock->x >= width || rock->y >= height)
123 /* this means that if a rock were to go off the screen at 12:00, but
124 would have been visible at 3:00, it won't come back once the observer
125 rotates around so that the rock would have been visible again.
132 XDrawPoint (dpy, window, gc, rock->x, rock->y);
133 else if (rock->size <= 3 || !draw_p)
134 XFillRectangle (dpy, window, gc,
135 rock->x - rock->size/2, rock->y - rock->size/2,
136 rock->size, rock->size);
137 else if (rock->size < MAX_WIDTH)
138 XCopyPlane (dpy, pixmaps [rock->size], window, gc,
139 0, 0, rock->size, rock->size,
140 rock->x - rock->size/2, rock->y - rock->size/2,
148 init_pixmaps (dpy, window)
155 pixmaps [0] = pixmaps [1] = 0;
156 for (i = MIN_DEPTH; i < MAX_WIDTH; i++)
158 int w = (1+(i/32))<<5; /* server might be faster if word-aligned */
160 Pixmap p = XCreatePixmap (dpy, window, w, h, 1);
165 fprintf (stderr, "%s: couldn't allocate pixmaps", progname);
169 { /* must use drawable of pixmap, not window (fmh) */
171 fg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
173 bg_gc = XCreateGC (dpy, p, GCForeground, &gcv);
175 XFillRectangle (dpy, p, bg_gc, 0, 0, w, h);
176 points [0].x = i * 0.15; points [0].y = i * 0.85;
177 points [1].x = i * 0.00; points [1].y = i * 0.20;
178 points [2].x = i * 0.30; points [2].y = i * 0.00;
179 points [3].x = i * 0.40; points [3].y = i * 0.10;
180 points [4].x = i * 0.90; points [4].y = i * 0.10;
181 points [5].x = i * 1.00; points [5].y = i * 0.55;
182 points [6].x = i * 0.45; points [6].y = i * 1.00;
183 XFillPolygon (dpy, p, fg_gc, points, 7, Nonconvex, CoordModeOrigin);
185 XFreeGC (dpy, fg_gc);
186 XFreeGC (dpy, bg_gc);
198 XWindowAttributes xgwa;
202 XGetWindowAttributes (dpy, window, &xgwa);
203 cmap = xgwa.colormap;
204 delay = get_integer_resource ("delay", "Integer");
205 if (delay < 0) delay = 0;
206 speed = get_integer_resource ("speed", "Integer");
207 if (speed < 1) speed = 1;
208 if (speed > 100) speed = 100;
209 rotate_p = get_boolean_resource ("rotate", "Boolean");
210 fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
211 bg = get_pixel_resource ("background", "Background", dpy, cmap);
214 draw_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
217 erase_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
219 for (i = 0; i < SIN_RESOLUTION; i++)
221 sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
222 coss [i] = cos ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
224 /* we actually only need i/speed of these, but wtf */
225 for (i = 1; i < (sizeof (depths) / sizeof (depths[0])); i++)
226 depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE));
227 depths [0] = M_PI/2; /* avoid division by 0 */
229 nrocks = get_integer_resource ("count", "Count");
230 if (nrocks < 1) nrocks = 1;
231 rocks = (struct rock *) calloc (nrocks, sizeof (struct rock));
232 init_pixmaps (dpy, window);
233 XClearWindow (dpy, window);
242 for (i = 0; i < nrocks; i++)
243 rock_tick (&rocks [i], d);
249 static int current_delta = 0; /* observer Z rotation */
250 static int window_tick = 50;
252 if (window_tick++ == 50)
254 XWindowAttributes xgwa;
255 XGetWindowAttributes (dpy, window, &xgwa);
258 height = xgwa.height;
263 if ((random () % 50) == 0)
265 int d = current_delta;
266 int new_delta = ((random () % 11) - 5);
267 if ((random () % 10) == 0)
270 while (d == current_delta)
273 for (i = 0; i < 3; i++)
275 if (current_delta < new_delta) d++;
278 current_delta = new_delta;
280 tick_rocks (current_delta);
284 char *progclass = "Rocks";
286 char *defaults [] = {
287 "Rocks.background: black", /* to placate SGI */
288 "Rocks.foreground: white",
296 XrmOptionDescRec options [] = {
297 { "-count", ".count", XrmoptionSepArg, 0 },
298 { "-norotate", ".rotate", XrmoptionNoArg, "false" },
299 { "-delay", ".delay", XrmoptionSepArg, 0 },
300 { "-speed", ".speed", XrmoptionSepArg, 0 }
302 int options_size = (sizeof (options) / sizeof (options[0]));
305 screenhack (dpy, window)
309 init_rocks (dpy, window);
314 if (delay) usleep (delay);