http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / extrusion.c
index 2e6958ccf0effdcb631e39b2b6a1eea4f6a66400..7e98f5e3bf924524049e5cf24b065702a6081a73 100644 (file)
  * which can be obtained from http://www.linas.org/gle/index.html
   */
 
-/*-
- * 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 HAVE_CONFIG_H
 #include <config.h>
 #endif
 
 #ifdef STANDALONE
-# define PROGCLASS                                             "Screensaver"
-# define HACK_INIT                                             init_screensaver
-# define HACK_DRAW                                             draw_screensaver
-# define HACK_RESHAPE                                  reshape_screensaver
-# define screensaver_opts                              xlockmore_opts
-#define        DEFAULTS                        "*delay:                        10000   \n" \
-                                                                               "*showFPS:              False   \n" \
-                                                                               "*light:                        True    \n" \
-                                        "*wire:                                False   \n" \
-                                        "*texture:                     False   \n" \
-                                                                               "*image:                        BUILTIN \n" \
-                                        "*name:             RANDOM  \n" \
-                                        "*example:          0       \n"
+#define        DEFAULTS        "*delay:         20000  \n" \
+                                       "*showFPS:       False  \n" \
+                                       "*wireframe: False   \n"
 
+# define refresh_extrusion 0
+# define release_extrusion 0
 # include "xlockmore.h"                                /* from the xscreensaver distribution */
 #else /* !STANDALONE */
 # include "xlock.h"                                    /* from the xlockmore distribution */
 # endif /* VMS */
 #endif
 
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <malloc.h>
-#include <GL/gl.h>
-#include <GL/glu.h>
-#ifdef HAVE_GLE3
-#include <GL/gle.h>
-#else
-#include <GL/tube.h>
-#endif
-
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
 
 #include "xpm-ximage.h"
+#include "rotator.h"
+#include "gltrackball.h"
+#include "extrusion.h"
 
 #define checkImageWidth 64
 #define checkImageHeight 64
 
 
-extern void InitStuff_helix2(void);
-extern void DrawStuff_helix2(void);
-extern void InitStuff_helix3(void);
-extern void DrawStuff_helix3(void);
-extern void InitStuff_helix4(void);
-extern void DrawStuff_helix4(void);
-extern void InitStuff_joinoffset(void);
-extern void DrawStuff_joinoffset(void);
-extern void InitStuff_screw(void);
-extern void DrawStuff_screw(void);
-extern void InitStuff_taper(void);
-extern void DrawStuff_taper(void);
-extern void InitStuff_twistoid(void);
-extern void DrawStuff_twistoid(void);
-
-
-
 #define WIDTH 640
 #define HEIGHT 480
 
 #define DEF_LIGHT              "True"
-#define DEF_WIRE               "False"
 #define DEF_TEXTURE            "False"
-#define DEF_TEXTURE_QUALITY   "False"
+#define DEF_TEX_QUAL   "False"
 #define DEF_MIPMAP     "False"
 #define DEF_NAME        "RANDOM"
 #define DEF_IMAGE      "BUILTIN"
 
 static int do_light;
-static int do_wire;
 static int do_texture;
