-/* -*- 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