From http://www.jwz.org/xscreensaver/xscreensaver-5.40.tar.gz
[xscreensaver] / hacks / glx / dnalogo.c
index 2d3bbb2c8df383e8ffc3370d6901cff20c82afb7..2b24f8311c74b8060377bdab84e6ac8b49f76998 100644 (file)
@@ -1,4 +1,4 @@
-/* DNA Logo, Copyright (c) 2001-2015 Jamie Zawinski <jwz@jwz.org>
+/* DNA Logo, Copyright (c) 2001-2018 Jamie Zawinski <jwz@jwz.org>
  *
  *      DNA Lounge
  *
@@ -8,7 +8,7 @@
  *      San Francisco, CA
  *      94103
  *
- *      http://www.dnalounge.com/
+ *      https://www.dnalounge.com/
  *      http://www.dnapizza.com/
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
                        "*wallFacets:       360     \n" \
                        "*barFacets:        90      \n" \
                        "*clockwise:        False   \n" \
-                       "*turns:            0.69    \n" \
-                       "*turnSpacing:      2.2     \n" \
-                       "*barSpacing:       0.2   \n" \
-                       "*wallHeight:       0.45    \n" \
+                       "*turns:            0.72    \n" \
+                       "*turnSpacing:      2.3     \n" \
+                       "*barSpacing:       0.268   \n" \
+                       "*wallHeight:       0.42    \n" \
                        "*wallThickness:    0.12    \n" \
                        "*barThickness:     0.058   \n" \
                        "*wallTaper:        0.95    \n" \
-                       "*gasketSize:       1.88    \n" \
+                       "*gasketSize:       2.0     \n" \
                        "*gasketDepth:      0.15    \n" \
                        "*gasketThickness:  0.4     \n" \
-                       "*frameSize:        1.20    \n" \
+                       "*frameSize:        1.28    \n" \
                        "*frameDepth:       0.01    \n" \
                        "*frameThickness:   0.03    \n" \
                        "*triangleSize:     0.045   \n" \
                        "*cwFont:           " CWFONT "\n" \
                        "*geometry:         =640x640\n" \
 
-# if defined(HAVE_COCOA)
+# if defined(HAVE_COCOA) || defined(HAVE_ANDROID)
 #  define CWFONT "Yearling 28, OCR A Std 24"
 # else
 #  define CWFONT "-*-helvetica-medium-r-normal-*-*-240-*-*-*-*-*-*"
 # endif
 
-# define refresh_logo 0
+# define free_logo 0
 # define release_logo 0
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
-#undef LINEAR
 #undef DXF_OUTPUT_HACK
 
 #ifdef DXF_OUTPUT_HACK   /* When this is defined, instead of rendering
@@ -108,14 +107,18 @@ typedef enum {
   HELIX_IN, HELIX, HELIX_OUT,
   PIZZA_IN, PIZZA, PIZZA_OUT,
   HELIX_AND_PIZZA,
+# ifdef CW
   CODEWORD_IN, CODEWORD, CODEWORD_OUT, CODEWORD_BLANK
+# endif
 } glyph_mode;
 
 typedef struct {
   Bool spinning_p;
-  GLfloat position;     /* 0.0 - 1.0 */
-  GLfloat speed;        /* how far along the path (may be negative) */
-  GLfloat probability;  /* relative likelyhood to start spinning */
+  GLfloat position;            /* 0.0 - 1.0 */
+  GLfloat position_eased;      /* 0.0 - 1.0, eased in and out */
+  GLfloat easement;            /* portion of path that is eased. <= 0.5 */
+  GLfloat speed;               /* how far along the path (may be negative) */
+  GLfloat probability;         /* relative likelyhood to start spinning */
 } spinner;
 
 typedef struct {
@@ -149,6 +152,7 @@ typedef struct {
   GLfloat frame_thickness;
   GLfloat triangle_size;
 
+# ifdef CW
   int codeword_facets, codeword_disc_facets;
   GLfloat codeword_spread, codeword_line_width, codeword_thickness;
   GLfloat codeword_cap_size;
@@ -161,6 +165,12 @@ typedef struct {
   XYZ *codeword_guides;
   GLfloat codeword_color[4], codeword_bg[4];
   texture_font_data *font;
+# endif
+
+# ifdef DEBUG
+  GLfloat persp_off, pos_off;
+  texture_font_data *label_font;
+# endif
 
   GLfloat speed;
   glyph_mode mode;
@@ -169,7 +179,9 @@ typedef struct {
 
   spinner gasket_spinnerx, gasket_spinnery, gasket_spinnerz;
   spinner scene_spinnerx,  scene_spinnery;     /* for DNA */
+# ifdef CW
   rotator *scene_rot;                          /* for Codeword */
+# endif
   spinner helix_spinnerz;
   spinner pizza_spinnery, pizza_spinnerz;
   spinner frame_spinner;
@@ -189,9 +201,11 @@ static XrmOptionDescRec opts[] = {
   { "-pizza",    ".mode",   XrmoptionNoArg,  "pizza"    },
   { "-helix",    ".mode",   XrmoptionNoArg,  "helix"    },
   { "-both",     ".mode",   XrmoptionNoArg,  "both"     },
+# ifdef CW
   { "-codeword", ".mode",   XrmoptionNoArg,  "codeword" },
   { "-cw",       ".mode",   XrmoptionNoArg,  "codeword" },
   { "-text",     ".text",   XrmoptionSepArg, 0          },
+# endif
 };
 
 ENTRYPOINT ModeSpecOpt logo_opts = {countof(opts), opts, 0, NULL, NULL};
@@ -500,6 +514,9 @@ vector_angle (double ax, double ay, double az,
   return (angle);
 }
 
+
+# ifdef CW
+
 static void
 normalize (XYZ *p)
 {
@@ -523,6 +540,8 @@ dot (const XYZ u, const XYZ v)
   return (u.x * v.x) + (u.y * v.y) + (u.z * v.z);
 }
 
+#endif /* CW */
+
 \f
 /* Make the helix
  */
@@ -546,7 +565,7 @@ make_helix (logo_configuration *dc, int facetted, int wire)
   th  = 0;
   x1  = 1;
   y1  = 0;
-  x1b = 1 - dc->wall_thickness;
+  x1b = 1;
   y1b = 0;
 
   z1 = -(dc->turn_spacing * dc->turns / 2);
@@ -577,13 +596,13 @@ make_helix (logo_configuration *dc, int facetted, int wire)
 
   while (th + th_inc <= max_th)
     {
+      GLfloat thick = dc->wall_thickness;
+
       th += th_inc;
 
       x2 = cos (th);
       y2 = sin (th);
       z2 = z1 + z_inc;
-      x2b = x2 * (1 - dc->wall_thickness);
-      y2b = y2 * (1 - dc->wall_thickness);
 
       h2 = h1;
       h2off = h1off;
@@ -599,6 +618,11 @@ make_helix (logo_configuration *dc, int facetted, int wire)
                 h2off = h2 - dc->wall_height/2;
               else
                 h2off = dc->wall_height/2 - h2;
+
+              if (th + th_inc <= 0)
+                thick = 0;
+              else
+              thick *= cos (M_PI / 2 * (1 - (th / dc->wall_taper)));
             }
           else if (th >= max_th - dc->wall_taper)
             {
@@ -612,9 +636,17 @@ make_helix (logo_configuration *dc, int facetted, int wire)
                 h2off = dc->wall_height/2 - h2;
               else
                 h2off = h2 - dc->wall_height/2;
+
+              if (th + th_inc > max_th)
+                thick = 0;
+              else
+                thick *= cos(M_PI / 2 * (1 - ((max_th - th)/dc->wall_taper)));
             }
         }
 
+      x2b = x2 * (1 - thick);
+      y2b = y2 * (1 - thick);
+
       /* outer face
        */
       glFrontFace(GL_CW);
@@ -728,6 +760,11 @@ make_ladder (logo_configuration *dc, int facetted, int wire)
   th = (max_th * pad_ratio/2);
   z  = -(max_z / 2) + (max_z * pad_ratio/2);
 
+  /* ##### WHYYYYYY */
+  /* The image is not reflected across line y = -x and I don't know why. */
+  th += M_PI * -0.035;
+  z -= 0.08;
+
   if (!dc->clockwise)
     z = -z, z_inc = -z_inc;
 
@@ -1519,7 +1556,6 @@ make_pizza (logo_configuration *dc, int facetted, int wire)
   GLfloat th, x, y, s;
   int i, j, k;
   int endpoints;
-  int endedge1;
 
 # ifdef HAVE_TESS
   tess_out TO, *to = &TO;
@@ -1571,7 +1607,6 @@ make_pizza (logo_configuration *dc, int facetted, int wire)
         points[j++] = edge[i*2];
         points[j++] = 0;
       }
-    endedge1 = i;
   }
 
   s = 0.798;  /* radius of end of slice, before crust gap */
@@ -1759,21 +1794,39 @@ make_pizza (logo_configuration *dc, int facetted, int wire)
 # else  /* !HAVE_TESS */
   if (! wire)
     {
+      glTranslatef(0, 0, thick2);
+      glNormal3f (0, 0, 1);
+      glFrontFace (GL_CW);
+
+      /* Sadly, jwzgl's glVertexPointer seems not to be recordable inside
+         display lists. */
+#  if 0
       glDisableClientState (GL_COLOR_ARRAY);
       glDisableClientState (GL_NORMAL_ARRAY);
       glDisableClientState (GL_TEXTURE_COORD_ARRAY);
       glEnableClientState (GL_VERTEX_ARRAY);
       glVertexPointer (3, GL_FLOAT, 0, dnapizza_triangles);
-
-      glTranslatef(0, 0, thick2);
-      glNormal3f (0, 0, 1);
-      glFrontFace (GL_CW);
       glDrawArrays (GL_TRIANGLES, 0, countof (dnapizza_triangles) / 3);
+#  else
+      glBegin (GL_TRIANGLES);
+      for (i = 0; i < countof (dnapizza_triangles); i += 3)
+        glVertex3fv (dnapizza_triangles + i);
+      glEnd();
+#  endif
 
       glTranslatef(0, 0, -thick2*2);
       glNormal3f (0, 0, -1);
       glFrontFace (GL_CCW);
+
+#  if 0
       glDrawArrays (GL_TRIANGLES, 0, countof (dnapizza_triangles) / 3);
+#  else
+      int i;
+      glBegin (GL_TRIANGLES);
+      for (i = 0; i < countof (dnapizza_triangles); i += 3)
+        glVertex3fv (dnapizza_triangles + i);
+      glEnd();
+#  endif
 
       glTranslatef(0, 0, thick2);
     }
@@ -1899,6 +1952,8 @@ make_pizza (logo_configuration *dc, int facetted, int wire)
 }
 
 
