~ubuntu-branches/ubuntu/trusty/xscreensaver/trusty

« back to all changes in this revision

Viewing changes to hacks/glx/klein.c

  • Committer: Bazaar Package Importer
  • Author(s): Robert Ancell
  • Date: 2009-11-30 13:33:13 UTC
  • mfrom: (1.1.8 upstream) (2.1.6 squeeze)
  • Revision ID: james.westby@ubuntu.com-20091130133313-3b5nz2e7hvbb8h3l
Tags: 5.10-3ubuntu1
* Merge with Debian unstable, remaining changes: (LP: #489062)
  - debian/control: add Build-Depends on ubuntu-artwork
  - debian/rules: use /usr/share/backgrounds
  - debian/control: Move xli | xloadimage recommends to suggests
  - debian/split-hacks.config: Use different set of default hacks to Debian
  - debian/source_xscreensaver.py: Add apport hook
  - debian/patches/53_XScreenSaver.ad.in.patch: Use Ubuntu branding

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* -*- Mode: C; tab-width: 4 -*- */
2
 
/* Klein --- Klein Bottle, Moebius and other parametric surfaces
3
 
 * visualization */
4
 
 
5
 
/*
6
 
 * Revision History:
7
 
 * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca
8
 
 *       
9
 
 * 01-Mar-2003  mirtchov    modified as a xscreensaver hack
10
 
 *
11
 
 */
 
1
/* klein --- Shows a Klein bottle that rotates in 4d or on which you
 
2
   can walk */
 
3
 
 
4
#if 0
 
5
static const char sccsid[] = "@(#)klein.c  1.1 08/10/04 xlockmore";
 
6
#endif
 
7
 
 
8
/* Copyright (c) 2005-2009 Carsten Steger <carsten@mirsanmir.org>. */
 
9
 
 
10
/*
 
11
 * Permission to use, copy, modify, and distribute this software and its
 
12
 * documentation for any purpose and without fee is hereby granted,
 
13
 * provided that the above copyright notice appear in all copies and that
 
14
 * both that copyright notice and this permission notice appear in
 
15
 * supporting documentation.
 
16
 *
 
17
 * This file is provided AS IS with no warranties of any kind.  The author
 
18
 * shall have no liability with respect to the infringement of copyrights,
 
19
 * trade secrets or any patents by this file or any part thereof.  In no
 
20
 * event will the author be liable for any lost revenue or profits or
 
21
 * other special, indirect and consequential damages.
 
22
 *
 
23
 * REVISION HISTORY:
 
24
 * C. Steger - 08/10/04: Initial version
 
25
 * C. Steger - 09/08/03: Changes to the parameter handling
 
26
 */
 
27
 
 
28
/*
 
29
 * This program shows two different Klein bottles in 4d: the figure-8 Klein
 
30
 * bottle or the Lawson Klein bottle.  You can walk on the Klein bottle, see
 
31
 * it turn in 4d, or walk on it while it turns in 4d.  The figure-8 Klein
 
32
 * bottle is well known in its 3d form.  The 4d form used in this program is
 
33
 * an extension of the 3d form to 4d that does not intersect itself in 4d
 
34
 * (which can be seen in the depth colors mode).  The Lawson Klein bottle,
 
35
 * on the other hand, does intersect itself in 4d.  Its primary use is that
 
36
 * it has a nice appearance for walking and for turning in 3d.  The Klein
 
37
 * bottle is a non-orientable surface.  To make this apparent, the two-sided
 
38
 * color mode can be used.  Alternatively, orientation markers (curling
 
39
 * arrows) can be drawn as a texture map on the surface of the Klein bottle.
 
40
 * While walking on the Klein bottle, you will notice that the orientation
 
41
 * of the curling arrows changes (which it must because the Klein bottle is
 
42
 * non-orientable).  The program projects the 4d Klein bottle to 3d using
 
43
 * either a perspective or an orthographic projection.  Which of the two
 
44
 * alternatives looks more appealing depends on the viewing mode and the
 
45
 * Klein bottle.  For example, the Lawson Klein bottle looks nicest when
 
46
 * projected perspectively.  The figure-8 Klein bottle, on the other
 
47
 * hand, looks nicer while walking when projected orthographically from 4d.
 
48
 * The projected Klein bottle can then be projected to the screen either
 
49
 * perspectively or orthographically.  When using the walking modes,
 
50
 * perspective projection to the screen should be used.  There are three
 
51
 * display modes for the Klein bottle: mesh (wireframe), solid, or
 
52
 * transparent.  Furthermore, the appearance of the Klein bottle can be as
 
53
 * a solid object or as a set of see-through bands.  Finally, the colors
 
54
 * with with the Klein bottle is drawn can be set to two-sided, rainbow, or
 
55
 * depth.  In the first case, the Klein bottle is drawn with red on one
 
56
 * "side" and green on the "other side".  Of course, the Klein bottle only
 
57
 * has one side, so the color jumps from red to green along a curve on the
 
58
 * surface of the Klein bottle.  This mode enables you to see that the Klein
 
59
 * bottle is non-orientable.  The second mode draws the Klein bottle with
 
60
 * fully saturated rainbow colors.  This gives a very nice effect when
 
61
 * combined with the see-through bands mode or with the orientation markers
 
62
 * drawn.  The third mode draws the Klein bottle with colors that are chosen
 
63
 * according to the 4d "depth" of the points.  This mode enables you to see
 
64
 * that the figure-8 Klein bottle does not intersect itself in 4d, while the
 
65
 * Lawson Klein bottle does intersect itself.  The rotation speed for each
 
66
 * of the six planes around which the Klein bottle rotates can be chosen.
 
67
 * For the walk-and-turn more, only the rotation speeds around the true 4d
 
68
 * planes are used (the xy, xz, and yz planes).  Furthermore, in the walking
 
69
 * modes the walking direction in the 2d base square of the Klein bottle and
 
70
 * the walking speed can be chosen.  This program is somewhat inspired by
 
71
 * Thomas Banchoff's book "Beyond the Third Dimension: Geometry, Computer
 
72
 * Graphics, and Higher Dimensions", Scientific American Library, 1990.
 
73
 */
 
74
 
 
75
#ifndef M_PI
 
76
#define M_PI 3.14159265358979323846
 
77
#endif
 
78
 
 
79
#define KLEIN_BOTTLE_FIGURE_8      0
 
80
#define KLEIN_BOTTLE_LAWSON        1
 
81
#define NUM_KLEIN_BOTTLES          2
 
82
 
 
83
#define DISP_WIREFRAME             0
 
84
#define DISP_SURFACE               1
 
85
#define DISP_TRANSPARENT           2
 
86
#define NUM_DISPLAY_MODES          3
 
87
 
 
88
#define APPEARANCE_SOLID           0
 
89
#define APPEARANCE_BANDS           1
 
90
#define NUM_APPEARANCES            2
 
91
 
 
92
#define COLORS_TWOSIDED            0
 
93
#define COLORS_RAINBOW             1
 
94
#define COLORS_DEPTH               2
 
95
#define NUM_COLORS                 3
 
96
 
 
97
#define VIEW_WALK                  0
 
98
#define VIEW_TURN                  1
 
99
#define VIEW_WALKTURN              2
 
100
#define NUM_VIEW_MODES             3
 
101
 
 
102
#define DISP_3D_PERSPECTIVE        0
 
103
#define DISP_3D_ORTHOGRAPHIC       1
 
104
#define NUM_DISP_3D_MODES          2
 
105
 
 
106
#define DISP_4D_PERSPECTIVE        0
 
107
#define DISP_4D_ORTHOGRAPHIC       1
 
108
#define NUM_DISP_4D_MODES          2
 
109
 
 
110
#define DEF_KLEIN_BOTTLE           "random"
 
111
#define DEF_DISPLAY_MODE           "random"
 
112
#define DEF_APPEARANCE             "random"
 
113
#define DEF_COLORS                 "random"
 
114
#define DEF_VIEW_MODE              "random"
 
115
#define DEF_MARKS                  "False"
 
116
#define DEF_PROJECTION_3D          "random"
 
117
#define DEF_PROJECTION_4D          "random"
 
118
#define DEF_SPEEDWX                "1.1"
 
119
#define DEF_SPEEDWY                "1.3"
 
120
#define DEF_SPEEDWZ                "1.5"
 
121
#define DEF_SPEEDXY                "1.7"
 
122
#define DEF_SPEEDXZ                "1.9"
 
123
#define DEF_SPEEDYZ                "2.1"
 
124
#define DEF_WALK_DIRECTION         "7.0"
 
125
#define DEF_WALK_SPEED             "20.0"
12
126
 
13
127
#ifdef STANDALONE
14
 
# define DEFAULTS                                       "*delay:                20000   \n" \
15
 
                                                                        "*showFPS:      False   \n"
 
128
# define DEFAULTS           "*delay:      10000 \n" \
 
129
                            "*showFPS:    False \n" \
16
130
 
17
131
# define refresh_klein 0
18
 
# include "xlockmore.h"         /* from the xscreensaver distribution */
 
132
# include "xlockmore.h"         /* from the xscreensaver distribution */
19
133
#else  /* !STANDALONE */
20
 
# include "xlock.h"                     /* from the xlockmore distribution */
 
134
# include "xlock.h"             /* from the xlockmore distribution */
21
135
#endif /* !STANDALONE */
22
136
 
23
137
#ifdef USE_GL
24
138
 
25
 
#define DEF_SPIN                                "True"
26
 
#define DEF_WANDER                              "False"
27
 
#define DEF_RAND                                "True"
28
 
#define DEF_SPEED                               "150"
 
139
#include <X11/keysym.h>
29
140
 
30
 
#include "rotator.h"
31
141
#include "gltrackball.h"
32
142
 
33
 
#undef countof
34
 
#define countof(x) (sizeof((x))/sizeof((*x)))
35
 
 
36
 
/* surfaces being drawn */
37
 
enum { 
38
 
        KLEIN = 0,
39
 
        DINI,
40
 
        ENNEPER,
41
 
        KUEN,
42
 
        MOEBIUS,
43
 
        SEASHELL,
44
 
        SWALLOWTAIL,
45
 
        BOHEM,
46
 
    SURFACE_LAST
47
 
};
48
 
 
49
 
/* primitives to draw with 
50
 
 * note that we skip the polygons and
51
 
 * triangle fans -- too slow
52
 
 *
53
 
 * also removed triangle_strip and quads -- 
54
 
 * just doesn't look good enough
55
 
 */
56
 
enum {
57
 
        MY_POINTS = 0,
58
 
        MY_LINES,
59
 
        MY_LINE_LOOP,
60
 
        MY_PRIM_LAST
61
 
};
62
 
 
63
 
 
64
 
static Bool rand;
65
 
static int render;
66
 
static int speed;
67
 
static Bool do_spin;
68
 
static Bool do_wander;
69
 
 
70
 
static XrmOptionDescRec opts[] = {
71
 
  {"-speed",   ".speed",    XrmoptionSepArg, 0 },
72
 
  { "-spin",   ".spin",   XrmoptionNoArg, "True" },
73
 
  { "+spin",   ".spin",   XrmoptionNoArg, "False" },
74
 
  { "-wander", ".wander", XrmoptionNoArg, "True" },
75
 
  { "+wander", ".wander", XrmoptionNoArg, "False" },
76
 
  { "-random", ".rand", XrmoptionNoArg, "True" },
77
 
  { "+random", ".rand", XrmoptionNoArg, "False" },
78
 
};
79
 
 
80
 
static argtype vars[] = {
81
 
  {&rand,      "rand",   "Random", DEF_RAND,   t_Bool},
82
 
  {&do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},
83
 
  {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
84
 
  {&speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},
85
 
};
86
 
 
87
 
 
88
 
ENTRYPOINT ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};
89
 
 
90
 
 
91
 
 
92
 
typedef struct{
93
 
  GLfloat x;
94
 
  GLfloat y;
95
 
  GLfloat z;
96
 
} GL_VECTOR;
 
143
 
 
144
#ifdef USE_MODULES
 
145
ModStruct   klein_description =
 
146
{"klein", "init_klein", "draw_klein", "release_klein",
 
147
 "draw_klein", "change_klein", NULL, &klein_opts,
 
148
 25000, 1, 1, 1, 1.0, 4, "",
 
149
 "Rotate a Klein bottle in 4d or walk on it", 0, NULL};
 
150
 
 
151
#endif
 
152
 
 
153
 
 
154
static char *klein_bottle;
 
155
static int bottle_type;
 
156
static char *mode;
 
157
static int display_mode;
 
158
static char *appear;
 
159
static int appearance;
 
160
static char *color_mode;
 
161
static int colors;
 
162
static char *view_mode;
 
163
static int view;
 
164
static Bool marks;
 
165
static char *proj_3d;
 
166
static int projection_3d;
 
167
static char *proj_4d;
 
168
static int projection_4d;
 
169
static float speed_wx;
 
170
static float speed_wy;
 
171
static float speed_wz;
 
172
static float speed_xy;
 
173
static float speed_xz;
 
174
static float speed_yz;
 
175
static float walk_direction;
 
176
static float walk_speed;
 
177
 
 
178
 
 
179
static XrmOptionDescRec opts[] =
 
180
{
 
181
  {"-klein-bottle",      ".kleinBottle",   XrmoptionSepArg, 0 },
 
182
  {"-figure-8",          ".kleinBottle",   XrmoptionNoArg,  "figure-8" },
 
183
  {"-lawson",            ".kleinBottle",   XrmoptionNoArg,  "lawson" },
 
184
  {"-mode",              ".displayMode",   XrmoptionSepArg, 0 },
 
185
  {"-wireframe",         ".displayMode",   XrmoptionNoArg,  "wireframe" },
 
186
  {"-surface",           ".displayMode",   XrmoptionNoArg,  "surface" },
 
187
  {"-transparent",       ".displayMode",   XrmoptionNoArg,  "transparent" },
 
188
  {"-appearance",        ".appearance",    XrmoptionSepArg, 0 },
 
189
  {"-solid",             ".appearance",    XrmoptionNoArg,  "solid" },
 
190
  {"-bands",             ".appearance",    XrmoptionNoArg,  "bands" },
 
191
  {"-colors",            ".colors",        XrmoptionSepArg, 0 },
 
192
  {"-twosided",          ".colors",        XrmoptionNoArg,  "two-sided" },
 
193
  {"-rainbow",           ".colors",        XrmoptionNoArg,  "rainbow" },
 
194
  {"-depth",             ".colors",        XrmoptionNoArg,  "depth" },
 
195
  {"-view-mode",         ".viewMode",      XrmoptionSepArg, 0 },
 
196
  {"-walk",              ".viewMode",      XrmoptionNoArg,  "walk" },
 
197
  {"-turn",              ".viewMode",      XrmoptionNoArg,  "turn" },
 
198
  {"-walk-turn",         ".viewMode",      XrmoptionNoArg,  "walk-turn" },
 
199
  {"-orientation-marks", ".marks",         XrmoptionNoArg, "on"},
 
200
  {"+orientation-marks", ".marks",         XrmoptionNoArg, "off"},
 
201
  {"-projection-3d",     ".projection3d",  XrmoptionSepArg, 0 },
 
202
  {"-perspective-3d",    ".projection3d",  XrmoptionNoArg,  "perspective" },
 
203
  {"-orthographic-3d",   ".projection3d",  XrmoptionNoArg,  "orthographic" },
 
204
  {"-projection-4d",     ".projection4d",  XrmoptionSepArg, 0 },
 
205
  {"-perspective-4d",    ".projection4d",  XrmoptionNoArg,  "perspective" },
 
206
  {"-orthographic-4d",   ".projection4d",  XrmoptionNoArg,  "orthographic" },
 
207
  {"-speed-wx",          ".speedwx",       XrmoptionSepArg, 0 },
 
208
  {"-speed-wy",          ".speedwy",       XrmoptionSepArg, 0 },
 
209
  {"-speed-wz",          ".speedwz",       XrmoptionSepArg, 0 },
 
210
  {"-speed-xy",          ".speedxy",       XrmoptionSepArg, 0 },
 
211
  {"-speed-xz",          ".speedxz",       XrmoptionSepArg, 0 },
 
212
  {"-speed-yz",          ".speedyz",       XrmoptionSepArg, 0 },
 
213
  {"-walk-direction",    ".walkDirection", XrmoptionSepArg, 0 },
 
214
  {"-walk-speed",        ".walkSpeed",     XrmoptionSepArg, 0 }
 
215
};
 
216
 
 
217
static argtype vars[] =
 
218
{
 
219
  { &klein_bottle,   "kleinBottle",   "KleinBottle",   DEF_KLEIN_BOTTLE,   t_String },
 
220
  { &mode,           "displayMode",   "DisplayMode",   DEF_DISPLAY_MODE,   t_String },
 
221
  { &appear,         "appearance",    "Appearance",    DEF_APPEARANCE,     t_String },
 
222
  { &color_mode,     "colors",        "Colors",        DEF_COLORS,         t_String },
 
223
  { &view_mode,      "viewMode",      "ViewMode",      DEF_VIEW_MODE,      t_String },
 
224
  { &marks,          "marks",         "Marks",         DEF_MARKS,          t_Bool },
 
225
  { &proj_3d,        "projection3d",  "Projection3d",  DEF_PROJECTION_3D,  t_String },
 
226
  { &proj_4d,        "projection4d",  "Projection4d",  DEF_PROJECTION_4D,  t_String },
 
227
  { &speed_wx,       "speedwx",       "Speedwx",       DEF_SPEEDWX,        t_Float},
 
228
  { &speed_wy,       "speedwy",       "Speedwy",       DEF_SPEEDWY,        t_Float},
 
229
  { &speed_wz,       "speedwz",       "Speedwz",       DEF_SPEEDWZ,        t_Float},
 
230
  { &speed_xy,       "speedxy",       "Speedxy",       DEF_SPEEDXY,        t_Float},
 
231
  { &speed_xz,       "speedxz",       "Speedxz",       DEF_SPEEDXZ,        t_Float},
 
232
  { &speed_yz,       "speedyz",       "Speedyz",       DEF_SPEEDYZ,        t_Float},
 
233
  { &walk_direction, "walkDirection", "WalkDirection", DEF_WALK_DIRECTION, t_Float},
 
234
  { &walk_speed,     "walkSpeed",     "WalkSpeed",     DEF_WALK_SPEED,     t_Float}
 
235
};
 
236
 
 
237
ENTRYPOINT ModeSpecOpt klein_opts =
 
238
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, NULL};
 
