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