+# ifdef CW
+
 /* Upcase string, convert Unicrud to ASCII, remove any non-letters.
  */
 static char *
@@ -1935,7 +1990,7 @@ make_codeword_path (ModeInfo *mi)
 
   int dial = 0;
   int letter;
-  GLfloat last_r;
+  GLfloat last_r = 0;
 
   GLfloat inner_circum = M_PI * 2 * (iradius + rtick * 2);
   GLfloat outer_circum = M_PI * 2 * (iradius + rtick * (letters + 1));
@@ -2328,7 +2383,7 @@ codeword_text_output (ModeInfo *mi, GLfloat anim_ratio)
           buf[1] = 0;
           texture_string_metrics (dc->font, buf, &e, &ascent, &descent);
 
-# ifdef USE_IPHONE
+# ifdef HAVE_MOBILE
           /* #### Magic magic magic WTF... */
           glScalef (0.5, 0.5, 0.5);
 # endif
@@ -2497,7 +2552,7 @@ draw_codeword_path (ModeInfo *mi)
   glColor4fv (dc->codeword_color);
   glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, dc->codeword_color);
 
-# ifdef USE_IPHONE  /* Make the whole thing fit on the phone screen */
+# ifdef HAVE_MOBILE  /* Make the whole thing fit on the phone screen */
   {
     GLfloat size = MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi);
     glScalef (0.9, 0.9, 0.9);