239
 
 
240
 
 
241
/* Radius of the Figure 8 Klein bottle */
 
242
#define FIGURE_8_RADIUS 2.0
 
243
 
 
244
/* Offset by which we walk above the Klein bottle */
 
245
#define DELTAY  0.02
 
246
 
 
247
/* Number of subdivisions of the Klein bottle */
 
248
#define NUMU 128
 
249
#define NUMV 128
 
250
 
 
251
/* Number of subdivisions per band */
 
252
#define NUMB 8
 
253
 
97
254
 
98
255
typedef struct {
99
 
        GLXContext *glx_context;
100
 
        Window      window;
101
 
        rotator    *rot;
102
 
        trackball_state *trackball;
103
 
        Bool              button_down_p;
104
 
 
105
 
        int render;
106
 
        int surface;
107
 
 
108
 
        float du, dv;
109
 
        float a, b, c;
110
 
 
111
 
    float draw_step;
112
 
 
 
256
  GLint      WindH, WindW;
 
257
  GLXContext *glx_context;
 
258
  /* 4D rotation angles */
 
259
  float alpha, beta, delta, zeta, eta, theta;
 
260
  /* Movement parameters */
 
261
  float umove, vmove, dumove, dvmove;
 
262
  int side;
 
263
  /* The viewing offset in 4d */
 
264
  float offset4d[4];
 
265
  /* The viewing offset in 3d */
 
266
  float offset3d[4];
 
267
  /* The 4d coordinates of the Klein bottle and their derivatives */
 
268
  float x[(NUMU+1)*(NUMV+1)][4];
 
269
  float xu[(NUMU+1)*(NUMV+1)][4];
 
270
  float xv[(NUMU+1)*(NUMV+1)][4];
 
271
  float pp[(NUMU+1)*(NUMV+1)][3];
 
272
  float pn[(NUMU+1)*(NUMV+1)][3];
 
273
  /* The precomputed colors of the Klein bottle */
 
274
  float col[(NUMU+1)*(NUMV+1)][4];
 
275
  /* The precomputed texture coordinates of the Klein bottle */
 
276
  float tex[(NUMU+1)*(NUMV+1)][2];
 
277
  /* The "curlicue" texture */
 
278
  GLuint tex_name;
 
279
  /* Aspect ratio of the current window */
 
280
  float aspect;
 
281
  /* Trackball states */
 
282
  trackball_state *trackballs[2];
 
283
  int current_trackball;
 
284
  Bool button_pressed;
 
285
  /* A random factor to modify the rotation speeds */
 
286
  float speed_scale;
113
287
} kleinstruct;
114
288
 
115
 
static kleinstruct *klein = NULL;
116
 
 
117
 
 
118
 
static void
119
 
draw(ModeInfo *mi)
120
 
{
121
 
        kleinstruct *kp = &klein[MI_SCREEN(mi)];
122
 
        double u, v;
123
 
        float coord[3];
124
 
        
125
 
    mi->polygon_count = 0;
126
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
127
 
 
128
 
        glEnable(GL_DEPTH_TEST);
129
 
        glEnable(GL_NORMALIZE);
130
 
        glEnable(GL_CULL_FACE);
131
 
 
132
 
        glPushMatrix();
133
 
 
134
 
        {
135
 
                double x, y, z;
136
 
                get_position (kp->rot, &x, &y, &z, !kp->button_down_p);
137
 
                glTranslatef((x - 0.5) * 10,
138
 
                                                                 (y - 0.5) * 10,
139
 
                                                                 (z - 0.5) * 20);
140
 
 
141
 
                gltrackball_rotate (kp->trackball);
142
 
 
143
 
                get_rotation (kp->rot, &x, &y, &z, !kp->button_down_p);
144
 
                glRotatef (x * 360, 1.0, 0.0, 0.0);
145
 
                glRotatef (y * 360, 0.0, 1.0, 0.0);
146
 
                glRotatef (z * 360, 0.0, 0.0, 1.0);
147
 
        }
148
 
 
149
 
        glScalef( 4.0, 4.0, 4.0 );
150
 
 
151
 
        glBegin(kp->render);
152
 
        switch(kp->surface) {
153
 
        case KLEIN:
154
 
                for(u = -M_PI; u < M_PI; u+=kp->du){
155
 
                        for(v = -M_PI; v < M_PI; v+=kp->dv){
156
 
                                coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -
157
 
                                                        sin(2*v)*sin(u/2)/2);
158
 
                                coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -
159
 
                                                        sin(2*v)*sin(u/2)/2);
160
 
                                coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;
161
 
                                glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
162
 
                                glVertex3fv(coord);
163
 
                mi->polygon_count++;
164
 
                        }
165
 
                }
166
 
                break;
167
 
                case DINI:
168
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
169
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
170
 
                                        coord[0] = kp->a*cos(u)*sin(v);
171
 
                                        coord[1] = kp->a*sin(u)*sin(v);
172
 
                                        coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;
173
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
174
 
                                        glVertex3fv(coord);
175
 
                    mi->polygon_count++;
176
 
                                }
177
 
                        }
178
 
                        break;
179
 
                case ENNEPER:
180
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
181
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
182
 
                                        coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);
183
 
                                        coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);
184
 
                                        coord[2] = u*u-v*v;
185
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
186
 
                                        glVertex3fv(coord);
187
 
                    mi->polygon_count++;
188
 
                                }
189
 
                        }
190
 
                        break;
191
 
                case KUEN:
192
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
193
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
194
 
                                        coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));
195
 
                                        coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));
196
 
                                        coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));
197
 
 
198
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
199
 
                                        glVertex3fv(coord);
200
 
                    mi->polygon_count++;
201
 
                                }
202
 
                        }
203
 
                        break;
204
 
                case MOEBIUS:
205
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
206
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
207
 
                                        coord[0] = cos(u)+v*cos(u/2)*cos(u);
208
 
                                        coord[1] = sin(u)+v*cos(u/2)*sin(u);
209
 
                                        coord[2] = v*sin(u/2);
210
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
211
 
                                        glVertex3fv(coord);
212
 
                    mi->polygon_count++;
213
 
                                }
214
 
                        }
215
 
                        break;
216
 
                case SEASHELL:
217
 
                        for(u = 0; u < 2*M_PI; u+=kp->du){
218
 
                                for(v = 0; v < 2*M_PI; v+=kp->dv){
219
 
                                        coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);
220
 
                                        coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);
221
 
                                        coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);
222
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
223
 
                                        glVertex3fv(coord);
224
 
                    mi->polygon_count++;
225
 
                                }
226
 
                        }
227
 
                        break;
228
 
                case SWALLOWTAIL:
229
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
230
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
231
 
                                        coord[0] = u*pow(v,2) + 3*pow(v,4);
232
 
                                        coord[1] = -2*u*v - 4*pow(v,3);
233
 
                                        coord[2] = u;
234
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
235
 
                                        glVertex3fv(coord);
236
 
                    mi->polygon_count++;
237
 
                                }
238
 
                        }
239
 
                        break;
240
 
                case BOHEM:
241
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
242
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
243
 
                                        coord[0] = kp->a*cos(u);
244
 
                                        coord[1] = 1.5*cos(v) + kp->a*sin(u);
245
 
                                        coord[2] = sin(v);
246
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
247
 
                                        glVertex3fv(coord);
248
 
                    mi->polygon_count++;
249
 
                                }
250
 
                        }
251
 
                        break;
252
 
                default:
253
 
                        for(u = -M_PI; u < M_PI; u+=kp->du){
254
 
                                for(v = -M_PI; v < M_PI; v+=kp->dv){
255
 
                                        coord[0] = sin(u)*kp->a;        
256
 
                                        coord[1] = cos(u)*kp->a;
257
 
                                        coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);
258
 
                                        glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
259
 
                                        glVertex3fv(coord);
260
 
                    mi->polygon_count++;
261
 
                                }
262
 
                        }
263
 
                        break;
264
 
        }
265
 
        glEnd();
266
 
        glPopMatrix();
267
 
 
268
 
    if (kp->render == GL_LINES)
269
 
      mi->polygon_count /= 2;
270
 
 
271
 
        kp->a = sin(kp->draw_step+=0.01);
272
 
        kp->b = cos(kp->draw_step+=0.01);
273
 
}
274
 
 
275
 
 
276
 
/* new window size or exposure */
277
 
ENTRYPOINT void
278
 
reshape_klein(ModeInfo *mi, int width, int height)
279
 
{
280
 
        GLfloat h = (GLfloat) height / (GLfloat) width;
281
 
 
282
 
        glViewport(0, 0, (GLint) width, (GLint) height);
283
 
        glMatrixMode(GL_PROJECTION);
284
 
        glLoadIdentity();
285
 
        gluPerspective (30.0, 1/h, 1.0, 100.0);
286
 
 
287
 
        glMatrixMode(GL_MODELVIEW);
288
 
        glLoadIdentity();
289
 
        gluLookAt( 0.0, 0.0, 30.0,
290
 
                         0.0, 0.0, 0.0,
291
 
                         0.0, 1.0, 0.0);
292
 
        
293
 
        glClear(GL_COLOR_BUFFER_BIT);
294
 
}
295
 
 
296
 
 
297
 
ENTRYPOINT Bool
298
 
klein_handle_event (ModeInfo *mi, XEvent *event)
299
 
