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