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