X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fimsmap.c;h=fad6a8ca4dedf993df6257e681277f1ef84c60c4;hp=d8b1c088c51a2ac4ecdfcd0a9d7296fcfa676d79;hb=96a411663168b0ba5432b407a83be55f3df0c802;hpb=0cac953ce8d5139c1a264b417951ee15a3176b51 diff --git a/hacks/imsmap.c b/hacks/imsmap.c index d8b1c088..fad6a8ca 100644 --- a/hacks/imsmap.c +++ b/hacks/imsmap.c @@ -8,54 +8,61 @@ * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. + * + * Revision History: + * 24-aug-92: jwz: hacked. + * 17-May-97: jwz: hacked more. */ -#include "screenhack.h" #include +#include +#include +#include /* for gettimeofday() */ + +#include #include +#include "screenhack.h" + #define NSTEPS 7 #define COUNT (1 << NSTEPS) #define CELL(c, r) cell[((unsigned int)(c)) + ((unsigned int) (r)) * xmax] -static enum mode_t { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode; +static enum imsmap_mode { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode; static GC gc, gc2; -static Display *disp; -static Window wind; -static XWindowAttributes wattrs; +static XWindowAttributes xgwa; #if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */ #define signed /**/ #endif -static unsigned long *pixels = 0, fg_pixel, bg_pixel; -static int npixels = 0; static Colormap cmap; -static int timeout, cycle_delay; -static int cycle_p; +static int ncolors; +static XColor *colors; +static Bool cycle_p; +static int cycle_direction; +static Bool extra_krinkly_p; + +static int delay, cycle_delay; static signed char *cell = NULL; static int xmax, ymax; static int iterations; static void -initwin (dsp, win) - Display *dsp; - Window win; +init_map (Display *dpy, Window window) { + unsigned long fg_pixel = 0, bg_pixel = 0; int fg_h, bg_h; double fg_s, fg_v, bg_s, bg_v; - enum mode_t this_mode; + enum imsmap_mode this_mode; static Bool rv_p; - static int ncolors = 0; - int shift; - double dshift; XGCValues gcv; - XGetWindowAttributes (dsp, win, &wattrs); - cmap = wattrs.colormap; + XGetWindowAttributes (dpy, window, &xgwa); + cmap = xgwa.colormap; if (!ncolors) { @@ -63,25 +70,40 @@ initwin (dsp, win) rv_p = get_boolean_resource ("reverseVideo", "ReverseVideo"); cycle_p = get_boolean_resource ("cycle", "Cycle"); ncolors = get_integer_resource ("ncolors", "Integer"); - timeout = get_integer_resource ("timeout", "Integer"); + delay = get_integer_resource ("delay", "Integer"); cycle_delay = get_integer_resource ("cycleDelay", "Integer"); iterations = get_integer_resource ("iterations", "Integer"); if (iterations < 0) iterations = 0; else if (iterations > 7) iterations = 7; - pixels = (unsigned long *) calloc (ncolors, sizeof (unsigned int)); - fg_pixel = get_pixel_resource ("background", "Background", dsp, cmap); - bg_pixel = get_pixel_resource ("foreground", "Foreground", dsp, cmap); - if (mono_p && fg_pixel == bg_pixel) - bg_pixel = !bg_pixel; + if (ncolors <= 2) ncolors = 0; + if (ncolors == 0) mono_p = True; + if (ncolors > 255) ncolors = 255; /* too many look bad */ + + fg_pixel = get_pixel_resource ("background", "Background", dpy, cmap); + bg_pixel = get_pixel_resource ("foreground", "Foreground", dpy, cmap); + + if (fg_pixel == bg_pixel) + { + XColor black, white; + black.red = black.green = black.blue = 0; + white.red = white.green = white.blue = 0xFFFF; + black.flags = white.flags = DoRed|DoGreen|DoBlue; + XAllocColor(dpy, cmap, &black); + XAllocColor(dpy, cmap, &white); + if (bg_pixel == black.pixel) + fg_pixel = white.pixel; + else + fg_pixel = black.pixel; + } if (mono_p) cycle_p = False; gcv.foreground = fg_pixel; gcv.background = bg_pixel; - gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv); + gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv); gcv.foreground = bg_pixel; - gc2 = XCreateGC (dsp, win, GCForeground, &gcv); + gc2 = XCreateGC (dpy, window, GCForeground, &gcv); if (!mode_str || !strcmp (mode_str, "random")) mode = MODE_RANDOM; @@ -99,142 +121,163 @@ initwin (dsp, win) mode = MODE_RANDOM; } } - else if (! mono_p) - XFreeColors (dsp, cmap, pixels, npixels, 0); this_mode = mode; if (!mono_p && mode == MODE_RANDOM) - switch (random () % 3) { + switch (random () % 6) { case 0: this_mode = MODE_H; break; case 1: this_mode = MODE_S; break; case 2: this_mode = MODE_V; break; + default: break; } if (mono_p) - { - npixels = ncolors; - pixels [0] = fg_pixel; - pixels [1] = bg_pixel; - } + extra_krinkly_p = !(random() % 15); else + extra_krinkly_p = !(random() % 5); + + if (!mono_p) { - XColor fg_color, bg_color; + double distance, fg_H, bg_H, dh; - if (fg_pixel == bg_pixel) + RETRY: + fg_h = random() % 360; + fg_s = frand(1.0); + fg_v = frand(1.0); + + bg_h = fg_h; + bg_s = fg_s; + bg_v = fg_v; + + switch (this_mode) { - HSV_AGAIN: - fg_h = random () % 360; - bg_h = random () % 360; - fg_s = frand (1.0); - bg_s = frand (1.0); - V_AGAIN: - fg_v = frand (1.0); - bg_v = frand (1.0); - if ((fg_v - bg_v) > -0.4 && (fg_v - bg_v) < 0.4) - goto V_AGAIN; - hsv_to_rgb (fg_h, fg_s, fg_v, - &fg_color.red, &fg_color.green, &fg_color.blue); - hsv_to_rgb (bg_h, bg_s, bg_v, - &bg_color.red, &bg_color.green, &bg_color.blue); + case MODE_H: + bg_h = random() % 360; + if (fg_v < 0.4) + goto RETRY; + distance = fg_h - bg_h; + if (distance < 0) + distance = -distance; + if (distance > 360) + distance = 180 - (distance - 180); + if (distance < 30) + goto RETRY; + break; + + case MODE_S: + bg_s = frand(1.0); + if (fg_v < 0.4) + goto RETRY; + distance = fg_s - bg_s; + if (distance < 0) + distance = -distance; + if (distance < 0.2) + goto RETRY; + break; + + case MODE_V: + bg_v = frand(1.0); + distance = fg_v - bg_v; + if (distance < 0) + distance = -distance; + if (distance < 0.4) + goto RETRY; + break; + + default: + bg_h = random() % 360; + bg_s = frand(1.0); + bg_v = frand(1.0); + + fg_H = ((double) fg_h) / 360; + bg_H = ((double) bg_h) / 360; + dh = fg_H - bg_H; + if (dh < 0) dh = -dh; + if (dh > 0.5) dh = 0.5 - (dh - 0.5); + distance = sqrt ((dh * dh) + + ((fg_s - bg_s) * (fg_s - bg_s)) + + ((fg_v - bg_v) * (fg_v - bg_v))); + if (distance < 0.2) + goto RETRY; } + + cycle_p = True; + if (colors) + free_colors (dpy, cmap, colors, ncolors); else - { - fg_color.pixel = fg_pixel; - if (! XQueryColor (dsp, cmap, &fg_color)) - abort (); - bg_color.pixel = bg_pixel; - if (! XQueryColor (dsp, cmap, &bg_color)) - abort (); - } - fg_color.flags = DoRed|DoGreen|DoBlue; - bg_color.flags = DoRed|DoGreen|DoBlue; - - rgb_to_hsv (fg_color.red, fg_color.green, fg_color.blue, - &fg_h, &fg_s, &fg_v); - rgb_to_hsv (bg_color.red, bg_color.green, bg_color.blue, - &bg_h, &bg_s, &bg_v); - - if (/*mode == MODE_RANDOM &&*/ - ((this_mode == MODE_S && (fg_s-bg_s) > -0.3 && (fg_s-bg_s) < 0.3) || - (this_mode == MODE_V && (fg_v-bg_v) > -0.3 && (fg_v-bg_v) < 0.3) || - (this_mode == MODE_H && (fg_h-bg_h) > -30 && (fg_h-bg_h) < 30))) - goto HSV_AGAIN; - - switch (this_mode) { - case MODE_H: shift = (bg_h - fg_h) / ncolors; break; - case MODE_S: dshift = (bg_s - fg_s) / ncolors; break; - case MODE_V: dshift = (bg_v - fg_v) / ncolors; break; - default: abort (); + colors = (XColor *) malloc (ncolors * sizeof(*colors)); + + cycle_direction = (random() & 1 ? 1 : -1); + + RETRY_NON_WRITABLE: + { + int n = ncolors; + make_color_ramp (dpy, cmap, + fg_h, fg_s, fg_v, + bg_h, bg_s, bg_v, + colors, &n, + True, True, cycle_p); + if (n == 0 && cycle_p) + { + cycle_p = False; + goto RETRY_NON_WRITABLE; + } + ncolors = n; } - - if (mode == MODE_RANDOM && - ((this_mode == MODE_H) - ? ((shift > -2 && shift < 2) || fg_s < 0.3 || fg_v < 0.3) - : (dshift > -0.005 && dshift < 0.005))) - goto HSV_AGAIN; - if (mode == MODE_RANDOM && this_mode == MODE_S && fg_v < 0.5) - goto V_AGAIN; + if (ncolors <= 0) + mono_p = 1; + } - for (npixels = 0; npixels < ncolors; npixels++) + if (mono_p) + { + static Bool done = False; + static XColor c[50]; + colors = c; + cycle_p = False; + ncolors = sizeof(c)/sizeof(*c); + if (!done) { - if (cycle_p) - { - unsigned long plane_masks; - /* allocate the writable color cells, one at a time. */ - if (! XAllocColorCells (dsp, cmap, False, &plane_masks, 0, - &fg_color.pixel, 1)) - { - fprintf (stderr, - "%s: couldn't allocate %s writable color cells. Turning off -cycle.\n", - progname, (npixels ? "enough" : "any")); - cycle_p = 0; - goto NON_CYCLE; - } - XStoreColor (dsp, cmap, &fg_color); - } - else - { - NON_CYCLE: - if (!XAllocColor (dsp, cmap, &fg_color)) - break; - } - pixels[npixels] = fg_color.pixel; - - switch (this_mode) - { - case MODE_H: fg_h = (fg_h + shift) % 360; break; - case MODE_S: fg_s += dshift; break; - case MODE_V: fg_v += dshift; break; - default: abort (); - } - hsv_to_rgb (fg_h, fg_s, fg_v, - &fg_color.red, &fg_color.green, &fg_color.blue); + int i; + done = True; + colors[0].pixel = fg_pixel; + for (i = 1; i < ncolors; i++) + colors[i].pixel = bg_pixel; } } - XSetForeground (dsp, gc, pixels [0]); - XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height); + + XSetForeground (dpy, gc, colors[1].pixel); + XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height); } -#define HEIGHT_TO_PIXEL(height) \ - (((int) (height)) < 0 ? 0 : \ - ((int) (height)) >= npixels ? npixels - 3 : ((int) (height))) +#define HEIGHT_TO_PIXEL(height) \ + ((height) < 0 \ + ? (extra_krinkly_p \ + ? ncolors - ((-(height)) % ncolors) \ + : 0) \ + : ((height) >= ncolors \ + ? (extra_krinkly_p \ + ? (height) % ncolors \ + : ncolors-1) \ + : (height))) + static unsigned int -set (l, c, size, height) - unsigned int l, c, size; - int height; +set (unsigned int l, + unsigned int c, + unsigned int size, + int height) { int rang = 1 << (NSTEPS - size); height = height + (random () % rang) - rang / 2; + height = HEIGHT_TO_PIXEL(height); CELL (l, c) = height; - - return pixels [HEIGHT_TO_PIXEL (height)]; + return colors[height].pixel; } static void -floyd_steinberg () +floyd_steinberg (Display *dpy, Window window) { int x, y, err; @@ -244,11 +287,14 @@ floyd_steinberg () don't use enormous amounts of memory. */ XImage *image = - XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)), + XCreateImage (dpy, xgwa.visual, 1, XYBitmap, 0, /* depth, format, offset */ - (char *) calloc ((xmax + 1) / 8, 1), /* data */ + (char *) calloc ((xmax + 8) / 8, 1), /* data */ xmax, 1, 8, 0); /* w, h, pad, bpl */ + XSetForeground (dpy, gc, colors[0].pixel); + XSetBackground (dpy, gc, colors[1].pixel); + for (y = 0; y < ymax - 1; y++) { for (x = 0; x < xmax - 1; x++) @@ -268,80 +314,97 @@ floyd_steinberg () CELL (x+1, y) += (int) (((float) err) * 3.0/8.0); CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0); } - XPutImage (disp, wind, gc, image, 0, 0, 0, y, xmax, 1); + XPutImage (dpy, window, gc, image, 0, 0, 0, y, xmax, 1); } XDestroyImage (image); } static void -draw (x, y, pixel, grid_size) /* not called in mono mode */ - int x, y, grid_size; - unsigned long pixel; +draw (Display *dpy, Window window, + int x, int y, unsigned long pixel, int grid_size) { static unsigned int last_pixel, last_valid = 0; if (! (last_valid && pixel == last_pixel)) - XSetForeground (disp, gc, pixel); + XSetForeground (dpy, gc, pixel); last_valid = 1, last_pixel = pixel; if (grid_size == 1) - XDrawPoint (disp, wind, gc, x, y); + XDrawPoint (dpy, window, gc, x, y); else - XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size); + XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size); } static void -drawmap () +draw_map (Display *dpy, Window window) { - unsigned int x, y, i, step, nextStep, x1, x2, y1, y2; + int xstep, ystep, xnextStep, ynextStep; + int x, y, i, x1, x2, y1, y2; unsigned int pixel, qpixels [4]; - xmax = wattrs.width; - ymax = wattrs.height; + int backwards = random() & 1; + + xmax = xgwa.width; + ymax = xgwa.height; cell = (signed char *) calloc (xmax * ymax, 1); if (cell == NULL) exit (1); CELL (0, 0) = 0; - step = COUNT; + xstep = (backwards ? -COUNT : COUNT); + ystep = COUNT; for (i = 0; i < iterations; i++) { - nextStep = step / 2; - for (x = 0; x < xmax; x += step) + xnextStep = xstep / 2; + ynextStep = ystep / 2; + for (x = (backwards ? xmax-1 : 0); + (backwards ? x >= 0 : x < xmax); + x += xstep) { - x1 = x + nextStep; - if (x1 >= xmax) + x1 = x + xnextStep; + if (x1 < 0) + x1 = xmax-1; + else if (x1 >= xmax) x1 = 0; - x2 = x + step; - if (x2 >= xmax) + + x2 = x + xstep; + if (x2 < 0) + x2 = xmax-1; + else if (x2 >= xmax) x2 = 0; - for (y = 0; y < ymax; y += step) + + for (y = 0; y < ymax; y += ystep) { - y1 = y + nextStep; - if (y1 >= ymax) + y1 = y + ynextStep; + if (y1 < 0) + y1 = ymax-1; + else if (y1 >= ymax) y1 = 0; - y2 = y + step; - if (y2 >= ymax) + + y2 = y + ystep; + if (y2 < 0) + y2 = ymax-1; + else if (y2 >= ymax) y2 = 0; - qpixels [0] = pixels [HEIGHT_TO_PIXEL (CELL (x, y))]; - qpixels [1] = pixels [HEIGHT_TO_PIXEL (CELL (x, y2))]; - qpixels [2] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y))]; - qpixels [3] = pixels [HEIGHT_TO_PIXEL (CELL (x2, y2))]; + qpixels [0] = colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel; + qpixels [1] = colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel; + qpixels [2] = colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel; + qpixels [3] = colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel; pixel = set (x, y1, i, ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2); if (! mono_p && (pixel != qpixels[0] || pixel != qpixels[1] || pixel != qpixels[2] || pixel != qpixels[3])) - draw (x, y1, pixel, nextStep); + draw (dpy, window, x, y1, pixel, ynextStep); pixel = set (x1, y, i, ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2); if (! mono_p && (pixel != qpixels[0] || pixel != qpixels[1] || pixel != qpixels[2] || pixel != qpixels[3])) - draw (x1, y, pixel, nextStep); + draw (dpy, window, x1, y, pixel, ynextStep); pixel = set (x1, y1, i, ((int) CELL (x, y) + (int) CELL (x, y2) + @@ -350,56 +413,55 @@ drawmap () if (! mono_p && (pixel != qpixels[0] || pixel != qpixels[1] || pixel != qpixels[2] || pixel != qpixels[3])) - draw (x1, y1, pixel, nextStep); + draw (dpy, window, x1, y1, pixel, ynextStep); + + + if (cycle_p) + { + struct timeval now; + static struct timeval then = { 0, 0 }; + unsigned long diff; +#ifdef GETTIMEOFDAY_TWO_ARGS + struct timezone tzp; + gettimeofday(&now, &tzp); +#else + gettimeofday(&now); +#endif + diff = (((now.tv_sec - then.tv_sec) * 1000000) + + (now.tv_usec - then.tv_usec)); + if (diff > cycle_delay) + { + rotate_colors (dpy, cmap, colors, ncolors, + cycle_direction); + then = now; + } + } } } - step = nextStep; + xstep = xnextStep; + ystep = ynextStep; if (!mono_p) - XSync (disp, True); + XSync (dpy, False); + screenhack_handle_events (dpy); } if (mono_p) /* in mono-mode, we do all the drawing at the end */ - floyd_steinberg (); + floyd_steinberg (dpy, window); free (cell); - XSync (disp, True); -} - -static void -cycle (dpy) - Display *dpy; -{ - XColor *colors = (XColor *) malloc (npixels * sizeof (XColor)); - time_t stop; - int i; - for (i = 0; i < npixels; i++) - colors [i].pixel = pixels [i]; - XQueryColors (dpy, cmap, colors, npixels); - stop = (time_t) ((time ((time_t) 0)) + timeout); - while (stop >= (time_t) time ((time_t) 0)) - { - unsigned long scratch = colors [npixels-1].pixel; - for (i = npixels-1; i > 0; i--) - colors [i].pixel = colors [i-1].pixel; - colors [0].pixel = scratch; - XStoreColors (dpy, cmap, colors, npixels); - XSync (dpy, True); - if (cycle_delay) usleep (cycle_delay); - } - XSync (dpy, True); - free (colors); + XSync (dpy, False); } char *progclass = "Imsmap"; char *defaults [] = { - "*background: black", - "*foreground: black", + ".background: black", + ".foreground: black", "*mode: random", "*ncolors: 50", "*iterations: 7", - "*timeout: 10", + "*delay: 10", "*cycleDelay: 100000", "*cycle: true", 0 @@ -407,33 +469,41 @@ char *defaults [] = { XrmOptionDescRec options [] = { { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, - { "-timeout", ".timeout", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 }, { "-mode", ".mode", XrmoptionSepArg, 0 }, { "-iterations", ".iterations", XrmoptionSepArg, 0 }, { "-cycle", ".cycle", XrmoptionNoArg, "True" }, - { "-no-cycle", ".cycle", XrmoptionNoArg, "False" } + { "-no-cycle", ".cycle", XrmoptionNoArg, "False" }, + { 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) { - disp = dpy; - wind = window; while (1) { - initwin (dpy, window); - drawmap (); - if (timeout) + init_map (dpy, window); + draw_map (dpy, window); + if (delay) { if (cycle_p) - cycle (dpy); + { + time_t start = time((time_t) 0); + while (start + delay > time((time_t) 0)) + { + rotate_colors (dpy, cmap, colors, ncolors, + cycle_direction); + if (cycle_delay) usleep(cycle_delay); + screenhack_handle_events (dpy); + } + } else - sleep (timeout); + { + screenhack_handle_events (dpy); + sleep (delay); + } } } }