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