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-2005 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
29 * This program shows the Clifford torus as it rotates in 4d. The Clifford
30 * torus is a torus lies on the "surface" of the hypersphere in 4d. The
31 * program projects the 4d torus to 3d using either a perspective or an
32 * orthographic projection. Of the two alternatives, the perspecitve
33 * projection looks much more appealing. In orthographic projections the
34 * torus degenerates into a doubly covered cylinder for some angles. The
35 * projected 3d torus can then be projected to the screen either perspectively
36 * or orthographically. There are three display modes for the torus: mesh
37 * (wireframe), solid, or transparent. Furthermore, the appearance of the
38 * torus can be as a solid object or as a set of see-through bands or
39 * see-through spirals. Finally, the colors with with the torus is drawn can
40 * be set to either two-sided or to colorwheel. In the first case, the torus
41 * is drawn with red on the outside and green on the inside. This mode
42 * enables you to see that the torus turns inside-out as it rotates in 4d.
43 * The second mode draws the torus in a fully saturated color wheel. This
44 * gives a very nice effect when combined with the see-through bands or
45 * see-through spirals mode. The rotation speed for each of the six planes
46 * around which the torus rotates can be chosen. This program is very much
47 * inspired by Thomas Banchoff's book "Beyond the Third Dimension: Geometry,
48 * Computer Graphics, and Higher Dimensions", Scientific American Library,
53 #define M_PI 3.14159265358979323846
56 #define DISP_WIREFRAME 0
57 #define DISP_WIREFRAME_STR "0"
58 #define DISP_SURFACE 1
59 #define DISP_SURFACE_STR "1"
60 #define DISP_TRANSPARENT 2
61 #define DISP_TRANSPARENT_STR "2"
63 #define APPEARANCE_SOLID 0
64 #define APPEARANCE_SOLID_STR "0"
65 #define APPEARANCE_BANDS 1
66 #define APPEARANCE_BANDS_STR "1"
67 #define APPEARANCE_SPIRALS 2
68 #define APPEARANCE_SPIRALS_STR "2"
69 #define APPEARANCE_SPIRALS_1 3
70 #define APPEARANCE_SPIRALS_1_STR "3"
71 #define APPEARANCE_SPIRALS_2 4
72 #define APPEARANCE_SPIRALS_2_STR "4"
73 #define APPEARANCE_SPIRALS_4 5
74 #define APPEARANCE_SPIRALS_4_STR "5"
75 #define APPEARANCE_SPIRALS_8 6
76 #define APPEARANCE_SPIRALS_8_STR "6"
77 #define APPEARANCE_SPIRALS_16 7
78 #define APPEARANCE_SPIRALS_16_STR "7"
80 #define COLORS_TWOSIDED 0
81 #define COLORS_TWOSIDED_STR "0"
82 #define COLORS_COLORWHEEL 1
83 #define COLORS_COLORWHEEL_STR "1"
85 #define DISP_3D_PERSPECTIVE 0
86 #define DISP_3D_PERSPECTIVE_STR "0"
87 #define DISP_3D_ORTHOGRAPHIC 1
88 #define DISP_3D_ORTHOGRAPHIC_STR "1"
90 #define DISP_4D_PERSPECTIVE 0
91 #define DISP_4D_PERSPECTIVE_STR "0"
92 #define DISP_4D_ORTHOGRAPHIC 1
93 #define DISP_4D_ORTHOGRAPHIC_STR "1"
96 #define DALPHA_STR "1.1"
98 #define DBETA_STR "1.3"
100 #define DDELTA_STR "1.5"
102 #define DZETA_STR "1.7"
104 #define DETA_STR "1.9"
106 #define DTHETA_STR "2.1"
108 #define DEF_DISPLAY_MODE DISP_SURFACE_STR
109 #define DEF_APPEARANCE APPEARANCE_BANDS_STR
110 #define DEF_COLORS COLORS_COLORWHEEL_STR
111 #define DEF_3D_PROJECTION DISP_3D_PERSPECTIVE_STR
112 #define DEF_4D_PROJECTION DISP_4D_PERSPECTIVE_STR
113 #define DEF_DALPHA DALPHA_STR
114 #define DEF_DBETA DBETA_STR
115 #define DEF_DDELTA DDELTA_STR
116 #define DEF_DZETA DZETA_STR
117 #define DEF_DETA DETA_STR
118 #define DEF_DTHETA DTHETA_STR
121 # define DEFAULTS "*delay: 25000 \n" \
122 "*showFPS: False \n" \
124 # define refresh_hypertorus 0
125 # include "xlockmore.h" /* from the xscreensaver distribution */
126 #else /* !STANDALONE */
127 # include "xlock.h" /* from the xlockmore distribution */
128 #endif /* !STANDALONE */
132 #include <X11/keysym.h>
134 #include "gltrackball.h"
138 ModStruct hypertorus_description =
139 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
140 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
141 25000, 1, 1, 1, 1.0, 4, "",
142 "Shows a hypertorus rotating in 4d", 0, NULL};
147 static int display_mode;
148 static int appearance;
149 static int num_spirals;
151 static int projection_3d;
152 static int projection_4d;
153 static float speed_wx;
154 static float speed_wy;
155 static float speed_wz;
156 static float speed_xy;
157 static float speed_xz;
158 static float speed_yz;
160 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
161 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
164 static XrmOptionDescRec opts[] =
166 {"-mode", ".hypertorus.displayMode", XrmoptionSepArg, 0 },
167 {"-wireframe", ".hypertorus.displayMode", XrmoptionNoArg,
168 DISP_WIREFRAME_STR },
169 {"-surface", ".hypertorus.displayMode", XrmoptionNoArg,
171 {"-transparent", ".hypertorus.displayMode", XrmoptionNoArg,
172 DISP_TRANSPARENT_STR },
174 {"-appearance", ".hypertorus.appearance", XrmoptionSepArg, 0 },
175 {"-solid", ".hypertorus.appearance", XrmoptionNoArg,
176 APPEARANCE_SOLID_STR },
177 {"-bands", ".hypertorus.appearance", XrmoptionNoArg,
178 APPEARANCE_BANDS_STR },
179 {"-spirals-1", ".hypertorus.appearance", XrmoptionNoArg,
180 APPEARANCE_SPIRALS_1_STR },
181 {"-spirals-2", ".hypertorus.appearance", XrmoptionNoArg,
182 APPEARANCE_SPIRALS_2_STR },
183 {"-spirals-4", ".hypertorus.appearance", XrmoptionNoArg,
184 APPEARANCE_SPIRALS_4_STR },
185 {"-spirals-8", ".hypertorus.appearance", XrmoptionNoArg,
186 APPEARANCE_SPIRALS_8_STR },
187 {"-spirals-16", ".hypertorus.appearance", XrmoptionNoArg,
188 APPEARANCE_SPIRALS_16_STR },
189 {"-twosided", ".hypertorus.colors", XrmoptionNoArg,
190 COLORS_TWOSIDED_STR },
191 {"-colorwheel", ".hypertorus.colors", XrmoptionNoArg,
192 COLORS_COLORWHEEL_STR },
193 {"-perspective-3d", ".hypertorus.projection3d", XrmoptionNoArg,
194 DISP_3D_PERSPECTIVE_STR },
195 {"-orthographic-3d", ".hypertorus.projection3d", XrmoptionNoArg,
196 DISP_3D_ORTHOGRAPHIC_STR },
197 {"-perspective-4d", ".hypertorus.projection4d", XrmoptionNoArg,
198 DISP_4D_PERSPECTIVE_STR },
199 {"-orthographic-4d", ".hypertorus.projection4d", XrmoptionNoArg,
200 DISP_4D_ORTHOGRAPHIC_STR },
201 {"-speed-wx", ".hypertorus.speedwx", XrmoptionSepArg, 0 },
202 {"-speed-wy", ".hypertorus.speedwy", XrmoptionSepArg, 0 },
203 {"-speed-wz", ".hypertorus.speedwz", XrmoptionSepArg, 0 },
204 {"-speed-xy", ".hypertorus.speedxy", XrmoptionSepArg, 0 },
205 {"-speed-xz", ".hypertorus.speedxz", XrmoptionSepArg, 0 },
206 {"-speed-yz", ".hypertorus.speedyz", XrmoptionSepArg, 0 }
209 static argtype vars[] =
211 { &display_mode, "displayMode", "DisplayMode",
212 DEF_DISPLAY_MODE, t_Int },
213 { &appearance, "appearance", "Appearance",
214 DEF_APPEARANCE, t_Int },
215 { &colors, "colors", "Colors",
217 { &projection_3d, "projection3d", "Projection3d",
218 DEF_3D_PROJECTION, t_Int },
219 { &projection_4d, "projection4d", "Projection4d",
220 DEF_4D_PROJECTION, t_Int },
221 { &speed_wx, "speedwx", "Speedwx",
222 DEF_DALPHA, t_Float},
223 { &speed_wy, "speedwy", "Speedwy",
225 { &speed_wz, "speedwz", "Speedwz",
226 DEF_DDELTA, t_Float},
227 { &speed_xy, "speedxy", "Speedxy",
229 { &speed_xz, "speedxz", "Speedxz",
231 { &speed_yz, "speedyz", "Speedyz",
235 static OptionStruct desc[] =
237 { "-wireframe", "display the torus as a wireframe mesh" },
238 { "-surface", "display the torus as a solid surface" },
239 { "-transparent", "display the torus as a transparent surface" },
240 { "-solid", "display the torus as a solid object" },
241 { "-bands", "display the torus as see-through bands" },
242 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
243 { "-twosided", "display the torus with two colors" },
244 { "-colorwheel", "display the torus with a smooth color wheel" },
245 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
246 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
247 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
248 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
249 { "-speed-wx <arg>", "rotation speed around the wx plane" },
250 { "-speed-wy <arg>", "rotation speed around the wy plane" },
251 { "-speed-wz <arg>", "rotation speed around the wz plane" },
252 { "-speed-xy <arg>", "rotation speed around the xy plane" },
253 { "-speed-xz <arg>", "rotation speed around the xz plane" },
254 { "-speed-yz <arg>", "rotation speed around the yz plane" }
257 ENTRYPOINT ModeSpecOpt hypertorus_opts =
258 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
263 GLXContext *glx_context;
264 /* 4D rotation angles */
265 float alpha, beta, delta, zeta, eta, theta;
266 /* Aspect ratio of the current window */
268 /* Trackball states */
269 trackball_state *trackballs[2];
270 int current_trackball;
277 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
280 /* Add a rotation around the wx-plane to the matrix m. */
281 static void rotatewx(float m[4][4], float phi)
299 /* Add a rotation around the wy-plane to the matrix m. */
300 static void rotatewy(float m[4][4], float phi)
318 /* Add a rotation around the wz-plane to the matrix m. */
319 static void rotatewz(float m[4][4], float phi)
337 /* Add a rotation around the xy-plane to the matrix m. */
338 static void rotatexy(float m[4][4], float phi)
356 /* Add a rotation around the xz-plane to the matrix m. */
357 static void rotatexz(float m[4][4], float phi)
375 /* Add a rotation around the yz-plane to the matrix m. */
376 static void rotateyz(float m[4][4], float phi)
394 /* Compute the rotation matrix m from the rotation angles. */
395 static void rotateall(float al, float be, float de, float ze, float et,
396 float th, float m[4][4])
412 /* Multiply two rotation matrices: o=m*n. */
413 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
423 o[i][j] += m[i][k]*n[k][j];
429 /* Compute a 4D rotation matrix from two unit quaternions. */
430 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
432 double al, be, de, ze, et, th;
433 double r00, r01, r02, r12, r22;
435 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
436 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
437 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
438 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
439 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
441 al = atan2(-r12,r22)*180.0/M_PI;
442 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
443 de = atan2(-r01,r00)*180.0/M_PI;
445 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
446 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
447 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
448 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
449 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
451 ze = atan2(-r12,r22)*180.0/M_PI;
452 et = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
453 th = atan2(-r01,r00)*180.0/M_PI;
455 rotateall(al,be,de,ze,et,th,m);
459 /* Compute a fully saturated and bright color based on an angle. */
460 static void color(double angle)
466 if (colors != COLORS_COLORWHEEL)
470 angle = fmod(angle,2*M_PI);
472 angle = fmod(angle,-2*M_PI);
473 s = floor(angle/(M_PI/3));
474 t = angle/(M_PI/3)-s;
510 if (display_mode == DISP_TRANSPARENT)
515 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
519 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
520 will only work correctly if numu and numv are set to 64 or any higher
521 power of 2. Similarly, the banded appearance will only work correctly
522 if numu and numv are divisible by 4. */
523 static void hypertorus(ModeInfo *mi, double umin, double umax, double vmin,
524 double vmax, int numu, int numv)
526 static const GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
527 static const GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
528 static const GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
529 static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
530 float p[3], pu[3], pv[3], n[3], mat[4][4];
531 int i, j, k, l, m, b, skew;
533 double cu, su, cv, sv;
534 double xx[4], xxu[4], xxv[4], x[4], xu[4], xv[4];
536 float q1[4], q2[4], r1[4][4], r2[4][4];
537 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
539 rotateall(hp->alpha,hp->beta,hp->delta,hp->zeta,hp->eta,hp->theta,r1);
541 gltrackball_get_quaternion(hp->trackballs[0],q1);
542 gltrackball_get_quaternion(hp->trackballs[1],q2);
543 quats_to_rotmat(q1,q2,r2);
545 mult_rotmat(r2,r1,mat);
547 if (colors != COLORS_COLORWHEEL)
549 glColor3fv(mat_diff_red);
550 if (display_mode == DISP_TRANSPARENT)
552 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
553 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
557 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
558 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
565 for (i=0; i<numu; i++)
567 if ((appearance == APPEARANCE_BANDS ||
568 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
570 if (display_mode == DISP_WIREFRAME)
571 glBegin(GL_QUAD_STRIP);
573 glBegin(GL_TRIANGLE_STRIP);
574 for (j=0; j<=numv; j++)
582 if (appearance == APPEARANCE_SPIRALS)
584 u += 4.0*skew/numv*v;
585 b = ((i/4)&(skew-1))*(numu/(4*skew));
586 color(ur*4*b/numu+umin);
615 r += mat[l][m]*xx[m];
616 s += mat[l][m]*xxu[m];
617 t += mat[l][m]*xxv[m];
623 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
627 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
634 s = x[3]+offset4d[3];
638 r = x[l]+offset4d[l];
639 p[l] = r/s+offset3d[l];
640 pu[l] = (xu[l]*s-r*xu[3])/t;
641 pv[l] = (xv[l]*s-r*xv[3])/t;
644 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
645 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
646 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
647 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
660 static void init(ModeInfo *mi)
662 static const GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
663 static const GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
664 static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
665 static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
666 static const GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
667 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
669 if (appearance >= APPEARANCE_SPIRALS_1)
671 num_spirals = 1<<(appearance-APPEARANCE_SPIRALS_1);
672 appearance = APPEARANCE_SPIRALS;
686 glMatrixMode(GL_PROJECTION);
688 if (projection_3d == DISP_3D_PERSPECTIVE)
689 gluPerspective(60.0,1.0,0.1,100.0);
691 glOrtho(-1.0,1.0,-1.0,1.0,0.1,100.0);;
692 glMatrixMode(GL_MODELVIEW);
695 if (display_mode == DISP_WIREFRAME)
697 glDisable(GL_DEPTH_TEST);
698 glShadeModel(GL_FLAT);
699 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
700 glDisable(GL_LIGHTING);
701 glDisable(GL_LIGHT0);
704 else if (display_mode == DISP_SURFACE)
706 glEnable(GL_DEPTH_TEST);
707 glDepthFunc(GL_LESS);
708 glShadeModel(GL_SMOOTH);
709 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
710 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
711 glEnable(GL_LIGHTING);
713 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
714 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
715 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
716 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
717 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
718 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
719 glDepthMask(GL_TRUE);
722 else if (display_mode == DISP_TRANSPARENT)
724 glDisable(GL_DEPTH_TEST);
725 glShadeModel(GL_SMOOTH);
726 glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
727 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
728 glEnable(GL_LIGHTING);
730 glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
731 glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
732 glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
733 glLightfv(GL_LIGHT0,GL_POSITION,light_position);
734 glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
735 glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
736 glDepthMask(GL_FALSE);
738 glBlendFunc(GL_SRC_ALPHA,GL_ONE);
742 glDisable(GL_DEPTH_TEST);
743 glShadeModel(GL_FLAT);
744 glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
745 glDisable(GL_LIGHTING);
746 glDisable(GL_LIGHT0);
752 /* Redisplay the hypertorus. */
753 static void display_hypertorus(ModeInfo *mi)
755 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
757 if (!hp->button_pressed)
759 hp->alpha += speed_wx * hp->speed_scale;
760 if (hp->alpha >= 360.0)
762 hp->beta += speed_wy * hp->speed_scale;
763 if (hp->beta >= 360.0)
765 hp->delta += speed_wz * hp->speed_scale;
766 if (hp->delta >= 360.0)
768 hp->zeta += speed_xy * hp->speed_scale;
769 if (hp->zeta >= 360.0)
771 hp->eta += speed_xz * hp->speed_scale;
772 if (hp->eta >= 360.0)
774 hp->theta += speed_yz * hp->speed_scale;
775 if (hp->theta >= 360.0)
779 glMatrixMode(GL_PROJECTION);
781 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
783 if (hp->aspect >= 1.0)
784 glOrtho(-hp->aspect,hp->aspect,-1.0,1.0,0.1,100.0);
786 glOrtho(-1.0,1.0,-1.0/hp->aspect,1.0/hp->aspect,0.1,100.0);
790 gluPerspective(60.0,hp->aspect,0.1,100.0);
792 glMatrixMode(GL_MODELVIEW);
795 hypertorus(mi,0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
799 ENTRYPOINT void reshape_hypertorus(ModeInfo *mi, int width, int height)
801 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
803 hp->WindW = (GLint)width;
804 hp->WindH = (GLint)height;
805 glViewport(0,0,width,height);
806 hp->aspect = (GLfloat)width/(GLfloat)height;
810 ENTRYPOINT Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
812 Display *display = MI_DISPLAY(mi);
813 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
816 if (event->xany.type == ButtonPress &&
817 event->xbutton.button == Button1)
819 hp->button_pressed = True;
820 gltrackball_start(hp->trackballs[hp->current_trackball],
821 event->xbutton.x, event->xbutton.y,
822 MI_WIDTH(mi), MI_HEIGHT(mi));
825 else if (event->xany.type == ButtonRelease &&
826 event->xbutton.button == Button1)
828 hp->button_pressed = False;
831 else if (event->xany.type == KeyPress)
833 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
834 if (sym == XK_Shift_L || sym == XK_Shift_R)
836 hp->current_trackball = 1;
837 if (hp->button_pressed)
838 gltrackball_start(hp->trackballs[hp->current_trackball],
839 event->xbutton.x, event->xbutton.y,
840 MI_WIDTH(mi), MI_HEIGHT(mi));
844 else if (event->xany.type == KeyRelease)
846 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
847 if (sym == XK_Shift_L || sym == XK_Shift_R)
849 hp->current_trackball = 0;
850 if (hp->button_pressed)
851 gltrackball_start(hp->trackballs[hp->current_trackball],
852 event->xbutton.x, event->xbutton.y,
853 MI_WIDTH(mi), MI_HEIGHT(mi));
857 else if (event->xany.type == MotionNotify && hp->button_pressed)
859 gltrackball_track(hp->trackballs[hp->current_trackball],
860 event->xmotion.x, event->xmotion.y,
861 MI_WIDTH(mi), MI_HEIGHT(mi));
870 *-----------------------------------------------------------------------------
871 *-----------------------------------------------------------------------------
873 *-----------------------------------------------------------------------------
874 *-----------------------------------------------------------------------------
878 *-----------------------------------------------------------------------------
879 * Initialize hypertorus. Called each time the window changes.
880 *-----------------------------------------------------------------------------
883 ENTRYPOINT void init_hypertorus(ModeInfo *mi)
885 hypertorusstruct *hp;
889 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
890 sizeof(hypertorusstruct));
894 hp = &hyper[MI_SCREEN(mi)];
897 hp->trackballs[0] = gltrackball_init();
898 hp->trackballs[1] = gltrackball_init();
899 hp->current_trackball = 0;
900 hp->button_pressed = False;
902 /* make multiple screens rotate at slightly different rates. */
903 hp->speed_scale = 0.9 + frand(0.3);
905 if ((hp->glx_context = init_GL(mi)) != NULL)
907 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
908 glDrawBuffer(GL_BACK);
918 *-----------------------------------------------------------------------------
919 * Called by the mainline code periodically to update the display.
920 *-----------------------------------------------------------------------------
922 ENTRYPOINT void draw_hypertorus(ModeInfo *mi)
924 Display *display = MI_DISPLAY(mi);
925 Window window = MI_WINDOW(mi);
926 hypertorusstruct *hp;
930 hp = &hyper[MI_SCREEN(mi)];
932 MI_IS_DRAWN(mi) = True;
933 if (!hp->glx_context)
936 glXMakeCurrent(display,window,*(hp->glx_context));
938 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
941 display_hypertorus(mi);
948 glXSwapBuffers(display,window);
953 *-----------------------------------------------------------------------------
954 * The display is being taken away from us. Free up malloc'ed
955 * memory and X resources that we've alloc'ed. Only called
956 * once, we must zap everything for every screen.
957 *-----------------------------------------------------------------------------
960 ENTRYPOINT void release_hypertorus(ModeInfo *mi)
966 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
968 hypertorusstruct *hp = &hyper[screen];
971 hp->glx_context = (GLXContext *)NULL;
973 (void) free((void *)hyper);
974 hyper = (hypertorusstruct *)NULL;
980 ENTRYPOINT void change_hypertorus(ModeInfo *mi)
982 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
984 if (!hp->glx_context)
987 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));
990 #endif /* !STANDALONE */
992 XSCREENSAVER_MODULE ("Hypertorus", hypertorus)