1 /* imsmap, Copyright (c) 1992-2013 Juergen Nickelsen and Jamie Zawinski.
2 * Derived from code by Markus Schirmer, TU Berlin.
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation. No representations are made about the suitability of this
9 * software for any purpose. It is provided "as is" without express or
13 * 24-aug-92: jwz: hacked.
14 * 17-May-97: jwz: hacked more.
20 #include "screenhack.h"
23 #define COUNT (1 << NSTEPS)
24 #define CELL(c, r) st->cell[((unsigned int)(c)) + ((unsigned int) (r)) * st->xmax]
26 #if defined(sun) && !__STDC__ /* sun cc doesn't know "signed char" */
41 int iteration, iterations;
43 int cx, xstep, ystep, xnextStep, ynextStep;
45 unsigned int last_pixel, last_valid;
50 XWindowAttributes xgwa;
56 #define HEIGHT_TO_PIXEL(height) \
58 ? (st->extra_krinkly_p \
59 ? st->ncolors - 1 - ((-(height)) % st->ncolors) \
61 : ((height) >= st->ncolors \
62 ? (st->extra_krinkly_p \
63 ? (height) % st->ncolors \
69 set (struct state *st,
75 int rang = 1 << (NSTEPS - size);
76 height = height + (random () % rang) - rang / 2;
77 height = HEIGHT_TO_PIXEL(height);
79 return st->colors[height].pixel;
84 floyd_steinberg (struct state *st)
88 /* Instead of repeatedly calling XPutPixel(), we make an Image and then
89 send its bits over all at once. This consumes much less network
90 bandwidth. The image we create is Wx1 intead of WxH, so that we
91 don't use enormous amounts of memory.
94 XCreateImage (st->dpy, st->xgwa.visual,
95 1, XYBitmap, 0, /* depth, format, offset */
96 (char *) calloc ((st->xmax + 8) / 8, 1), /* data */
97 st->xmax, 1, 8, 0); /* w, h, pad, bpl */
99 XSetForeground (st->dpy, st->gc, st->colors[0].pixel);
100 XSetBackground (st->dpy, st->gc, st->colors[1].pixel);
102 for (y = 0; y < st->ymax - 1; y++)
104 for (x = 0; x < st->xmax - 1; x++)
109 XPutPixel (image, x, 0, 1);
113 err = CELL (x, y) - 1;
114 XPutPixel (image, x, 0, 0);
116 /* distribute error */
117 CELL (x, y+1) += (int) (((float) err) * 3.0/8.0);
118 CELL (x+1, y) += (int) (((float) err) * 3.0/8.0);
119 CELL (x+1, y+1) += (int) (((float) err) * 1.0/4.0);
121 XPutImage (st->dpy, st->window, st->gc, image, 0, 0, 0, y, st->xmax, 1);
123 XDestroyImage (image);
128 draw (struct state *st,
129 int x, int y, unsigned long pixel, int grid_size)
141 if (! (st->last_valid && pixel == st->last_pixel))
142 XSetForeground (st->dpy, st->gc, pixel);
143 st->last_valid = 1, st->last_pixel = pixel;
145 XDrawPoint (st->dpy, st->window, st->gc, x, y);
147 XFillRectangle (st->dpy, st->window, st->gc, x, y, grid_size, grid_size);
152 init_map (struct state *st)
156 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
157 st->cmap = st->xgwa.colormap;
159 st->flip_x = (random() % 2);
160 st->flip_xy = (random() % 2);
165 free_colors (st->xgwa.screen, st->cmap, st->colors, st->ncolors);
168 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
169 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
170 st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
171 st->iterations = get_integer_resource (st->dpy, "iterations", "Integer");
172 if (st->iterations < 0) st->iterations = 0;
173 else if (st->iterations > 7) st->iterations = 7;
175 if (st->ncolors <= 2) st->ncolors = 0;
176 if (st->ncolors == 0) mono_p = True;
177 if (st->ncolors > 255) st->ncolors = 255; /* too many look bad */
179 if (!st->gc) st->gc = XCreateGC (st->dpy, st->window, 0, &gcv);
180 if (!st->gc2) st->gc2 = XCreateGC (st->dpy, st->window, 0, &gcv);
183 st->extra_krinkly_p = !(random() % 15);
185 st->extra_krinkly_p = !(random() % 5);
189 st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors));
191 make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->cmap,
192 st->colors, &st->ncolors,
194 if (st->ncolors <= 2)
201 unsigned long fg_pixel =
202 get_pixel_resource (st->dpy, st->xgwa.colormap,
203 "foreground", "Foreground");
204 unsigned long bg_pixel =
205 get_pixel_resource (st->dpy, st->xgwa.colormap,
206 "background", "Background");
210 st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors));
212 st->colors[0].pixel = fg_pixel;
213 for (i = 1; i < st->ncolors; i++)
214 st->colors[i].pixel = bg_pixel;
217 XSetForeground (st->dpy, st->gc, st->colors[1].pixel);
218 XFillRectangle (st->dpy, st->window, st->gc, 0, 0,
219 st->xgwa.width, st->xgwa.height);
223 st->xmax = st->xgwa.height;
224 st->ymax = st->xgwa.width;
228 st->xmax = st->xgwa.width;
229 st->ymax = st->xgwa.height;
232 if (st->cell) free (st->cell);
233 st->cell = (signed char *) calloc (st->xmax * st->ymax, 1);
245 imsmap_init (Display *dpy, Window window)
247 struct state *st = (struct state *) calloc (1, sizeof(*st));
256 imsmap_draw (Display *dpy, Window window, void *closure)
258 struct state *st = (struct state *) closure;
259 int this_delay = st->delay2;
262 /* do this many lines at a time without pausing */
263 int col_chunk = st->iteration * 2 + 1;
265 if (st->iteration > st->iterations)
270 st->xnextStep = st->xstep / 2;
271 st->ynextStep = st->ystep / 2;
274 for (i = 0; i < col_chunk; i++)
280 x1 = x + st->xnextStep;
283 else if (x1 >= st->xmax)
289 else if (x2 >= st->xmax)
292 for (y = 0; y < st->ymax; y += st->ystep)
294 unsigned int pixel, qpixels [4];
296 y1 = y + st->ynextStep;
299 else if (y1 >= st->ymax)
305 else if (y2 >= st->ymax)
308 qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
309 qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
310 qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
311 qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
313 pixel = set (st, x, y1, st->iteration,
314 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
317 (pixel != qpixels[0] || pixel != qpixels[1] ||
318 pixel != qpixels[2] || pixel != qpixels[3]))
319 draw (st, x, y1, pixel, st->ynextStep);
321 pixel = set (st, x1, y, st->iteration,
322 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
324 (pixel != qpixels[0] || pixel != qpixels[1] ||
325 pixel != qpixels[2] || pixel != qpixels[3]))
326 draw (st, x1, y, pixel, st->ynextStep);
328 pixel = set (st, x1, y1, st->iteration,
329 ((int) CELL (x, y) + (int) CELL (x, y2) +
330 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
333 (pixel != qpixels[0] || pixel != qpixels[1] ||
334 pixel != qpixels[2] || pixel != qpixels[3]))
335 draw (st, x1, y1, pixel, st->ynextStep);
339 if (st->cx >= st->xmax)
343 if (st->cx >= st->xmax)
346 st->xstep = st->xnextStep;
347 st->ystep = st->ynextStep;
351 if (st->iteration > st->iterations)
352 this_delay = st->delay * 1000000;
355 floyd_steinberg (st); /* in mono, do all drawing at the end */
363 imsmap_reshape (Display *dpy, Window window, void *closure,
364 unsigned int w, unsigned int h)
366 struct state *st = (struct state *) closure;
372 imsmap_event (Display *dpy, Window window, void *closure, XEvent *event)
374 struct state *st = (struct state *) closure;
375 if (screenhack_event_helper (dpy, window, event))
386 imsmap_free (Display *dpy, Window window, void *closure)
388 struct state *st = (struct state *) closure;
389 if (st->colors) free (st->colors);
390 if (st->cell) free (st->cell);
395 static const char *imsmap_defaults [] = {
396 ".background: #000066",
397 ".foreground: #FF00FF",
405 "*ignoreRotation: True",
410 static XrmOptionDescRec imsmap_options [] = {
411 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
412 { "-delay", ".delay", XrmoptionSepArg, 0 },
413 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
414 { "-mode", ".mode", XrmoptionSepArg, 0 },
415 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
419 XSCREENSAVER_MODULE ("IMSMap", imsmap)