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-2007 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
30 * This program shows the Clifford torus as it rotates in 4d. The Clifford
31 * torus is a torus lies on the "surface" of the hypersphere in 4d. The
32 * program projects the 4d torus to 3d using either a perspective or an
33 * orthographic projection. Of the two alternatives, the perspecitve
34 * projection looks much more appealing. In orthographic projections the
35 * torus degenerates into a doubly covered cylinder for some angles. The
36 * projected 3d torus can then be projected to the screen either perspectively
37 * or orthographically. There are three display modes for the torus: mesh
38 * (wireframe), solid, or transparent. Furthermore, the appearance of the
39 * torus can be as a solid object or as a set of see-through bands or
40 * see-through spirals. Finally, the colors with with the torus is drawn can
41 * be set to either two-sided or to colorwheel. In the first case, the torus
42 * is drawn with red on the outside and green on the inside. This mode
43 * enables you to see that the torus turns inside-out as it rotates in 4d.
44 * The second mode draws the torus in a fully saturated color wheel. This
45 * gives a very nice effect when combined with the see-through bands or
46 * see-through spirals mode. The rotation speed for each of the six planes
47 * around which the torus rotates can be chosen. This program is very much
48 * inspired by Thomas Banchoff's book "Beyond the Third Dimension: Geometry,
49 * Computer Graphics, and Higher Dimensions", Scientific American Library,
54 #define M_PI 3.14159265358979323846
57 #define DISP_WIREFRAME 0
58 #define DISP_WIREFRAME_STR "0"
59 #define DISP_SURFACE 1
60 #define DISP_SURFACE_STR "1"
61 #define DISP_TRANSPARENT 2
62 #define DISP_TRANSPARENT_STR "2"
64 #define APPEARANCE_SOLID 0
65 #define APPEARANCE_SOLID_STR "0"
66 #define APPEARANCE_BANDS 1
67 #define APPEARANCE_BANDS_STR "1"
68 #define APPEARANCE_SPIRALS 2
69 #define APPEARANCE_SPIRALS_STR "2"
70 #define APPEARANCE_SPIRALS_1 3
71 #define APPEARANCE_SPIRALS_1_STR "3"
72 #define APPEARANCE_SPIRALS_2 4
73 #define APPEARANCE_SPIRALS_2_STR "4"
74 #define APPEARANCE_SPIRALS_4 5
75 #define APPEARANCE_SPIRALS_4_STR "5"
76 #define APPEARANCE_SPIRALS_8 6
77 #define APPEARANCE_SPIRALS_8_STR "6"
78 #define APPEARANCE_SPIRALS_16 7
79 #define APPEARANCE_SPIRALS_16_STR "7"
81 #define COLORS_TWOSIDED 0
82 #define COLORS_TWOSIDED_STR "0"
83 #define COLORS_COLORWHEEL 1
84 #define COLORS_COLORWHEEL_STR "1"
86 #define DISP_3D_PERSPECTIVE 0
87 #define DISP_3D_PERSPECTIVE_STR "0"
88 #define DISP_3D_ORTHOGRAPHIC 1
89 #define DISP_3D_ORTHOGRAPHIC_STR "1"
91 #define DISP_4D_PERSPECTIVE 0
92 #define DISP_4D_PERSPECTIVE_STR "0"
93 #define DISP_4D_ORTHOGRAPHIC 1
94 #define DISP_4D_ORTHOGRAPHIC_STR "1"
97 #define DALPHA_STR "1.1"
99 #define DBETA_STR "1.3"
101 #define DDELTA_STR "1.5"
103 #define DZETA_STR "1.7"
105 #define DETA_STR "1.9"
107 #define DTHETA_STR "2.1"
109 #define DEF_DISPLAY_MODE DISP_TRANSPARENT_STR
110 #define DEF_APPEARANCE APPEARANCE_BANDS_STR
111 #define DEF_COLORS COLORS_COLORWHEEL_STR
112 #define DEF_3D_PROJECTION DISP_3D_PERSPECTIVE_STR
113 #define DEF_4D_PROJECTION DISP_4D_PERSPECTIVE_STR
114 #define DEF_DALPHA DALPHA_STR
115 #define DEF_DBETA DBETA_STR
116 #define DEF_DDELTA DDELTA_STR
117 #define DEF_DZETA DZETA_STR
118 #define DEF_DETA DETA_STR
119 #define DEF_DTHETA DTHETA_STR
122 # define DEFAULTS "*delay: 25000 \n" \
123 "*showFPS: False \n" \
125 # define refresh_hypertorus 0
126 # include "xlockmore.h" /* from the xscreensaver distribution */
127 #else /* !STANDALONE */
128 # include "xlock.h" /* from the xlockmore distribution */
129 #endif /* !STANDALONE */
133 #include <X11/keysym.h>
135 #include "gltrackball.h"
139 ModStruct hypertorus_description =
140 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
141 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
142 25000, 1, 1, 1, 1.0, 4, "",
143 "Shows a hypertorus rotating in 4d", 0, NULL};
148 static int display_mode;
149 static int appearance;
150 static int num_spirals;
152 static int projection_3d;
153 static int projection_4d;
154 static float speed_wx;
155 static float speed_wy;
156 static float speed_wz;
157 static float speed_xy;
158 static float speed_xz;
159 static float speed_yz;
161 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
162 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
165 static XrmOptionDescRec opts[] =
167 {"-mode", ".hypertorus.displayMode", XrmoptionSepArg, 0 },
168 {"-wireframe", ".hypertorus.displayMode", XrmoptionNoArg,
169 DISP_WIREFRAME_STR },
170 {"-surface", ".hypertorus.displayMode", XrmoptionNoArg,
172 {"-transparent", ".hypertorus.displayMode", XrmoptionNoArg,
173 DISP_TRANSPARENT_STR },
175 {"-appearance", ".hypertorus.appearance", XrmoptionSepArg, 0 },
176 {"-solid", ".hypertorus.appearance", XrmoptionNoArg,
177 APPEARANCE_SOLID_STR },
178 {"-bands", ".hypertorus.appearance", XrmoptionNoArg,
179 APPEARANCE_BANDS_STR },
180 {"-spirals-1", ".hypertorus.appearance", XrmoptionNoArg,
181 APPEARANCE_SPIRALS_1_STR },
182 {"-spirals-2", ".hypertorus.appearance", XrmoptionNoArg,
183 APPEARANCE_SPIRALS_2_STR },
184 {"-spirals-4", ".hypertorus.appearance", XrmoptionNoArg,
185 APPEARANCE_SPIRALS_4_STR },
186 {"-spirals-8", ".hypertorus.appearance", XrmoptionNoArg,
187 APPEARANCE_SPIRALS_8_STR },
188 {"-spirals-16", ".hypertorus.appearance", XrmoptionNoArg,
189 APPEARANCE_SPIRALS_16_STR },
190 {"-twosided", ".hypertorus.colors", XrmoptionNoArg,
191 COLORS_TWOSIDED_STR },
192 {"-colorwheel", ".hypertorus.colors", XrmoptionNoArg,
193 COLORS_COLORWHEEL_STR },
194 {"-perspective-3d", ".hypertorus.projection3d", XrmoptionNoArg,
195 DISP_3D_PERSPECTIVE_STR },
196 {"-orthographic-3d", ".hypertorus.projection3d", XrmoptionNoArg,
197 DISP_3D_ORTHOGRAPHIC_STR },
198 {"-perspective-4d", ".hypertorus.projection4d", XrmoptionNoArg,
199 DISP_4D_PERSPECTIVE_STR },
200 {"-orthographic-4d", ".hypertorus.projection4d", XrmoptionNoArg,
201 DISP_4D_ORTHOGRAPHIC_STR },
202 {"-speed-wx", ".hypertorus.speedwx", XrmoptionSepArg, 0 },
203 {"-speed-wy", ".hypertorus.speedwy", XrmoptionSepArg, 0 },
204 {"-speed-wz", ".hypertorus.speedwz", XrmoptionSepArg, 0 },
205 {"-speed-xy", ".hypertorus.speedxy", XrmoptionSepArg, 0 },
206 {"-speed-xz", ".hypertorus.speedxz", XrmoptionSepArg, 0 },
207 {"-speed-yz", ".hypertorus.speedyz", XrmoptionSepArg, 0 }
210 static argtype vars[] =
212 { &display_mode, "displayMode", "DisplayMode",
213 DEF_DISPLAY_MODE, t_Int },
214 { &appearance, "appearance", "Appearance",
215 DEF_APPEARANCE, t_Int },
216 { &colors, "colors", "Colors",
218 { &projection_3d, "projection3d", "Projection3d",
219 DEF_3D_PROJECTION, t_Int },
220 { &projection_4d, "projection4d", "Projection4d",
221 DEF_4D_PROJECTION, t_Int },
222 { &speed_wx, "speedwx", "Speedwx",
223 DEF_DALPHA, t_Float},
224 { &speed_wy, "speedwy", "Speedwy",
226 { &speed_wz, "speedwz", "Speedwz",
227 DEF_DDELTA, t_Float},
228 { &speed_xy, "speedxy", "Speedxy",
230 { &speed_xz, "speedxz", "Speedxz",
232 { &speed_yz, "speedyz", "Speedyz",
236 static OptionStruct desc[] =
238 { "-wireframe", "display the torus as a wireframe mesh" },
239 { "-surface", "display the torus as a solid surface" },
240 { "-transparent", "display the torus as a transparent surface" },
241 { "-solid", "display the torus as a solid object" },
242 { "-bands", "display the torus as see-through bands" },
243 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
244 { "-twosided", "display the torus with two colors" },
245 { "-colorwheel", "display the torus with a smooth color wheel" },
246 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
247 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
248 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
249 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
250 { "-speed-wx <arg>", "rotation speed around the wx plane" },
251 { "-speed-wy <arg>", "rotation speed around the wy plane" },
252 { "-speed-wz <arg>", "rotation speed around the wz plane" },
253 { "-speed-xy <arg>", "rotation speed around the xy plane" },
254 { "-speed-xz <arg>", "rotation speed around the xz plane" },
255 { "-speed-yz <arg>", "rotation speed around the yz plane" }
258 ENTRYPOINT ModeSpecOpt hypertorus_opts =
259 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
264 GLXContext *glx_context;
265 /* 4D rotation angles */
266 float alpha, beta, delta, zeta, eta, theta;
267 /* Aspect ratio of the current window */
269 /* Trackball states */
270 trackball_state *trackballs[2];
271 int current_trackball;
278 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
281 /* Add a rotation around the wx-plane to the matrix m. */
282 static void rotatewx(float m[4][4], float phi)
300 /* Add a rotation around the wy-plane to the matrix m. */
301 static void rotatewy(float m[4][4], float phi)
319 /* Add a rotation around the wz-plane to the matrix m. */
320 static void rotatewz(float m[4][4], float phi)
338 /* Add a rotation around the xy-plane to the matrix m. */
339 static void rotatexy(float m[4][4], float phi)
357 /* Add a rotation around the xz-plane to the matrix m. */
358 static void rotatexz(float m[4][4], float phi)
376 /* Add a rotation around the yz-plane to the matrix m. */
377 static void rotateyz(float m[4][4], float phi)
395 /* Compute the rotation matrix m from the rotation angles. */
396 static void rotateall(float al, float be, float de, float ze, float et,
397 float th, float m[4][4])
413 /* Multiply two rotation matrices: o=m*n. */
414 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
424 o[i][j] += m[i][k]*n[k][j];
430 /* Compute a 4D rotation matrix from two unit quaternions. */
431 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
433 double al, be, de, ze, et, th;
434 double r00, r01, r02, r12, r22;
436 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
437 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
438 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
439 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
440 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
442 al = atan2(-r12,r22)*180.0/M_PI;
443 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
444 de = atan2(-r01,r00)*180.0/M_PI;
446 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
447 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
448 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
449 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
450 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
452 et = atan2(-r12,r22)*180.0/M_PI;
453 th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
454 ze = atan2(-r01,r00)*180.0/M_PI;
456 rotateall(al,be,de,ze,et,-th,m);
460 /* Compute a fully saturated and bright color based on an angle. */
461 static void color(double angle)
467 if (colors != COLORS_COLORWHEEL)
471 angle = fmod(angle,2*M_PI);
473 angle = fmod(angle,-2*M_PI);
474 s = floor(angle/(M_PI/3));
475 t = angle/(M_PI/3)-s;
511 if (display_mode == DISP_TRANSPARENT)
516 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
520 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
521 will only work correctly if numu and numv are set to 64 or any higher
522 power of 2. Similarly, the banded appearance will only work correctly
523 if numu and numv are divisible by 4. */
524 static int hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
525 double vmax, int numu, int numv)
528 static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
529 static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
530 static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
531 static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
532 float p[3], pu[3], pv[3], n[3], mat[4][4];
533 int i, j, k, l, m, b, skew;
535 double cu, su, cv, sv;
536 double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
538 float q1[4], q2[4], r1[4][4], r2[4][4];
539 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
541 rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);
543 gltrackball_get_quaternion(hp->trackballs[0],q1);
544 gltrackball_get_quaternion(hp->trackballs[1],q2);
545 quats_to_rotmat(q1,q2,r2);
547 mult_rotmat(r2,r1,mat);
549 if (colors != COLORS_COLORWHEEL)
551 glColor3fv(mat_diff_red);
552 if (display_mode == DISP_TRANSPARENT)
554 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
555 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
559 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
560 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
567 for (i=0; i<numu; i++)
569 if ((appearance == APPEARANCE_BANDS ||
570 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
572 if (display_mode == DISP_WIREFRAME)
573 glBegin(GL_QUAD_STRIP);
575 glBegin(GL_TRIANGLE_STRIP);
576 for (j=0; j<=numv; j++)
584 if (appearance == APPEARANCE_SPIRALS)
586 u += 4.0*skew/numv*v;
587 b = ((i/4)&(skew-1))*(numu/(4*skew));
588 color(ur*4*b/numu+umin);
617 r += mat[l][m]*xx[m];
618 s += mat[l][m]*xxu[m];
619 t += mat[l][m]*xxv[m];
625 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
629 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
636 s = x[3]+offset4d[3];
640 r = x[l]+offset4d[l];
641 p[l] = r/s+offset3d[l];
642 pu[l] = (xu[l]*s-r*xu[3])/t;
643 pv[l] = (xv[l]*s-r*xv[3])/t;
646 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
647 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
648 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
649 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
665 static void init(ModeInfo *mi)
667 static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
668 static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
669 static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
670 static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
671 static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
672 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
674 if (appearance >= APPEARANCE_SPIRALS_1)
676 num_spirals = 1<<(appearance-APPEARANCE_SPIRALS_1);
677 appearance = APPEARANCE_SPIRALS;
691 glMatrixMode(GL_PROJECTION);
693 if (projection_3d == DISP_3D_PERSPECTIVE)
694 gluPerspective(60.0,1.0,0.1,100.0);
696 glOrtho(-1.0,1.0,-1.0,1.0,0.1,100.0);;
697 glMatrixMode(GL_MODELVIEW);
700 if (display_mode == DISP_WIREFRAME)
702 glDisable(GL_DEPTH_TEST);
703 glShadeModel(GL_FLAT);
704 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
705 glDisable(GL_LIGHTING);
706 glDisable(GL_LIGHT0);
709 else if (display_mode == DISP_SURFACE)
711 glEnable(GL_DEPTH_TEST);
712 glDepthFunc(GL_LESS);
713 glShadeModel(GL_SMOOTH);
714 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
715 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
716 glEnable(GL_LIGHTING);
718 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
719 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
720 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
721 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
722 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
723 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
724 glDepthMask(GL_TRUE);
727 else if (display_mode == DISP_TRANSPARENT)
729 glDisable(GL_DEPTH_TEST);
730 glShadeModel(GL_SMOOTH);
731 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
732 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
733 glEnable(GL_LIGHTING);
735 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
736 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
737 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
738 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
739 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
740 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
741 glDepthMask(GL_FALSE);
743 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
747 glDisable(GL_DEPTH_TEST);
748 glShadeModel(GL_FLAT);
749 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
750 glDisable(GL_LIGHTING);
751 glDisable(GL_LIGHT0);
757 /* Redisplay the hypertorus. */
758 static void display_hypertorus(ModeInfo *mi)
760 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
762 if (!hp->button_pressed)
764 hp->alpha += speed_wx * hp->speed_scale;
765 if (hp->alpha >= 360.0)
767 hp->beta += speed_wy * hp->speed_scale;
768 if (hp->beta >= 360.0)
770 hp->delta += speed_wz * hp->speed_scale;
771 if (hp->delta >= 360.0)
773 hp->zeta += speed_xy * hp->speed_scale;
774 if (hp->zeta >= 360.0)
776 hp->eta += speed_xz * hp->speed_scale;
777 if (hp->eta >= 360.0)
779 hp->theta += speed_yz * hp->speed_scale;
780 if (hp->theta >= 360.0)
784 glMatrixMode(GL_PROJECTION);
786 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
788 if (hp->aspect >= 1.0)
789 glOrtho(-hp->aspect,hp->aspect,-1.0,1.0,0.1,100.0);
791 glOrtho(-1.0,1.0,-1.0/hp->aspect,1.0/hp->aspect,0.1,100.0);
795 gluPerspective(60.0,hp->aspect,0.1,100.0);
797 glMatrixMode(GL_MODELVIEW);
800 mi->polygon_count = hypertorus(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
804 ENTRYPOINT void reshape_hypertorus(ModeInfo *mi, int width, int height)
806 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
808 hp->WindW = (GLint)width;
809 hp->WindH = (GLint)height;
810 glViewport(0,0,width,height);
811 hp->aspect = (GLfloat)width/(GLfloat)height;
815 ENTRYPOINT Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
817 Display *display = MI_DISPLAY(mi);
818 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
821 if (event->xany.type == ButtonPress &&
822 event->xbutton.button == Button1)
824 hp->button_pressed = True;
825 gltrackball_start(hp->trackballs[hp->current_trackball],
826 event->xbutton.x, event->xbutton.y,
827 MI_WIDTH(mi), MI_HEIGHT(mi));
830 else if (event->xany.type == ButtonRelease &&
831 event->xbutton.button == Button1)
833 hp->button_pressed = False;
836 else if (event->xany.type == KeyPress)
838 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
839 if (sym == XK_Shift_L || sym == XK_Shift_R)
841 hp->current_trackball = 1;
842 if (hp->button_pressed)
843 gltrackball_start(hp->trackballs[hp->current_trackball],
844 event->xbutton.x, event->xbutton.y,
845 MI_WIDTH(mi), MI_HEIGHT(mi));
849 else if (event->xany.type == KeyRelease)
851 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
852 if (sym == XK_Shift_L || sym == XK_Shift_R)
854 hp->current_trackball = 0;
855 if (hp->button_pressed)
856 gltrackball_start(hp->trackballs[hp->current_trackball],
857 event->xbutton.x, event->xbutton.y,
858 MI_WIDTH(mi), MI_HEIGHT(mi));
862 else if (event->xany.type == MotionNotify && hp->button_pressed)
864 gltrackball_track(hp->trackballs[hp->current_trackball],
865 event->xmotion.x, event->xmotion.y,
866 MI_WIDTH(mi), MI_HEIGHT(mi));
875 *-----------------------------------------------------------------------------
876 *-----------------------------------------------------------------------------
878 *-----------------------------------------------------------------------------
879 *-----------------------------------------------------------------------------
883 *-----------------------------------------------------------------------------
884 * Initialize hypertorus. Called each time the window changes.
885 *-----------------------------------------------------------------------------
888 ENTRYPOINT void init_hypertorus(ModeInfo *mi)
890 hypertorusstruct *hp;
894 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
895 sizeof(hypertorusstruct));
899 hp = &hyper[MI_SCREEN(mi)];
902 hp->trackballs[0] = gltrackball_init();
903 hp->trackballs[1] = gltrackball_init();
904 hp->current_trackball = 0;
905 hp->button_pressed = False;
907 /* make multiple screens rotate at slightly different rates. */
908 hp->speed_scale = 0.9 + frand(0.3);
910 if ((hp->glx_context = init_GL(mi)) != NULL)
912 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
913 glDrawBuffer(GL_BACK);
923 *-----------------------------------------------------------------------------
924 * Called by the mainline code periodically to update the display.
925 *-----------------------------------------------------------------------------
927 ENTRYPOINT void draw_hypertorus(ModeInfo *mi)
929 Display *display = MI_DISPLAY(mi);
930 Window window = MI_WINDOW(mi);
931 hypertorusstruct *hp;
935 hp = &hyper[MI_SCREEN(mi)];
937 MI_IS_DRAWN(mi) = True;
938 if (!hp->glx_context)
941 glXMakeCurrent(display,window,*(hp->glx_context));
943 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
946 display_hypertorus(mi);
953 glXSwapBuffers(display,window);
958 *-----------------------------------------------------------------------------
959 * The display is being taken away from us. Free up malloc'ed
960 * memory and X resources that we've alloc'ed. Only called
961 * once, we must zap everything for every screen.
962 *-----------------------------------------------------------------------------
965 ENTRYPOINT void release_hypertorus(ModeInfo *mi)
971 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
973 hypertorusstruct *hp = &hyper[screen];
976 hp->glx_context = (GLXContext *)NULL;
978 (void) free((void *)hyper);
979 hyper = (hypertorusstruct *)NULL;
985 ENTRYPOINT void change_hypertorus(ModeInfo *mi)
987 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
989 if (!hp->glx_context)
992 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));
995 #endif /* !STANDALONE */
997 XSCREENSAVER_MODULE ("Hypertorus", hypertorus)