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