X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fimsmap.c;h=6e1f31dded435a8f7bbc437cc2dead2c62546155;hp=7a619b94e14817f8c5046588fb06a8fe777b64b2;hb=6b1c86cf395f59389e4ece4ea8f4bea2c332745b;hpb=ccbc9f87eb59497b23bd0424ee1ed20ad7c7db54 diff --git a/hacks/imsmap.c b/hacks/imsmap.c index 7a619b94..6e1f31dd 100644 --- a/hacks/imsmap.c +++ b/hacks/imsmap.c @@ -1,4 +1,4 @@ -/* imsmap, Copyright (c) 1992 Juergen Nickelsen +/* imsmap, Copyright (c) 1992-2008 Juergen Nickelsen and Jamie Zawinski. * Derived from code by Markus Schirmer, TU Berlin. * * Permission to use, copy, modify, distribute, and sell this software and its @@ -8,231 +8,80 @@ * 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 "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 GC gc, gc2; -static Display *disp; -static Window wind; -static XWindowAttributes wattrs; +#define CELL(c, r) st->cell[((unsigned int)(c)) + ((unsigned int) (r)) * st->xmax] #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 signed char *cell = NULL; -static int xmax, ymax; -static int iterations; +struct state { + Display *dpy; + Window window; + Colormap cmap; + int ncolors; + XColor *colors; + Bool extra_krinkly_p; -static void -initwin (dsp, win) - Display *dsp; - Window win; -{ - int fg_h, bg_h; - double fg_s, fg_v, bg_s, bg_v; - - enum mode_t this_mode; - static Bool rv_p; - static int ncolors = 0; - int shift = 0; - double dshift = 0; - - XGCValues gcv; + int delay, delay2; + signed char *cell; + int xmax, ymax; + int iteration, iterations; - XGetWindowAttributes (dsp, win, &wattrs); - cmap = wattrs.colormap; + int cx, xstep, ystep, xnextStep, ynextStep; - if (!ncolors) - { - char *mode_str = get_string_resource ("mode", "Mode"); - 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"); - 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 (mono_p) cycle_p = False; - - gcv.foreground = fg_pixel; - gcv.background = bg_pixel; - gc = XCreateGC (dsp, win, GCForeground|GCBackground, &gcv); - gcv.foreground = bg_pixel; - gc2 = XCreateGC (dsp, win, GCForeground, &gcv); - - if (!mode_str || !strcmp (mode_str, "random")) - mode = MODE_RANDOM; - else if (!strcmp (mode_str, "h") || !strcmp (mode_str, "hue")) - mode = MODE_H; - else if (!strcmp (mode_str, "s") || !strcmp (mode_str, "saturation")) - mode = MODE_S; - else if (!strcmp (mode_str, "v") || !strcmp (mode_str, "value")) - mode = MODE_V; - else - { - fprintf (stderr, - "%s: mode must be hue, saturation, value, or random, not \"%s\"\n", - progname, mode_str); - 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) { - case 0: this_mode = MODE_H; break; - case 1: this_mode = MODE_S; break; - case 2: this_mode = MODE_V; break; - } + unsigned int last_pixel, last_valid; + int flip_x; + int flip_xy; - if (mono_p) - { - npixels = ncolors; - pixels [0] = fg_pixel; - pixels [1] = bg_pixel; - } - else - { - XColor fg_color, bg_color; + GC gc, gc2; + XWindowAttributes xgwa; - if (fg_pixel == bg_pixel) - { - 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); - } - else - { - XQueryColor (dsp, cmap, &fg_color); - XQueryColor (dsp, cmap, &bg_color); - fg_color.pixel = fg_pixel; - bg_color.pixel = bg_pixel; - } - 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 (); - } - - 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; - - for (npixels = 0; npixels < ncolors; npixels++) - { - 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); - } - } - XSetForeground (dsp, gc, pixels [0]); - XFillRectangle (dsp, win, gc, 0, 0, wattrs.width, wattrs.height); -} + struct timeval then; +}; -#define HEIGHT_TO_PIXEL(height) \ - (((int) (height)) < 0 ? 0 : \ - ((int) (height)) >= npixels ? npixels - 3 : ((int) (height))) +#define HEIGHT_TO_PIXEL(height) \ + ((height) < 0 \ + ? (st->extra_krinkly_p \ + ? st->ncolors - 1 - ((-(height)) % st->ncolors) \ + : 0) \ + : ((height) >= st->ncolors \ + ? (st->extra_krinkly_p \ + ? (height) % st->ncolors \ + : st->ncolors-1) \ + : (height))) + static unsigned int -set (l, c, size, height) - unsigned int l, c, size; - int height; +set (struct state *st, + 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 st->colors[height].pixel; } + static void -floyd_steinberg () +floyd_steinberg (struct state *st) { int x, y, err; @@ -242,14 +91,17 @@ floyd_steinberg () don't use enormous amounts of memory. */ XImage *image = - XCreateImage (disp, DefaultVisual(disp,DefaultScreen(disp)), + XCreateImage (st->dpy, st->xgwa.visual, 1, XYBitmap, 0, /* depth, format, offset */ - (char *) calloc ((xmax + 1) / 8, 1), /* data */ - xmax, 1, 8, 0); /* w, h, pad, bpl */ + (char *) calloc ((st->xmax + 8) / 8, 1), /* data */ + st->xmax, 1, 8, 0); /* w, h, pad, bpl */ + + XSetForeground (st->dpy, st->gc, st->colors[0].pixel); + XSetBackground (st->dpy, st->gc, st->colors[1].pixel); - for (y = 0; y < ymax - 1; y++) + for (y = 0; y < st->ymax - 1; y++) { - for (x = 0; x < xmax - 1; x++) + for (x = 0; x < st->xmax - 1; x++) { if (CELL(x, y) < 0) { @@ -266,172 +118,298 @@ 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 (st->dpy, st->window, st->gc, image, 0, 0, 0, y, st->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 (struct state *st, + 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); - last_valid = 1, last_pixel = pixel; + if (st->flip_x) + x = st->xmax - x; + + if (st->flip_xy) + { + int swap = x; + x = y; + y = swap; + } + + if (! (st->last_valid && pixel == st->last_pixel)) + XSetForeground (st->dpy, st->gc, pixel); + st->last_valid = 1, st->last_pixel = pixel; if (grid_size == 1) - XDrawPoint (disp, wind, gc, x, y); + XDrawPoint (st->dpy, st->window, st->gc, x, y); else - XFillRectangle (disp, wind, gc, x, y, grid_size, grid_size); + XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size); } -static void -drawmap () +static void +init_map (struct state *st) { - unsigned int x, y, i, step, nextStep, x1, x2, y1, y2; - unsigned int pixel, qpixels [4]; + XGCValues gcv; - xmax = wattrs.width; - ymax = wattrs.height; + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->cmap = st->xgwa.colormap; - cell = (signed char *) calloc (xmax * ymax, 1); - if (cell == NULL) - exit (1); + st->flip_x = (random() % 2); + st->flip_xy = (random() % 2); - CELL (0, 0) = 0; - step = COUNT; - for (i = 0; i < iterations; i++) + if (mono_p) + st->flip_xy = 0; + + st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer"); + st->delay = get_integer_resource (st->dpy, "delay", "Integer"); + st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer"); + st->iterations = get_integer_resource (st->dpy, "iterations", "Integer"); + if (st->iterations < 0) st->iterations = 0; + else if (st->iterations > 7) st->iterations = 7; + + if (st->ncolors <= 2) st->ncolors = 0; + if (st->ncolors == 0) mono_p = True; + if (st->ncolors > 255) st->ncolors = 255; /* too many look bad */ + + if (!st->gc) st->gc = XCreateGC (st->dpy, st->window, 0, &gcv); + if (!st->gc2) st->gc2 = XCreateGC (st->dpy, st->window, 0, &gcv); + + if (mono_p) + st->extra_krinkly_p = !(random() % 15); + else + st->extra_krinkly_p = !(random() % 5); + + if (!mono_p) { - nextStep = step / 2; - for (x = 0; x < xmax; x += step) - { - x1 = x + nextStep; - if (x1 >= xmax) - x1 = 0; - x2 = x + step; - if (x2 >= xmax) - x2 = 0; - for (y = 0; y < ymax; y += step) - { - y1 = y + nextStep; - if (y1 >= ymax) - y1 = 0; - y2 = y + step; - 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))]; - - 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); - - 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); - - pixel = set (x1, y1, i, - ((int) CELL (x, y) + (int) CELL (x, y2) + - (int) CELL (x2, y) + (int) CELL (x2, y2) + 2) - / 4); - if (! mono_p && - (pixel != qpixels[0] || pixel != qpixels[1] || - pixel != qpixels[2] || pixel != qpixels[3])) - draw (x1, y1, pixel, nextStep); - } - } - step = nextStep; - if (!mono_p) - XSync (disp, True); + if (st->colors) + free_colors (st->dpy, st->cmap, st->colors, st->ncolors); + else + st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors)); + + make_smooth_colormap (st->dpy, st->xgwa.visual, st->cmap, + st->colors, &st->ncolors, + True, 0, False); + if (st->ncolors <= 2) + mono_p = 1; } + if (mono_p) - /* in mono-mode, we do all the drawing at the end */ - floyd_steinberg (); - - free (cell); - XSync (disp, True); + { + int i; + unsigned long fg_pixel = + get_pixel_resource (st->dpy, st->xgwa.colormap, + "foreground", "Foreground"); + unsigned long bg_pixel = + get_pixel_resource (st->dpy, st->xgwa.colormap, + "background", "Background"); + if (!st->colors) + { + st->ncolors = 50; + st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors)); + } + st->colors[0].pixel = fg_pixel; + for (i = 1; i < st->ncolors; i++) + st->colors[i].pixel = bg_pixel; + } + + XSetForeground (st->dpy, st->gc, st->colors[1].pixel); + XFillRectangle (st->dpy, st->window, st->gc, 0, 0, + st->xgwa.width, st->xgwa.height); + + if (st->flip_xy) + { + st->xmax = st->xgwa.height; + st->ymax = st->xgwa.width; + } + else + { + st->xmax = st->xgwa.width; + st->ymax = st->xgwa.height; + } + + if (st->cell) free (st->cell); + st->cell = (signed char *) calloc (st->xmax * st->ymax, 1); + + CELL (0, 0) = 0; + st->xstep = COUNT; + st->ystep = COUNT; + + st->iteration = 0; + st->cx = 0; } -static void -cycle (dpy) - Display *dpy; + +static void * +imsmap_init (Display *dpy, Window window) +{ + struct state *st = (struct state *) calloc (1, sizeof(*st)); + st->dpy = dpy; + st->window = window; + init_map (st); + return st; +} + + +static unsigned long +imsmap_draw (Display *dpy, Window window, void *closure) { - XColor *colors = (XColor *) malloc (npixels * sizeof (XColor)); - time_t stop; + struct state *st = (struct state *) closure; + int this_delay = st->delay2; 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)) + + /* do this many lines at a time without pausing */ + int col_chunk = st->iteration * 2 + 1; + + if (st->iteration > st->iterations) + init_map (st); + + if (st->cx == 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); + st->xnextStep = st->xstep / 2; + st->ynextStep = st->ystep / 2; } - XSync (dpy, True); - free (colors); + + for (i = 0; i < col_chunk; i++) + { + int x1, x2, y1, y2; + int y; + int x = st->cx; + + x1 = x + st->xnextStep; + if (x1 < 0) + x1 = st->xmax-1; + else if (x1 >= st->xmax) + x1 = 0; + + x2 = x + st->xstep; + if (x2 < 0) + x2 = st->xmax-1; + else if (x2 >= st->xmax) + x2 = 0; + + for (y = 0; y < st->ymax; y += st->ystep) + { + unsigned int pixel, qpixels [4]; + + y1 = y + st->ynextStep; + if (y1 < 0) + y1 = st->ymax-1; + else if (y1 >= st->ymax) + y1 = 0; + + y2 = y + st->ystep; + if (y2 < 0) + y2 = st->ymax-1; + else if (y2 >= st->ymax) + y2 = 0; + + qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel; + qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel; + qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel; + qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel; + + pixel = set (st, x, y1, st->iteration, + ((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 (st, x, y1, pixel, st->ynextStep); + + pixel = set (st, x1, y, st->iteration, + ((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 (st, x1, y, pixel, st->ynextStep); + + pixel = set (st, x1, y1, st->iteration, + ((int) CELL (x, y) + (int) CELL (x, y2) + + (int) CELL (x2, y) + (int) CELL (x2, y2) + 2) + / 4); + if (! mono_p && + (pixel != qpixels[0] || pixel != qpixels[1] || + pixel != qpixels[2] || pixel != qpixels[3])) + draw (st, x1, y1, pixel, st->ynextStep); + } + + st->cx += st->xstep; + if (st->cx >= st->xmax) + break; + } + + if (st->cx >= st->xmax) + { + st->cx = 0; + st->xstep = st->xnextStep; + st->ystep = st->ynextStep; + + st->iteration++; + + if (st->iteration > st->iterations) + this_delay = st->delay * 1000000; + + if (mono_p) + floyd_steinberg (st); /* in mono, do all drawing at the end */ + } + + return this_delay; +} + + +static void +imsmap_reshape (Display *dpy, Window window, void *closure, + unsigned int w, unsigned int h) +{ + struct state *st = (struct state *) closure; + init_map (st); } -char *progclass = "Imsmap"; +static Bool +imsmap_event (Display *dpy, Window window, void *closure, XEvent *event) +{ + struct state *st = (struct state *) closure; + if (event->xany.type == ButtonPress) + { + init_map (st); + return True; + } + + return False; +} + + +static void +imsmap_free (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + if (st->colors) free (st->colors); + if (st->cell) free (st->cell); + free (st); +} + -char *defaults [] = { - "Imsmap.background: black", /* to placate SGI */ - "Imsmap.foreground: black", +static const char *imsmap_defaults [] = { + ".background: #000066", + ".foreground: #FF00FF", "*mode: random", "*ncolors: 50", "*iterations: 7", - "*timeout: 10", - "*cycleDelay: 100000", - "*cycle: true", + "*delay: 5", + "*delay2: 20000", 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec imsmap_options [] = { { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, - { "-timeout", ".timeout", XrmoptionSepArg, 0 }, - { "-cycle-delay", ".cycleDelay", XrmoptionSepArg, 0 }, + { "-delay", ".delay", XrmoptionSepArg, 0 }, + { "-delay2", ".delay2", XrmoptionSepArg, 0 }, { "-mode", ".mode", XrmoptionSepArg, 0 }, { "-iterations", ".iterations", XrmoptionSepArg, 0 }, - { "-cycle", ".cycle", XrmoptionNoArg, "True" }, - { "-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; -{ - disp = dpy; - wind = window; - while (1) - { - initwin (dpy, window); - drawmap (); - if (timeout) - { - if (cycle_p) - cycle (dpy); - else - sleep (timeout); - } - } -} +XSCREENSAVER_MODULE ("IMSMAP", imsmap)