From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / crackberg.c
index c4e925c73670fdcc389bce8954db781cad9f0004..dcbe481bfa9b47502d36eb2a25784e2d4711f8e6 100644 (file)
@@ -1,7 +1,7 @@
 /***************************
  ** crackberg; Matus Telgarsky [ catachresis@cmu.edu ] 2005 
  ** */
-#ifndef HAVE_COCOA
+#ifndef HAVE_JWXYZ
 # define XK_MISCELLANY
 # include <X11/keysymdef.h>
 #endif
@@ -11,6 +11,7 @@
                    "*wireframe:    False       \n" \
 
 # define refresh_crackberg 0
+# define release_crackberg 0
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
@@ -131,6 +132,10 @@ struct _cberg_state {
 
     double vs0r,vs0g,vs0b, vs1r, vs1g, vs1b,
            vf0r,vf0g,vf0b, vf1r, vf1g, vf1b;
+
+    Bool button_down_p;
+    int mouse_x, mouse_y;
+    struct timeval paused;
 };
 
 
@@ -1162,23 +1167,19 @@ static inline double drunken_rando(double cur_val, double max, double width)
  ** */
 
 ENTRYPOINT void reshape_crackberg (ModeInfo *mi, int w, int h);
+static void free_crackberg (ModeInfo *mi);
 
 ENTRYPOINT void init_crackberg (ModeInfo *mi)
 {
     cberg_state *cberg;
 
-    if (!cbergs) {
-        nsubdivs %= 16; /* just in case.. */
+    nsubdivs %= 16; /* just in case.. */
 
-        if ( !(cbergs = calloc(MI_NUM_SCREENS(mi), sizeof(cberg_state)))) {
-            perror(progname);
-            exit(1);
-        }
+    MI_INIT(mi, cbergs, free_crackberg);
 
-        if (visibility > 1.0 || visibility < 0.2) {
-            printf("visibility must be in range [0.2 .. 1.0]\n");
-            visibility = 1.0;
-        }
+    if (visibility > 1.0 || visibility < 0.2) {
+        printf("visibility must be in range [0.2 .. 1.0]\n");
+        visibility = 1.0;
     }
 
     cberg = &cbergs[MI_SCREEN(mi)];
@@ -1207,7 +1208,9 @@ ENTRYPOINT void init_crackberg (ModeInfo *mi)
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
     glShadeModel((flat) ? GL_FLAT : GL_SMOOTH);
+# ifndef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
     glPolygonMode(GL_FRONT_AND_BACK, (MI_IS_WIREFRAME(mi)) ? GL_LINE : GL_FILL);
+# endif
 
     if (lit) {
         glEnable(GL_LIGHTING);
@@ -1254,7 +1257,9 @@ ENTRYPOINT Bool crackberg_handle_event (ModeInfo *mi, XEvent *ev)
     if (ev->xany.type == KeyPress) {
         switch (keysym) {
             case XK_Left:   cberg->motion_state |= MOTION_LROT;  break;
+            case XK_Prior:  cberg->motion_state |= MOTION_LROT;  break;
             case XK_Right:  cberg->motion_state |= MOTION_RROT;  break;
+            case XK_Next:   cberg->motion_state |= MOTION_RROT;  break;
             case XK_Down:   cberg->motion_state |= MOTION_BACK;  break;
             case XK_Up:     cberg->motion_state |= MOTION_FORW;  break;
             case '1':       cberg->motion_state |= MOTION_DEC;   break; 
@@ -1282,7 +1287,9 @@ ENTRYPOINT Bool crackberg_handle_event (ModeInfo *mi, XEvent *ev)
 
         switch (keysym) {
             case XK_Left:   cberg->motion_state &= ~MOTION_LROT;  break;
+            case XK_Prior:  cberg->motion_state &= ~MOTION_LROT;  break;
             case XK_Right:  cberg->motion_state &= ~MOTION_RROT;  break;
+            case XK_Next:   cberg->motion_state &= ~MOTION_RROT;  break;
             case XK_Down:   cberg->motion_state &= ~MOTION_BACK;  break;
             case XK_Up:     cberg->motion_state &= ~MOTION_FORW;  break;
             case '1':       cberg->motion_state &= ~MOTION_DEC;   break; 
@@ -1297,6 +1304,51 @@ ENTRYPOINT Bool crackberg_handle_event (ModeInfo *mi, XEvent *ev)
                 break;
             default:            return False;
         }
+    } else if (ev->xany.type == ButtonPress &&
+               ev->xbutton.button == Button1) {
+      cberg->button_down_p = True;
+      cberg->mouse_x = ev->xbutton.x;
+      cberg->mouse_y = ev->xbutton.y;
+      cberg->motion_state = MOTION_MANUAL;
+      cberg->paused.tv_sec = 0;
+    } else if (ev->xany.type == ButtonRelease &&
+               ev->xbutton.button == Button1) {
+      cberg->button_down_p = False;
+      cberg->motion_state = MOTION_AUTO;
+      /* After mouse-up, don't go back into auto-motion mode for a second, so
+         that repeated click-and-drag gestures don't fight with auto-motion. */
+      gettimeofday(&cberg->paused, NULL);
+    } else if (ev->xany.type == MotionNotify &&
+               cberg->button_down_p) {
+      int dx = ev->xmotion.x - cberg->mouse_x;
+      int dy = ev->xmotion.y - cberg->mouse_y;
+      cberg->mouse_x = ev->xmotion.x;
+      cberg->mouse_y = ev->xmotion.y;
+      cberg->motion_state = MOTION_MANUAL;
+
+      /* Take the larger dimension, since motion_state doesn't scale */
+      if (dx > 0 && dx > dy) dy = 0;
+      if (dx < 0 && dx < dy) dy = 0;
+      if (dy > 0 && dy > dx) dx = 0;
+      if (dy < 0 && dy < dx) dx = 0;
+
+      {
+        int rot = current_device_rotation();
+        int swap;
+        while (rot <= -180) rot += 360;
+        while (rot >   180) rot -= 360;
+        if (rot > 135 || rot < -135)           /* 180 */
+            dx = -dx, dy = -dy;
+        else if (rot > 45)                     /* 90 */
+          swap = dx, dx = -dy, dy = swap;
+        else if (rot < -45)                    /* 270 */
+          swap = dx, dx = dy, dy = -swap;
+      }
+
+      if      (dx > 0) cberg->motion_state |= MOTION_LEFT;
+      else if (dx < 0) cberg->motion_state |= MOTION_RIGHT;
+      else if (dy > 0) cberg->motion_state |= MOTION_FORW;
+      else if (dy < 0) cberg->motion_state |= MOTION_BACK;
     } else
         return False;
     return True;
@@ -1320,7 +1372,8 @@ ENTRYPOINT void draw_crackberg (ModeInfo *mi)
 
         cberg->elapsed = cur_frame - cberg->prev_frame;
 
-        if (cberg->motion_state == MOTION_AUTO) {
+        if (cberg->motion_state == MOTION_AUTO &&
+            cberg->paused.tv_sec < cur_frame_t.tv_sec) {
             cberg->x += cberg->dx * cberg->elapsed;
             cberg->y += cberg->dy * cberg->elapsed;
             /* cberg->z */
@@ -1404,19 +1457,12 @@ ENTRYPOINT void draw_crackberg (ModeInfo *mi)
 }
 
 /* uh */
-ENTRYPOINT void release_crackberg (ModeInfo *mi)
+static void free_crackberg (ModeInfo *mi)
 {
-  if (cbergs) {
-    int screen;
-    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-      cberg_state *cberg = &cbergs[screen];
-      if (cberg->norms)
-        free(cberg->norms);
-      free(cberg->heights);
-    }
-    free (cbergs);
-    cbergs = 0;
-  }
+  cberg_state *cberg = &cbergs[MI_SCREEN(mi)];
+  if (cberg->norms)
+    free(cberg->norms);
+  free(cberg->heights);
 }
 
 XSCREENSAVER_MODULE ("Crackberg", crackberg)