{
300
 
        kleinstruct *kp = &klein[MI_SCREEN(mi)];
301
 
 
302
 
        if (event->xany.type == ButtonPress && event->xbutton.button == Button1) {
303
 
                        kp->button_down_p = True;
304
 
                        gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
305
 
                        return True;
306
 
        } else if (event->xany.type == ButtonRelease && event->xbutton.button == Button1) {
307
 
                        kp->button_down_p = False;
308
 
                        return True;
309
 
        } else if (event->xany.type == ButtonPress &&
310
 
               (event->xbutton.button == Button4 ||
311
 
                event->xbutton.button == Button5 ||
312
 
                event->xbutton.button == Button6 ||
313
 
                event->xbutton.button == Button7)) {
314
 
      gltrackball_mousewheel (kp->trackball, event->xbutton.button, 10,
315
 
                              !!event->xbutton.state);
316
 
      return True;
317
 
    } else if (event->xany.type == MotionNotify && kp->button_down_p) {
318
 
                        gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
319
 
                        return True;
320
 
        }
321
 
 
322
 
        return False;
323
 
}
324
 
 
325
 
 
326
 
ENTRYPOINT void
327
 
init_klein(ModeInfo *mi)
328
 
{
329
 
        int      screen = MI_SCREEN(mi);
330
 
        kleinstruct *kp;
331
 
 
332
 
        if (klein == NULL) {
333
 
                if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)
334
 
                        return;
335
 
        }
336
 
        kp = &klein[screen];
337
 
 
338
 
        kp->window = MI_WINDOW(mi);
339
 
 
340
 
        {
341
 
                double spin_speed        = 1.0;
342
 
                double wander_speed = 0.03;
343
 
                kp->rot = make_rotator (do_spin ? spin_speed : 0,
344
 
                                                do_spin ? spin_speed : 0,
345
 
                                                do_spin ? spin_speed : 0,
346
 
                                                1.0,
347
 
                                                do_wander ? wander_speed : 0,
348
 
                                                True);
349
 
                kp->trackball = gltrackball_init ();
350
 
        }
351
 
 
352
 
        if(rand) {
353
 
                render = random() % MY_PRIM_LAST;
354
 
                kp->surface = random() % SURFACE_LAST;
355
 
        } else {
356
 
                render = MY_LINE_LOOP;
357
 
                kp->surface = KLEIN;
358
 
        }
359
 
 
360
 
        switch (render) {
361
 
        case MY_POINTS: kp->render = GL_POINTS; break;
362
 
        case MY_LINES: kp->render = GL_LINES; break;
363
 
        case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;
364
 
        default:
365
 
                        kp->render = GL_LINE_LOOP;
366
 
        }
367
 
/*kp->render=GL_TRIANGLE_FAN;*/
368
 
/*kp->render=GL_POLYGON;*/
369
 
 
370
 
        kp->du = 0.07;
371
 
        kp->dv = 0.07;
372
 
        kp->a = kp->b = 1;
373
 
        kp->c = 0.1;
374
 
 
375
 
 
376
 
        if ((kp->glx_context = init_GL(mi)) != NULL) {
377
 
                reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
378
 
        } else {
379
 
                MI_CLEARWINDOW(mi);
380
 
        }
381
 
}
382
 
 
383
 
ENTRYPOINT void
384
 
draw_klein(ModeInfo * mi)
385
 
{
386
 
        kleinstruct *kp = &klein[MI_SCREEN(mi)];
387
 
        Display *display = MI_DISPLAY(mi);
388
 
        Window  window = MI_WINDOW(mi);
389
 
 
390
 
        if (!kp->glx_context) return;
391
 
 
392
 
        glDrawBuffer(GL_BACK);
393
 
 
394
 
        glXMakeCurrent(display, window, *(kp->glx_context));
395
 
        draw(mi);
396
 
        if (mi->fps_p) do_fps (mi);
397
 
        glFinish();
398
 
        glXSwapBuffers(display, window);
399
 
}
400
 
 
401
 
ENTRYPOINT void
402
 
release_klein(ModeInfo * mi)
403
 
{
404
 
        if (klein != NULL) {
405
 
                int      screen;
406
 
 
407
 
                for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
408
 
                        kleinstruct *kp = &klein[screen];
409
 
 
410
 
                        if (kp->glx_context) {
411
 
                                /* Display lists MUST be freed while their glXContext is current. */
412
 
                                glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));
413
 
                        }
414
 
                }
415
 
                (void) free((void *) klein);
416
 
                klein = NULL;
417
 
        }
418
 
        FreeAllGL(mi);
419
 
}
420
 
 
 
289
static kleinstruct *klein = (kleinstruct *) NULL;
 
290
 
 
291
 
 
292
/* A texture map containing a "curlicue" */
 
293
#define TEX_DIMENSION 64
 
294
static const unsigned char texture[TEX_DIMENSION*TEX_DIMENSION] = {
 
295
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
296
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
297
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
298
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
299
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
300
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
301
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
302
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
303
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
304
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
305
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
306
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
307
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
308
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
309
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
310
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
311
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
312
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
313
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
314
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
315
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
316
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
317
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
318
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
319
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
320
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
321
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
322
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
323
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
324
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
325
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
326
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
327
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
328
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
329
  255,255,255,255,255,255,255, 58, 43, 43, 43, 43, 45, 70, 70, 70,
 
330
   70, 70, 70, 70, 74, 98, 98, 98,100,194,255,255,255,255,255,255,
 
331
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
332
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
333
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
334
    0,  0,  0,  0,  0,  0,  0, 30,186,255,255,255,255,255,255,255,
 
335
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
336
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
337
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
338
    0,  0,  0,  0,  0,  1,111,244,255,255,255,255,255,255,255,255,
 
339
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
340
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
341
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
342
    0,  0,  0,  0, 43,198,255,255,255,255,255,255,255,255,255,255,
 
343
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
344
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
345
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
346
    0,  0,  5,123,248,255,255,255,255,255,255,255,255,255,255,255,
 
347
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
348
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
349
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
350
    0, 50,209,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
351
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,246,
 
352
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
353
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
354
   74,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
355
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,138,  4,
 
356
   66,229,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
357
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
358
    1,170,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
359
  255,255,255,255,255,255,255,255,255,255,255,255,255,153,  0,  0,
 
360
    0, 53,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
361
  255,255,255,255,255,255,255, 18,  0,  0,  0,  0,  0,  0,  0,  0,
 
362
    0,  6,188,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
363
  255,255,255,255,255,255,255,255,255,255,255,255,213,  7,  0,  0,
 
364
    0,  0,226,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
365
  255,255,255,255,255,255,255, 45,  0,  0,  0,  0,  0, 47,  0,  0,
 
366
    0,  0, 22,225,255,255,255,255,255,255,255,255,255,255,255,255,
 
367
  255,255,255,255,255,255,255,255,255,255,255,254, 54,  0,  0,  0,
 
368
    0, 81,254,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
369
  255,255,255,255,255,255,255, 45,  0,  0,  0,  0, 56,247, 82,  0,
 
370
    0,  0,  0, 59,253,255,255,255,255,255,255,255,255,255,255,255,
 
371
  255,255,255,255,255,255,255,255,255,255,255,152,  0,  0,  0,  0,
 
372
   52,243,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
373
  255,255,255,255,255,255,255, 45,  0,  0,  0,  8,215,255,250, 56,
 
374
    0,  0,  0,  0,142,255,255,255,255,255,255,255,255,255,255,255,
 
375
  255,255,255,255,255,255,255,255,255,255,241, 19,  0,  0,  0, 15,
 
376
  220,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
377
  255,255,255,255,255,255,255, 45,  0,  0,  0,129,255,255,255,230,
 
378
   23,  0,  0,  0, 12,230,255,255,255,255,255,255,255,255,255,255,
 
379
  255,255,255,255,255,255,255,255,255,255,131,  0,  0,  0,  0,157,
 
380
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
381
  255,255,255,255,255,255,255, 45,  0,  0, 49,250,255,255,255,255,
 
382
  171,  0,  0,  0,  0,112,255,255,255,255,255,255,255,255,255,255,
 
383
  255,255,255,255,255,255,255,255,255,246, 19,  0,  0,  0, 54,253,
 
384
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
385
  255,255,255,255,255,255,255, 45,  0,  5,208,255,255,255,255,255,
 
386
  255, 77,  0,  0,  0,  9,231,255,255,255,255,255,255,255,255,255,
 
387
  255,255,255,255,255,255,255,255,255,163,  0,  0,  0,  0,186,255,
 
388
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
389
  255,255,255,255,255,255,255, 45,  0,121,255,255,255,255,255,255,
 
390
  255,211,  2,  0,  0,  0,134,255,255,255,255,255,255,255,255,255,
 
391
  255,255,255,255,255,255,255,255,255, 69,  0,  0,  0, 50,255,255,
 
392
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
393
  255,255,255,255,255,255,255, 45, 41,247,255,255,255,255,255,255,
 
394
  255,255, 73,  0,  0,  0, 38,254,255,255,255,255,255,255,255,255,
 
395
  255,255,255,255,255,255,255,255,237,  4,  0,  0,  0,145,255,255,
 
396
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
397
  255,255,255,255,255,255,255, 52,201,255,255,255,255,255,255,255,
 
398
  255,255,169,  0,  0,  0,  0,216,255,255,255,255,255,255,255,255,
 
399
  255,255,255,255,255,255,255,255,181,  0,  0,  0,  0,229,255,255,
 
400
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
401
  255,255,255,255,255,255,255,186,255,255,255,255,255,255,255,255,
 
402
  255,255,247,  7,  0,  0,  0,150,255,255,255,255,255,255,255,255,
 
403
  255,255,255,255,255,255,255,255,130,  0,  0,  0, 42,255,255,255,
 
404
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
405
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
406
  255,255,255, 67,  0,  0,  0, 91,255,255,255,255,255,255,255,255,
 
407
  255,255,255,255,255,255,255,255, 79,  0,  0,  0, 95,255,255,255,
 
408
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
409
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
410
  255,255,255,120,  0,  0,  0, 56,255,255,255,255,255,255,255,255,
 
411
  255,255,255,255,255,255,255,255, 55,  0,  0,  0,130,255,255,255,
 
412
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
413
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
414
  255,255,255,157,  0,  0,  0, 21,255,255,255,255,255,255,255,255,
 
415
  255,255,255,255,255,255,255,255, 34,  0,  0,  0,161,255,255,255,
 
416
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
417
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
418
  255,255,255,179,  0,  0,  0,  2,250,255,255,255,255,255,255,255,
 
419
  255,255,255,255,255,255,255,255, 27,  0,  0,  0,168,255,255,255,
 
420
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
421
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
422
  255,255,255,200,  0,  0,  0,  0,249,255,255,255,255,255,255,255,
 
423
  255,255,255,255,255,255,255,255, 27,  0,  0,  0,168,255,255,255,
 
424
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
425
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
426
  255,255,255,200,  0,  0,  0,  0,249,255,255,255,255,255,255,255,
 
427
  255,255,255,255,255,255,255,255, 27,  0,  0,  0,163,255,255,255,
 
428
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
429
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
430
  255,255,255,183,  0,  0,  0,  0,249,255,255,255,255,255,255,255,
 
431
  255,255,255,255,255,255,255,255, 42,  0,  0,  0,135,255,255,255,
 
432
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
433
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
434
  255,255,255,161,  0,  0,  0, 17,254,255,255,255,255,255,255,255,
 
435
  255,255,255,255,255,255,255,255, 76,  0,  0,  0,100,255,255,255,
 
436
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
437
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
438
  255,255,255,126,  0,  0,  0, 48,255,255,255,255,255,255,255,255,
 
439
  255,255,255,255,255,255,255,255,114,  0,  0,  0, 53,255,255,255,
 
440
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
441
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
442
  255,255,255, 78,  0,  0,  0, 84,255,255,255,255,255,255,255,255,
 
443
  255,255,255,255,255,255,255,255,165,  0,  0,  0,  3,241,255,255,
 
444
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
445
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
446
  255,255,252, 16,  0,  0,  0,139,255,255,255,255,255,255,255,255,
 
447
  255,255,255,255,255,255,255,255,228,  0,  0,  0,  0,161,255,255,
 
448
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
449
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
450
  255,255,192,  0,  0,  0,  0,198,255,255,255,255,255,255,255,255,
 
451
  255,255,255,255,255,255,255,255,255, 46,  0,  0,  0, 67,255,255,
 
452
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
453
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
454
  255,255, 93,  0,  0,  0, 21,250,255,255,255,255,255,255,255,255,
 
455
  255,255,255,255,255,255,255,255,255,139,  0,  0,  0,  1,211,255,
 
456
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
457
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
458
  255,226,  7,  0,  0,  0,108,255,255,255,255,255,255,255,255,255,
 
459
  255,255,255,255,255,255,255,255,255,230,  6,  0,  0,  0, 79,255,
 
460
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
461
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
462
  255,106,  0,  0,  0,  1,206,255,255,255,255,255,255,255,255,255,
 
463
  255,255,255,255,255,255,255,255,255,255, 97,  0,  0,  0,  0,183,
 
464
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
465
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
466
  202,  3,  0,  0,  0, 67,255,255,255,255,255,255,255,255,255,255,
 
467
  255,255,255,255,255,255,255,255,255,255,221,  8,  0,  0,  0, 27,
 
468
  235,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
469
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,243,
 
470
   40,  0,  0,  0,  0,198,255,255,255,255,255,255,255,255,255,255,
 
471
  255,255,255,255,255,255,255,255,255,255,255,126,  0,  0,  0,  0,
 
472
   71,252,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
473
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,253, 85,
 
474
    0,  0,  0,  0, 96,255,255,255,255,255,255,255,255,255,255,255,
 
475
  255,255,255,255,255,255,255,255,255,255,255,247, 44,  0,  0,  0,
 
476
    0, 91,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
477
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,116,  0,
 
478
    0,  0,  0, 25,233,255,255,255,255,255,255,255,255,255,255,255,
 
479
  255,255,255,255,255,255,255,255,255,255,255,255,216, 11,  0,  0,
 
480
    0,  0, 90,251,255,255,255,255,255,255,255,255,255,255,255,255,
 
481
  255,255,255,255,255,255,255,255,255,255,255,255,252,112,  0,  0,
 
482
    0,  0,  4,191,255,255,255,255,255,255,255,255,255,255,255,255,
 
483
  255,255,255,255,255,255,255,255,255,255,255,255,255,174,  4,  0,
 
484
    0,  0,  0, 72,235,255,255,255,255,255,255,255,255,255,255,255,
 
485
  255,255,255,255,255,255,255,255,255,255,255,242, 84,  0,  0,  0,
 
486
    0,  0,146,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
487
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,150,  1,
 
488
    0,  0,  0,  0, 27,181,255,255,255,255,255,255,255,255,255,255,
 
489
  255,255,255,255,255,255,255,255,255,255,194, 39,  0,  0,  0,  0,
 
490
    0,120,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
491
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,151,
 
492
    4,  0,  0,  0,  0,  0, 77,209,255,255,255,255,255,255,255,255,
 
493
  255,255,255,255,255,255,255,255,216, 92,  1,  0,  0,  0,  0,  0,
 
494
  125,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
495
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
496
  175, 12,  0,  0,  0,  0,  0,  1, 70,164,241,255,255,255,255,255,
 
497
  255,255,255,255,255,242,171, 77,  2,  0,  0,  0,  0,  0,  4,150,
 
498
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
499
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
500
  255,214, 41,  0,  0,  0,  0,  0,  0,  0,  4, 48, 98,138,163,163,
 
501
  163,163,140,103, 55,  5,  0,  0,  0,  0,  0,  0,  0, 30,199,255,
 
502
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
503
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
504
  255,255,245,125,  8,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
505
    0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  3,105,240,255,255,
 
506
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
507
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
508
  255,255,255,255,222,100,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0,
 
509
    0,  0,  0,  0,  0,  0,  0,  0,  0,  2, 83,210,255,255,255,255,
 
510
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
511
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
512
  255,255,255,255,255,255,228,136, 45,  0,  0,  0,  0,  0,  0,  0,
 
513
    0,  0,  0,  0,  0,  0,  0, 37,125,220,255,255,255,255,255,255,
 
514
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
515
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
516
  255,255,255,255,255,255,255,255,255,225,166,112, 74, 43, 32, 12,
 
517
    8, 32, 40, 71,105,162,218,255,255,255,255,255,255,255,255,255,
 
518
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
519
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
520
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
521
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
522
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
523
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
524
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
525
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
526
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
527
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
528
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
529
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
530
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
531
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
532
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
533
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
534
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
535
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
536
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
537
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
538
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
539
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
540
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
541
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
542
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
543
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
544
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
545
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
546
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
547
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
548
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
549
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
550
  255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
 
551
};
 
