http://slackware.bholcomb.com/slackware/slackware-11.0/source/xap/xscreensaver/xscree...
[xscreensaver] / hacks / glx / gears.c
index f97232bf4c624df34332a53ef32e3aa6a21a3890..bd0bb4e6092528a04d35a806a56d6a367e28e0fd 100644 (file)
@@ -1,9 +1,8 @@
 /* -*- Mode: C; tab-width: 4 -*- */
 /* gears --- 3D gear wheels */
 
-#if !defined( lint ) && !defined( SABER )
+#if 0
 static const char sccsid[] = "@(#)gears.c      4.07 97/11/24 xlockmore";
-
 #endif
 
 /*-
@@ -35,49 +34,46 @@ static const char sccsid[] = "@(#)gears.c   4.07 97/11/24 xlockmore";
  * been fixed in MesaGL 2.2 and later releases.
  */
 
-/*-
- * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
- * otherwise caddr_t is not defined correctly
- */
-
-#include <X11/Intrinsic.h>
-
 #ifdef STANDALONE
-# define PROGCLASS                                     "Gears"
-# define HACK_INIT                                     init_gears
-# define HACK_DRAW                                     draw_gears
-# define HACK_RESHAPE                          reshape_gears
-# define gears_opts                                    xlockmore_opts
-# define DEFAULTS      "*count:                1       \n"                     \
+# define DEFAULTS      "*count:                1000000 \n"                     \
                                        "*cycles:               2       \n"                     \
                                        "*delay:                20000   \n"                     \
-                                       "*planetary:    False   \n"                     \
                                        "*showFPS:      False   \n"                     \
                                        "*wireframe:    False   \n"
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
+# define refresh_gears 0
 #else  /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
 #endif /* !STANDALONE */
 
 #ifdef USE_GL
 
+#include "rotator.h"
+#include "gltrackball.h"
+
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
-#define DEF_PLANETARY "False"
+#define DEF_MODE "random"
+#define DEF_SPIN "True"
 