@@ -2643,7 +2698,7 @@ draw_codeword_path (ModeInfo *mi)
   /* Draw the start and end caps */
   {
     int i;
-    GLfloat x, y, z, x2, y2, z2, X, Y, Z, L;
+    GLfloat x, y, z, x2, y2, z2, X, Y, Z;
     GLfloat r = dc->codeword_spread * dc->codeword_cap_size;
 
     i = 0;
@@ -2676,7 +2731,6 @@ draw_codeword_path (ModeInfo *mi)
     X = (x2 - x);
     Y = (y2 - y);
     Z = (z2 - z);
-    L = sqrt (X*X + Y*Y + Z*Z);
 
     glPushMatrix();
     glTranslatef (x, y, z);
@@ -2697,26 +2751,43 @@ draw_codeword_path (ModeInfo *mi)
   return polys;
 }
 
+#endif /* CW */
+
 
-\f
-/* Window management, etc
- */
 ENTRYPOINT void
 reshape_logo (ModeInfo *mi, int width, int height)
 {
+# ifdef DEBUG
+  logo_configuration *dc = &dcs[MI_SCREEN(mi)];
+# endif
   GLfloat h = (GLfloat) height / (GLfloat) width;
+  GLfloat persp = 64;  /* 30 */
+  GLfloat pos   = 13;  /* 30 */
+
+# ifdef DEBUG
+  persp += dc->persp_off;
+  pos += dc->pos_off;
+# endif
 
   glViewport (0, 0, (GLint) width, (GLint) height);
 
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
-  gluPerspective (30.0, 1/h, 1.0, 100.0);
+  gluPerspective (persp, 1/h, 1, 100);
 
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
-  gluLookAt( 0.0, 0.0, 30.0,
-             0.0, 0.0, 0.0,
-             0.0, 1.0, 0.0);
+  gluLookAt( 0, 0, pos,
+             0, 0, 0,
+             0, 1, 0);
+
+# ifdef HAVE_MOBILE    /* Keep it the same relative size when rotated. */
+  {
+    int o = (int) current_device_rotation();
+    if (o != 0 && o != 180 && o != -180)
+      glScalef (1/h, 1/h, 1/h);  /* #### Why does this change the lighting? */
+  }
+# endif
 
   glClear(GL_COLOR_BUFFER_BIT);
 }