552
 
 
553
 
 
554
/* Add a rotation around the wx-plane to the matrix m. */
 
555
static void rotatewx(float m[4][4], float phi)
 
556
{
 
557
  float c, s, u, v;
 
558
  int i;
 
559
 
 
560
  phi *= M_PI/180.0;
 
561
  c = cos(phi);
 
562
  s = sin(phi);
 
563
  for (i=0; i<4; i++)
 
564
  {
 
565
    u = m[i][1];
 
566
    v = m[i][2];
 
567
    m[i][1] = c*u+s*v;
 
568
    m[i][2] = -s*u+c*v;
 
569
  }
 
570
}
 
571
 
 
572
 
 
573
/* Add a rotation around the wy-plane to the matrix m. */
 
574
static void rotatewy(float m[4][4], float phi)
 
575
{
 
576
  float c, s, u, v;
 
577
  int i;
 
578
 
 
579
  phi *= M_PI/180.0;
 
580
  c = cos(phi);
 
581
  s = sin(phi);
 
582
  for (i=0; i<4; i++)
 
583
  {
 
584
    u = m[i][0];
 
585
    v = m[i][2];
 
586
    m[i][0] = c*u-s*v;
 
587
    m[i][2] = s*u+c*v;
 
588
  }
 
589
}
 
590
 
 
591
 
 
592
/* Add a rotation around the wz-plane to the matrix m. */
 
593
static void rotatewz(float m[4][4], float phi)
 
594
{
 
595
  float c, s, u, v;
 
596
  int i;
 
597
 
 
598
  phi *= M_PI/180.0;
 
599
  c = cos(phi);
 
600
  s = sin(phi);
 
601
  for (i=0; i<4; i++)
 
602
  {
 
603
    u = m[i][0];
 
604
    v = m[i][1];
 
605
    m[i][0] = c*u+s*v;
 
606
    m[i][1] = -s*u+c*v;
 
607
  }
 
608
}
 
609
 
 
610
 
 
611
/* Add a rotation around the xy-plane to the matrix m. */
 
612
static void rotatexy(float m[4][4], float phi)
 
613
{
 
614
  float c, s, u, v;
 
615
  int i;
 
616
 
 
617
  phi *= M_PI/180.0;
 
618
  c = cos(phi);
 
619
  s = sin(phi);
 
620
  for (i=0; i<4; i++)
 
621
  {
 
622
    u = m[i][2];
 
623
    v = m[i][3];
 
624
    m[i][2] = c*u+s*v;
 
625
    m[i][3] = -s*u+c*v;
 
626
  }
 
627
}
 
628
 
 
629
 
 
630
/* Add a rotation around the xz-plane to the matrix m. */
 
631
static void rotatexz(float m[4][4], float phi)
 
632
{
 
633
  float c, s, u, v;
 
634
  int i;
 
635
 
 
636
  phi *= M_PI/180.0;
 
637
  c = cos(phi);
 
638
  s = sin(phi);
 
639
  for (i=0; i<4; i++)
 
640
  {
 
641
    u = m[i][1];
 
642
    v = m[i][3];
 
643
    m[i][1] = c*u-s*v;
 
644
    m[i][3] = s*u+c*v;
 
645
  }
 
646
}
 
647
 
 
648
 
 
649
/* Add a rotation around the yz-plane to the matrix m. */
 
650
static void rotateyz(float m[4][4], float phi)
 
651
{
 
652
  float c, s, u, v;
 
653
  int i;
 
654
 
 
655
  phi *= M_PI/180.0;
 
656
  c = cos(phi);
 
657
  s = sin(phi);
 
658
  for (i=0; i<4; i++)
 
659
  {
 
660
    u = m[i][0];
 
661
    v = m[i][3];
 
662
    m[i][0] = c*u-s*v;
 
663
    m[i][3] = s*u+c*v;
 
664
  }
 
665
}
 
666
 
 
667
 
 
668
/* Compute the rotation matrix m from the rotation angles. */
 
669
static void rotateall(float al, float be, float de, float ze, float et,
 
670
                      float th, float m[4][4])
 
671
{
 
672
  int i, j;
 
673
 
 
674
  for (i=0; i<4; i++)
 
675
    for (j=0; j<4; j++)
 
676
      m[i][j] = (i==j);
 
677
  rotatewx(m,al);
 
678
  rotatewy(m,be);
 
679
  rotatewz(m,de);
 
680
  rotatexy(m,ze);
 
681
  rotatexz(m,et);
 
682
  rotateyz(m,th);
 
683
}
 
684
 
 
685
 
 
686
/* Compute the rotation matrix m from the 4d rotation angles. */
 
687
static void rotateall4d(float ze, float et, float th, float m[4][4])
 
688
{
 
689
  int i, j;
 
690
 
 
691
  for (i=0; i<4; i++)
 
692
    for (j=0; j<4; j++)
 
693
      m[i][j] = (i==j);
 
694
  rotatexy(m,ze);
 
695
  rotatexz(m,et);
 
696
  rotateyz(m,th);
 
697
}
 
698
 
 
699
 
 
700
/* Multiply two rotation matrices: o=m*n. */
 
701
static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
 
702
{
 
703
  int i, j, k;
 
704
 
 
705
  for (i=0; i<4; i++)
 
706
  {
 
707
    for (j=0; j<4; j++)
 
708
    {
 
709
      o[i][j] = 0.0;
 
710
      for (k=0; k<4; k++)
 
711
        o[i][j] += m[i][k]*n[k][j];
 
712
    }
 
713
  }
 
714
}
 
715
 
 
716
 
 
717
/* Compute a 4D rotation matrix from two unit quaternions. */
 
718
static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
 
719
{
 
720
  double al, be, de, ze, et, th;
 
721
  double r00, r01, r02, r12, r22;
 
722
 
 
723
  r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
 
724
  r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
 
725
  r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
 
726
  r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
 
727
  r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
 
728
 
 
729
  al = atan2(-r12,r22)*180.0/M_PI;
 
730
  be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
 
731
  de = atan2(-r01,r00)*180.0/M_PI;
 
732
 
 
733
  r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
 
734
  r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
 
735
  r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
 
736
  r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
 
737
  r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
 
738
 
 
739
  et = atan2(-r12,r22)*180.0/M_PI;
 
740
  th = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
 
741
  ze = atan2(-r01,r00)*180.0/M_PI;
 
742
 
 
743
  rotateall(al,be,de,ze,et,-th,m);
 
744
}
 
745
 
 
746
 
 
747
/* Compute a fully saturated and bright color based on an angle. */
 
748
static void color(double angle, float col[4])
 
749
{
 
750
  int s;
 
751
  double t;
 
752
 
 
753
  if (colors == COLORS_TWOSIDED)
 
754
    return;
 
755
 
 
756
  if (angle >= 0.0)
 
757
    angle = fmod(angle,2.0*M_PI);
 
758
  else
 
759
    angle = fmod(angle,-2.0*M_PI);
 
760
  s = floor(angle/(M_PI/3));
 
761
  t = angle/(M_PI/3)-s;
 
762
  if (s >= 6)
 
763
    s = 0;
 
764
  switch (s)
 
765
  {
 
766
    case 0:
 
767
      col[0] = 1.0;
 
768
      col[1] = t;
 
769
      col[2] = 0.0;
 
770
      break;
 
771
    case 1:
 
772
      col[0] = 1.0-t;
 
773
      col[1] = 1.0;
 
774
      col[2] = 0.0;
 
775
      break;
 
776
    case 2:
 
777
      col[0] = 0.0;
 
778
      col[1] = 1.0;
 
779
      col[2] = t;
 
780
      break;
 
781
    case 3:
 
782
      col[0] = 0.0;
 
783
      col[1] = 1.0-t;
 
784
      col[2] = 1.0;
 
785
      break;
 
786
    case 4:
 
787
      col[0] = t;
 
788
      col[1] = 0.0;
 
789
      col[2] = 1.0;
 
790
      break;
 
791
    case 5:
 
792
      col[0] = 1.0;
 
793
      col[1] = 0.0;
 
794
      col[2] = 1.0-t;
 
795
      break;
 
796
  }
 
797
  if (display_mode == DISP_TRANSPARENT)
 
798
    col[3] = 0.7;
 
799
  else
 
800
    col[3] = 1.0;
 
801
}
 
802
 
 
803
 
 
804
/* Set up the figure-8 Klein bottle coordinates, colors, and texture. */
 
805
static void setup_figure8(ModeInfo *mi, double umin, double umax, double vmin,
 
806
                          double vmax)
 
