1 /* xscreensaver, Copyright (c) 2008-2015 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
11 * Draws repetitive patterns that should undo burned in LCD screens.
12 * Concept shamelessly cloned from
13 * http://toastycode.com/blog/2008/02/05/lcd-scrub/
16 #include "screenhack.h"
19 #define countof(x) (sizeof((x))/sizeof((*x)))
24 XWindowAttributes xgwa;
25 enum { HORIZ_W, HORIZ_B,
32 unsigned int enabled_mask;
45 pick_mode (struct state *st)
50 if (++st->mode == END)
52 if (st->enabled_mask & (1 << st->mode))
58 lcdscrub_init (Display *dpy, Window window)
60 struct state *st = (struct state *) calloc (1, sizeof(*st));
62 unsigned long fgp, bgp;
66 st->delay = get_integer_resource (st->dpy, "delay", "Integer");
67 st->spread = get_integer_resource (st->dpy, "spread", "Integer");
68 st->cycles = get_integer_resource (st->dpy, "cycles", "Integer");
70 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
71 fgp = get_pixel_resource (st->dpy, st->xgwa.colormap,
72 "foreground", "Foreground");
73 bgp = get_pixel_resource (st->dpy, st->xgwa.colormap,
74 "background", "Background");
78 st->bg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
79 st->bg2 = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
82 st->fg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
85 jwxyz_XSetAntiAliasing (st->dpy, st->fg, False);
86 jwxyz_XSetAntiAliasing (st->dpy, st->bg, False);
87 jwxyz_XSetAntiAliasing (st->dpy, st->bg2, False);
92 if (get_boolean_resource (st->dpy, R, "Mode")) st->enabled_mask |= (1 << F)
93 PREF("modeHW", HORIZ_W);
94 PREF("modeHB", HORIZ_B);
95 PREF("modeVW", VERT_W);
96 PREF("modeVB", VERT_B);
97 PREF("modeDW", DIAG_W);
98 PREF("modeDB", DIAG_B);
100 PREF("modeB", BLACK);
101 PREF("modeRGB", RGB);
102 PREF("modeRandom", RANDOM);
104 if (! st->enabled_mask)
106 fprintf (stderr, "%s: no modes enabled\n", progname);
116 /* A test harness for visualizing different random number generators.
117 This doesn't really belong in lcdscrub, but it was a convenient
122 static unsigned long mwc1616_x = 1;
123 static unsigned long mwc1616_y = 2;
126 mwc1616_srand (unsigned long seed)
128 mwc1616_x = seed | 1;
129 mwc1616_y = seed | 2;
135 mwc1616_x = 18000 * (mwc1616_x & 0xFFFF) + (mwc1616_x >> 16);
136 mwc1616_y = 30903 * (mwc1616_y & 0xFFFF) + (mwc1616_y >> 16);
137 return (mwc1616_x << 16) + (mwc1616_y & 0xFFFF);
142 # define srand mwc1616_srand
143 # define random() ((unsigned int) (mwc1616() & (unsigned int) (~0)))
146 #elif 0 /* xorshift128plus */
149 static uint64_t xo_state0 = 1;
150 static uint64_t xo_state1 = 2;
153 xorshift128plus_srand (unsigned long seed)
155 xo_state0 = seed | 1;
156 xo_state1 = seed | 2;
160 xorshift128plus (void)
162 register uint64_t s1 = xo_state0;
163 register uint64_t s0 = xo_state1;
175 # define srand xorshift128plus_srand
176 # define random() ((unsigned int) (xorshift128plus() & (unsigned int) (~0)))
179 #else /* ya_random */
183 #endif /* ya_random */
187 /* If you see patterns in this image, the PRNG sucks.
190 lcdscrub_random (struct state *st)
192 unsigned long steps_per_frame = 3000000;
193 unsigned long segments = 0x8000; /* 2^15 */
195 if (! st->collisions)
198 # if GETTIMEOFDAY_TWO_ARGS
199 gettimeofday (&tp, 0);
203 srand ((unsigned int) (tp.tv_sec ^ tp.tv_usec));
206 XCreateImage (st->dpy, st->xgwa.visual, 1, XYPixmap,
207 0, NULL, segments, segments, 8, 0);
208 if (! st->collisions) abort();
209 st->collisions->data = (char *)
210 calloc (segments, st->collisions->bytes_per_line); /* 128 MB */
211 if (! st->collisions->data) abort();
214 while (--steps_per_frame)
216 unsigned long x = random() & (segments-1);
217 unsigned long y = random() & (segments-1);
218 unsigned long p = XGetPixel (st->collisions, x, y) ? 0 : 1;
219 XPutPixel (st->collisions, x, y, p);
220 st->ncollisions += (p ? 1 : -1);
228 XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
232 p = XCreatePixmap (st->dpy, st->window, w, h, 1);
233 gc = XCreateGC (st->dpy, p, 0, 0);
234 XSetBackground (st->dpy, gc, 0);
235 XSetForeground (st->dpy, gc, 1);
236 XPutImage (st->dpy, p, gc, st->collisions, 0, 0, 0, 0, w, h);
237 XFreeGC (st->dpy, gc);
240 XClearWindow (st->dpy, st->window);
241 XSetClipMask (st->dpy, gc, p);
242 XFillRectangle (st->dpy, st->window, gc, 0, 0, w, h);
243 XFreePixmap (st->dpy, p);
247 fprintf(stderr, "%.2f\n", st->ncollisions / (float) (segments*segments));
253 lcdscrub_draw (Display *dpy, Window window, void *closure)
255 struct state *st = (struct state *) closure;
256 int count = st->count % st->spread;
258 GC fg = (st->mode & 1 ? st->fg : st->bg);
259 GC bg = (st->mode & 1 ? st->bg : st->fg);
264 XFillRectangle (st->dpy, st->window, bg, 0, 0,
265 st->xgwa.width, st->xgwa.height);
266 for (i = count; i < st->xgwa.height; i += st->spread)
267 XDrawLine (st->dpy, st->window, fg, 0, i, st->xgwa.width, i);
271 XFillRectangle (st->dpy, st->window, bg, 0, 0,
272 st->xgwa.width, st->xgwa.height);
273 for (i = count; i < st->xgwa.width; i += st->spread)
274 XDrawLine (st->dpy, st->window, fg, i, 0, i, st->xgwa.height);
278 XFillRectangle (st->dpy, st->window, bg, 0, 0,
279 st->xgwa.width, st->xgwa.height);
280 for (i = count; i < st->xgwa.width; i += st->spread)
281 XDrawLine (st->dpy, st->window, fg, i, 0,
282 i + st->xgwa.width, st->xgwa.width);
283 for (i = -count; i < st->xgwa.height; i += st->spread)
284 XDrawLine (st->dpy, st->window, fg, 0, i,
285 st->xgwa.height, i + st->xgwa.height);
289 int scale = 10 * 8; /* 8 sec */
290 static const unsigned short colors[][3] = {
291 { 0xFFFF, 0x0000, 0x0000 },
292 { 0x0000, 0xFFFF, 0x0000 },
293 { 0x0000, 0x0000, 0xFFFF },
294 { 0xFFFF, 0xFFFF, 0x0000 },
295 { 0xFFFF, 0x0000, 0xFFFF },
296 { 0x0000, 0xFFFF, 0xFFFF },
297 { 0xFFFF, 0xFFFF, 0xFFFF },
298 { 0x0000, 0x0000, 0x0000 },
300 static unsigned long last = 0;
303 xc.red = colors[st->color_tick / scale][0];
304 xc.green = colors[st->color_tick / scale][1];
305 xc.blue = colors[st->color_tick / scale][2];
306 if (last) XFreeColors (st->dpy, st->xgwa.colormap, &last, 1, 0);
307 XAllocColor (st->dpy, st->xgwa.colormap, &xc);
309 XSetForeground (st->dpy, bg, xc.pixel);
310 st->color_tick = (st->color_tick + 1) % (countof(colors) * scale);
315 XFillRectangle (st->dpy, st->window, bg, 0, 0,
316 st->xgwa.width, st->xgwa.height);
319 lcdscrub_random (st);
328 if (st->count > st->spread * st->cycles)
335 lcdscrub_reshape (Display *dpy, Window window, void *closure,
336 unsigned int w, unsigned int h)
341 lcdscrub_event (Display *dpy, Window window, void *closure, XEvent *event)
347 lcdscrub_free (Display *dpy, Window window, void *closure)
349 struct state *st = (struct state *) closure;
350 XFreeGC (dpy, st->fg);
351 XFreeGC (dpy, st->bg);
352 XFreeGC (dpy, st->bg2);
355 free (st->collisions->data);
356 st->collisions->data = 0;
357 XDestroyImage (st->collisions);
363 static const char *lcdscrub_defaults [] = {
364 ".background: black",
365 ".foreground: white",
379 "*modeRandom: False",
383 static XrmOptionDescRec lcdscrub_options [] = {
384 { "-delay", ".delay", XrmoptionSepArg, 0 },
385 { "-spread", ".spread", XrmoptionSepArg, 0 },
386 { "-cycles", ".cycles", XrmoptionSepArg, 0 },
387 { "-no-hw", ".modeHW", XrmoptionNoArg, "False" },
388 { "-no-hb", ".modeHB", XrmoptionNoArg, "False" },
389 { "-no-vw", ".modeVW", XrmoptionNoArg, "False" },
390 { "-no-vb", ".modeVB", XrmoptionNoArg, "False" },
391 { "-no-dw", ".modeDW", XrmoptionNoArg, "False" },
392 { "-no-db", ".modeDB", XrmoptionNoArg, "False" },
393 { "-no-w", ".modeW", XrmoptionNoArg, "False" },
394 { "-no-b", ".modeB", XrmoptionNoArg, "False" },
395 { "-no-rgb", ".modeRGB", XrmoptionNoArg, "False" },
396 { "-random", ".modeRandom", XrmoptionNoArg, "True" },
401 XSCREENSAVER_MODULE ("LCDscrub", lcdscrub)