http://www.archive.org/download/tucows_10294_XScreenSaver/xscreensaver-4.10.tar.gz
[xscreensaver] / hacks / glx / klein.c
1 /* -*- Mode: C; tab-width: 4 -*- */\r
2 /* Klein --- Klein Bottle, Moebius and other parametric surfaces\r
3  * visualization */\r
4 \r
5 /*\r
6  * Revision History:\r
7  * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca\r
8  *       \r
9  * 01-Mar-2003  mirtchov    modified as a xscreensaver hack\r
10  *\r
11  */\r
12 \r
13 /*-\r
14  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.\r
15  * otherwise caddr_t is not defined correctly\r
16  */\r
17 \r
18 #include <X11/Intrinsic.h>\r
19 \r
20 #ifdef STANDALONE\r
21 # define PROGCLASS                                      "Klein"\r
22 # define HACK_INIT                                      init_klein\r
23 # define HACK_DRAW                                      draw_klein\r
24 # define HACK_RESHAPE                           reshape_klein\r
25 # define HACK_HANDLE_EVENT                      klein_handle_event\r
26 # define EVENT_MASK                                     PointerMotionMask\r
27 # define klein_opts                                     xlockmore_opts\r
28 \r
29 \r
30 #define DEF_SPIN                                "True"\r
31 #define DEF_WANDER                              "False"\r
32 #define DEF_RANDOM                              "False"\r
33 #define DEF_SPEED                               "150"\r
34 \r
35 # define DEFAULTS                                       "*delay:                20000   \n"                     \\r
36                                                                         "*showFPS:      False   \n"                     \\r
37                                                                         "*wireframe:    False   \n"                     \\r
38                                                                         "*random:          " DEF_RANDOM     "\n"        \\r
39                                                                         "*speed:           " DEF_SPEED     "\n" \\r
40                                                                         "*spin:        " DEF_SPIN      "\n" \\r
41                                                                         "*wander:      " DEF_WANDER    "\n" \\r
42 \r
43 # include "xlockmore.h"         /* from the xscreensaver distribution */\r
44 #else  /* !STANDALONE */\r
45 # include "xlock.h"                     /* from the xlockmore distribution */\r
46 #endif /* !STANDALONE */\r
47 \r
48 #ifdef USE_GL\r
49 \r
50 #include <GL/glu.h>\r
51 #include "rotator.h"\r
52 #include "gltrackball.h"\r
53 \r
54 #undef countof\r
55 #define countof(x) (sizeof((x))/sizeof((*x)))\r
56 \r
57 /* surfaces being drawn */\r
58 enum { \r
59         KLEIN = 0,\r
60         DINI,\r
61         ENNEPER,\r
62         KUEN,\r
63         MOEBIUS,\r
64         SEASHELL,\r
65         SWALLOWTAIL,\r
66         BOHEM,\r
67     SURFACE_LAST,\r
68 };\r
69 \r
70 /* primitives to draw with \r
71  * note that we skip the polygons and\r
72  * triangle fans -- too slow\r
73  *\r
74  * also removed triangle_strip and quads -- \r
75  * just doesn't look good enough\r
76  */\r
77 enum {\r
78         MY_POINTS = 0,\r
79         MY_LINES,\r
80         MY_LINE_LOOP,\r
81         MY_PRIM_LAST,\r
82 };\r
83 \r
84 \r
85 static Bool rand;\r
86 static int render;\r
87 static int speed;\r
88 static Bool do_spin;\r
89 static Bool do_wander;\r
90 \r
91 static XrmOptionDescRec opts[] = {\r
92   {"-speed",   ".speed",    XrmoptionSepArg, (caddr_t) 0 },\r
93   { "-spin",   ".spin",   XrmoptionNoArg, "True" },\r
94   { "+spin",   ".spin",   XrmoptionNoArg, "False" },\r
95   { "-wander", ".wander", XrmoptionNoArg, "True" },\r
96   { "+wander", ".wander", XrmoptionNoArg, "False" },\r
97   { "-random", ".rand", XrmoptionNoArg, "True" },\r
98   { "+random", ".rand", XrmoptionNoArg, "False" },\r
99 };\r
100 \r
101 static argtype vars[] = {\r
102   {(caddr_t *) &rand,   "rand",   "Random",   DEF_RANDOM,   t_Bool},\r
103   {(caddr_t *) &do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},\r
104   {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},\r
105   {(caddr_t *) &speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},\r
106 };\r
107 \r
108 \r
109 ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};\r
110 \r
111 \r
112 \r
113 typedef struct{\r
114   GLfloat x;\r
115   GLfloat y;\r
116   GLfloat z;\r
117 } GL_VECTOR;\r
118 \r
119 typedef struct {\r
120         GLXContext *glx_context;\r
121         Window      window;\r
122         rotator    *rot;\r
123         trackball_state *trackball;\r
124         Bool              button_down_p;\r
125 \r
126         int render;\r
127         int surface;\r
128 \r
129         float du, dv;\r
130         float a, b, c;\r
131 \r
132 } kleinstruct;\r
133 \r
134 static kleinstruct *klein = NULL;\r
135 \r
136 \r
137 static void\r
138 draw(ModeInfo *mi)\r
139 {\r
140         kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
141         static float step = 0.0;\r
142         double u, v;\r
143         float coord[3];\r
144         \r
145         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);\r
146 \r
147         glEnable(GL_DEPTH_TEST);\r
148         glEnable(GL_NORMALIZE);\r
149         glEnable(GL_CULL_FACE);\r
150 \r
151         glPushMatrix();\r
152 \r
153         {\r
154                 double x, y, z;\r
155                 get_position (kp->rot, &x, &y, &z, !kp->button_down_p);\r
156                 glTranslatef((x - 0.5) * 10,\r
157                                                                  (y - 0.5) * 10,\r
158                                                                  (z - 0.5) * 20);\r
159 \r
160                 gltrackball_rotate (kp->trackball);\r
161 \r
162                 get_rotation (kp->rot, &x, &y, &z, !kp->button_down_p);\r
163                 glRotatef (x * 360, 1.0, 0.0, 0.0);\r
164                 glRotatef (y * 360, 0.0, 1.0, 0.0);\r
165                 glRotatef (z * 360, 0.0, 0.0, 1.0);\r
166         }\r
167 \r
168         glScalef( 4.0, 4.0, 4.0 );\r
169 \r
170         glBegin(kp->render);\r
171         switch(kp->surface) {\r
172         case KLEIN:\r
173                 for(u = -M_PI; u < M_PI; u+=kp->du){\r
174                         for(v = -M_PI; v < M_PI; v+=kp->dv){\r
175                                 coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -\r
176                                                         sin(2*v)*sin(u/2)/2);\r
177                                 coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -\r
178                                                         sin(2*v)*sin(u/2)/2);\r
179                                 coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;\r
180                                 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
181                                 glVertex3fv(coord);\r
182                         }\r
183                 }\r
184                 break;\r
185                 case DINI:\r
186                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
187                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
188                                         coord[0] = kp->a*cos(u)*sin(v);\r
189                                         coord[1] = kp->a*sin(u)*sin(v);\r
190                                         coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;\r
191                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
192                                         glVertex3fv(coord);\r
193                                 }\r
194                         }\r
195                         break;\r
196                 case ENNEPER:\r
197                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
198                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
199                                         coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);\r
200                                         coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);\r
201                                         coord[2] = u*u-v*v;\r
202                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
203                                         glVertex3fv(coord);\r
204                                 }\r
205                         }\r
206                         break;\r
207                 case KUEN:\r
208                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
209                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
210                                         coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));\r
211                                         coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));\r
212                                         coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));\r
213 \r
214                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
215                                         glVertex3fv(coord);\r
216                                 }\r
217                         }\r
218                         break;\r
219                 case MOEBIUS:\r
220                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
221                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
222                                         coord[0] = cos(u)+v*cos(u/2)*cos(u);\r
223                                         coord[1] = sin(u)+v*cos(u/2)*sin(u);\r
224                                         coord[2] = v*sin(u/2);\r
225                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
226                                         glVertex3fv(coord);\r
227                                 }\r
228                         }\r
229                         break;\r
230                 case SEASHELL:\r
231                         for(u = 0; u < 2*M_PI; u+=kp->du){\r
232                                 for(v = 0; v < 2*M_PI; v+=kp->dv){\r
233                                         coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);\r
234                                         coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);\r
235                                         coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);\r
236                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
237                                         glVertex3fv(coord);\r
238                                 }\r
239                         }\r
240                         break;\r
241                 case SWALLOWTAIL:\r
242                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
243                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
244                                         coord[0] = u*pow(v,2) + 3*pow(v,4);\r
245                                         coord[1] = -2*u*v - 4*pow(v,3);\r
246                                         coord[2] = u;\r
247                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
248                                         glVertex3fv(coord);\r
249                                 }\r
250                         }\r
251                         break;\r
252                 case BOHEM:\r
253                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
254                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
255                                         coord[0] = kp->a*cos(u);\r
256                                         coord[1] = 1.5*cos(v) + kp->a*sin(u);\r
257                                         coord[2] = sin(v);\r
258                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
259                                         glVertex3fv(coord);\r
260                                 }\r
261                         }\r
262                         break;\r
263                 default:\r
264                         for(u = -M_PI; u < M_PI; u+=kp->du){\r
265                                 for(v = -M_PI; v < M_PI; v+=kp->dv){\r
266                                         coord[0] = sin(u)*kp->a;        \r
267                                         coord[1] = cos(u)*kp->a;\r
268                                         coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);\r
269                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);\r
270                                         glVertex3fv(coord);\r
271                                 }\r
272                         }\r
273                         break;\r
274         }\r
275         glEnd();\r
276         glPopMatrix();\r
277 \r
278 \r
279         kp->a = sin(step+=0.01);\r
280         kp->b = cos(step+=0.01);\r
281 }\r
282 \r
283 \r
284 /* new window size or exposure */\r
285 void\r
286 reshape_klein(ModeInfo *mi, int width, int height)\r
287 {\r
288         GLfloat h = (GLfloat) height / (GLfloat) width;\r
289 \r
290         glViewport(0, 0, (GLint) width, (GLint) height);\r
291         glMatrixMode(GL_PROJECTION);\r
292         glLoadIdentity();\r
293         gluPerspective (30.0, 1/h, 1.0, 100.0);\r
294 \r
295         glMatrixMode(GL_MODELVIEW);\r
296         glLoadIdentity();\r
297         gluLookAt( 0.0, 0.0, 30.0,\r
298                          0.0, 0.0, 0.0,\r
299                          0.0, 1.0, 0.0);\r
300         \r
301         glClear(GL_COLOR_BUFFER_BIT);\r
302 }\r
303 \r
304 \r
305 Bool\r
306 klein_handle_event (ModeInfo *mi, XEvent *event)\r
307 {\r
308         kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
309 \r
310         if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {\r
311                         kp->button_down_p = True;\r
312                         gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));\r
313                         return True;\r
314         } else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {\r
315                         kp->button_down_p = False;\r
316                         return True;\r
317         } else if (event->xany.type == MotionNotify && kp->button_down_p) {\r
318                         gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));\r
319                         return True;\r
320         }\r
321 \r
322         return False;\r
323 }\r
324 \r
325 \r
326 void\r
327 init_klein(ModeInfo *mi)\r
328 {\r
329         int      screen = MI_SCREEN(mi);\r
330         kleinstruct *kp;\r
331 \r
332         if (klein == NULL) {\r
333                 if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)\r
334                         return;\r
335         }\r
336         kp = &klein[screen];\r
337 \r
338         kp->window = MI_WINDOW(mi);\r
339 \r
340         {\r
341                 double spin_speed        = 1.0;\r
342                 double wander_speed = 0.03;\r
343                 kp->rot = make_rotator (do_spin ? spin_speed : 0,\r
344                                                 do_spin ? spin_speed : 0,\r
345                                                 do_spin ? spin_speed : 0,\r
346                                                 1.0,\r
347                                                 do_wander ? wander_speed : 0,\r
348                                                 True);\r
349                 kp->trackball = gltrackball_init ();\r
350         }\r
351 \r
352         if(rand) {\r
353                 render = random() % MY_PRIM_LAST;\r
354                 kp->surface = random() % SURFACE_LAST;\r
355         } else {\r
356                 render = MY_LINE_LOOP;\r
357                 kp->surface = KLEIN;\r
358         }\r
359 \r
360         switch (render) {\r
361         case MY_POINTS: kp->render = GL_POINTS; break;\r
362         case MY_LINES: kp->render = GL_LINES; break;\r
363         case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;\r
364         default:\r
365                         kp->render = GL_LINE_LOOP;\r
366         }\r
367 /*kp->render=GL_TRIANGLE_FAN;*/\r
368 /*kp->render=GL_POLYGON;*/\r
369 \r
370         kp->du = 0.07;\r
371         kp->dv = 0.07;\r
372         kp->a = kp->b = 1;\r
373         kp->c = 0.1;\r
374 \r
375 \r
376         if ((kp->glx_context = init_GL(mi)) != NULL) {\r
377                 reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));\r
378         } else {\r
379                 MI_CLEARWINDOW(mi);\r
380         }\r
381 }\r
382 \r
383 void\r
384 draw_klein(ModeInfo * mi)\r
385 {\r
386         kleinstruct *kp = &klein[MI_SCREEN(mi)];\r
387         Display *display = MI_DISPLAY(mi);\r
388         Window  window = MI_WINDOW(mi);\r
389 \r
390         if (!kp->glx_context) return;\r
391 \r
392         glDrawBuffer(GL_BACK);\r
393 \r
394         glXMakeCurrent(display, window, *(kp->glx_context));\r
395         draw(mi);\r
396         if (mi->fps_p) do_fps (mi);\r
397         glFinish();\r
398         glXSwapBuffers(display, window);\r
399 }\r
400 \r
401 void\r
402 release_klein(ModeInfo * mi)\r
403 {\r
404         if (klein != NULL) {\r
405                 int      screen;\r
406 \r
407                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {\r
408                         kleinstruct *kp = &klein[screen];\r
409 \r
410                         if (kp->glx_context) {\r
411                                 /* Display lists MUST be freed while their glXContext is current. */\r
412                                 glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));\r
413                         }\r
414                 }\r
415                 (void) free((void *) klein);\r
416                 klein = NULL;\r
417         }\r
418         FreeAllGL(mi);\r
419 }\r
420 \r
421 \r
422 /*********************************************************/\r
423 \r
424 #endif\r