807
{
 
808
  int i, j, k, l;
 
809
  double u, v, ur, vr;
 
810
  double cu, su, cv, sv, cv2, sv2, c2u, s2u;
 
811
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
812
 
 
813
  ur = umax-umin;
 
814
  vr = vmax-vmin;
 
815
  for (i=0; i<=NUMU; i++)
 
816
  {
 
817
    for (j=0; j<=NUMV; j++)
 
818
    {
 
819
      k = i*(NUMV+1)+j;
 
820
      u = -ur*j/NUMU+umin;
 
821
      v = vr*i/NUMV+vmin;
 
822
      if (colors == COLORS_DEPTH)
 
823
        color((cos(u)+1.0)*M_PI*2.0/3.0,kb->col[k]);
 
824
      else
 
825
        color(v,kb->col[k]);
 
826
      kb->tex[k][0] = -32*u/(2.0*M_PI);
 
827
      kb->tex[k][1] = 32*v/(2.0*M_PI);
 
828
      cu = cos(u);
 
829
      su = sin(u);
 
830
      cv = cos(v);
 
831
      sv = sin(v);
 
832
      cv2 = cos(0.5*v);
 
833
      sv2 = sin(0.5*v);
 
834
      c2u = cos(2.0*u);
 
835
      s2u = sin(2.0*u);
 
836
      kb->x[k][0] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*cv;
 
837
      kb->x[k][1] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*sv;
 
838
      kb->x[k][2] = su*sv2+s2u*cv2;
 
839
      kb->x[k][3] = cu;
 
840
      kb->xu[k][0] = (cu*cv2-2.0*c2u*sv2)*cv;
 
841
      kb->xu[k][1] = (cu*cv2-2.0*c2u*sv2)*sv;
 
842
      kb->xu[k][2] = cu*sv2+2.0*c2u*cv2;
 
843
      kb->xu[k][3] = -su;
 
844
      kb->xv[k][0] = ((-0.5*su*sv2-0.5*s2u*cv2)*cv-
 
845
                      (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*sv);
 
846
      kb->xv[k][1] = ((-0.5*su*sv2-0.5*s2u*cv2)*sv+
 
847
                      (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*cv);
 
848
      kb->xv[k][2] = 0.5*su*cv2-0.5*s2u*sv2;
 
849
      kb->xv[k][3] = 0.0;
 
850
      for (l=0; l<4; l++)
 
851
      {
 
852
        kb->x[k][l] /= FIGURE_8_RADIUS+1.25;
 
853
        kb->xu[k][l] /= FIGURE_8_RADIUS+1.25;
 
854
        kb->xv[k][l] /= FIGURE_8_RADIUS+1.25;
 
855
      }
 
856
    }
 
857
  }
 
858
}
 
859
 
 
860
 
 
861
/* Set up the Lawson Klein bottle coordinates, colors, and texture. */
 
862
static void setup_lawson(ModeInfo *mi, double umin, double umax, double vmin,
 
863
                         double vmax)
 
864
{
 
865
  int i, j, k;
 
866
  double u, v, ur, vr;
 
867
  double cu, su, cv, sv, cv2, sv2;
 
868
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
869
 
 
870
  ur = umax-umin;
 
871
  vr = vmax-vmin;
 
872
  for (i=0; i<=NUMV; i++)
 
873
  {
 
874
    for (j=0; j<=NUMU; j++)
 
875
    {
 
876
      k = i*(NUMU+1)+j;
 
877
      u = -ur*j/NUMU+umin;
 
878
      v = vr*i/NUMV+vmin;
 
879
      if (colors == COLORS_DEPTH)
 
880
        color((sin(u)*cos(0.5*v)+1.0)*M_PI*2.0/3.0,kb->col[k]);
 
881
      else
 
882
        color(v,kb->col[k]);
 
883
      kb->tex[k][0] = -32*u/(2.0*M_PI);
 
884
      kb->tex[k][1] = 32*v/(2.0*M_PI);
 
885
      cu = cos(u);
 
886
      su = sin(u);
 
887
      cv = cos(v);
 
888
      sv = sin(v);
 
889
      cv2 = cos(0.5*v);
 
890
      sv2 = sin(0.5*v);
 
891
      kb->x[k][0] = cu*cv;
 
892
      kb->x[k][1] = cu*sv;
 
893
      kb->x[k][2] = su*sv2;
 
894
      kb->x[k][3] = su*cv2;
 
895
      kb->xu[k][0] = -su*cv;
 
896
      kb->xu[k][1] = -su*sv;
 
897
      kb->xu[k][2] = cu*sv2;
 
898
      kb->xu[k][3] = cu*cv2;
 
899
      kb->xv[k][0] = -cu*sv;
 
900
      kb->xv[k][1] = cu*cv;
 
901
      kb->xv[k][2] = su*cv2*0.5;
 
902
      kb->xv[k][3] = -su*sv2*0.5;
 
903
    }
 
904
  }
 
905
}
 
906
 
 
907
 
 
908
/* Draw a figure-8 Klein bottle projected into 3D. */
 
909
static int figure8(ModeInfo *mi, double umin, double umax, double vmin,
 
910
                   double vmax)
 
911
{
 
912
  int polys = 0;
 
913
  static const GLfloat mat_diff_red[]         = { 1.0, 0.0, 0.0, 1.0 };
 
914
  static const GLfloat mat_diff_green[]       = { 0.0, 1.0, 0.0, 1.0 };
 
915
  static const GLfloat mat_diff_trans_red[]   = { 1.0, 0.0, 0.0, 0.7 };
 
916
  static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
 
917
  float p[3], pu[3], pv[3], pm[3], n[3], b[3], mat[4][4];
 
918
  int i, j, k, l, m, o;
 
919
  double u, v;
 
920
  double xx[4], xxu[4], xxv[4], y[4], yu[4], yv[4];
 
921
  double q, r, s, t;
 
922
  double cu, su, cv, sv, cv2, sv2, c2u, s2u;
 
923
  float q1[4], q2[4], r1[4][4], r2[4][4];
 
924
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
925
 
 
926
  if (view == VIEW_WALK || view == VIEW_WALKTURN)
 
927
  {
 
928
    /* Compute the rotation that rotates the Klein bottle in 4D without the
 
929
       trackball rotations. */
 
930
    rotateall4d(kb->zeta,kb->eta,kb->theta,mat);
 
931
 
 
932
    u = kb->umove;
 
933
    v = kb->vmove;
 
934
    cu = cos(u);
 
935
    su = sin(u);
 
936
    cv = cos(v);
 
937
    sv = sin(v);
 
938
    cv2 = cos(0.5*v);
 
939
    sv2 = sin(0.5*v);
 
940
    c2u = cos(2.0*u);
 
941
    s2u = sin(2.0*u);
 
942
    xx[0] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*cv;
 
943
    xx[1] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*sv;
 
944
    xx[2] = su*sv2+s2u*cv2;
 
945
    xx[3] = cu;
 
946
    xxu[0] = (cu*cv2-2.0*c2u*sv2)*cv;
 
947
    xxu[1] = (cu*cv2-2.0*c2u*sv2)*sv;
 
948
    xxu[2] = cu*sv2+2.0*c2u*cv2;
 
949
    xxu[3] = -su;
 
950
    xxv[0] = ((-0.5*su*sv2-0.5*s2u*cv2)*cv-
 
951
              (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*sv);
 
952
    xxv[1] = ((-0.5*su*sv2-0.5*s2u*cv2)*sv+
 
953
              (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*cv);
 
954
    xxv[2] = 0.5*su*cv2-0.5*s2u*sv2;
 
955
    xxv[3] = 0.0;
 
956
    for (l=0; l<4; l++)
 
957
    {
 
958
      xx[l] /= FIGURE_8_RADIUS+1.25;
 
959
      xxu[l] /= FIGURE_8_RADIUS+1.25;
 
960
      xxv[l] /= FIGURE_8_RADIUS+1.25;
 
961
    }
 
962
    for (l=0; l<4; l++)
 
963
    {
 
964
      y[l] = (mat[l][0]*xx[0]+mat[l][1]*xx[1]+
 
965
              mat[l][2]*xx[2]+mat[l][3]*xx[3]);
 
966
      yu[l] = (mat[l][0]*xxu[0]+mat[l][1]*xxu[1]+
 
967
               mat[l][2]*xxu[2]+mat[l][3]*xxu[3]);
 
968
      yv[l] = (mat[l][0]*xxv[0]+mat[l][1]*xxv[1]+
 
969
               mat[l][2]*xxv[2]+mat[l][3]*xxv[3]);
 
970
    }
 
971
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
972
    {
 
973
      for (l=0; l<3; l++)
 
974
      {
 
975
        p[l] = y[l]+kb->offset4d[l];
 
976
        pu[l] = yu[l];
 
977
        pv[l] = yv[l];
 
978
      }
 
979
    }
 
980
    else
 
981
    {
 
982
      s = y[3]+kb->offset4d[3];
 
983
      q = 1.0/s;
 
984
      t = q*q;
 
985
      for (l=0; l<3; l++)
 
986
      {
 
987
        r = y[l]+kb->offset4d[l];
 
988
        p[l] = r*q;
 
989
        pu[l] = (yu[l]*s-r*yu[3])*t;
 
990
        pv[l] = (yv[l]*s-r*yv[3])*t;
 
991
      }
 
992
    }
 
993
    n[0] = pu[1]*pv[2]-pu[2]*pv[1];
 
994
    n[1] = pu[2]*pv[0]-pu[0]*pv[2];
 
995
    n[2] = pu[0]*pv[1]-pu[1]*pv[0];
 
996
    t = 1.0/(kb->side*4.0*sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]));
 
997
    n[0] *= t;
 
998
    n[1] *= t;
 
999
    n[2] *= t;
 
1000
    pm[0] = pu[0]*kb->dumove+pv[0]*kb->dvmove;
 
1001
    pm[1] = pu[1]*kb->dumove+pv[1]*kb->dvmove;
 
1002
    pm[2] = pu[2]*kb->dumove+pv[2]*kb->dvmove;
 
1003
    t = 1.0/(4.0*sqrt(pm[0]*pm[0]+pm[1]*pm[1]+pm[2]*pm[2]));
 
1004
    pm[0] *= t;
 
1005
    pm[1] *= t;
 
1006
    pm[2] *= t;
 
1007
    b[0] = n[1]*pm[2]-n[2]*pm[1];
 
1008
    b[1] = n[2]*pm[0]-n[0]*pm[2];
 
1009
    b[2] = n[0]*pm[1]-n[1]*pm[0];
 
1010
    t = 1.0/(4.0*sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]));
 
1011
    b[0] *= t;
 
1012
    b[1] *= t;
 
1013
    b[2] *= t;
 
1014
 
 
1015
    /* Compute alpha, beta, delta from the three basis vectors.
 
1016
           |  -b[0]  -b[1]  -b[2] |
 
1017
       m = |   n[0]   n[1]   n[2] |
 
1018
           | -pm[0] -pm[1] -pm[2] |
 
1019
    */
 
1020
    kb->alpha = atan2(-n[2],-pm[2])*180/M_PI;
 
1021
    kb->beta = atan2( -b[2],sqrt(b[0]*b[0]+b[1]*b[1]))*180/M_PI;
 
1022
    kb->delta = atan2(b[1],-b[0])*180/M_PI;
 
1023
 
 
1024
    /* Compute the rotation that rotates the Klein bottle in 4D. */
 
1025
    rotateall(kb->alpha,kb->beta,kb->delta,kb->zeta,kb->eta,kb->theta,mat);
 
1026
 
 
1027
    u = kb->umove;
 
1028
    v = kb->vmove;
 
1029
    cu = cos(u);
 
1030
    su = sin(u);
 
1031
    cv = cos(v);
 
1032
    sv = sin(v);
 
1033
    cv2 = cos(0.5*v);
 
1034
    sv2 = sin(0.5*v);
 
1035
    c2u = cos(2.0*u);
 
1036
    s2u = sin(2.0*u);
 
1037
    xx[0] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*cv;
 
1038
    xx[1] = (su*cv2-s2u*sv2+FIGURE_8_RADIUS)*sv;
 
1039
    xx[2] = su*sv2+s2u*cv2;
 
1040
    xx[3] = cu;
 
1041
    for (l=0; l<4; l++)
 
1042
      xx[l] /= FIGURE_8_RADIUS+1.25;
 
1043
    for (l=0; l<4; l++)
 
1044
    {
 
1045
      r = 0.0;
 
1046
      for (m=0; m<4; m++)
 
1047
        r += mat[l][m]*xx[m];
 
1048
      y[l] = r;
 
1049
    }
 
1050
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1051
    {
 
1052
      for (l=0; l<3; l++)
 
1053
        p[l] = y[l]+kb->offset4d[l];
 
1054
    }
 
1055
    else
 
1056
    {
 
1057
      s = y[3]+kb->offset4d[3];
 
1058
      for (l=0; l<3; l++)
 
1059
        p[l] = (y[l]+kb->offset4d[l])/s;
 
1060
    }
 
1061
 
 
1062
    kb->offset3d[0] = -p[0];
 
1063
    kb->offset3d[1] = -p[1]-DELTAY;
 
1064
    kb->offset3d[2] = -p[2];
 
1065
  }
 
1066
  else
 
1067
  {
 
1068
    /* Compute the rotation that rotates the Klein bottle in 4D, including
 
1069
       the trackball rotations. */
 
1070
    rotateall(kb->alpha,kb->beta,kb->delta,kb->zeta,kb->eta,kb->theta,r1);
 
1071
 
 
1072
    gltrackball_get_quaternion(kb->trackballs[0],q1);
 
1073
    gltrackball_get_quaternion(kb->trackballs[1],q2);
 
1074
    quats_to_rotmat(q1,q2,r2);
 
1075
 
 
1076
    mult_rotmat(r2,r1,mat);
 
1077
  }
 
1078
 
 
1079
  /* Project the points from 4D to 3D. */
 
1080
  for (i=0; i<=NUMU; i++)
 
1081
  {
 
1082
    for (j=0; j<=NUMV; j++)
 
1083
    {
 
1084
      o = i*(NUMV+1)+j;
 
1085
      for (l=0; l<4; l++)
 
1086
      {
 
1087
        y[l] = (mat[l][0]*kb->x[o][0]+mat[l][1]*kb->x[o][1]+
 
1088
                mat[l][2]*kb->x[o][2]+mat[l][3]*kb->x[o][3]);
 
1089
        yu[l] = (mat[l][0]*kb->xu[o][0]+mat[l][1]*kb->xu[o][1]+
 
1090
                 mat[l][2]*kb->xu[o][2]+mat[l][3]*kb->xu[o][3]);
 
1091
        yv[l] = (mat[l][0]*kb->xv[o][0]+mat[l][1]*kb->xv[o][1]+
 
1092
                 mat[l][2]*kb->xv[o][2]+mat[l][3]*kb->xv[o][3]);
 
1093
      }
 
1094
      if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1095
      {
 
1096
        for (l=0; l<3; l++)
 
1097
        {
 
1098
          kb->pp[o][l] = (y[l]+kb->offset4d[l])+kb->offset3d[l];
 
1099
          pu[l] = yu[l];
 
1100
          pv[l] = yv[l];
 
1101
        }
 
1102
      }
 
1103
      else
 
1104
      {
 
1105
        s = y[3]+kb->offset4d[3];
 
1106
        q = 1.0/s;
 
1107
        t = q*q;
 
1108
        for (l=0; l<3; l++)
 
1109
        {
 
1110
          r = y[l]+kb->offset4d[l];
 
1111
          kb->pp[o][l] = r*q+kb->offset3d[l];
 
1112
          pu[l] = (yu[l]*s-r*yu[3])*t;
 
1113
          pv[l] = (yv[l]*s-r*yv[3])*t;
 
1114
        }
 
1115
      }
 
1116
      kb->pn[o][0] = pu[1]*pv[2]-pu[2]*pv[1];
 
1117
      kb->pn[o][1] = pu[2]*pv[0]-pu[0]*pv[2];
 
1118
      kb->pn[o][2] = pu[0]*pv[1]-pu[1]*pv[0];
 
1119
      t = 1.0/sqrt(kb->pn[o][0]*kb->pn[o][0]+kb->pn[o][1]*kb->pn[o][1]+
 
1120
                   kb->pn[o][2]*kb->pn[o][2]);
 
1121
      kb->pn[o][0] *= t;
 
1122
      kb->pn[o][1] *= t;
 
1123
      kb->pn[o][2] *= t;
 
1124
    }
 
1125
  }
 
1126
 
 
1127
  if (colors == COLORS_TWOSIDED)
 
1128
  {
 
1129
    glColor3fv(mat_diff_red);
 
1130
    if (display_mode == DISP_TRANSPARENT)
 
1131
    {
 
1132
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
 
1133
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
 
1134
    }
 
1135
    else
 
1136
    {
 
1137
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
 
1138
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
 
1139
    }
 
1140
  }
 
1141
  glBindTexture(GL_TEXTURE_2D,kb->tex_name);
 
1142
 
 
1143
  for (i=0; i<NUMU; i++)
 
1144
  {
 
1145
    if (appearance == APPEARANCE_BANDS && ((i & (NUMB-1)) >= NUMB/2))
 
1146
      continue;
 
1147
    if (display_mode == DISP_WIREFRAME)
 
1148
      glBegin(GL_QUAD_STRIP);
 
1149
    else
 
1150
      glBegin(GL_TRIANGLE_STRIP);
 
1151
    for (j=0; j<=NUMV; j++)
 
1152
    {
 
1153
      for (k=0; k<=1; k++)
 
1154
      {
 
1155
        l = (i+k);
 
1156
        m = j;
 
1157
        o = l*(NUMV+1)+m;
 
1158
        glNormal3fv(kb->pn[o]);
 
1159
        glTexCoord2fv(kb->tex[o]);
 
1160
        if (colors != COLORS_TWOSIDED)
 
1161
        {
 
1162
          glColor3fv(kb->col[o]);
 
1163
          glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,kb->col[o]);
 
1164
        }
 
1165
        glVertex3fv(kb->pp[o]);
 
1166
        polys++;
 
1167
      }
 
1168
    }
 
1169
    glEnd();
 
1170
  }
 
