From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / hypercube.c
index 05574fb35f5fd9f0b1db66cb243e4047e847fe79..0055696b8d110c66703fc8e94f69bdcca3540412 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1992, 1995 Jamie Zawinski <jwz@netscape.com>
+/* xscreensaver, Copyright (c) 1992-2008 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
 #include <math.h>
 #include "screenhack.h"
 
-static Display *dpy;
-static Window window;
-static GC color0, color1, color2, color3, color4, color5, color6, color7;
-static GC black;
+#define POINT_COUNT 16
+#define LINE_COUNT 32
 
-static int delay;
+#define ANGLE_SCALE 0.001
 
-static int observer_z;
-static int x_offset, y_offset;
-static int unit_pixels;
-
-struct point_state {
-  int old_x, old_y;
-  int new_x, new_y;
-  Bool same_p;
+struct line_info
+{
+  char li_ip;
+  char li_iq;
+  char li_color;
+  char li_pad;
 };
 
-static void
-move_line (state0, state1, gc)
-     struct point_state *state0, *state1;
-     GC gc;
+struct point_state
 {
-  if (state0->same_p && state1->same_p)
-    return;
-  if (mono_p)
-    {
-      XDrawLine (dpy, window, black,
-                state0->old_x, state0->old_y, state1->old_x, state1->old_y);
-      XDrawLine (dpy, window, gc,
-                state0->new_x, state0->new_y, state1->new_x, state1->new_y);
-    }
-  else
-    {
-      XSegment segments [2];
-      segments [0].x1 = state0->old_x; segments [0].y1 = state0->old_y;
-      segments [0].x2 = state1->old_x; segments [0].y2 = state1->old_y;
-      segments [1].x1 = state0->new_x; segments [1].y1 = state0->new_y;
-      segments [1].x2 = state1->new_x; segments [1].y2 = state1->new_y;
-      XDrawSegments (dpy, window, gc, segments, 2);
-    }
-}
+  short old_x, old_y;
+  short new_x, new_y;
+};
 
-static void
-hyper (xy, xz, yz, xw, yw, zw)
-     double xy, xz, yz, xw, yw, zw;
+struct hyper_state
 {
-  double cos_xy = cos (xy), sin_xy = sin (xy);
-  double cos_xz = cos (xz), sin_xz = sin (xz);
-  double cos_yz = cos (yz), sin_yz = sin (yz);
-  double cos_xw = cos (xw), sin_xw = sin (xw);
-  double cos_yw = cos (yw), sin_yw = sin (yw);
-  double cos_zw = cos (zw), sin_zw = sin (zw);
-
-  double ax = 1.0, ay = 0.0, az = 0.0, aw = 0.0;
-  double bx = 0.0, by = 1.0, bz = 0.0, bw = 0.0;
-  double cx = 0.0, cy = 0.0, cz = 1.0, cw = 0.0;
-  double dx = 0.0, dy = 0.0, dz = 0.0, dw = 1.0;
-
-  double _tmp0_, _tmp1_;
-
-  struct point_state points [16];
-  memset (points, 0, sizeof (points));
-
-#define mmmm (&points[0])
-#define mmmp (&points[1])
-#define mmpm (&points[2])
-#define mmpp (&points[3])
-#define mpmm (&points[4])
-#define mpmp (&points[5])
-#define mppm (&points[6])
-#define mppp (&points[7])
-#define pmmm (&points[8])
-#define pmmp (&points[9])
-#define pmpm (&points[10])
-#define pmpp (&points[11])
-#define ppmm (&points[12])
-#define ppmp (&points[13])
-#define pppm (&points[14])
-#define pppp (&points[15])
-
-  while (1)
-    {
-      double temp_mult;
-
-#define compute(a,b,c,d,point_state) \
-      temp_mult = (unit_pixels / (((a*az) + (b*bz) + (c*cz) + (d*dz) +   \
-                                  (a*aw) + (b*bw) + (c*cw) + (d*dw))     \
-                                 - observer_z));                         \
-  point_state->old_x = point_state->new_x;                               \
-  point_state->old_y = point_state->new_y;                               \
-  point_state->new_x = ((((a*ax) + (b*bx) + (c*cx) + (d*dx)) * temp_mult) \
-                       + x_offset);                                      \
-  point_state->new_y = ((((a*ay) + (b*by) + (c*cy) + (d*dy)) * temp_mult) \
-                       + y_offset);                                      \
-  point_state->same_p = (point_state->old_x == point_state->new_x &&     \
-                        point_state->old_y == point_state->new_y);
-
-      compute (-1, -1, -1, -1, mmmm);
-      compute (-1, -1, -1,  1, mmmp);
-      compute (-1, -1,  1, -1, mmpm);
-      compute (-1, -1,  1,  1, mmpp);
-      compute (-1,  1, -1, -1, mpmm);
-      compute (-1,  1, -1,  1, mpmp);
-      compute (-1,  1,  1, -1, mppm);
-      compute (-1,  1,  1,  1, mppp);
-      compute ( 1, -1, -1, -1, pmmm);
-      compute ( 1, -1, -1,  1, pmmp);
-      compute ( 1, -1,  1, -1, pmpm);
-      compute ( 1, -1,  1,  1, pmpp);
-      compute ( 1,  1, -1, -1, ppmm);
-      compute ( 1,  1, -1,  1, ppmp);
-      compute ( 1,  1,  1, -1, pppm);
-      compute ( 1,  1,  1,  1, pppp);
-
-      move_line (mmmm, mmmp, color0);
-      move_line (mmmm, mmpm, color0);
-      move_line (mmpm, mmpp, color0);
-      move_line (mmmp, mmpp, color0);
-      
-      move_line (pmmm, pmmp, color1);
-      move_line (pmmm, pmpm, color1);
-      move_line (pmpm, pmpp, color1);
-      move_line (pmmp, pmpp, color1);
-      
-      move_line (mpmm, mpmp, color2);
-      move_line (mpmm, mppm, color2);
-      move_line (mppm, mppp, color2);
-      move_line (mpmp, mppp, color2);
-      
-      move_line (mmpp, mppp, color3);
-      move_line (mmpp, pmpp, color3);
-      move_line (pmpp, pppp, color3);
-      move_line (mppp, pppp, color3);
-      
-      move_line (mmmm, mpmm, color4);
-      move_line (mmmm, pmmm, color4);
-      move_line (mpmm, ppmm, color4);
-      move_line (pmmm, ppmm, color4);
-      
-      move_line (mmmp, mpmp, color5);
-      move_line (mmmp, pmmp, color5);
-      move_line (pmmp, ppmp, color5);
-      move_line (mpmp, ppmp, color5);
-      
-      move_line (mmpm, mppm, color6);
-      move_line (mmpm, pmpm, color6);
-      move_line (pmpm, pppm, color6);
-      move_line (mppm, pppm, color6);
-      
-      move_line (ppmm, ppmp, color7);
-      move_line (ppmm, pppm, color7);
-      move_line (pppm, pppp, color7);
-      move_line (ppmp, pppp, color7);
-
- /* If you get error messages about the following forms, and you think you're
-    using an ANSI C conforming compiler, then you're mistaken.  Possibly you're
-    mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa.
-    Regardless, your system is broken; it's not a bug in this program.
-  */
-#if __STDC__
-# define rotate(name,dim0,dim1,cos,sin) \
-      _tmp0_ = ((name##dim0 * cos) + (name##dim1 * sin)); \
-      _tmp1_ = ((name##dim1 * cos) - (name##dim0 * sin)); \
-      name##dim0 = _tmp0_; \
-      name##dim1 = _tmp1_;
-
-# define rotates(dim0,dim1) \
-      if (sin_##dim0##dim1 != 0) {                                \
-        rotate(a, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
-        rotate(b, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
-        rotate(c, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
-        rotate(d, dim0, dim1, cos_##dim0##dim1, sin_##dim0##dim1); \
-      }
-
-#else /* !__STDC__, courtesy of Andreas Luik <luik@isa.de> */
-# define rotate(name,dim0,dim1,cos,sin) \
-      _tmp0_ = ((name/**/dim0 * cos) + (name/**/dim1 * sin)); \
-      _tmp1_ = ((name/**/dim1 * cos) - (name/**/dim0 * sin)); \
-      name/**/dim0 = _tmp0_; \
-      name/**/dim1 = _tmp1_;
-
-# define rotates(dim0,dim1) \
-      if (sin_/**/dim0/**/dim1 != 0) {                                \
-        rotate(a,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
-        rotate(b,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
-        rotate(c,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
-        rotate(d,dim0,dim1,cos_/**/dim0/**/dim1,sin_/**/dim0/**/dim1); \
-      }
-#endif /* !__STDC__ */
-
-      rotates (x,y);
-      rotates (x,z);
-      rotates (y,z);
-      rotates (x,w);
-      rotates (y,w);
-      rotates (z,w);
-
-      XSync (dpy, True);
-      if (delay) usleep (delay);
-    }
-}
+  char hs_stop;
+  char hs_icon;
+  char hs_resize;
+  char hs_redraw;
+  Display *hs_display;
+  Window hs_window;
+  float hs_two_observer_z;
+  float hs_offset_x;
+  float hs_offset_y;
+  float hs_unit_scale;
+  int hs_delay;
+  GC hs_color_gcs[8];
+  GC black_gc;
+#if 0
+  double hs_angle_xy;
+  double hs_angle_xz;
+  double hs_angle_yz;
+  double hs_angle_xw;
+  double hs_angle_yw;
+  double hs_angle_zw;
+#endif
+  double hs_cos_xy, hs_sin_xy;
+  double hs_cos_xz, hs_sin_xz;
+  double hs_cos_yz, hs_sin_yz;
+  double hs_cos_xw, hs_sin_xw;
+  double hs_cos_yw, hs_sin_yw;
+  double hs_cos_zw, hs_sin_zw;
+  double hs_ref_ax, hs_ref_ay, hs_ref_az, hs_ref_aw;
+  double hs_ref_bx, hs_ref_by, hs_ref_bz, hs_ref_bw;
+  double hs_ref_cx, hs_ref_cy, hs_ref_cz, hs_ref_cw;
+  double hs_ref_dx, hs_ref_dy, hs_ref_dz, hs_ref_dw;
+  struct point_state hs_points[POINT_COUNT];
+  int roted;
+};
 
-\f
-char *progclass = "Hypercube";
+static const struct line_info line_table[LINE_COUNT];
 
-char *defaults [] = {
-  "Hypercube.background:       black",         /* to placate SGI */
-  "Hypercube.foreground:       white",
-  "*color0:    red",
-  "*color1:    orange",
-  "*color2:    yellow",
-  "*color3:    white",
+static const char *hypercube_defaults[] =
+{
+  "*observer-z:        3.0",
+  "*delay: 10000",
+  "*xy: 3",
+  "*xz:        5",
+  "*yw:        10",
+  "*yz:        0",
+  "*xw:        0",
+  "*zw:        0",
+  ".background:        black",
+  ".foreground:        white",
+  "*fpsSolid:  true",
+  "*color0:    magenta",
+  "*color3:    #FF0093",
+  "*color1:    yellow",
+  "*color2:    #FF9300",
   "*color4:    green",
-  "*color5:    cyan",
-  "*color6:    dodgerblue",
-  "*color7:    magenta",
-
-  "*xw:                0.000",
-  "*xy:                0.010",
-  "*xz:                0.005",
-  "*yw:                0.010",
-  "*yz:                0.000",
-  "*zw:                0.000",
-
-  "*observer-z:        5",
-  "*delay:     100000",
+  "*color7:    #00FFD0",
+  "*color5:    #8080FF",
+  "*color6:    #00D0FF",
+
   0
 };
 
-XrmOptionDescRec options [] = {
+static XrmOptionDescRec hypercube_options [] =
+{
   { "-color0",         ".color0",      XrmoptionSepArg, 0 },
   { "-color1",         ".color1",      XrmoptionSepArg, 0 },
   { "-color2",         ".color2",      XrmoptionSepArg, 0 },
@@ -262,73 +117,453 @@ XrmOptionDescRec options [] = {
   { "-zw",             ".zw",          XrmoptionSepArg, 0 },
 
   { "-observer-z",     ".observer-z",  XrmoptionSepArg, 0 },
-  { "-delay",          ".delay",       XrmoptionSepArg, 0 }
+  { "-delay",          ".delay",       XrmoptionSepArg, 0 },
+  { 0, 0, 0, 0 }
 };
 
-int options_size = (sizeof (options) / sizeof (options[0]));
 
+static void set_sizes (struct hyper_state *hs, int width, int height);
 
-void
-screenhack (d, w)
-     Display *d;
-     Window w;
+static void *
+hypercube_init (Display *dpy, Window win)
 {
   XGCValues gcv;
-  XWindowAttributes xgwa;
   Colormap cmap;
-  double xy, xz, yz, xw, yw, zw;
-  unsigned long bg;
+  unsigned long bg_pixel;
+  int delay;
+  float observer_z;
 
-  dpy = d;
-  window = w;
-  XGetWindowAttributes (dpy, window, &xgwa);
-  cmap = xgwa.colormap;
+  struct hyper_state *hs = (struct hyper_state *) calloc (1, sizeof(*hs));
+  hs->hs_display = dpy;
+  hs->hs_window = win;
 
-  x_offset = xgwa.width / 2;
-  y_offset = xgwa.height / 2;
-  unit_pixels = xgwa.width < xgwa.height ? xgwa.width : xgwa.height;
+  observer_z = get_float_resource (dpy, "observer-z", "Float");
+  if (observer_z < 1.125)
+    observer_z = 1.125;
+  /* hs->hs_observer_z = observer_z; */
+  hs->hs_two_observer_z = 2.0 * observer_z;
 
-  xy = get_float_resource ("xy", "Float");
-  xz = get_float_resource ("xz", "Float");
-  yz = get_float_resource ("yz", "Float");
-  xw = get_float_resource ("xw", "Float");
-  yw = get_float_resource ("yw", "Float");
-  zw = get_float_resource ("zw", "Float");
+  {
+    XWindowAttributes wa;
+    XGetWindowAttributes (dpy, win, &wa);
+    cmap = wa.colormap;
+    set_sizes (hs, wa.width, wa.height);
+  }
 
-  observer_z = get_integer_resource ("observer-z", "Integer");
+  delay = get_integer_resource (dpy, "delay", "Integer");
+  hs->hs_delay = delay;
 
-  delay = get_integer_resource ("delay", "Integer");
-
-  bg = get_pixel_resource ("background", "Background", dpy, cmap);
+  bg_pixel = get_pixel_resource (dpy, cmap, "background", "Background");
 
   if (mono_p)
     {
+      GC black_gc;
+      unsigned long fg_pixel;
+      GC white_gc;
+
       gcv.function = GXcopy;
-      gcv.foreground = bg;
-      black = XCreateGC (dpy, window, GCForeground|GCFunction, &gcv);
-      gcv.foreground = get_pixel_resource ("foreground", "Foreground",
-                                          dpy, cmap);
-      color0 = color1 = color2 = color3 = color4 = color5 = color6 = color7 =
-       XCreateGC (dpy, window, GCForeground|GCFunction, &gcv);
+      gcv.foreground = bg_pixel;
+      black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
+      fg_pixel = get_pixel_resource (dpy, cmap, "foreground", "Foreground");
+      gcv.foreground = fg_pixel ^ bg_pixel;
+      white_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
+      hs->hs_color_gcs[0] = black_gc;
+      hs->hs_color_gcs[1] = white_gc;
     }
   else
     {
-      black = 0;
-      gcv.function = GXxor;
-#define make_gc(color,name) \
-       gcv.foreground = bg ^ get_pixel_resource ((name), "Foreground", \
-                                                 dpy, cmap);           \
-       color = XCreateGC (dpy, window, GCForeground|GCFunction, &gcv)
-
-      make_gc (color0,"color0");
-      make_gc (color1,"color1");
-      make_gc (color2,"color2");
-      make_gc (color3,"color3");
-      make_gc (color4,"color4");
-      make_gc (color5,"color5");
-      make_gc (color6,"color6");
-      make_gc (color7,"color7");
+      int col;
+
+      gcv.function = GXcopy;
+
+      gcv.foreground = get_pixel_resource (dpy, cmap,
+                                           "background", "Background");
+      hs->black_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
+
+      for (col = 0; col < 8; col++)
+       {
+         char buffer[16];
+         unsigned long fg_pixel;
+         GC color_gc;
+
+         sprintf (buffer, "color%d", col);
+         fg_pixel = get_pixel_resource (dpy, cmap, buffer, "Foreground");
+         gcv.foreground = fg_pixel;
+         color_gc = XCreateGC (dpy, win, GCForeground|GCFunction, &gcv);
+         hs->hs_color_gcs[col] = color_gc;
+       }
+    }
+
+  hs->hs_ref_ax = 1.0, hs->hs_ref_ay = 0.0, hs->hs_ref_az = 0.0, hs->hs_ref_aw = 0.0;
+  hs->hs_ref_bx = 0.0, hs->hs_ref_by = 1.0, hs->hs_ref_bz = 0.0, hs->hs_ref_bw = 0.0;
+  hs->hs_ref_cx = 0.0, hs->hs_ref_cy = 0.0, hs->hs_ref_cz = 1.0, hs->hs_ref_cw = 0.0;
+  hs->hs_ref_dx = 0.0, hs->hs_ref_dy = 0.0, hs->hs_ref_dz = 0.0, hs->hs_ref_dw = 1.0;
+
+  {
+  double xy;
+  double xz;
+  double yz;
+  double xw;
+  double yw;
+  double zw;
+  double cos_xy, sin_xy;
+  double cos_xz, sin_xz;
+  double cos_yz, sin_yz;
+  double cos_xw, sin_xw;
+  double cos_yw, sin_yw;
+  double cos_zw, sin_zw;
+
+  xy = get_float_resource (dpy, "xy", "Float") * ANGLE_SCALE;
+  xz = get_float_resource (dpy, "xz", "Float") * ANGLE_SCALE;
+  yz = get_float_resource (dpy, "yz", "Float") * ANGLE_SCALE;
+  xw = get_float_resource (dpy, "xw", "Float") * ANGLE_SCALE;
+  yw = get_float_resource (dpy, "yw", "Float") * ANGLE_SCALE;
+  zw = get_float_resource (dpy, "zw", "Float") * ANGLE_SCALE;
+
+  cos_xy = cos (xy), sin_xy = sin (xy);
+  hs->hs_cos_xy = cos_xy, hs->hs_sin_xy = sin_xy;
+  cos_xz = cos (xz), sin_xz = sin (xz);
+  hs->hs_cos_xz = cos_xz, hs->hs_sin_xz = sin_xz;
+  cos_yz = cos (yz), sin_yz = sin (yz);
+  hs->hs_cos_yz = cos_yz, hs->hs_sin_yz = sin_yz;
+  cos_xw = cos (xw), sin_xw = sin (xw);
+  hs->hs_cos_xw = cos_xw, hs->hs_sin_xw = sin_xw;
+  cos_yw = cos (yw), sin_yw = sin (yw);
+  hs->hs_cos_yw = cos_yw, hs->hs_sin_yw = sin_yw;
+  cos_zw = cos (zw), sin_zw = sin (zw);
+  hs->hs_cos_zw = cos_zw, hs->hs_sin_zw = sin_zw;
+  }
+
+  return hs;
+}
+
+
+static unsigned long
+hypercube_draw (Display *dpy, Window window, void *closure)
+{
+  struct hyper_state *hs = (struct hyper_state *) closure;
+  int this_delay = hs->hs_delay;
+
+#ifdef HAVE_JWXYZ      /* Don't second-guess Quartz's double-buffering */
+  XClearWindow (dpy, window);
+#endif
+
+    {
+      int icon;
+      int resize;
+      char moved[POINT_COUNT];
+      int redraw;
+      int stop;
+
+      icon = hs->hs_icon;
+      resize = hs->hs_resize;
+      if (icon || !(hs->roted | resize))
+       goto skip1;
+
+      {
+       float observer_z;
+       float unit_scale;
+       float offset_x;
+       float offset_y;
+       double az, bz, cz, dz;
+       double sum_z;
+       double ax, bx, cx, dx;
+       double sum_x;
+       double ay, by, cy, dy;
+       double sum_y;
+       struct point_state *ps;
+       int old_x;
+       int old_y;
+       double mul;
+       double xf;
+       double yf;
+       int new_x;
+       int new_y;
+       int mov;
+
+
+#define compute(as,bs,cs,ds,i) \
+  az = hs->hs_ref_az; bz = hs->hs_ref_bz; cz = hs->hs_ref_cz; dz = hs->hs_ref_dz; \
+  ax = hs->hs_ref_ax; bx = hs->hs_ref_bx; cx = hs->hs_ref_cx; dx = hs->hs_ref_dx; \
+  ay = hs->hs_ref_ay; by = hs->hs_ref_by; cy = hs->hs_ref_cy; dy = hs->hs_ref_dy; \
+  sum_z = as az bs bz cs cz ds dz; \
+  observer_z = hs->hs_two_observer_z; \
+  unit_scale = hs->hs_unit_scale; \
+  sum_x = as ax bs bx cs cx ds dx; \
+  sum_y = as ay bs by cs cy ds dy; \
+  ps = &hs->hs_points[i]; \
+  mul = unit_scale / (observer_z - sum_z); \
+  offset_x = hs->hs_offset_x; \
+  offset_y = hs->hs_offset_y; \
+  old_x = ps->new_x; \
+  old_y = ps->new_y; \
+  xf = sum_x * mul + offset_x; \
+  yf = sum_y * mul + offset_y; \
+  new_x = (int)rint(xf); \
+  new_y = (int)rint(yf); \
+  ps->old_x = old_x; \
+  ps->old_y = old_y; \
+  ps->new_x = new_x; \
+  ps->new_y = new_y; \
+  mov = old_x != new_x || old_y != new_y; \
+  moved[i] = mov;
+
+       compute (-, -, -, -, 0);
+       compute (-, -, -, +, 1);
+       compute (-, -, +, -, 2);
+       compute (-, -, +, +, 3);
+       compute (-, +, -, -, 4);
+       compute (-, +, -, +, 5);
+       compute (-, +, +, -, 6);
+       compute (-, +, +, +, 7);
+       compute (+, -, -, -, 8);
+       compute (+, -, -, +, 9);
+       compute (+, -, +, -, 10);
+       compute (+, -, +, +, 11);
+       compute (+, +, -, -, 12);
+       compute (+, +, -, +, 13);
+       compute (+, +, +, -, 14);
+       compute (+, +, +, +, 15);
+      }
+
+    skip1:
+      icon = hs->hs_icon;
+      redraw = hs->hs_redraw;
+      if (icon || !(hs->roted | redraw))
+       goto skip2;
+
+      {
+       int lc;
+       const struct line_info *lip;
+       int mono;
+       Window win;
+
+       lc = LINE_COUNT;
+       lip = &line_table[0];
+       mono = mono_p;
+       win = hs->hs_window;
+
+       while (--lc >= 0)
+         {
+           int ip;
+           int iq;
+           int col;
+           struct point_state *sp;
+           struct point_state *sq;
+           int mov_p;
+           int mov_q;
+           GC erase_gc;
+           GC draw_gc;
+           int p_x;
+           int p_y;
+           int q_x;
+           int q_y;
+
+           ip = lip->li_ip;
+           iq = lip->li_iq;
+           col = lip->li_color;
+           lip++;
+           mov_p = moved[ip];
+           mov_q = moved[iq];
+           if (!(redraw | mov_p | mov_q))
+             continue;
+
+           sp = &hs->hs_points[ip];
+           sq = &hs->hs_points[iq];
+
+           if (mono)
+             {
+               erase_gc = hs->hs_color_gcs[0];
+               draw_gc = hs->hs_color_gcs[1];
+             }
+           else
+             {
+               erase_gc = hs->black_gc;
+               draw_gc = hs->hs_color_gcs[col];
+             }
+
+           if (!redraw)
+             {
+               p_x = sp->old_x;
+               p_y = sp->old_y;
+               q_x = sq->old_x;
+               q_y = sq->old_y;
+               XDrawLine (dpy, win, erase_gc, p_x, p_y, q_x, q_y);
+             }
+
+           p_x = sp->new_x;
+           p_y = sp->new_y;
+           q_x = sq->new_x;
+           q_y = sq->new_y;
+           XDrawLine (dpy, win, draw_gc, p_x, p_y, q_x, q_y);
+         }
+      }
+
+    skip2:
+      stop = hs->hs_stop;
+      hs->roted = 0;
+      if (stop)
+       goto skip3;
+
+      hs->roted = 1;
+
+      {
+       double cos_a;
+       double sin_a;
+       double old_u;
+       double old_v;
+       double new_u;
+       double new_v;
+
+ /* If you get error messages about the following forms, and you think you're
+    using an ANSI C conforming compiler, then you're mistaken.  Possibly you're
+    mixing an ANSI compiler with a non-ANSI preprocessor, or vice versa.
+    Regardless, your system is broken; it's not a bug in this program.
+  */
+#if defined(__STDC__) || defined(__ANSI_CPP__)
+
+#define rotate(name,dim0,dim1) \
+  old_u = hs->hs_ref_##name##dim0; \
+  old_v = hs->hs_ref_##name##dim1; \
+  new_u = old_u * cos_a + old_v * sin_a; \
+  new_v = old_v * cos_a - old_u * sin_a; \
+  hs->hs_ref_##name##dim0 = new_u; \
+  hs->hs_ref_##name##dim1 = new_v;
+
+#define rotates(dim0,dim1) \
+  if (hs->hs_sin_##dim0##dim1 != 0) { \
+    cos_a = hs->hs_cos_##dim0##dim1; \
+    sin_a = hs->hs_sin_##dim0##dim1; \
+    rotate(a,dim0,dim1); \
+    rotate(b,dim0,dim1); \
+    rotate(c,dim0,dim1); \
+    rotate(d,dim0,dim1); \
+  }
+
+#else /* !__STDC__, courtesy of Andreas Luik <luik@isa.de> */
+
+#define rotate(name,dim0,dim1) \
+  old_u = hs->hs_ref_/**/name/**/dim0; \
+  old_v = hs->hs_ref_/**/name/**/dim1; \
+  new_u = old_u * cos_a + old_v * sin_a; \
+  new_v = old_v * cos_a - old_u * sin_a; \
+  hs->hs_ref_/**/name/**/dim0 = new_u; \
+  hs->hs_ref_/**/name/**/dim1 = new_v;
+
+#define rotates(dim0,dim1) \
+  if (hs->hs_sin_/**/dim0/**/dim1 != 0) { \
+    cos_a = hs->hs_cos_/**/dim0/**/dim1; \
+    sin_a = hs->hs_sin_/**/dim0/**/dim1; \
+    rotate(a,dim0,dim1); \
+    rotate(b,dim0,dim1); \
+    rotate(c,dim0,dim1); \
+    rotate(d,dim0,dim1); \
+  }
+
+#endif /* !__STDC__ */
+
+       rotates (x,y);
+       rotates (x,z);
+       rotates (y,z);
+       rotates (x,w);
+       rotates (y,w);
+       rotates (z,w);
+      }
+
+    skip3:
+      /* stop = hs->hs_stop; */
+      if (stop && this_delay < 10000)
+       this_delay = 10000;
     }
+  return this_delay;
+}
+
 
-  hyper (xy, xz, yz, xw, yw, zw);
+static Bool
+hypercube_event (Display *dpy, Window window, void *closure, XEvent *e)
+{
+  struct hyper_state *hs = (struct hyper_state *) closure;
+  if (e->type == ButtonPress && e->xbutton.button == 2)
+    {
+      hs->hs_stop = !hs->hs_stop;
+      return True;
+    }
+  return False;
+}
+
+static void
+hypercube_reshape (Display *dpy, Window window, void *closure,
+                   unsigned int w, unsigned int h)
+{
+  struct hyper_state *hs = (struct hyper_state *) closure;
+  set_sizes (hs, w, h);
+  XClearWindow (dpy, window);
+}
+
+
+static void
+set_sizes (struct hyper_state *hs, int width, int height)
+{
+  double observer_z;
+  int min_dim;
+  double var;
+  double offset_x;
+  double offset_y;
+  double unit_scale;
+
+  observer_z = 0.5 * hs->hs_two_observer_z;
+  min_dim = width < height ? width : height;
+  var = sqrt(observer_z * observer_z - 1.0);
+  offset_x = 0.5 * (double)(width - 1);
+  offset_y = 0.5 * (double)(height - 1);
+  unit_scale = 0.4 * min_dim * var;
+  hs->hs_offset_x = (float)offset_x;
+  hs->hs_offset_y = (float)offset_y;
+  hs->hs_unit_scale = (float)unit_scale;
 }
+
+
+/* data */
+
+static const struct line_info line_table[LINE_COUNT] =
+{
+    { 0, 1, 0, },
+    { 0, 2, 0, },
+    { 1, 3, 0, },
+    { 2, 3, 0, },
+    { 4, 5, 1, },
+    { 4, 6, 1, },
+    { 5, 7, 1, },
+    { 6, 7, 1, },
+    { 0, 4, 4, },
+    { 0, 8, 4, },
+    { 4, 12, 4, },
+    { 8, 12, 4, },
+    { 1, 5, 5, },
+    { 1, 9, 5, },
+    { 5, 13, 5, },
+    { 9, 13, 5, },
+    { 2, 6, 6, },
+    { 2, 10, 6, },
+    { 6, 14, 6, },
+    { 10, 14, 6, },
+    { 3, 7, 7, },
+    { 3, 11, 7, },
+    { 7, 15, 7, },
+    { 11, 15, 7, },
+    { 8, 9, 2, },
+    { 8, 10, 2, },
+    { 9, 11, 2, },
+    { 10, 11, 2, },
+    { 12, 13, 3, },
+    { 12, 14, 3, },
+    { 13, 15, 3, },
+    { 14, 15, 3, },
+};
+
+static void
+hypercube_free (Display *dpy, Window window, void *closure)
+{
+}
+
+XSCREENSAVER_MODULE ("HyperCube", hypercube)