@@ -2766,14 +2837,7 @@ init_logo (ModeInfo *mi)
       exit (1);
     }
 
-  if (!dcs) {
-    dcs = (logo_configuration *)
-      calloc (MI_NUM_SCREENS(mi), sizeof (logo_configuration));
-    if (!dcs) {
-      fprintf(stderr, "%s: out of memory\n", progname);
-      exit(1);
-    }
-  }
+  MI_INIT (mi, dcs);
 
   dc = &dcs[MI_SCREEN(mi)];
 
@@ -2803,6 +2867,7 @@ init_logo (ModeInfo *mi)
   dc->triangle_size   = get_float_resource(mi->dpy, "triangleSize",   "Float");
 
   dc->speed           = get_float_resource(mi->dpy, "speed",          "Float");
+# ifdef CW
   dc->codeword_text   = get_string_resource(mi->dpy, "text",         "String");
   dc->codeword_text   = codeword_simplify_text (dc->codeword_text);
   dc->codeword_text_out =
@@ -2818,6 +2883,7 @@ init_logo (ModeInfo *mi)
   dc->codeword_line_width = get_float_resource(mi->dpy, "cwLineWidth", "Float");
   dc->codeword_thickness  = get_float_resource(mi->dpy, "cwThickness", "Float");
   dc->codeword_cap_size = get_float_resource(mi->dpy, "cwCapSize",     "Float");
