http://packetstormsecurity.org/UNIX/admin/xscreensaver-3.30.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 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.70, 0.60, 0.00, 1.00 };
144 static GLfloat interior_color[] = { 0.25, 0.25, 0.20, 1.00 };
145
146
147 typedef struct {
148   GLXContext *glx_context;
149
150   GLuint box;                      /* display list IDs */
151   GLuint star1, star2;
152   GLuint tetra_une, tetra_usw, tetra_dwn, tetra_dse, tetra_mid;
153   GLuint lid_0, lid_1, lid_2, lid_3, lid_4;
154   GLuint taser_base, taser_lifter, taser_slider;
155
156   GLfloat rotx, roty, rotz;        /* current object rotation */
157   GLfloat dx, dy, dz;              /* current rotational velocity */
158   GLfloat ddx, ddy, ddz;           /* current rotational acceleration */
159   GLfloat d_max;                   /* max velocity */
160   XImage *texture;                 /* image bits */
161   GLuint texids[6];                /* texture map IDs */
162   lament_type type;                /* which mode of the object is current */
163
164   int anim_pause;                  /* countdown before animating again */
165   GLfloat anim_r, anim_y, anim_z;  /* relative position during anims */
166
167 } lament_configuration;
168
169 static lament_configuration *lcs = NULL;
170
171 #define FACE_N 3
172 #define FACE_S 2
173 #define FACE_E 0
174 #define FACE_W 4
175 #define FACE_U 5
176 #define FACE_D 1
177
178 static void
179 parse_image_data(ModeInfo *mi)
180 {
181   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
182   lc->texture = xpm_to_ximage (mi->dpy,
183                                mi->xgwa.visual,
184                                mi->xgwa.colormap,
185                                lament_faces);
186 }
187
188 \f
189 /* Computing normal vectors (thanks to Nat Friedman <ndf@mit.edu>)
190  */
191
192 typedef struct vector {
193   GLfloat x, y, z;
194 } vector;
195
196 typedef struct plane {
197   vector p1, p2, p3;
198 } plane;
199
200 static void
201 vector_set(vector *v, GLfloat x, GLfloat y, GLfloat z)
202 {
203   v->x = x;
204   v->y = y;
205   v->z = z;
206 }
207
208 static void
209 vector_cross(vector v1, vector v2, vector *v3)
210 {
211   v3->x = (v1.y * v2.z) - (v1.z * v2.y);
212   v3->y = (v1.z * v2.x) - (v1.x * v2.z);
213   v3->z = (v1.x * v2.y) - (v1.y * v2.x);
214 }
215
216 static void
217 vector_subtract(vector v1, vector v2, vector *res)
218 {
219   res->x = v1.x - v2.x;
220   res->y = v1.y - v2.y;
221   res->z = v1.z - v2.z;
222 }
223
224 static void
225 plane_normal(plane p, vector *n)
226 {
227   vector v1, v2;
228   vector_subtract(p.p1, p.p2, &v1);
229   vector_subtract(p.p1, p.p3, &v2);
230   vector_cross(v2, v1, n);
231 }
232
233 static void
234 do_normal(GLfloat x1, GLfloat y1, GLfloat z1,
235           GLfloat x2, GLfloat y2, GLfloat z2,
236           GLfloat x3, GLfloat y3, GLfloat z3)
237 {
238   plane plane;
239   vector n;
240   vector_set(&plane.p1, x1, y1, z1);
241   vector_set(&plane.p2, x2, y2, z2);
242   vector_set(&plane.p3, x3, y3, z3);
243   plane_normal(plane, &n);
244   n.x = -n.x; n.y = -n.y; n.z = -n.z;
245
246   glNormal3f(n.x, n.y, n.z);
247
248 #ifdef DEBUG
249   /* Draw a line in the direction of this face's normal. */
250   {
251     GLfloat ax = n.x > 0 ? n.x : -n.x;
252     GLfloat ay = n.y > 0 ? n.y : -n.y;
253     GLfloat az = n.z > 0 ? n.z : -n.z;
254     GLfloat mx = (x1 + x2 + x3) / 3;
255     GLfloat my = (y1 + y2 + y3) / 3;
256     GLfloat mz = (z1 + z2 + z3) / 3;
257     GLfloat xx, yy, zz;
258
259     GLfloat max = ax > ay ? ax : ay;
260     if (az > max) max = az;
261     max *= 2;
262     xx = n.x / max;
263     yy = n.y / max;
264     zz = n.z / max;
265
266     glBegin(GL_LINE_LOOP);
267     glVertex3f(mx, my, mz);
268     glVertex3f(mx+xx, my+yy, mz+zz);
269     glEnd();
270   }
271 #endif /* DEBUG */
272 }
273
274
275 \f
276 /* Shorthand utilities for making faces, with proper normals.
277  */
278
279 static void
280 face3(GLint texture, GLfloat *color, Bool wire,
281       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
282       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
283       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3)
284 {
285 #ifdef HAVE_GLBINDTEXTURE
286   glBindTexture(GL_TEXTURE_2D, texture);
287 #endif /* HAVE_GLBINDTEXTURE */
288   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
289   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
290   glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
291   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
292   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
293   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
294   glEnd();
295 }
296
297 static void
298 face4(GLint texture, GLfloat *color, Bool wire,
299       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
300       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
301       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
302       GLfloat s4, GLfloat t4, GLfloat x4, GLfloat y4, GLfloat z4)
303 {
304 #ifdef HAVE_GLBINDTEXTURE
305   glBindTexture(GL_TEXTURE_2D, texture);
306 #endif /* HAVE_GLBINDTEXTURE */
307   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
308   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
309   glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
310   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
311   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
312   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
313   glTexCoord2f(s4, t4); glVertex3f(x4, y4, z4);
314   glEnd();
315 }
316
317 static void
318 face5(GLint texture, GLfloat *color, Bool wire,
319       GLfloat s1, GLfloat t1, GLfloat x1, GLfloat y1, GLfloat z1,
320       GLfloat s2, GLfloat t2, GLfloat x2, GLfloat y2, GLfloat z2,
321       GLfloat s3, GLfloat t3, GLfloat x3, GLfloat y3, GLfloat z3,
322       GLfloat s4, GLfloat t4, GLfloat x4, GLfloat y4, GLfloat z4,
323       GLfloat s5, GLfloat t5, GLfloat x5, GLfloat y5, GLfloat z5)
324 {
325 #ifdef HAVE_GLBINDTEXTURE
326   glBindTexture(GL_TEXTURE_2D, texture);
327 #endif /* HAVE_GLBINDTEXTURE */
328   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
329   do_normal(x1, y1, z1,  x2, y2, z2,  x3, y3, z3);
330   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
331   glTexCoord2f(s1, t1); glVertex3f(x1, y1, z1);
332   glTexCoord2f(s2, t2); glVertex3f(x2, y2, z2);
333   glTexCoord2f(s3, t3); glVertex3f(x3, y3, z3);
334   glTexCoord2f(s4, t4); glVertex3f(x4, y4, z4);
335   glTexCoord2f(s5, t5); glVertex3f(x5, y5, z5);
336   glEnd();
337 }
338
339
340 \f
341 /* Creating object models
342  */
343
344 static void
345 box(ModeInfo *mi, Bool wire)
346 {
347   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
348
349   glNewList(lc->box, GL_COMPILE);
350   glShadeModel(GL_SMOOTH);
351
352   /* N */
353   face4(lc->texids[FACE_N], exterior_color, wire,
354         0.0, 0.0,       -0.5,  0.5,  0.5,
355         1.0, 0.0,        0.5,  0.5,  0.5,
356         1.0, 1.0,        0.5,  0.5, -0.5,
357         0.0, 1.0,       -0.5,  0.5, -0.5);
358
359   /* S */
360   face4(lc->texids[FACE_S], exterior_color, wire,
361         0.0, 0.0,        -0.5, -0.5, -0.5,
362         1.0, 0.0,         0.5, -0.5, -0.5,
363         1.0, 1.0,         0.5, -0.5,  0.5,
364         0.0, 1.0,        -0.5, -0.5,  0.5);
365
366   /* E */
367   face4(lc->texids[FACE_E], exterior_color, wire,
368         0.0, 0.0,        0.5, -0.5, -0.5,
369         1.0, 0.0,        0.5,  0.5, -0.5,
370         1.0, 1.0,        0.5,  0.5,  0.5,
371         0.0, 1.0,        0.5, -0.5,  0.5);
372
373   /* W */
374   face4(lc->texids[FACE_W], exterior_color, wire,
375         1.0, 1.0,       -0.5, -0.5,  0.5,
376         0.0, 1.0,       -0.5,  0.5,  0.5,
377         0.0, 0.0,       -0.5,  0.5, -0.5,
378         1.0, 0.0,       -0.5, -0.5, -0.5);
379
380   /* U */
381   face4(lc->texids[FACE_U], exterior_color, wire,
382         1.0, 0.0,        0.5, -0.5,  0.5,
383         1.0, 1.0,        0.5,  0.5,  0.5,
384         0.0, 1.0,       -0.5,  0.5,  0.5,
385         0.0, 0.0,       -0.5, -0.5,  0.5);
386
387   /* D */
388   face4(lc->texids[FACE_D], exterior_color, wire,
389         0.0, 1.0,       -0.5, -0.5, -0.5,
390         0.0, 0.0,       -0.5,  0.5, -0.5,
391         1.0, 0.0,        0.5,  0.5, -0.5,
392         1.0, 1.0,        0.5, -0.5, -0.5);
393
394   glEndList();
395 }
396
397
398 static void
399 star(ModeInfo *mi, Bool top, Bool wire)
400 {
401   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
402   int i;
403
404   int points[][2] = {
405     {  77,  74 }, {  60,  98 }, {   0,  71 }, {   0,   0 },    /* L1 */
406     {  60,  98 }, {  55, 127 }, {   0, 127 }, {   0,  71 },    /* L2 */
407     {  55, 127 }, {  60, 154 }, {   0, 179 }, {   0, 127 },    /* L3 */
408     {  60, 154 }, {  76, 176 }, {   0, 255 }, {   0, 179 },    /* L4 */
409     {  76, 176 }, { 100, 193 }, {  74, 255 }, {   0, 255 },    /* B1 */
410     { 100, 193 }, { 127, 198 }, { 127, 255 }, {  74, 255 },    /* B2 */
411     { 127, 198 }, { 151, 193 }, { 180, 255 }, { 127, 255 },    /* B3 */
412     { 151, 193 }, { 178, 177 }, { 255, 255 }, { 180, 255 },    /* B4 */
413     { 178, 177 }, { 193, 155 }, { 255, 181 }, { 255, 255 },    /* R4 */
414     { 193, 155 }, { 199, 127 }, { 255, 127 }, { 255, 181 },    /* R3 */
415     { 199, 127 }, { 194,  99 }, { 255,  74 }, { 255, 127 },    /* R2 */
416     { 194,  99 }, { 179,  76 }, { 255,   0 }, { 255,  74 },    /* R1 */
417     { 179,  76 }, { 155,  60 }, { 180,   0 }, { 255,   0 },    /* T4 */
418     { 155,  60 }, { 126,  55 }, { 126,   0 }, { 180,   0 },    /* T3 */
419     { 126,  55 }, { 100,  60 }, {  75,   0 }, { 126,   0 },    /* T2 */
420     { 100,  60 }, {  77,  74 }, {   0,   0 }, {  75,   0 },    /* T1 */
421   };
422
423   for (i = 0; i < countof(points); i++)
424     points[i][1] = 255-points[i][1];
425
426   if (top)
427     glNewList(lc->star1, GL_COMPILE);
428   else
429     glNewList(lc->star2, GL_COMPILE);
430
431   if (!top)
432     glRotatef(-180.0, 1.0, 0.0, 0.0);
433
434   for (i = 0; i < countof(points)/4; i += 2)
435     {
436       int j, k;
437
438       /* Top face.
439        */
440
441       GLfloat s[4], t[4], x[4], y[4], z[4];
442       for (j = 3, k = 0; j >= 0; j--, k++)
443         {
444           GLfloat xx = points[(i*4)+j][0] / 255.0L;
445           GLfloat yy = points[(i*4)+j][1] / 255.0L;
446           s[k] = xx;
447           t[k] = yy;
448           x[k] = xx-0.5;
449           y[k] = yy-0.5;
450           z[k] = 0.5;
451         }
452       face4(lc->texids[top ? FACE_U : FACE_D], exterior_color, wire,
453             s[0], t[0],  x[0], y[0], z[0],
454             s[1], t[1],  x[1], y[1], z[1],
455             s[2], t[2],  x[2], y[2], z[2],
456             s[3], t[3],  x[3], y[3], z[3]);
457
458       /* Bottom face.
459        */
460       for (j = 0, k = 0; j < 4; 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] = 1.0 - 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       /* Connecting faces.
477        */
478       for (j = 3; j >= 0; j--)
479         {
480           int k = (j == 0 ? 3 : j-1);
481           Bool front_p = (j == 3);
482           GLfloat x1 = points[(i*4)+j][0] / 255.0L;
483           GLfloat y1 = points[(i*4)+j][1] / 255.0L;
484           GLfloat x2 = points[(i*4)+k][0] / 255.0L;
485           GLfloat y2 = points[(i*4)+k][1] / 255.0L;
486
487           GLfloat tx1=0.0, tx2=1.0, ty1=0.0, ty2=1.0;
488
489           int texture = 0;
490           int facing = i/4;
491           facing = (facing + j + 5) % 4;
492
493           switch (facing) {
494           case 0:
495             texture = FACE_W;
496             if (top) {
497               tx1 = 1.0 - y1;  tx2 = 1.0 - y2;
498               ty1 = 0.0;       ty2 = 1.0;
499             } else {
500               tx1 = y1;  tx2 = y2;
501               ty1 = 1.0; ty2 = 0.0;
502             }
503             break;
504           case 1:
505             texture = top ? FACE_S : FACE_N;
506             tx1 = x1;  tx2 = x2;
507             ty1 = 0.0; ty2 = 1.0;
508             break;
509           case 2:
510             texture = FACE_E;
511             if (top) {
512               tx1 = y1;  tx2 = y2;
513               ty1 = 0.0; ty2 = 1.0;
514             } else {
515               tx1 = 1.0 - y1;  tx2 = 1.0 - y2;
516               ty1 = 1.0;       ty2 = 0.0;
517             }
518             break;
519           case 3:
520             texture = top ? FACE_N : FACE_S;
521             tx1 = x1;  tx2 = x2;
522             ty1 = 1.0; ty2 = 0.0;
523             break;
524           }
525
526           x1 -= 0.5; x2 -= 0.5;
527           y1 -= 0.5; y2 -= 0.5;
528
529           face4(front_p ? lc->texids[texture] : 0,
530                 front_p ? exterior_color : interior_color,
531                 wire,
532                 tx1, ty2,  x1, y1,  0.5,
533                 tx1, ty1,  x1, y1, -0.5,
534                 tx2, ty1,  x2, y2, -0.5,
535                 tx2, ty2,  x2, y2,  0.5);
536         }
537     }
538
539
540   /* Central core top cap.
541    */
542 #ifdef HAVE_GLBINDTEXTURE
543   glBindTexture(GL_TEXTURE_2D, lc->texids[top ? FACE_U : FACE_D]);
544 #endif /* HAVE_GLBINDTEXTURE */
545   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, exterior_color);
546
547   i = 1;
548   do_normal(points[i+0][0], points[i+0][1], 0,
549             points[i+4][0], points[i+4][1], 0,
550             points[i+8][0], points[i+8][1], 0);
551   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
552   for (i = 1; i < countof(points); i += 4)
553     {
554       GLfloat x = points[i][0] / 255.0L;
555       GLfloat y = points[i][1] / 255.0L;
556       glTexCoord2f(x, y);
557       glVertex3f(x-0.5, y-0.5, 0.5);
558     }
559   glEnd();
560
561
562   /* Central core bottom cap.
563    */
564 #ifdef HAVE_GLBINDTEXTURE
565   glBindTexture(GL_TEXTURE_2D, 0);
566 #endif /* HAVE_GLBINDTEXTURE */
567   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, interior_color);
568
569   i = countof(points) - 9;
570   do_normal(points[i+0][0], points[i+0][1], 0,
571             points[i+4][0], points[i+4][1], 0,
572             points[i+8][0], points[i+8][1], 0);
573
574   glBegin(wire ? GL_LINE_LOOP : GL_POLYGON);
575   for (i = countof(points) - 3; i >= 0; i -= 4)
576     {
577       GLfloat x = points[i][0] / 255.0L;
578       GLfloat y = points[i][1] / 255.0L;
579       glVertex3f(x-0.5, y-0.5, 0);
580     }
581   glEnd();
582   
583
584   /* Central core walls.
585    */
586   for (i = 1; i < countof(points); i += 4)
587     {
588
589       GLfloat x1 = points[i-1][0] / 255.0L;
590       GLfloat y1 = points[i-1][1] / 255.0L;
591       GLfloat x2 = points[i][0] / 255.0L;
592       GLfloat y2 = points[i][1] / 255.0L;
593       face4(0, interior_color, wire,
594             0.0, 0.0,  x1-0.5, y1-0.5, 0.5,
595             0.0, 0.0,  x1-0.5, y1-0.5, 0.0,
596             0.0, 0.0,  x2-0.5, y2-0.5, 0.0,
597             0.0, 0.0,  x2-0.5, y2-0.5, 0.5);
598     }
599
600   glEndList();
601 }
602
603
604 static void
605 tetra(ModeInfo *mi, Bool wire)
606 {
607   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
608
609   glNewList(lc->tetra_une, GL_COMPILE);
610   {
611     glShadeModel(GL_SMOOTH);
612
613     /* Ua */
614     face3(lc->texids[FACE_U], exterior_color, wire,
615           1.0, 0.0,      0.5, -0.5,  0.5,
616           1.0, 1.0,      0.5,  0.5,  0.5,
617           0.0, 1.0,     -0.5,  0.5,  0.5);
618
619     /* Na */
620     face3(lc->texids[FACE_N], exterior_color, wire,
621           0.0, 0.0,     -0.5,  0.5,  0.5,
622           1.0, 0.0,      0.5,  0.5,  0.5,
623           1.0, 1.0,      0.5,  0.5, -0.5);
624
625     /* Eb */
626     face3(lc->texids[FACE_E], exterior_color, wire,
627           1.0, 0.0,      0.5,  0.5, -0.5,
628           1.0, 1.0,      0.5,  0.5,  0.5,
629           0.0, 1.0,      0.5, -0.5,  0.5);
630
631     face3(0, interior_color, wire,
632           0.0, 0.0,      0.5,  0.5, -0.5,
633           0.0, 0.0,      0.5, -0.5,  0.5,
634           0.0, 0.0,     -0.5,  0.5,  0.5);
635   }
636   glEndList();
637
638   glNewList(lc->tetra_usw, GL_COMPILE);
639   {
640     /* Ub */
641     face3(lc->texids[FACE_U], exterior_color, wire,
642           0.0, 1.0,     -0.5,  0.5,  0.5,
643           0.0, 0.0,     -0.5, -0.5,  0.5,
644           1.0, 0.0,      0.5, -0.5,  0.5);
645
646     /* Sb */
647     face3(lc->texids[FACE_S], exterior_color, wire,
648           1.0, 1.0,      0.5, -0.5,  0.5,
649           0.0, 1.0,     -0.5, -0.5,  0.5,
650           0.0, 0.0,     -0.5, -0.5, -0.5);
651
652     /* Wb */
653     face3(lc->texids[FACE_W], exterior_color, wire,
654           1.0, 0.0,     -0.5, -0.5, -0.5,
655           1.0, 1.0,     -0.5, -0.5,  0.5,
656           0.0, 1.0,     -0.5,  0.5,  0.5);
657
658     face3(0, interior_color, wire,
659           0.0,0.0,      -0.5, -0.5, -0.5,
660           0.0,0.0,      -0.5,  0.5,  0.5,
661           0.0,0.0,       0.5, -0.5,  0.5);
662   }
663   glEndList();
664
665   glNewList(lc->tetra_dwn, GL_COMPILE);
666   {
667     /* Db */
668     face3(lc->texids[FACE_D], exterior_color, wire,
669           0.0, 1.0,     -0.5, -0.5, -0.5,
670           0.0, 0.0,     -0.5,  0.5, -0.5,
671           1.0, 0.0,      0.5,  0.5, -0.5);
672
673     /* Wa */
674     face3(lc->texids[FACE_W], exterior_color, wire,
675           0.0, 1.0,     -0.5,  0.5,  0.5,
676           0.0, 0.0,     -0.5,  0.5, -0.5,
677           1.0, 0.0,     -0.5, -0.5, -0.5);
678
679     /* Nb */
680     face3(lc->texids[FACE_N], exterior_color, wire,
681           1.0, 1.0,      0.5,  0.5, -0.5,
682           0.0, 1.0,     -0.5,  0.5, -0.5,
683           0.0, 0.0,     -0.5,  0.5,  0.5);
684
685     face3(0, interior_color, wire,
686           0.0, 0.0,      0.5,  0.5, -0.5,
687           0.0, 0.0,     -0.5,  0.5,  0.5,
688           0.0, 0.0,     -0.5, -0.5, -0.5);
689   }
690   glEndList();
691
692   glNewList(lc->tetra_dse, GL_COMPILE);
693   {
694     /* Sa */
695     face3(lc->texids[FACE_S], exterior_color, wire,
696           0.0, 0.0,     -0.5, -0.5, -0.5,
697           1.0, 0.0,      0.5, -0.5, -0.5,
698           1.0, 1.0,      0.5, -0.5,  0.5);
699
700     /* Ea */
701     face3(lc->texids[FACE_E], exterior_color, wire,
702           0.0, 1.0,      0.5, -0.5,  0.5,
703           0.0, 0.0,      0.5, -0.5, -0.5,
704           1.0, 0.0,      0.5,  0.5, -0.5);
705
706     /* Da */
707     face3(lc->texids[FACE_D], exterior_color, wire,
708           1.0, 0.0,      0.5,  0.5, -0.5,
709           1.0, 1.0,      0.5, -0.5, -0.5,
710           0.0, 1.0,     -0.5, -0.5, -0.5);
711
712     face3(0, interior_color, wire,
713           0.0, 0.0,      0.5, -0.5,  0.5,
714           0.0, 0.0,      0.5,  0.5, -0.5,
715           0.0, 0.0,     -0.5, -0.5, -0.5);
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 void
1877 reshape_lament(ModeInfo *mi, 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
1980           clear_gl_error();
1981           glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1982                        lc->texture->width, height, 0,
1983                        GL_RGBA, GL_UNSIGNED_BYTE,
1984                        (lc->texture->data +
1985                         (lc->texture->bytes_per_line * height * i)));
1986           check_gl_error("texture");
1987
1988           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1989           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1990           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1991           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1992           glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1993           glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
1994         }
1995
1996 #else  /* !HAVE_GLBINDTEXTURE */
1997       fprintf(stderr,
1998               "%s: this version of GL doesn't support multiple texture maps.\n"
1999               "\tGet OpenGL 1.1.\n",
2000               progname);
2001       exit (1);
2002 #endif /* !HAVE_GLBINDTEXTURE */
2003     }
2004
2005   lc->box = glGenLists(16);
2006   lc->star1 = lc->box+1;
2007   lc->star2 = lc->box+2;
2008   lc->tetra_une = lc->box+3;
2009   lc->tetra_usw = lc->box+4;
2010   lc->tetra_dwn = lc->box+5;
2011   lc->tetra_dse = lc->box+6;
2012   lc->tetra_mid = lc->box+7;
2013   lc->lid_0 = lc->box+8;
2014   lc->lid_1 = lc->box+9;
2015   lc->lid_2 = lc->box+10;
2016   lc->lid_3 = lc->box+11;
2017   lc->lid_4 = lc->box+12;
2018   lc->taser_base = lc->box+13;
2019   lc->taser_lifter = lc->box+14;
2020   lc->taser_slider = lc->box+15;
2021
2022   box(mi, wire);
2023   star(mi, True, wire);
2024   star(mi, False, wire);
2025   tetra(mi, wire);
2026   lid(mi, wire);
2027   taser(mi, wire);
2028 }
2029
2030
2031 # ifdef HAVE_MESA_GL
2032
2033 # include <signal.h>
2034
2035 static RETSIGTYPE
2036 lament_signal_kludge (int sig)
2037 {
2038   signal (sig, SIG_DFL);
2039   fprintf (stderr,
2040            "\n"
2041            "%s: dying with signal %d (%s).\n"
2042            "\n"
2043            "\tThis is almost certainly a bug in the MesaGL library,\n"
2044            "\tespecially if the stack trace in the core file mentions\n"
2045            "\t`lambda_textured_triangle' or `render_quad'.\n"
2046            "\n"
2047            "\tI encourage you to report this to the Mesa maintainers\n"
2048            "\tat <http://www.mesa3d.org/>.  I reported this bug more\n"
2049            "\tthan a year ago, and it is trivially reproducible.\n"
2050            "\tI do not know a workaround.\n"
2051            "\n",
2052            progname,
2053            sig,
2054            (sig == SIGILL ? "SIGILL" :
2055             sig == SIGFPE ? "SIGFPE" :
2056             sig == SIGBUS ? "SIGBUS" :
2057             sig == SIGSEGV ? "SIGSEGV" : "???"));
2058   fflush (stderr);
2059   kill (getpid (), sig);
2060 }
2061
2062 static void
2063 handle_signals (void)
2064 {
2065   signal (SIGILL,  lament_signal_kludge);
2066   signal (SIGFPE,  lament_signal_kludge);
2067   signal (SIGBUS,  lament_signal_kludge);
2068   signal (SIGSEGV, lament_signal_kludge);
2069 }
2070 # endif /* HAVE_MESA_GL */
2071
2072
2073 void
2074 init_lament(ModeInfo *mi)
2075 {
2076   lament_configuration *lc;
2077   if (!lcs)
2078     {
2079       lcs = (lament_configuration *)
2080         calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
2081       if (!lcs)
2082         {
2083           fprintf(stderr, "%s: out of memory\n", progname);
2084           exit(1);
2085         }
2086     }
2087
2088   lc = &lcs[MI_SCREEN(mi)];
2089
2090   lc->rotx = frand(1.0) * RANDSIGN();
2091   lc->roty = frand(1.0) * RANDSIGN();
2092   lc->rotz = frand(1.0) * RANDSIGN();
2093
2094   /* bell curve from 0-1.5 degrees, avg 0.75 */
2095   lc->dx = (frand(1) + frand(1) + frand(1)) / (360*2);
2096   lc->dy = (frand(1) + frand(1) + frand(1)) / (360*2);
2097   lc->dz = (frand(1) + frand(1) + frand(1)) / (360*2);
2098
2099   lc->d_max = lc->dx * 2;
2100
2101   lc->ddx = 0.00006 + frand(0.00003);
2102   lc->ddy = 0.00006 + frand(0.00003);
2103   lc->ddz = 0.00006 + frand(0.00003);
2104
2105   lc->type = LAMENT_BOX;
2106   lc->anim_pause = 300 + (random() % 100);
2107
2108   if ((lc->glx_context = init_GL(mi)) != NULL)
2109     {
2110       reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
2111       gl_init(mi);
2112     }
2113
2114 # ifdef HAVE_MESA_GL
2115   handle_signals ();
2116 # endif /* HAVE_MESA_GL */
2117 }
2118
2119
2120 void
2121 draw_lament(ModeInfo *mi)
2122 {
2123   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
2124   Display *dpy = MI_DISPLAY(mi);
2125   Window window = MI_WINDOW(mi);
2126
2127   if (!lc->glx_context)
2128     return;
2129
2130   glDrawBuffer(GL_BACK);
2131
2132   glXMakeCurrent(dpy, window, *(lc->glx_context));
2133   draw(mi);
2134   if (mi->fps_p) do_fps (mi);
2135
2136   glFinish();
2137   glXSwapBuffers(dpy, window);
2138
2139   if (lc->type != LAMENT_LID_ZOOM)
2140     {
2141       rotate(&lc->rotx, &lc->dx, &lc->ddx, lc->d_max);
2142       rotate(&lc->roty, &lc->dy, &lc->ddy, lc->d_max);
2143       rotate(&lc->rotz, &lc->dz, &lc->ddz, lc->d_max);
2144     }
2145
2146   if (lc->anim_pause)
2147     lc->anim_pause--;
2148   else
2149     animate(mi);
2150 }
2151
2152 #endif /* USE_GL */