-/* xscreensaver, Copyright (c) 1992 Jamie Zawinski <jwz@mcom.com>
+/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997, 1998
+ * Jamie Zawinski <jwz@jwz.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* implied warranty.
*/
-/* Flying through an asteroid field. Based on TI Explorer Lisp code by
+/* 18-Sep-97: Johannes Keukelaar <johannes@nada.kth.se>: Added some color.
+ * Using -mono gives the old behaviour. (Modified by jwz.)
+ */
+/* Flying through an asteroid field. Based on TI Explorer Lisp code by
John Nguyen <johnn@hx.lcs.mit.edu>
*/
-#include "screenhack.h"
#include <stdio.h>
#include <math.h>
-#if __STDC__
-#include <math.h> /* for M_PI */
-#endif
+#include "screenhack.h"
-#define MIN_DEPTH 2 /* rocks disappar when they get this close */
+#define MIN_ROCKS 1
+#define MIN_DEPTH 2 /* rocks disappear when they get this close */
#define MAX_DEPTH 60 /* this is where rocks appear */
-#define MAX_WIDTH 100 /* how big (in pixels) rocks are at depth 1 */
+#define MIN_SIZE 3 /* how small where pixmaps are not used */
+#define MAX_SIZE 200 /* how big (in pixels) rocks are at depth 1 */
#define DEPTH_SCALE 100 /* how many ticks there are between depths */
#define SIN_RESOLUTION 1000
+#define MAX_DEP 0.3 /* how far the displacement can be (percent) */
+#define DIRECTION_CHANGE_RATE 60
+#define MAX_DEP_SPEED 5 /* Maximum speed for movement */
+#define MOVE_STYLE 0 /* Only 0 and 1. Distinguishes the fact that
+ these are the rocks that are moving (1)
+ or the rocks source (0). */
+
/* there's not much point in the above being user-customizable, but those
numbers might want to be tweaked for displays with an order of magnitude
higher resolution or compute power.
static Display *dpy;
static Window window;
static int width, height, midx, midy;
-static GC draw_gc, erase_gc;
-static Bool rotate_p ;
-
+static int dep_x, dep_y;
+static int ncolors;
+static XColor *colors;
+static float max_dep;
+static GC erase_gc;
+static GC *draw_gcs;
+static Bool rotate_p;
+static Bool move_p;
static int speed;
+static Bool threed;
+static GC threed_left_gc, threed_right_gc;
+static double threed_delta;
+
+#define GETZDIFF(z) \
+ (threed_delta * 40.0 * \
+ (1.0 - ((MAX_DEPTH * DEPTH_SCALE / 2) / \
+ ((z) + 20.0 * DEPTH_SCALE))))
struct rock {
int real_size;
int theta;
int depth;
int size, x, y;
+ int diff;
+ int color;
};
static struct rock *rocks;
static int nrocks;
-static Pixmap pixmaps [MAX_WIDTH];
+static Pixmap pixmaps [MAX_SIZE];
static int delay;
-static void rock_reset(), rock_tick(), rock_compute(), rock_draw();
-static void init_pixmaps(), init_rocks(), tick_rocks(), rocks_once();
-
+static void rock_compute (struct rock *);
+static void rock_draw (struct rock *, Bool draw_p);
static void
-rock_reset (rock)
- struct rock *rock;
+rock_reset (struct rock *rock)
{
- rock->real_size = MAX_WIDTH;
+ rock->real_size = MAX_SIZE;
rock->r = (SIN_RESOLUTION * 0.7) + (random () % (30 * SIN_RESOLUTION));
rock->theta = random () % SIN_RESOLUTION;
rock->depth = MAX_DEPTH * DEPTH_SCALE;
+ rock->color = random() % ncolors;
rock_compute (rock);
rock_draw (rock, True);
}
static void
-rock_tick (rock, d)
- struct rock *rock;
- int d;
+rock_tick (struct rock *rock, int d)
{
if (rock->depth > 0)
{
}
static void
-rock_compute (rock)
- struct rock *rock;
+rock_compute (struct rock *rock)
{
double factor = depths [rock->depth];
- rock->size = (int) ((rock->real_size * factor) + 0.5);
+ double rsize = rock->real_size * factor;
+
+ rock->size = (int) (rsize + 0.5);
+ rock->diff = (int) GETZDIFF(rock->depth);
rock->x = midx + (coss [rock->theta] * rock->r * factor);
rock->y = midy + (sins [rock->theta] * rock->r * factor);
+
+ if (move_p)
+ {
+ double move_factor = (((double) MOVE_STYLE) -
+ (((double) rock->depth) /
+ (((double) (MAX_DEPTH + 1)) *
+ ((double) DEPTH_SCALE))));
+ /* move_factor is 0 when the rock is close, 1 when far */
+ rock->x += (((double) dep_x) * move_factor);
+ rock->y += (((double) dep_y) * move_factor);
+ }
}
static void
struct rock *rock;
Bool draw_p;
{
- GC gc = draw_p ? draw_gc : erase_gc;
+ GC gc = (draw_p
+ ? (threed ? erase_gc : draw_gcs[rock->color])
+ : erase_gc);
+
if (rock->x <= 0 || rock->y <= 0 || rock->x >= width || rock->y >= height)
{
/* this means that if a rock were to go off the screen at 12:00, but
rotates around so that the rock would have been visible again.
Oh well.
*/
- rock->depth = 0;
+ if (!move_p)
+ rock->depth = 0;
return;
}
if (rock->size <= 1)
- XDrawPoint (dpy, window, gc, rock->x, rock->y);
- else if (rock->size <= 3 || !draw_p)
- XFillRectangle (dpy, window, gc,
- rock->x - rock->size/2, rock->y - rock->size/2,
- rock->size, rock->size);
- else if (rock->size < MAX_WIDTH)
- XCopyPlane (dpy, pixmaps [rock->size], window, gc,
- 0, 0, rock->size, rock->size,
- rock->x - rock->size/2, rock->y - rock->size/2,
- 1);
- else
- abort ();
+ {
+ if (threed)
+ {
+ if (draw_p) gc = threed_left_gc;
+ XDrawPoint (dpy, window, gc, rock->x - rock->diff, rock->y);
+ if (draw_p) gc = threed_right_gc;
+ XDrawPoint (dpy, window, gc, rock->x + rock->diff, rock->y);
+ }
+ else
+ {
+ XDrawPoint (dpy, window, gc, rock->x, rock->y);
+ }
+ }
+ else if (rock->size <= MIN_SIZE || !draw_p)
+ {
+ if (threed)
+ {
+ if (draw_p) gc = threed_left_gc;
+ XFillRectangle(dpy, window, gc,
+ rock->x - rock->size / 2 - rock->diff,
+ rock->y - rock->size / 2,
+ rock->size, rock->size);
+ if (draw_p) gc = threed_right_gc;
+ XFillRectangle(dpy, window, gc,
+ rock->x - rock->size / 2 + rock->diff,
+ rock->y - rock->size / 2,
+ rock->size, rock->size);
+ }
+ else
+ {
+ XFillRectangle (dpy, window, gc,
+ rock->x - rock->size/2, rock->y - rock->size/2,
+ rock->size, rock->size);
+ }
+ }
+ else if (rock->size < MAX_SIZE)
+ {
+ if (threed)
+ {
+ gc = threed_left_gc;
+ XCopyPlane(dpy, pixmaps[rock->size], window, gc,
+ 0, 0, rock->size, rock->size,
+ rock->x - rock->size / 2 - rock->diff,
+ rock->y - rock->size / 2, 1L);
+ gc = threed_right_gc;
+ XCopyPlane(dpy, pixmaps[rock->size], window, gc,
+ 0, 0, rock->size, rock->size,
+ rock->x - rock->size / 2 + rock->diff,
+ rock->y - rock->size / 2, 1L);
+ }
+ else
+ {
+ XCopyPlane (dpy, pixmaps [rock->size], window, gc,
+ 0, 0, rock->size, rock->size,
+ rock->x - rock->size/2, rock->y - rock->size/2,
+ 1L);
+ }
+ }
}
static void
-init_pixmaps (dpy, window)
- Display *dpy;
- Window window;
+init_pixmaps (Display *dpy, Window window)
{
int i;
XGCValues gcv;
- GC fg_gc = 0, bg_gc;
+ GC fg_gc = 0, bg_gc = 0;
pixmaps [0] = pixmaps [1] = 0;
- for (i = MIN_DEPTH; i < MAX_WIDTH; i++)
+ for (i = MIN_DEPTH; i < MAX_SIZE; i++)
{
int w = (1+(i/32))<<5; /* server might be faster if word-aligned */
int h = i;
}
+static int
+compute_move(int axe) /* 0 for x, 1 for y */
+{
+ static int current_dep[2] = {0, 0};
+ static int speed[2] = {0, 0};
+ static short direction[2] = {0, 0};
+ static int limit[2] = {0, 0};
+ int change = 0;
+
+ limit[0] = midx;
+ limit[1] = midy;
+
+ current_dep[axe] += speed[axe]; /* We adjust the displacement */
+
+ if (current_dep[axe] > (int) (limit[axe] * max_dep))
+ {
+ if (current_dep[axe] > limit[axe])
+ current_dep[axe] = limit[axe];
+ direction[axe] = -1;
+ } /* This is when we reach the upper screen limit */
+ if (current_dep[axe] < (int) (-limit[axe] * max_dep))
+ {
+ if (current_dep[axe] < -limit[axe])
+ current_dep[axe] = -limit[axe];
+ direction[axe] = 1;
+ } /* This is when we reach the lower screen limit */
+ if (direction[axe] == 1) /* We adjust the speed */
+ speed[axe] += 1;
+ else if (direction[axe] == -1)
+ speed[axe] -= 1;
+
+ if (speed[axe] > MAX_DEP_SPEED)
+ speed[axe] = MAX_DEP_SPEED;
+ else if (speed[axe] < -MAX_DEP_SPEED)
+ speed[axe] = -MAX_DEP_SPEED;
+
+ if (move_p && !(random() % DIRECTION_CHANGE_RATE))
+ {
+ /* We change direction */
+ change = random() & 1;
+ if (change != 1)
+ {
+ if (direction[axe] == 0)
+ direction[axe] = change - 1; /* 0 becomes either 1 or -1 */
+ else
+ direction[axe] = 0; /* -1 or 1 become 0 */
+ }
+ }
+ return (current_dep[axe]);
+}
+
static void
-init_rocks (d, w)
- Display *d;
- Window w;
+tick_rocks (int d)
+{
+ int i;
+
+ if (move_p)
+ {
+ dep_x = compute_move(0);
+ dep_y = compute_move(1);
+ }
+
+ for (i = 0; i < nrocks; i++)
+ rock_tick (&rocks [i], d);
+}
+
+
+static void
+rocks_once (void)
+{
+ static int current_delta = 0; /* observer Z rotation */
+ static int window_tick = 50;
+ static int new_delta = 0;
+ static int dchange_tick = 0;
+
+ if (window_tick++ == 50)
+ {
+ XWindowAttributes xgwa;
+ XGetWindowAttributes (dpy, window, &xgwa);
+ window_tick = 0;
+ width = xgwa.width;
+ height = xgwa.height;
+ midx = width/2;
+ midy = height/2;
+ }
+
+ if (current_delta != new_delta)
+ {
+ if (dchange_tick++ == 5)
+ {
+ dchange_tick = 0;
+ if (current_delta < new_delta)
+ current_delta++;
+ else
+ current_delta--;
+ }
+ }
+ else
+ {
+ if (! (random() % 50))
+ {
+ new_delta = ((random() % 11) - 5);
+ if (! (random() % 10))
+ new_delta *= 5;
+ }
+ }
+ tick_rocks (current_delta);
+}
+
+static void
+init_rocks (Display *d, Window w)
{
int i;
XGCValues gcv;
Colormap cmap;
XWindowAttributes xgwa;
- unsigned int fg, bg;
+ unsigned int bg;
dpy = d;
window = w;
XGetWindowAttributes (dpy, window, &xgwa);
if (speed < 1) speed = 1;
if (speed > 100) speed = 100;
rotate_p = get_boolean_resource ("rotate", "Boolean");
- fg = get_pixel_resource ("foreground", "Foreground", dpy, cmap);
+ move_p = get_boolean_resource ("move", "Boolean");
+ if (mono_p)
+ ncolors = 2;
+ else
+ ncolors = get_integer_resource ("colors", "Colors");
+
+ if (ncolors < 2)
+ {
+ ncolors = 2;
+ mono_p = True;
+ }
+
+ colors = (XColor *) malloc(ncolors * sizeof(*colors));
+ draw_gcs = (GC *) malloc(ncolors * sizeof(*draw_gcs));
+
bg = get_pixel_resource ("background", "Background", dpy, cmap);
- gcv.foreground = fg;
- gcv.background = bg;
- draw_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+ colors[0].pixel = bg;
+ colors[0].flags = DoRed|DoGreen|DoBlue;
+ XQueryColor(dpy, cmap, &colors[0]);
+
+ ncolors--;
+ make_random_colormap(dpy, xgwa.visual, cmap, colors+1, &ncolors, True,
+ True, 0, True);
+ ncolors++;
+
+ if (ncolors < 2)
+ {
+ ncolors = 2;
+ mono_p = True;
+ }
+
+ if (mono_p)
+ {
+ unsigned int fg = get_pixel_resource("foreground", "Foreground",
+ dpy, cmap);
+ colors[1].pixel = fg;
+ colors[1].flags = DoRed|DoGreen|DoBlue;
+ XQueryColor(dpy, cmap, &colors[1]);
+ gcv.foreground = fg;
+ gcv.background = bg;
+ draw_gcs[0] = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+ draw_gcs[1] = draw_gcs[0];
+ }
+ else
+ for( i = 0; i < ncolors; i++ )
+ {
+ gcv.foreground = colors[i].pixel;
+ gcv.background = bg;
+ draw_gcs[i] = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+ }
+
gcv.foreground = bg;
- gcv.background = fg;
erase_gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv);
+ max_dep = (move_p ? MAX_DEP : 0);
+
for (i = 0; i < SIN_RESOLUTION; i++)
{
sins [i] = sin ((((double) i) / (SIN_RESOLUTION / 2)) * M_PI);
depths [i] = atan (((double) 0.5) / (((double) i) / DEPTH_SCALE));
depths [0] = M_PI/2; /* avoid division by 0 */
+ threed = get_boolean_resource("use3d", "Boolean");
+ if (threed)
+ {
+ gcv.background = bg;
+ gcv.foreground = get_pixel_resource ("left3d", "Foreground", dpy, cmap);
+ threed_left_gc = XCreateGC (dpy, window, GCForeground|GCBackground,&gcv);
+ gcv.foreground = get_pixel_resource ("right3d", "Foreground", dpy, cmap);
+ threed_right_gc = XCreateGC (dpy, window,GCForeground|GCBackground,&gcv);
+ threed_delta = get_float_resource("delta3d", "Integer");
+ }
+
+ /* don't want any exposure events from XCopyPlane */
+ for( i = 0; i < ncolors; i++)
+ XSetGraphicsExposures (dpy, draw_gcs[i], False);
+ XSetGraphicsExposures (dpy, erase_gc, False);
+
nrocks = get_integer_resource ("count", "Count");
if (nrocks < 1) nrocks = 1;
rocks = (struct rock *) calloc (nrocks, sizeof (struct rock));
}
-static void
-tick_rocks (d)
- int d;
-{
- int i;
- for (i = 0; i < nrocks; i++)
- rock_tick (&rocks [i], d);
-}
-
-static void
-rocks_once ()
-{
- static int current_delta = 0; /* observer Z rotation */
- static int window_tick = 50;
-
- if (window_tick++ == 50)
- {
- XWindowAttributes xgwa;
- XGetWindowAttributes (dpy, window, &xgwa);
- window_tick = 0;
- width = xgwa.width;
- height = xgwa.height;
- midx = width/2;
- midy = height/2;
- }
-
- if ((random () % 50) == 0)
- {
- int d = current_delta;
- int new_delta = ((random () % 11) - 5);
- if ((random () % 10) == 0)
- new_delta *= 5;
-
- while (d == current_delta)
- {
- int i;
- for (i = 0; i < 3; i++)
- tick_rocks (d);
- if (current_delta < new_delta) d++;
- else d--;
- }
- current_delta = new_delta;
- }
- tick_rocks (current_delta);
-}
-
\f
char *progclass = "Rocks";
char *defaults [] = {
- "Rocks.background: black", /* to placate SGI */
- "Rocks.foreground: white",
+ ".background: Black",
+ ".foreground: #E9967A",
+ "*colors: 5",
"*count: 100",
"*delay: 50000",
"*speed: 100",
"*rotate: true",
+ "*move: true",
+ "*use3d: False",
+ "*left3d: Blue",
+ "*right3d: Red",
+ "*delta3d: 1.5",
0
};
XrmOptionDescRec options [] = {
{ "-count", ".count", XrmoptionSepArg, 0 },
+ { "-rotate", ".rotate", XrmoptionNoArg, "true" },
{ "-norotate", ".rotate", XrmoptionNoArg, "false" },
+ { "-move", ".move", XrmoptionNoArg, "true" },
+ { "-nomove", ".move", XrmoptionNoArg, "false" },
{ "-delay", ".delay", XrmoptionSepArg, 0 },
- { "-speed", ".speed", XrmoptionSepArg, 0 }
+ { "-speed", ".speed", XrmoptionSepArg, 0 },
+ {"-3d", ".use3d", XrmoptionNoArg, "True"},
+ {"-no-3d", ".use3d", XrmoptionNoArg, "False"},
+ {"-left3d", ".left3d", XrmoptionSepArg, 0 },
+ {"-right3d", ".right3d", XrmoptionSepArg, 0 },
+ {"-delta3d", ".delta3d", XrmoptionSepArg, 0 },
+ { "-colors", ".colors", XrmoptionSepArg, 0 },
+ { 0, 0, 0, 0 }
};
-int options_size = (sizeof (options) / sizeof (options[0]));
void
-screenhack (dpy, window)
- Display *dpy;
- Window window;
+screenhack (Display *dpy, Window window)
{
init_rocks (dpy, window);
while (1)
{
rocks_once ();
- XSync (dpy, True);
+ XSync (dpy, False);
+ screenhack_handle_events (dpy);
if (delay) usleep (delay);
}
}