1 /* hypertorus --- Shows a hypertorus that rotates in 4d */
4 static const char sccsid[] = "@(#)hypertorus.c 1.2 05/09/28 xlockmore";
7 /* Copyright (c) 2003-2009 Carsten Steger <carsten@mirsanmir.org>. */
10 * Permission to use, copy, modify, and distribute this software and its
11 * documentation for any purpose and without fee is hereby granted,
12 * provided that the above copyright notice appear in all copies and that
13 * both that copyright notice and this permission notice appear in
14 * supporting documentation.
16 * This file is provided AS IS with no warranties of any kind. The author
17 * shall have no liability with respect to the infringement of copyrights,
18 * trade secrets or any patents by this file or any part thereof. In no
19 * event will the author be liable for any lost revenue or profits or
20 * other special, indirect and consequential damages.
23 * C. Steger - 03/05/18: Initial version
24 * C. Steger - 05/09/28: Added the spirals appearance mode
25 * and trackball support
26 * C. Steger - 07/01/23: Improved 4d trackball support
27 * C. Steger - 09/08/22: Removed check-config.pl warnings
31 * This program shows the Clifford torus as it rotates in 4d. The Clifford
32 * torus is a torus lies on the "surface" of the hypersphere in 4d. The
33 * program projects the 4d torus to 3d using either a perspective or an
34 * orthographic projection. Of the two alternatives, the perspecitve
35 * projection looks much more appealing. In orthographic projections the
36 * torus degenerates into a doubly covered cylinder for some angles. The
37 * projected 3d torus can then be projected to the screen either perspectively
38 * or orthographically. There are three display modes for the torus: mesh
39 * (wireframe), solid, or transparent. Furthermore, the appearance of the
40 * torus can be as a solid object or as a set of see-through bands or
41 * see-through spirals. Finally, the colors with with the torus is drawn can
42 * be set to either two-sided or to colorwheel. In the first case, the torus
43 * is drawn with red on the outside and green on the inside. This mode
44 * enables you to see that the torus turns inside-out as it rotates in 4d.
45 * The second mode draws the torus in a fully saturated color wheel. This
46 * gives a very nice effect when combined with the see-through bands or
47 * see-through spirals mode. The rotation speed for each of the six planes
48 * around which the torus rotates can be chosen. This program is very much
49 * inspired by Thomas Banchoff's book "Beyond the Third Dimension: Geometry,
50 * Computer Graphics, and Higher Dimensions", Scientific American Library,
55 #define M_PI 3.14159265358979323846
58 #define DISP_WIREFRAME 0
59 #define DISP_SURFACE 1
60 #define DISP_TRANSPARENT 2
62 #define APPEARANCE_SOLID 0
63 #define APPEARANCE_BANDS 1
64 #define APPEARANCE_SPIRALS 2
66 #define COLORS_TWOSIDED 0
67 #define COLORS_COLORWHEEL 1
69 #define DISP_3D_PERSPECTIVE 0
70 #define DISP_3D_ORTHOGRAPHIC 1
72 #define DISP_4D_PERSPECTIVE 0
73 #define DISP_4D_ORTHOGRAPHIC 1
75 #define DEF_DISPLAY_MODE "surface"
76 #define DEF_APPEARANCE "bands"
77 #define DEF_COLORS "colorwheel"
78 #define DEF_PROJECTION_3D "perspective"
79 #define DEF_PROJECTION_4D "perspective"
80 #define DEF_SPEEDWX "1.1"
81 #define DEF_SPEEDWY "1.3"
82 #define DEF_SPEEDWZ "1.5"
83 #define DEF_SPEEDXY "1.7"
84 #define DEF_SPEEDXZ "1.9"
85 #define DEF_SPEEDYZ "2.1"
88 # define DEFAULTS "*delay: 25000 \n" \
89 "*showFPS: False \n" \
91 # define refresh_hypertorus 0
92 # include "xlockmore.h" /* from the xscreensaver distribution */
93 #else /* !STANDALONE */
94 # include "xlock.h" /* from the xlockmore distribution */
95 #endif /* !STANDALONE */
99 #include <X11/keysym.h>
101 #include "gltrackball.h"
105 ModStruct hypertorus_description =
106 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
107 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
108 25000, 1, 1, 1, 1.0, 4, "",
109 "Shows a hypertorus rotating in 4d", 0, NULL};
115 static int display_mode;
117 static int appearance;
118 static int num_spirals;
119 static char *color_mode;
121 static char *proj_3d;
122 static int projection_3d;
123 static char *proj_4d;
124 static int projection_4d;
125 static float speed_wx;
126 static float speed_wy;
127 static float speed_wz;
128 static float speed_xy;
129 static float speed_xz;
130 static float speed_yz;
132 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
133 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
136 static XrmOptionDescRec opts[] =
138 {"-mode", ".displayMode", XrmoptionSepArg, 0 },
139 {"-wireframe", ".displayMode", XrmoptionNoArg, "wireframe" },
140 {"-surface", ".displayMode", XrmoptionNoArg, "surface" },
141 {"-transparent", ".displayMode", XrmoptionNoArg, "transparent" },
142 {"-appearance", ".appearance", XrmoptionSepArg, 0 },
143 {"-solid", ".appearance", XrmoptionNoArg, "solid" },
144 {"-bands", ".appearance", XrmoptionNoArg, "bands" },
145 {"-spirals-1", ".appearance", XrmoptionNoArg, "spirals-1" },
146 {"-spirals-2", ".appearance", XrmoptionNoArg, "spirals-2" },
147 {"-spirals-4", ".appearance", XrmoptionNoArg, "spirals-4" },
148 {"-spirals-8", ".appearance", XrmoptionNoArg, "spirals-8" },
149 {"-spirals-16", ".appearance", XrmoptionNoArg, "spirals-16" },
150 {"-twosided", ".colors", XrmoptionNoArg, "twosided" },
151 {"-colorwheel", ".colors", XrmoptionNoArg, "colorwheel" },
152 {"-perspective-3d", ".projection3d", XrmoptionNoArg, "perspective" },
153 {"-orthographic-3d", ".projection3d", XrmoptionNoArg, "orthographic" },
154 {"-perspective-4d", ".projection4d", XrmoptionNoArg, "perspective" },
155 {"-orthographic-4d", ".projection4d", XrmoptionNoArg, "orthographic" },
156 {"-speed-wx", ".speedwx", XrmoptionSepArg, 0 },
157 {"-speed-wy", ".speedwy", XrmoptionSepArg, 0 },
158 {"-speed-wz", ".speedwz", XrmoptionSepArg, 0 },
159 {"-speed-xy", ".speedxy", XrmoptionSepArg, 0 },
160 {"-speed-xz", ".speedxz", XrmoptionSepArg, 0 },
161 {"-speed-yz", ".speedyz", XrmoptionSepArg, 0 }
164 static argtype vars[] =
166 { &mode, "displayMode", "DisplayMode", DEF_DISPLAY_MODE, t_String },
167 { &appear, "appearance", "Appearance", DEF_APPEARANCE, t_String },
168 { &color_mode, "colors", "Colors", DEF_COLORS, t_String },
169 { &proj_3d, "projection3d", "Projection3d", DEF_PROJECTION_3D, t_String },
170 { &proj_4d, "projection4d", "Projection4d", DEF_PROJECTION_4D, t_String },
171 { &speed_wx, "speedwx", "Speedwx", DEF_SPEEDWX, t_Float},
172 { &speed_wy, "speedwy", "Speedwy", DEF_SPEEDWY, t_Float},
173 { &speed_wz, "speedwz", "Speedwz", DEF_SPEEDWZ, t_Float},
174 { &speed_xy, "speedxy", "Speedxy", DEF_SPEEDXY, t_Float},
175 { &speed_xz, "speedxz", "Speedxz", DEF_SPEEDXZ, t_Float},
176 { &speed_yz, "speedyz", "Speedyz", DEF_SPEEDYZ, t_Float}
179 static OptionStruct desc[] =
181 { "-wireframe", "display the torus as a wireframe mesh" },
182 { "-surface", "display the torus as a solid surface" },
183 { "-transparent", "display the torus as a transparent surface" },
184 { "-solid", "display the torus as a solid object" },
185 { "-bands", "display the torus as see-through bands" },
186 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
187 { "-twosided", "display the torus with two colors" },
188 { "-colorwheel", "display the torus with a smooth color wheel" },
189 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
190 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
191 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
192 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
193 { "-speed-wx <arg>", "rotation speed around the wx plane" },
194 { "-speed-wy <arg>", "rotation speed around the wy plane" },
195 { "-speed-wz <arg>", "rotation speed around the wz plane" },
196 { "-speed-xy <arg>", "rotation speed around the xy plane" },
197 { "-speed-xz <arg>", "rotation speed around the xz plane" },
198 { "-speed-yz <arg>", "rotation speed around the yz plane" }
201 ENTRYPOINT ModeSpecOpt hypertorus_opts =
202 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
207 GLXContext *glx_context;
208 /* 4D rotation angles */
209 float alpha, beta, delta, zeta, eta, theta;
210 /* Aspect ratio of the current window */
212 /* Trackball states */
213 trackball_state *trackballs[2];
214 int current_trackball;
221 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
224 /* Add a rotation around the wx-plane to the matrix m. */
225 static void rotatewx(float m[4][4], float phi)
243 /* Add a rotation around the wy-plane to the matrix m. */
244 static void rotatewy(float m[4][4], float phi)
262 /* Add a rotation around the wz-plane to the matrix m. */
263 static void rotatewz(float m[4][4], float phi)
281 /* Add a rotation around the xy-plane to the matrix m. */
282 static void rotatexy(float m[4][4], float phi)
300 /* Add a rotation around the xz-plane to the matrix m. */
301 static void rotatexz(float m[4][4], float phi)
319 /* Add a rotation around the yz-plane to the matrix m. */
320 static void rotateyz(float m[4][4], float phi)
338 /* Compute the rotation matrix m from the rotation angles. */
339 static void rotateall(float al, float be, float de, float ze, float et,
340 float th, float m[4][4])
356 /* Multiply two rotation matrices: o=m*n. */
357 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
367 o[i][j] += m[i][k]*n[k][j];
373 /* Compute a 4D rotation matrix from two unit quaternions. */
374 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
376 double al, be, de, ze, et, th;
377 double r00, r01, r02, r12, r22;
379 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
380 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
381 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
382 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
383 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
385 al = atan2(-r12,r22)*180.0/M_PI;
386 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
387 de = atan2(-r01,r00)*180.0/M_PI;
389 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
390 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
391 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
392 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
393 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
395 et = atan2(-r12,r22)*180.0/M_PI;
396 th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
397 ze = atan2(-r01,r00)*180.0/M_PI;
399 rotateall(al,be,de,ze,et,-th,m);
403 /* Compute a fully saturated and bright color based on an angle. */
404 static void color(double angle)
410 if (colors != COLORS_COLORWHEEL)
414 angle = fmod(angle,2*M_PI);
416 angle = fmod(angle,-2*M_PI);
417 s = floor(angle/(M_PI/3));
418 t = angle/(M_PI/3)-s;
454 if (display_mode == DISP_TRANSPARENT)
459 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
463 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
464 will only work correctly if numu and numv are set to 64 or any higher
465 power of 2. Similarly, the banded appearance will only work correctly
466 if numu and numv are divisible by 4. */
467 static int hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
468 double vmax, int numu, int numv)
471 static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
472 static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
473 static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
474 static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
475 float p[3], pu[3], pv[3], n[3], mat[4][4];
476 int i, j, k, l, m, b, skew;
478 double cu, su, cv, sv;
479 double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
481 float q1[4], q2[4], r1[4][4], r2[4][4];
482 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
484 rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);
486 gltrackball_get_quaternion(hp->trackballs[0],q1);
487 gltrackball_get_quaternion(hp->trackballs[1],q2);
488 quats_to_rotmat(q1,q2,r2);
490 mult_rotmat(r2,r1,mat);
492 if (colors != COLORS_COLORWHEEL)
494 glColor3fv(mat_diff_red);
495 if (display_mode == DISP_TRANSPARENT)
497 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
498 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
502 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
503 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
510 for (i=0; i<numu; i++)
512 if ((appearance == APPEARANCE_BANDS ||
513 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
515 if (display_mode == DISP_WIREFRAME)
516 glBegin(GL_QUAD_STRIP);
518 glBegin(GL_TRIANGLE_STRIP);
519 for (j=0; j<=numv; j++)
527 if (appearance == APPEARANCE_SPIRALS)
529 u += 4.0*skew/numv*v;
530 b = ((i/4)&(skew-1))*(numu/(4*skew));
531 color(ur*4*b/numu+umin);
560 r += mat[l][m]*xx[m];
561 s += mat[l][m]*xxu[m];
562 t += mat[l][m]*xxv[m];
568 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
572 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
579 s = x[3]+offset4d[3];
583 r = x[l]+offset4d[l];
584 p[l] = r/s+offset3d[l];
585 pu[l] = (xu[l]*s-r*xu[3])/t;
586 pv[l] = (xv[l]*s-r*xv[3])/t;
589 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
590 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
591 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
592 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
608 static void init(ModeInfo *mi)
610 static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
611 static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
612 static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
613 static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
614 static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
615 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
624 glMatrixMode(GL_PROJECTION);
626 if (projection_3d == DISP_3D_PERSPECTIVE)
627 gluPerspective(60.0,1.0,0.1,100.0);
629 glOrtho(-1.0,1.0,-1.0,1.0,0.1,100.0);;
630 glMatrixMode(GL_MODELVIEW);
633 if (display_mode == DISP_WIREFRAME)
635 glDisable(GL_DEPTH_TEST);
636 glShadeModel(GL_FLAT);
637 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
638 glDisable(GL_LIGHTING);
639 glDisable(GL_LIGHT0);
642 else if (display_mode == DISP_SURFACE)
644 glEnable(GL_DEPTH_TEST);
645 glDepthFunc(GL_LESS);
646 glShadeModel(GL_SMOOTH);
647 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
648 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
649 glEnable(GL_LIGHTING);
651 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
652 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
653 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
654 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
655 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
656 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
657 glDepthMask(GL_TRUE);
660 else if (display_mode == DISP_TRANSPARENT)
662 glDisable(GL_DEPTH_TEST);
663 glShadeModel(GL_SMOOTH);
664 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
665 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
666 glEnable(GL_LIGHTING);
668 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
669 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
670 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
671 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
672 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
673 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
674 glDepthMask(GL_FALSE);
676 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
680 glDisable(GL_DEPTH_TEST);
681 glShadeModel(GL_FLAT);
682 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
683 glDisable(GL_LIGHTING);
684 glDisable(GL_LIGHT0);
690 /* Redisplay the hypertorus. */
691 static void display_hypertorus(ModeInfo *mi)
693 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
695 if (!hp->button_pressed)
697 hp->alpha += speed_wx * hp->speed_scale;
698 if (hp->alpha >= 360.0)
700 hp->beta += speed_wy * hp->speed_scale;
701 if (hp->beta >= 360.0)
703 hp->delta += speed_wz * hp->speed_scale;
704 if (hp->delta >= 360.0)
706 hp->zeta += speed_xy * hp->speed_scale;
707 if (hp->zeta >= 360.0)
709 hp->eta += speed_xz * hp->speed_scale;
710 if (hp->eta >= 360.0)
712 hp->theta += speed_yz * hp->speed_scale;
713 if (hp->theta >= 360.0)
717 glMatrixMode(GL_PROJECTION);
719 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
721 if (hp->aspect >= 1.0)
722 glOrtho(-hp->aspect,hp->aspect,-1.0,1.0,0.1,100.0);
724 glOrtho(-1.0,1.0,-1.0/hp->aspect,1.0/hp->aspect,0.1,100.0);
728 gluPerspective(60.0,hp->aspect,0.1,100.0);
730 glMatrixMode(GL_MODELVIEW);
733 mi->polygon_count = hypertorus(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
737 ENTRYPOINT void reshape_hypertorus(ModeInfo *mi, int width, int height)
739 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
741 hp->WindW = (GLint)width;
742 hp->WindH = (GLint)height;
743 glViewport(0,0,width,height);
744 hp->aspect = (GLfloat)width/(GLfloat)height;
748 ENTRYPOINT Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
750 Display *display = MI_DISPLAY(mi);
751 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
754 if (event->xany.type == ButtonPress &&
755 event->xbutton.button == Button1)
757 hp->button_pressed = True;
758 gltrackball_start(hp->trackballs[hp->current_trackball],
759 event->xbutton.x, event->xbutton.y,
760 MI_WIDTH(mi), MI_HEIGHT(mi));
763 else if (event->xany.type == ButtonRelease &&
764 event->xbutton.button == Button1)
766 hp->button_pressed = False;
769 else if (event->xany.type == KeyPress)
771 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
772 if (sym == XK_Shift_L || sym == XK_Shift_R)
774 hp->current_trackball = 1;
775 if (hp->button_pressed)
776 gltrackball_start(hp->trackballs[hp->current_trackball],
777 event->xbutton.x, event->xbutton.y,
778 MI_WIDTH(mi), MI_HEIGHT(mi));
782 else if (event->xany.type == KeyRelease)
784 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
785 if (sym == XK_Shift_L || sym == XK_Shift_R)
787 hp->current_trackball = 0;
788 if (hp->button_pressed)
789 gltrackball_start(hp->trackballs[hp->current_trackball],
790 event->xbutton.x, event->xbutton.y,
791 MI_WIDTH(mi), MI_HEIGHT(mi));
795 else if (event->xany.type == MotionNotify && hp->button_pressed)
797 gltrackball_track(hp->trackballs[hp->current_trackball],
798 event->xmotion.x, event->xmotion.y,
799 MI_WIDTH(mi), MI_HEIGHT(mi));
808 *-----------------------------------------------------------------------------
809 *-----------------------------------------------------------------------------
811 *-----------------------------------------------------------------------------
812 *-----------------------------------------------------------------------------
816 *-----------------------------------------------------------------------------
817 * Initialize hypertorus. Called each time the window changes.
818 *-----------------------------------------------------------------------------
821 ENTRYPOINT void init_hypertorus(ModeInfo *mi)
823 hypertorusstruct *hp;
827 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
828 sizeof(hypertorusstruct));
832 hp = &hyper[MI_SCREEN(mi)];
835 hp->trackballs[0] = gltrackball_init();
836 hp->trackballs[1] = gltrackball_init();
837 hp->current_trackball = 0;
838 hp->button_pressed = False;
840 /* Set the display mode. */
841 if (!strcasecmp(mode,"wireframe") || !strcasecmp(mode,"0"))
843 display_mode = DISP_WIREFRAME;
845 else if (!strcasecmp(mode,"surface") || !strcasecmp(mode,"1"))
847 display_mode = DISP_SURFACE;
849 else if (!strcasecmp(mode,"transparent") || !strcasecmp(mode,"2"))
851 display_mode = DISP_TRANSPARENT;
855 display_mode = DISP_SURFACE;
858 /* Set the appearance. */
859 if (!strcasecmp(appear,"solid") || !strcasecmp(appear,"0"))
861 appearance = APPEARANCE_SOLID;
863 else if (!strcasecmp(appear,"bands") || !strcasecmp(appear,"1"))
865 appearance = APPEARANCE_BANDS;
868 else if (!strcasecmp(appear,"spirals-1") || !strcasecmp(appear,"3"))
870 appearance = APPEARANCE_SPIRALS;
873 else if (!strcasecmp(appear,"spirals-2") || !strcasecmp(appear,"4"))
875 appearance = APPEARANCE_SPIRALS;
878 else if (!strcasecmp(appear,"spirals-4") || !strcasecmp(appear,"5"))
880 appearance = APPEARANCE_SPIRALS;
883 else if (!strcasecmp(appear,"spirals-8") || !strcasecmp(appear,"6"))
885 appearance = APPEARANCE_SPIRALS;
888 else if (!strcasecmp(appear,"spirals-16") || !strcasecmp(appear,"7"))
890 appearance = APPEARANCE_SPIRALS;
895 appearance = APPEARANCE_BANDS;
899 /* Set the color mode. */
900 if (!strcasecmp(color_mode,"twosided"))
902 colors = COLORS_TWOSIDED;
904 else if (!strcasecmp(color_mode,"colorwheel"))
906 colors = COLORS_COLORWHEEL;
910 colors = COLORS_COLORWHEEL;
913 /* Set the 3d projection mode. */
914 if (!strcasecmp(proj_3d,"perspective") || !strcasecmp(proj_3d,"0"))
916 projection_3d = DISP_3D_PERSPECTIVE;
918 else if (!strcasecmp(proj_3d,"orthographic") || !strcasecmp(proj_3d,"1"))
920 projection_3d = DISP_3D_ORTHOGRAPHIC;
924 projection_3d = DISP_3D_PERSPECTIVE;
927 /* Set the 4d projection mode. */
928 if (!strcasecmp(proj_4d,"perspective") || !strcasecmp(proj_4d,"0"))
930 projection_4d = DISP_4D_PERSPECTIVE;
932 else if (!strcasecmp(proj_4d,"orthographic") || !strcasecmp(proj_4d,"1"))
934 projection_4d = DISP_4D_ORTHOGRAPHIC;
938 projection_4d = DISP_4D_PERSPECTIVE;
941 /* make multiple screens rotate at slightly different rates. */
942 hp->speed_scale = 0.9 + frand(0.3);
944 if ((hp->glx_context = init_GL(mi)) != NULL)
946 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
947 glDrawBuffer(GL_BACK);
957 *-----------------------------------------------------------------------------
958 * Called by the mainline code periodically to update the display.
959 *-----------------------------------------------------------------------------
961 ENTRYPOINT void draw_hypertorus(ModeInfo *mi)
963 Display *display = MI_DISPLAY(mi);
964 Window window = MI_WINDOW(mi);
965 hypertorusstruct *hp;
969 hp = &hyper[MI_SCREEN(mi)];
971 MI_IS_DRAWN(mi) = True;
972 if (!hp->glx_context)
975 glXMakeCurrent(display,window,*(hp->glx_context));
977 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
980 display_hypertorus(mi);
987 glXSwapBuffers(display,window);
992 *-----------------------------------------------------------------------------
993 * The display is being taken away from us. Free up malloc'ed
994 * memory and X resources that we've alloc'ed. Only called
995 * once, we must zap everything for every screen.
996 *-----------------------------------------------------------------------------
999 ENTRYPOINT void release_hypertorus(ModeInfo *mi)
1005 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1007 hypertorusstruct *hp = &hyper[screen];
1009 if (hp->glx_context)
1010 hp->glx_context = (GLXContext *)NULL;
1012 (void) free((void *)hyper);
1013 hyper = (hypertorusstruct *)NULL;
1019 ENTRYPOINT void change_hypertorus(ModeInfo *mi)
1021 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
1023 if (!hp->glx_context)
1026 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));
1029 #endif /* !STANDALONE */
1031 XSCREENSAVER_MODULE ("Hypertorus", hypertorus)