1171
  polys /= 2;
 
1172
  return polys;
 
1173
}
 
1174
 
 
1175
 
 
1176
/* Draw a Lawson Klein bottle projected into 3D. */
 
1177
static int lawson(ModeInfo *mi, double umin, double umax, double vmin,
 
1178
                  double vmax)
 
1179
{
 
1180
  int polys = 0;
 
1181
  static const GLfloat mat_diff_red[]         = { 1.0, 0.0, 0.0, 1.0 };
 
1182
  static const GLfloat mat_diff_green[]       = { 0.0, 1.0, 0.0, 1.0 };
 
1183
  static const GLfloat mat_diff_trans_red[]   = { 1.0, 0.0, 0.0, 0.7 };
 
1184
  static const GLfloat mat_diff_trans_green[] = { 0.0, 1.0, 0.0, 0.7 };
 
1185
  float p[3], pu[3], pv[3], pm[3], n[3], b[3], mat[4][4];
 
1186
  int i, j, k, l, m, o;
 
1187
  double u, v;
 
1188
  double cu, su, cv, sv, cv2, sv2;
 
1189
  double xx[4], xxu[4], xxv[4], y[4], yu[4], yv[4];
 
1190
  double q, r, s, t;
 
1191
  float q1[4], q2[4], r1[4][4], r2[4][4];
 
1192
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1193
 
 
1194
  if (view == VIEW_WALK || view == VIEW_WALKTURN)
 
1195
  {
 
1196
    /* Compute the rotation that rotates the Klein bottle in 4D without the
 
1197
       trackball rotations. */
 
1198
    rotateall4d(kb->zeta,kb->eta,kb->theta,mat);
 
1199
 
 
1200
    u = kb->umove;
 
1201
    v = kb->vmove;
 
1202
    cu = cos(u);
 
1203
    su = sin(u);
 
1204
    cv = cos(v);
 
1205
    sv = sin(v);
 
1206
    cv2 = cos(0.5*v);
 
1207
    sv2 = sin(0.5*v);
 
1208
    xx[0] = cu*cv;
 
1209
    xx[1] = cu*sv;
 
1210
    xx[2] = su*sv2;
 
1211
    xx[3] = su*cv2;
 
1212
    xxu[0] = -su*cv;
 
1213
    xxu[1] = -su*sv;
 
1214
    xxu[2] = cu*sv2;
 
1215
    xxu[3] = cu*cv2;
 
1216
    xxv[0] = -cu*sv;
 
1217
    xxv[1] = cu*cv;
 
1218
    xxv[2] = su*cv2*0.5;
 
1219
    xxv[3] = -su*sv2*0.5;
 
1220
    for (l=0; l<4; l++)
 
1221
    {
 
1222
      y[l] = (mat[l][0]*xx[0]+mat[l][1]*xx[1]+
 
1223
              mat[l][2]*xx[2]+mat[l][3]*xx[3]);
 
1224
      yu[l] = (mat[l][0]*xxu[0]+mat[l][1]*xxu[1]+
 
1225
               mat[l][2]*xxu[2]+mat[l][3]*xxu[3]);
 
1226
      yv[l] = (mat[l][0]*xxv[0]+mat[l][1]*xxv[1]+
 
1227
               mat[l][2]*xxv[2]+mat[l][3]*xxv[3]);
 
1228
    }
 
1229
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1230
    {
 
1231
      for (l=0; l<3; l++)
 
1232
      {
 
1233
        p[l] = y[l]+kb->offset4d[l];
 
1234
        pu[l] = yu[l];
 
1235
        pv[l] = yv[l];
 
1236
      }
 
1237
    }
 
1238
    else
 
1239
    {
 
1240
      s = y[3]+kb->offset4d[3];
 
1241
      q = 1.0/s;
 
1242
      t = q*q;
 
1243
      for (l=0; l<3; l++)
 
1244
      {
 
1245
        r = y[l]+kb->offset4d[l];
 
1246
        p[l] = r*q;
 
1247
        pu[l] = (yu[l]*s-r*yu[3])*t;
 
1248
        pv[l] = (yv[l]*s-r*yv[3])*t;
 
1249
      }
 
1250
    }
 
1251
    n[0] = pu[1]*pv[2]-pu[2]*pv[1];
 
1252
    n[1] = pu[2]*pv[0]-pu[0]*pv[2];
 
1253
    n[2] = pu[0]*pv[1]-pu[1]*pv[0];
 
1254
    t = 1.0/(kb->side*4.0*sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]));
 
1255
    n[0] *= t;
 
1256
    n[1] *= t;
 
1257
    n[2] *= t;
 
1258
    pm[0] = pu[0]*kb->dumove+pv[0]*kb->dvmove;
 
1259
    pm[1] = pu[1]*kb->dumove+pv[1]*kb->dvmove;
 
1260
    pm[2] = pu[2]*kb->dumove+pv[2]*kb->dvmove;
 
1261
    t = 1.0/(4.0*sqrt(pm[0]*pm[0]+pm[1]*pm[1]+pm[2]*pm[2]));
 
1262
    pm[0] *= t;
 
1263
    pm[1] *= t;
 
1264
    pm[2] *= t;
 
1265
    b[0] = n[1]*pm[2]-n[2]*pm[1];
 
1266
    b[1] = n[2]*pm[0]-n[0]*pm[2];
 
1267
    b[2] = n[0]*pm[1]-n[1]*pm[0];
 
1268
    t = 1.0/(4.0*sqrt(b[0]*b[0]+b[1]*b[1]+b[2]*b[2]));
 
1269
    b[0] *= t;
 
1270
    b[1] *= t;
 
1271
    b[2] *= t;
 
1272
 
 
1273
    /* Compute alpha, beta, delta from the three basis vectors.
 
1274
           |  -b[0]  -b[1]  -b[2] |
 
1275
       m = |   n[0]   n[1]   n[2] |
 
1276
           | -pm[0] -pm[1] -pm[2] |
 
1277
    */
 
1278
    kb->alpha = atan2(-n[2],-pm[2])*180/M_PI;
 
1279
    kb->beta = atan2( -b[2],sqrt(b[0]*b[0]+b[1]*b[1]))*180/M_PI;
 
1280
    kb->delta = atan2(b[1],-b[0])*180/M_PI;
 
1281
 
 
1282
    /* Compute the rotation that rotates the Klein bottle in 4D. */
 
1283
    rotateall(kb->alpha,kb->beta,kb->delta,kb->zeta,kb->eta,kb->theta,mat);
 
1284
 
 
1285
    u = kb->umove;
 
1286
    v = kb->vmove;
 
1287
    cu = cos(u);
 
1288
    su = sin(u);
 
1289
    cv = cos(v);
 
1290
    sv = sin(v);
 
1291
    cv2 = cos(0.5*v);
 
1292
    sv2 = sin(0.5*v);
 
1293
    xx[0] = cu*cv;
 
1294
    xx[1] = cu*sv;
 
1295
    xx[2] = su*sv2;
 
1296
    xx[3] = su*cv2;
 
1297
    for (l=0; l<4; l++)
 
1298
    {
 
1299
      r = 0.0;
 
1300
      for (m=0; m<4; m++)
 
1301
        r += mat[l][m]*xx[m];
 
1302
      y[l] = r;
 
1303
    }
 
1304
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1305
    {
 
1306
      for (l=0; l<3; l++)
 
1307
        p[l] = y[l]+kb->offset4d[l];
 
1308
    }
 
1309
    else
 
1310
    {
 
1311
      s = y[3]+kb->offset4d[3];
 
1312
      for (l=0; l<3; l++)
 
1313
        p[l] = (y[l]+kb->offset4d[l])/s;
 
1314
    }
 
1315
 
 
1316
    kb->offset3d[0] = -p[0];
 
1317
    kb->offset3d[1] = -p[1]-DELTAY;
 
1318
    kb->offset3d[2] = -p[2];
 
1319
  }
 
1320
  else
 
1321
  {
 
1322
    /* Compute the rotation that rotates the Klein bottle in 4D, including
 
1323
       the trackball rotations. */
 
1324
    rotateall(kb->alpha,kb->beta,kb->delta,kb->zeta,kb->eta,kb->theta,r1);
 
1325
 
 
1326
    gltrackball_get_quaternion(kb->trackballs[0],q1);
 
1327
    gltrackball_get_quaternion(kb->trackballs[1],q2);
 
1328
    quats_to_rotmat(q1,q2,r2);
 
1329
 
 
1330
    mult_rotmat(r2,r1,mat);
 
1331
  }
 
1332
 
 
1333
  /* Project the points from 4D to 3D. */
 
1334
  for (i=0; i<=NUMV; i++)
 
1335
  {
 
1336
    for (j=0; j<=NUMU; j++)
 
1337
    {
 
1338
      o = i*(NUMU+1)+j;
 
1339
      for (l=0; l<4; l++)
 
1340
      {
 
1341
        y[l] = (mat[l][0]*kb->x[o][0]+mat[l][1]*kb->x[o][1]+
 
1342
                mat[l][2]*kb->x[o][2]+mat[l][3]*kb->x[o][3]);
 
1343
        yu[l] = (mat[l][0]*kb->xu[o][0]+mat[l][1]*kb->xu[o][1]+
 
1344
                 mat[l][2]*kb->xu[o][2]+mat[l][3]*kb->xu[o][3]);
 
1345
        yv[l] = (mat[l][0]*kb->xv[o][0]+mat[l][1]*kb->xv[o][1]+
 
1346
                 mat[l][2]*kb->xv[o][2]+mat[l][3]*kb->xv[o][3]);
 
1347
      }
 
1348
      if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1349
      {
 
1350
        for (l=0; l<3; l++)
 
1351
        {
 
1352
          kb->pp[o][l] = (y[l]+kb->offset4d[l])+kb->offset3d[l];
 
1353
          pu[l] = yu[l];
 
1354
          pv[l] = yv[l];
 
1355
        }
 
1356
      }
 
1357
      else
 
1358
      {
 
1359
        s = y[3]+kb->offset4d[3];
 
1360
        q = 1.0/s;
 
1361
        t = q*q;
 
1362
        for (l=0; l<3; l++)
 
1363
        {
 
1364
          r = y[l]+kb->offset4d[l];
 
1365
          kb->pp[o][l] = r*q+kb->offset3d[l];
 
1366
          pu[l] = (yu[l]*s-r*yu[3])*t;
 
1367
          pv[l] = (yv[l]*s-r*yv[3])*t;
 
1368
        }
 
1369
      }
 
1370
      kb->pn[o][0] = pu[1]*pv[2]-pu[2]*pv[1];
 
1371
      kb->pn[o][1] = pu[2]*pv[0]-pu[0]*pv[2];
 
1372
      kb->pn[o][2] = pu[0]*pv[1]-pu[1]*pv[0];
 
1373
      t = 1.0/sqrt(kb->pn[o][0]*kb->pn[o][0]+kb->pn[o][1]*kb->pn[o][1]+
 
1374
                   kb->pn[o][2]*kb->pn[o][2]);
 
1375
      kb->pn[o][0] *= t;
 
1376
      kb->pn[o][1] *= t;
 
1377
      kb->pn[o][2] *= t;
 
1378
    }
 
1379
  }
 
1380
 
 
1381
  if (colors == COLORS_TWOSIDED)
 
1382
  {
 
1383
    glColor3fv(mat_diff_red);
 
1384
    if (display_mode == DISP_TRANSPARENT)
 
1385
    {
 
1386
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_red);
 
1387
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_trans_green);
 
1388
    }
 
1389
    else
 
1390
    {
 
1391
      glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE,mat_diff_red);
 
1392
      glMaterialfv(GL_BACK,GL_AMBIENT_AND_DIFFUSE,mat_diff_green);
 
1393
    }
 
1394
  }
 
1395
  glBindTexture(GL_TEXTURE_2D,kb->tex_name);
 
1396
 
 
1397
  for (i=0; i<NUMV; i++)
 
