http://ftp.x.org/contrib/applications/xscreensaver-3.09.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
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     glEnd();
716   }
717   glEndList();
718
719   glNewList(lc->tetra_mid, GL_COMPILE);
720   {
721     face3(0, interior_color, wire,
722           0.0, 0.0,      0.5, -0.5,  0.5,
723           0.0, 0.0,      0.5,  0.5, -0.5,
724           0.0, 0.0,     -0.5,  0.5,  0.5);
725
726     face3(0, interior_color, wire,
727           0.0, 0.0,     -0.5,  0.5,  0.5,
728           0.0, 0.0,     -0.5, -0.5, -0.5,
729           0.0, 0.0,      0.5, -0.5,  0.5);
730
731     face3(0, interior_color, wire,
732           0.0, 0.0,     -0.5,  0.5,  0.5,
733           0.0, 0.0,      0.5,  0.5, -0.5,
734           0.0, 0.0,     -0.5, -0.5, -0.5);
735
736     face3(0, interior_color, wire,
737           0.0, 0.0,      0.5,  0.5, -0.5,
738           0.0, 0.0,      0.5, -0.5,  0.5,
739           0.0, 0.0,     -0.5, -0.5, -0.5);
740
741     face3(0, interior_color, wire,
742           0.0, 0.0,      0.5, -0.5,  0.5,
743           0.0, 0.0,      0.5,  0.5, -0.5,
744           0.0, 0.0,     -0.5, -0.5, -0.5);
745   }
746   glEndList();
747
748 }
749
750 static void
751 lid(ModeInfo *mi, Bool wire)
752 {
753   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
754   int i;
755
756   int points[][2] = {
757     { 128,  20 },{  21, 129 },{   0, 129 },{   0,   0 },{ 128,   0 }, /* L1 */
758     {  21, 129 },{ 127, 234 },{ 127, 255 },{   0, 255 },{   0, 129 }, /* L2 */
759     { 127, 234 },{ 233, 127 },{ 255, 127 },{ 255, 255 },{ 127, 255 }, /* R2 */
760     { 233, 127 },{ 128,  20 },{ 128,   0 },{ 255,   0 },{ 255, 127 }, /* R1 */
761   };
762
763   for (i = 0; i < countof(points); i++)
764     points[i][1] = 255-points[i][1];
765
766   glNewList(lc->lid_0, GL_COMPILE);
767   glShadeModel(GL_SMOOTH);
768
769   /* N */
770   face4(lc->texids[FACE_N], exterior_color, wire,
771         0.0, 0.0,       -0.5,  0.5,  0.5,
772         1.0, 0.0,        0.5,  0.5,  0.5,
773         1.0, 1.0,        0.5,  0.5, -0.5,
774         0.0, 1.0,       -0.5,  0.5, -0.5);
775
776   /* S */
777   face4(lc->texids[FACE_S], exterior_color, wire,
778         0.0, 0.0,       -0.5, -0.5, -0.5,
779         1.0, 0.0,        0.5, -0.5, -0.5,
780         1.0, 1.0,        0.5, -0.5,  0.5,
781         0.0, 1.0,       -0.5, -0.5,  0.5);
782
783   /* E */
784   face4(lc->texids[FACE_E], exterior_color, wire,
785         0.0, 0.0,        0.5, -0.5, -0.5,
786         1.0, 0.0,        0.5,  0.5, -0.5,
787         1.0, 1.0,        0.5,  0.5,  0.5,
788         0.0, 1.0,        0.5, -0.5,  0.5);
789
790   /* U */
791   face4(lc->texids[FACE_U], exterior_color, wire,
792         1.0, 0.0,        0.5, -0.5,  0.5,
793         1.0, 1.0,        0.5,  0.5,  0.5,
794         0.0, 1.0,       -0.5,  0.5,  0.5,
795         0.0, 0.0,       -0.5, -0.5,  0.5);
796
797   /* D */
798   face4(lc->texids[FACE_D], exterior_color, wire,
799         0.0, 1.0,       -0.5, -0.5, -0.5,
800         0.0, 0.0,       -0.5,  0.5, -0.5,
801         1.0, 0.0,        0.5,  0.5, -0.5,
802         1.0, 1.0,        0.5, -0.5, -0.5);
803
804   /* W -- lid_0 */
805   for (i = 0; i < countof(points)/5; i++)
806     {
807       int j;
808       GLfloat s[5], t[5], x[5], y[5], z[5];
809       for (j = 0; j < 5; j++)
810         {
811           GLfloat xx = points[(i*5)+j][0] / 255.0L;
812           GLfloat yy = points[(i*5)+j][1] / 255.0L;
813           s[j] = 1.0-xx;
814           t[j] = yy;
815           x[j] = -0.5;
816           y[j] = xx-0.5;
817           z[j] = yy-0.5;
818         }
819       face5(lc->texids[FACE_W], exterior_color, wire,
820             s[0], t[0],  x[0], y[0], z[0],
821             s[1], t[1],  x[1], y[1], z[1],
822             s[2], t[2],  x[2], y[2], z[2],
823             s[3], t[3],  x[3], y[3], z[3],
824             s[4], t[4],  x[4], y[4], z[4]);
825     }
826   glEndList();
827
828
829   /* W -- lid_1 through lid_4 */
830   for (i = 0; i < 4; i++)
831     {
832       GLfloat x1, y1, x2, y2, x3, y3;
833
834       glNewList(lc->lid_1 + i, GL_COMPILE);
835       glShadeModel(GL_SMOOTH);
836
837       x1 = points[(i*5)+1][0] / 255.0L;
838       y1 = points[(i*5)+1][1] / 255.0L;
839       x2 = points[(i*5)][0] / 255.0L;
840       y2 = points[(i*5)][1] / 255.0L;
841       x3 = 0.5;
842       y3 = 0.5;
843
844       /* Outer surface */
845       face3(lc->texids[FACE_W], exterior_color, wire,
846             1.0-x1, y1,         -0.5, x1-0.5, y1-0.5,
847             1.0-x2, y2,         -0.5, x2-0.5, y2-0.5,
848             1.0-x3, y3,         -0.5, x3-0.5, y3-0.5);
849
850       /* Inner surface */
851       face3(0, interior_color, wire,
852             0.0, 0.0,   -0.48, x2-0.5, y2-0.5,
853             0.0, 0.0,   -0.48, x1-0.5, y1-0.5,
854             0.0, 0.0,   -0.48, x3-0.5, y3-0.5);
855
856       /* Lip 1 */
857       face4(0, interior_color, wire,
858             0.0, 0.0,   -0.5,  x1-0.5, y1-0.5,
859             0.0, 0.0,   -0.5,  x3-0.5, y3-0.5,
860             0.0, 0.0,   -0.48, x3-0.5, y3-0.5,
861             0.0, 0.0,   -0.48, x1-0.5, y1-0.5);
862
863       /* Lip 2 */
864       face4(0, interior_color, wire,
865             0.0, 0.0,   -0.48, x2-0.5, y2-0.5,
866             0.0, 0.0,   -0.48, x3-0.5, y3-0.5,
867             0.0, 0.0,   -0.5,  x3-0.5, y3-0.5,
868             0.0, 0.0,   -0.5,  x2-0.5, y2-0.5);
869
870       glEndList();
871     }
872 }
873
874 static void
875 taser(ModeInfo *mi, Bool wire)
876 {
877   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
878   int i;
879
880   int slider_face_points[][2] = {
881     {  86,  58 },{  38, 106 },{  70, 106 },{ 118,  58 },{  -1,  -1 }, /* a */
882     { 136,  58 },{ 184, 106 },{ 216, 106 },{ 168,  58 },{  -1,  -1 }, /* b */
883     {  38, 106 },{   0, 144 },{   0, 190 },{  60, 190 },{ 108, 106 }, /* c */
884     { 144, 106 },{ 194, 190 },{ 254, 190 },{ 254, 144 },{ 216, 106 }, /* d */
885     {  98, 124 },{  60, 190 },{  92, 190 },{ 126, 158 },{ 126, 124 }, /* e */
886     { 126, 124 },{ 126, 158 },{ 160, 190 },{ 194, 190 },{ 154, 124 }, /* f */
887     {  22, 190 },{  22, 254 },{  60, 254 },{  60, 190 },{  -1,  -1 }, /* g */
888     { 194, 190 },{ 194, 254 },{ 230, 254 },{ 230, 190 },{  -1,  -1 }, /* h */
889     {  60, 190 },{  60, 210 },{  92, 210 },{  92, 190 },{  -1,  -1 }, /* i */
890     { 160, 190 },{ 160, 210 },{ 194, 210 },{ 194, 190 },{  -1,  -1 }, /* j */
891     { 110, 172 },{  92, 190 },{ 110, 190 },{  -1,  -1 },{  -1,  -1 }, /* k */
892     { 140, 172 },{ 140, 190 },{ 160, 190 },{  -1,  -1 },{  -1,  -1 }, /* l */
893     { 110, 172 },{ 140, 172 },{ 126, 156 },{  -1,  -1 },{  -1,  -1 }, /* m */
894   };
895
896   int body_face_points[][2] = {
897     {   0,   0 },{   0,  58 },{ 254,  58 },{ 254,   0 },{  -1,  -1 }, /* A */
898     {   0,  58 },{   0, 144 },{  86,  58 },{  -1,  -1 },{  -1,  -1 }, /* B */
899     { 168,  58 },{ 254, 144 },{ 254,  58 },{  -1,  -1 },{  -1,  -1 }, /* C */
900     { 118,  58 },{  70, 106 },{ 184, 106 },{ 136,  58 },{  -1,  -1 }, /* F */
901     { 108, 106 },{  98, 124 },{ 154, 124 },{ 144, 106 },{  -1,  -1 }, /* G */
902   };
903
904   int lifter_face_points[][2] = {
905     {   0, 190 },{   0, 254 },{  22, 254 },{  22, 190 },{  -1,  -1 }, /* D */
906     { 230, 190 },{ 230, 254 },{ 254, 254 },{ 254, 190 },{  -1,  -1 }, /* E */
907     {  60, 210 },{  60, 254 },{ 194, 254 },{ 194, 210 },{  -1,  -1 }, /* H */
908     {  92, 190 },{  92, 210 },{ 160, 210 },{ 160, 190 },{  -1,  -1 }, /* I */
909     { 110, 172 },{ 110, 190 },{ 140, 190 },{ 140, 172 },{  -1,  -1 }, /* J */
910   };
911
912   int body_perimiter_points[][2] = {
913     {   0, 144 },{  86,  59 },{ 119,  58 },{  71, 107 },
914     { 108, 107 },{  98, 124 },{ 155, 124 },{ 144, 107 },
915     { 185, 106 },{ 136,  59 },{ 169,  59 },{ 255, 145 },
916     { 255,   0 },{   0,   0 },
917   };
918
919   int slider_perimiter_points[][2] = {
920     {  86,  58 },{   0,  144 },{   0, 190 },{  22,  190 },{  22, 254 },
921     {  60, 254 },{  60,  210 },{  92, 210 },{  92,  190 },{ 110, 190 },
922     { 110, 172 },{  140, 172 },{ 140, 190 },{ 160,  190 },{ 160, 210 },
923     { 194, 210 },{  194, 254 },{ 230, 254 },{ 230,  190 },{ 254, 190 },
924     { 254, 144 },{  168,  58 },{ 136,  58 },{ 184,  106 },{ 144, 106 },
925     { 154, 124 },{  98,  124 },{ 108, 106 },{  70,  106 },{ 118,  58 },
926   };
927
928   int lifter_perimiter_points_1[][2] = {
929     {   0, 189 },{   0, 254 },{  22, 255 },{  23, 190 },
930   };
931
932   int lifter_perimiter_points_2[][2] = {
933     { 230, 254 },{ 255, 255 },{ 254, 190 },{ 230, 190 },
934   };
935
936   int lifter_perimiter_points_3[][2] = {
937     {  60, 254 },{ 194, 254 },{ 194, 211 },{ 160, 210 },
938     { 160, 190 },{ 140, 191 },{ 141, 172 },{ 111, 172 },
939     { 110, 190 },{ 93, 190 },{ 92, 210 },{ 60, 211 },
940   };
941
942   for (i = 0; i < countof(slider_face_points); i++)
943     slider_face_points[i][1] = 255-slider_face_points[i][1];
944   for (i = 0; i < countof(body_face_points); i++)
945     body_face_points[i][1] = 255-body_face_points[i][1];
946   for (i = 0; i < countof(lifter_face_points); i++)
947     lifter_face_points[i][1] = 255-lifter_face_points[i][1];
948   for (i = 0; i < countof(body_perimiter_points); i++)
949     body_perimiter_points[i][1] = 255-body_perimiter_points[i][1];
950   for (i = 0; i < countof(slider_perimiter_points); i++)
951     slider_perimiter_points[i][1] = 255-slider_perimiter_points[i][1];
952   for (i = 0; i < countof(lifter_perimiter_points_1); i++)
953     lifter_perimiter_points_1[i][1] = 255-lifter_perimiter_points_1[i][1];
954   for (i = 0; i < countof(lifter_perimiter_points_2); i++)
955     lifter_perimiter_points_2[i][1] = 255-lifter_perimiter_points_2[i][1];
956   for (i = 0; i < countof(lifter_perimiter_points_3); i++)
957     lifter_perimiter_points_3[i][1] = 255-lifter_perimiter_points_3[i][1];
958
959   /* -------------------------------------------------------------------- */
960
961   glNewList(lc->taser_base, GL_COMPILE);
962   glShadeModel(GL_SMOOTH);
963
964   /* N */
965   face4(lc->texids[FACE_N], exterior_color, wire,
966         0.0, 0.0,       -0.5,  0.5,  0.5,
967         0.75, 0.0,       0.25, 0.5,  0.5,
968         0.75, 0.75,      0.25, 0.5, -0.25,
969         0.0, 0.75,      -0.5,  0.5, -0.25);
970
971   /* S */
972   face4(lc->texids[FACE_S], exterior_color, wire,
973         0.0,  0.25,     -0.5,  -0.5, -0.25,
974         0.75, 0.25,      0.25, -0.5, -0.25,
975         0.75, 1.0,       0.25, -0.5,  0.5,
976         0.0,  1.0,      -0.5,  -0.5,  0.5);
977
978   /* interior E */
979   face4(0, interior_color, wire,
980         0.0, 0.0,        0.25, -0.5, -0.25,
981         1.0, 0.0,        0.25,  0.5, -0.25,
982         1.0, 1.0,        0.25,  0.5,  0.5,
983         0.0, 1.0,        0.25, -0.5,  0.5);
984
985   /* W */
986   face4(lc->texids[FACE_W], exterior_color, wire,
987         1.0, 1.0,       -0.5, -0.5,  0.5,
988         0.0, 1.0,       -0.5,  0.5,  0.5,
989         0.0, 0.25,      -0.5,  0.5, -0.25,
990         1.0, 0.25,      -0.5, -0.5, -0.25);
991
992   /* U */
993   face4(lc->texids[FACE_U], exterior_color, wire,
994         0.75, 0.0,       0.25, -0.5,  0.5,
995         0.75, 1.0,       0.25,  0.5,  0.5,
996         0.0, 1.0,       -0.5,   0.5,  0.5,
997         0.0, 0.0,       -0.5,  -0.5,  0.5);
998
999   /* interior D */
1000   face4(0, interior_color, wire,
1001         0.0, 1.0,       -0.5,  -0.5, -0.25,
1002         0.0, 0.0,       -0.5,   0.5, -0.25,
1003         1.0, 0.0,        0.25,  0.5, -0.25,
1004         1.0, 1.0,        0.25, -0.5, -0.25);
1005
1006   /* Top face */
1007   for (i = 0; i < countof(body_face_points)/5; i++)
1008     {
1009       int j;
1010 #ifdef HAVE_GLBINDTEXTURE
1011       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1012 #endif /* HAVE_GLBINDTEXTURE */
1013       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1014
1015       do_normal(0, body_face_points[(i*5)+0][0], body_face_points[(i*5)+0][1],
1016                 0, body_face_points[(i*5)+1][0], body_face_points[(i*5)+1][1],
1017                 0, body_face_points[(i*5)+2][0], body_face_points[(i*5)+2][1]
1018                 );
1019       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1020       for (j = 0; j < 5; j++)
1021         {
1022           int ix = body_face_points[(i*5)+j][0];
1023           int iy = body_face_points[(i*5)+j][1];
1024           GLfloat x, y;
1025           if (ix == -1)  /* these are padding: ignore them */
1026             continue;
1027           x = ix / 255.0L;
1028           y = iy / 255.0L;
1029           glTexCoord2f(x, y);
1030           glVertex3f(0.5, x-0.5, y-0.5);
1031         }
1032       glEnd();
1033     }
1034
1035   /* Side walls */
1036   for (i = 0; i < countof(body_perimiter_points); i++)
1037     {
1038       int j = (i+1 >= countof(body_perimiter_points) ? 0 : i+1);
1039       GLfloat x1 = body_perimiter_points[i][0] / 255.0;
1040       GLfloat y1 = body_perimiter_points[i][1] / 255.0;
1041       GLfloat x2 = body_perimiter_points[j][0] / 255.0;
1042       GLfloat y2 = body_perimiter_points[j][1] / 255.0;
1043       int texture = -1;
1044       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1045
1046       if (i == 11)
1047         {
1048           texture = lc->texids[FACE_N];
1049           s1 = 1.0;  t1 = 0.0;
1050           s2 = 1.0;  t2 = 0.568;
1051           s3 = 0.75, t3 = 0.568;
1052           s4 = 0.75; t4 = 0.0;
1053         }
1054       else if (i == 12)
1055         {
1056           texture = lc->texids[FACE_U];
1057           s1 = 1.0;  t1 = 0.0;
1058           s2 = 1.0;  t2 = 1.0;
1059           s3 = 0.75, t3 = 1.0;
1060           s4 = 0.75; t4 = 0.0;
1061         }
1062       else if (i == 13)
1063         {
1064           texture = lc->texids[FACE_S];
1065           s1 = 1.0;  t1 = 0.437;
1066           s2 = 1.0;  t2 = 1.0;
1067           s3 = 0.75; t3 = 1.0;
1068           s4 = 0.75; t4 = 0.437;
1069         }
1070
1071       face4((texture == -1 ? 0 : texture),
1072             (texture == -1 ? interior_color : exterior_color),
1073             wire,
1074             s1, t1,  0.5,  x2-0.5, y2-0.5,
1075             s2, t2,  0.5,  x1-0.5, y1-0.5,
1076             s3, t3,  0.25, x1-0.5, y1-0.5,
1077             s4, t4,  0.25, x2-0.5, y2-0.5);
1078     }
1079
1080   glEndList();
1081
1082   /* -------------------------------------------------------------------- */
1083
1084   glNewList(lc->taser_lifter, GL_COMPILE);
1085   glShadeModel(GL_SMOOTH);
1086
1087   /* N */
1088   face4(lc->texids[FACE_N], exterior_color, wire,
1089         0.0,  0.75,     -0.5,  0.5, -0.25,
1090         0.75, 0.75,      0.25, 0.5, -0.25,
1091         0.75, 1.0,       0.25, 0.5, -0.5,
1092         0.0,  1.0,      -0.5,  0.5, -0.5);
1093
1094   /* S */
1095   face4(lc->texids[FACE_S], exterior_color, wire,
1096         0.0,  0.0,      -0.5,  -0.5, -0.5,
1097         0.75, 0.0,       0.25, -0.5, -0.5,
1098         0.75, 0.25,      0.25, -0.5, -0.25,
1099         0.0,  0.25,     -0.5,  -0.5, -0.25);
1100
1101   /* interior E */
1102   face4(0, interior_color, wire,
1103         0.0, 1.0,        0.25, -0.5, -0.5,
1104         1.0, 1.0,        0.25,  0.5, -0.5,
1105         1.0, 0.0,        0.25,  0.5, -0.25,
1106         0.0, 0.0,        0.25, -0.5, -0.25);
1107
1108   /* W */
1109   face4(lc->texids[FACE_W], exterior_color, wire,
1110         1.0, 0.25,      -0.5, -0.5, -0.25,
1111         0.0, 0.25,      -0.5,  0.5, -0.25,
1112         0.0, 0.0,       -0.5,  0.5, -0.5,
1113         1.0, 0.0,       -0.5, -0.5, -0.5);
1114
1115   /* interior U */
1116   face4(0, interior_color, wire,
1117         1.0, 0.0,        0.25, -0.5,  -0.25,
1118         1.0, 1.0,        0.25,  0.5,  -0.25,
1119         0.0, 1.0,       -0.5,   0.5,  -0.25,
1120         0.0, 0.0,       -0.5,  -0.5,  -0.25);
1121
1122   /* D */
1123   face4(lc->texids[FACE_D], exterior_color, wire,
1124         0.0, 1.0,       -0.5, -0.5, -0.5,
1125         0.0, 0.0,       -0.5,  0.5, -0.5,
1126         0.75, 0.0,       0.25,  0.5, -0.5,
1127         0.75, 1.0,       0.25, -0.5, -0.5);
1128
1129
1130   /* Top face */
1131   for (i = 0; i < countof(lifter_face_points)/5; i++)
1132     {
1133       int j;
1134
1135 #ifdef HAVE_GLBINDTEXTURE
1136       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1137 #endif /* HAVE_GLBINDTEXTURE */
1138       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1139
1140       do_normal(
1141          0, lifter_face_points[(i*5)+0][0], lifter_face_points[(i*5)+0][1],
1142          0, lifter_face_points[(i*5)+1][0], lifter_face_points[(i*5)+1][1],
1143          0, lifter_face_points[(i*5)+2][0], lifter_face_points[(i*5)+2][1]);
1144
1145       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1146       for (j = 0; j < 5; j++)
1147         {
1148           int ix = lifter_face_points[(i*5)+j][0];
1149           int iy = lifter_face_points[(i*5)+j][1];
1150           GLfloat x, y;
1151           if (ix == -1)  /* these are padding: ignore them */
1152             continue;
1153           x = ix / 255.0L;
1154           y = iy / 255.0L;
1155           glTexCoord2f(x, y);
1156           glVertex3f(0.5, x-0.5, y-0.5);
1157         }
1158       glEnd();
1159     }
1160
1161   /* Side walls */
1162   for (i = 0; i < countof(lifter_perimiter_points_1); i++)
1163     {
1164       int j = (i+1 >= countof(lifter_perimiter_points_1) ? 0 : i+1);
1165       GLfloat x1 = lifter_perimiter_points_1[i][0] / 255.0;
1166       GLfloat y1 = lifter_perimiter_points_1[i][1] / 255.0;
1167       GLfloat x2 = lifter_perimiter_points_1[j][0] / 255.0;
1168       GLfloat y2 = lifter_perimiter_points_1[j][1] / 255.0;
1169       int texture = -1;
1170       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1171
1172       if (i == 0)
1173         {
1174           texture = lc->texids[FACE_S];
1175           s1 = 1.0;  t1 = 0.0;
1176           s2 = 1.0;  t2 = 0.26;
1177           s3 = 0.75, t3 = 0.26;
1178           s4 = 0.75; t4 = 0.0;
1179         }
1180       else if (i == 1)
1181         {
1182           texture = lc->texids[FACE_D];
1183           s1 = 1.0;  t1 = 0.914;
1184           s2 = 1.0;  t2 = 1.0;
1185           s3 = 0.75; t3 = 1.0;
1186           s4 = 0.75; t4 = 0.914;
1187         }
1188
1189       face4((texture == -1 ? 0 : texture),
1190             (texture == -1 ? interior_color : exterior_color),
1191             wire,
1192             s1, t1,  0.5,  x2-0.5, y2-0.5,
1193             s2, t2,  0.5,  x1-0.5, y1-0.5,
1194             s3, t3,  0.25, x1-0.5, y1-0.5,
1195             s4, t4,  0.25, x2-0.5, y2-0.5);
1196     }
1197
1198   for (i = 0; i < countof(lifter_perimiter_points_2); i++)
1199     {
1200       int j = (i+1 >= countof(lifter_perimiter_points_2) ? 0 : i+1);
1201       GLfloat x1 = lifter_perimiter_points_2[i][0] / 255.0;
1202       GLfloat y1 = lifter_perimiter_points_2[i][1] / 255.0;
1203       GLfloat x2 = lifter_perimiter_points_2[j][0] / 255.0;
1204       GLfloat y2 = lifter_perimiter_points_2[j][1] / 255.0;
1205       int texture = -1;
1206       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1207
1208       if (i == 0)
1209         {
1210           texture = lc->texids[FACE_D];
1211           s1 = 1.0;  t1 = 0.0;
1212           s2 = 1.0;  t2 = 0.095;
1213           s3 = 0.75; t3 = 0.095;
1214           s4 = 0.75; t4 = 0.0;
1215         }
1216       else if (i == 1)
1217         {
1218           texture = lc->texids[FACE_N];
1219           s1 = 1.0;  t1 = 0.745;
1220           s2 = 1.0;  t2 = 1.0;
1221           s3 = 0.75; t3 = 1.0;
1222           s4 = 0.75; t4 = 0.745;
1223         }
1224
1225       face4((texture == -1 ? 0 : texture),
1226             (texture == -1 ? interior_color : exterior_color),
1227             wire,
1228             s1, t1,  0.5,  x2-0.5, y2-0.5,
1229             s2, t2,  0.5,  x1-0.5, y1-0.5,
1230             s3, t3,  0.25, x1-0.5, y1-0.5,
1231             s4, t4,  0.25, x2-0.5, y2-0.5);
1232     }
1233
1234   for (i = 0; i < countof(lifter_perimiter_points_3); i++)
1235     {
1236       int j = (i+1 >= countof(lifter_perimiter_points_3) ? 0 : i+1);
1237       GLfloat x1 = lifter_perimiter_points_3[i][0] / 255.0;
1238       GLfloat y1 = lifter_perimiter_points_3[i][1] / 255.0;
1239       GLfloat x2 = lifter_perimiter_points_3[j][0] / 255.0;
1240       GLfloat y2 = lifter_perimiter_points_3[j][1] / 255.0;
1241       int texture = -1;
1242       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1243
1244       if (i == 0)
1245         {
1246           texture = lc->texids[FACE_D];
1247           s1 = 1.0;  t1 = 0.235;
1248           s2 = 1.0;  t2 = 0.765;
1249           s3 = 0.75; t3 = 0.765;
1250           s4 = 0.75; t4 = 0.235;
1251         }
1252
1253       face4((texture == -1 ? 0 : texture),
1254             (texture == -1 ? interior_color : exterior_color),
1255             wire,
1256             s1, t1,  0.5,  x2-0.5, y2-0.5,
1257             s2, t2,  0.5,  x1-0.5, y1-0.5,
1258             s3, t3,  0.25, x1-0.5, y1-0.5,
1259             s4, t4,  0.25, x2-0.5, y2-0.5);
1260     }
1261
1262   glEndList();
1263
1264   /* -------------------------------------------------------------------- */
1265
1266   glNewList(lc->taser_slider, GL_COMPILE);
1267   glShadeModel(GL_SMOOTH);
1268
1269   /* Top face */
1270   for (i = 0; i < countof(slider_face_points)/5; i++)
1271     {
1272       int j;
1273 #ifdef HAVE_GLBINDTEXTURE
1274       glBindTexture(GL_TEXTURE_2D, lc->texids[FACE_E]);
1275 #endif /* HAVE_GLBINDTEXTURE */
1276       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1277
1278       do_normal(
1279            0, slider_face_points[(i*5)+0][0], slider_face_points[(i*5)+0][1],
1280            0, slider_face_points[(i*5)+1][0], slider_face_points[(i*5)+1][1],
1281            0, slider_face_points[(i*5)+2][0], slider_face_points[(i*5)+2][1]);
1282       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1283       for (j = 0; j < 5; j++)
1284         {
1285           int ix = slider_face_points[(i*5)+j][0];
1286           int iy = slider_face_points[(i*5)+j][1];
1287           GLfloat x, y;
1288           if (ix == -1)  /* these are padding: ignore them */
1289             continue;
1290           x = ix / 255.0L;
1291           y = iy / 255.0L;
1292           glTexCoord2f(x, y);
1293           glVertex3f(0.5, x-0.5, y-0.5);
1294         }
1295       glEnd();
1296     }
1297
1298   /* Bottom face */
1299   for (i = countof(slider_face_points)/5 - 1; i >= 0; i--)
1300     {
1301       int j;
1302 #ifdef HAVE_GLBINDTEXTURE
1303       glBindTexture(GL_TEXTURE_2D, 0);
1304 #endif /* HAVE_GLBINDTEXTURE */
1305       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, interior_color);
1306
1307       do_normal(
1308            0, slider_face_points[(i*5)+2][0], slider_face_points[(i*5)+2][1],
1309            0, slider_face_points[(i*5)+1][0], slider_face_points[(i*5)+1][1],
1310            0, slider_face_points[(i*5)+0][0], slider_face_points[(i*5)+0][1]);
1311       glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
1312       for (j = 4; j >= 0; j--)
1313         {
1314           int ix = slider_face_points[(i*5)+j][0];
1315           int iy = slider_face_points[(i*5)+j][1];
1316           GLfloat x, y;
1317           if (ix == -1)  /* these are padding: ignore them */
1318             continue;
1319           x = ix / 255.0L;
1320           y = iy / 255.0L;
1321           glTexCoord2f(x, y);
1322           glVertex3f(0.25, x-0.5, y-0.5);
1323         }
1324       glEnd();
1325     }
1326
1327   /* Side walls */
1328   for (i = 0; i < countof(slider_perimiter_points); i++)
1329     {
1330       int j = (i+1 >= countof(slider_perimiter_points) ? 0 : i+1);
1331       GLfloat x1 = slider_perimiter_points[i][0] / 255.0;
1332       GLfloat y1 = slider_perimiter_points[i][1] / 255.0;
1333       GLfloat x2 = slider_perimiter_points[j][0] / 255.0;
1334       GLfloat y2 = slider_perimiter_points[j][1] / 255.0;
1335       int texture = -1;
1336       GLfloat s1=0, t1=0, s2=0, t2=0, s3=0, t3=0, s4=0, t4=0;
1337
1338       if (i == 1)
1339         {
1340           texture = lc->texids[FACE_S];
1341           s1 = 1.0;  t1 = 0.255;
1342           s2 = 1.0;  t2 = 0.435;
1343           s3 = 0.75; t3 = 0.435;
1344           s4 = 0.75; t4 = 0.255;
1345         }
1346       else if (i == 4)
1347         {
1348           texture = lc->texids[FACE_D];
1349           s1 = 1.0;  t1 = 0.758;
1350           s2 = 1.0;  t2 = 0.915;
1351           s3 = 0.75; t3 = 0.915;
1352           s4 = 0.75; t4 = 0.758;
1353         }
1354       else if (i == 16)
1355         {
1356           texture = lc->texids[FACE_D];
1357           s1 = 1.0;  t1 = 0.095;
1358           s2 = 1.0;  t2 = 0.24;
1359           s3 = 0.75; t3 = 0.24;
1360           s4 = 0.75; t4 = 0.095;
1361         }
1362       else if (i == 19)
1363         {
1364           texture = lc->texids[FACE_N];
1365           s1 = 1.0;  t1 = 0.568;
1366           s2 = 1.0;  t2 = 0.742;
1367           s3 = 0.75; t3 = 0.742;
1368           s4 = 0.75; t4 = 0.568;
1369         }
1370
1371       face4((texture == -1 ? 0 : texture),
1372             (texture == -1 ? interior_color : exterior_color),
1373             wire,
1374             s1, t1,  0.5,  x2-0.5, y2-0.5,
1375             s2, t2,  0.5,  x1-0.5, y1-0.5,
1376             s3, t3,  0.25, x1-0.5, y1-0.5,
1377             s4, t4,  0.25, x2-0.5, y2-0.5);
1378     }
1379
1380   glEndList();
1381 }
1382
1383
1384 \f
1385 /* Rendering and animating object models
1386  */
1387
1388 static void
1389 draw(ModeInfo *mi)
1390 {
1391   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1392   Bool wire = MI_IS_WIREFRAME(mi);
1393
1394   if (!wire)
1395     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1396   else
1397     glClear(GL_COLOR_BUFFER_BIT);
1398
1399   glPushMatrix();
1400   {
1401     GLfloat x = lc->rotx;
1402     GLfloat y = lc->roty;
1403     GLfloat z = lc->rotz;
1404
1405 #if 0
1406  x=0.75; y=0; z=0; 
1407 #endif
1408
1409     if (x < 0) x = 1 - (x + 1);
1410     if (y < 0) y = 1 - (y + 1);
1411     if (z < 0) z = 1 - (z + 1);
1412
1413     /* Make into the screen be +Y right be +X, and up be +Z. */
1414     glRotatef(-90.0, 1.0, 0.0, 0.0);
1415
1416     /* Scale it up. */
1417     glScalef(4.0, 4.0, 4.0);
1418
1419 #ifdef DEBUG
1420     glPushMatrix();
1421     {
1422       /* Shift to the upper left, and draw the vanilla box. */
1423       glTranslatef(-0.6, 0.0, 0.6);
1424
1425       /* Apply rotation to the object. */
1426       glRotatef(x * 360, 1.0, 0.0, 0.0);
1427       glRotatef(y * 360, 0.0, 1.0, 0.0);
1428       glRotatef(z * 360, 0.0, 0.0, 1.0);
1429
1430       /* Draw it. */
1431       glCallList(lc->box);
1432     }
1433     glPopMatrix();
1434
1435     /* Shift to the lower right, and draw the animated object. */
1436     glTranslatef(0.6, 0.0, -0.6);
1437 #endif /* DEBUG */
1438
1439
1440     glPushMatrix();
1441     {
1442       /* Apply rotation to the object. */
1443       glRotatef(x * 360, 1.0, 0.0, 0.0);
1444       glRotatef(y * 360, 0.0, 1.0, 0.0);
1445       glRotatef(z * 360, 0.0, 0.0, 1.0);
1446
1447       switch (lc->type)
1448         {
1449         case LAMENT_BOX:
1450           glCallList(lc->box);
1451           break;
1452
1453         case LAMENT_STAR_OUT:
1454         case LAMENT_STAR_ROT:
1455         case LAMENT_STAR_ROT_IN:
1456         case LAMENT_STAR_ROT_OUT:
1457         case LAMENT_STAR_UNROT:
1458         case LAMENT_STAR_IN:
1459           glTranslatef(0.0, 0.0, lc->anim_z/2);
1460           glRotatef(lc->anim_r/2, 0.0, 0.0, 1.0);
1461           glCallList(lc->star1);
1462
1463           glTranslatef(0.0, 0.0, -lc->anim_z);
1464           glRotatef(-lc->anim_r, 0.0, 0.0, 1.0);
1465           glCallList(lc->star2);
1466           break;
1467
1468         case LAMENT_TETRA_UNE:
1469         case LAMENT_TETRA_USW:
1470         case LAMENT_TETRA_DWN:
1471         case LAMENT_TETRA_DSE:
1472           {
1473             int magic;
1474             GLfloat x, y, z;
1475             switch (lc->type) {
1476             case LAMENT_TETRA_UNE: magic = lc->tetra_une;
1477               x = 1.0; y = 1.0; z = 1.0; break;
1478             case LAMENT_TETRA_USW: magic = lc->tetra_usw;
1479               x = 1.0; y = 1.0; z = -1.0; break;
1480             case LAMENT_TETRA_DWN: magic = lc->tetra_dwn;
1481               x = 1.0; y = -1.0; z = 1.0; break;
1482             case LAMENT_TETRA_DSE: magic = lc->tetra_dse;
1483               x = -1.0; y = 1.0; z = 1.0; break;
1484             default: abort(); break;
1485             }
1486             glCallList(lc->tetra_mid);
1487             if (magic != lc->tetra_une) glCallList(lc->tetra_une);
1488             if (magic != lc->tetra_usw) glCallList(lc->tetra_usw);
1489             if (magic != lc->tetra_dwn) glCallList(lc->tetra_dwn);
1490             if (magic != lc->tetra_dse) glCallList(lc->tetra_dse);
1491             glRotatef(lc->anim_r, x, y, z);
1492             glCallList(magic);
1493           }
1494           break;
1495
1496         case LAMENT_LID_OPEN:
1497         case LAMENT_LID_CLOSE:
1498         case LAMENT_LID_ZOOM:
1499           {
1500             GLfloat d = 0.417;
1501
1502             glTranslatef(lc->anim_z, 0.0, 0.0);
1503
1504             glCallList(lc->lid_0);
1505
1506             glPushMatrix();
1507               glTranslatef(-0.5, -d, 0.0);
1508               glRotatef(-lc->anim_r, 0.0, -1.0, -1.0);
1509               glTranslatef( 0.5,  d, 0.0);
1510               glCallList(lc->lid_1);
1511             glPopMatrix();
1512             glPushMatrix();
1513               glTranslatef(-0.5, -d, 0.0);
1514               glRotatef( lc->anim_r, 0.0, -1.0,   1.0);
1515               glTranslatef( 0.5,  d, 0.0);
1516               glCallList(lc->lid_2);
1517             glPopMatrix();
1518             glPushMatrix();
1519               glTranslatef(-0.5,  d, 0.0);
1520               glRotatef( lc->anim_r, 0.0,  -1.0,  -1.0);
1521               glTranslatef( 0.5, -d, 0.0);
1522               glCallList(lc->lid_3);
1523             glPopMatrix();
1524             glPushMatrix();
1525               glTranslatef(-0.5,  d, 0.0);
1526               glRotatef(-lc->anim_r, 0.0,  -1.0,   1.0);
1527               glTranslatef( 0.5, -d, 0.0);
1528               glCallList(lc->lid_4);
1529             glPopMatrix();
1530           }
1531           break;
1532
1533         case LAMENT_TASER_OUT:
1534         case LAMENT_TASER_SLIDE:
1535         case LAMENT_TASER_SLIDE_IN:
1536         case LAMENT_TASER_IN:
1537
1538           glTranslatef(-lc->anim_z/2, 0.0, 0.0);
1539           glCallList(lc->taser_base);
1540
1541           glTranslatef(lc->anim_z, 0.0, 0.0);
1542           glCallList(lc->taser_lifter);
1543
1544           glTranslatef(0.0, 0.0, lc->anim_y);
1545           glCallList(lc->taser_slider);
1546           break;
1547
1548         default:
1549           abort();
1550           break;
1551         }
1552     }
1553     glPopMatrix();
1554
1555   }
1556   glPopMatrix();
1557 }
1558
1559
1560 static void
1561 animate(ModeInfo *mi)
1562 {
1563   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1564   int pause = 10;
1565 /*  int pause2 = 60;*/
1566   int pause3 = 120;
1567
1568   switch (lc->type)
1569     {
1570     case LAMENT_BOX:
1571       {
1572         /* Rather than just picking states randomly, pick an ordering randomly,
1573            do it, and then re-randomize.  That way one can be assured of seeing
1574            all states in a short time period, though not always in the same
1575            order (it's frustrating to see it pick the same state 5x in a row.)
1576          */
1577         static lament_type states[] = {
1578           LAMENT_STAR_OUT, LAMENT_STAR_OUT,
1579           LAMENT_TETRA_UNE, LAMENT_TETRA_USW,
1580           LAMENT_TETRA_DWN, LAMENT_TETRA_DSE,
1581           LAMENT_LID_OPEN, LAMENT_LID_OPEN, LAMENT_LID_OPEN,
1582           LAMENT_TASER_OUT, LAMENT_TASER_OUT,
1583           LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
1584           LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX, LAMENT_BOX,
1585         };
1586         static int state = countof(states);
1587
1588         if (state < countof(states))
1589           {
1590             lc->type = states[state++];
1591           }
1592         else
1593           {
1594             int i;
1595             state = 0;
1596             for (i = 0; i < countof(states); i++)
1597               {
1598                 int a = random() % countof(states);
1599                 lament_type swap = states[a];
1600                 states[a] = states[i];
1601                 states[i] = swap;
1602               }
1603           }
1604
1605         if (lc->type == LAMENT_BOX)
1606           lc->anim_pause = pause3;
1607
1608         lc->anim_r = 0.0;
1609         lc->anim_y = 0.0;
1610         lc->anim_z = 0.0;
1611       }
1612       break;
1613
1614       /* -------------------------------------------------------------- */
1615
1616     case LAMENT_STAR_OUT:
1617       lc->anim_z += 0.01;
1618       if (lc->anim_z >= 1.0)
1619         {
1620           lc->anim_z = 1.0;
1621           lc->type = LAMENT_STAR_ROT;
1622           lc->anim_pause = pause;
1623         }
1624       break;
1625
1626     case LAMENT_STAR_ROT:
1627       lc->anim_r += 1.0;
1628       if (lc->anim_r >= 45.0)
1629         {
1630           lc->anim_r = 45.0;
1631           lc->type = LAMENT_STAR_ROT_IN;
1632           lc->anim_pause = pause;
1633         }
1634       break;
1635
1636     case LAMENT_STAR_ROT_IN:
1637       lc->anim_z -= 0.01;
1638       if (lc->anim_z <= 0.0)
1639         {
1640           lc->anim_z = 0.0;
1641           lc->type = LAMENT_STAR_ROT_OUT;
1642           lc->anim_pause = pause3 * (1 + (random() % 4) + (random() % 4));
1643         }
1644       break;
1645
1646     case LAMENT_STAR_ROT_OUT:
1647       lc->anim_z += 0.01;
1648       if (lc->anim_z >= 1.0)
1649         {
1650           lc->anim_z = 1.0;
1651           lc->type = LAMENT_STAR_UNROT;
1652           lc->anim_pause = pause;
1653         }
1654       break;
1655       
1656     case LAMENT_STAR_UNROT:
1657       lc->anim_r -= 1.0;
1658       if (lc->anim_r <= 0.0)
1659         {
1660           lc->anim_r = 0.0;
1661           lc->type = LAMENT_STAR_IN;
1662           lc->anim_pause = pause;
1663         }
1664       break;
1665
1666     case LAMENT_STAR_IN:
1667       lc->anim_z -= 0.01;
1668       if (lc->anim_z <= 0.0)
1669         {
1670           lc->anim_z = 0.0;
1671           lc->type = LAMENT_BOX;
1672           lc->anim_pause = pause3;
1673         }
1674       break;
1675
1676       /* -------------------------------------------------------------- */
1677
1678     case LAMENT_TETRA_UNE:
1679     case LAMENT_TETRA_USW:
1680     case LAMENT_TETRA_DWN:
1681     case LAMENT_TETRA_DSE:
1682
1683       lc->anim_r += 1.0;
1684       if (lc->anim_r >= 360.0)
1685         {
1686           lc->anim_r = 0.0;
1687           lc->type = LAMENT_BOX;
1688           lc->anim_pause = pause3;
1689         }
1690       else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1691         {
1692           lc->anim_r = 120.0;
1693           lc->anim_pause = pause;
1694         }
1695       else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1696         {
1697           lc->anim_r = 240.0;
1698           lc->anim_pause = pause;
1699         }
1700       break;
1701
1702       /* -------------------------------------------------------------- */
1703
1704     case LAMENT_LID_OPEN:
1705       lc->anim_r += 1.0;
1706
1707       if (lc->anim_r >= 112.0)
1708         {
1709           GLfloat hysteresis = 0.05;
1710
1711           lc->anim_r = 112.0;
1712           lc->anim_z = 0.0;
1713           lc->anim_pause = pause3;
1714
1715           if (lc->rotx >= -hysteresis &&
1716               lc->rotx <=  hysteresis &&
1717               ((lc->rotz >=  (0.25 - hysteresis) &&
1718                 lc->rotz <=  (0.25 + hysteresis)) ||
1719                (lc->rotz >= (-0.25 - hysteresis) &&
1720                 lc->rotz <= (-0.25 + hysteresis))))
1721             {
1722               lc->type = LAMENT_LID_ZOOM;
1723               lc->rotx = 0.00;
1724               lc->rotz = (lc->rotz < 0 ? -0.25 : 0.25);
1725             }
1726           else
1727             {
1728               lc->type = LAMENT_LID_CLOSE;
1729             }
1730         }
1731       break;
1732
1733     case LAMENT_LID_CLOSE:
1734       lc->anim_r -= 1.0;
1735       if (lc->anim_r <= 0.0)
1736         {
1737           lc->anim_r = 0.0;
1738           lc->type = LAMENT_BOX;
1739           lc->anim_pause = pause3;
1740         }
1741       break;
1742
1743     case LAMENT_LID_ZOOM:
1744       lc->anim_z -= 0.1;
1745       if (lc->anim_z < -50.0)
1746         {
1747           lc->anim_r = 0.0;
1748           lc->anim_z = 0.0;
1749           lc->rotx = frand(1.0) * RANDSIGN();
1750           lc->roty = frand(1.0) * RANDSIGN();
1751           lc->rotz = frand(1.0) * RANDSIGN();
1752           lc->type = LAMENT_BOX;
1753         }
1754       break;
1755
1756       /* -------------------------------------------------------------- */
1757
1758     case LAMENT_TASER_OUT:
1759       lc->anim_z += 0.0025;
1760       if (lc->anim_z >= 0.25)
1761         {
1762           lc->anim_z = 0.25;
1763           lc->type = LAMENT_TASER_SLIDE;
1764           lc->anim_pause = pause * (1 + (random() % 5) + (random() % 5));
1765         }
1766       break;
1767
1768     case LAMENT_TASER_SLIDE:
1769       lc->anim_y += 0.0025;
1770       if (lc->anim_y >= 0.23)
1771         {
1772           lc->anim_y = 0.23;
1773           lc->type = LAMENT_TASER_SLIDE_IN;
1774           lc->anim_pause = pause3 * (1 + (random() % 5) + (random() % 5));
1775         }
1776       break;
1777
1778     case LAMENT_TASER_SLIDE_IN:
1779       lc->anim_y -= 0.0025;
1780       if (lc->anim_y <= 0.0)
1781         {
1782           lc->anim_y = 0.0;
1783           lc->type = LAMENT_TASER_IN;
1784           lc->anim_pause = pause;
1785         }
1786       break;
1787
1788     case LAMENT_TASER_IN:
1789       lc->anim_z -= 0.0025;
1790       if (lc->anim_z <= 0.0)
1791         {
1792           lc->anim_z = 0.0;
1793           lc->type = LAMENT_BOX;
1794           lc->anim_pause = pause3;
1795         }
1796       break;
1797
1798     default:
1799       abort();
1800       break;
1801     }
1802 }
1803
1804
1805 static void
1806 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
1807 {
1808   double ppos = *pos;
1809
1810   /* tick position */
1811   if (ppos < 0)
1812     ppos = -(ppos + *v);
1813   else
1814     ppos += *v;
1815
1816   if (ppos > 1.0)
1817     ppos -= 1.0;
1818   else if (ppos < 0)
1819     ppos += 1.0;
1820
1821   if (ppos < 0) abort();
1822   if (ppos > 1.0) abort();
1823   *pos = (*pos > 0 ? ppos : -ppos);
1824
1825   /* accelerate */
1826   *v += *dv;
1827
1828   /* clamp velocity */
1829   if (*v > max_v || *v < -max_v)
1830     {
1831       *dv = -*dv;
1832     }
1833   /* If it stops, start it going in the other direction. */
1834   else if (*v < 0)
1835     {
1836       if (random() % 4)
1837         {
1838           *v = 0;
1839
1840           /* keep going in the same direction */
1841           if (random() % 2)
1842             *dv = 0;
1843           else if (*dv < 0)
1844             *dv = -*dv;
1845         }
1846       else
1847         {
1848           /* reverse gears */
1849           *v = -*v;
1850           *dv = -*dv;
1851           *pos = -*pos;
1852         }
1853     }
1854
1855   /* Alter direction of rotational acceleration randomly. */
1856   if (! (random() % 120))
1857     *dv = -*dv;
1858
1859   /* Change acceleration very occasionally. */
1860   if (! (random() % 200))
1861     {
1862       if (*dv == 0)
1863         *dv = 0.00001;
1864       else if (random() & 1)
1865         *dv *= 1.2;
1866       else
1867         *dv *= 0.8;
1868     }
1869 }
1870
1871
1872 \f
1873 /* Window management, etc
1874  */
1875
1876 static void
1877 reshape(int width, int height)
1878 {
1879   int target_size = 180;
1880   int win_size = (width > height ? height : width);
1881   GLfloat h = (GLfloat) height / (GLfloat) width;
1882
1883   glViewport(0, 0, (GLint) width, (GLint) height);
1884
1885 /*  glViewport(-600, -600, 1800, 1800); */
1886
1887   glMatrixMode(GL_PROJECTION);
1888   glLoadIdentity();
1889   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1890   glMatrixMode(GL_MODELVIEW);
1891   glLoadIdentity();
1892   glTranslatef(0.0, 0.0, -40.0);
1893
1894   /* This scale makes the box take up most of the window */
1895   glScalef(2.0, 2.0, 2.0);
1896
1897   /* But if the window is more than a little larger than our target size,
1898      scale the object back down, so that the bits drawn on the screen end
1899      up rougly target_size across (actually it ends up a little larger.)
1900      Note that the image-map bits we have are 128x128.  Therefore, if the
1901      image is magnified a lot, it looks pretty blocky.  So it's better to
1902      have a 128x128 animation on a 1280x1024 screen that looks good, than
1903      a 1024x1024 animation that looks really pixellated.
1904    */
1905   if (win_size > target_size * 1.5)
1906     {
1907       GLfloat ratio = ((GLfloat) target_size / (GLfloat) win_size);
1908       ratio *= 2.0;
1909       glScalef(ratio, ratio, ratio);
1910     }
1911
1912   /* The depth buffer will be cleared, if needed, before the
1913    * next frame.  Right now we just want to black the screen.
1914    */
1915   glClear(GL_COLOR_BUFFER_BIT);
1916 }
1917
1918
1919 static void
1920 gl_init(ModeInfo *mi)
1921 {
1922   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1923   Bool wire = MI_IS_WIREFRAME(mi);
1924
1925   if (wire)
1926     do_texture = False;
1927
1928   if (!wire)
1929     {
1930       static GLfloat pos0[]  = { -4.0, 2.0, 5.0, 1.0 };
1931       static GLfloat pos1[]  = { 12.0, 5.0, 1.0, 1.0 };
1932       static GLfloat local[] = { 0.0 };
1933       static GLfloat ambient[] = { 0.3, 0.3, 0.3, 1.0 };
1934       static GLfloat spec[] = { 1.0, 1.0, 1.0, 1.0 };
1935       static GLfloat shine[] = { 100.0 };
1936
1937       glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1938       glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1939
1940       glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
1941       glLightfv(GL_LIGHT1, GL_AMBIENT, ambient);
1942
1943       glLightfv(GL_LIGHT0, GL_SPECULAR, spec);
1944       glLightfv(GL_LIGHT1, GL_SPECULAR, spec);
1945
1946       glLightModelfv(GL_LIGHT_MODEL_LOCAL_VIEWER, local);
1947       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
1948       glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
1949       glMaterialfv(GL_FRONT, GL_SHININESS, shine);
1950
1951       glEnable(GL_LIGHTING);
1952       glEnable(GL_LIGHT0);
1953       glEnable(GL_LIGHT1);
1954       glDisable(GL_LIGHT1);
1955
1956       glEnable(GL_DEPTH_TEST);
1957       glEnable(GL_TEXTURE_2D);
1958       glEnable(GL_NORMALIZE);
1959       glEnable(GL_CULL_FACE);
1960     }
1961
1962   if (do_texture)
1963     {
1964 #ifdef HAVE_GLBINDTEXTURE
1965       int i;
1966       for (i = 0; i < 6; i++)
1967         glGenTextures(1, &lc->texids[i]);
1968
1969       parse_image_data(mi);
1970
1971       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1972       glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width);
1973
1974       for (i = 0; i < 6; i++)
1975         {
1976           int height = lc->texture->width;      /* assume square */
1977           glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1978           glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
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
1985           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1986           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1987           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1988           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1989           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1990           glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1991         }
1992
1993 #else  /* !HAVE_GLBINDTEXTURE */
1994       fprintf(stderr,
1995               "%s: this version of GL doesn't support multiple texture maps.\n"
1996               "\tGet OpenGL 1.1.\n",
1997               progname);
1998       exit (1);
1999 #endif /* !HAVE_GLBINDTEXTURE */
2000     }
2001
2002   lc->box = glGenLists(16);
2003   lc->star1 = lc->box+1;
2004   lc->star2 = lc->box+2;
2005   lc->tetra_une = lc->box+3;
2006   lc->tetra_usw = lc->box+4;
2007   lc->tetra_dwn = lc->box+5;
2008   lc->tetra_dse = lc->box+6;
2009   lc->tetra_mid = lc->box+7;
2010   lc->lid_0 = lc->box+8;
2011   lc->lid_1 = lc->box+9;
2012   lc->lid_2 = lc->box+10;
2013   lc->lid_3 = lc->box+11;
2014   lc->lid_4 = lc->box+12;
2015   lc->taser_base = lc->box+13;
2016   lc->taser_lifter = lc->box+14;
2017   lc->taser_slider = lc->box+15;
2018
2019   box(mi, wire);
2020   star(mi, True, wire);
2021   star(mi, False, wire);
2022   tetra(mi, wire);
2023   lid(mi, wire);
2024   taser(mi, wire);
2025 }
2026
2027
2028 void
2029 init_lament(ModeInfo *mi)
2030 {
2031   lament_configuration *lc;
2032   if (!lcs)
2033     {
2034       lcs = (lament_configuration *)
2035         calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
2036       if (!lcs)
2037         {
2038           fprintf(stderr, "%s: out of memory\n", progname);
2039           exit(1);
2040         }
2041     }
2042
2043   lc = &lcs[MI_SCREEN(mi)];
2044
2045   lc->rotx = frand(1.0) * RANDSIGN();
2046   lc->roty = frand(1.0) * RANDSIGN();
2047   lc->rotz = frand(1.0) * RANDSIGN();
2048
2049   /* bell curve from 0-1.5 degrees, avg 0.75 */
2050   lc->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
2051   lc->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
2052   lc->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
2053
2054   lc->d_max = lc->dx * 2;
2055
2056   lc->ddx = 0.00006 + frand(0.00003);
2057   lc->ddy = 0.00006 + frand(0.00003);
2058   lc->ddz = 0.00006 + frand(0.00003);
2059
2060   lc->ddx = 0.00001;
2061   lc->ddy = 0.00001;
2062   lc->ddz = 0.00001;
2063
2064   lc->type = LAMENT_BOX;
2065   lc->anim_pause = 300 + (random() % 100);
2066
2067   if ((lc->glx_context = init_GL(mi)) != NULL)
2068     {
2069       reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
2070       gl_init(mi);
2071     }
2072 }
2073
2074
2075 void
2076 draw_lament(ModeInfo *mi)
2077 {
2078   static int tick = 0;
2079   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
2080   Display *dpy = MI_DISPLAY(mi);
2081   Window window = MI_WINDOW(mi);
2082
2083   if (!lc->glx_context)
2084     return;
2085
2086   glDrawBuffer(GL_BACK);
2087
2088   glXMakeCurrent(dpy, window, *(lc->glx_context));
2089   draw(mi);
2090   glFinish();
2091   glXSwapBuffers(dpy, window);
2092
2093   if (lc->type != LAMENT_LID_ZOOM)
2094     {
2095       rotate(&lc->rotx, &lc->dx, &lc->ddx, lc->d_max);
2096       rotate(&lc->roty, &lc->dy, &lc->ddy, lc->d_max);
2097       rotate(&lc->rotz, &lc->dz, &lc->ddz, lc->d_max);
2098     }
2099
2100   if (lc->anim_pause)
2101     lc->anim_pause--;
2102   else
2103     animate(mi);
2104
2105   if (++tick > 500)
2106     {
2107       tick = 0;
2108       reshape(MI_WIDTH(mi), MI_HEIGHT(mi));
2109     }
2110 }
2111
2112 #endif /* USE_GL */