-static int planetary;
+static char *mode_str;
+static int spin;
 
 static XrmOptionDescRec opts[] = {
-  {"-planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "true" },
-  {"+planetary", ".gears.planetary", XrmoptionNoArg, (caddr_t) "false" },
+  {"-mode",      ".gears.mode", XrmoptionSepArg, 0 },
+  {"-planetary", ".gears.mode", XrmoptionNoArg, "planetary" },
+  {"-simple",    ".gears.mode", XrmoptionNoArg, "simple" },
+  {"-spin", ".gears.spin", XrmoptionNoArg, "true" },
+  {"+spin", ".gears.spin", XrmoptionNoArg, "false" },
 };
 
 static argtype vars[] = {
-  {(caddr_t *) &planetary, "planetary", "Planetary", DEF_PLANETARY, t_Bool},
+  {&mode_str, "mode", "Mode", DEF_MODE, t_String},
+  {&spin, "spin", "Spin", DEF_SPIN, t_Bool},
 };
 
-ModeSpecOpt gears_opts = {countof(opts), opts, countof(vars), vars, NULL};
+ENTRYPOINT ModeSpecOpt gears_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
 #ifdef USE_MODULES
 ModStruct   gears_description =
@@ -88,19 +84,26 @@ ModStruct   gears_description =
 
 #endif
 
-typedef struct {
+#define SMOOTH_TUBE       /* whether to have smooth or faceted tubes */
 
-  GLfloat rotx, roty, rotz;       /* current object rotation */
-  GLfloat dx, dy, dz;             /* current rotational velocity */
-  GLfloat ddx, ddy, ddz;          /* current rotational acceleration */
-  GLfloat d_max;                          /* max velocity */
+#ifdef SMOOTH_TUBE
+# define TUBE_FACES  20   /* how densely to render tubes */
+#else
+# define TUBE_FACES  6
+#endif
 
+
+typedef struct {
   GLuint      gear1, gear2, gear3;
   GLuint      gear_inner, gear_outer;
   GLuint      armature;
   GLfloat     angle;
   GLXContext *glx_context;
   Window      window;
+  rotator    *rot;
+  trackball_state *trackball;
+  Bool           button_down_p;
+  int            planetary_p;
 } gearsstruct;
 
 static gearsstruct *gears = NULL;
@@ -336,80 +339,113 @@ gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
 }
 
 
-
 static void
-tube(GLfloat radius, GLfloat width, GLint facets, Bool wire)
+unit_tube (Bool wire)
 {
-  GLint i;
-  GLfloat da = 2.0 * M_PI / facets / 4.0;
-
+  int i;
+  int faces = TUBE_FACES;
+  GLfloat step = M_PI * 2 / faces;
+  GLfloat th;
+  int z = 0;
+
+  /* side walls
+   */
   glFrontFace(GL_CCW);
 
-  /* draw bottom of tube */
+# ifdef SMOOTH_TUBE
+  glBegin(wire ? GL_LINES : GL_QUAD_STRIP);
+# else
+  glBegin(wire ? GL_LINES : GL_QUADS);
+# endif
 
-  glShadeModel(GL_FLAT);
-  glNormal3f(0, 0, 1);
-  if (!wire)
+  for (i = 0, th = 0; i <= faces; i++)
     {
-      glBegin(GL_TRIANGLE_FAN);
-      glVertex3f(0, 0, width * 0.5);
-      for (i = 0; i <= facets; i++) {
-        GLfloat angle = i * 2.0 * M_PI / facets;
-        glVertex3f(radius * cos(angle), radius * sin(angle), width * 0.5);
-      }
-      glEnd();
+      GLfloat x = cos (th);
+      GLfloat y = sin (th);
+      glNormal3f(x, 0, y);
+      glVertex3f(x, 0.0, y);
+      glVertex3f(x, 1.0, y);
+      th += step;
+
+# ifndef SMOOTH_TUBE
+      x = cos (th);
+      y = sin (th);
+      glVertex3f(x, 1.0, y);
+      glVertex3f(x, 0.0, y);
+# endif
     }
+  glEnd();
 
-  /* draw top of tube */
-
-  glShadeModel(GL_FLAT);
-  glNormal3f(0, 0, -1);
-  glFrontFace(GL_CW);
-  if (!wire)
+  /* End caps
+   */
+  for (z = 0; z <= 1; z++)
     {
-      glBegin(GL_TRIANGLE_FAN);
-      glVertex3f(0, 0, -width * 0.5);
-      for (i = 0; i <= facets; i++) {
-        GLfloat angle = i * 2.0 * M_PI / facets;
-        glVertex3f(radius * cos(angle), radius * sin(angle), -width * 0.5);
-      }
+      glFrontFace(z == 0 ? GL_CCW : GL_CW);
+      glNormal3f(0, (z == 0 ? -1 : 1), 0);
+      glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
+      if (! wire) glVertex3f(0, z, 0);
+      for (i = 0, th = 0; i <= faces; i++)
+        {
+          GLfloat x = cos (th);
+          GLfloat y = sin (th);
+          glVertex3f(x, z, y);
+          th += step;
+        }
       glEnd();
     }
+}
 
-  /* draw side of tube */
-  glFrontFace(GL_CW);
-  glShadeModel(GL_SMOOTH);
 
-  if (!wire)
-    glBegin(GL_QUAD_STRIP);
+static void
+tube (GLfloat x1, GLfloat y1, GLfloat z1,
+      GLfloat x2, GLfloat y2, GLfloat z2,
+      GLfloat diameter, GLfloat cap_size,
+      Bool wire)
+{
+  GLfloat length, angle, a, b, c;
 
-  for (i = 0; i <= facets; i++) {
-    GLfloat angle = i * 2.0 * M_PI / facets;
-    
-    if (wire)
-      glBegin(GL_LINES);
+  if (diameter <= 0) abort();
 
-    glNormal3f(cos(angle), sin(angle), 0.0);
+  a = (x2 - x1);
+  b = (y2 - y1);
+  c = (z2 - z1);
 
-    glVertex3f(radius * cos(angle), radius * sin(angle), -width * 0.5);
-    glVertex3f(radius * cos(angle), radius * sin(angle), width * 0.5);
+  length = sqrt (a*a + b*b + c*c);
+  angle = acos (a / length);
 
-    if (wire) {
-      glVertex3f(radius * cos(angle), radius * sin(angle), -width * 0.5);
-      glVertex3f(radius * cos(angle + 4 * da), radius * sin(angle + 4 * da), -width * 0.5);
-      glVertex3f(radius * cos(angle), radius * sin(angle), width * 0.5);
-      glVertex3f(radius * cos(angle + 4 * da), radius * sin(angle + 4 * da), width * 0.5);
-      glEnd();
-    }
-  }
+  glPushMatrix();
+  glTranslatef(x1, y1, z1);
+  glScalef (length, length, length);
 
-  if (!wire)
-    glEnd();
+  if (c == 0 && b == 0)
+    glRotatef (angle / (M_PI / 180), 0, 1, 0);
+  else
+    glRotatef (angle / (M_PI / 180), 0, -c, b);
 
-  glFrontFace(GL_CCW);
+  glRotatef (-90, 0, 0, 1);
+  glScalef (diameter/length, 1, diameter/length);
+
+  /* extend the endpoints of the tube by the cap size in both directions */
+  if (cap_size != 0)
+    {
+      GLfloat c = cap_size/length;
+      glTranslatef (0, -c, 0);
+      glScalef (1, 1+c+c, 1);
+    }
+
+  unit_tube (wire);
+  glPopMatrix();
 }
 
 
+static void
+ctube (GLfloat diameter, GLfloat width, Bool wire)
+{
+  tube (0, 0,  width/2,
+        0, 0, -width/2,
+        diameter, 0, wire);
+}
+
 static void
 arm(GLfloat length,
     GLfloat width1, GLfloat height1,
@@ -498,19 +534,18 @@ draw(ModeInfo * mi)
 
        glPushMatrix();
 
-    {
-      GLfloat x = gp->rotx;
-      GLfloat y = gp->roty;
-      GLfloat z = gp->rotz;
-      if (x < 0) x = 1 - (x + 1);
-      if (y < 0) y = 1 - (y + 1);
-      if (z < 0) z = 1 - (z + 1);
-      glRotatef(x * 360, 1.0, 0.0, 0.0);
-      glRotatef(y * 360, 0.0, 1.0, 0.0);
-      glRotatef(z * 360, 0.0, 0.0, 1.0);
-    }
+    gltrackball_rotate (gp->trackball);
+
+    if (spin)
+         {
+               double x, y, z;
+               get_rotation (gp->rot, &x, &y, &z, !gp->button_down_p);
+               glRotatef (x * 360, 1.0, 0.0, 0.0);
+               glRotatef (y * 360, 0.0, 1.0, 0.0);
+               glRotatef (z * 360, 0.0, 0.0, 1.0);
+         }
 
-    if (!planetary) {
+    if (!gp->planetary_p) {
       glPushMatrix();
       glTranslatef(-3.0, -2.0, 0.0);
       glRotatef(gp->angle, 0.0, 0.0, 1.0);
@@ -531,7 +566,7 @@ draw(ModeInfo * mi)
       glCallList(gp->gear3);
       glPopMatrix();
 
-    } else { /* planetary */
+    } else { /* gp->planetary_p */
 
       glScalef(0.8, 0.8, 0.8);
 
@@ -579,8 +614,8 @@ draw(ModeInfo * mi)
 
 
 /* new window size or exposure */
-void
-reshape_gears(ModeInfo *mi, int width, int height)
+ENTRYPOINT void
+reshape_gears (ModeInfo *mi, int width, int height)
 {
        GLfloat     h = (GLfloat) height / (GLfloat) width;
 
@@ -604,18 +639,12 @@ static void
 pinit(ModeInfo * mi)
 {
        gearsstruct *gp = &gears[MI_SCREEN(mi)];
-       static GLfloat pos[4] =
-       {5.0, 5.0, 10.0, 1.0};
-       static GLfloat red[4] =
-       {0.8, 0.1, 0.0, 1.0};
-       static GLfloat green[4] =
-       {0.0, 0.8, 0.2, 1.0};
-       static GLfloat blue[4] =
-       {0.2, 0.2, 1.0, 1.0};
-       static GLfloat gray[4] =
-       {0.5, 0.5, 0.5, 1.0};
-       static GLfloat white[4] =
-       {1.0, 1.0, 1.0, 1.0};
+       static const GLfloat pos[4]   = {5.0, 5.0, 10.0, 1.0};
+       static const GLfloat red[4]   = {0.8, 0.1, 0.0, 1.0};
+       static const GLfloat green[4] = {0.0, 0.8, 0.2, 1.0};
+       static const GLfloat blue[4]  = {0.2, 0.2, 1.0, 1.0};
+       static const GLfloat gray[4]  = {0.5, 0.5, 0.5, 1.0};
+       static const GLfloat white[4] = {1.0, 1.0, 1.0, 1.0};
        int         wire = MI_IS_WIREFRAME(mi);
        int         mono = MI_IS_MONO(mi);
 
@@ -641,7 +670,7 @@ pinit(ModeInfo * mi)
 
        /* make the gears */
 
-    if (! planetary) {
+    if (! gp->planetary_p) {
 
       gp->gear1 = glGenLists(1);
       glNewList(gp->gear1, GL_COMPILE);
@@ -694,7 +723,7 @@ pinit(ModeInfo * mi)
       if (!wire)
                glEnable(GL_NORMALIZE);
 
-    } else { /* planetary */
+    } else { /* gp->planetary_p */
 
       gp->gear1 = glGenLists(1);
       glNewList(gp->gear1, GL_COMPILE);
@@ -785,21 +814,22 @@ pinit(ModeInfo * mi)
       glPushMatrix();
       glTranslatef(7.0, 0, 0);
       glRotatef(90, 0, 1, 0);
-      tube(0.5, 0.5, 10, wire);   /* nub 1 */
+
+      ctube(0.5, 0.5, wire);   /* nub 1 */
       glPopMatrix();
 
       glPushMatrix();
       glRotatef(120, 0, 0, 1);
       glTranslatef(7.0, 0, 0);
       glRotatef(90, 0, 1, 0);
-      tube(0.5, 0.5, 10, wire);   /* nub 2 */
+      ctube(0.5, 0.5, wire);   /* nub 2 */
       glPopMatrix();
 
       glPushMatrix();
       glRotatef(240, 0, 0, 1);
       glTranslatef(7.0, 0, 0);
       glRotatef(90, 0, 1, 0);
-      tube(0.5, 0.5, 10, wire);   /* nub 3 */
+      ctube(0.5, 0.5, wire);   /* nub 3 */
       glPopMatrix();
 
 
@@ -822,34 +852,33 @@ pinit(ModeInfo * mi)
       }
 
       glTranslatef(0, 0, 1.5);
-
-      tube(0.5, 10, 15, wire);       /* center axle */
+      ctube(0.5, 10, wire);       /* center axle */
 
       glPushMatrix();
       glTranslatef(0.0, 4.2, -1);
-      tube(0.5, 3, 15, wire);       /* axle 1 */
+      ctube(0.5, 3, wire);       /* axle 1 */
       glTranslatef(0, 0, 1.8);
-      tube(0.7, 0.7, 15, wire);
+      ctube(0.7, 0.7, wire);
       glPopMatrix();
 
       glPushMatrix();
       glRotatef(120, 0.0, 0.0, 1.0);
       glTranslatef(0.0, 4.2, -1);
-      tube(0.5, 3, 15, wire);       /* axle 2 */
+      ctube(0.5, 3, wire);       /* axle 2 */
       glTranslatef(0, 0, 1.8);
-      tube(0.7, 0.7, 15, wire);
+      ctube(0.7, 0.7, wire);
       glPopMatrix();
 
       glPushMatrix();
       glRotatef(240, 0.0, 0.0, 1.0);
       glTranslatef(0.0, 4.2, -1);
-      tube(0.5, 3, 15, wire);       /* axle 3 */
+      ctube(0.5, 3, wire);       /* axle 3 */
       glTranslatef(0, 0, 1.8);
-      tube(0.7, 0.7, 15, wire);
+      ctube(0.7, 0.7, wire);
       glPopMatrix();
 
       glTranslatef(0, 0, 1.5);      /* center disk */
-      tube(1.5, 2, 20, wire);
+      ctube(1.5, 2, wire);
 
       glPushMatrix();
       glRotatef(270, 0, 0, 1);
@@ -879,79 +908,49 @@ pinit(ModeInfo * mi)
 }
 
 
-/* lifted from lament.c */
-#define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
-#define RANDSIGN() ((random() & 1) ? 1 : -1)
-
-static void
-rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
+ENTRYPOINT Bool
+gears_handle_event (ModeInfo *mi, XEvent *event)
 {
-  double ppos = *pos;
-
-  /* tick position */
-  if (ppos < 0)
-    ppos = -(ppos + *v);
-  else
-    ppos += *v;
-
-  if (ppos > 1.0)
-    ppos -= 1.0;
-  else if (ppos < 0)
-    ppos += 1.0;
-
-  if (ppos < 0) abort();
-  if (ppos > 1.0) abort();
-  *pos = (*pos > 0 ? ppos : -ppos);
+  gearsstruct *gp = &gears[MI_SCREEN(mi)];
 
-  /* accelerate */
-  *v += *dv;
-
-  /* clamp velocity */
-  if (*v > max_v || *v < -max_v)
+  if (event->xany.type == ButtonPress &&
+      event->xbutton.button == Button1)
     {
-      *dv = -*dv;
+      gp->button_down_p = True;
+      gltrackball_start (gp->trackball,
+                         event->xbutton.x, event->xbutton.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
     }
-  /* If it stops, start it going in the other direction. */
-  else if (*v < 0)
+  else if (event->xany.type == ButtonRelease &&
+           event->xbutton.button == Button1)
     {
-      if (random() % 4)
-       {
-         *v = 0;
-
-         /* keep going in the same direction */
-         if (random() % 2)
-           *dv = 0;
-         else if (*dv < 0)
-           *dv = -*dv;
-       }
-      else
-       {
-         /* reverse gears */
-         *v = -*v;
-         *dv = -*dv;
-         *pos = -*pos;
-       }
+      gp->button_down_p = False;
+      return True;
     }
-
-  /* Alter direction of rotational acceleration randomly. */
-  if (! (random() % 120))
-    *dv = -*dv;
-
-  /* Change acceleration very occasionally. */
-  if (! (random() % 200))
+  else if (event->xany.type == ButtonPress &&
+           (event->xbutton.button == Button4 ||
+            event->xbutton.button == Button5))
+    {
+      gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
+                              !!event->xbutton.state);
+      return True;
+    }
+  else if (event->xany.type == MotionNotify &&
+           gp->button_down_p)
     {
-      if (*dv == 0)
-       *dv = 0.00001;
-      else if (random() & 1)
-       *dv *= 1.2;
-      else
-       *dv *= 0.8;
+      gltrackball_track (gp->trackball,
+                         event->xmotion.x, event->xmotion.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
     }
+
+  return False;
 }
 
 
-void
-init_gears(ModeInfo * mi)
+ENTRYPOINT void
+init_gears (ModeInfo * mi)
 {
        int         screen = MI_SCREEN(mi);
 
@@ -966,26 +965,20 @@ init_gears(ModeInfo * mi)
        }
        gp = &gears[screen];
 
-       gp->window = MI_WINDOW(mi);
-
-    gp->rotx = frand(1.0) * RANDSIGN();
-    gp->roty = frand(1.0) * RANDSIGN();
-    gp->rotz = frand(1.0) * RANDSIGN();
-
-    /* bell curve from 0-1.5 degrees, avg 0.75 */
-    gp->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
-    gp->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
-    gp->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
-
-    gp->d_max = gp->dx * 2;
+    if (mode_str && !strcasecmp (mode_str, "planetary"))
+      gp->planetary_p = True;
+    else if (mode_str && !strcasecmp (mode_str, "simple"))
+      gp->planetary_p = False;
+    else if (!mode_str || !*mode_str || !strcasecmp (mode_str, "random"))
+      gp->planetary_p = !(random() % 2);
+    else
+      fprintf (stderr, "%s: mode must be planetary, simple, or random", 
+               progname);
 
-    gp->ddx = 0.00006 + frand(0.00003);
-    gp->ddy = 0.00006 + frand(0.00003);
-    gp->ddz = 0.00006 + frand(0.00003);
+       gp->window = MI_WINDOW(mi);
 
-    gp->ddx = 0.00001;
-    gp->ddy = 0.00001;
-    gp->ddz = 0.00001;
+    gp->rot = make_rotator (1, 1, 1, 1, 0, True);
+    gp->trackball = gltrackball_init ();
 
        if ((gp->glx_context = init_GL(mi)) != NULL) {
                reshape_gears(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
@@ -995,15 +988,15 @@ init_gears(ModeInfo * mi)
        }
 }
 
-void
-draw_gears(ModeInfo * mi)
+ENTRYPOINT void
+draw_gears (ModeInfo * mi)
 {
        gearsstruct *gp = &gears[MI_SCREEN(mi)];
        Display    *display = MI_DISPLAY(mi);
        Window      window = MI_WINDOW(mi);
        int         angle_incr = MI_CYCLES(mi) ? MI_CYCLES(mi) : 2;
 
-    if (planetary)
+    if (gp->planetary_p)
       angle_incr *= 3;
 
        if (!gp->glx_context)
@@ -1017,17 +1010,13 @@ draw_gears(ModeInfo * mi)
        /* let's do something so we don't get bored */
        gp->angle = (int) (gp->angle + angle_incr) % 360;
 
-    rotate(&gp->rotx, &gp->dx, &gp->ddx, gp->d_max);
-    rotate(&gp->roty, &gp->dy, &gp->ddy, gp->d_max);
-    rotate(&gp->rotz, &gp->dz, &gp->ddz, gp->d_max);
-
     if (mi->fps_p) do_fps (mi);
        glFinish();
        glXSwapBuffers(display, window);
 }
 
-void
-release_gears(ModeInfo * mi)
+ENTRYPOINT void
+release_gears (ModeInfo * mi)
 {
        if (gears != NULL) {
                int         screen;
@@ -1059,6 +1048,8 @@ release_gears(ModeInfo * mi)
 }
 
 
+XSCREENSAVER_MODULE ("Gears", gears)
+
 /*********************************************************/
 
 #endif