1 /* Surface --- Parametric 3d surfaces visualization */
5 * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca>
7 * 01-Mar-2003 mirtchov Modified as a xscreensaver hack.
8 * 01-jan-2009 steger Renamed from klein.c to surfaces.c.
9 * Removed the Klein bottle.
10 * Added many new surfaces.
11 * Added many command line options.
15 /* surfaces to draw */
16 #define SURFACE_RANDOM -1
17 #define SURFACE_DINI 0
18 #define SURFACE_ENNEPER 1
19 #define SURFACE_KUEN 2
20 #define SURFACE_MOEBIUS 3
21 #define SURFACE_SEASHELL 4
22 #define SURFACE_SWALLOWTAIL 5
23 #define SURFACE_BOHEMIAN 6
24 #define SURFACE_WHITNEY 7
25 #define SURFACE_PLUECKER 8
26 #define SURFACE_HENNEBERG 9
27 #define SURFACE_CATALAN 10
28 #define SURFACE_CORKSCREW 11
29 #define NUM_SURFACES 12
31 /* primitives to draw with
32 * note that we skip the polygons and
33 * triangle fans -- too slow
35 * also removed triangle_strip and quads --
36 * just doesn't look good enough
38 #define RENDER_RANDOM -1
39 #define RENDER_POINTS 0
40 #define RENDER_LINES 1
41 #define RENDER_LINE_LOOP 2
45 # define DEFAULTS "*delay: 20000 \n" \
48 # define refresh_surface 0
49 # include "xlockmore.h" /* from the xscreensaver distribution */
50 #else /* !STANDALONE */
51 # include "xlock.h" /* from the xlockmore distribution */
52 #endif /* !STANDALONE */
56 #define DEF_SURFACE "random"
57 #define DEF_MODE "random"
58 #define DEF_SPIN "True"
59 #define DEF_WANDER "False"
60 #define DEF_SPEED "300"
63 #include "gltrackball.h"
66 #define countof(x) (sizeof((x))/sizeof((*x)))
69 static char *surface_type;
70 static char *render_mode;
74 static Bool do_wander;
76 static XrmOptionDescRec opts[] = {
77 { "-surface", ".surface", XrmoptionSepArg, 0 },
78 { "-random-surface", ".surface", XrmoptionNoArg, "random" },
79 { "-dini", ".surface", XrmoptionNoArg, "dini" },
80 { "-enneper", ".surface", XrmoptionNoArg, "enneper" },
81 { "-kuen", ".surface", XrmoptionNoArg, "kuen" },
82 { "-moebius", ".surface", XrmoptionNoArg, "moebius" },
83 { "-seashell", ".surface", XrmoptionNoArg, "seashell" },
84 { "-swallowtail", ".surface", XrmoptionNoArg, "swallowtail" },
85 { "-bohemian", ".surface", XrmoptionNoArg, "bohemian" },
86 { "-whitney", ".surface", XrmoptionNoArg, "whitney" },
87 { "-pluecker", ".surface", XrmoptionNoArg, "pluecker" },
88 { "-henneberg", ".surface", XrmoptionNoArg, "henneberg" },
89 { "-catalan", ".surface", XrmoptionNoArg, "catalan" },
90 { "-corkscrew", ".surface", XrmoptionNoArg, "corkscrew" },
91 { "-mode", ".mode", XrmoptionSepArg, 0 },
92 { "-random-mode", ".mode", XrmoptionNoArg, "random" },
93 { "-points", ".mode", XrmoptionNoArg, "points" },
94 { "-lines", ".mode", XrmoptionNoArg, "lines" },
95 { "-line-loops", ".mode", XrmoptionNoArg, "line-loops" },
96 { "-speed", ".speed", XrmoptionSepArg, 0 },
97 { "-spin", ".spin", XrmoptionNoArg, "True" },
98 { "+spin", ".spin", XrmoptionNoArg, "False" },
99 { "-wander", ".wander", XrmoptionNoArg, "True" },
100 { "+wander", ".wander", XrmoptionNoArg, "False" },
103 static argtype vars[] = {
104 {&surface_type, "surface", "Surface", DEF_SURFACE, t_String },
105 {&render_mode, "mode", "Mode", DEF_MODE, t_String },
106 {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool },
107 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool },
108 {&speed, "speed", "Speed", DEF_SPEED, t_Int },
112 ENTRYPOINT ModeSpecOpt surface_opts =
113 {countof(opts), opts, countof(vars), vars, NULL};
124 GLXContext *glx_context;
127 trackball_state *trackball;
142 static surfacestruct *surface = NULL;
145 static void draw(ModeInfo *mi)
147 surfacestruct *sp = &surface[MI_SCREEN(mi)];
152 mi->polygon_count = 0;
153 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
155 glEnable(GL_DEPTH_TEST);
156 glEnable(GL_NORMALIZE);
157 glEnable(GL_CULL_FACE);
163 get_position(sp->rot, &x, &y, &z, !sp->button_down_p);
164 glTranslatef((x-0.5)*10, (y-0.5)*10, (z-0.5)*20);
166 /* Do it twice because we don't track the device's orientation. */
167 glRotatef( current_device_rotation(), 0, 0, 1);
168 gltrackball_rotate(sp->trackball);
169 glRotatef(-current_device_rotation(), 0, 0, 1);
171 get_rotation(sp->rot, &x, &y, &z, !sp->button_down_p);
172 glRotatef(x*360, 1.0, 0.0, 0.0);
173 glRotatef(y*360, 0.0, 1.0, 0.0);
174 glRotatef(z*360, 0.0, 0.0, 1.0);
177 glScalef(4.0, 4.0, 4.0);
182 for (v=0.11; v<=2.0; v+=sp->dv)
185 for (u=0; u<=6.0*M_PI; u+=sp->du)
187 coord[0] = sp->a*cos(u)*sin(v);
188 coord[1] = sp->a*sin(u)*sin(v);
189 coord[2] = sp->a*(cos(v)+log(tan(0.5*v)))+0.2*sp->b*u;
190 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
197 case SURFACE_ENNEPER:
198 for (u=-M_PI; u<=M_PI; u+=sp->du)
201 for (v=-M_PI; v<M_PI; v+=sp->dv)
203 coord[0] = sp->a*(u-(1.0/3.0*u*u*u)+u*v*v);
204 coord[1] = sp->b*(v-(1.0/3.0*v*v*v)+u*u*v);
206 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
214 for (u=-4.48; u<=4.48; u+=sp->du)
217 for (v=M_PI/51; v<M_PI; v+=sp->dv)
219 coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));
220 coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));
221 coord[2] = log(tan(0.5*v))+2*cos(v)/(1+u*u*sin(v)*sin(v));
222 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
229 case SURFACE_MOEBIUS:
230 for (u=-M_PI; u<M_PI; u+=sp->du)
233 for (v=-0.735; v<0.74; v+=sp->dv)
235 coord[0] = cos(u)+v*cos(u/2)*cos(u);
236 coord[1] = sin(u)+v*cos(u/2)*sin(u);
237 coord[2] = v*sin(u/2);
238 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
245 case SURFACE_SEASHELL:
246 for (u=0; u<2*M_PI; u+=sp->du)
249 for (v=0; v<2*M_PI; v+=sp->dv)
251 coord[0] = sp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sp->c*cos(2*v);
252 coord[1] = sp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+sp->c*sin(2*v);
253 coord[2] = 2*sp->b*v/(2*M_PI)+sp->a*(1-v/(2*M_PI))*sin(u);
254 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
261 case SURFACE_SWALLOWTAIL:
262 for (u=-2.5; u<2.0; u+=sp->du)
265 for (v=-1.085; v<1.09; v+=sp->dv)
267 coord[0] = u*v*v+3*v*v*v*v;
268 coord[1] = -2*u*v-4*v*v*v;
270 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
277 case SURFACE_BOHEMIAN:
278 for (u=-M_PI; u<M_PI; u+=sp->du)
281 for (v=-M_PI; v<M_PI; v+=sp->dv)
283 coord[0] = sp->a*cos(u);
284 coord[1] = sp->b*cos(v)+sp->a*sin(u);
286 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
293 case SURFACE_WHITNEY:
294 for (v=-1.995; v<2.0; v+=sp->dv)
297 for (u=-1.995; u<2.0; u+=sp->du)
302 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
309 case SURFACE_PLUECKER:
310 for (u=0; u<2.5; u+=sp->dv)
313 for (v=-M_PI; v<M_PI; v+=sp->du)
317 coord[2] = 2*cos(v)*sin(v);
318 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
325 case SURFACE_HENNEBERG:
326 for (u=0.9; u<2.55; u+=sp->dv)
329 for (v=-M_PI; v<M_PI; v+=sp->du)
331 coord[0] = sinh(1.0/3.0*u)*cos(v)-1.0/3.0*sinh(u)*cos(3.0*v);
332 coord[1] = sinh(1.0/3.0*u)*sin(v)+1.0/3.0*sinh(u)*sin(3.0*v);
333 coord[2] = cosh(2.0/3.0*u)*cos(2.0*v);
334 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
341 case SURFACE_CATALAN:
342 for (v=-2; v<2; v+=sp->du)
345 for (u=-2*M_PI; u<2*M_PI+0.05; u+=sp->dv)
347 coord[0] = 0.33*(u-sin(u)*cosh(v));
348 coord[1] = 0.33*(1.0-cos(u)*cosh(v));
349 coord[2] = 0.33*4.0*sin(0.5*u)*sinh(0.5*v);
350 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
357 case SURFACE_CORKSCREW:
358 for (v=-M_PI; v<M_PI; v+=sp->du)
361 for (u=-M_PI; u<M_PI; u+=sp->dv)
363 coord[0] = 0.5*(sp->a+2.0)*cos(u)*cos(v);
364 coord[1] = 0.5*(sp->a+2.0)*sin(u)*cos(v);
365 coord[2] = 0.5*(sp->a+2.0)*sin(v)+u;
366 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
376 if (sp->render == GL_LINES)
377 mi->polygon_count /= 2;
379 sp->a = sin(sp->draw_step+=0.01);
380 sp->b = cos(sp->draw_step+=0.01);
381 sp->c = sin(sp->draw_step+0.25*M_PI);
383 if (sp->random_surface || sp->random_render)
386 if (sp->frame >= speed)
389 if (sp->random_surface)
390 sp->surface = random() % NUM_SURFACES;
391 if (sp->random_render)
393 render = random() % NUM_RENDER;
397 sp->render = GL_POINTS;
400 sp->render = GL_LINES;
402 case RENDER_LINE_LOOP:
403 if (sp->surface == SURFACE_BOHEMIAN ||
404 sp->surface == SURFACE_PLUECKER ||
405 sp->surface == SURFACE_HENNEBERG)
406 sp->render = GL_LINE_LOOP;
408 sp->render = GL_LINE_STRIP;
411 sp->render = GL_LINE_LOOP;
420 /* new window size or exposure */
421 ENTRYPOINT void reshape_surface(ModeInfo *mi, int width, int height)
423 GLfloat h = (GLfloat) height / (GLfloat) width;
425 glViewport(0, 0, (GLint) width, (GLint) height);
426 glMatrixMode(GL_PROJECTION);
428 gluPerspective (30.0, 1/h, 1.0, 100.0);
430 glMatrixMode(GL_MODELVIEW);
432 gluLookAt(0.0, 0.0, 30.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
434 glClear(GL_COLOR_BUFFER_BIT);
438 ENTRYPOINT Bool surface_handle_event(ModeInfo *mi, XEvent *event)
440 surfacestruct *sp = &surface[MI_SCREEN(mi)];
442 if (event->xany.type == ButtonPress && event->xbutton.button == Button1)
444 sp->button_down_p = True;
445 gltrackball_start(sp->trackball, event->xbutton.x, event->xbutton.y,
446 MI_WIDTH (mi), MI_HEIGHT (mi));
449 else if (event->xany.type == ButtonRelease &&
450 event->xbutton.button == Button1)
452 sp->button_down_p = False;
455 else if (event->xany.type == ButtonPress &&
456 (event->xbutton.button == Button4 ||
457 event->xbutton.button == Button5 ||
458 event->xbutton.button == Button6 ||
459 event->xbutton.button == Button7)) {
460 gltrackball_mousewheel(sp->trackball, event->xbutton.button, 10,
461 !!event->xbutton.state);
464 else if (event->xany.type == MotionNotify && sp->button_down_p)
466 gltrackball_track (sp->trackball, event->xmotion.x, event->xmotion.y,
467 MI_WIDTH (mi), MI_HEIGHT (mi));
475 ENTRYPOINT void init_surface(ModeInfo *mi)
477 int screen = MI_SCREEN(mi);
482 if ((surface = (surfacestruct *) calloc(MI_NUM_SCREENS(mi),
483 sizeof(surfacestruct))) == NULL)
486 sp = &surface[screen];
488 sp->window = MI_WINDOW(mi);
491 double spin_speed = 1.0;
492 double wander_speed = 0.03;
493 sp->rot = make_rotator(do_spin ? spin_speed : 0,
494 do_spin ? spin_speed : 0,
495 do_spin ? spin_speed : 0,
497 do_wander ? wander_speed : 0,
499 sp->trackball = gltrackball_init ();
502 if (!strcasecmp(surface_type,"random"))
504 sp->random_surface = True;
505 sp->surface = random() % NUM_SURFACES;
507 else if (!strcasecmp(surface_type,"dini"))
509 sp->random_surface = False;
510 sp->surface = SURFACE_DINI;
512 else if (!strcasecmp(surface_type,"enneper"))
514 sp->random_surface = False;
515 sp->surface = SURFACE_ENNEPER;
517 else if (!strcasecmp(surface_type,"kuen"))
519 sp->random_surface = False;
520 sp->surface = SURFACE_KUEN;
522 else if (!strcasecmp(surface_type,"moebius"))
524 sp->random_surface = False;
525 sp->surface = SURFACE_MOEBIUS;
527 else if (!strcasecmp(surface_type,"seashell"))
529 sp->random_surface = False;
530 sp->surface = SURFACE_SEASHELL;
532 else if (!strcasecmp(surface_type,"swallowtail"))
534 sp->random_surface = False;
535 sp->surface = SURFACE_SWALLOWTAIL;
537 else if (!strcasecmp(surface_type,"bohemian"))
539 sp->random_surface = False;
540 sp->surface = SURFACE_BOHEMIAN;
542 else if (!strcasecmp(surface_type,"whitney"))
544 sp->random_surface = False;
545 sp->surface = SURFACE_WHITNEY;
547 else if (!strcasecmp(surface_type,"pluecker"))
549 sp->random_surface = False;
550 sp->surface = SURFACE_PLUECKER;
552 else if (!strcasecmp(surface_type,"henneberg"))
554 sp->random_surface = False;
555 sp->surface = SURFACE_HENNEBERG;
557 else if (!strcasecmp(surface_type,"catalan"))
559 sp->random_surface = False;
560 sp->surface = SURFACE_CATALAN;
562 else if (!strcasecmp(surface_type,"corkscrew"))
564 sp->random_surface = False;
565 sp->surface = SURFACE_CORKSCREW;
569 sp->random_surface = True;
570 sp->surface = random() % NUM_SURFACES;
573 if (!strcasecmp(render_mode,"random"))
575 sp->random_render = True;
576 render = random() % NUM_RENDER;
578 else if (!strcasecmp(render_mode,"points"))
580 sp->random_render = False;
581 render = RENDER_POINTS;
583 else if (!strcasecmp(render_mode,"lines"))
585 sp->random_render = False;
586 render = RENDER_LINES;
588 else if (!strcasecmp(render_mode,"line-loops"))
590 sp->random_render = False;
591 render = RENDER_LINE_LOOP;
595 sp->random_render = True;
596 render = random() % NUM_RENDER;
602 sp->render = GL_POINTS;
605 sp->render = GL_LINES;
607 case RENDER_LINE_LOOP:
608 if (sp->surface == SURFACE_BOHEMIAN ||
609 sp->surface == SURFACE_PLUECKER ||
610 sp->surface == SURFACE_HENNEBERG)
611 sp->render = GL_LINE_LOOP;
613 sp->render = GL_LINE_STRIP;
616 sp->render = GL_LINE_LOOP;
627 if ((sp->glx_context = init_GL(mi)) != NULL)
629 reshape_surface(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
638 ENTRYPOINT void draw_surface(ModeInfo * mi)
640 surfacestruct *sp = &surface[MI_SCREEN(mi)];
641 Display *display = MI_DISPLAY(mi);
642 Window window = MI_WINDOW(mi);
644 if (!sp->glx_context)
647 glDrawBuffer(GL_BACK);
649 glXMakeCurrent(display, window, *(sp->glx_context));
654 glXSwapBuffers(display, window);
658 ENTRYPOINT void release_surface(ModeInfo * mi)
664 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
666 surfacestruct *sp = &surface[screen];
670 /* Display lists MUST be freed while their glXContext is current. */
671 glXMakeCurrent(MI_DISPLAY(mi), sp->window, *(sp->glx_context));
674 (void) free((void *)surface);
681 XSCREENSAVER_MODULE_2("Surfaces", surfaces, surface)