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" \
90 "*suppressRotationAnimation: True\n" \
92 # define refresh_hypertorus 0
93 # include "xlockmore.h" /* from the xscreensaver distribution */
94 #else /* !STANDALONE */
95 # include "xlock.h" /* from the xlockmore distribution */
96 #endif /* !STANDALONE */
100 #include "gltrackball.h"
104 ModStruct hypertorus_description =
105 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
106 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
107 25000, 1, 1, 1, 1.0, 4, "",
108 "Shows a hypertorus rotating in 4d", 0, NULL};
114 static int display_mode;
116 static int appearance;
117 static int num_spirals;
118 static char *color_mode;
120 static char *proj_3d;
121 static int projection_3d;
122 static char *proj_4d;
123 static int projection_4d;
124 static float speed_wx;
125 static float speed_wy;
126 static float speed_wz;
127 static float speed_xy;
128 static float speed_xz;
129 static float speed_yz;
131 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
132 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
135 static XrmOptionDescRec opts[] =
137 {"-mode", ".displayMode", XrmoptionSepArg, 0 },
138 {"-wireframe", ".displayMode", XrmoptionNoArg, "wireframe" },
139 {"-surface", ".displayMode", XrmoptionNoArg, "surface" },
140 {"-transparent", ".displayMode", XrmoptionNoArg, "transparent" },
141 {"-appearance", ".appearance", XrmoptionSepArg, 0 },
142 {"-solid", ".appearance", XrmoptionNoArg, "solid" },
143 {"-bands", ".appearance", XrmoptionNoArg, "bands" },
144 {"-spirals-1", ".appearance", XrmoptionNoArg, "spirals-1" },
145 {"-spirals-2", ".appearance", XrmoptionNoArg, "spirals-2" },
146 {"-spirals-4", ".appearance", XrmoptionNoArg, "spirals-4" },
147 {"-spirals-8", ".appearance", XrmoptionNoArg, "spirals-8" },
148 {"-spirals-16", ".appearance", XrmoptionNoArg, "spirals-16" },
149 {"-twosided", ".colors", XrmoptionNoArg, "twosided" },
150 {"-colorwheel", ".colors", XrmoptionNoArg, "colorwheel" },
151 {"-perspective-3d", ".projection3d", XrmoptionNoArg, "perspective" },
152 {"-orthographic-3d", ".projection3d", XrmoptionNoArg, "orthographic" },
153 {"-perspective-4d", ".projection4d", XrmoptionNoArg, "perspective" },
154 {"-orthographic-4d", ".projection4d", XrmoptionNoArg, "orthographic" },
155 {"-speed-wx", ".speedwx", XrmoptionSepArg, 0 },
156 {"-speed-wy", ".speedwy", XrmoptionSepArg, 0 },
157 {"-speed-wz", ".speedwz", XrmoptionSepArg, 0 },
158 {"-speed-xy", ".speedxy", XrmoptionSepArg, 0 },
159 {"-speed-xz", ".speedxz", XrmoptionSepArg, 0 },
160 {"-speed-yz", ".speedyz", XrmoptionSepArg, 0 }
163 static argtype vars[] =
165 { &mode, "displayMode", "DisplayMode", DEF_DISPLAY_MODE, t_String },
166 { &appear, "appearance", "Appearance", DEF_APPEARANCE, t_String },
167 { &color_mode, "colors", "Colors", DEF_COLORS, t_String },
168 { &proj_3d, "projection3d", "Projection3d", DEF_PROJECTION_3D, t_String },
169 { &proj_4d, "projection4d", "Projection4d", DEF_PROJECTION_4D, t_String },
170 { &speed_wx, "speedwx", "Speedwx", DEF_SPEEDWX, t_Float},
171 { &speed_wy, "speedwy", "Speedwy", DEF_SPEEDWY, t_Float},
172 { &speed_wz, "speedwz", "Speedwz", DEF_SPEEDWZ, t_Float},
173 { &speed_xy, "speedxy", "Speedxy", DEF_SPEEDXY, t_Float},
174 { &speed_xz, "speedxz", "Speedxz", DEF_SPEEDXZ, t_Float},
175 { &speed_yz, "speedyz", "Speedyz", DEF_SPEEDYZ, t_Float}
178 static OptionStruct desc[] =
180 { "-wireframe", "display the torus as a wireframe mesh" },
181 { "-surface", "display the torus as a solid surface" },
182 { "-transparent", "display the torus as a transparent surface" },
183 { "-solid", "display the torus as a solid object" },
184 { "-bands", "display the torus as see-through bands" },
185 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
186 { "-twosided", "display the torus with two colors" },
187 { "-colorwheel", "display the torus with a smooth color wheel" },
188 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
189 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
190 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
191 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
192 { "-speed-wx <arg>", "rotation speed around the wx plane" },
193 { "-speed-wy <arg>", "rotation speed around the wy plane" },
194 { "-speed-wz <arg>", "rotation speed around the wz plane" },
195 { "-speed-xy <arg>", "rotation speed around the xy plane" },
196 { "-speed-xz <arg>", "rotation speed around the xz plane" },
197 { "-speed-yz <arg>", "rotation speed around the yz plane" }
200 ENTRYPOINT ModeSpecOpt hypertorus_opts =
201 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
206 GLXContext *glx_context;
207 /* 4D rotation angles */
208 float alpha, beta, delta, zeta, eta, theta;
209 /* Aspect ratio of the current window */
211 /* Trackball states */
212 trackball_state *trackballs[2];
213 int current_trackball;
220 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
223 /* Add a rotation around the wx-plane to the matrix m. */
224 static void rotatewx(float m[4][4], float phi)
242 /* Add a rotation around the wy-plane to the matrix m. */
243 static void rotatewy(float m[4][4], float phi)
261 /* Add a rotation around the wz-plane to the matrix m. */
262 static void rotatewz(float m[4][4], float phi)
280 /* Add a rotation around the xy-plane to the matrix m. */
281 static void rotatexy(float m[4][4], float phi)
299 /* Add a rotation around the xz-plane to the matrix m. */
300 static void rotatexz(float m[4][4], float phi)
318 /* Add a rotation around the yz-plane to the matrix m. */
319 static void rotateyz(float m[4][4], float phi)
337 /* Compute the rotation matrix m from the rotation angles. */
338 static void rotateall(float al, float be, float de, float ze, float et,
339 float th, float m[4][4])
355 /* Multiply two rotation matrices: o=m*n. */
356 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
366 o[i][j] += m[i][k]*n[k][j];
372 /* Compute a 4D rotation matrix from two unit quaternions. */
373 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
375 double al, be, de, ze, et, th;
376 double r00, r01, r02, r12, r22;
378 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
379 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
380 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
381 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
382 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
384 al = atan2(-r12,r22)*180.0/M_PI;
385 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
386 de = atan2(-r01,r00)*180.0/M_PI;
388 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
389 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
390 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
391 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
392 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
394 et = atan2(-r12,r22)*180.0/M_PI;
395 th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
396 ze = atan2(-r01,r00)*180.0/M_PI;
398 rotateall(al,be,de,ze,et,-th,m);
402 /* Compute a fully saturated and bright color based on an angle. */
403 static void color(double angle)
409 if (colors != COLORS_COLORWHEEL)
413 angle = fmod(angle,2*M_PI);
415 angle = fmod(angle,-2*M_PI);
416 s = floor(angle/(M_PI/3));
417 t = angle/(M_PI/3)-s;
453 if (display_mode == DISP_TRANSPARENT)
458 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
462 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
463 will only work correctly if numu and numv are set to 64 or any higher
464 power of 2. Similarly, the banded appearance will only work correctly
465 if numu and numv are divisible by 4. */
466 static int hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
467 double vmax, int numu, int numv)
470 static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
471 static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
472 static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
473 static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
474 float p[3], pu[3], pv[3], n[3], mat[4][4];
475 int i, j, k, l, m, b, skew;
477 double cu, su, cv, sv;
478 double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
480 float q1[4], q2[4], r1[4][4], r2[4][4];
481 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
483 rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);
485 gltrackball_get_quaternion(hp->trackballs[0],q1);
486 gltrackball_get_quaternion(hp->trackballs[1],q2);
487 quats_to_rotmat(q1,q2,r2);
489 mult_rotmat(r2,r1,mat);
491 if (colors != COLORS_COLORWHEEL)
493 glColor3fv(mat_diff_red);
494 if (display_mode == DISP_TRANSPARENT)
496 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
497 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
501 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
502 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
506 #if 0 /* #### not working */
507 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
509 GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
510 int o = (int) current_device_rotation();
511 if (o != 0 && o != 180 && o != -180)
512 glScalef (1/h, 1/h, 1/h);
520 for (i=0; i<numu; i++)
522 if ((appearance == APPEARANCE_BANDS ||
523 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
525 if (display_mode == DISP_WIREFRAME)
526 glBegin(GL_QUAD_STRIP);
528 glBegin(GL_TRIANGLE_STRIP);
529 for (j=0; j<=numv; j++)
537 if (appearance == APPEARANCE_SPIRALS)
539 u += 4.0*skew/numv*v;
540 b = ((i/4)&(skew-1))*(numu/(4*skew));
541 color(ur*4*b/numu+umin);
570 r += mat[l][m]*xx[m];
571 s += mat[l][m]*xxu[m];
572 t += mat[l][m]*xxv[m];
578 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
582 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
589 s = x[3]+offset4d[3];
593 r = x[l]+offset4d[l];
594 p[l] = r/s+offset3d[l];
595 pu[l] = (xu[l]*s-r*xu[3])/t;
596 pv[l] = (xv[l]*s-r*xv[3])/t;
599 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
600 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
601 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
602 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
618 static void init(ModeInfo *mi)
620 static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
621 static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
622 static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
623 static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
624 static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
625 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
634 glMatrixMode(GL_PROJECTION);
636 if (projection_3d == DISP_3D_PERSPECTIVE)
637 gluPerspective(60.0,1.0,0.1,100.0);
639 glOrtho(-1.0,1.0,-1.0,1.0,0.1,100.0);;
640 glMatrixMode(GL_MODELVIEW);
643 # ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */
644 if (display_mode == DISP_WIREFRAME)
645 display_mode = DISP_SURFACE;
648 if (display_mode == DISP_SURFACE)
650 glEnable(GL_DEPTH_TEST);
651 glDepthFunc(GL_LESS);
652 glShadeModel(GL_SMOOTH);
653 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
654 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
655 glEnable(GL_LIGHTING);
657 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
658 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
659 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
660 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
661 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
662 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
663 glDepthMask(GL_TRUE);
666 else if (display_mode == DISP_TRANSPARENT)
668 glDisable(GL_DEPTH_TEST);
669 glShadeModel(GL_SMOOTH);
670 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
671 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
672 glEnable(GL_LIGHTING);
674 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
675 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
676 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
677 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
678 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
679 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
680 glDepthMask(GL_FALSE);
682 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
684 else /* display_mode == DISP_WIREFRAME */
686 glDisable(GL_DEPTH_TEST);
687 glShadeModel(GL_FLAT);
688 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
689 glDisable(GL_LIGHTING);
690 glDisable(GL_LIGHT0);
696 /* Redisplay the hypertorus. */
697 static void display_hypertorus(ModeInfo *mi)
699 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
701 if (!hp->button_pressed)
703 hp->alpha += speed_wx * hp->speed_scale;
704 if (hp->alpha >= 360.0)
706 hp->beta += speed_wy * hp->speed_scale;
707 if (hp->beta >= 360.0)
709 hp->delta += speed_wz * hp->speed_scale;
710 if (hp->delta >= 360.0)
712 hp->zeta += speed_xy * hp->speed_scale;
713 if (hp->zeta >= 360.0)
715 hp->eta += speed_xz * hp->speed_scale;
716 if (hp->eta >= 360.0)
718 hp->theta += speed_yz * hp->speed_scale;
719 if (hp->theta >= 360.0)
723 glMatrixMode(GL_PROJECTION);
725 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
727 if (hp->aspect >= 1.0)
728 glOrtho(-hp->aspect,hp->aspect,-1.0,1.0,0.1,100.0);
730 glOrtho(-1.0,1.0,-1.0/hp->aspect,1.0/hp->aspect,0.1,100.0);
734 gluPerspective(60.0,hp->aspect,0.1,100.0);
736 glMatrixMode(GL_MODELVIEW);
739 mi->polygon_count = hypertorus(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
743 ENTRYPOINT void reshape_hypertorus(ModeInfo *mi, int width, int height)
745 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
747 hp->WindW = (GLint)width;
748 hp->WindH = (GLint)height;
749 glViewport(0,0,width,height);
750 hp->aspect = (GLfloat)width/(GLfloat)height;
754 ENTRYPOINT Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
756 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
760 if (event->xany.type == KeyPress || event->xany.type == KeyRelease)
761 XLookupString (&event->xkey, &c, 1, &sym, 0);
763 if (event->xany.type == ButtonPress &&
764 event->xbutton.button == Button1)
766 hp->button_pressed = True;
767 gltrackball_start(hp->trackballs[hp->current_trackball],
768 event->xbutton.x, event->xbutton.y,
769 MI_WIDTH(mi), MI_HEIGHT(mi));
772 else if (event->xany.type == ButtonRelease &&
773 event->xbutton.button == Button1)
775 hp->button_pressed = False;
778 else if (event->xany.type == KeyPress)
780 if (sym == XK_Shift_L || sym == XK_Shift_R)
782 hp->current_trackball = 1;
783 if (hp->button_pressed)
784 gltrackball_start(hp->trackballs[hp->current_trackball],
785 event->xbutton.x, event->xbutton.y,
786 MI_WIDTH(mi), MI_HEIGHT(mi));
790 else if (event->xany.type == KeyRelease)
792 if (sym == XK_Shift_L || sym == XK_Shift_R)
794 hp->current_trackball = 0;
795 if (hp->button_pressed)
796 gltrackball_start(hp->trackballs[hp->current_trackball],
797 event->xbutton.x, event->xbutton.y,
798 MI_WIDTH(mi), MI_HEIGHT(mi));
802 else if (event->xany.type == MotionNotify && hp->button_pressed)
804 gltrackball_track(hp->trackballs[hp->current_trackball],
805 event->xmotion.x, event->xmotion.y,
806 MI_WIDTH(mi), MI_HEIGHT(mi));
815 *-----------------------------------------------------------------------------
816 *-----------------------------------------------------------------------------
818 *-----------------------------------------------------------------------------
819 *-----------------------------------------------------------------------------
823 *-----------------------------------------------------------------------------
824 * Initialize hypertorus. Called each time the window changes.
825 *-----------------------------------------------------------------------------
828 ENTRYPOINT void init_hypertorus(ModeInfo *mi)
830 hypertorusstruct *hp;
834 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
835 sizeof(hypertorusstruct));
839 hp = &hyper[MI_SCREEN(mi)];
842 hp->trackballs[0] = gltrackball_init(True);
843 hp->trackballs[1] = gltrackball_init(True);
844 hp->current_trackball = 0;
845 hp->button_pressed = False;
847 /* Set the display mode. */
848 if (!strcasecmp(mode,"wireframe") || !strcasecmp(mode,"0"))
850 display_mode = DISP_WIREFRAME;
852 else if (!strcasecmp(mode,"surface") || !strcasecmp(mode,"1"))
854 display_mode = DISP_SURFACE;
856 else if (!strcasecmp(mode,"transparent") || !strcasecmp(mode,"2"))
858 display_mode = DISP_TRANSPARENT;
862 display_mode = DISP_SURFACE;
865 /* Set the appearance. */
866 if (!strcasecmp(appear,"solid") || !strcasecmp(appear,"0"))
868 appearance = APPEARANCE_SOLID;
870 else if (!strcasecmp(appear,"bands") || !strcasecmp(appear,"1"))
872 appearance = APPEARANCE_BANDS;
875 else if (!strcasecmp(appear,"spirals-1") || !strcasecmp(appear,"3"))
877 appearance = APPEARANCE_SPIRALS;
880 else if (!strcasecmp(appear,"spirals-2") || !strcasecmp(appear,"4"))
882 appearance = APPEARANCE_SPIRALS;
885 else if (!strcasecmp(appear,"spirals-4") || !strcasecmp(appear,"5"))
887 appearance = APPEARANCE_SPIRALS;
890 else if (!strcasecmp(appear,"spirals-8") || !strcasecmp(appear,"6"))
892 appearance = APPEARANCE_SPIRALS;
895 else if (!strcasecmp(appear,"spirals-16") || !strcasecmp(appear,"7"))
897 appearance = APPEARANCE_SPIRALS;
902 appearance = APPEARANCE_BANDS;
906 /* Set the color mode. */
907 if (!strcasecmp(color_mode,"twosided"))
909 colors = COLORS_TWOSIDED;
911 else if (!strcasecmp(color_mode,"colorwheel"))
913 colors = COLORS_COLORWHEEL;
917 colors = COLORS_COLORWHEEL;
920 /* Set the 3d projection mode. */
921 if (!strcasecmp(proj_3d,"perspective") || !strcasecmp(proj_3d,"0"))
923 projection_3d = DISP_3D_PERSPECTIVE;
925 else if (!strcasecmp(proj_3d,"orthographic") || !strcasecmp(proj_3d,"1"))
927 projection_3d = DISP_3D_ORTHOGRAPHIC;
931 projection_3d = DISP_3D_PERSPECTIVE;
934 /* Set the 4d projection mode. */
935 if (!strcasecmp(proj_4d,"perspective") || !strcasecmp(proj_4d,"0"))
937 projection_4d = DISP_4D_PERSPECTIVE;
939 else if (!strcasecmp(proj_4d,"orthographic") || !strcasecmp(proj_4d,"1"))
941 projection_4d = DISP_4D_ORTHOGRAPHIC;
945 projection_4d = DISP_4D_PERSPECTIVE;
948 /* make multiple screens rotate at slightly different rates. */
949 hp->speed_scale = 0.9 + frand(0.3);
951 if ((hp->glx_context = init_GL(mi)) != NULL)
953 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
954 glDrawBuffer(GL_BACK);
964 *-----------------------------------------------------------------------------
965 * Called by the mainline code periodically to update the display.
966 *-----------------------------------------------------------------------------
968 ENTRYPOINT void draw_hypertorus(ModeInfo *mi)
970 Display *display = MI_DISPLAY(mi);
971 Window window = MI_WINDOW(mi);
972 hypertorusstruct *hp;
976 hp = &hyper[MI_SCREEN(mi)];
978 MI_IS_DRAWN(mi) = True;
979 if (!hp->glx_context)
982 glXMakeCurrent(display,window,*(hp->glx_context));
984 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
987 display_hypertorus(mi);
994 glXSwapBuffers(display,window);
999 *-----------------------------------------------------------------------------
1000 * The display is being taken away from us. Free up malloc'ed
1001 * memory and X resources that we've alloc'ed. Only called
1002 * once, we must zap everything for every screen.
1003 *-----------------------------------------------------------------------------
1006 ENTRYPOINT void release_hypertorus(ModeInfo *mi)
1012 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
1014 hypertorusstruct *hp = &hyper[screen];
1016 if (hp->glx_context)
1017 hp->glx_context = (GLXContext *)NULL;
1019 (void) free((void *)hyper);
1020 hyper = (hypertorusstruct *)NULL;
1026 ENTRYPOINT void change_hypertorus(ModeInfo *mi)
1028 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
1030 if (!hp->glx_context)
1033 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));
1036 #endif /* !STANDALONE */
1038 XSCREENSAVER_MODULE ("Hypertorus", hypertorus)