+# endif
 
   {
     char *s = get_string_resource (MI_DISPLAY (mi), "mode", "String");
@@ -2827,12 +2893,14 @@ init_logo (ModeInfo *mi)
       dc->mode = PIZZA;
     else if (!strcasecmp (s, "both"))
       dc->mode = HELIX_AND_PIZZA;
+# ifdef CW
     else if (!strcasecmp (s, "codeword"))
       dc->mode = CODEWORD_IN;
+# endif
     else
       {
         fprintf (stderr,
-               "%s: mode must be helix, pizza, both or codeword, not \"%s\"\n", 
+               "%s: mode must be helix, pizza or both, not \"%s\"\n", 
                  progname, s);
         exit (1);
       }
@@ -2844,8 +2912,14 @@ init_logo (ModeInfo *mi)
     dc->anim_ratio = 0;
   }
 
+# ifdef CW
   if (dc->mode == CODEWORD_IN)
     dc->font = load_texture_font (MI_DISPLAY(mi), "cwFont");
+# endif
+
+# ifdef DEBUG
+    dc->label_font = load_texture_font (MI_DISPLAY(mi), "fpsFont");
+# endif
 
   {
     XColor xcolor;
@@ -2883,6 +2957,7 @@ init_logo (ModeInfo *mi)
         exit (1);
       }
 
+# ifdef CW
     dc->codeword_color[0] = xcolor.red   / 65535.0;
     dc->codeword_color[1] = xcolor.green / 65535.0;
     dc->codeword_color[2] = xcolor.blue  / 65535.0;
@@ -2905,6 +2980,7 @@ init_logo (ModeInfo *mi)
     dc->codeword_bg[1] = xcolor.green / 65535.0;
     dc->codeword_bg[2] = xcolor.blue  / 65535.0;
     dc->codeword_bg[3] = 1.0;
+# endif /* CW */
   }
 
   dc->trackball = gltrackball_init (False);
@@ -2912,22 +2988,33 @@ init_logo (ModeInfo *mi)
   dc->gasket_spinnerx.probability = 0.1;
   dc->gasket_spinnery.probability = 0.1;
   dc->gasket_spinnerz.probability = 1.0;
+  dc->gasket_spinnerx.easement    = 0.08;
+  dc->gasket_spinnery.easement    = 0.08;
+  dc->gasket_spinnerz.easement    = 0.08;
 
   dc->helix_spinnerz.probability  = 0.6;
+  dc->helix_spinnerz.easement     = 0.2;
 
   dc->pizza_spinnerz.probability  = 0.6;
   dc->pizza_spinnery.probability  = 0.6;
+  dc->pizza_spinnerz.easement     = 0.2;
+  dc->pizza_spinnery.easement     = 0.2;
 
   dc->frame_spinner.probability   = 5.0;
+  dc->frame_spinner.easement      = 0.2;
 
   dc->scene_spinnerx.probability  = 0.1;
   dc->scene_spinnery.probability  = 0.0;
+  dc->scene_spinnerx.easement     = 0.1;
+  dc->scene_spinnery.easement     = 0.1;
 
+# ifdef CW
   if (dc->mode == CODEWORD_IN)
     {
       double tilt_speed = 0.003;
       dc->scene_rot = make_rotator (0, 0, 0, 0, tilt_speed, True);
     }
+# endif
 
   /* start the frame off-screen */
   dc->frame_spinner.spinning_p = True;
@@ -3050,8 +3137,9 @@ init_logo (ModeInfo *mi)
   if (do_frame) dc->polys[6] += make_frame (dc, 1);
   glEndList ();
 
+# ifdef CW
   make_codeword_path (mi);