1398
  {
 
1399
    if (appearance == APPEARANCE_BANDS && ((i & (NUMB-1)) >= NUMB/2))
 
1400
      continue;
 
1401
    if (display_mode == DISP_WIREFRAME)
 
1402
      glBegin(GL_QUAD_STRIP);
 
1403
    else
 
1404
      glBegin(GL_TRIANGLE_STRIP);
 
1405
    for (j=0; j<=NUMU; j++)
 
1406
    {
 
1407
      for (k=0; k<=1; k++)
 
1408
      {
 
1409
        l = (i+k);
 
1410
        m = j;
 
1411
        o = l*(NUMU+1)+m;
 
1412
        glNormal3fv(kb->pn[o]);
 
1413
        glTexCoord2fv(kb->tex[o]);
 
1414
        if (colors != COLORS_TWOSIDED)
 
1415
        {
 
1416
          glColor3fv(kb->col[o]);
 
1417
          glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE,kb->col[o]);
 
1418
        }
 
1419
        glVertex3fv(kb->pp[o]);
 
1420
        polys++;
 
1421
      }
 
1422
    }
 
1423
    glEnd();
 
1424
  }
 
1425
  polys /= 2;
 
1426
  return polys;
 
1427
}
 
1428
 
 
1429
 
 
1430
/* Generate a texture image that shows the orientation reversal. */
 
1431
static void gen_texture(ModeInfo *mi)
 
1432
{
 
1433
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1434
 
 
1435
  glGenTextures(1,&kb->tex_name);
 
1436
  glBindTexture(GL_TEXTURE_2D,kb->tex_name);
 
1437
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);
 
1438
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT);
 
1439
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT);
 
1440
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
 
1441
  glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
 
1442
  glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_MODULATE);
 
1443
  glTexImage2D(GL_TEXTURE_2D,0,GL_RGB,TEX_DIMENSION,TEX_DIMENSION,0,
 
1444
               GL_LUMINANCE,GL_UNSIGNED_BYTE,texture);
 
1445
}
 
1446
 
 
1447
 
 
1448
static void init(ModeInfo *mi)
 
1449
{
 
1450
  static const GLfloat light_ambient[]  = { 0.0, 0.0, 0.0, 1.0 };
 
1451
  static const GLfloat light_diffuse[]  = { 1.0, 1.0, 1.0, 1.0 };
 
1452
  static const GLfloat light_specular[] = { 1.0, 1.0, 1.0, 1.0 };
 
1453
  static const GLfloat light_position[] = { 1.0, 1.0, 1.0, 0.0 };
 
1454
  static const GLfloat mat_specular[]   = { 1.0, 1.0, 1.0, 1.0 };
 
1455
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1456
 
 
1457
  if (walk_speed == 0.0)
 
1458
    walk_speed = 20.0;
 
1459
 
 
1460
  if (view == VIEW_TURN)
 
1461
  {
 
1462
    kb->alpha = frand(360.0);
 
1463
    kb->beta = frand(360.0);
 
1464
    kb->delta = frand(360.0);
 
1465
  }
 
1466
  else
 
1467
  {
 
1468
    kb->alpha = 0.0;
 
1469
    kb->beta = 0.0;
 
1470
    kb->delta = 0.0;
 
1471
  }
 
1472
  kb->zeta = 0.0;
 
1473
  if (bottle_type == KLEIN_BOTTLE_FIGURE_8)
 
1474
    kb->eta = 0.0;
 
1475
  else
 
1476
    kb->eta = 45.0;
 
1477
  kb->theta = 0.0;
 
1478
  kb->umove = frand(2.0*M_PI);
 
1479
  kb->vmove = frand(2.0*M_PI);
 
1480
  kb->dumove = 0.0;
 
1481
  kb->dvmove = 0.0;
 
1482
  kb->side = 1;
 
1483
 
 
1484
  if (bottle_type == KLEIN_BOTTLE_FIGURE_8)
 
1485
  {
 
1486
    kb->offset4d[0] = 0.0;
 
1487
    kb->offset4d[1] = 0.0;
 
1488
    kb->offset4d[2] = 0.0;
 
1489
    kb->offset4d[3] = 1.5;
 
1490
    kb->offset3d[0] = 0.0;
 
1491
    kb->offset3d[1] = 0.0;
 
1492
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1493
      kb->offset3d[2] = -2.1;
 
1494
    else
 
1495
      kb->offset3d[2] = -1.9;
 
1496
    kb->offset3d[3] = 0.0;
 
1497
  }
 
1498
  else
 
1499
  {
 
1500
    kb->offset4d[0] = 0.0;
 
1501
    kb->offset4d[1] = 0.0;
 
1502
    kb->offset4d[2] = 0.0;
 
1503
    if (projection_4d == DISP_4D_PERSPECTIVE &&
 
1504
        projection_3d == DISP_3D_ORTHOGRAPHIC)
 
1505
      kb->offset4d[3] = 1.5;
 
1506
    else
 
1507
      kb->offset4d[3] = 1.1;
 
1508
    kb->offset3d[0] = 0.0;
 
1509
    kb->offset3d[1] = 0.0;
 
1510
    if (projection_4d == DISP_4D_ORTHOGRAPHIC)
 
1511
      kb->offset3d[2] = -2.0;
 
1512
    else
 
1513
      kb->offset3d[2] = -5.0;
 
1514
    kb->offset3d[3] = 0.0;
 
1515
  }
 
1516
 
 
1517
  gen_texture(mi);
 
1518
  if (bottle_type == KLEIN_BOTTLE_FIGURE_8)
 
1519
    setup_figure8(mi,0.0,2.0*M_PI,0.0,2.0*M_PI);
 
1520
  else
 
1521
    setup_lawson(mi,0.0,2.0*M_PI,0.0,2.0*M_PI);
 
1522
 
 
1523
  if (marks)
 
1524
    glEnable(GL_TEXTURE_2D);
 
1525
  else
 
1526
    glDisable(GL_TEXTURE_2D);
 
1527
 
 
1528
  glMatrixMode(GL_PROJECTION);
 
1529
  glLoadIdentity();
 
1530
  if (projection_3d == DISP_3D_PERSPECTIVE ||
 
1531
      view == VIEW_WALK || view == VIEW_WALKTURN)
 
1532
  {
 
1533
    if (view == VIEW_WALK || view == VIEW_WALKTURN)
 
1534
      gluPerspective(60.0,1.0,0.01,10.0);
 
1535
    else
 
1536
      gluPerspective(60.0,1.0,0.1,10.0);
 
1537
  }
 
1538
  else
 
1539
  {
 
1540
    glOrtho(-1.0,1.0,-1.0,1.0,0.1,10.0);
 
1541
  }
 
1542
  glMatrixMode(GL_MODELVIEW);
 
1543
  glLoadIdentity();
 
1544
 
 
1545
  if (display_mode == DISP_WIREFRAME)
 
1546
  {
 
1547
    glDisable(GL_DEPTH_TEST);
 
1548
    glShadeModel(GL_FLAT);
 
1549
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 
1550
    glDisable(GL_LIGHTING);
 
1551
    glDisable(GL_LIGHT0);
 
1552
    glDisable(GL_BLEND);
 
1553
  }
 
1554
  else if (display_mode == DISP_SURFACE)
 
1555
  {
 
1556
    glEnable(GL_DEPTH_TEST);
 
1557
    glDepthFunc(GL_LESS);
 
1558
    glShadeModel(GL_SMOOTH);
 
1559
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
 
1560
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
 
1561
    glEnable(GL_LIGHTING);
 
1562
    glEnable(GL_LIGHT0);
 
1563
    glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
 
1564
    glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
 
1565
    glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
 
1566
    glLightfv(GL_LIGHT0,GL_POSITION,light_position);
 
1567
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
 
1568
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
 
1569
    glDepthMask(GL_TRUE);
 
1570
    glDisable(GL_BLEND);
 
1571
  }
 
1572
  else if (display_mode == DISP_TRANSPARENT)
 
1573
  {
 
1574
    glDisable(GL_DEPTH_TEST);
 
1575
    glShadeModel(GL_SMOOTH);
 
1576
    glPolygonMode(GL_FRONT_AND_BACK,GL_FILL);
 
1577
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE,GL_TRUE);
 
1578
    glEnable(GL_LIGHTING);
 
1579
    glEnable(GL_LIGHT0);
 
1580
    glLightfv(GL_LIGHT0,GL_AMBIENT,light_ambient);
 
1581
    glLightfv(GL_LIGHT0,GL_DIFFUSE,light_diffuse);
 
1582
    glLightfv(GL_LIGHT0,GL_SPECULAR,light_specular);
 
1583
    glLightfv(GL_LIGHT0,GL_POSITION,light_position);
 
1584
    glMaterialfv(GL_FRONT_AND_BACK,GL_SPECULAR,mat_specular);
 
1585
    glMaterialf(GL_FRONT_AND_BACK,GL_SHININESS,50.0);
 
1586
    glDepthMask(GL_FALSE);
 
1587
    glEnable(GL_BLEND);
 
1588
    glBlendFunc(GL_SRC_ALPHA,GL_ONE);
 
1589
  }
 
1590
  else
 
1591
  {
 
1592
    glDisable(GL_DEPTH_TEST);
 
1593
    glShadeModel(GL_FLAT);
 
1594
    glPolygonMode(GL_FRONT_AND_BACK,GL_LINE);
 
1595
    glDisable(GL_LIGHTING);
 
1596
    glDisable(GL_LIGHT0);
 
1597
    glDisable(GL_BLEND);
 
1598
  }
 
1599
}
 
1600
 
 
1601
 
 
1602
/* Redisplay the Klein bottle. */
 
1603
static void display_klein(ModeInfo *mi)
 
1604
{
 
1605
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1606
 
 
1607
  if (!kb->button_pressed)
 
1608
  {
 
1609
    if (view == VIEW_TURN)
 
1610
    {
 
1611
      kb->alpha += speed_wx * kb->speed_scale;
 
1612
      if (kb->alpha >= 360.0)
 
1613
        kb->alpha -= 360.0;
 
1614
      kb->beta += speed_wy * kb->speed_scale;
 
1615
      if (kb->beta >= 360.0)
 
1616
        kb->beta -= 360.0;
 
1617
      kb->delta += speed_wz * kb->speed_scale;
 
1618
      if (kb->delta >= 360.0)
 
1619
        kb->delta -= 360.0;
 
1620
      kb->zeta += speed_xy * kb->speed_scale;
 
1621
      if (kb->zeta >= 360.0)
 
1622
        kb->zeta -= 360.0;
 
1623
      kb->eta += speed_xz * kb->speed_scale;
 
1624
      if (kb->eta >= 360.0)
 
1625
        kb->eta -= 360.0;
 
1626
      kb->theta += speed_yz * kb->speed_scale;
 
1627
      if (kb->theta >= 360.0)
 
1628
        kb->theta -= 360.0;
 
1629
    }
 
1630
    if (view == VIEW_WALKTURN)
 
1631
    {
 
1632
      kb->zeta += speed_xy * kb->speed_scale;
 
1633
      if (kb->zeta >= 360.0)
 
1634
        kb->zeta -= 360.0;
 
1635
      kb->eta += speed_xz * kb->speed_scale;
 
1636
      if (kb->eta >= 360.0)
 
1637
        kb->eta -= 360.0;
 
1638
      kb->theta += speed_yz * kb->speed_scale;
 
1639
      if (kb->theta >= 360.0)
 
1640
        kb->theta -= 360.0;
 
1641
    }
 
1642
    if (view == VIEW_WALK || view == VIEW_WALKTURN)
 
1643
    {
 
1644
      kb->dvmove = cos(walk_direction*M_PI/180.0)*walk_speed*M_PI/4096.0;
 
1645
      kb->vmove += kb->dvmove;
 
1646
      if (kb->vmove >= 2.0*M_PI)
 
1647
      {
 
1648
        kb->vmove -= 2.0*M_PI;
 
1649
        kb->umove = 2.0*M_PI-kb->umove;
 
1650
        kb->side = -kb->side;
 
1651
      }
 
1652
      kb->dumove = (kb->side*sin(walk_direction*M_PI/180.0)*
 
1653
                    walk_speed*M_PI/4096.0);
 
1654
      kb->umove += kb->dumove;
 
1655
      if (kb->umove >= 2.0*M_PI)
 
1656
        kb->umove -= 2.0*M_PI;
 
1657
      if (kb->umove < 0.0)
 
1658
        kb->umove += 2.0*M_PI;
 
1659
    }
 
1660
  }
 
1661
 
 
1662
  glMatrixMode(GL_PROJECTION);
 
1663
  glLoadIdentity();
 
1664
  if (projection_3d == DISP_3D_PERSPECTIVE ||
 
1665
      view == VIEW_WALK || view == VIEW_WALKTURN)
 
1666
  {
 
1667
    if (view == VIEW_WALK || view == VIEW_WALKTURN)
 
1668
      gluPerspective(60.0,kb->aspect,0.01,10.0);
 
1669
    else
 
1670
      gluPerspective(60.0,kb->aspect,0.1,10.0);
 
1671
  }
 
1672
  else
 
1673
  {
 
1674
    if (kb->aspect >= 1.0)
 
1675
      glOrtho(-kb->aspect,kb->aspect,-1.0,1.0,0.1,10.0);
 
1676
    else
 
1677
      glOrtho(-1.0,1.0,-1.0/kb->aspect,1.0/kb->aspect,0.1,10.0);
 
1678
  }
 
1679
  glMatrixMode(GL_MODELVIEW);
 
1680
  glLoadIdentity();
 
1681
 
 
1682
  if (bottle_type == KLEIN_BOTTLE_FIGURE_8)
 
1683
    mi->polygon_count = figure8(mi,0.0,2.0*M_PI,0.0,2.0*M_PI);
 
1684
  else
 
1685
    mi->polygon_count = lawson(mi,0.0,2.0*M_PI,0.0,2.0*M_PI);
 
1686
}
 
1687
 
 
1688
 
 
1689
ENTRYPOINT void reshape_klein(ModeInfo *mi, int width, int height)
 
1690
{
 
1691
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1692
 
 
1693
  kb->WindW = (GLint)width;
 
1694
  kb->WindH = (GLint)height;
 
1695
  glViewport(0,0,width,height);
 
1696
  kb->aspect = (GLfloat)width/(GLfloat)height;
 
1697
}
 
1698
 
 
1699
 
 
1700
ENTRYPOINT Bool klein_handle_event(ModeInfo *mi, XEvent *event)
 