-static int do_texture_quality;
+static int do_tex_qual;
 static int do_mipmap;
 static char *which_name;
 static char *which_image;
 
 static XrmOptionDescRec opts[] = {
-  {"-light",   ".extrusion.light",     XrmoptionNoArg, (caddr_t) "true" },
-  {"+light",   ".extrusion.light",     XrmoptionNoArg, (caddr_t) "false" },
-  {"-wire",    ".extrusion.wire",      XrmoptionNoArg, (caddr_t) "true" },
-  {"+wire",    ".extrusion.wire",      XrmoptionNoArg, (caddr_t) "false" },
-  {"-texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
-  {"+texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "false" },
-  {"-texture", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
-  {"+texture_quality", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "false" },
-  {"-texture_quality", ".extrusion.texture",   XrmoptionNoArg, (caddr_t) "true" },
-  {"+mipmap", ".extrusion.mipmap",   XrmoptionNoArg, (caddr_t) "false" },
-  {"-mipmap", ".extrusion.mipmap",   XrmoptionNoArg, (caddr_t) "true" },
-  {"-name",   ".extrusion.name",  XrmoptionSepArg, (caddr_t) NULL },
-  {"-image",   ".extrusion.image",  XrmoptionSepArg, (caddr_t) NULL },
+  {"-light",           ".extrusion.light",   XrmoptionNoArg, "true" },
+  {"+light",           ".extrusion.light",   XrmoptionNoArg, "false" },
+  {"-texture",         ".extrusion.texture", XrmoptionNoArg, "true" },
+  {"+texture",         ".extrusion.texture", XrmoptionNoArg, "false" },
+  {"-texture",         ".extrusion.texture", XrmoptionNoArg, "true" },
+  {"+texture_quality", ".extrusion.texture", XrmoptionNoArg, "false" },
+  {"-texture_quality", ".extrusion.texture", XrmoptionNoArg, "true" },
+  {"+mipmap",          ".extrusion.mipmap",  XrmoptionNoArg, "false" },
+  {"-mipmap",          ".extrusion.mipmap",  XrmoptionNoArg, "true" },
+  {"-name",            ".extrusion.name",    XrmoptionSepArg, 0 },
+  {"-image",           ".extrusion.image",   XrmoptionSepArg, 0 },
 };
 
 
 static argtype vars[] = {
-  {(caddr_t *) &do_light,    "light",   "Light",   DEF_LIGHT,   t_Bool},
-  {(caddr_t *) &do_wire,    "wire",   "Wire",   DEF_WIRE,   t_Bool},
-  {(caddr_t *) &do_texture,    "texture",   "Texture",   DEF_TEXTURE,   t_Bool},
-  {(caddr_t *) &do_texture_quality,    "texture_quality",   "Texture_Quality",   DEF_TEXTURE_QUALITY,   t_Bool},
-  {(caddr_t *) &do_mipmap,    "mipmap",   "Mipmap",   DEF_MIPMAP,   t_Bool},
-  {(caddr_t *) &which_name, "name",   "Name",   DEF_NAME,   t_String},
-  {(caddr_t *) &which_image, "image",   "Image",   DEF_IMAGE,   t_String},
+  {&do_light,   "light",           "Light",           DEF_LIGHT,    t_Bool},
+  {&do_texture,         "texture",         "Texture",         DEF_TEXTURE,  t_Bool},
+  {&do_tex_qual, "texture_quality", "Texture_Quality", DEF_TEX_QUAL, t_Bool},
+  {&do_mipmap,   "mipmap",          "Mipmap",          DEF_MIPMAP,   t_Bool},
+  {&which_name,  "name",            "Name",            DEF_NAME,     t_String},
+  {&which_image, "image",           "Image",           DEF_IMAGE,    t_String},
 };
 
 
@@ -153,58 +106,55 @@ static OptionStruct desc[] =
 {
   {"-name num", "example 'name' to draw (helix2, helix3, helix4, joinoffset, screw, taper, twistoid)"},
   {"-/+ light", "whether to do enable lighting (slower)"},
-  {"-/+ wire", "whether to do use wireframe instead of filled (faster)"},
   {"-/+ texture", "whether to apply a texture (slower)"},
   {"-image <filename>", "texture image to load"},
   {"-/+ texture_quality", "whether to use texture smoothing (slower)"},
   {"-/+ mipmap", "whether to use texture mipmap (slower)"},
 };
 
-ModeSpecOpt screensaver_opts = {countof(opts), opts, countof(vars), vars, desc};
+ENTRYPOINT ModeSpecOpt extrusion_opts = {countof(opts), opts, countof(vars), vars, desc};
 
 #ifdef USE_MODULES
-ModStruct   screensaver_description =
-{"screensaver", "init_screensaver", "draw_screensaver", "release_screensaver",
- "draw_screensaver", "init_screensaver", NULL, &screensaver_opts,
+ModStruct   extrusion_description =
+{"extrusion", "init_extrusion", "draw_extrusion", "release_extrusion",
+ "draw_extrusion", "init_extrusion", NULL, &extrusion_opts,
  1000, 1, 2, 1, 4, 1.0, "",
- "OpenGL screensaver", 0, NULL};
+ "OpenGL extrusion", 0, NULL};
 #endif
 
 
-/* structure for holding the screensaver data */
+/* structure for holding the extrusion data */
 typedef struct {
   int screen_width, screen_height;
   GLXContext *glx_context;
+  rotator *rot;
+  trackball_state *trackball;
+  Bool button_down_p;
+  Bool button2_down_p;
+  int mouse_start_x, mouse_start_y;
+  int mouse_x, mouse_y;
+  int mouse_dx, mouse_dy;
   Window window;
   XColor fg, bg;
-} screensaverstruct;
-static screensaverstruct *Screensaver = NULL;
-
+  int extrusion_number;
+} extrusionstruct;
 
+static extrusionstruct *Extrusion = NULL;
 
 
-/* convenient access to the screen width */
-static int global_width=640, global_height=480;
 
 /* set up a light */
-static GLfloat lightOnePosition[] = {40.0, 40, 100.0, 0.0};
-static GLfloat lightOneColor[] = {0.99, 0.99, 0.99, 1.0}; 
+static const GLfloat lightOnePosition[] = {40.0, 40, 100.0, 0.0};
+static const GLfloat lightOneColor[] = {0.99, 0.99, 0.00, 1.0}; 
 
-static GLfloat lightTwoPosition[] = {-40.0, 40, 100.0, 0.0};
-static GLfloat lightTwoColor[] = {0.99, 0.99, 0.99, 1.0}; 
+static const GLfloat lightTwoPosition[] = {-40.0, 40, 100.0, 0.0};
+static const GLfloat lightTwoColor[] = {0.00, 0.99, 0.99, 1.0}; 
 
 float rot_x=0, rot_y=0, rot_z=0;
-static float dx=0, dy=0, dz=0;
-static float ddx=0, ddy=0, ddz=0;
-static float d_max = 0;
-static int screensaver_number;
+float lastx=0, lasty=0;
 
-static float max_lastx=300, max_lasty=400;
+static float max_lastx=400,  max_lasty=400;
 static float min_lastx=-400, min_lasty=-400;
-static float d_lastx=0, d_lasty=0;
-static float dd_lastx=0, dd_lasty=0;
-static float max_dlastx=0, max_dlasty=0;
-float lastx=0, lasty=0;
 
 struct functions {
   void (*InitStuff)(void);
@@ -216,7 +166,7 @@ struct functions {
    like we're looking at them from the back or something
 */
 
-static struct functions funcs_ptr[] = {
+static const struct functions funcs_ptr[] = {
   {InitStuff_helix2, DrawStuff_helix2, "helix2"},
   {InitStuff_helix3, DrawStuff_helix3, "helix3"},
   {InitStuff_helix4, DrawStuff_helix4, "helix4"},
@@ -226,13 +176,13 @@ static struct functions funcs_ptr[] = {
   {InitStuff_twistoid, DrawStuff_twistoid, "twistoid"},
 };
 
-static int num_screensavers = countof(funcs_ptr);
+static int num_extrusions = countof(funcs_ptr);
 
 
 /* BEGINNING OF FUNCTIONS */
 
 
-GLubyte *
+static GLubyte *
 Generate_Image(int *width, int *height, int *format)
 {
   GLubyte *result;
@@ -261,7 +211,7 @@ Generate_Image(int *width, int *height, int *format)
 
 /* Create a texture in OpenGL.  First an image is loaded 
    and stored in a raster buffer, then it's  */
-void Create_Texture(ModeInfo *mi, const char *filename)
+static void Create_Texture(ModeInfo *mi, const char *filename)
 {
   int height, width;
   GLubyte *image;
@@ -273,7 +223,7 @@ void Create_Texture(ModeInfo *mi, const char *filename)
     {
       XImage *ximage = xpm_file_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
                                            MI_COLORMAP (mi), filename);
-      image  = ximage->data;
+      image  = (GLubyte *) ximage->data;
       width  = ximage->width;
       height = ximage->height;
       format = GL_RGBA;
@@ -287,7 +237,7 @@ void Create_Texture(ModeInfo *mi, const char *filename)
   /* perhaps we can edge a bit more speed at the expense of quality */
   glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
 
-  if (do_texture_quality) {
+  if (do_tex_qual) {
        /* with texture_quality, the min and mag filters look *much* nice but are *much* slower */
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
@@ -308,7 +258,7 @@ void Create_Texture(ModeInfo *mi, const char *filename)
                                  GL_UNSIGNED_BYTE, image);
       if (status)
         {
-          const char *s = gluErrorString (status);
+          const char *s = (char *) gluErrorString (status);
           fprintf (stderr, "%s: error mipmapping %dx%d texture: %s\n",
                    progname, width, height,
                    (s ? s : "(unknown)"));
@@ -326,208 +276,88 @@ void Create_Texture(ModeInfo *mi, const char *filename)
 }
 
 
-/* mostly lifted from lament.c */
 static void
-rotate (float *pos, float *v, float *dv, float max_v)
+init_rotation (ModeInfo *mi)
 {
-  double ppos = *pos;
-
-  /* tick position */
-  if (ppos < 0)
-    ppos = -(ppos + *v);
-  else
-    ppos += *v;
-
-  if (ppos > 360)
-    ppos -= 360;
-  else if (ppos < 0)
-    ppos += 360;
-
-  if (ppos < 0) abort();
-  if (ppos > 360) abort();
-  *pos = (*pos > 0 ? ppos : -ppos);
-
-  /* accelerate */
-  *v += *dv;
-
-  /* clamp velocity */
-  if (*v > max_v || *v < -max_v)
-    {
-      *dv = -*dv;
-    }
-  /* If it stops, start it going in the other direction. */
-  else if (*v < 0)
-    {
-      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;
-        }
-    }
-
-  /* Alter direction of rotational acceleration randomly. */
-  if (! (random() % 120))
-    *dv = -*dv;
-
-  /* Change acceleration very occasionally. */
-  if (! (random() % 200))
-    {
-      if (*dv == 0)
-        *dv = 0.00001;
-      else if (random() & 1)
-        *dv *= 1.2;
-      else
-        *dv *= 0.8;
-    }
-}
-
-
-static void
-bounce (float *pos, float *v, float *dv, float max_v)
-{
-  *pos += *v;
-
-  if (*pos > 1.0)
-    *pos = 1.0, *v = -*v, *dv = -*dv;
-  else if (*pos < 0)
-    *pos = 0, *v = -*v, *dv = -*dv;
-
-  if (*pos < 0.0) abort();
-  if (*pos > 1.0) abort();
-
-  /* accelerate */
-  *v += *dv;
-
-  /* clamp velocity */
-  if (*v > max_v || *v < -max_v)
-    {
-      *dv = -*dv;
-    }
-
-  /* Alter direction of rotational acceleration randomly. */
-  if (! (random() % 120))
-    *dv = -*dv;
-
-  /* Change acceleration very occasionally. */
-  if (! (random() % 200))
-    {
-      if (*dv == 0)
-        *dv = 0.00001;
-      else if (random() & 1)
-        *dv *= 1.2;
-      else
-        *dv *= 0.8;
-    }
-}
-
-
-static void
-init_rotation (void)
-{
-  rot_x = (float) (random() % (360 * 2)) - 360;  /* -360 - 360 */
-  rot_y = (float) (random() % (360 * 2)) - 360;
-  rot_z = (float) (random() % (360 * 2)) - 360;
-
-  /* bell curve from 0-1.5 degrees, avg 0.75 */
-  dx = (frand(1) + frand(1) + frand(1)) / 2.0;
-  dy = (frand(1) + frand(1) + frand(1)) / 2.0;
-  dz = (frand(1) + frand(1) + frand(1)) / 2.0;
-
-  d_max = dx * 2;
-
-  ddx = 0.004;
-  ddy = 0.004;
-  ddz = 0.004;
+  extrusionstruct *gp = &Extrusion[MI_SCREEN(mi)];
+  double spin_speed = 0.5;
+  gp->rot = make_rotator (spin_speed, spin_speed, spin_speed,
+                          0.2,
+                          0.005,
+                          True);
+  gp->trackball = gltrackball_init ();
 
   lastx = (random() % (int) (max_lastx - min_lastx)) + min_lastx;
   lasty = (random() % (int) (max_lasty - min_lasty)) + min_lasty;
-  d_lastx = (frand(1) + frand(1) + frand(1));
-  d_lasty = (frand(1) + frand(1) + frand(1));
-  max_dlastx = d_lastx * 2;
-  max_dlasty = d_lasty * 2;
-  dd_lastx = 0.004;
-  dd_lasty = 0.004;
 }
 
 
-/* draw the screensaver once */
-void draw_screensaver(ModeInfo * mi)
+/* draw the extrusion once */
+ENTRYPOINT void
+draw_extrusion(ModeInfo * mi)
 {
-  screensaverstruct *gp = &Screensaver[MI_SCREEN(mi)];
+  extrusionstruct *gp = &Extrusion[MI_SCREEN(mi)];
   Display    *display = MI_DISPLAY(mi);
   Window      window = MI_WINDOW(mi);
 
-  Window root, child;
-  int rootx, rooty, winx, winy;
-  unsigned int mask;
-  XEvent event;
+  static const GLfloat color[4] = {0.6, 0.6, 0.4, 1.0};
+  /* static const GLfloat spec[4]  = {0.6, 0.6, 0.6, 1.0}; */
+  /* static const GLfloat shiny    = 40.0; */
+
+  double x, y, z;
 
   if (!gp->glx_context)
        return;
 
-  glXMakeCurrent(display, window, *(gp->glx_context));
+  glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));
 
-  funcs_ptr[screensaver_number].DrawStuff();
-         
-  rotate(&rot_x, &dx, &ddx, d_max);
-  rotate(&rot_y, &dy, &ddy, d_max);
-  rotate(&rot_z, &dz, &ddz, d_max);
+  glPushMatrix();
 
-  /* swallow any ButtonPress events */
-  while (XCheckMaskEvent (MI_DISPLAY(mi), ButtonPressMask, &event))
-    ;
-  /* check the pointer position and button state. */
-  XQueryPointer (MI_DISPLAY(mi), MI_WINDOW(mi),
-                 &root, &child, &rootx, &rooty, &winx, &winy, &mask);
+  gltrackball_rotate (gp->trackball);
+
+  get_rotation (gp->rot, &x, &y, &z,
+                !(gp->button_down_p || gp->button2_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);
 
   /* track the mouse only if a button is down. */
-  if (mask & (Button1Mask|Button2Mask|Button3Mask|Button4Mask|Button5Mask))
+  if (gp->button2_down_p)
     {
-      lastx = winx;
-      lasty = winy;
-    }
-  else
-    {
-      float scale = (max_lastx - min_lastx);
-      lastx -= min_lastx;
-      lasty -= min_lasty;
-      lastx /= scale;
-      lasty /= scale;
-      d_lastx /= scale;
-      d_lasty /= scale;
-      dd_lastx /= scale;
-      dd_lasty /= scale;
-      bounce(&lastx, &d_lastx, &dd_lastx, max_dlastx);
-      bounce(&lasty, &d_lasty, &dd_lasty, max_dlasty);
-      lastx *= scale;
-      lasty *= scale;
-      lastx += min_lastx;
-      lasty += min_lasty;
-      d_lastx *= scale;
-      d_lasty *= scale;
-      dd_lastx *= scale;
-      dd_lasty *= scale;
+      gp->mouse_dx += gp->mouse_x - gp->mouse_start_x;
+      gp->mouse_dy += gp->mouse_y - gp->mouse_start_y;
+      gp->mouse_start_x = gp->mouse_x;
+      gp->mouse_start_y = gp->mouse_y;
     }
 
+  {
+    float scale = (max_lastx - min_lastx);
+    get_position (gp->rot, &x, &y, &z,
+                  !(gp->button_down_p || gp->button2_down_p));
+    lastx = x * scale + min_lastx + gp->mouse_dx;
+    lasty = y * scale + min_lasty + gp->mouse_dy;
+  }
+
+  glScalef(0.5, 0.5, 0.5);
+
+  /* glMaterialfv (GL_FRONT_AND_BACK, GL_SPECULAR,            spec); */
+  /* glMateriali  (GL_FRONT_AND_BACK, GL_SHININESS,           shiny); */
+
+  glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color);
+  glFrontFace(GL_CCW);
+
+  funcs_ptr[gp->extrusion_number].DrawStuff();
+         
+  glPopMatrix();
+
   if (mi->fps_p) do_fps (mi);
   glXSwapBuffers(display, window);
 }
 
 
 /* set up lighting conditions */
-static void SetupLight(void)
+static void
+SetupLight(void)
 {
   glLightfv (GL_LIGHT0, GL_POSITION, lightOnePosition);
   glLightfv (GL_LIGHT0, GL_DIFFUSE, lightOneColor);
@@ -543,54 +373,60 @@ static void SetupLight(void)
   glEnable (GL_COLOR_MATERIAL);
 }
 
-/* reset the projection matrix */
-static void resetProjection(void) {
+/* Standard reshape function */
+ENTRYPOINT void
+reshape_extrusion (ModeInfo *mi, int width, int height)
+{
+  GLfloat h = (GLfloat) height / (GLfloat) width;
+
+  glViewport (0, 0, (GLint) width, (GLint) height);
+
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
-  glFrustum (-9, 9, -9, 9, 50, 150.0);
+  gluPerspective (30.0, 1/h, 1.0, 100.0);
+
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
-}
+  gluLookAt( 0.0, 0.0, 30.0,
+             0.0, 0.0, 0.0,
+             0.0, 1.0, 0.0);
 
-/* Standard reshape function */
-void
-reshape_screensaver(ModeInfo *mi, int width, int height)
-{
-  global_width=width;
-  global_height=height;
-  glViewport( 0, 0, global_width, global_height );
-  resetProjection();
+  glClear(GL_COLOR_BUFFER_BIT);
 }
 
 
-/* decide which screensaver example to run */
-static void chooseScreensaverExample(void) {
+/* decide which extrusion example to run */
+static void
+chooseExtrusionExample (ModeInfo *mi)
+{
+  extrusionstruct *gp = &Extrusion[MI_SCREEN(mi)];
   int i;
   /* call the extrusion init routine */
 
   if (!strncmp(which_name, "RANDOM", strlen(which_name))) {
-    screensaver_number = random() % num_screensavers;
+    gp->extrusion_number = random() % num_extrusions;
   }
   else {
-       screensaver_number=-1;
-       for (i=0; i < num_screensavers; i++) {
+       gp->extrusion_number=-1;
+       for (i=0; i < num_extrusions; i++) {
          if (!strncmp(which_name, funcs_ptr[i].name, strlen(which_name))) {
-               screensaver_number = i;
+               gp->extrusion_number = i;
          }
        }         
   }
        
-  if (screensaver_number < 0 || screensaver_number >= num_screensavers) {
-       fprintf(stderr, "%s: invalid screensaver example number!\n", progname);
-       fprintf(stderr, "%s: known screensavers:\n", progname);
-       for (i=0; i < num_screensavers; i++)
+  if (gp->extrusion_number < 0 || gp->extrusion_number >= num_extrusions) {
+       fprintf(stderr, "%s: invalid extrusion example number!\n", progname);
+       fprintf(stderr, "%s: known extrusions:\n", progname);
+       for (i=0; i < num_extrusions; i++)
          fprintf(stderr,"\t%s\n", funcs_ptr[i].name);
        exit(1);
   }
-  init_rotation();
-  funcs_ptr[screensaver_number].InitStuff();
+  init_rotation(mi);
+  funcs_ptr[gp->extrusion_number].InitStuff();
 }
 
+
 /* main OpenGL initialization routine */
 static void
 initializeGL(ModeInfo *mi, GLsizei width, GLsizei height) 
@@ -598,18 +434,18 @@ initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
   int style;
   int mode;
 
-  reshape_screensaver(mi, width, height);
+  reshape_extrusion(mi, width, height);
   glViewport( 0, 0, width, height ); 
 
   glEnable(GL_DEPTH_TEST);
   glClearColor(0,0,0,0);
-/*    glCullFace(GL_BACK); */
-/*    glEnable(GL_CULL_FACE); */
+  glDisable (GL_CULL_FACE);
+  glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, True);
   glShadeModel(GL_SMOOTH);
 
   if (do_light)
        SetupLight();
-  if (do_wire) {
+  if (MI_IS_WIREFRAME(mi)) {
        glPolygonMode(GL_FRONT,GL_LINE);
        glPolygonMode(GL_BACK,GL_LINE);
   }
@@ -634,41 +470,88 @@ initializeGL(ModeInfo *mi, GLsizei width, GLsizei height)
 
 }
 
-/* xscreensaver initialization routine */
-void init_screensaver(ModeInfo * mi)
+ENTRYPOINT Bool
+extrusion_handle_event (ModeInfo *mi, XEvent *event)
+{
+  extrusionstruct *gp = &Extrusion[MI_SCREEN(mi)];
+
+  if (event->xany.type == ButtonPress &&
+      (event->xbutton.button == Button4 ||
+       event->xbutton.button == Button5 ||
+       event->xbutton.button == Button6 ||
+       event->xbutton.button == Button7))
+    {
+      gltrackball_mousewheel (gp->trackball, event->xbutton.button, 10,
+                              !!event->xbutton.state);
+      return True;
+    }
+  else if (event->xany.type == ButtonPress &&   /* rotate with left button */
+           !event->xbutton.state)              /* if no modifier keys */
+    {
+      gp->button_down_p = True;
+      gltrackball_start (gp->trackball,
+                         event->xbutton.x, event->xbutton.y,
+                         MI_WIDTH (mi), MI_HEIGHT (mi));
+      return True;
+    }
+  else if (event->xany.type == ButtonPress)  /* deform with other buttons */
+    {                                        /* or with modifier keys */
+      gp->button2_down_p = True;
+      gp->mouse_start_x = gp->mouse_x = event->xbutton.x;
+      gp->mouse_start_y = gp->mouse_y = event->xbutton.y;
+      return True;
+    }
+  else if (event->xany.type == ButtonRelease)
+    {
+      gp->button_down_p = False;
+      gp->button2_down_p = False;
+      return True;
+    }
+  else if (event->xany.type == MotionNotify)
+    {
+      if (gp->button_down_p)
+        gltrackball_track (gp->trackball,
+                           event->xmotion.x, event->xmotion.y,
+                           MI_WIDTH (mi), MI_HEIGHT (mi));
+      if (gp->button2_down_p)
+        {
+          gp->mouse_x = event->xmotion.x;
+          gp->mouse_y = event->xmotion.y;
+        }
+      return True;
+    }
+
+  return False;
+}
+
+
+/* xextrusion initialization routine */
+ENTRYPOINT void
+init_extrusion (ModeInfo * mi)
 {
   int screen = MI_SCREEN(mi);
-  screensaverstruct *gp;
+  extrusionstruct *gp;
 
-  if (Screensaver == NULL) {
-       if ((Screensaver = (screensaverstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (screensaverstruct))) == NULL)
+  if (MI_IS_WIREFRAME(mi)) do_light = 0;
+
+  if (Extrusion == NULL) {
+       if ((Extrusion = (extrusionstruct *)
+         calloc(MI_NUM_SCREENS(mi), sizeof (extrusionstruct))) == NULL)
          return;
   }
-  gp = &Screensaver[screen];
+  gp = &Extrusion[screen];
 
   gp->window = MI_WINDOW(mi);
   if ((gp->glx_context = init_GL(mi)) != NULL) {
-       reshape_screensaver(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+       reshape_extrusion(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
        initializeGL(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-       chooseScreensaverExample();
+       chooseExtrusionExample(mi);
   } else {
        MI_CLEARWINDOW(mi);
   }
 
 }
 
-/* all sorts of nice cleanup code should go here! */
-void release_screensaver(ModeInfo * mi)
-{
-  int screen;
-  if (Screensaver != NULL) {
-       for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-         /*      screensaverstruct *gp = &Screensaver[screen];*/
-       }
-       (void) free((void *) Screensaver);
-       Screensaver = NULL;
-  }
-  FreeAllGL(mi);
-}
-#endif
+XSCREENSAVER_MODULE ("Extrusion", extrusion)
 
+#endif  /* USE_GL */