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>
102 #include "gltrackball.h"
106 ModStruct hypertorus_description =
107 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
108 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
109 25000, 1, 1, 1, 1.0, 4, "",
110 "Shows a hypertorus rotating in 4d", 0, NULL};
116 static int display_mode;
118 static int appearance;
119 static int num_spirals;
120 static char *color_mode;
122 static char *proj_3d;
123 static int projection_3d;
124 static char *proj_4d;
125 static int projection_4d;
126 static float speed_wx;
127 static float speed_wy;
128 static float speed_wz;
129 static float speed_xy;
130 static float speed_xz;
131 static float speed_yz;
133 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
134 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
137 static XrmOptionDescRec opts[] =
139 {"-mode", ".displayMode", XrmoptionSepArg, 0 },
140 {"-wireframe", ".displayMode", XrmoptionNoArg, "wireframe" },
141 {"-surface", ".displayMode", XrmoptionNoArg, "surface" },
142 {"-transparent", ".displayMode", XrmoptionNoArg, "transparent" },
143 {"-appearance", ".appearance", XrmoptionSepArg, 0 },
144 {"-solid", ".appearance", XrmoptionNoArg, "solid" },
145 {"-bands", ".appearance", XrmoptionNoArg, "bands" },
146 {"-spirals-1", ".appearance", XrmoptionNoArg, "spirals-1" },
147 {"-spirals-2", ".appearance", XrmoptionNoArg, "spirals-2" },
148 {"-spirals-4", ".appearance", XrmoptionNoArg, "spirals-4" },
149 {"-spirals-8", ".appearance", XrmoptionNoArg, "spirals-8" },
150 {"-spirals-16", ".appearance", XrmoptionNoArg, "spirals-16" },
151 {"-twosided", ".colors", XrmoptionNoArg, "twosided" },
152 {"-colorwheel", ".colors", XrmoptionNoArg, "colorwheel" },
153 {"-perspective-3d", ".projection3d", XrmoptionNoArg, "perspective" },
154 {"-orthographic-3d", ".projection3d", XrmoptionNoArg, "orthographic" },
155 {"-perspective-4d", ".projection4d", XrmoptionNoArg, "perspective" },
156 {"-orthographic-4d", ".projection4d", XrmoptionNoArg, "orthographic" },
157 {"-speed-wx", ".speedwx", XrmoptionSepArg, 0 },
158 {"-speed-wy", ".speedwy", XrmoptionSepArg, 0 },
159 {"-speed-wz", ".speedwz", XrmoptionSepArg, 0 },
160 {"-speed-xy", ".speedxy", XrmoptionSepArg, 0 },
161 {"-speed-xz", ".speedxz", XrmoptionSepArg, 0 },
162 {"-speed-yz", ".speedyz", XrmoptionSepArg, 0 }
165 static argtype vars[] =
167 { &mode, "displayMode", "DisplayMode", DEF_DISPLAY_MODE, t_String },
168 { &appear, "appearance", "Appearance", DEF_APPEARANCE, t_String },
169 { &color_mode, "colors", "Colors", DEF_COLORS, t_String },
170 { &proj_3d, "projection3d", "Projection3d", DEF_PROJECTION_3D, t_String },
171 { &proj_4d, "projection4d", "Projection4d", DEF_PROJECTION_4D, t_String },
172 { &speed_wx, "speedwx", "Speedwx", DEF_SPEEDWX, t_Float},
173 { &speed_wy, "speedwy", "Speedwy", DEF_SPEEDWY, t_Float},
174 { &speed_wz, "speedwz", "Speedwz", DEF_SPEEDWZ, t_Float},
175 { &speed_xy, "speedxy", "Speedxy", DEF_SPEEDXY, t_Float},
176 { &speed_xz, "speedxz", "Speedxz", DEF_SPEEDXZ, t_Float},
177 { &speed_yz, "speedyz", "Speedyz", DEF_SPEEDYZ, t_Float}
180 static OptionStruct desc[] =
182 { "-wireframe", "display the torus as a wireframe mesh" },
183 { "-surface", "display the torus as a solid surface" },
184 { "-transparent", "display the torus as a transparent surface" },
185 { "-solid", "display the torus as a solid object" },
186 { "-bands", "display the torus as see-through bands" },
187 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
188 { "-twosided", "display the torus with two colors" },
189 { "-colorwheel", "display the torus with a smooth color wheel" },
190 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
191 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
192 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
193 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
194 { "-speed-wx <arg>", "rotation speed around the wx plane" },
195 { "-speed-wy <arg>", "rotation speed around the wy plane" },
196 { "-speed-wz <arg>", "rotation speed around the wz plane" },
197 { "-speed-xy <arg>", "rotation speed around the xy plane" },
198 { "-speed-xz <arg>", "rotation speed around the xz plane" },
199 { "-speed-yz <arg>", "rotation speed around the yz plane" }
202 ENTRYPOINT ModeSpecOpt hypertorus_opts =
203 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
208 GLXContext *glx_context;
209 /* 4D rotation angles */
210 float alpha, beta, delta, zeta, eta, theta;
211 /* Aspect ratio of the current window */
213 /* Trackball states */
214 trackball_state *trackballs[2];
215 int current_trackball;
222 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
225 /* Add a rotation around the wx-plane to the matrix m. */
226 static void rotatewx(float m[4][4], float phi)
244 /* Add a rotation around the wy-plane to the matrix m. */
245 static void rotatewy(float m[4][4], float phi)
263 /* Add a rotation around the wz-plane to the matrix m. */
264 static void rotatewz(float m[4][4], float phi)
282 /* Add a rotation around the xy-plane to the matrix m. */
283 static void rotatexy(float m[4][4], float phi)
301 /* Add a rotation around the xz-plane to the matrix m. */
302 static void rotatexz(float m[4][4], float phi)
320 /* Add a rotation around the yz-plane to the matrix m. */
321 static void rotateyz(float m[4][4], float phi)
339 /* Compute the rotation matrix m from the rotation angles. */
340 static void rotateall(float al, float be, float de, float ze, float et,
341 float th, float m[4][4])
357 /* Multiply two rotation matrices: o=m*n. */
358 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
368 o[i][j] += m[i][k]*n[k][j];
374 /* Compute a 4D rotation matrix from two unit quaternions. */
375 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
377 double al, be, de, ze, et, th;
378 double r00, r01, r02, r12, r22;
380 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
381 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
382 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
383 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
384 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
386 al = atan2(-r12,r22)*180.0/M_PI;
387 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
388 de = atan2(-r01,r00)*180.0/M_PI;
390 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
391 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
392 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
393 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
394 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
396 et = atan2(-r12,r22)*180.0/M_PI;
397 th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
398 ze = atan2(-r01,r00)*180.0/M_PI;
400 rotateall(al,be,de,ze,et,-th,m);
404 /* Compute a fully saturated and bright color based on an angle. */
405 static void color(double angle)
411 if (colors != COLORS_COLORWHEEL)
415 angle = fmod(angle,2*M_PI);
417 angle = fmod(angle,-2*M_PI);
418 s = floor(angle/(M_PI/3));
419 t = angle/(M_PI/3)-s;
455 if (display_mode == DISP_TRANSPARENT)
460 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
464 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
465 will only work correctly if numu and numv are set to 64 or any higher
466 power of 2. Similarly, the banded appearance will only work correctly
467 if numu and numv are divisible by 4. */
468 static int hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
469 double vmax, int numu, int numv)
472 static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
473 static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
474 static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
475 static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
476 float p[3], pu[3], pv[3], n[3], mat[4][4];
477 int i, j, k, l, m, b, skew;
479 double cu, su, cv, sv;
480 double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
482 float q1[4], q2[4], r1[4][4], r2[4][4];
483 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
485 rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);
487 gltrackball_get_quaternion(hp->trackballs[0],q1);
488 gltrackball_get_quaternion(hp->trackballs[1],q2);
489 quats_to_rotmat(q1,q2,r2);
491 mult_rotmat(r2,r1,mat);
493 if (colors != COLORS_COLORWHEEL)
495 glColor3fv(mat_diff_red);
496 if (display_mode == DISP_TRANSPARENT)
498 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
499 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
503 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
504 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
511 for (i=0; i<numu; i++)
513 if ((appearance == APPEARANCE_BANDS ||
514 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
516 if (display_mode == DISP_WIREFRAME)
517 glBegin(GL_QUAD_STRIP);
519 glBegin(GL_TRIANGLE_STRIP);
520 for (j=0; j<=numv; j++)
528 if (appearance == APPEARANCE_SPIRALS)
530 u += 4.0*skew/numv*v;
531 b = ((i/4)&(skew-1))*(numu/(4*skew));
532 color(ur*4*b/numu+umin);
561 r += mat[l][m]*xx[m];
562 s += mat[l][m]*xxu[m];
563 t += mat[l][m]*xxv[m];
569 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
573 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
580 s = x[3]+offset4d[3];
584 r = x[l]+offset4d[l];
585 p[l] = r/s+offset3d[l];
586 pu[l] = (xu[l]*s-r*xu[3])/t;
587 pv[l] = (xv[l]*s-r*xv[3])/t;
590 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
591 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
592 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
593 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
609 static void init(ModeInfo *mi)
611 static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
612 static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
613 static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
614 static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
615 static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
616 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
625 glMatrixMode(GL_PROJECTION);
627 if (projection_3d == DISP_3D_PERSPECTIVE)
628 gluPerspective(60.0,1.0,0.1,100.0);
630 glOrtho(-1.0,1.0,-1.0,1.0,0.1,100.0);;
631 glMatrixMode(GL_MODELVIEW);
634 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
635 if (display_mode == DISP_WIREFRAME)
636 display_mode = DISP_SURFACE;
639 if (display_mode == DISP_SURFACE)
641 glEnable(GL_DEPTH_TEST);
642 glDepthFunc(GL_LESS);
643 glShadeModel(GL_SMOOTH);
644 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
645 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
646 glEnable(GL_LIGHTING);
648 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
649 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
650 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
651 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
652 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
653 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
654 glDepthMask(GL_TRUE);
657 else if (display_mode == DISP_TRANSPARENT)
659 glDisable(GL_DEPTH_TEST);
660 glShadeModel(GL_SMOOTH);
661 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
662 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
663 glEnable(GL_LIGHTING);
665 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
666 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
667 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
668 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
669 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
670 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
671 glDepthMask(GL_FALSE);
673 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
675 else /* display_mode == DISP_WIREFRAME */
677 glDisable(GL_DEPTH_TEST);
678 glShadeModel(GL_FLAT);
679 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
680 glDisable(GL_LIGHTING);
681 glDisable(GL_LIGHT0);
687 /* Redisplay the hypertorus. */
688 static void display_hypertorus(ModeInfo *mi)
690 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
692 if (!hp->button_pressed)
694 hp->alpha += speed_wx * hp->speed_scale;
695 if (hp->alpha >= 360.0)
697 hp->beta += speed_wy * hp->speed_scale;
698 if (hp->beta >= 360.0)
700 hp->delta += speed_wz * hp->speed_scale;
701 if (hp->delta >= 360.0)
703 hp->zeta += speed_xy * hp->speed_scale;
704 if (hp->zeta >= 360.0)
706 hp->eta += speed_xz * hp->speed_scale;
707 if (hp->eta >= 360.0)
709 hp->theta += speed_yz * hp->speed_scale;
710 if (hp->theta >= 360.0)
714 glMatrixMode(GL_PROJECTION);
716 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
718 if (hp->aspect >= 1.0)
719 glOrtho(-hp->aspect,hp->aspect,-1.0,1.0,0.1,100.0);
721 glOrtho(-1.0,1.0,-1.0/hp->aspect,1.0/hp->aspect,0.1,100.0);
725 gluPerspective(60.0,hp->aspect,0.1,100.0);
727 glMatrixMode(GL_MODELVIEW);
730 mi->polygon_count = hypertorus(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
734 ENTRYPOINT void reshape_hypertorus(ModeInfo *mi, int width, int height)
736 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
738 hp->WindW = (GLint)width;
739 hp->WindH = (GLint)height;
740 glViewport(0,0,width,height);
741 hp->aspect = (GLfloat)width/(GLfloat)height;
745 ENTRYPOINT Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
747 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
751 if (event->xany.type == KeyPress || event->xany.type == KeyRelease)
752 XLookupString (&event->xkey, &c, 1, &sym, 0);
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 if (sym == XK_Shift_L || sym == XK_Shift_R)
773 hp->current_trackball = 1;
774 if (hp->button_pressed)
775 gltrackball_start(hp->trackballs[hp->current_trackball],
776 event->xbutton.x, event->xbutton.y,
777 MI_WIDTH(mi), MI_HEIGHT(mi));
781 else if (event->xany.type == KeyRelease)
783 if (sym == XK_Shift_L || sym == XK_Shift_R)
785 hp->current_trackball = 0;
786 if (hp->button_pressed)
787 gltrackball_start(hp->trackballs[hp->current_trackball],
788 event->xbutton.x, event->xbutton.y,
789 MI_WIDTH(mi), MI_HEIGHT(mi));
793 else if (event->xany.type == MotionNotify && hp->button_pressed)
795 gltrackball_track(hp->trackballs[hp->current_trackball],
796 event->xmotion.x, event->xmotion.y,
797 MI_WIDTH(mi), MI_HEIGHT(mi));
806 *-----------------------------------------------------------------------------
807 *-----------------------------------------------------------------------------
809 *-----------------------------------------------------------------------------
810 *-----------------------------------------------------------------------------
814 *-----------------------------------------------------------------------------
815 * Initialize hypertorus. Called each time the window changes.
816 *-----------------------------------------------------------------------------
819 ENTRYPOINT void init_hypertorus(ModeInfo *mi)
821 hypertorusstruct *hp;
825 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
826 sizeof(hypertorusstruct));
830 hp = &hyper[MI_SCREEN(mi)];
833 hp->trackballs[0] = gltrackball_init();
834 hp->trackballs[1] = gltrackball_init();
835 hp->current_trackball = 0;
836 hp->button_pressed = False;
838 /* Set the display mode. */
839 if (!strcasecmp(mode,"wireframe") || !strcasecmp(mode,"0"))
841 display_mode = DISP_WIREFRAME;
843 else if (!strcasecmp(mode,"surface") || !strcasecmp(mode,"1"))
845 display_mode = DISP_SURFACE;
847 else if (!strcasecmp(mode,"transparent") || !strcasecmp(mode,"2"))
849 display_mode = DISP_TRANSPARENT;
853 display_mode = DISP_SURFACE;
856 /* Set the appearance. */
857 if (!strcasecmp(appear,"solid") || !strcasecmp(appear,"0"))
859 appearance = APPEARANCE_SOLID;
861 else if (!strcasecmp(appear,"bands") || !strcasecmp(appear,"1"))
863 appearance = APPEARANCE_BANDS;
866 else if (!strcasecmp(appear,"spirals-1") || !strcasecmp(appear,"3"))
868 appearance = APPEARANCE_SPIRALS;
871 else if (!strcasecmp(appear,"spirals-2") || !strcasecmp(appear,"4"))
873 appearance = APPEARANCE_SPIRALS;
876 else if (!strcasecmp(appear,"spirals-4") || !strcasecmp(appear,"5"))
878 appearance = APPEARANCE_SPIRALS;
881 else if (!strcasecmp(appear,"spirals-8") || !strcasecmp(appear,"6"))
883 appearance = APPEARANCE_SPIRALS;
886 else if (!strcasecmp(appear,"spirals-16") || !strcasecmp(appear,"7"))
888 appearance = APPEARANCE_SPIRALS;
893 appearance = APPEARANCE_BANDS;
897 /* Set the color mode. */
898 if (!strcasecmp(color_mode,"twosided"))
900 colors = COLORS_TWOSIDED;
902 else if (!strcasecmp(color_mode,"colorwheel"))
904 colors = COLORS_COLORWHEEL;
908 colors = COLORS_COLORWHEEL;
911 /* Set the 3d projection mode. */
912 if (!strcasecmp(proj_3d,"perspective") || !strcasecmp(proj_3d,"0"))
914 projection_3d = DISP_3D_PERSPECTIVE;
916 else if (!strcasecmp(proj_3d,"orthographic") || !strcasecmp(proj_3d,"1"))
918 projection_3d = DISP_3D_ORTHOGRAPHIC;
922 projection_3d = DISP_3D_PERSPECTIVE;
925 /* Set the 4d projection mode. */
926 if (!strcasecmp(proj_4d,"perspective") || !strcasecmp(proj_4d,"0"))
928 projection_4d = DISP_4D_PERSPECTIVE;
930 else if (!strcasecmp(proj_4d,"orthographic") || !strcasecmp(proj_4d,"1"))
932 projection_4d = DISP_4D_ORTHOGRAPHIC;
936 projection_4d = DISP_4D_PERSPECTIVE;
939 /* make multiple screens rotate at slightly different rates. */
940 hp->speed_scale = 0.9 + frand(0.3);
942 if ((hp->glx_context = init_GL(mi)) != NULL)
944 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
945 glDrawBuffer(GL_BACK);
955 *-----------------------------------------------------------------------------
956 * Called by the mainline code periodically to update the display.
957 *-----------------------------------------------------------------------------
959 ENTRYPOINT void draw_hypertorus(ModeInfo *mi)
961 Display *display = MI_DISPLAY(mi);
962 Window window = MI_WINDOW(mi);
963 hypertorusstruct *hp;
967 hp = &hyper[MI_SCREEN(mi)];
969 MI_IS_DRAWN(mi) = True;
970 if (!hp->glx_context)
973 glXMakeCurrent(display,window,*(hp->glx_context));
975 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
978 display_hypertorus(mi);
985 glXSwapBuffers(display,window);
990 *-----------------------------------------------------------------------------
991 * The display is being taken away from us. Free up malloc'ed
992 * memory and X resources that we've alloc'ed. Only called
993 * once, we must zap everything for every screen.
994 *-----------------------------------------------------------------------------
997 ENTRYPOINT void release_hypertorus(ModeInfo *mi)
1003 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1005 hypertorusstruct *hp = &hyper[screen];
1007 if (hp->glx_context)
1008 hp->glx_context = (GLXContext *)NULL;
1010 (void) free((void *)hyper);
1011 hyper = (hypertorusstruct *)NULL;
1017 ENTRYPOINT void change_hypertorus(ModeInfo *mi)
1019 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
1021 if (!hp->glx_context)
1024 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));
1027 #endif /* !STANDALONE */
1029 XSCREENSAVER_MODULE ("Hypertorus", hypertorus)