1 /* imsmap, Copyright (c) 1992 Juergen Nickelsen <nickel@cs.tu-berlin.de>
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);
167 st->ncolors = get_integer_resource (st->dpy, "ncolors", "Integer");
168 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
169 st->delay2 = get_integer_resource (st->dpy, "delay2", "Integer");
170 st->iterations = get_integer_resource (st->dpy, "iterations", "Integer");
171 if (st->iterations < 0) st->iterations = 0;
172 else if (st->iterations > 7) st->iterations = 7;
174 if (st->ncolors <= 2) st->ncolors = 0;
175 if (st->ncolors == 0) mono_p = True;
176 if (st->ncolors > 255) st->ncolors = 255; /* too many look bad */
178 st->gc = XCreateGC (st->dpy, st->window, 0, &gcv);
179 st->gc2 = XCreateGC (st->dpy, st->window, 0, &gcv);
183 st->extra_krinkly_p = !(random() % 15);
185 st->extra_krinkly_p = !(random() % 5);
190 free_colors (st->dpy, st->cmap, st->colors, st->ncolors);
192 st->colors = (XColor *) malloc (st->ncolors * sizeof(*st->colors));
194 make_smooth_colormap (st->dpy, st->xgwa.visual, st->cmap,
195 st->colors, &st->ncolors,
197 if (st->ncolors <= 2)
204 unsigned long fg_pixel =
205 get_pixel_resource (st->dpy, st->xgwa.colormap,
206 "foreground", "Foreground");
207 unsigned long bg_pixel =
208 get_pixel_resource (st->dpy, st->xgwa.colormap,
209 "background", "Background");
213 st->colors = (XColor *) calloc (st->ncolors, sizeof(*st->colors));
215 st->colors[0].pixel = fg_pixel;
216 for (i = 1; i < st->ncolors; i++)
217 st->colors[i].pixel = bg_pixel;
220 XSetForeground (st->dpy, st->gc, st->colors[1].pixel);
221 XFillRectangle (st->dpy, st->window, st->gc, 0, 0, st->xgwa.width, st->xgwa.height);
225 st->xmax = st->xgwa.height;
226 st->ymax = st->xgwa.width;
230 st->xmax = st->xgwa.width;
231 st->ymax = st->xgwa.height;
234 if (st->cell) free (st->cell);
235 st->cell = (signed char *) calloc (st->xmax * st->ymax, 1);
247 imsmap_init (Display *dpy, Window window)
249 struct state *st = (struct state *) calloc (1, sizeof(*st));
258 imsmap_draw (Display *dpy, Window window, void *closure)
260 struct state *st = (struct state *) closure;
261 int this_delay = st->delay2;
264 /* do this many lines at a time without pausing */
265 int col_chunk = st->iteration * 2 + 1;
267 if (st->iteration > st->iterations)
272 st->xnextStep = st->xstep / 2;
273 st->ynextStep = st->ystep / 2;
276 for (i = 0; i < col_chunk; i++)
282 x1 = x + st->xnextStep;
285 else if (x1 >= st->xmax)
291 else if (x2 >= st->xmax)
294 for (y = 0; y < st->ymax; y += st->ystep)
296 unsigned int pixel, qpixels [4];
298 y1 = y + st->ynextStep;
301 else if (y1 >= st->ymax)
307 else if (y2 >= st->ymax)
310 qpixels [0] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y))].pixel;
311 qpixels [1] = st->colors [HEIGHT_TO_PIXEL (CELL (x, y2))].pixel;
312 qpixels [2] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y))].pixel;
313 qpixels [3] = st->colors [HEIGHT_TO_PIXEL (CELL (x2, y2))].pixel;
315 pixel = set (st, x, y1, st->iteration,
316 ((int) CELL (x, y) + (int) CELL (x, y2) + 1) / 2);
319 (pixel != qpixels[0] || pixel != qpixels[1] ||
320 pixel != qpixels[2] || pixel != qpixels[3]))
321 draw (st, x, y1, pixel, st->ynextStep);
323 pixel = set (st, x1, y, st->iteration,
324 ((int) CELL (x, y) + (int) CELL (x2, y) + 1) / 2);
326 (pixel != qpixels[0] || pixel != qpixels[1] ||
327 pixel != qpixels[2] || pixel != qpixels[3]))
328 draw (st, x1, y, pixel, st->ynextStep);
330 pixel = set (st, x1, y1, st->iteration,
331 ((int) CELL (x, y) + (int) CELL (x, y2) +
332 (int) CELL (x2, y) + (int) CELL (x2, y2) + 2)
335 (pixel != qpixels[0] || pixel != qpixels[1] ||
336 pixel != qpixels[2] || pixel != qpixels[3]))
337 draw (st, x1, y1, pixel, st->ynextStep);
341 if (st->cx >= st->xmax)
345 if (st->cx >= st->xmax)
348 st->xstep = st->xnextStep;
349 st->ystep = st->ynextStep;
353 if (st->iteration > st->iterations)
354 this_delay = st->delay * 1000000;
357 floyd_steinberg (st); /* in mono, do all drawing at the end */
365 imsmap_reshape (Display *dpy, Window window, void *closure,
366 unsigned int w, unsigned int h)
368 struct state *st = (struct state *) closure;
374 imsmap_event (Display *dpy, Window window, void *closure, XEvent *event)
376 struct state *st = (struct state *) closure;
377 if (event->xany.type == ButtonPress)
388 imsmap_free (Display *dpy, Window window, void *closure)
390 struct state *st = (struct state *) closure;
391 if (st->colors) free (st->colors);
392 if (st->cell) free (st->cell);
397 static const char *imsmap_defaults [] = {
398 ".background: #000066",
399 ".foreground: #FF00FF",
408 static XrmOptionDescRec imsmap_options [] = {
409 { "-ncolors", ".ncolors", XrmoptionSepArg, 0 },
410 { "-delay", ".delay", XrmoptionSepArg, 0 },
411 { "-delay2", ".delay2", XrmoptionSepArg, 0 },
412 { "-mode", ".mode", XrmoptionSepArg, 0 },
413 { "-iterations", ".iterations", XrmoptionSepArg, 0 },
417 XSCREENSAVER_MODULE ("IMSMAP", imsmap)