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