From http://www.jwz.org/xscreensaver/xscreensaver-5.35.tar.gz
[xscreensaver] / hacks / lcdscrub.c
index e7f220c08aa28e242a2a1e1e574409ae3239ea61..5fd165e3c1d45f73d03aa7fc7c2f663fcf40fc16 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 2008-2013 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 2008-2015 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -27,6 +27,7 @@ struct state {
          DIAG_W, DIAG_B, 
          WHITE, BLACK,
          RGB,
+         RANDOM,
          END } mode;
   unsigned int enabled_mask;
   int count;
@@ -35,6 +36,8 @@ struct state {
   int delay;
   int spread;
   int cycles;
+  XImage *collisions;
+  long ncollisions;
 };
 
 
@@ -56,6 +59,8 @@ lcdscrub_init (Display *dpy, Window window)
 {
   struct state *st = (struct state *) calloc (1, sizeof(*st));
   XGCValues gcv;
+  unsigned long fgp, bgp;
+
   st->dpy = dpy;
   st->window = window;
   st->delay  = get_integer_resource (st->dpy, "delay",  "Integer");
@@ -63,15 +68,20 @@ lcdscrub_init (Display *dpy, Window window)
   st->cycles = get_integer_resource (st->dpy, "cycles", "Integer");
 
   XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
-  gcv.foreground = BlackPixelOfScreen (st->xgwa.screen);
-  gcv.background = WhitePixelOfScreen (st->xgwa.screen);
+  fgp = get_pixel_resource (st->dpy, st->xgwa.colormap, 
+                            "foreground", "Foreground");
+  bgp = get_pixel_resource (st->dpy, st->xgwa.colormap,
+                            "background", "Background");
+
+  gcv.foreground = bgp;
+  gcv.background = fgp;
   st->bg  = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
   st->bg2 = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
-  gcv.foreground = WhitePixelOfScreen (st->xgwa.screen);
-  gcv.background = BlackPixelOfScreen (st->xgwa.screen);
+  gcv.foreground = fgp;
+  gcv.background = bgp;
   st->fg = XCreateGC (st->dpy, st->window, GCForeground, &gcv);
 
-#ifdef HAVE_COCOA
+#ifdef HAVE_JWXYZ
   jwxyz_XSetAntiAliasing (st->dpy, st->fg,  False);
   jwxyz_XSetAntiAliasing (st->dpy, st->bg,  False);
   jwxyz_XSetAntiAliasing (st->dpy, st->bg2, False);
@@ -89,6 +99,7 @@ lcdscrub_init (Display *dpy, Window window)
   PREF("modeW",  WHITE);
   PREF("modeB",  BLACK);
   PREF("modeRGB", RGB);
+  PREF("modeRandom", RANDOM);
 # undef PREF
   if (! st->enabled_mask) 
     {
@@ -101,6 +112,143 @@ lcdscrub_init (Display *dpy, Window window)
   return st;
 }
 
+
+/* A test harness for visualizing different random number generators.
+   This doesn't really belong in lcdscrub, but it was a convenient
+   place to put it.
+ */
+#if 0                                                          /* mwc1616 */
+
+static unsigned long mwc1616_x = 1;
+static unsigned long mwc1616_y = 2;
+
+static void
+mwc1616_srand (unsigned long seed)
+{
+  mwc1616_x = seed | 1;
+  mwc1616_y = seed | 2;
+}
+
+static unsigned long
+mwc1616 (void)
+{
+  mwc1616_x = 18000 * (mwc1616_x & 0xFFFF) + (mwc1616_x >> 16);
+  mwc1616_y = 30903 * (mwc1616_y & 0xFFFF) + (mwc1616_y >> 16);
+  return (mwc1616_x << 16) + (mwc1616_y & 0xFFFF);
+}
+
+# undef random
+# undef srand
+# define srand mwc1616_srand
+# define random() ((unsigned int) (mwc1616() & (unsigned int) (~0)))
+
+
+#elif 0                                                /* xorshift128plus */
+
+
+static uint64_t xo_state0 = 1;
+static uint64_t xo_state1 = 2;
+
+static void
+xorshift128plus_srand (unsigned long seed)
+{
+  xo_state0 = seed | 1;
+  xo_state1 = seed | 2;
+}
+
+static uint64_t
+xorshift128plus (void)
+{
+  register uint64_t s1 = xo_state0;
+  register uint64_t s0 = xo_state1;
+  xo_state0 = s0;
+  s1 ^= s1 << 23;
+  s1 ^= s1 >> 17;
+  s1 ^= s0;
+  s1 ^= s0 >> 26;
+  xo_state1 = s1;
+  return s1;
+}
+
+# undef random
+# undef srand
+# define srand xorshift128plus_srand
+# define random() ((unsigned int) (xorshift128plus() & (unsigned int) (~0)))
+
+
+#else                                                          /* ya_random */
+# undef srand
+# define srand(n)
+
+#endif                                                         /* ya_random */
+
+
+
+/* If you see patterns in this image, the PRNG sucks.
+ */
+static void
+lcdscrub_random (struct state *st)
+{
+  unsigned long steps_per_frame = 3000000;
+  unsigned long segments = 0x8000;  /* 2^15 */
+
+  if (! st->collisions)
+    {
+      struct timeval tp;
+# if GETTIMEOFDAY_TWO_ARGS
+      gettimeofday (&tp, 0);
+# else
+      gettimeofday (&tp);
+# endif
+      srand ((unsigned int) (tp.tv_sec ^ tp.tv_usec));
+
+      st->collisions = 
+        XCreateImage (st->dpy, st->xgwa.visual, 1, XYPixmap,
+                      0, NULL, segments, segments, 8, 0);
+      if (! st->collisions) abort();
+      st->collisions->data = (char *)
+        calloc (segments, st->collisions->bytes_per_line);  /* 128 MB */
+      if (! st->collisions->data) abort();
+    }
+
+  while (--steps_per_frame)
+    {
+      unsigned long x = random() & (segments-1);
+      unsigned long y = random() & (segments-1);
+      unsigned long p = XGetPixel (st->collisions, x, y) ? 0 : 1;
+      XPutPixel (st->collisions, x, y, p);
+      st->ncollisions += (p ? 1 : -1);
+    }
+
+  {
+    int w, h;
+    Pixmap p;
+    GC gc;
+
+    XGetWindowAttributes (st->dpy, st->window, &st->xgwa);
+    w = st->xgwa.width;
+    h = st->xgwa.height;
+
+    p = XCreatePixmap (st->dpy, st->window, w, h, 1);
+    gc = XCreateGC (st->dpy, p, 0, 0);
+    XSetBackground (st->dpy, gc, 0);
+    XSetForeground (st->dpy, gc, 1);
+    XPutImage (st->dpy, p, gc, st->collisions, 0, 0, 0, 0, w, h);
+    XFreeGC (st->dpy, gc);
+
+    gc = st->fg;
+    XClearWindow (st->dpy, st->window);
+    XSetClipMask (st->dpy, gc, p);
+    XFillRectangle (st->dpy, st->window, gc, 0, 0, w, h);
+    XFreePixmap (st->dpy, p);
+  }
+
+  /*
+    fprintf(stderr, "%.2f\n", st->ncollisions / (float) (segments*segments));
+  */
+}
+
+
 static unsigned long
 lcdscrub_draw (Display *dpy, Window window, void *closure)
 {
@@ -167,6 +315,9 @@ lcdscrub_draw (Display *dpy, Window window, void *closure)
     XFillRectangle (st->dpy, st->window, bg, 0, 0,
                     st->xgwa.width, st->xgwa.height);
     break;
+  case RANDOM:
+    lcdscrub_random (st);
+    break;
   default: 
     abort(); 
     break;
@@ -199,6 +350,12 @@ lcdscrub_free (Display *dpy, Window window, void *closure)
   XFreeGC (dpy, st->fg);
   XFreeGC (dpy, st->bg);
   XFreeGC (dpy, st->bg2);
+  if (st->collisions)
+    {
+      free (st->collisions->data);
+      st->collisions->data = 0;
+      XDestroyImage (st->collisions);
+    }
   free (st);
 }
 
@@ -206,6 +363,7 @@ lcdscrub_free (Display *dpy, Window window, void *closure)
 static const char *lcdscrub_defaults [] = {
   ".background:                black",
   ".foreground:                white",
+  "*fpsSolid:          True",
   "*delay:             100000",
   "*spread:            8",
   "*cycles:            60",
@@ -218,6 +376,7 @@ static const char *lcdscrub_defaults [] = {
   "*modeW:             True",
   "*modeB:             True",
   "*modeRGB:           True",
+  "*modeRandom:                False",
   0
 };
 
@@ -234,6 +393,7 @@ static XrmOptionDescRec lcdscrub_options [] = {
   { "-no-w",           ".modeW",       XrmoptionNoArg, "False" },
   { "-no-b",           ".modeB",       XrmoptionNoArg, "False" },
   { "-no-rgb",         ".modeRGB",     XrmoptionNoArg, "False" },
+  { "-random",         ".modeRandom",  XrmoptionNoArg, "True" },
   { 0, 0, 0, 0 }
 };