X-Git-Url: http://git.hungrycats.org/cgi-bin/gitweb.cgi?p=xscreensaver;a=blobdiff_plain;f=hacks%2Fimsmap.c;h=6e1f31dded435a8f7bbc437cc2dead2c62546155;hp=cb88c10a6cc6ea8bc0420b1418c81dd4d742f885;hb=6b1c86cf395f59389e4ece4ea8f4bea2c332745b;hpb=0ed85ca0e4b0eae40a4f50a51d63f2f41e45373a diff --git a/hacks/imsmap.c b/hacks/imsmap.c index cb88c10a..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 @@ -16,254 +16,58 @@ #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 imsmap_mode { MODE_H, MODE_S, MODE_V, MODE_RANDOM } mode; - -static GC gc, gc2; -static XWindowAttributes xgwa; +#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 Colormap cmap; -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; +struct state { + Display *dpy; + Window window; + Colormap cmap; + int ncolors; + XColor *colors; + Bool extra_krinkly_p; -static void -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 imsmap_mode this_mode; - static Bool rv_p; - - XGCValues gcv; + int delay, delay2; + signed char *cell; + int xmax, ymax; + int iteration, iterations; - XGetWindowAttributes (dpy, window, &xgwa); - cmap = xgwa.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"); - 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; - - 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; - } + unsigned int last_pixel, last_valid; + int flip_x; + int flip_xy; - if (mono_p) cycle_p = False; - - gcv.foreground = fg_pixel; - gcv.background = bg_pixel; - gc = XCreateGC (dpy, window, GCForeground|GCBackground, &gcv); - gcv.foreground = bg_pixel; - gc2 = XCreateGC (dpy, window, 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; - } - } + GC gc, gc2; + XWindowAttributes xgwa; - this_mode = mode; - if (!mono_p && mode == MODE_RANDOM) - 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) - extra_krinkly_p = !(random() % 15); - else - extra_krinkly_p = !(random() % 5); - - if (!mono_p) - { - double distance, fg_H, bg_H, dh; - - 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) - { - 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 - 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 (ncolors <= 0) - mono_p = 1; - } - - if (mono_p) - { - static Bool done = False; - static XColor c[50]; - colors = c; - cycle_p = False; - ncolors = sizeof(c)/sizeof(*c); - if (!done) - { - int i; - done = True; - colors[0].pixel = fg_pixel; - for (i = 1; i < ncolors; i++) - colors[i].pixel = bg_pixel; - } - } - - XSetForeground (dpy, gc, colors[1].pixel); - XFillRectangle (dpy, window, gc, 0, 0, xgwa.width, xgwa.height); -} + struct timeval then; +}; -#define HEIGHT_TO_PIXEL(height) \ - ((height) < 0 \ - ? (extra_krinkly_p \ - ? ncolors - ((-(height)) % ncolors) \ - : 0) \ - : ((height) >= ncolors \ - ? (extra_krinkly_p \ - ? (height) % ncolors \ - : ncolors-1) \ +#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 (unsigned int l, +set (struct state *st, + unsigned int l, unsigned int c, unsigned int size, int height) @@ -272,11 +76,12 @@ set (unsigned int l, height = height + (random () % rang) - rang / 2; height = HEIGHT_TO_PIXEL(height); CELL (l, c) = height; - return colors[height].pixel; + return st->colors[height].pixel; } + static void -floyd_steinberg (Display *dpy, Window window) +floyd_steinberg (struct state *st) { int x, y, err; @@ -286,17 +91,17 @@ floyd_steinberg (Display *dpy, Window window) don't use enormous amounts of memory. */ XImage *image = - XCreateImage (dpy, xgwa.visual, + XCreateImage (st->dpy, st->xgwa.visual, 1, XYBitmap, 0, /* depth, format, offset */ - (char *) calloc ((xmax + 8) / 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 (dpy, gc, colors[0].pixel); - XSetBackground (dpy, gc, colors[1].pixel); + 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) { @@ -313,196 +118,298 @@ floyd_steinberg (Display *dpy, Window window) CELL (x+1, y) += (int) (((float) err) * 3.0/8.0); CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0); } - XPutImage (dpy, window, 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 (Display *dpy, Window window, +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 (dpy, 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 (dpy, window, gc, x, y); + XDrawPoint (st->dpy, st->window, st->gc, x, y); else - XFillRectangle (dpy, window, gc, x, y, grid_size, grid_size); + XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size); } -static void -draw_map (Display *dpy, Window window) +static void +init_map (struct state *st) { - int xstep, ystep, xnextStep, ynextStep; - int x, y, i, x1, x2, y1, y2; - unsigned int pixel, qpixels [4]; + XGCValues gcv; + + XGetWindowAttributes (st->dpy, st->window, &st->xgwa); + st->cmap = st->xgwa.colormap; - int backwards = random() & 1; + st->flip_x = (random() % 2); + st->flip_xy = (random() % 2); - xmax = xgwa.width; - ymax = xgwa.height; + if (mono_p) + st->flip_xy = 0; - cell = (signed char *) calloc (xmax * ymax, 1); - if (cell == NULL) - exit (1); + 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; - CELL (0, 0) = 0; - xstep = (backwards ? -COUNT : COUNT); - ystep = COUNT; - for (i = 0; i < iterations; i++) + 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) { - xnextStep = xstep / 2; - ynextStep = ystep / 2; - for (x = (backwards ? xmax-1 : 0); - (backwards ? x >= 0 : x < xmax); - x += xstep) - { - x1 = x + xnextStep; - if (x1 < 0) - x1 = xmax-1; - else if (x1 >= xmax) - x1 = 0; - - x2 = x + xstep; - if (x2 < 0) - x2 = xmax-1; - else if (x2 >= xmax) - x2 = 0; - - for (y = 0; y < ymax; y += ystep) - { - y1 = y + ynextStep; - if (y1 < 0) - y1 = ymax-1; - else if (y1 >= ymax) - y1 = 0; - - y2 = y + ystep; - if (y2 < 0) - y2 = ymax-1; - else if (y2 >= ymax) - y2 = 0; - - 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 (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 (dpy, window, x1, y, pixel, ynextStep); - - 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 (dpy, window, x1, y1, pixel, ynextStep); - - - if (cycle_p) - { - struct timeval now; - static struct timeval then = { 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; - } - } - } - } - xstep = xnextStep; - ystep = ynextStep; - if (!mono_p) - XSync (dpy, False); - screenhack_handle_events (dpy); + 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 (dpy, window); - - free (cell); - XSync (dpy, False); + { + 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 * +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; } -char *progclass = "Imsmap"; +static unsigned long +imsmap_draw (Display *dpy, Window window, void *closure) +{ + struct state *st = (struct state *) closure; + int this_delay = st->delay2; + int i; -char *defaults [] = { - ".background: black", - ".foreground: black", + /* 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) + { + st->xnextStep = st->xstep / 2; + st->ynextStep = st->ystep / 2; + } + + 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); +} + + +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); +} + + +static const char *imsmap_defaults [] = { + ".background: #000066", + ".foreground: #FF00FF", "*mode: random", "*ncolors: 50", "*iterations: 7", - "*delay: 10", - "*cycleDelay: 100000", - "*cycle: true", + "*delay: 5", + "*delay2: 20000", 0 }; -XrmOptionDescRec options [] = { +static XrmOptionDescRec imsmap_options [] = { { "-ncolors", ".ncolors", XrmoptionSepArg, 0 }, { "-delay", ".delay", XrmoptionSepArg, 0 }, - { "-cycle-delay", ".cycleDelay", 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 } }; - -void -screenhack (Display *dpy, Window window) -{ - while (1) - { - init_map (dpy, window); - draw_map (dpy, window); - if (delay) - { - if (cycle_p) - { - 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 - { - screenhack_handle_events (dpy); - sleep (delay); - } - } - } -} +XSCREENSAVER_MODULE ("IMSMAP", imsmap)