http://www.uw-madison.lkams.kernel.org/pub/mirrors/fink/distfiles/xscreensaver-4...
[xscreensaver] / hacks / glx / klein.c
index afe9f221ac27400602814780cacf6709be25a83d..b068e3f4e7ff8259be004e41437ea1b78e9d9730 100644 (file)
-/* -*- Mode: C; tab-width: 4 -*- */\r
-/* Klein --- Klein Bottle, Moebius and other parametric surfaces\r
- * visualization */\r
-\r
-/*\r
- * Revision History:\r
- * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca\r
- *       \r
- * 01-Mar-2003  mirtchov    modified as a xscreensaver hack\r
- *\r
- */\r
-\r
-/*-\r
- * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.\r
- * otherwise caddr_t is not defined correctly\r
- */\r
-\r
-#include <X11/Intrinsic.h>\r
-\r
-#ifdef STANDALONE\r
-# define PROGCLASS                                     "Klein"\r
-# define HACK_INIT                                     init_klein\r
-# define HACK_DRAW                                     draw_klein\r
-# define HACK_RESHAPE                          reshape_klein\r
-# define HACK_HANDLE_EVENT                     klein_handle_event\r
-# define EVENT_MASK                                    PointerMotionMask\r
-# define klein_opts                                    xlockmore_opts\r
-\r
-\r
-#define DEF_SPIN                               "True"\r
-#define DEF_WANDER                             "False"\r
-#define DEF_RANDOM                             "False"\r
-#define DEF_SPEED                              "150"\r
-\r
-# define DEFAULTS                                      "*delay:                20000   \n"                     \\r
-                                                                       "*showFPS:      False   \n"                     \\r
-                                                                       "*wireframe:    False   \n"                     \\r
-                                                                       "*random:          " DEF_RANDOM     "\n"        \\r
-                                                                       "*speed:           " DEF_SPEED     "\n" \\r
-                                                                       "*spin:        " DEF_SPIN      "\n" \\r
-                                                                       "*wander:      " DEF_WANDER    "\n" \\r
-\r
-# include "xlockmore.h"                /* from the xscreensaver distribution */\r
-#else  /* !STANDALONE */\r
-# include "xlock.h"                    /* from the xlockmore distribution */\r
-#endif /* !STANDALONE */\r
-\r
-#ifdef USE_GL\r
-\r
-#include <GL/glu.h>\r
-#include "rotator.h"\r
-#include "gltrackball.h"\r
-\r
-#undef countof\r
-#define countof(x) (sizeof((x))/sizeof((*x)))\r
-\r
-/* surfaces being drawn */\r
-enum { \r
-       KLEIN = 0,\r
-       DINI,\r
-       ENNEPER,\r
-       KUEN,\r
-       MOEBIUS,\r
-       SEASHELL,\r
-       SWALLOWTAIL,\r
-       BOHEM,\r
-    SURFACE_LAST,\r
-};\r
-\r
-/* primitives to draw with \r
- * note that we skip the polygons and\r
- * triangle fans -- too slow\r
- *\r
- * also removed triangle_strip and quads -- \r
- * just doesn't look good enough\r
- */\r
-enum {\r
-       MY_POINTS = 0,\r
-       MY_LINES,\r
-       MY_LINE_LOOP,\r
-       MY_PRIM_LAST,\r
-};\r
-\r
-\r
-static Bool rand;\r
-static int render;\r
-static int speed;\r
-static Bool do_spin;\r
-static Bool do_wander;\r
-\r
-static XrmOptionDescRec opts[] = {\r
-  {"-speed",   ".speed",    XrmoptionSepArg, (caddr_t) 0 },\r
-  { "-spin",   ".spin",   XrmoptionNoArg, "True" },\r
-  { "+spin",   ".spin",   XrmoptionNoArg, "False" },\r
-  { "-wander", ".wander", XrmoptionNoArg, "True" },\r
-  { "+wander", ".wander", XrmoptionNoArg, "False" },\r
-  { "-random", ".rand", XrmoptionNoArg, "True" },\r
-  { "+random", ".rand", XrmoptionNoArg, "False" },\r
-};\r
-\r
-static argtype vars[] = {\r
-  {(caddr_t *) &rand,   "rand",   "Random",   DEF_RANDOM,   t_Bool},\r
-  {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},\r
-  {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},\r
-  {(caddr_t *) &speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},\r
-};\r
-\r
-\r
-ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};\r
-\r
-\r
-\r
-typedef struct{\r
-  GLfloat x;\r
-  GLfloat y;\r
-  GLfloat z;\r
-} GL_VECTOR;\r
-\r
-typedef struct {\r
-       GLXContext *glx_context;\r
-       Window      window;\r
-       rotator    *rot;\r
-       trackball_state *trackball;\r
-       Bool              button_down_p;\r
-\r
-       int render;\r
-       int surface;\r
-\r
-       float du, dv;\r
-       float a, b, c;\r
-\r
-} kleinstruct;\r
-\r
-static kleinstruct *klein = NULL;\r
-\r
-\r
-static void\r
-draw(ModeInfo *mi)\r
-{\r
-       kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
-       static float step = 0.0;\r
-       double u, v;\r
-       float coord[3];\r
-       \r
-       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
-\r
-       glEnable(GL_DEPTH_TEST);\r
-       glEnable(GL_NORMALIZE);\r
-       glEnable(GL_CULL_FACE);\r
-\r
-       glPushMatrix();\r
-\r
-       {\r
-               double x, y, z;\r
-               get_position (kp->rot, &x, &y, &z, !kp->button_down_p);\r
-               glTranslatef((x - 0.5) * 10,\r
-                                                                (y - 0.5) * 10,\r
-                                                                (z - 0.5) * 20);\r
-\r
-               gltrackball_rotate (kp->trackball);\r
-\r
-               get_rotation (kp->rot, &x, &y, &z, !kp->button_down_p);\r
-               glRotatef (x * 360, 1.0, 0.0, 0.0);\r
-               glRotatef (y * 360, 0.0, 1.0, 0.0);\r
-               glRotatef (z * 360, 0.0, 0.0, 1.0);\r
-       }\r
-\r
-       glScalef( 4.0, 4.0, 4.0 );\r
-\r
-       glBegin(kp->render);\r
-       switch(kp->surface) {\r
-       case KLEIN:\r
-               for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                       for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                               coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -\r
-                                                       sin(2*v)*sin(u/2)/2);\r
-                               coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -\r
-                                                       sin(2*v)*sin(u/2)/2);\r
-                               coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;\r
-                               glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                               glVertex3fv(coord);\r
-                       }\r
-               }\r
-               break;\r
-               case DINI:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = kp->a*cos(u)*sin(v);\r
-                                       coord[1] = kp->a*sin(u)*sin(v);\r
-                                       coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case ENNEPER:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);\r
-                                       coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);\r
-                                       coord[2] = u*u-v*v;\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case KUEN:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));\r
-                                       coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));\r
-                                       coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));\r
-\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case MOEBIUS:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = cos(u)+v*cos(u/2)*cos(u);\r
-                                       coord[1] = sin(u)+v*cos(u/2)*sin(u);\r
-                                       coord[2] = v*sin(u/2);\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case SEASHELL:\r
-                       for(u = 0; u < 2*M_PI; u+=kp->du){\r
-                               for(v = 0; v < 2*M_PI; v+=kp->dv){\r
-                                       coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);\r
-                                       coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);\r
-                                       coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case SWALLOWTAIL:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = u*pow(v,2) + 3*pow(v,4);\r
-                                       coord[1] = -2*u*v - 4*pow(v,3);\r
-                                       coord[2] = u;\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               case BOHEM:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = kp->a*cos(u);\r
-                                       coord[1] = 1.5*cos(v) + kp->a*sin(u);\r
-                                       coord[2] = sin(v);\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-               default:\r
-                       for(u = -M_PI; u < M_PI; u+=kp->du){\r
-                               for(v = -M_PI; v < M_PI; v+=kp->dv){\r
-                                       coord[0] = sin(u)*kp->a;        \r
-                                       coord[1] = cos(u)*kp->a;\r
-                                       coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);\r
-                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
-                                       glVertex3fv(coord);\r
-                               }\r
-                       }\r
-                       break;\r
-       }\r
-       glEnd();\r
-       glPopMatrix();\r
-\r
-\r
-       kp->a = sin(step+=0.01);\r
-       kp->b = cos(step+=0.01);\r
-}\r
-\r
-\r
-/* new window size or exposure */\r
-void\r
-reshape_klein(ModeInfo *mi, int width, int height)\r
-{\r
-       GLfloat h = (GLfloat) height / (GLfloat) width;\r
-\r
-       glViewport(0, 0, (GLint) width, (GLint) height);\r
-       glMatrixMode(GL_PROJECTION);\r
-       glLoadIdentity();\r
-       gluPerspective (30.0, 1/h, 1.0, 100.0);\r
-\r
-       glMatrixMode(GL_MODELVIEW);\r
-       glLoadIdentity();\r
-       gluLookAt( 0.0, 0.0, 30.0,\r
-                        0.0, 0.0, 0.0,\r
-                        0.0, 1.0, 0.0);\r
-       \r
-       glClear(GL_COLOR_BUFFER_BIT);\r
-}\r
-\r
-\r
-Bool\r
-klein_handle_event (ModeInfo *mi, XEvent *event)\r
-{\r
-       kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
-\r
-       if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {\r
-                       kp->button_down_p = True;\r
-                       gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));\r
-                       return True;\r
-       } else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {\r
-                       kp->button_down_p = False;\r
-                       return True;\r
-       } else if (event->xany.type == MotionNotify && kp->button_down_p) {\r
-                       gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));\r
-                       return True;\r
-       }\r
-\r
-       return False;\r
-}\r
-\r
-\r
-void\r
-init_klein(ModeInfo *mi)\r
-{\r
-       int      screen = MI_SCREEN(mi);\r
-       kleinstruct *kp;\r
-\r
-       if (klein == NULL) {\r
-               if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)\r
-                       return;\r
-       }\r
-       kp = &klein[screen];\r
-\r
-       kp->window = MI_WINDOW(mi);\r
-\r
-       {\r
-               double spin_speed        = 1.0;\r
-               double wander_speed = 0.03;\r
-               kp->rot = make_rotator (do_spin ? spin_speed : 0,\r
-                                               do_spin ? spin_speed : 0,\r
-                                               do_spin ? spin_speed : 0,\r
-                                               1.0,\r
-                                               do_wander ? wander_speed : 0,\r
-                                               True);\r
-               kp->trackball = gltrackball_init ();\r
-       }\r
-\r
-       if(rand) {\r
-               render = random() % MY_PRIM_LAST;\r
-               kp->surface = random() % SURFACE_LAST;\r
-       } else {\r
-               render = MY_LINE_LOOP;\r
-               kp->surface = KLEIN;\r
-       }\r
-\r
-       switch (render) {\r
-       case MY_POINTS: kp->render = GL_POINTS; break;\r
-       case MY_LINES: kp->render = GL_LINES; break;\r
-       case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;\r
-       default:\r
-                       kp->render = GL_LINE_LOOP;\r
-       }\r
-/*kp->render=GL_TRIANGLE_FAN;*/\r
-/*kp->render=GL_POLYGON;*/\r
-\r
-       kp->du = 0.07;\r
-       kp->dv = 0.07;\r
-       kp->a = kp->b = 1;\r
-       kp->c = 0.1;\r
-\r
-\r
-       if ((kp->glx_context = init_GL(mi)) != NULL) {\r
-               reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));\r
-       } else {\r
-               MI_CLEARWINDOW(mi);\r
-       }\r
-}\r
-\r
-void\r
-draw_klein(ModeInfo * mi)\r
-{\r
-       kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
-       Display *display = MI_DISPLAY(mi);\r
-       Window  window = MI_WINDOW(mi);\r
-\r
-       if (!kp->glx_context) return;\r
-\r
-       glDrawBuffer(GL_BACK);\r
-\r
-       glXMakeCurrent(display, window, *(kp->glx_context));\r
-       draw(mi);\r
-       if (mi->fps_p) do_fps (mi);\r
-       glFinish();\r
-       glXSwapBuffers(display, window);\r
-}\r
-\r
-void\r
-release_klein(ModeInfo * mi)\r
-{\r
-       if (klein != NULL) {\r
-               int      screen;\r
-\r
-               for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {\r
-                       kleinstruct *kp = &klein[screen];\r
-\r
-                       if (kp->glx_context) {\r
-                               /* Display lists MUST be freed while their glXContext is current. */\r
-                               glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));\r
-                       }\r
-               }\r
-               (void) free((void *) klein);\r
-               klein = NULL;\r
-       }\r
-       FreeAllGL(mi);\r
-}\r
-\r
-\r
-/*********************************************************/\r
-\r
-#endif\r
+/* -*- Mode: C; tab-width: 4 -*- */
+/* Klein --- Klein Bottle, Moebius and other parametric surfaces
+ * visualization */
+
+/*
+ * Revision History:
+ * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca
+ *       
+ * 01-Mar-2003  mirtchov    modified as a xscreensaver hack
+ *
+ */
+
+/*-
+ * 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                                     "Klein"
+# define HACK_INIT                                     init_klein
+# define HACK_DRAW                                     draw_klein
+# define HACK_RESHAPE                          reshape_klein
+# define HACK_HANDLE_EVENT                     klein_handle_event
+# define EVENT_MASK                                    PointerMotionMask
+# define klein_opts                                    xlockmore_opts
+
+
+#define DEF_SPIN                               "True"
+#define DEF_WANDER                             "False"
+#define DEF_RANDOM                             "False"
+#define DEF_SPEED                              "150"
+
+# define DEFAULTS                                      "*delay:                20000   \n"                     \
+                                                                       "*showFPS:      False   \n"                     \
+                                                                       "*wireframe:    False   \n"                     \
+                                                                       "*random:          " DEF_RANDOM     "\n"        \
+                                                                       "*speed:           " DEF_SPEED     "\n" \
+                                                                       "*spin:        " DEF_SPIN      "\n" \
+                                                                       "*wander:      " DEF_WANDER    "\n" \
+
+# include "xlockmore.h"                /* from the xscreensaver distribution */
+#else  /* !STANDALONE */
+# include "xlock.h"                    /* from the xlockmore distribution */
+#endif /* !STANDALONE */
+
+#ifdef USE_GL
+
+#include <GL/glu.h>
+#include "rotator.h"
+#include "gltrackball.h"
+
+#undef countof
+#define countof(x) (sizeof((x))/sizeof((*x)))
+
+/* surfaces being drawn */
+enum { 
+       KLEIN = 0,
+       DINI,
+       ENNEPER,
+       KUEN,
+       MOEBIUS,
+       SEASHELL,
+       SWALLOWTAIL,
+       BOHEM,
+    SURFACE_LAST,
+};
+
+/* primitives to draw with 
+ * note that we skip the polygons and
+ * triangle fans -- too slow
+ *
+ * also removed triangle_strip and quads -- 
+ * just doesn't look good enough
+ */
+enum {
+       MY_POINTS = 0,
+       MY_LINES,
+       MY_LINE_LOOP,
+       MY_PRIM_LAST,
+};
+
+
+static Bool rand;
+static int render;
+static int speed;
+static Bool do_spin;
+static Bool do_wander;
+
+static XrmOptionDescRec opts[] = {
+  {"-speed",   ".speed",    XrmoptionSepArg, (caddr_t) 0 },
+  { "-spin",   ".spin",   XrmoptionNoArg, "True" },
+  { "+spin",   ".spin",   XrmoptionNoArg, "False" },
+  { "-wander", ".wander", XrmoptionNoArg, "True" },
+  { "+wander", ".wander", XrmoptionNoArg, "False" },
+  { "-random", ".rand", XrmoptionNoArg, "True" },
+  { "+random", ".rand", XrmoptionNoArg, "False" },
+};
+
+static argtype vars[] = {
+  {(caddr_t *) &rand,   "rand",   "Random",   DEF_RANDOM,   t_Bool},
+  {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},
+  {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
+  {(caddr_t *) &speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},
+};
+
+
+ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};
+
+
+
+typedef struct{
+  GLfloat x;
+  GLfloat y;
+  GLfloat z;
+} GL_VECTOR;
+
+typedef struct {
+       GLXContext *glx_context;
+       Window      window;
+       rotator    *rot;
+       trackball_state *trackball;
+       Bool              button_down_p;
+
+       int render;
+       int surface;
+
+       float du, dv;
+       float a, b, c;
+
+} kleinstruct;
+
+static kleinstruct *klein = NULL;
+
+
+static void
+draw(ModeInfo *mi)
+{
+       kleinstruct *kp = &klein[MI_SCREEN(mi)];
+       static float step = 0.0;
+       double u, v;
+       float coord[3];
+       
+       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+       glEnable(GL_DEPTH_TEST);
+       glEnable(GL_NORMALIZE);
+       glEnable(GL_CULL_FACE);
+
+       glPushMatrix();
+
+       {
+               double x, y, z;
+               get_position (kp->rot, &x, &y, &z, !kp->button_down_p);
+               glTranslatef((x - 0.5) * 10,
+                                                                (y - 0.5) * 10,
+                                                                (z - 0.5) * 20);
+
+               gltrackball_rotate (kp->trackball);
+
+               get_rotation (kp->rot, &x, &y, &z, !kp->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);
+       }
+
+       glScalef( 4.0, 4.0, 4.0 );
+
+       glBegin(kp->render);
+       switch(kp->surface) {
+       case KLEIN:
+               for(u = -M_PI; u < M_PI; u+=kp->du){
+                       for(v = -M_PI; v < M_PI; v+=kp->dv){
+                               coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -
+                                                       sin(2*v)*sin(u/2)/2);
+                               coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -
+                                                       sin(2*v)*sin(u/2)/2);
+                               coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;
+                               glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                               glVertex3fv(coord);
+                       }
+               }
+               break;
+               case DINI:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = kp->a*cos(u)*sin(v);
+                                       coord[1] = kp->a*sin(u)*sin(v);
+                                       coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case ENNEPER:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);
+                                       coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);
+                                       coord[2] = u*u-v*v;
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case KUEN:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));
+                                       coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));
+                                       coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));
+
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case MOEBIUS:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = cos(u)+v*cos(u/2)*cos(u);
+                                       coord[1] = sin(u)+v*cos(u/2)*sin(u);
+                                       coord[2] = v*sin(u/2);
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case SEASHELL:
+                       for(u = 0; u < 2*M_PI; u+=kp->du){
+                               for(v = 0; v < 2*M_PI; v+=kp->dv){
+                                       coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);
+                                       coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);
+                                       coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case SWALLOWTAIL:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = u*pow(v,2) + 3*pow(v,4);
+                                       coord[1] = -2*u*v - 4*pow(v,3);
+                                       coord[2] = u;
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               case BOHEM:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = kp->a*cos(u);
+                                       coord[1] = 1.5*cos(v) + kp->a*sin(u);
+                                       coord[2] = sin(v);
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+               default:
+                       for(u = -M_PI; u < M_PI; u+=kp->du){
+                               for(v = -M_PI; v < M_PI; v+=kp->dv){
+                                       coord[0] = sin(u)*kp->a;        
+                                       coord[1] = cos(u)*kp->a;
+                                       coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);
+                                       glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
+                                       glVertex3fv(coord);
+                               }
+                       }
+                       break;
+       }
+       glEnd();
+       glPopMatrix();
+
+
+       kp->a = sin(step+=0.01);
+       kp->b = cos(step+=0.01);
+}
+
+
+/* new window size or exposure */
+void
+reshape_klein(ModeInfo *mi, int width, int height)
+{
+       GLfloat h = (GLfloat) height / (GLfloat) width;
+
+       glViewport(0, 0, (GLint) width, (GLint) height);
+       glMatrixMode(GL_PROJECTION);
+       glLoadIdentity();
+       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);
+       
+       glClear(GL_COLOR_BUFFER_BIT);
+}
+
+
+Bool
+klein_handle_event (ModeInfo *mi, XEvent *event)
+{
+       kleinstruct *kp = &klein[MI_SCREEN(mi)];
+
+       if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {
+                       kp->button_down_p = True;
+                       gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
+                       return True;
+       } else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {
+                       kp->button_down_p = False;
+                       return True;
+       } else if (event->xany.type == MotionNotify && kp->button_down_p) {
+                       gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
+                       return True;
+       }
+
+       return False;
+}
+
+
+void
+init_klein(ModeInfo *mi)
+{
+       int      screen = MI_SCREEN(mi);
+       kleinstruct *kp;
+
+       if (klein == NULL) {
+               if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)
+                       return;
+       }
+       kp = &klein[screen];
+
+       kp->window = MI_WINDOW(mi);
+
+       {
+               double spin_speed        = 1.0;
+               double wander_speed = 0.03;
+               kp->rot = make_rotator (do_spin ? spin_speed : 0,
+                                               do_spin ? spin_speed : 0,
+                                               do_spin ? spin_speed : 0,
+                                               1.0,
+                                               do_wander ? wander_speed : 0,
+                                               True);
+               kp->trackball = gltrackball_init ();
+       }
+
+       if(rand) {
+               render = random() % MY_PRIM_LAST;
+               kp->surface = random() % SURFACE_LAST;
+       } else {
+               render = MY_LINE_LOOP;
+               kp->surface = KLEIN;
+       }
+
+       switch (render) {
+       case MY_POINTS: kp->render = GL_POINTS; break;
+       case MY_LINES: kp->render = GL_LINES; break;
+       case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;
+       default:
+                       kp->render = GL_LINE_LOOP;
+       }
+/*kp->render=GL_TRIANGLE_FAN;*/
+/*kp->render=GL_POLYGON;*/
+
+       kp->du = 0.07;
+       kp->dv = 0.07;
+       kp->a = kp->b = 1;
+       kp->c = 0.1;
+
+
+       if ((kp->glx_context = init_GL(mi)) != NULL) {
+               reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
+       } else {
+               MI_CLEARWINDOW(mi);
+       }
+}
+
+void
+draw_klein(ModeInfo * mi)
+{
+       kleinstruct *kp = &klein[MI_SCREEN(mi)];
+       Display *display = MI_DISPLAY(mi);
+       Window  window = MI_WINDOW(mi);
+
+       if (!kp->glx_context) return;
+
+       glDrawBuffer(GL_BACK);
+
+       glXMakeCurrent(display, window, *(kp->glx_context));
+       draw(mi);
+       if (mi->fps_p) do_fps (mi);
+       glFinish();
+       glXSwapBuffers(display, window);
+}
+
+void
+release_klein(ModeInfo * mi)
+{
+       if (klein != NULL) {
+               int      screen;
+
+               for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
+                       kleinstruct *kp = &klein[screen];
+
+                       if (kp->glx_context) {
+                               /* Display lists MUST be freed while their glXContext is current. */
+                               glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));
+                       }
+               }
+               (void) free((void *) klein);
+               klein = NULL;
+       }
+       FreeAllGL(mi);
+}
+
+
+/*********************************************************/
+
+#endif