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