1701
{
 
1702
  Display *display = MI_DISPLAY(mi);
 
1703
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
1704
  KeySym  sym;
 
1705
 
 
1706
  if (event->xany.type == ButtonPress &&
 
1707
      event->xbutton.button == Button1)
 
1708
  {
 
1709
    kb->button_pressed = True;
 
1710
    gltrackball_start(kb->trackballs[kb->current_trackball],
 
1711
                      event->xbutton.x, event->xbutton.y,
 
1712
                      MI_WIDTH(mi), MI_HEIGHT(mi));
 
1713
    return True;
 
1714
  }
 
1715
  else if (event->xany.type == ButtonRelease &&
 
1716
           event->xbutton.button == Button1)
 
1717
  {
 
1718
    kb->button_pressed = False;
 
1719
    return True;
 
1720
  }
 
1721
  else if (event->xany.type == KeyPress)
 
1722
  {
 
1723
    sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
 
1724
    if (sym == XK_Shift_L || sym == XK_Shift_R)
 
1725
    {
 
1726
      kb->current_trackball = 1;
 
1727
      if (kb->button_pressed)
 
1728
        gltrackball_start(kb->trackballs[kb->current_trackball],
 
1729
                          event->xbutton.x, event->xbutton.y,
 
1730
                          MI_WIDTH(mi), MI_HEIGHT(mi));
 
1731
      return True;
 
1732
    }
 
1733
  }
 
1734
  else if (event->xany.type == KeyRelease)
 
1735
  {
 
1736
    sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
 
1737
    if (sym == XK_Shift_L || sym == XK_Shift_R)
 
1738
    {
 
1739
      kb->current_trackball = 0;
 
1740
      if (kb->button_pressed)
 
1741
        gltrackball_start(kb->trackballs[kb->current_trackball],
 
1742
                          event->xbutton.x, event->xbutton.y,
 
1743
                          MI_WIDTH(mi), MI_HEIGHT(mi));
 
1744
      return True;
 
1745
    }
 
1746
  }
 
1747
  else if (event->xany.type == MotionNotify && kb->button_pressed)
 
1748
  {
 
1749
    gltrackball_track(kb->trackballs[kb->current_trackball],
 
1750
                      event->xmotion.x, event->xmotion.y,
 
1751
                      MI_WIDTH(mi), MI_HEIGHT(mi));
 
1752
    return True;
 
1753
  }
 
1754
 
 
1755
  return False;
 
1756
}
 
1757
 
 
1758
 
 
1759
/*
 
1760
 *-----------------------------------------------------------------------------
 
1761
 *-----------------------------------------------------------------------------
 
1762
 *    Xlock hooks.
 
1763
 *-----------------------------------------------------------------------------
 
1764
 *-----------------------------------------------------------------------------
 
1765
 */
 
1766
 
 
1767
/*
 
1768
 *-----------------------------------------------------------------------------
 
1769
 *    Initialize klein.  Called each time the window changes.
 
1770
 *-----------------------------------------------------------------------------
 
1771
 */
 
1772
 
 
1773
ENTRYPOINT void init_klein(ModeInfo *mi)
 
1774
{
 
1775
  kleinstruct *kb;
 
1776
 
 
1777
  if (klein == NULL)
 
1778
  {
 
1779
    klein = (kleinstruct *)calloc(MI_NUM_SCREENS(mi),
 
1780
                                              sizeof(kleinstruct));
 
1781
    if (klein == NULL)
 
1782
      return;
 
1783
  }
 
1784
  kb = &klein[MI_SCREEN(mi)];
 
1785
 
 
1786
  
 
1787
  kb->trackballs[0] = gltrackball_init();
 
1788
  kb->trackballs[1] = gltrackball_init();
 
1789
  kb->current_trackball = 0;
 
1790
  kb->button_pressed = False;
 
1791
 
 
1792
  /* Set the Klein bottle. */
 
1793
  if (!strcasecmp(klein_bottle,"random"))
 
1794
  {
 
1795
    bottle_type = random() % NUM_KLEIN_BOTTLES;
 
1796
  }
 
1797
  else if (!strcasecmp(klein_bottle,"figure-8"))
 
1798
  {
 
1799
    bottle_type = KLEIN_BOTTLE_FIGURE_8;
 
1800
  }
 
1801
  else if (!strcasecmp(klein_bottle,"lawson"))
 
1802
  {
 
1803
    bottle_type = KLEIN_BOTTLE_LAWSON;
 
1804
  }
 
1805
  else
 
1806
  {
 
1807
    bottle_type = random() % NUM_KLEIN_BOTTLES;
 
1808
  }
 
1809
 
 
1810
  /* Set the display mode. */
 
1811
  if (!strcasecmp(mode,"random"))
 
1812
  {
 
1813
    display_mode = random() % NUM_DISPLAY_MODES;
 
1814
  }
 
1815
  else if (!strcasecmp(mode,"wireframe"))
 
1816
  {
 
1817
    display_mode = DISP_WIREFRAME;
 
1818
  }
 
1819
  else if (!strcasecmp(mode,"surface"))
 
1820
  {
 
1821
    display_mode = DISP_SURFACE;
 
1822
  }
 
1823
  else if (!strcasecmp(mode,"transparent"))
 
1824
  {
 
1825
    display_mode = DISP_TRANSPARENT;
 
1826
  }
 
1827
  else
 
1828
  {
 
1829
    display_mode = random() % NUM_DISPLAY_MODES;
 
1830
  }
 
1831
 
 
1832
  /* Orientation marks don't make sense in wireframe mode. */
 
1833
  if (display_mode == DISP_WIREFRAME)
 
1834
    marks = False;
 
1835
 
 
1836
  /* Set the appearance. */
 
1837
  if (!strcasecmp(appear,"random"))
 
1838
  {
 
1839
    appearance = random() % NUM_APPEARANCES;
 
1840
  }
 
1841
  else if (!strcasecmp(appear,"solid"))
 
1842
  {
 
1843
    appearance = APPEARANCE_SOLID;
 
1844
  }
 
1845
  else if (!strcasecmp(appear,"bands"))
 
1846
  {
 
1847
    appearance = APPEARANCE_BANDS;
 
1848
  }
 
1849
  else
 
1850
  {
 
1851
    appearance = random() % NUM_APPEARANCES;
 
1852
  }
 
1853
 
 
1854
  /* Set the color mode. */
 
1855
  if (!strcasecmp(color_mode,"random"))
 
1856
  {
 
1857
    colors = random() % NUM_COLORS;
 
1858
  }
 
1859
  else if (!strcasecmp(color_mode,"two-sided"))
 
1860
  {
 
1861
    colors = COLORS_TWOSIDED;
 
1862
  }
 
1863
  else if (!strcasecmp(color_mode,"rainbow"))
 
1864
  {
 
1865
    colors = COLORS_RAINBOW;
 
1866
  }
 
1867
  else if (!strcasecmp(color_mode,"depth"))
 
1868
  {
 
1869
    colors = COLORS_DEPTH;
 
1870
  }
 
1871
  else
 
1872
  {
 
1873
    colors = random() % NUM_COLORS;
 
1874
  }
 
1875
 
 
1876
  /* Set the view mode. */
 
1877
  if (!strcasecmp(view_mode,"random"))
 
1878
  {
 
1879
    view = random() % NUM_VIEW_MODES;
 
1880
  }
 
1881
  else if (!strcasecmp(view_mode,"walk"))
 
1882
  {
 
1883
    view = VIEW_WALK;
 
1884
  }
 
1885
  else if (!strcasecmp(view_mode,"turn"))
 
1886
  {
 
1887
    view = VIEW_TURN;
 
1888
  }
 
1889
  else if (!strcasecmp(view_mode,"walk-turn"))
 
1890
  {
 
1891
    view = VIEW_WALKTURN;
 
1892
  }
 
1893
  else
 
1894
  {
 
1895
    view = random() % NUM_VIEW_MODES;
 
1896
  }
 
1897
 
 
1898
  /* Set the 3d projection mode. */
 
1899
  if (!strcasecmp(proj_3d,"random"))
 
1900
  {
 
1901
    /* Orthographic projection only makes sense in turn mode. */
 
1902
    if (view == VIEW_TURN)
 
1903
      projection_3d = random() % NUM_DISP_3D_MODES;
 
1904
    else
 
1905
      projection_3d = DISP_3D_PERSPECTIVE;
 
1906
  }
 
1907
  else if (!strcasecmp(proj_3d,"perspective"))
 
1908
  {
 
1909
    projection_3d = DISP_3D_PERSPECTIVE;
 
1910
  }
 
1911
  else if (!strcasecmp(proj_3d,"orthographic"))
 
1912
  {
 
1913
    projection_3d = DISP_3D_ORTHOGRAPHIC;
 
1914
  }
 
1915
  else
 
1916
  {
 
1917
    /* Orthographic projection only makes sense in turn mode. */
 
1918
    if (view == VIEW_TURN)
 
1919
      projection_3d = random() % NUM_DISP_3D_MODES;
 
1920
    else
 
1921
      projection_3d = DISP_3D_PERSPECTIVE;
 
1922
  }
 
1923
 
 
1924
  /* Set the 4d projection mode. */
 
1925
  if (!strcasecmp(proj_4d,"random"))
 
1926
  {
 
1927
    projection_4d = random() % NUM_DISP_4D_MODES;
 
1928
  }
 
1929
  else if (!strcasecmp(proj_4d,"perspective"))
 
1930
  {
 
1931
    projection_4d = DISP_4D_PERSPECTIVE;
 
1932
  }
 
1933
  else if (!strcasecmp(proj_4d,"orthographic"))
 
1934
  {
 
1935
    projection_4d = DISP_4D_ORTHOGRAPHIC;
 
1936
  }
 
1937
  else
 
1938
  {
 
1939
    projection_4d = random() % NUM_DISP_4D_MODES;
 
1940
  }
 
1941
 
 
1942
  /* Modify the speeds to a useful range in walk-and-turn mode. */
 
1943
  if (view == VIEW_WALKTURN)
 
1944
  {
 
1945
    speed_wx *= 0.2;
 
1946
    speed_wy *= 0.2;
 
1947
    speed_wz *= 0.2;
 
1948
    speed_xy *= 0.2;
 
1949
    speed_xz *= 0.2;
 
1950
    speed_yz *= 0.2;
 
1951
  }
 
1952
 
 
1953
  /* make multiple screens rotate at slightly different rates. */
 
1954
  kb->speed_scale = 0.9 + frand(0.3);
 
1955
 
 
1956
  if ((kb->glx_context = init_GL(mi)) != NULL)
 
1957
  {
 
1958
    reshape_klein(mi,MI_WIDTH(mi),MI_HEIGHT(mi));
 
1959
    glDrawBuffer(GL_BACK);
 
1960
    init(mi);
 
1961
  }
 
1962
  else
 
1963
  {
 
1964
    MI_CLEARWINDOW(mi);
 
1965
  }
 
1966
}
 
1967
 
 
1968
/*
 
1969
 *-----------------------------------------------------------------------------
 
1970
 *    Called by the mainline code periodically to update the display.
 
1971
 *-----------------------------------------------------------------------------
 
1972
 */
 
1973
ENTRYPOINT void draw_klein(ModeInfo *mi)
 
1974
{
 
1975
  Display          *display = MI_DISPLAY(mi);
 
1976
  Window           window = MI_WINDOW(mi);
 
1977
  kleinstruct *kb;
 
1978
 
 
1979
  if (klein == NULL)
 
1980
    return;
 
1981
  kb = &klein[MI_SCREEN(mi)];
 
1982
 
 
1983
  MI_IS_DRAWN(mi) = True;
 
1984
  if (!kb->glx_context)
 
1985
    return;
 
1986
 
 
1987
  glXMakeCurrent(display,window,*(kb->glx_context));
 
1988
 
 
1989
  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
 
1990
  glLoadIdentity();
 
1991
 
 
1992
  display_klein(mi);
 
1993
 
 
1994
  if (MI_IS_FPS(mi))
 
1995
    do_fps (mi);
 
1996
 
 
1997
  glFlush();
 
1998
 
 
1999
  glXSwapBuffers(display,window);
 
2000
}
 
2001
 
 
2002
 
 
2003
/*
 
2004
 *-----------------------------------------------------------------------------
 
2005
 *    The display is being taken away from us.  Free up malloc'ed 
 
2006
 *      memory and X resources that we've alloc'ed.  Only called
 
2007
 *      once, we must zap everything for every screen.
 
2008
 *-----------------------------------------------------------------------------
 
2009
 */
 
2010
 
 
2011
ENTRYPOINT void release_klein(ModeInfo *mi)
 
2012
{
 
2013
  if (klein != NULL)
 
2014
  {
 
2015
    int screen;
 
2016
 
 
2017
    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
 
2018
    {
 
2019
      kleinstruct *kb = &klein[screen];
 
2020
 
 
2021
      if (kb->glx_context)
 
2022
        kb->glx_context = (GLXContext *)NULL;
 
2023
    }
 
2024
    (void) free((void *)klein);
 
2025
    klein = (kleinstruct *)NULL;
 
2026
  }
 
2027
  FreeAllGL(mi);
 
2028
}
 
2029
 
 
2030
#ifndef STANDALONE
 
2031
ENTRYPOINT void change_klein(ModeInfo *mi)
 
2032
{
 
2033
  kleinstruct *kb = &klein[MI_SCREEN(mi)];
 
2034
 
 
2035
  if (!kb->glx_context)
 
2036
    return;
 
2037
 
 
2038
  glXMakeCurrent(MI_DISPLAY(mi),MI_WINDOW(mi),*(kb->glx_context));
 
2039
  init(mi);
 
2040
}
 
2041
#endif /* !STANDALONE */
421
2042
 
422
2043
XSCREENSAVER_MODULE ("Klein", klein)
423
2044
 
424
 
/*********************************************************/
425
 
 
426
 
#endif
 
2045
#endif /* USE_GL */