X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=hacks%2Frocks.c;h=f70f26c2ab240c02a403acf3ec6e10f06854626d;hb=0bd2eabab3e404c6769fe8f59b639275e960c415;hp=e97e6df39228293a065158ce3be3cee8183d54b1;hpb=0a1527cc01e9894017614b7c36b838b2b6914ba9;p=xscreensaver diff --git a/hacks/rocks.c b/hacks/rocks.c index e97e6df3..f70f26c2 100644 --- a/hacks/rocks.c +++ b/hacks/rocks.c @@ -1,4 +1,5 @@ -/* xscreensaver, Copyright (c) 1992 Jamie Zawinski +/* xscreensaver, Copyright (c) 1992, 1995, 1996, 1997 + * Jamie Zawinski * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that @@ -9,23 +10,32 @@ * implied warranty. */ -/* Flying through an asteroid field. Based on TI Explorer Lisp code by +/* 18-Sep-97: Johannes Keukelaar : 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 */ -#include "screenhack.h" #include #include -#if __STDC__ -#include -#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. @@ -38,10 +48,23 @@ static double depths [(MAX_DEPTH + 1) * DEPTH_SCALE]; 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; @@ -49,33 +72,32 @@ struct rock { 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) { @@ -100,13 +122,26 @@ rock_tick (rock, d) } 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 @@ -114,7 +149,10 @@ rock_draw (rock, draw_p) 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 @@ -122,35 +160,80 @@ rock_draw (rock, draw_p) 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; @@ -184,16 +267,123 @@ init_pixmaps (dpy, window) } +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); @@ -204,15 +394,62 @@ init_rocks (d, w) 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); @@ -223,6 +460,22 @@ init_rocks (d, w) 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)); @@ -231,77 +484,44 @@ init_rocks (d, w) } -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); -} - char *progclass = "Rocks"; char *defaults [] = { - "*background: black", - "*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)