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