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