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 PROGCLASS "Hypertorus"
122 # define HACK_INIT init_hypertorus
123 # define HACK_DRAW draw_hypertorus
124 # define HACK_RESHAPE reshape_hypertorus
125 # define HACK_HANDLE_EVENT hypertorus_handle_event
126 # define EVENT_MASK PointerMotionMask|KeyReleaseMask
127 # define hypertorus_opts xlockmore_opts
128 # define DEFAULTS "*delay: 25000 \n" \
129 "*showFPS: False \n" \
131 # include "xlockmore.h" /* from the xscreensaver distribution */
132 #else /* !STANDALONE */
133 # include "xlock.h" /* from the xlockmore distribution */
134 #endif /* !STANDALONE */
138 #include <X11/keysym.h>
141 #include "gltrackball.h"
145 ModStruct hypertorus_description =
146 {"hypertorus", "init_hypertorus", "draw_hypertorus", "release_hypertorus",
147 "draw_hypertorus", "change_hypertorus", NULL, &hypertorus_opts,
148 25000, 1, 1, 1, 1.0, 4, "",
149 "Shows a hypertorus rotating in 4d", 0, NULL};
154 static int display_mode;
155 static int appearance;
156 static int num_spirals;
158 static int projection_3d;
159 static int projection_4d;
160 static float speed_wx;
161 static float speed_wy;
162 static float speed_wz;
163 static float speed_xy;
164 static float speed_xz;
165 static float speed_yz;
167 /* 4D rotation angles */
168 static float alpha, beta, delta, zeta, eta, theta;
171 /* Trackball states */
172 trackball_state *trackballs[2];
173 int current_trackball;
176 static const float offset4d[4] = { 0.0, 0.0, 0.0, 2.0 };
177 static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
180 static XrmOptionDescRec opts[] =
182 {"-wireframe", ".hypertorus.displayMode", XrmoptionNoArg,
183 DISP_WIREFRAME_STR },
184 {"-surface", ".hypertorus.displayMode", XrmoptionNoArg,
186 {"-transparent", ".hypertorus.displayMode", XrmoptionNoArg,
187 DISP_TRANSPARENT_STR },
188 {"-solid", ".hypertorus.appearance", XrmoptionNoArg,
189 APPEARANCE_SOLID_STR },
190 {"-bands", ".hypertorus.appearance", XrmoptionNoArg,
191 APPEARANCE_BANDS_STR },
192 {"-spirals-1", ".hypertorus.appearance", XrmoptionNoArg,
193 APPEARANCE_SPIRALS_1_STR },
194 {"-spirals-2", ".hypertorus.appearance", XrmoptionNoArg,
195 APPEARANCE_SPIRALS_2_STR },
196 {"-spirals-4", ".hypertorus.appearance", XrmoptionNoArg,
197 APPEARANCE_SPIRALS_4_STR },
198 {"-spirals-8", ".hypertorus.appearance", XrmoptionNoArg,
199 APPEARANCE_SPIRALS_8_STR },
200 {"-spirals-16", ".hypertorus.appearance", XrmoptionNoArg,
201 APPEARANCE_SPIRALS_16_STR },
202 {"-twosided", ".hypertorus.colors", XrmoptionNoArg,
203 COLORS_TWOSIDED_STR },
204 {"-colorwheel", ".hypertorus.colors", XrmoptionNoArg,
205 COLORS_COLORWHEEL_STR },
206 {"-perspective-3d", ".hypertorus.projection3d", XrmoptionNoArg,
207 DISP_3D_PERSPECTIVE_STR },
208 {"-orthographic-3d", ".hypertorus.projection3d", XrmoptionNoArg,
209 DISP_3D_ORTHOGRAPHIC_STR },
210 {"-perspective-4d", ".hypertorus.projection4d", XrmoptionNoArg,
211 DISP_4D_PERSPECTIVE_STR },
212 {"-orthographic-4d", ".hypertorus.projection4d", XrmoptionNoArg,
213 DISP_4D_ORTHOGRAPHIC_STR },
214 {"-speed-wx", ".hypertorus.speedwx", XrmoptionSepArg, 0 },
215 {"-speed-wy", ".hypertorus.speedwy", XrmoptionSepArg, 0 },
216 {"-speed-wz", ".hypertorus.speedwz", XrmoptionSepArg, 0 },
217 {"-speed-xy", ".hypertorus.speedxy", XrmoptionSepArg, 0 },
218 {"-speed-xz", ".hypertorus.speedxz", XrmoptionSepArg, 0 },
219 {"-speed-yz", ".hypertorus.speedyz", XrmoptionSepArg, 0 }
222 static argtype vars[] =
224 { &display_mode, "displayMode", "DisplayMode",
225 DEF_DISPLAY_MODE, t_Int },
226 { &appearance, "appearance", "Appearance",
227 DEF_APPEARANCE, t_Int },
228 { &colors, "colors", "Colors",
230 { &projection_3d, "projection3d", "Projection3d",
231 DEF_3D_PROJECTION, t_Int },
232 { &projection_4d, "projection4d", "Projection4d",
233 DEF_4D_PROJECTION, t_Int },
234 { &speed_wx, "speedwx", "Speedwx",
235 DEF_DALPHA, t_Float},
236 { &speed_wy, "speedwy", "Speedwy",
238 { &speed_wz, "speedwz", "Speedwz",
239 DEF_DDELTA, t_Float},
240 { &speed_xy, "speedxy", "Speedxy",
242 { &speed_xz, "speedxz", "Speedxz",
244 { &speed_yz, "speedyz", "Speedyz",
248 static OptionStruct desc[] =
250 { "-wireframe", "display the torus as a wireframe mesh" },
251 { "-surface", "display the torus as a solid surface" },
252 { "-transparent", "display the torus as a transparent surface" },
253 { "-solid", "display the torus as a solid object" },
254 { "-bands", "display the torus as see-through bands" },
255 { "-spirals-{1,2,4,8,16}", "display the torus as see-through spirals" },
256 { "-twosided", "display the torus with two colors" },
257 { "-colorwheel", "display the torus with a smooth color wheel" },
258 { "-perspective-3d", "project the torus perspectively from 3d to 2d" },
259 { "-orthographic-3d", "project the torus orthographically from 3d to 2d" },
260 { "-perspective-4d", "project the torus perspectively from 4d to 3d" },
261 { "-orthographic-4d", "project the torus orthographically from 4d to 3d" },
262 { "-speed-wx <arg>", "rotation speed around the wx plane" },
263 { "-speed-wy <arg>", "rotation speed around the wy plane" },
264 { "-speed-wz <arg>", "rotation speed around the wz plane" },
265 { "-speed-xy <arg>", "rotation speed around the xy plane" },
266 { "-speed-xz <arg>", "rotation speed around the xz plane" },
267 { "-speed-yz <arg>", "rotation speed around the yz plane" }
270 ModeSpecOpt hypertorus_opts =
271 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
276 GLXContext *glx_context;
279 static hypertorusstruct *hyper = (hypertorusstruct *) NULL;
282 /* Add a rotation around the wx-plane to the matrix m. */
283 static void rotatewx(float m[4][4], float phi)
301 /* Add a rotation around the wy-plane to the matrix m. */
302 static void rotatewy(float m[4][4], float phi)
320 /* Add a rotation around the wz-plane to the matrix m. */
321 static void rotatewz(float m[4][4], float phi)
339 /* Add a rotation around the xy-plane to the matrix m. */
340 static void rotatexy(float m[4][4], float phi)
358 /* Add a rotation around the xz-plane to the matrix m. */
359 static void rotatexz(float m[4][4], float phi)
377 /* Add a rotation around the yz-plane to the matrix m. */
378 static void rotateyz(float m[4][4], float phi)
396 /* Compute the rotation matrix m from the rotation angles. */
397 static void rotateall(float al, float be, float de, float ze, float et,
398 float th, float m[4][4])
414 /* Multiply two rotation matrices: o=m*n. */
415 static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
425 o[i][j] += m[i][k]*n[k][j];
431 /* Compute a 4D rotation matrix from two unit quaternions. */
432 static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
434 double al, be, de, ze, et, th;
435 double r00, r01, r02, r12, r22;
437 r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
438 r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
439 r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
440 r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
441 r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
443 al = atan2(-r12,r22)*180.0/M_PI;
444 be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
445 de = atan2(-r01,r00)*180.0/M_PI;
447 r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
448 r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
449 r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
450 r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
451 r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
453 ze = atan2(-r12,r22)*180.0/M_PI;
454 et = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
455 th = atan2(-r01,r00)*180.0/M_PI;
457 rotateall(al,be,de,ze,et,th,m);
461 /* Compute a fully saturated and bright color based on an angle. */
462 static void color(double angle)
468 if (colors != COLORS_COLORWHEEL)
472 angle = fmod(angle,2*M_PI);
474 angle = fmod(angle,-2*M_PI);
475 s = floor(angle/(M_PI/3));
476 t = angle/(M_PI/3)-s;
512 if (display_mode == DISP_TRANSPARENT)
517 glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,color);
521 /* Draw a hypertorus projected into 3D. Note that the spirals appearance
522 will only work correctly if numu and numv are set to 64 or any higher
523 power of 2. Similarly, the banded appearance will only work correctly
524 if numu and numv are divisible by 4. */
525 static void hypertorus(double umin, double umax, double vmin, double vmax,
528 static GLfloat mat_diff_red[] = { 1.0, 0.0, 0.0, 1.0 };
529 static GLfloat mat_diff_green[] = { 0.0, 1.0, 0.0, 1.0 };
530 static GLfloat mat_diff_trans_red[] = { 1.0, 0.0, 0.0, 0.7 };
531 static 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];
540 rotateall(alpha,beta,delta,zeta,eta,theta,r1);
542 gltrackball_get_quaternion(trackballs[0],q1);
543 gltrackball_get_quaternion(trackballs[1],q2);
544 quats_to_rotmat(q1,q2,r2);
546 mult_rotmat(r2,r1,mat);
548 if (colors != COLORS_COLORWHEEL)
550 glColor3fv(mat_diff_red);
551 if (display_mode == DISP_TRANSPARENT)
553 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
554 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
558 glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
559 glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
566 for (i=0; i<numu; i++)
568 if ((appearance == APPEARANCE_BANDS ||
569 appearance == APPEARANCE_SPIRALS) && ((i & 3) >= 2))
571 if (display_mode == DISP_WIREFRAME)
572 glBegin(GL_QUAD_STRIP);
574 glBegin(GL_TRIANGLE_STRIP);
575 for (j=0; j<=numv; j++)
583 if (appearance == APPEARANCE_SPIRALS)
585 u += 4.0*skew/numv*v;
586 b = ((i/4)&(skew-1))*(numu/(4*skew));
587 color(ur*4*b/numu+umin);
616 r += mat[l][m]*xx[m];
617 s += mat[l][m]*xxu[m];
618 t += mat[l][m]*xxv[m];
624 if (projection_4d == DISP_4D_ORTHOGRAPHIC)
628 p[l] = (x[l]+offset4d[l])/1.5+offset3d[l];
635 s = x[3]+offset4d[3];
639 r = x[l]+offset4d[l];
640 p[l] = r/s+offset3d[l];
641 pu[l] = (xu[l]*s-r*xu[3])/t;
642 pv[l] = (xv[l]*s-r*xv[3])/t;
645 n[0] = pu[1]*pv[2]-pu[2]*pv[1];
646 n[1] = pu[2]*pv[0]-pu[0]*pv[2];
647 n[2] = pu[0]*pv[1]-pu[1]*pv[0];
648 t = sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);
661 static void init(ModeInfo *mi)
663 static GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
664 static GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
665 static GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
666 static GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
667 static GLfloat mat_specular[] = { 1.0, 1.0, 1.0, 1.0 };
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(void)
777 glMatrixMode(GL_PROJECTION);
779 if (projection_3d == DISP_3D_ORTHOGRAPHIC)
782 glOrtho(-aspect,aspect,-1.0,1.0,0.1,100.0);
784 glOrtho(-1.0,1.0,-1.0/aspect,1.0/aspect,0.1,100.0);
788 gluPerspective(60.0,aspect,0.1,100.0);
790 glMatrixMode(GL_MODELVIEW);
793 hypertorus(0.0,2.0*M_PI,0.0,2.0*M_PI,64,64);
797 void reshape_hypertorus(ModeInfo * mi, int width, int height)
799 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
801 hp->WindW = (GLint)width;
802 hp->WindH = (GLint)height;
803 glViewport(0,0,width,height);
804 aspect = (GLfloat)width/(GLfloat)height;
808 Bool hypertorus_handle_event(ModeInfo *mi, XEvent *event)
810 Display *display = MI_DISPLAY(mi);
813 if (event->xany.type == ButtonPress &&
814 event->xbutton.button == Button1)
816 button_pressed = True;
817 gltrackball_start(trackballs[current_trackball],
818 event->xbutton.x, event->xbutton.y,
819 MI_WIDTH(mi), MI_HEIGHT(mi));
822 else if (event->xany.type == ButtonRelease &&
823 event->xbutton.button == Button1)
825 button_pressed = False;
828 else if (event->xany.type == KeyPress)
830 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
831 if (sym == XK_Shift_L || sym == XK_Shift_R)
833 current_trackball = 1;
835 gltrackball_start(trackballs[current_trackball],
836 event->xbutton.x, event->xbutton.y,
837 MI_WIDTH(mi), MI_HEIGHT(mi));
841 else if (event->xany.type == KeyRelease)
843 sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
844 if (sym == XK_Shift_L || sym == XK_Shift_R)
846 current_trackball = 0;
848 gltrackball_start(trackballs[current_trackball],
849 event->xbutton.x, event->xbutton.y,
850 MI_WIDTH(mi), MI_HEIGHT(mi));
854 else if (event->xany.type == MotionNotify && button_pressed)
856 gltrackball_track(trackballs[current_trackball],
857 event->xmotion.x, event->xmotion.y,
858 MI_WIDTH(mi), MI_HEIGHT(mi));
867 *-----------------------------------------------------------------------------
868 *-----------------------------------------------------------------------------
870 *-----------------------------------------------------------------------------
871 *-----------------------------------------------------------------------------
875 *-----------------------------------------------------------------------------
876 * Initialize hypertorus. Called each time the window changes.
877 *-----------------------------------------------------------------------------
880 void init_hypertorus(ModeInfo * mi)
882 hypertorusstruct *hp;
886 hyper = (hypertorusstruct *)calloc(MI_NUM_SCREENS(mi),
887 sizeof(hypertorusstruct));
891 hp = &hyper[MI_SCREEN(mi)];
893 trackballs[0] = gltrackball_init();
894 trackballs[1] = gltrackball_init();
895 current_trackball = 0;
896 button_pressed = False;
898 if ((hp->glx_context = init_GL(mi)) != NULL)
900 reshape_hypertorus(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
901 glDrawBuffer(GL_BACK);
911 *-----------------------------------------------------------------------------
912 * Called by the mainline code periodically to update the display.
913 *-----------------------------------------------------------------------------
915 void draw_hypertorus(ModeInfo * mi)
917 Display *display = MI_DISPLAY(mi);
918 Window window = MI_WINDOW(mi);
919 hypertorusstruct *hp;
923 hp = &hyper[MI_SCREEN(mi)];
925 MI_IS_DRAWN(mi) = True;
926 if (!hp->glx_context)
929 glXMakeCurrent(display,window,*(hp->glx_context));
931 glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
934 display_hypertorus();
941 glXSwapBuffers(display,window);
946 *-----------------------------------------------------------------------------
947 * The display is being taken away from us. Free up malloc'ed
948 * memory and X resources that we've alloc'ed. Only called
949 * once, we must zap everything for every screen.
950 *-----------------------------------------------------------------------------
953 void release_hypertorus(ModeInfo * mi)
959 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
961 hypertorusstruct *hp = &hyper[screen];
964 hp->glx_context = (GLXContext *)NULL;
966 (void) free((void *)hyper);
967 hyper = (hypertorusstruct *)NULL;
972 void change_hypertorus(ModeInfo * mi)
974 hypertorusstruct *hp = &hyper[MI_SCREEN(mi)];
976 if (!hp->glx_context)
979 glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(hp->glx_context));