-
+# endif
 
   /* When drawing both solid and wireframe objects,
      make sure the wireframe actually shows up! */
@@ -3074,6 +3162,22 @@ logo_handle_event (ModeInfo *mi, XEvent *event)
       KeySym keysym;
       char c = 0;
       XLookupString (&event->xkey, &c, 1, &keysym, 0);
+
+# ifdef DEBUG
+      {
+        GLfloat step = 0.1;
+        if      (c == 'a') dc->persp_off += step;
+        else if (c == 'z') dc->persp_off -= step;
+        else if (c == 's') dc->pos_off   += step;
+        else if (c == 'x') dc->pos_off   -= step;
+        else return False;
+
+        /* dc->pos_off = -dc->persp_off; */
+        reshape_logo (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+        return True;
+      }
+# endif
+
       if (c == ' ' || c == '\t')
         {
           switch (dc->anim_state) {
@@ -3085,10 +3189,12 @@ logo_handle_event (ModeInfo *mi, XEvent *event)
             dc->anim_state = PIZZA_OUT;
             dc->anim_ratio = 0.0;
             return True;
+# ifdef CW
           case CODEWORD:
             dc->anim_state = CODEWORD_OUT;
             dc->anim_ratio = 0.0;
             return True;
+# endif
           default:
             break;
           }
@@ -3099,6 +3205,14 @@ logo_handle_event (ModeInfo *mi, XEvent *event)
 }
 
 
+static GLfloat
+spinner_ease (GLfloat x)
+{
+  /* Smooth curve up, ending at slope = 1. */
+  return cos ((x/2 + 1) * M_PI) + 1;
+}
+
+
 static void
 tick_spinner (ModeInfo *mi, spinner *s)
 {
@@ -3110,12 +3224,20 @@ tick_spinner (ModeInfo *mi, spinner *s)
   if (s->spinning_p)
     {
       s->position += s->speed;
-      if (s->position >=  1.0 || s->position <= -1.0)
-          
+      if (s->position >=  1.0 || s->position <= 0.0)
         {
           s->position = 0;
+          s->position_eased = 0;
           s->spinning_p = False;
         }
+      else if (s->easement > 0 && s->position <= s->easement)
+        s->position_eased = (s->easement *
+                             spinner_ease (s->position / s->easement));
+      else if (s->easement > 0 && s->position >= 1-s->easement)
+        s->position_eased = (1 - s->easement *
+                             spinner_ease ((1 - s->position) / s->easement));
+      else
+        s->position_eased = s->position;
     }
   else if (s->probability &&
            (random() % (int) (PROBABILITY_SCALE / s->probability)) == 0)
@@ -3127,7 +3249,10 @@ tick_spinner (ModeInfo *mi, spinner *s)
         s->speed = dc->speed * (frand(ss/3) + frand(ss/3) + frand(ss/3));
       } while (s->speed <= 0);
       if (random() & 1)
-        s->speed = -s->speed;
+        {
+          s->speed = -s->speed;
+          s->position = 1.0;
+        }
     }
 }
 
@@ -3156,7 +3281,9 @@ draw_logo (ModeInfo *mi)
   GLfloat specular[]  = {0.8, 0.8, 0.8, 1.0};
   GLfloat shininess   = 50.0;
   Bool pizza_p;
+# ifdef CW
   Bool codeword_p;
+# endif
 
   if (!dc->glx_context)
     return;
@@ -3171,6 +3298,7 @@ draw_logo (ModeInfo *mi)
                         (random() % 200) +
                         (random() % 200));
       
+# ifndef DEBUG
   tick_spinner (mi, &dc->gasket_spinnerx);
   tick_spinner (mi, &dc->gasket_spinnery);
   tick_spinner (mi, &dc->gasket_spinnerz);
@@ -3181,28 +3309,7 @@ draw_logo (ModeInfo *mi)
   tick_spinner (mi, &dc->scene_spinnery);
   tick_spinner (mi, &dc->frame_spinner);
   link_spinners (mi, &dc->scene_spinnerx, &dc->scene_spinnery);
