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 if (st->ncolors < 1) st->ncolors = 1;
190 st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors));
192 make_smooth_colormap (st->xgwa.screen, st->xgwa.visual, st->cmap,
193 st->colors, &st->ncolors,
195 if (st->ncolors <= 2)
202 unsigned long fg_pixel =
203 get_pixel_resource (st->dpy, st->xgwa.colormap,
204 "foreground", "Foreground");
205 unsigned long bg_pixel =
206 get_pixel_resource (st->dpy, st->xgwa.colormap,
207 "background", "Background");
211 st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors));
213 st->colors[0].pixel = fg_pixel;
214 for (i = 1; i < st->ncolors; i++)
215 st->colors[i].pixel = bg_pixel;
218 XSetForeground (st->dpy, st->gc, st->colors[1].pixel);
219 XFillRectangle (st->dpy, st->window, st->gc, 0, 0,
220 st->xgwa.width, st->xgwa.height);
224 st->xmax = st->xgwa.height;
225 st->ymax = st->xgwa.width;
229 st->xmax = st->xgwa.width;
230 st->ymax = st->xgwa.height;
233 if (st->cell) free (st->cell);
234 st->cell = (signed char *) calloc (st->xmax * st->ymax, 1);
246 imsmap_init (Display *dpy, Window window)
248 struct state *st = (struct state *) calloc (1, sizeof(*st));
257 imsmap_draw (Display *dpy, Window window, void *closure)
259 struct state *st = (struct state *) closure;
260 int this_delay = st->delay2;
263 /* do this many lines at a time without pausing */
264 int col_chunk = st->iteration * 2 + 1;
266 if (st->iteration > st->iterations)
271 st->xnextStep = st->xstep / 2;
272 st->ynextStep = st->ystep / 2;
275 for (i = 0; i < col_chunk; i++)
281 x1 = x + st->xnextStep;
284 else if (x1 >= st->xmax)
290 else if (x2 >= st->xmax)
293 for (y = 0; y < st->ymax; y += st->ystep)
295 unsigned int pixel, qpixels [4];
297 y1 = y + st->ynextStep;
300 else if (y1 >= st->ymax)
306 else if (y2 >= st->ymax)
309 qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
310 qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
311 qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
312 qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
314 pixel = set (st, x, y1, st->iteration,
315 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
318 (pixel != qpixels[0] || pixel != qpixels[1] ||
319 pixel != qpixels[2] || pixel != qpixels[3]))
320 draw (st, x, y1, pixel, st->ynextStep);
322 pixel = set (st, x1, y, st->iteration,
323 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
325 (pixel != qpixels[0] || pixel != qpixels[1] ||
326 pixel != qpixels[2] || pixel != qpixels[3]))
327 draw (st, x1, y, pixel, st->ynextStep);
329 pixel = set (st, x1, y1, st->iteration,
330 ((int) CELL (x, y) + (int) CELL (x, y2) +
331 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
334 (pixel != qpixels[0] || pixel != qpixels[1] ||
335 pixel != qpixels[2] || pixel != qpixels[3]))
336 draw (st, x1, y1, pixel, st->ynextStep);
340 if (st->cx >= st->xmax)
344 if (st->cx >= st->xmax)
347 st->xstep = st->xnextStep;
348 st->ystep = st->ynextStep;
352 if (st->iteration > st->iterations)
353 this_delay = st->delay * 1000000;
356 floyd_steinberg (st); /* in mono, do all drawing at the end */
364 imsmap_reshape (Display *dpy, Window window, void *closure,
365 unsigned int w, unsigned int h)
367 struct state *st = (struct state *) closure;
373 imsmap_event (Display *dpy, Window window, void *closure, XEvent *event)
375 struct state *st = (struct state *) closure;
376 if (screenhack_event_helper (dpy, window, event))
387 imsmap_free (Display *dpy, Window window, void *closure)
389 struct state *st = (struct state *) closure;
390 if (st->colors) free (st->colors);
391 if (st->cell) free (st->cell);
396 static const char *imsmap_defaults [] = {
397 ".background: #000066",
398 ".foreground: #FF00FF",
406 "*ignoreRotation: True",
411 static XrmOptionDescRec imsmap_options [] = {
412 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
413 { "-delay", ".delay", XrmoptionSepArg, 0 },
414 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
415 { "-mode", ".mode", XrmoptionSepArg, 0 },
416 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
420 XSCREENSAVER_MODULE ("IMSMap", imsmap)