9aae80cc19197132bd1c529da10a951f2482c998
[xscreensaver] / lament.c
1 /* xscreensaver, Copyright (c) 1998 Jamie Zawinski <jwz@jwz.org>
2  *
3  * Permission to use, copy, modify, distribute, and sell this software and its
4  * documentation for any purpose is hereby granted without fee, provided that
5  * the above copyright notice appear in all copies and that both that
6  * copyright notice and this permission notice appear in supporting
7  * documentation.  No representations are made about the suitability of this
8  * software for any purpose.  It is provided "as is" without express or 
9  * implied warranty.
10  */
11
12 /* Animates Lemarchand's Box, the Lament Configuration.  By jwz, 25-Jul-98.
13
14    TODO:
15
16      *  The "gold" color isn't quite right; it looks more like "yellow" than
17         "gold" to me.
18
19      *  For some reason, the interior surfaces are shinier than the exterior
20         surfaces.  I don't understand why, but this should be remedied.
21
22      *  Perhaps use a slightly-bumpy or oily texture for the interior surfaces?
23
24      *  Some of the edges don't line up perfectly (since the images are not
25         perfectly symetrical.)  Something should be done about this; either
26         making the edges overlap slightly (instead of leaving gaps) or fixing
27         the images so that the edges may be symmetrical.
28
29      *  I want the gold leaf to seem to be raised up from the surface, but I
30         think this isn't possible with OpenGL.  Supposedly, OpenGL only 
31         supports Gouraud shading (interpolating edge normals from face normals,
32         and shading smoothly) but bump-maps only work with Phong shading
33         (computing a normal for each rendered pixel.)
34
35      *  As far as I can tell, OpenGL doesn't do shadows.  As a result, the
36         forward-facing interior walls are drawn bright, not dark.  If it was
37         casting shadows properly, it wouldn't matter so much that the edges
38         don't quite line up, because the lines would be black, and thus not
39         visible.  But the edges don't match up, and so the bright interior
40         faces show through, and that sucks.
41
42         But apparently there are tricky ways around this:
43         http://reality.sgi.com/opengl/tips/rts/
44         I think these techniques require GLUT, however, which isn't 
45         (currently) required by any other xscreensaver hacks.
46
47      *  There should be strange lighting effects playing across the surface:
48         electric sparks, or little glittery blobs of light.  
49         http://reality.sgi.com/opengl/tips/lensflare/ might provide guidance.
50
51      *  Need to add some more modes, to effect the transition from the cube
52         shapes to the "spike" or "leviathan" shapes.  I have extensive notes
53         on how these transformations occur, but unfortunately, due to camera
54         trickery, the transitions require dematerializations which do not
55         preserve object volume.  But I suppose that's allowed, in
56         non-Euclidian or hyperdimensional spaces (since the extra mass could
57         simply be rotated along the axis to which one cannot point.)
58
59         The other hard thing about this is that the "leviathan" shapes contain
60         a much larger number of facets, and I modelled this whole thing by 
61         hand, since I don't have any 3d-object-editing tools that I know how
62         to use (or that look like they would take any less than several months
63         to become even marginally proficient with...)
64
65      *  Perhaps there should be a table top, on which it casts a shadow?
66         And then multiple light sources (for multiple shadows)?
67
68      *  Needs music.  ("Hellraiser Themes" by Coil: TORSO CD161; also
69         duplicated on the "Unnatural History 2" compilation, WORLN M04699.)
70
71      *  I'm not totally happy with the spinning motion; I like the
72         acceleration and deceleration, but it often feels like it's going too
73         fast, or not naturally enough, or something.
74
75      *  However, the motion is better than that used by gears, superquadrics,
76         etc.; so maybe I should make them all share the same motion code.
77  */
78
79 #include <X11/Intrinsic.h>
80
81 #define PROGCLASS       "Lament"
82 #define HACK_INIT       init_lament
83 #define HACK_DRAW       draw_lament
84 #define lament_opts     xlockmore_opts
85 #define DEFAULTS        "*delay:        10000   \n"     \
86                         "*wireframe:    False   \n"     \
87                         "*texture:      True    \n"
88 #include "xlockmore.h"
89
90 #ifdef USE_GL /* whole file */
91
92 #undef countof
93 #define countof(x) (sizeof((x))/sizeof((*x)))
94
95 #define DEF_TEXTURE "True"
96
97 static int do_texture;
98 static XrmOptionDescRec opts[] = {
99   {"-texture", ".lament.texture", XrmoptionNoArg, (caddr_t) "true" },
100   {"+texture", ".lament.texture", XrmoptionNoArg, (caddr_t) "false" },
101 };
102
103 static argtype vars[] = {
104   {(caddr_t *) &do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
105 };
106
107 ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars, NULL};
108
109 #include "xpm-ximage.h"
110 #include "../images/lament.xpm"
111
112 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
113 #define RANDSIGN() ((random() & 1) ? 1 : -1)
114
115 typedef enum {
116   LAMENT_BOX,
117
118   LAMENT_STAR_OUT,
119   LAMENT_STAR_ROT,
120   LAMENT_STAR_ROT_IN,
121   LAMENT_STAR_ROT_OUT,
122   LAMENT_STAR_UNROT,
123   LAMENT_STAR_IN,
124
125   LAMENT_TETRA_UNE,
126   LAMENT_TETRA_USW,
127   LAMENT_TETRA_DWN,
128   LAMENT_TETRA_DSE,
129
130   LAMENT_LID_OPEN,
131   LAMENT_LID_CLOSE,
132   LAMENT_LID_ZOOM,
133
134   LAMENT_TASER_OUT,
135   LAMENT_TASER_SLIDE,
136   LAMENT_TASER_SLIDE_IN,
137   LAMENT_TASER_IN
138
139 } lament_type;
140
141 static GLfloat exterior_color[] = { 0.70, 0.60, 0.00, 1.00 };
142 static GLfloat interior_color[] = { 0.25, 0.25, 0.20, 1.00 };
143
144
145 typedef struct {
146   GLXContext *glx_context;
147
148   GLuint box;                      /* display list IDs */
149   GLuint star1, star2;
150   GLuint tetra_une, tetra_usw, tetra_dwn, tetra_dse, tetra_mid;
151   GLuint lid_0, lid_1, lid_2, lid_3, lid_4;
152   GLuint taser_base, taser_lifter, taser_slider;
153
154   GLfloat rotx, roty, rotz;        /* current object rotation */
155   GLfloat dx, dy, dz;              /* current rotational velocity */
156   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
157   GLfloat d_max;                   /* max velocity */
158   XImage *texture;                 /* image bits */
159   GLuint texids[6];                /* texture map IDs */
160   lament_type type;                /* which mode of the object is current */
161
162   int anim_pause;                  /* countdown before animating again */
163   GLfloat anim_r, anim_y, anim_z;  /* relative position during anims */
164
165 } lament_configuration;
166
167 static lament_configuration *lcs = NULL;
168
169 #define FACE_N 3
170 #define FACE_S 2
171 #define FACE_E 0
172 #define FACE_W 4
173 #define FACE_U 5
174 #define FACE_D 1
175
176 static void
177 parse_image_data(ModeInfo *mi)
178 {
179   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
180   lc->texture = xpm_to_ximage (mi->dpy,
181                                mi->xgwa.visual,
182                                mi->xgwa.colormap,
183                                lament_faces);
184 }
185
186
187 \f
188 /* Computing normal vectors (thanks to Nat Friedman <ndf@mit.edu>)
189  */
190
191 typedef struct vector {
192   GLfloat x, y, z;
193 } vector;
194
195 typedef struct plane {
196   vector p1, p2, p3;
197 } plane;
198
199 static void
200 vector_set(vector *v, GLfloat x, GLfloat y, GLfloat z)
201 {
202   v->x = x;
203   v->y = y;
204   v->z = z;
205 }
206
207 static void
208 vector_cross(vector v1, vector v2, vector *v3)
209 {
210   v3->x = (v1.y * v2.z) - (v1.z * v2.y);
211   v3->y = (v1.z * v2.x) - (v1.x * v2.z);
212   v3->z = (v1.x * v2.y) - (v1.y * v2.x);
213 }
214
215 static void
216 vector_subtract(vector v1, vector v2, vector *res)
217 {
218   res->x = v1.x - v2.x;
219   res->y = v1.y - v2.y;
220   res->z = v1.z - v2.z;
221 }
222
223 static void
224 plane_normal(plane p, vector *n)
225 {
226   vector v1, v2;
227   vector_subtract(p.p1, p.p2, &v1);
228   vector_subtract(p.p1, p.p3, &v2);
229   vector_cross(v2, v1, n);
230 }
231
232 static void
233 do_normal(GLfloat x1, GLfloat y1, GLfloat z1,
234           GLfloat x2, GLfloat y2, GLfloat z2,
235           GLfloat x3, GLfloat y3, GLfloat z3)
236 {
237   plane plane;
238   vector n;
239   vector_set(&plane.p1, x1, y1, z1);
240   vector_set(&plane.p2, x2, y2, z2);
241   vector_set(&plane.p3, x3, y3, z3);
242   plane_normal(plane, &n);
243   n.x = -n.x; n.y = -n.y; n.z = -n.z;
244
245   glNormal3f(n.x, n.y, n.z);
246
247 #ifdef DEBUG
248   /* Draw a line in the direction of this face's normal. */
249   {
250     GLfloat ax = n.x > 0 ? n.x : -n.x;
251     GLfloat ay = n.y > 0 ? n.y : -n.y;
252     GLfloat az = n.z > 0 ? n.z : -n.z;
253     GLfloat mx = (x1 + x2 + x3) / 3;
254     GLfloat my = (y1 + y2 + y3) / 3;
255     GLfloat mz = (z1 + z2 + z3) / 3;
256     GLfloat xx, yy, zz;
257
258     GLfloat max = ax > ay ? ax : ay;
259     if (az > max) max = az;
260     max *= 2;
261     xx = n.x / max;
262     yy = n.y / max;
263     zz = n.z / max;
264
265     glBegin(GL_LINE_LOOP);
266     glVertex3f(mx, my, mz);
267     glVertex3f(mx+xx, my+yy, mz+zz);
268     glEnd();
269   }
270 #endif /* DEBUG */
271 }
272
273
274 \f
275 /* Shorthand utilities for making faces, with proper normals.
276  */
277
278 static void
279 face3(GLint texture, GLfloat *color, Bool wire,
280       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
281       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
282       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3)
283 {
284 #ifdef HAVE_GLBINDTEXTURE
285   glBindTexture(GL_TEXTURE_2D, texture);
286 #endif /* HAVE_GLBINDTEXTURE */
287   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
288   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
289   glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
290   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
291   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
292   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
293   glEnd();
294 }
295
296 static void
297 face4(GLint texture, GLfloat *color, Bool wire,
298       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
299       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
300       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
301       GLfloat s4, GLfloat t4, GLfloat x4, GLfloat y4, GLfloat z4)
302 {
303 #ifdef HAVE_GLBINDTEXTURE
304   glBindTexture(GL_TEXTURE_2D, texture);
305 #endif /* HAVE_GLBINDTEXTURE */
306   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
307   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
308   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
309   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
310   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
311   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
312   glTexCoord2f(s4, t4); glVertex3f(x4, y4, z4);
313   glEnd();
314 }
315
316 static void
317 face5(GLint texture, GLfloat *color, Bool wire,
318       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
319       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
320       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
321       GLfloat s4, GLfloat t4, GLfloat x4, GLfloat y4, GLfloat z4,
322       GLfloat s5, GLfloat t5, GLfloat x5, GLfloat y5, GLfloat z5)
323 {
324 #ifdef HAVE_GLBINDTEXTURE
325   glBindTexture(GL_TEXTURE_2D, texture);
326 #endif /* HAVE_GLBINDTEXTURE */
327   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
328   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
329   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
330   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
331   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
332   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
333   glTexCoord2f(s4, t4); glVertex3f(x4, y4, z4);
334   glTexCoord2f(s5, t5); glVertex3f(x5, y5, z5);
335   glEnd();
336 }
337
338
339 \f
340 /* Creating object models
341  */
342
343 static void
344 box(ModeInfo *mi, Bool wire)
345 {
346   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
347
348   glNewList(lc->box, GL_COMPILE);
349   glShadeModel(GL_SMOOTH);
350
351   /* N */
352   face4(lc->texids[FACE_N], exterior_color, wire,
353         0.0, 0.0,       -0.5,  0.5,  0.5,
354         1.0, 0.0,        0.5,  0.5,  0.5,
355         1.0, 1.0,        0.5,  0.5, -0.5,
356         0.0, 1.0,       -0.5,  0.5, -0.5);
357
358   /* S */
359   face4(lc->texids[FACE_S], exterior_color, wire,
360         0.0, 0.0,        -0.5, -0.5, -0.5,
361         1.0, 0.0,         0.5, -0.5, -0.5,
362         1.0, 1.0,         0.5, -0.5,  0.5,
363         0.0, 1.0,        -0.5, -0.5,  0.5);
364
365   /* E */
366   face4(lc->texids[FACE_E], exterior_color, wire,
367         0.0, 0.0,        0.5, -0.5, -0.5,
368         1.0, 0.0,        0.5,  0.5, -0.5,
369         1.0, 1.0,        0.5,  0.5,  0.5,
370         0.0, 1.0,        0.5, -0.5,  0.5);
371
372   /* W */
373   face4(lc->texids[FACE_W], exterior_color, wire,
374         1.0, 1.0,       -0.5, -0.5,  0.5,
375         0.0, 1.0,       -0.5,  0.5,  0.5,
376         0.0, 0.0,       -0.5,  0.5, -0.5,
377         1.0, 0.0,       -0.5, -0.5, -0.5);
378
379   /* U */
380   face4(lc->texids[FACE_U], exterior_color, wire,
381         1.0, 0.0,        0.5, -0.5,  0.5,
382         1.0, 1.0,        0.5,  0.5,  0.5,
383         0.0, 1.0,       -0.5,  0.5,  0.5,
384         0.0, 0.0,       -0.5, -0.5,  0.5);
385
386   /* D */
387   face4(lc->texids[FACE_D], exterior_color, wire,
388         0.0, 1.0,       -0.5, -0.5, -0.5,
389         0.0, 0.0,       -0.5,  0.5, -0.5,
390         1.0, 0.0,        0.5,  0.5, -0.5,
391         1.0, 1.0,        0.5, -0.5, -0.5);
392
393   glEndList();
394 }
395
396
397 static void
398 star(ModeInfo *mi, Bool top, Bool wire)
399 {
400   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
401   int i;
402
403   int points[][2] = {
404     {  77,  74 }, {  60,  98 }, {   0,  71 }, {   0,   0 },    /* L1 */
405     {  60,  98 }, {  55, 127 }, {   0, 127 }, {   0,  71 },    /* L2 */
406     {  55, 127 }, {  60, 154 }, {   0, 179 }, {   0, 127 },    /* L3 */
407     {  60, 154 }, {  76, 176 }, {   0, 255 }, {   0, 179 },    /* L4 */
408     {  76, 176 }, { 100, 193 }, {  74, 255 }, {   0, 255 },    /* B1 */
409     { 100, 193 }, { 127, 198 }, { 127, 255 }, {  74, 255 },    /* B2 */
410     { 127, 198 }, { 151, 193 }, { 180, 255 }, { 127, 255 },    /* B3 */
411     { 151, 193 }, { 178, 177 }, { 255, 255 }, { 180, 255 },    /* B4 */
412     { 178, 177 }, { 193, 155 }, { 255, 181 }, { 255, 255 },    /* R4 */
413     { 193, 155 }, { 199, 127 }, { 255, 127 }, { 255, 181 },    /* R3 */
414     { 199, 127 }, { 194,  99 }, { 255,  74 }, { 255, 127 },    /* R2 */
415     { 194,  99 }, { 179,  76 }, { 255,   0 }, { 255,  74 },    /* R1 */
416     { 179,  76 }, { 155,  60 }, { 180,   0 }, { 255,   0 },    /* T4 */
417     { 155,  60 }, { 126,  55 }, { 126,   0 }, { 180,   0 },    /* T3 */
418     { 126,  55 }, { 100,  60 }, {  75,   0 }, { 126,   0 },    /* T2 */
419     { 100,  60 }, {  77,  74 }, {   0,   0 }, {  75,   0 },    /* T1 */
420   };
421
422   for (i = 0; i < countof(points); i++)
423     points[i][1] = 255-points[i][1];
424
425   if (top)
426     glNewList(lc->star1, GL_COMPILE);
427   else
428     glNewList(lc->star2, GL_COMPILE);
429
430   if (!top)
431     glRotatef(-180.0, 1.0, 0.0, 0.0);
432
433   for (i = 0; i < countof(points)/4; i += 2)
434     {
435       int j, k;
436
437       /* Top face.
438        */
439
440       GLfloat s[4], t[4], x[4], y[4], z[4];
441       for (j = 3, k = 0; j >= 0; j--, k++)
442         {
443           GLfloat xx = points[(i*4)+j][0] / 255.0L;
444           GLfloat yy = points[(i*4)+j][1] / 255.0L;
445           s[k] = xx;
446           t[k] = yy;
447           x[k] = xx-0.5;
448           y[k] = yy-0.5;
449           z[k] = 0.5;
450         }
451       face4(lc->texids[top ? FACE_U : FACE_D], exterior_color, wire,
452             s[0], t[0],  x[0], y[0], z[0],
453             s[1], t[1],  x[1], y[1], z[1],
454             s[2], t[2],  x[2], y[2], z[2],
455             s[3], t[3],  x[3], y[3], z[3]);
456
457       /* Bottom face.
458        */
459       for (j = 0, k = 0; j < 4; j++, k++)
460         {
461           GLfloat xx = points[(i*4)+j][0] / 255.0L;
462           GLfloat yy = points[(i*4)+j][1] / 255.0L;
463           s[k] = xx;
464           t[k] = 1.0 - yy;
465           x[k] = xx-0.5;
466           y[k] = yy-0.5;
467           z[k] = -0.5;
468         }
469       face4(lc->texids[top ? FACE_U : FACE_D], exterior_color, wire,
470             s[0], t[0],  x[0], y[0], z[0],
471             s[1], t[1],  x[1], y[1], z[1],
472             s[2], t[2],  x[2], y[2], z[2],
473             s[3], t[3],  x[3], y[3], z[3]);
474
475       /* Connecting faces.
476        */
477       for (j = 3; j >= 0; j--)
478         {
479           int k = (j == 0 ? 3 : j-1);
480           Bool front_p = (j == 3);
481           GLfloat x1 = points[(i*4)+j][0] / 255.0L;
482           GLfloat y1 = points[(i*4)+j][1] / 255.0L;
483           GLfloat x2 = points[(i*4)+k][0] / 255.0L;
484           GLfloat y2 = points[(i*4)+k][1] / 255.0L;
485
486           GLfloat tx1=0.0, tx2=1.0, ty1=0.0, ty2=1.0;
487
488           int texture = 0;
489           int facing = i/4;
490           facing = (facing + j + 5) % 4;
491
492           switch (facing) {
493           case 0:
494             texture = FACE_W;
495             if (top) {
496               tx1 = 1.0 - y1;  tx2 = 1.0 - y2;
497               ty1 = 0.0;       ty2 = 1.0;
498             } else {
499               tx1 = y1;  tx2 = y2;
500               ty1 = 1.0; ty2 = 0.0;
501             }
502             break;
503           case 1:
504             texture = top ? FACE_S : FACE_N;
505             tx1 = x1;  tx2 = x2;
506             ty1 = 0.0; ty2 = 1.0;
507             break;
508           case 2:
509             texture = FACE_E;
510             if (top) {
511               tx1 = y1;  tx2 = y2;
512               ty1 = 0.0; ty2 = 1.0;
513             } else {
514               tx1 = 1.0 - y1;  tx2 = 1.0 - y2;
515               ty1 = 1.0;       ty2 = 0.0;
516             }
517             break;
518           case 3:
519             texture = top ? FACE_N : FACE_S;
520             tx1 = x1;  tx2 = x2;
521             ty1 = 1.0; ty2 = 0.0;
522             break;
523           }
524
525           x1 -= 0.5; x2 -= 0.5;
526           y1 -= 0.5; y2 -= 0.5;
527
528           face4(front_p ? lc->texids[texture] : 0,
529                 front_p ? exterior_color : interior_color,
530                 wire,
531                 tx1, ty2,  x1, y1,  0.5,
532                 tx1, ty1,  x1, y1, -0.5,
533                 tx2, ty1,  x2, y2, -0.5,
534                 tx2, ty2,  x2, y2,  0.5);
535         }
536     }
537
538
539   /* Central core top cap.
540    */
541 #ifdef HAVE_GLBINDTEXTURE
542   glBindTexture(GL_TEXTURE_2D, lc->texids[top ? FACE_U : FACE_D]);
543 #endif /* HAVE_GLBINDTEXTURE */
544   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
545
546   i = 1;
547   do_normal(points[i+0][0], points[i+0][1], 0,
548             points[i+4][0], points[i+4][1], 0,
549             points[i+8][0], points[i+8][1], 0);
550   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
551   for (i = 1; i < countof(points); i += 4)
552     {
553       GLfloat x = points[i][0] / 255.0L;
554       GLfloat y = points[i][1] / 255.0L;
555       glTexCoord2f(x, y);
556       glVertex3f(x-0.5, y-0.5, 0.5);
557     }
558   glEnd();
559
560
561   /* Central core bottom cap.
562    */
563 #ifdef HAVE_GLBINDTEXTURE
564   glBindTexture(GL_TEXTURE_2D, 0);
565 #endif /* HAVE_GLBINDTEXTURE */
566   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, interior_color);
567
568   i = countof(points) - 9;
569   do_normal(points[i+0][0], points[i+0][1], 0,
570             points[i+4][0], points[i+4][1], 0,
571             points[i+8][0], points[i+8][1], 0);
572
573   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
574   for (i = countof(points) - 3; i >= 0; i -= 4)
575     {
576       GLfloat x = points[i][0] / 255.0L;
577       GLfloat y = points[i][1] / 255.0L;
578       glVertex3f(x-0.5, y-0.5, 0);
579     }
580   glEnd();
581   
582
583   /* Central core walls.
584    */
585   for (i = 1; i < countof(points); i += 4)
586     {
587
588       GLfloat x1 = points[i-1][0] / 255.0L;
589       GLfloat y1 = points[i-1][1] / 255.0L;
590       GLfloat x2 = points[i][0] / 255.0L;
591       GLfloat y2 = points[i][1] / 255.0L;
592       face4(0, interior_color, wire,
593             0.0, 0.0,  x1-0.5, y1-0.5, 0.5,
594             0.0, 0.0,  x1-0.5, y1-0.5, 0.0,
595             0.0, 0.0,  x2-0.5, y2-0.5, 0.0,
596             0.0, 0.0,  x2-0.5, y2-0.5, 0.5);
597     }
598
599   glEndList();
600 }
601
602
603 static void
604 tetra(ModeInfo *mi, Bool wire)
605 {
606   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
607
608   glNewList(lc->tetra_une, GL_COMPILE);
609   {
610     glShadeModel(GL_SMOOTH);
611
612     /* Ua */
613     face3(lc->texids[FACE_U], exterior_color, wire,
614           1.0, 0.0,      0.5, -0.5,  0.5,
615           1.0, 1.0,      0.5,  0.5,  0.5,
616           0.0, 1.0,     -0.5,  0.5,  0.5);
617
618     /* Na */
619     face3(lc->texids[FACE_N], exterior_color, wire,
620           0.0, 0.0,     -0.5,  0.5,  0.5,
621           1.0, 0.0,      0.5,  0.5,  0.5,
622           1.0, 1.0,      0.5,  0.5, -0.5);
623
624     /* Eb */
625     face3(lc->texids[FACE_E], exterior_color, wire,
626           1.0, 0.0,      0.5,  0.5, -0.5,
627           1.0, 1.0,      0.5,  0.5,  0.5,
628           0.0, 1.0,      0.5, -0.5,  0.5);
629
630     face3(0, interior_color, wire,
631           0.0, 0.0,      0.5,  0.5, -0.5,
632           0.0, 0.0,      0.5, -0.5,  0.5,
633           0.0, 0.0,     -0.5,  0.5,  0.5);
634   }
635   glEndList();
636
637   glNewList(lc->tetra_usw, GL_COMPILE);
638   {
639     /* Ub */
640     face3(lc->texids[FACE_U], exterior_color, wire,
641           0.0, 1.0,     -0.5,  0.5,  0.5,
642           0.0, 0.0,     -0.5, -0.5,  0.5,
643           1.0, 0.0,      0.5, -0.5,  0.5);
644
645     /* Sb */
646     face3(lc->texids[FACE_S], exterior_color, wire,
647           1.0, 1.0,      0.5, -0.5,  0.5,
648           0.0, 1.0,     -0.5, -0.5,  0.5,
649           0.0, 0.0,     -0.5, -0.5, -0.5);
650
651     /* Wb */
652     face3(lc->texids[FACE_W], exterior_color, wire,
653           1.0, 0.0,     -0.5, -0.5, -0.5,
654           1.0, 1.0,     -0.5, -0.5,  0.5,
655           0.0, 1.0,     -0.5,  0.5,  0.5);
656
657     face3(0, interior_color, wire,
658           0.0,0.0,      -0.5, -0.5, -0.5,
659           0.0,0.0,      -0.5,  0.5,  0.5,
660           0.0,0.0,       0.5, -0.5,  0.5);
661   }
662   glEndList();
663
664   glNewList(lc->tetra_dwn, GL_COMPILE);
665   {
666     /* Db */
667     face3(lc->texids[FACE_D], exterior_color, wire,
668           0.0, 1.0,     -0.5, -0.5, -0.5,
669           0.0, 0.0,     -0.5,  0.5, -0.5,
670           1.0, 0.0,      0.5,  0.5, -0.5);
671
672     /* Wa */
673     face3(lc->texids[FACE_W], exterior_color, wire,
674           0.0, 1.0,     -0.5,  0.5,  0.5,
675           0.0, 0.0,     -0.5,  0.5, -0.5,
676           1.0, 0.0,     -0.5, -0.5, -0.5);
677
678     /* Nb */
679     face3(lc->texids[FACE_N], exterior_color, wire,
680           1.0, 1.0,      0.5,  0.5, -0.5,
681           0.0, 1.0,     -0.5,  0.5, -0.5,
682           0.0, 0.0,     -0.5,  0.5,  0.5);
683
684     face3(0, interior_color, wire,
685           0.0, 0.0,      0.5,  0.5, -0.5,
686           0.0, 0.0,     -0.5,  0.5,  0.5,
687           0.0, 0.0,     -0.5, -0.5, -0.5);
688   }
689   glEndList();
690
691   glNewList(lc->tetra_dse, GL_COMPILE);
692   {
693     /* Sa */
694     face3(lc->texids[FACE_S], exterior_color, wire,
695           0.0, 0.0,     -0.5, -0.5, -0.5,
696           1.0, 0.0,      0.5, -0.5, -0.5,
697           1.0, 1.0,      0.5, -0.5,  0.5);
698
699     /* Ea */
700     face3(lc->texids[FACE_E], exterior_color, wire,
701           0.0, 1.0,      0.5, -0.5,  0.5,
702           0.0, 0.0,      0.5, -0.5, -0.5,
703           1.0, 0.0,      0.5,  0.5, -0.5);
704
705     /* Da */
706     face3(lc->texids[FACE_D], exterior_color, wire,
707           1.0, 0.0,      0.5,  0.5, -0.5,
708           1.0, 1.0,      0.5, -0.5, -0.5,
709           0.0, 1.0,     -0.5, -0.5, -0.5);
710
711     face3(0, interior_color, wire,
712           0.0, 0.0,      0.5, -0.5,  0.5,
713           0.0, 0.0,      0.5,  0.5, -0.5,
714           0.0, 0.0,     -0.5, -0.5, -0.5);
715   }
716   glEndList();
717
718   glNewList(lc->tetra_mid, GL_COMPILE);
719   {
720     face3(0, interior_color, wire,
721           0.0, 0.0,      0.5, -0.5,  0.5,
722           0.0, 0.0,      0.5,  0.5, -0.5,
723           0.0, 0.0,     -0.5,  0.5,  0.5);
724
725     face3(0, interior_color, wire,
726           0.0, 0.0,     -0.5,  0.5,  0.5,
727           0.0, 0.0,     -0.5, -0.5, -0.5,
728           0.0, 0.0,      0.5, -0.5,  0.5);
729
730     face3(0, interior_color, wire,
731           0.0, 0.0,     -0.5,  0.5,  0.5,
732           0.0, 0.0,      0.5,  0.5, -0.5,
733           0.0, 0.0,     -0.5, -0.5, -0.5);
734
735     face3(0, interior_color, wire,
736           0.0, 0.0,      0.5,  0.5, -0.5,
737           0.0, 0.0,      0.5, -0.5,  0.5,
738           0.0, 0.0,     -0.5, -0.5, -0.5);
739
740     face3(0, interior_color, wire,
741           0.0, 0.0,      0.5, -0.5,  0.5,
742           0.0, 0.0,      0.5,  0.5, -0.5,
743           0.0, 0.0,     -0.5, -0.5, -0.5);
744   }
745   glEndList();
746
747 }
748
749 static void
750 lid(ModeInfo *mi, Bool wire)
751 {
752   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
753   int i;
754
755   int points[][2] = {
756     { 128,  20 },{  21, 129 },{   0, 129 },{   0,   0 },{ 128,   0 }, /* L1 */
757     {  21, 129 },{ 127, 234 },{ 127, 255 },{   0, 255 },{   0, 129 }, /* L2 */
758     { 127, 234 },{ 233, 127 },{ 255, 127 },{ 255, 255 },{ 127, 255 }, /* R2 */
759     { 233, 127 },{ 128,  20 },{ 128,   0 },{ 255,   0 },{ 255, 127 }, /* R1 */
760   };
761
762   for (i = 0; i < countof(points); i++)
763     points[i][1] = 255-points[i][1];
764
765   glNewList(lc->lid_0, GL_COMPILE);
766   glShadeModel(GL_SMOOTH);
767
768   /* N */
769   face4(lc->texids[FACE_N], exterior_color, wire,
770         0.0, 0.0,       -0.5,  0.5,  0.5,
771         1.0, 0.0,        0.5,  0.5,  0.5,
772         1.0, 1.0,        0.5,  0.5, -0.5,
773         0.0, 1.0,       -0.5,  0.5, -0.5);
774
775   /* S */
776   face4(lc->texids[FACE_S], exterior_color, wire,
777         0.0, 0.0,       -0.5, -0.5, -0.5,
778         1.0, 0.0,        0.5, -0.5, -0.5,
779         1.0, 1.0,        0.5, -0.5,  0.5,
780         0.0, 1.0,       -0.5, -0.5,  0.5);
781
782   /* E */
783   face4(lc->texids[FACE_E], exterior_color, wire,
784         0.0, 0.0,        0.5, -0.5, -0.5,
785         1.0, 0.0,        0.5,  0.5, -0.5,
786         1.0, 1.0,        0.5,  0.5,  0.5,
787         0.0, 1.0,        0.5, -0.5,  0.5);
788
789   /* U */
790   face4(lc->texids[FACE_U], exterior_color, wire,
791         1.0, 0.0,        0.5, -0.5,  0.5,
792         1.0, 1.0,        0.5,  0.5,  0.5,
793         0.0, 1.0,       -0.5,  0.5,  0.5,
794         0.0, 0.0,       -0.5, -0.5,  0.5);
795
796   /* D */
797   face4(lc->texids[FACE_D], exterior_color, wire,
798         0.0, 1.0,       -0.5, -0.5, -0.5,
799         0.0, 0.0,       -0.5,  0.5, -0.5,
800         1.0, 0.0,        0.5,  0.5, -0.5,
801         1.0, 1.0,        0.5, -0.5, -0.5);
802
803   /* W -- lid_0 */
804   for (i = 0; i < countof(points)/5; i++)
805     {
806       int j;
807       GLfloat s[5], t[5], x[5], y[5], z[5];
808       for (j = 0; j < 5; j++)
809         {
810           GLfloat xx = points[(i*5)+j][0] / 255.0L;
811           GLfloat yy = points[(i*5)+j][1] / 255.0L;
812           s[j] = 1.0-xx;
813           t[j] = yy;
814           x[j] = -0.5;
815           y[j] = xx-0.5;
816           z[j] = yy-0.5;
817         }
818       face5(lc->texids[FACE_W], exterior_color, wire,
819             s[0], t[0],  x[0], y[0], z[0],
820             s[1], t[1],  x[1], y[1], z[1],
821             s[2], t[2],  x[2], y[2], z[2],
822             s[3], t[3],  x[3], y[3], z[3],
823             s[4], t[4],  x[4], y[4], z[4]);
824     }
825   glEndList();
826
827
828   /* W -- lid_1 through lid_4 */
829   for (i = 0; i < 4; i++)
830     {
831       GLfloat x1, y1, x2, y2, x3, y3;
832
833       glNewList(lc->lid_1 + i, GL_COMPILE);
834       glShadeModel(GL_SMOOTH);
835
836       x1 = points[(i*5)+1][0] / 255.0L;
837       y1 = points[(i*5)+1][1] / 255.0L;
838       x2 = points[(i*5)][0] / 255.0L;
839       y2 = points[(i*5)][1] / 255.0L;
840       x3 = 0.5;
841       y3 = 0.5;
842
843       /* Outer surface */
844       face3(lc->texids[FACE_W], exterior_color, wire,
845             1.0-x1, y1,         -0.5, x1-0.5, y1-0.5,
846             1.0-x2, y2,         -0.5, x2-0.5, y2-0.5,
847             1.0-x3, y3,         -0.5, x3-0.5, y3-0.5);
848
849       /* Inner surface */
850       face3(0, interior_color, wire,
851             0.0, 0.0,   -0.48, x2-0.5, y2-0.5,
852             0.0, 0.0,   -0.48, x1-0.5, y1-0.5,
853             0.0, 0.0,   -0.48, x3-0.5, y3-0.5);
854
855       /* Lip 1 */
856       face4(0, interior_color, wire,
857             0.0, 0.0,   -0.5,  x1-0.5, y1-0.5,
858             0.0, 0.0,   -0.5,  x3-0.5, y3-0.5,
859             0.0, 0.0,   -0.48, x3-0.5, y3-0.5,
860             0.0, 0.0,   -0.48, x1-0.5, y1-0.5);
861
862       /* Lip 2 */
863       face4(0, interior_color, wire,
864             0.0, 0.0,   -0.48, x2-0.5, y2-0.5,
865             0.0, 0.0,   -0.48, x3-0.5, y3-0.5,
866             0.0, 0.0,   -0.5,  x3-0.5, y3-0.5,
867             0.0, 0.0,   -0.5,  x2-0.5, y2-0.5);
868
869       glEndList();
870     }
871 }
872
873 static void
874 taser(ModeInfo *mi, Bool wire)
875 {
876   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
877   int i;
878
879   int slider_face_points[][2] = {
880     {  86,  58 },{  38, 106 },{  70, 106 },{ 118,  58 },{  -1,  -1 }, /* a */
881     { 136,  58 },{ 184, 106 },{ 216, 106 },{ 168,  58 },{  -1,  -1 }, /* b */
882     {  38, 106 },{   0, 144 },{   0, 190 },{  60, 190 },{ 108, 106 }, /* c */
883     { 144, 106 },{ 194, 190 },{ 254, 190 },{ 254, 144 },{ 216, 106 }, /* d */
884     {  98, 124 },{  60, 190 },{  92, 190 },{ 126, 158 },{ 126, 124 }, /* e */
885     { 126, 124 },{ 126, 158 },{ 160, 190 },{ 194, 190 },{ 154, 124 }, /* f */
886     {  22, 190 },{  22, 254 },{  60, 254 },{  60, 190 },{  -1,  -1 }, /* g */
887     { 194, 190 },{ 194, 254 },{ 230, 254 },{ 230, 190 },{  -1,  -1 }, /* h */
888     {  60, 190 },{  60, 210 },{  92, 210 },{  92, 190 },{  -1,  -1 }, /* i */
889     { 160, 190 },{ 160, 210 },{ 194, 210 },{ 194, 190 },{  -1,  -1 }, /* j */
890     { 110, 172 },{  92, 190 },{ 110, 190 },{  -1,  -1 },{  -1,  -1 }, /* k */
891     { 140, 172 },{ 140, 190 },{ 160, 190 },{  -1,  -1 },{  -1,  -1 }, /* l */
892     { 110, 172 },{ 140, 172 },{ 126, 156 },{  -1,  -1 },{  -1,  -1 }, /* m */
893   };
894
895   int body_face_points[][2] = {
896     {   0,   0 },{   0,  58 },{ 254,  58 },{ 254,   0 },{  -1,  -1 }, /* A */
897     {   0,  58 },{   0, 144 },{  86,  58 },{  -1,  -1 },{  -1,  -1 }, /* B */
898     { 168,  58 },{ 254, 144 },{ 254,  58 },{  -1,  -1 },{  -1,  -1 }, /* C */
899     { 118,  58 },{  70, 106 },{ 184, 106 },{ 136,  58 },{  -1,  -1 }, /* F */
900     { 108, 106 },{  98, 124 },{ 154, 124 },{ 144, 106 },{  -1,  -1 }, /* G */
901   };
902
903   int lifter_face_points[][2] = {
904     {   0, 190 },{   0, 254 },{  22, 254 },{  22, 190 },{  -1,  -1 }, /* D */
905     { 230, 190 },{ 230, 254 },{ 254, 254 },{ 254, 190 },{  -1,  -1 }, /* E */
906     {  60, 210 },{  60, 254 },{ 194, 254 },{ 194, 210 },{  -1,  -1 }, /* H */
907     {  92, 190 },{  92, 210 },{ 160, 210 },{ 160, 190 },{  -1,  -1 }, /* I */
908     { 110, 172 },{ 110, 190 },{ 140, 190 },{ 140, 172 },{  -1,  -1 }, /* J */
909   };
910
911   int body_perimiter_points[][2] = {
912     {   0, 144 },{  86,  59 },{ 119,  58 },{  71, 107 },
913     { 108, 107 },{  98, 124 },{ 155, 124 },{ 144, 107 },
914     { 185, 106 },{ 136,  59 },{ 169,  59 },{ 255, 145 },
915     { 255,   0 },{   0,   0 },
916   };
917
918   int slider_perimiter_points[][2] = {
919     {  86,  58 },{   0,  144 },{   0, 190 },{  22,  190 },{  22, 254 },
920     {  60, 254 },{  60,  210 },{  92, 210 },{  92,  190 },{ 110, 190 },
921     { 110, 172 },{  140, 172 },{ 140, 190 },{ 160,  190 },{ 160, 210 },
922     { 194, 210 },{  194, 254 },{ 230, 254 },{ 230,  190 },{ 254, 190 },
923     { 254, 144 },{  168,  58 },{ 136,  58 },{ 184,  106 },{ 144, 106 },
924     { 154, 124 },{  98,  124 },{ 108, 106 },{  70,  106 },{ 118,  58 },
925   };
926
927   int lifter_perimiter_points_1[][2] = {
928     {   0, 189 },{   0, 254 },{  22, 255 },{  23, 190 },
929   };
930
931   int lifter_perimiter_points_2[][2] = {
932     { 230, 254 },{ 255, 255 },{ 254, 190 },{ 230, 190 },
933   };
934
935   int lifter_perimiter_points_3[][2] = {
936     {  60, 254 },{ 194, 254 },{ 194, 211 },{ 160, 210 },
937     { 160, 190 },{ 140, 191 },{ 141, 172 },{ 111, 172 },
938     { 110, 190 },{ 93, 190 },{ 92, 210 },{ 60, 211 },
939   };
940
941   for (i = 0; i < countof(slider_face_points); i++)
942     slider_face_points[i][1] = 255-slider_face_points[i][1];
943   for (i = 0; i < countof(body_face_points); i++)
944     body_face_points[i][1] = 255-body_face_points[i][1];
945   for (i = 0; i < countof(lifter_face_points); i++)
946     lifter_face_points[i][1] = 255-lifter_face_points[i][1];
947   for (i = 0; i < countof(body_perimiter_points); i++)
948     body_perimiter_points[i][1] = 255-body_perimiter_points[i][1];
949   for (i = 0; i < countof(slider_perimiter_points); i++)
950     slider_perimiter_points[i][1] = 255-slider_perimiter_points[i][1];
951   for (i = 0; i < countof(lifter_perimiter_points_1); i++)
952     lifter_perimiter_points_1[i][1] = 255-lifter_perimiter_points_1[i][1];
953   for (i = 0; i < countof(lifter_perimiter_points_2); i++)
954     lifter_perimiter_points_2[i][1] = 255-lifter_perimiter_points_2[i][1];
955   for (i = 0; i < countof(lifter_perimiter_points_3); i++)
956     lifter_perimiter_points_3[i][1] = 255-lifter_perimiter_points_3[i][1];
957
958   /* -------------------------------------------------------------------- */
959
960   glNewList(lc->taser_base, GL_COMPILE);
961   glShadeModel(GL_SMOOTH);
962
963   /* N */
964   face4(lc->texids[FACE_N], exterior_color, wire,
965         0.0, 0.0,       -0.5,  0.5,  0.5,
966         0.75, 0.0,       0.25, 0.5,  0.5,
967         0.75, 0.75,      0.25, 0.5, -0.25,
968         0.0, 0.75,      -0.5,  0.5, -0.25);
969
970   /* S */
971   face4(lc->texids[FACE_S], exterior_color, wire,
972         0.0,  0.25,     -0.5,  -0.5, -0.25,
973         0.75, 0.25,      0.25, -0.5, -0.25,
974         0.75, 1.0,       0.25, -0.5,  0.5,
975         0.0,  1.0,      -0.5,  -0.5,  0.5);
976
977   /* interior E */
978   face4(0, interior_color, wire,
979         0.0, 0.0,        0.25, -0.5, -0.25,
980         1.0, 0.0,        0.25,  0.5, -0.25,
981         1.0, 1.0,        0.25,  0.5,  0.5,
982         0.0, 1.0,        0.25, -0.5,  0.5);
983
984   /* W */
985   face4(lc->texids[FACE_W], exterior_color, wire,
986         1.0, 1.0,       -0.5, -0.5,  0.5,
987         0.0, 1.0,       -0.5,  0.5,  0.5,
988         0.0, 0.25,      -0.5,  0.5, -0.25,
989         1.0, 0.25,      -0.5, -0.5, -0.25);
990
991   /* U */
992   face4(lc->texids[FACE_U], exterior_color, wire,
993         0.75, 0.0,       0.25, -0.5,  0.5,
994         0.75, 1.0,       0.25,  0.5,  0.5,
995         0.0, 1.0,       -0.5,   0.5,  0.5,
996         0.0, 0.0,       -0.5,  -0.5,  0.5);
997
998   /* interior D */
999   face4(0, interior_color, wire,
1000         0.0, 1.0,       -0.5,  -0.5, -0.25,
1001         0.0, 0.0,       -0.5,   0.5, -0.25,
1002         1.0, 0.0,        0.25,  0.5, -0.25,
1003         1.0, 1.0,        0.25, -0.5, -0.25);
1004
1005   /* Top face */
1006   for (i = 0; i < countof(body_face_points)/5; i++)
1007     {
1008       int j;
1009 #ifdef HAVE_GLBINDTEXTURE
1010       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1011 #endif /* HAVE_GLBINDTEXTURE */
1012       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1013
1014       do_normal(0, body_face_points[(i*5)+0][0], body_face_points[(i*5)+0][1],
1015                 0, body_face_points[(i*5)+1][0], body_face_points[(i*5)+1][1],
1016                 0, body_face_points[(i*5)+2][0], body_face_points[(i*5)+2][1]
1017                 );
1018       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1019       for (j = 0; j < 5; j++)
1020         {
1021           int ix = body_face_points[(i*5)+j][0];
1022           int iy = body_face_points[(i*5)+j][1];
1023           GLfloat x, y;
1024           if (ix == -1)  /* these are padding: ignore them */
1025             continue;
1026           x = ix / 255.0L;
1027           y = iy / 255.0L;
1028           glTexCoord2f(x, y);
1029           glVertex3f(0.5, x-0.5, y-0.5);
1030         }
1031       glEnd();
1032     }
1033
1034   /* Side walls */
1035   for (i = 0; i < countof(body_perimiter_points); i++)
1036     {
1037       int j = (i+1 >= countof(body_perimiter_points) ? 0 : i+1);
1038       GLfloat x1 = body_perimiter_points[i][0] / 255.0;
1039       GLfloat y1 = body_perimiter_points[i][1] / 255.0;
1040       GLfloat x2 = body_perimiter_points[j][0] / 255.0;
1041       GLfloat y2 = body_perimiter_points[j][1] / 255.0;
1042       int texture = -1;
1043       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1044
1045       if (i == 11)
1046         {
1047           texture = lc->texids[FACE_N];
1048           s1 = 1.0;  t1 = 0.0;
1049           s2 = 1.0;  t2 = 0.568;
1050           s3 = 0.75, t3 = 0.568;
1051           s4 = 0.75; t4 = 0.0;
1052         }
1053       else if (i == 12)
1054         {
1055           texture = lc->texids[FACE_U];
1056           s1 = 1.0;  t1 = 0.0;
1057           s2 = 1.0;  t2 = 1.0;
1058           s3 = 0.75, t3 = 1.0;
1059           s4 = 0.75; t4 = 0.0;
1060         }
1061       else if (i == 13)
1062         {
1063           texture = lc->texids[FACE_S];
1064           s1 = 1.0;  t1 = 0.437;
1065           s2 = 1.0;  t2 = 1.0;
1066           s3 = 0.75; t3 = 1.0;
1067           s4 = 0.75; t4 = 0.437;
1068         }
1069
1070       face4((texture == -1 ? 0 : texture),
1071             (texture == -1 ? interior_color : exterior_color),
1072             wire,
1073             s1, t1,  0.5,  x2-0.5, y2-0.5,
1074             s2, t2,  0.5,  x1-0.5, y1-0.5,
1075             s3, t3,  0.25, x1-0.5, y1-0.5,
1076             s4, t4,  0.25, x2-0.5, y2-0.5);
1077     }
1078
1079   glEndList();
1080
1081   /* -------------------------------------------------------------------- */
1082
1083   glNewList(lc->taser_lifter, GL_COMPILE);
1084   glShadeModel(GL_SMOOTH);
1085
1086   /* N */
1087   face4(lc->texids[FACE_N], exterior_color, wire,
1088         0.0,  0.75,     -0.5,  0.5, -0.25,
1089         0.75, 0.75,      0.25, 0.5, -0.25,
1090         0.75, 1.0,       0.25, 0.5, -0.5,
1091         0.0,  1.0,      -0.5,  0.5, -0.5);
1092
1093   /* S */
1094   face4(lc->texids[FACE_S], exterior_color, wire,
1095         0.0,  0.0,      -0.5,  -0.5, -0.5,
1096         0.75, 0.0,       0.25, -0.5, -0.5,
1097         0.75, 0.25,      0.25, -0.5, -0.25,
1098         0.0,  0.25,     -0.5,  -0.5, -0.25);
1099
1100   /* interior E */
1101   face4(0, interior_color, wire,
1102         0.0, 1.0,        0.25, -0.5, -0.5,
1103         1.0, 1.0,        0.25,  0.5, -0.5,
1104         1.0, 0.0,        0.25,  0.5, -0.25,
1105         0.0, 0.0,        0.25, -0.5, -0.25);
1106
1107   /* W */
1108   face4(lc->texids[FACE_W], exterior_color, wire,
1109         1.0, 0.25,      -0.5, -0.5, -0.25,
1110         0.0, 0.25,      -0.5,  0.5, -0.25,
1111         0.0, 0.0,       -0.5,  0.5, -0.5,
1112         1.0, 0.0,       -0.5, -0.5, -0.5);
1113
1114   /* interior U */
1115   face4(0, interior_color, wire,
1116         1.0, 0.0,        0.25, -0.5,  -0.25,
1117         1.0, 1.0,        0.25,  0.5,  -0.25,
1118         0.0, 1.0,       -0.5,   0.5,  -0.25,
1119         0.0, 0.0,       -0.5,  -0.5,  -0.25);
1120
1121   /* D */
1122   face4(lc->texids[FACE_D], exterior_color, wire,
1123         0.0, 1.0,       -0.5, -0.5, -0.5,
1124         0.0, 0.0,       -0.5,  0.5, -0.5,
1125         0.75, 0.0,       0.25,  0.5, -0.5,
1126         0.75, 1.0,       0.25, -0.5, -0.5);
1127
1128
1129   /* Top face */
1130   for (i = 0; i < countof(lifter_face_points)/5; i++)
1131     {
1132       int j;
1133
1134 #ifdef HAVE_GLBINDTEXTURE
1135       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1136 #endif /* HAVE_GLBINDTEXTURE */
1137       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1138
1139       do_normal(
1140          0, lifter_face_points[(i*5)+0][0], lifter_face_points[(i*5)+0][1],
1141          0, lifter_face_points[(i*5)+1][0], lifter_face_points[(i*5)+1][1],
1142          0, lifter_face_points[(i*5)+2][0], lifter_face_points[(i*5)+2][1]);
1143
1144       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1145       for (j = 0; j < 5; j++)
1146         {
1147           int ix = lifter_face_points[(i*5)+j][0];
1148           int iy = lifter_face_points[(i*5)+j][1];
1149           GLfloat x, y;
1150           if (ix == -1)  /* these are padding: ignore them */
1151             continue;
1152           x = ix / 255.0L;
1153           y = iy / 255.0L;
1154           glTexCoord2f(x, y);
1155           glVertex3f(0.5, x-0.5, y-0.5);
1156         }
1157       glEnd();
1158     }
1159
1160   /* Side walls */
1161   for (i = 0; i < countof(lifter_perimiter_points_1); i++)
1162     {
1163       int j = (i+1 >= countof(lifter_perimiter_points_1) ? 0 : i+1);
1164       GLfloat x1 = lifter_perimiter_points_1[i][0] / 255.0;
1165       GLfloat y1 = lifter_perimiter_points_1[i][1] / 255.0;
1166       GLfloat x2 = lifter_perimiter_points_1[j][0] / 255.0;
1167       GLfloat y2 = lifter_perimiter_points_1[j][1] / 255.0;
1168       int texture = -1;
1169       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1170
1171       if (i == 0)
1172         {
1173           texture = lc->texids[FACE_S];
1174           s1 = 1.0;  t1 = 0.0;
1175           s2 = 1.0;  t2 = 0.26;
1176           s3 = 0.75, t3 = 0.26;
1177           s4 = 0.75; t4 = 0.0;
1178         }
1179       else if (i == 1)
1180         {
1181           texture = lc->texids[FACE_D];
1182           s1 = 1.0;  t1 = 0.914;
1183           s2 = 1.0;  t2 = 1.0;
1184           s3 = 0.75; t3 = 1.0;
1185           s4 = 0.75; t4 = 0.914;
1186         }
1187
1188       face4((texture == -1 ? 0 : texture),
1189             (texture == -1 ? interior_color : exterior_color),
1190             wire,
1191             s1, t1,  0.5,  x2-0.5, y2-0.5,
1192             s2, t2,  0.5,  x1-0.5, y1-0.5,
1193             s3, t3,  0.25, x1-0.5, y1-0.5,
1194             s4, t4,  0.25, x2-0.5, y2-0.5);
1195     }
1196
1197   for (i = 0; i < countof(lifter_perimiter_points_2); i++)
1198     {
1199       int j = (i+1 >= countof(lifter_perimiter_points_2) ? 0 : i+1);
1200       GLfloat x1 = lifter_perimiter_points_2[i][0] / 255.0;
1201       GLfloat y1 = lifter_perimiter_points_2[i][1] / 255.0;
1202       GLfloat x2 = lifter_perimiter_points_2[j][0] / 255.0;
1203       GLfloat y2 = lifter_perimiter_points_2[j][1] / 255.0;
1204       int texture = -1;
1205       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1206
1207       if (i == 0)
1208         {
1209           texture = lc->texids[FACE_D];
1210           s1 = 1.0;  t1 = 0.0;
1211           s2 = 1.0;  t2 = 0.095;
1212           s3 = 0.75; t3 = 0.095;
1213           s4 = 0.75; t4 = 0.0;
1214         }
1215       else if (i == 1)
1216         {
1217           texture = lc->texids[FACE_N];
1218           s1 = 1.0;  t1 = 0.745;
1219           s2 = 1.0;  t2 = 1.0;
1220           s3 = 0.75; t3 = 1.0;
1221           s4 = 0.75; t4 = 0.745;
1222         }
1223
1224       face4((texture == -1 ? 0 : texture),
1225             (texture == -1 ? interior_color : exterior_color),
1226             wire,
1227             s1, t1,  0.5,  x2-0.5, y2-0.5,
1228             s2, t2,  0.5,  x1-0.5, y1-0.5,
1229             s3, t3,  0.25, x1-0.5, y1-0.5,
1230             s4, t4,  0.25, x2-0.5, y2-0.5);
1231     }
1232
1233   for (i = 0; i < countof(lifter_perimiter_points_3); i++)
1234     {
1235       int j = (i+1 >= countof(lifter_perimiter_points_3) ? 0 : i+1);
1236       GLfloat x1 = lifter_perimiter_points_3[i][0] / 255.0;
1237       GLfloat y1 = lifter_perimiter_points_3[i][1] / 255.0;
1238       GLfloat x2 = lifter_perimiter_points_3[j][0] / 255.0;
1239       GLfloat y2 = lifter_perimiter_points_3[j][1] / 255.0;
1240       int texture = -1;
1241       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1242
1243       if (i == 0)
1244         {
1245           texture = lc->texids[FACE_D];
1246           s1 = 1.0;  t1 = 0.235;
1247           s2 = 1.0;  t2 = 0.765;
1248           s3 = 0.75; t3 = 0.765;
1249           s4 = 0.75; t4 = 0.235;
1250         }
1251
1252       face4((texture == -1 ? 0 : texture),
1253             (texture == -1 ? interior_color : exterior_color),
1254             wire,
1255             s1, t1,  0.5,  x2-0.5, y2-0.5,
1256             s2, t2,  0.5,  x1-0.5, y1-0.5,
1257             s3, t3,  0.25, x1-0.5, y1-0.5,
1258             s4, t4,  0.25, x2-0.5, y2-0.5);
1259     }
1260
1261   glEndList();
1262
1263   /* -------------------------------------------------------------------- */
1264
1265   glNewList(lc->taser_slider, GL_COMPILE);
1266   glShadeModel(GL_SMOOTH);
1267
1268   /* Top face */
1269   for (i = 0; i < countof(slider_face_points)/5; i++)
1270     {
1271       int j;
1272 #ifdef HAVE_GLBINDTEXTURE
1273       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1274 #endif /* HAVE_GLBINDTEXTURE */
1275       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1276
1277       do_normal(
1278            0, slider_face_points[(i*5)+0][0], slider_face_points[(i*5)+0][1],
1279            0, slider_face_points[(i*5)+1][0], slider_face_points[(i*5)+1][1],
1280            0, slider_face_points[(i*5)+2][0], slider_face_points[(i*5)+2][1]);
1281       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1282       for (j = 0; j < 5; j++)
1283         {
1284           int ix = slider_face_points[(i*5)+j][0];
1285           int iy = slider_face_points[(i*5)+j][1];
1286           GLfloat x, y;
1287           if (ix == -1)  /* these are padding: ignore them */
1288             continue;
1289           x = ix / 255.0L;
1290           y = iy / 255.0L;
1291           glTexCoord2f(x, y);
1292           glVertex3f(0.5, x-0.5, y-0.5);
1293         }
1294       glEnd();
1295     }
1296
1297   /* Bottom face */
1298   for (i = countof(slider_face_points)/5 - 1; i >= 0; i--)
1299     {
1300       int j;
1301 #ifdef HAVE_GLBINDTEXTURE
1302       glBindTexture(GL_TEXTURE_2D, 0);
1303 #endif /* HAVE_GLBINDTEXTURE */
1304       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, interior_color);
1305
1306       do_normal(
1307            0, slider_face_points[(i*5)+2][0], slider_face_points[(i*5)+2][1],
1308            0, slider_face_points[(i*5)+1][0], slider_face_points[(i*5)+1][1],
1309            0, slider_face_points[(i*5)+0][0], slider_face_points[(i*5)+0][1]);
1310       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1311       for (j = 4; j >= 0; j--)
1312         {
1313           int ix = slider_face_points[(i*5)+j][0];
1314           int iy = slider_face_points[(i*5)+j][1];
1315           GLfloat x, y;
1316           if (ix == -1)  /* these are padding: ignore them */
1317             continue;
1318           x = ix / 255.0L;
1319           y = iy / 255.0L;
1320           glTexCoord2f(x, y);
1321           glVertex3f(0.25, x-0.5, y-0.5);
1322         }
1323       glEnd();
1324     }
1325
1326   /* Side walls */
1327   for (i = 0; i < countof(slider_perimiter_points); i++)
1328     {
1329       int j = (i+1 >= countof(slider_perimiter_points) ? 0 : i+1);
1330       GLfloat x1 = slider_perimiter_points[i][0] / 255.0;
1331       GLfloat y1 = slider_perimiter_points[i][1] / 255.0;
1332       GLfloat x2 = slider_perimiter_points[j][0] / 255.0;
1333       GLfloat y2 = slider_perimiter_points[j][1] / 255.0;
1334       int texture = -1;
1335       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1336
1337       if (i == 1)
1338         {
1339           texture = lc->texids[FACE_S];
1340           s1 = 1.0;  t1 = 0.255;
1341           s2 = 1.0;  t2 = 0.435;
1342           s3 = 0.75; t3 = 0.435;
1343           s4 = 0.75; t4 = 0.255;
1344         }
1345       else if (i == 4)
1346         {
1347           texture = lc->texids[FACE_D];
1348           s1 = 1.0;  t1 = 0.758;
1349           s2 = 1.0;  t2 = 0.915;
1350           s3 = 0.75; t3 = 0.915;
1351           s4 = 0.75; t4 = 0.758;
1352         }
1353       else if (i == 16)
1354         {
1355           texture = lc->texids[FACE_D];
1356           s1 = 1.0;  t1 = 0.095;
1357           s2 = 1.0;  t2 = 0.24;
1358           s3 = 0.75; t3 = 0.24;
1359           s4 = 0.75; t4 = 0.095;
1360         }
1361       else if (i == 19)
1362         {
1363           texture = lc->texids[FACE_N];
1364           s1 = 1.0;  t1 = 0.568;
1365           s2 = 1.0;  t2 = 0.742;
1366           s3 = 0.75; t3 = 0.742;
1367           s4 = 0.75; t4 = 0.568;
1368         }
1369
1370       face4((texture == -1 ? 0 : texture),
1371             (texture == -1 ? interior_color : exterior_color),
1372             wire,
1373             s1, t1,  0.5,  x2-0.5, y2-0.5,
1374             s2, t2,  0.5,  x1-0.5, y1-0.5,
1375             s3, t3,  0.25, x1-0.5, y1-0.5,
1376             s4, t4,  0.25, x2-0.5, y2-0.5);
1377     }
1378
1379   glEndList();
1380 }
1381
1382
1383 \f
1384 /* Rendering and animating object models
1385  */
1386
1387 static void
1388 draw(ModeInfo *mi)
1389 {
1390   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1391   Bool wire = MI_IS_WIREFRAME(mi);
1392
1393   if (!wire)
1394     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1395   else
1396     glClear(GL_COLOR_BUFFER_BIT);
1397
1398   glPushMatrix();
1399   {
1400     GLfloat x = lc->rotx;
1401     GLfloat y = lc->roty;
1402     GLfloat z = lc->rotz;
1403
1404 #if 0
1405  x=0.75; y=0; z=0; 
1406 #endif
1407
1408     if (x < 0) x = 1 - (x + 1);
1409     if (y < 0) y = 1 - (y + 1);
1410     if (z < 0) z = 1 - (z + 1);
1411
1412     /* Make into the screen be +Y right be +X, and up be +Z. */
1413     glRotatef(-90.0, 1.0, 0.0, 0.0);
1414
1415     /* Scale it up. */
1416     glScalef(4.0, 4.0, 4.0);
1417
1418 #ifdef DEBUG
1419     glPushMatrix();
1420     {
1421       /* Shift to the upper left, and draw the vanilla box. */
1422       glTranslatef(-0.6, 0.0, 0.6);
1423
1424       /* Apply rotation to the object. */
1425       glRotatef(x * 360, 1.0, 0.0, 0.0);
1426       glRotatef(y * 360, 0.0, 1.0, 0.0);
1427       glRotatef(z * 360, 0.0, 0.0, 1.0);
1428
1429       /* Draw it. */
1430       glCallList(lc->box);
1431     }
1432     glPopMatrix();
1433
1434     /* Shift to the lower right, and draw the animated object. */
1435     glTranslatef(0.6, 0.0, -0.6);
1436 #endif /* DEBUG */
1437
1438
1439     glPushMatrix();
1440     {
1441       /* Apply rotation to the object. */
1442       glRotatef(x * 360, 1.0, 0.0, 0.0);
1443       glRotatef(y * 360, 0.0, 1.0, 0.0);
1444       glRotatef(z * 360, 0.0, 0.0, 1.0);
1445
1446       switch (lc->type)
1447         {
1448         case LAMENT_BOX:
1449           glCallList(lc->box);
1450           break;
1451
1452         case LAMENT_STAR_OUT:
1453         case LAMENT_STAR_ROT:
1454         case LAMENT_STAR_ROT_IN:
1455         case LAMENT_STAR_ROT_OUT:
1456         case LAMENT_STAR_UNROT:
1457         case LAMENT_STAR_IN:
1458           glTranslatef(0.0, 0.0, lc->anim_z/2);
1459           glRotatef(lc->anim_r/2, 0.0, 0.0, 1.0);
1460           glCallList(lc->star1);
1461
1462           glTranslatef(0.0, 0.0, -lc->anim_z);
1463           glRotatef(-lc->anim_r, 0.0, 0.0, 1.0);
1464           glCallList(lc->star2);
1465           break;
1466
1467         case LAMENT_TETRA_UNE:
1468         case LAMENT_TETRA_USW:
1469         case LAMENT_TETRA_DWN:
1470         case LAMENT_TETRA_DSE:
1471           {
1472             int magic;
1473             GLfloat x, y, z;
1474             switch (lc->type) {
1475             case LAMENT_TETRA_UNE: magic = lc->tetra_une;
1476               x = 1.0; y = 1.0; z = 1.0; break;
1477             case LAMENT_TETRA_USW: magic = lc->tetra_usw;
1478               x = 1.0; y = 1.0; z = -1.0; break;
1479             case LAMENT_TETRA_DWN: magic = lc->tetra_dwn;
1480               x = 1.0; y = -1.0; z = 1.0; break;
1481             case LAMENT_TETRA_DSE: magic = lc->tetra_dse;
1482               x = -1.0; y = 1.0; z = 1.0; break;
1483             default: abort(); break;
1484             }
1485             glCallList(lc->tetra_mid);
1486             if (magic != lc->tetra_une) glCallList(lc->tetra_une);
1487             if (magic != lc->tetra_usw) glCallList(lc->tetra_usw);
1488             if (magic != lc->tetra_dwn) glCallList(lc->tetra_dwn);
1489             if (magic != lc->tetra_dse) glCallList(lc->tetra_dse);
1490             glRotatef(lc->anim_r, x, y, z);
1491             glCallList(magic);
1492           }
1493           break;
1494
1495         case LAMENT_LID_OPEN:
1496         case LAMENT_LID_CLOSE:
1497         case LAMENT_LID_ZOOM:
1498           {
1499             GLfloat d = 0.417;
1500
1501             glTranslatef(lc->anim_z, 0.0, 0.0);
1502
1503             glCallList(lc->lid_0);
1504
1505             glPushMatrix();
1506               glTranslatef(-0.5, -d, 0.0);
1507               glRotatef(-lc->anim_r, 0.0, -1.0, -1.0);
1508               glTranslatef( 0.5,  d, 0.0);
1509               glCallList(lc->lid_1);
1510             glPopMatrix();
1511             glPushMatrix();
1512               glTranslatef(-0.5, -d, 0.0);
1513               glRotatef( lc->anim_r, 0.0, -1.0,   1.0);
1514               glTranslatef( 0.5,  d, 0.0);
1515               glCallList(lc->lid_2);
1516             glPopMatrix();
1517             glPushMatrix();
1518               glTranslatef(-0.5,  d, 0.0);
1519               glRotatef( lc->anim_r, 0.0,  -1.0,  -1.0);
1520               glTranslatef( 0.5, -d, 0.0);
1521               glCallList(lc->lid_3);
1522             glPopMatrix();
1523             glPushMatrix();
1524               glTranslatef(-0.5,  d, 0.0);
1525               glRotatef(-lc->anim_r, 0.0,  -1.0,   1.0);
1526               glTranslatef( 0.5, -d, 0.0);
1527               glCallList(lc->lid_4);
1528             glPopMatrix();
1529           }
1530           break;
1531
1532         case LAMENT_TASER_OUT:
1533         case LAMENT_TASER_SLIDE:
1534         case LAMENT_TASER_SLIDE_IN:
1535         case LAMENT_TASER_IN:
1536
1537           glTranslatef(-lc->anim_z/2, 0.0, 0.0);
1538           glCallList(lc->taser_base);
1539
1540           glTranslatef(lc->anim_z, 0.0, 0.0);
1541           glCallList(lc->taser_lifter);
1542
1543           glTranslatef(0.0, 0.0, lc->anim_y);
1544           glCallList(lc->taser_slider);
1545           break;
1546
1547         default:
1548           abort();
1549           break;
1550         }
1551     }
1552     glPopMatrix();
1553
1554   }
1555   glPopMatrix();
1556 }
1557
1558
1559 static void
1560 animate(ModeInfo *mi)
1561 {
1562   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1563   int pause = 10;
1564 /*  int pause2 = 60;*/
1565   int pause3 = 120;
1566
1567   switch (lc->type)
1568     {
1569     case LAMENT_BOX:
1570       {
1571         /* Rather than just picking states randomly, pick an ordering randomly,
1572            do it, and then re-randomize.  That way one can be assured of seeing
1573            all states in a short time period, though not always in the same
1574            order (it's frustrating to see it pick the same state 5x in a row.)
1575          */
1576         static lament_type states[] = {
1577           LAMENT_STAR_OUT, LAMENT_STAR_OUT,
1578           LAMENT_TETRA_UNE, LAMENT_TETRA_USW,
1579           LAMENT_TETRA_DWN, LAMENT_TETRA_DSE,
1580           LAMENT_LID_OPEN, LAMENT_LID_OPEN, LAMENT_LID_OPEN,
1581           LAMENT_TASER_OUT, LAMENT_TASER_OUT,
1582           LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
1583           LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
1584         };
1585         static int state = countof(states);
1586
1587         if (state < countof(states))
1588           {
1589             lc->type = states[state++];
1590           }
1591         else
1592           {
1593             int i;
1594             state = 0;
1595             for (i = 0; i < countof(states); i++)
1596               {
1597                 int a = random() % countof(states);
1598                 lament_type swap = states[a];
1599                 states[a] = states[i];
1600                 states[i] = swap;
1601               }
1602           }
1603
1604         if (lc->type == LAMENT_BOX)
1605           lc->anim_pause = pause3;
1606
1607         lc->anim_r = 0.0;
1608         lc->anim_y = 0.0;
1609         lc->anim_z = 0.0;
1610       }
1611       break;
1612
1613       /* -------------------------------------------------------------- */
1614
1615     case LAMENT_STAR_OUT:
1616       lc->anim_z += 0.01;
1617       if (lc->anim_z >= 1.0)
1618         {
1619           lc->anim_z = 1.0;
1620           lc->type = LAMENT_STAR_ROT;
1621           lc->anim_pause = pause;
1622         }
1623       break;
1624
1625     case LAMENT_STAR_ROT:
1626       lc->anim_r += 1.0;
1627       if (lc->anim_r >= 45.0)
1628         {
1629           lc->anim_r = 45.0;
1630           lc->type = LAMENT_STAR_ROT_IN;
1631           lc->anim_pause = pause;
1632         }
1633       break;
1634
1635     case LAMENT_STAR_ROT_IN:
1636       lc->anim_z -= 0.01;
1637       if (lc->anim_z <= 0.0)
1638         {
1639           lc->anim_z = 0.0;
1640           lc->type = LAMENT_STAR_ROT_OUT;
1641           lc->anim_pause = pause3 * (1 + (random() % 4) + (random() % 4));
1642         }
1643       break;
1644
1645     case LAMENT_STAR_ROT_OUT:
1646       lc->anim_z += 0.01;
1647       if (lc->anim_z >= 1.0)
1648         {
1649           lc->anim_z = 1.0;
1650           lc->type = LAMENT_STAR_UNROT;
1651           lc->anim_pause = pause;
1652         }
1653       break;
1654       
1655     case LAMENT_STAR_UNROT:
1656       lc->anim_r -= 1.0;
1657       if (lc->anim_r <= 0.0)
1658         {
1659           lc->anim_r = 0.0;
1660           lc->type = LAMENT_STAR_IN;
1661           lc->anim_pause = pause;
1662         }
1663       break;
1664
1665     case LAMENT_STAR_IN:
1666       lc->anim_z -= 0.01;
1667       if (lc->anim_z <= 0.0)
1668         {
1669           lc->anim_z = 0.0;
1670           lc->type = LAMENT_BOX;
1671           lc->anim_pause = pause3;
1672         }
1673       break;
1674
1675       /* -------------------------------------------------------------- */
1676
1677     case LAMENT_TETRA_UNE:
1678     case LAMENT_TETRA_USW:
1679     case LAMENT_TETRA_DWN:
1680     case LAMENT_TETRA_DSE:
1681
1682       lc->anim_r += 1.0;
1683       if (lc->anim_r >= 360.0)
1684         {
1685           lc->anim_r = 0.0;
1686           lc->type = LAMENT_BOX;
1687           lc->anim_pause = pause3;
1688         }
1689       else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1690         {
1691           lc->anim_r = 120.0;
1692           lc->anim_pause = pause;
1693         }
1694       else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1695         {
1696           lc->anim_r = 240.0;
1697           lc->anim_pause = pause;
1698         }
1699       break;
1700
1701       /* -------------------------------------------------------------- */
1702
1703     case LAMENT_LID_OPEN:
1704       lc->anim_r += 1.0;
1705
1706       if (lc->anim_r >= 112.0)
1707         {
1708           GLfloat hysteresis = 0.05;
1709
1710           lc->anim_r = 112.0;
1711           lc->anim_z = 0.0;
1712           lc->anim_pause = pause3;
1713
1714           if (lc->rotx >= -hysteresis &&
1715               lc->rotx <=  hysteresis &&
1716               ((lc->rotz >=  (0.25 - hysteresis) &&
1717                 lc->rotz <=  (0.25 + hysteresis)) ||
1718                (lc->rotz >= (-0.25 - hysteresis) &&
1719                 lc->rotz <= (-0.25 + hysteresis))))
1720             {
1721               lc->type = LAMENT_LID_ZOOM;
1722               lc->rotx = 0.00;
1723               lc->rotz = (lc->rotz < 0 ? -0.25 : 0.25);
1724             }
1725           else
1726             {
1727               lc->type = LAMENT_LID_CLOSE;
1728             }
1729         }
1730       break;
1731
1732     case LAMENT_LID_CLOSE:
1733       lc->anim_r -= 1.0;
1734       if (lc->anim_r <= 0.0)
1735         {
1736           lc->anim_r = 0.0;
1737           lc->type = LAMENT_BOX;
1738           lc->anim_pause = pause3;
1739         }
1740       break;
1741
1742     case LAMENT_LID_ZOOM:
1743       lc->anim_z -= 0.1;
1744       if (lc->anim_z < -50.0)
1745         {
1746           lc->anim_r = 0.0;
1747           lc->anim_z = 0.0;
1748           lc->rotx = frand(1.0) * RANDSIGN();
1749           lc->roty = frand(1.0) * RANDSIGN();
1750           lc->rotz = frand(1.0) * RANDSIGN();
1751           lc->type = LAMENT_BOX;
1752         }
1753       break;
1754
1755       /* -------------------------------------------------------------- */
1756
1757     case LAMENT_TASER_OUT:
1758       lc->anim_z += 0.0025;
1759       if (lc->anim_z >= 0.25)
1760         {
1761           lc->anim_z = 0.25;
1762           lc->type = LAMENT_TASER_SLIDE;
1763           lc->anim_pause = pause * (1 + (random() % 5) + (random() % 5));
1764         }
1765       break;
1766
1767     case LAMENT_TASER_SLIDE:
1768       lc->anim_y += 0.0025;
1769       if (lc->anim_y >= 0.23)
1770         {
1771           lc->anim_y = 0.23;
1772           lc->type = LAMENT_TASER_SLIDE_IN;
1773           lc->anim_pause = pause3 * (1 + (random() % 5) + (random() % 5));
1774         }
1775       break;
1776
1777     case LAMENT_TASER_SLIDE_IN:
1778       lc->anim_y -= 0.0025;
1779       if (lc->anim_y <= 0.0)
1780         {
1781           lc->anim_y = 0.0;
1782           lc->type = LAMENT_TASER_IN;
1783           lc->anim_pause = pause;
1784         }
1785       break;
1786
1787     case LAMENT_TASER_IN:
1788       lc->anim_z -= 0.0025;
1789       if (lc->anim_z <= 0.0)
1790         {
1791           lc->anim_z = 0.0;
1792           lc->type = LAMENT_BOX;
1793           lc->anim_pause = pause3;
1794         }
1795       break;
1796
1797     default:
1798       abort();
1799       break;
1800     }
1801 }
1802
1803
1804 static void
1805 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
1806 {
1807   double ppos = *pos;
1808
1809   /* tick position */
1810   if (ppos < 0)
1811     ppos = -(ppos + *v);
1812   else
1813     ppos += *v;
1814
1815   if (ppos > 1.0)
1816     ppos -= 1.0;
1817   else if (ppos < 0)
1818     ppos += 1.0;
1819
1820   if (ppos < 0) abort();
1821   if (ppos > 1.0) abort();
1822   *pos = (*pos > 0 ? ppos : -ppos);
1823
1824   /* accelerate */
1825   *v += *dv;
1826
1827   /* clamp velocity */
1828   if (*v > max_v || *v < -max_v)
1829     {
1830       *dv = -*dv;
1831     }
1832   /* If it stops, start it going in the other direction. */
1833   else if (*v < 0)
1834     {
1835       if (random() % 4)
1836         {
1837           *v = 0;
1838
1839           /* keep going in the same direction */
1840           if (random() % 2)
1841             *dv = 0;
1842           else if (*dv < 0)
1843             *dv = -*dv;
1844         }
1845       else
1846         {
1847           /* reverse gears */
1848           *v = -*v;
1849           *dv = -*dv;
1850           *pos = -*pos;
1851         }
1852     }
1853
1854   /* Alter direction of rotational acceleration randomly. */
1855   if (! (random() % 120))
1856     *dv = -*dv;
1857
1858   /* Change acceleration very occasionally. */
1859   if (! (random() % 200))
1860     {
1861       if (*dv == 0)
1862         *dv = 0.00001;
1863       else if (random() & 1)
1864         *dv *= 1.2;
1865       else
1866         *dv *= 0.8;
1867     }
1868 }
1869
1870
1871 \f
1872 /* Window management, etc
1873  */
1874
1875 static void
1876 reshape(int width, int height)
1877 {
1878   int target_size = 180;
1879   int win_size = (width > height ? height : width);
1880   GLfloat h = (GLfloat) height / (GLfloat) width;
1881
1882   glViewport(0, 0, (GLint) width, (GLint) height);
1883
1884 /*  glViewport(-600, -600, 1800, 1800); */
1885
1886   glMatrixMode(GL_PROJECTION);
1887   glLoadIdentity();
1888   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1889   glMatrixMode(GL_MODELVIEW);
1890   glLoadIdentity();
1891   glTranslatef(0.0, 0.0, -40.0);
1892
1893   /* This scale makes the box take up most of the window */
1894   glScalef(2.0, 2.0, 2.0);
1895
1896   /* But if the window is more than a little larger than our target size,
1897      scale the object back down, so that the bits drawn on the screen end
1898      up rougly target_size across (actually it ends up a little larger.)
1899      Note that the image-map bits we have are 128x128.  Therefore, if the
1900      image is magnified a lot, it looks pretty blocky.  So it's better to
1901      have a 128x128 animation on a 1280x1024 screen that looks good, than
1902      a 1024x1024 animation that looks really pixellated.
1903    */
1904   if (win_size > target_size * 1.5)
1905     {
1906       GLfloat ratio = ((GLfloat) target_size / (GLfloat) win_size);
1907       ratio *= 2.0;
1908       glScalef(ratio, ratio, ratio);
1909     }
1910
1911   /* The depth buffer will be cleared, if needed, before the
1912    * next frame.  Right now we just want to black the screen.
1913    */
1914   glClear(GL_COLOR_BUFFER_BIT);
1915 }
1916
1917
1918 static void
1919 gl_init(ModeInfo *mi)
1920 {
1921   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1922   Bool wire = MI_IS_WIREFRAME(mi);
1923
1924   if (wire)
1925     do_texture = False;
1926
1927   if (!wire)
1928     {
1929       static GLfloat pos0[]  = { -4.0, 2.0, 5.0, 1.0 };
1930       static GLfloat pos1[]  = { 12.0, 5.0, 1.0, 1.0 };
1931       static GLfloat local[] = { 0.0 };
1932       static GLfloat ambient[] = { 0.3, 0.3, 0.3, 1.0 };
1933       static GLfloat spec[] = { 1.0, 1.0, 1.0, 1.0 };
1934       static GLfloat shine[] = { 100.0 };
1935
1936       glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1937       glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1938
1939       glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1940       glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1941
1942       glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
1943       glLightfv(GL_LIGHT1, GL_SPECULAR, spec);
1944
1945       glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local);
1946       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1947       glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1948       glMaterialfv(GL_FRONT, GL_SHININESS, shine);
1949
1950       glEnable(GL_LIGHTING);
1951       glEnable(GL_LIGHT0);
1952       glEnable(GL_LIGHT1);
1953       glDisable(GL_LIGHT1);
1954
1955       glEnable(GL_DEPTH_TEST);
1956       glEnable(GL_TEXTURE_2D);
1957       glEnable(GL_NORMALIZE);
1958       glEnable(GL_CULL_FACE);
1959     }
1960
1961   if (do_texture)
1962     {
1963 #ifdef HAVE_GLBINDTEXTURE
1964       int i;
1965       for (i = 0; i < 6; i++)
1966         glGenTextures(1, &lc->texids[i]);
1967
1968       parse_image_data(mi);
1969
1970       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1971       glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width);
1972
1973       for (i = 0; i < 6; i++)
1974         {
1975           int height = lc->texture->width;      /* assume square */
1976           glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1977           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1978           glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1979                        lc->texture->width, height, 0,
1980                        GL_RGBA, GL_UNSIGNED_BYTE,
1981                        (lc->texture->data +
1982                         (lc->texture->bytes_per_line * height * i)));
1983
1984           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1985           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1986           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1987           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1988           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1989           glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1990         }
1991
1992 #else  /* !HAVE_GLBINDTEXTURE */
1993       fprintf(stderr,
1994               "%s: this version of GL doesn't support multiple texture maps.\n"
1995               "\tGet OpenGL 1.1.\n",
1996               progname);
1997       exit (1);
1998 #endif /* !HAVE_GLBINDTEXTURE */
1999     }
2000
2001   lc->box = glGenLists(16);
2002   lc->star1 = lc->box+1;
2003   lc->star2 = lc->box+2;
2004   lc->tetra_une = lc->box+3;
2005   lc->tetra_usw = lc->box+4;
2006   lc->tetra_dwn = lc->box+5;
2007   lc->tetra_dse = lc->box+6;
2008   lc->tetra_mid = lc->box+7;
2009   lc->lid_0 = lc->box+8;
2010   lc->lid_1 = lc->box+9;
2011   lc->lid_2 = lc->box+10;
2012   lc->lid_3 = lc->box+11;
2013   lc->lid_4 = lc->box+12;
2014   lc->taser_base = lc->box+13;
2015   lc->taser_lifter = lc->box+14;
2016   lc->taser_slider = lc->box+15;
2017
2018   box(mi, wire);
2019   star(mi, True, wire);
2020   star(mi, False, wire);
2021   tetra(mi, wire);
2022   lid(mi, wire);
2023   taser(mi, wire);
2024 }
2025
2026
2027 # ifdef HAVE_MESA_GL
2028
2029 # include <signal.h>
2030
2031 static RETSIGTYPE
2032 lament_signal_kludge (int sig)
2033 {
2034   signal (sig, SIG_DFL);
2035   fprintf (stderr,
2036            "\n"
2037            "%s: dying with signal %d (%s).\n"
2038            "\n"
2039            "\tThis is almost certainly a bug in the MesaGL library,\n"
2040            "\tespecially if the stack trace in the core file mentions\n"
2041            "\t`lambda_textured_triangle' or `render_quad'.\n"
2042            "\n"
2043            "\tI encourage you to report this to the Mesa maintainers\n"
2044            "\tat <http://www.mesa3d.org/>.  I reported this bug more\n"
2045            "\tthan a year ago, and it is trivially reproducible.\n"
2046            "\tI do not know a workaround.\n"
2047            "\n",
2048            progname,
2049            sig,
2050            (sig == SIGILL ? "SIGILL" :
2051             sig == SIGFPE ? "SIGFPE" :
2052             sig == SIGBUS ? "SIGBUS" :
2053             sig == SIGSEGV ? "SIGSEGV" : "???"));
2054   fflush (stderr);
2055   kill (getpid (), sig);
2056 }
2057
2058 static void
2059 handle_signals (void)
2060 {
2061   signal (SIGILL,  lament_signal_kludge);
2062   signal (SIGFPE,  lament_signal_kludge);
2063   signal (SIGBUS,  lament_signal_kludge);
2064   signal (SIGSEGV, lament_signal_kludge);
2065 }
2066 # endif /* HAVE_MESA_GL */
2067
2068
2069 void
2070 init_lament(ModeInfo *mi)
2071 {
2072   lament_configuration *lc;
2073   if (!lcs)
2074     {
2075       lcs = (lament_configuration *)
2076         calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
2077       if (!lcs)
2078         {
2079           fprintf(stderr, "%s: out of memory\n", progname);
2080           exit(1);
2081         }
2082     }
2083
2084   lc = &lcs[MI_SCREEN(mi)];
2085
2086   lc->rotx = frand(1.0) * RANDSIGN();
2087   lc->roty = frand(1.0) * RANDSIGN();
2088   lc->rotz = frand(1.0) * RANDSIGN();
2089
2090   /* bell curve from 0-1.5 degrees, avg 0.75 */
2091   lc->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
2092   lc->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
2093   lc->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
2094
2095   lc->d_max = lc->dx * 2;
2096
2097   lc->ddx = 0.00006 + frand(0.00003);
2098   lc->ddy = 0.00006 + frand(0.00003);
2099   lc->ddz = 0.00006 + frand(0.00003);
2100
2101   lc->ddx = 0.00001;
2102   lc->ddy = 0.00001;
2103   lc->ddz = 0.00001;
2104
2105   lc->type = LAMENT_BOX;
2106   lc->anim_pause = 300 + (random() % 100);
2107
2108   if ((lc->glx_context = init_GL(mi)) != NULL)
2109     {
2110       reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
2111       gl_init(mi);
2112     }
2113
2114 # ifdef HAVE_MESA_GL
2115   handle_signals ();
2116 # endif /* HAVE_MESA_GL */
2117 }
2118
2119
2120 void
2121 draw_lament(ModeInfo *mi)
2122 {
2123   static int tick = 0;
2124   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
2125   Display *dpy = MI_DISPLAY(mi);
2126   Window window = MI_WINDOW(mi);
2127
2128   if (!lc->glx_context)
2129     return;
2130
2131   glDrawBuffer(GL_BACK);
2132
2133   glXMakeCurrent(dpy, window, *(lc->glx_context));
2134   draw(mi);
2135   glFinish();
2136   glXSwapBuffers(dpy, window);
2137
2138   if (lc->type != LAMENT_LID_ZOOM)
2139     {
2140       rotate(&lc->rotx, &lc->dx, &lc->ddx, lc->d_max);
2141       rotate(&lc->roty, &lc->dy, &lc->ddy, lc->d_max);
2142       rotate(&lc->rotz, &lc->dz, &lc->ddz, lc->d_max);
2143     }
2144
2145   if (lc->anim_pause)
2146     lc->anim_pause--;
2147   else
2148     animate(mi);
2149
2150   if (++tick > 500)
2151     {
2152       tick = 0;
2153       reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
2154     }
2155 }
2156
2157 #endif /* USE_GL */