-
-# ifdef LINEAR
-  {
-    static double i = 0.0;
-    dc->anim_state = HELIX;
-    dc->wire_overlay = 0;
-    dc->gasket_spinnerx.spinning_p = 0;
-    dc->gasket_spinnery.spinning_p = 0;
-    dc->gasket_spinnerz.spinning_p = 0;
-    dc->helix_spinnerz.spinning_p = 0;
-    dc->pizza_spinnery.spinning_p = 0;
-    dc->pizza_spinnerz.spinning_p = 0;
-    dc->scene_spinnerx.spinning_p = 0;
-    dc->scene_spinnery.spinning_p = 0;
-    dc->frame_spinner.spinning_p = 0;
-    dc->frame_spinner.position = 0.3;
-    dc->gasket_spinnerz.position = i;
-    dc->helix_spinnerz.position = i;
-    i += 0.005;
-    if (i > 1) i = 0;
-  }
-# endif /* LINEAR */
+# endif /* DEBUG */
 
   switch (dc->anim_state)
     {
@@ -3255,6 +3362,7 @@ draw_logo (ModeInfo *mi)
       break;
 
 
+# ifdef CW
     case CODEWORD_IN:
       dc->scene_spinnerx.probability = 0.2;
       dc->scene_spinnery.probability = 0.05;
@@ -3268,7 +3376,7 @@ draw_logo (ModeInfo *mi)
       break;
 
     case CODEWORD:
-      dc->scene_spinnerx.probability = 2.5;
+      dc->scene_spinnerx.probability = 0.5;
       dc->scene_spinnery.probability = 0.2;
       if (! dc->button_down_p)
         dc->anim_ratio += (0.0005 + frand(0.002)) * dc->speed;
@@ -3302,20 +3410,28 @@ draw_logo (ModeInfo *mi)
           dc->anim_state = CODEWORD_IN;
         }
       break;
+# endif /* CW */
 
     default:
       abort();
       break;
     }
 
+# ifdef DEBUG
+  dc->anim_state = HELIX;
+  dc->wire_overlay = 0;
+# endif
+
   pizza_p = (dc->anim_state == PIZZA ||
              dc->anim_state == PIZZA_IN ||
              dc->anim_state == PIZZA_OUT);
 
+# ifdef CW
   codeword_p = (dc->anim_state == CODEWORD ||
                 dc->anim_state == CODEWORD_IN ||
                 dc->anim_state == CODEWORD_OUT ||
                 dc->anim_state == CODEWORD_BLANK);
+# endif
 
   glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -3323,20 +3439,19 @@ draw_logo (ModeInfo *mi)
   glRotatef(current_device_rotation(), 0, 0, 1);
   {
     GLfloat scale = 1.8;
-# ifdef LINEAR
-    scale = 3.85;
-# endif
     glScalef(scale, scale, scale);
 
     glColor3f(dc->color[0], dc->color[1], dc->color[2]);
 
 
     /* Draw frame before trackball rotation */
+# ifdef CW
     if (! codeword_p)
+# endif
       {
-        GLfloat p = (dc->frame_spinner.position >= 0
-                     ? dc->frame_spinner.position
-                     : -dc->frame_spinner.position);
+        GLfloat p = (dc->frame_spinner.position_eased >= 0
+                     ? dc->frame_spinner.position_eased
+                     : -dc->frame_spinner.position_eased);
         GLfloat size = (p > 0.5 ? 1-p : p);
         scale = 1 + (size * 10);
         glPushMatrix();
@@ -3373,22 +3488,18 @@ draw_logo (ModeInfo *mi)
     glRotatef(90, 1, 0, 0);
     glRotatef(90, 0, 0, 1);
 
-# ifdef LINEAR
-#  define SINIFY(I) (I)
-# else
-#  define SINIFY(I) sin (M_PI/2 * (I))
-# endif
-
+# ifdef CW
     if (! codeword_p)
+# endif
       {
-        glRotatef (360 * SINIFY (dc->scene_spinnerx.position), 0, 1, 0);
-        glRotatef (360 * SINIFY (dc->scene_spinnery.position), 0, 0, 1);
+        glRotatef (360 * dc->scene_spinnerx.position_eased, 0, 1, 0);
+        glRotatef (360 * dc->scene_spinnery.position_eased, 0, 0, 1);
 
         glPushMatrix();
 
-        glRotatef (360 * SINIFY (dc->gasket_spinnerx.position), 0, 1, 0);
-        glRotatef (360 * SINIFY (dc->gasket_spinnery.position), 0, 0, 1);
-        glRotatef (360 * SINIFY (dc->gasket_spinnerz.position), 1, 0, 0);
+        glRotatef (360 * dc->gasket_spinnerx.position_eased, 0, 1, 0);
+        glRotatef (360 * dc->gasket_spinnery.position_eased, 0, 0, 1);
+        glRotatef (360 * dc->gasket_spinnerz.position_eased, 1, 0, 0);
 
         memcpy (gcolor, dc->color, sizeof (dc->color));
         if (dc->wire_overlay != 0)
@@ -3426,12 +3537,12 @@ draw_logo (ModeInfo *mi)
 
         if (pizza_p)
           {
-            glRotatef (360 * SINIFY (dc->pizza_spinnery.position), 1, 0, 0);
-            glRotatef (360 * SINIFY (dc->pizza_spinnerz.position), 0, 0, 1);
+            glRotatef (360 * dc->pizza_spinnery.position_eased, 1, 0, 0);
+            glRotatef (360 * dc->pizza_spinnerz.position_eased, 0, 0, 1);
           }
         else
           {
-            glRotatef (360 * SINIFY (dc->helix_spinnerz.position), 0, 0, 1);
+            glRotatef (360 * dc->helix_spinnerz.position_eased, 0, 0, 1);
           }
 
         scale = ((dc->anim_state == PIZZA_IN || dc->anim_state == HELIX_IN)
@@ -3478,19 +3589,20 @@ draw_logo (ModeInfo *mi)
             mi->polygon_count += dc->polys[0];
           }
       }
+# ifdef CW
     else       /* codeword_p */
       {
-# if 0
+#  if 0
         double max = 70;  /* face front */
         double x, y, z;
         get_position (dc->scene_rot, &x, &y, &z, !dc->button_down_p);
         glRotatef (max/2 - x*max, 0, 0, 1);
         glRotatef (max/2 - y*max, 0, 1, 0);
         /* glRotatef (max/2 - z*max, 1, 0, 0); */
-# else
-        glRotatef (360 * SINIFY (dc->scene_spinnerx.position), 0, 1, 0);
-        glRotatef (360 * SINIFY (dc->scene_spinnery.position), 0, 0, 1);
-# endif
+#  else
+        glRotatef (360 * dc->scene_spinnerx.position_eased, 0, 1, 0);
+        glRotatef (360 * dc->scene_spinnery.position_eased, 0, 0, 1);
+#  endif
 
         glClearColor (dc->codeword_bg[0],
                       dc->codeword_bg[1],
@@ -3498,12 +3610,24 @@ draw_logo (ModeInfo *mi)
                       dc->codeword_bg[3]);
         mi->polygon_count += draw_codeword_path (mi);
       }
+# endif /* CW */
   }
   glPopMatrix();
 
   if (dc->wire_overlay > 0)
     dc->wire_overlay--;
 
+# ifdef DEBUG
+  {
+    char s[1024];
+    sprintf (s, "a/z, s/x; per = %0.2f pos = %0.2f",
+             dc->persp_off, dc->pos_off);
+    glColor3f (1,1,1);
+    print_texture_label (dpy, dc->label_font, MI_WIDTH(mi), MI_HEIGHT(mi),
+                         1, s);
+  }
+# endif
+
   if (mi->fps_p) do_fps (mi);
   glFinish();