From http://www.jwz.org/xscreensaver/xscreensaver-5.17.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.  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   int target_size = lc->texture->width * 1.4;
1382   int win_size = (MI_WIDTH(mi) > MI_HEIGHT(mi) ? MI_HEIGHT(mi) : MI_WIDTH(mi));
1383
1384   /* This scale makes the box take up most of the window */
1385   glScalef(8, 8, 8);
1386
1387   /* But if the window is more than a little larger than our target size,
1388      scale the object back down, so that the bits drawn on the screen end
1389      up rougly target_size across (actually it ends up a little larger.)
1390      Note that the image-map bits we have are 128x128.  Therefore, if the
1391      image is magnified a lot, it looks pretty blocky.  So it's better to
1392      have a 128x128 animation on a 1280x1024 screen that looks good, than
1393      a 1024x1024 animation that looks really pixelated.
1394    */
1395
1396   {
1397     int max = 340;                /* Let's not go larger than life-sized. */
1398     if (target_size > max)
1399       target_size = max;
1400   }
1401
1402   if (win_size > 640 &&
1403       win_size > target_size * 1.5)
1404     {
1405       GLfloat ratio = ((GLfloat) target_size / (GLfloat) win_size);
1406       ratio *= 2.0;
1407       glScalef(ratio, ratio, ratio);
1408     }
1409 }
1410
1411
1412 static void
1413 draw(ModeInfo *mi)
1414 {
1415   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1416   Bool wire = MI_IS_WIREFRAME(mi);
1417
1418   if (!wire)
1419     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1420   else
1421     glClear(GL_COLOR_BUFFER_BIT);
1422
1423   glPushMatrix();
1424
1425   gltrackball_rotate (lc->trackball);
1426
1427   /* Make into the screen be +Y right be +X, and up be +Z. */
1428   glRotatef(-90.0, 1.0, 0.0, 0.0);
1429
1430   scale_for_window (mi);
1431
1432 #if 0
1433     glPushMatrix();
1434     {
1435       /* Shift to the upper left, and draw the vanilla box. */
1436       glTranslatef(-0.6, 0.0, 0.6);
1437
1438       /* Apply rotation to the object. */
1439       glRotatef(x * 360, 1.0, 0.0, 0.0);
1440       glRotatef(y * 360, 0.0, 1.0, 0.0);
1441       glRotatef(z * 360, 0.0, 0.0, 1.0);
1442
1443       /* Draw it. */
1444       glCallList(lc->box);
1445     }
1446     glPopMatrix();
1447
1448     /* Shift to the lower right, and draw the animated object. */
1449     glTranslatef(0.6, 0.0, -0.6);
1450 #endif /* 0 */
1451
1452
1453     glPushMatrix();
1454     {
1455       /* Apply rotation to the object. */
1456       if (lc->type != LAMENT_LID_ZOOM)
1457         get_rotation (lc->rot, &lc->rotx, &lc->roty, &lc->rotz,
1458                       !lc->button_down_p);
1459       glRotatef (lc->rotx * 360, 1.0, 0.0, 0.0);
1460       glRotatef (lc->roty * 360, 0.0, 1.0, 0.0);
1461       glRotatef (lc->rotz * 360, 0.0, 0.0, 1.0);
1462
1463       check_facing(mi);
1464
1465       switch (lc->type)
1466         {
1467         case LAMENT_BOX:
1468           glCallList(lc->box);
1469           break;
1470
1471         case LAMENT_STAR_OUT:
1472         case LAMENT_STAR_ROT:
1473         case LAMENT_STAR_ROT_IN:
1474         case LAMENT_STAR_ROT_OUT:
1475         case LAMENT_STAR_UNROT:
1476         case LAMENT_STAR_IN:
1477           glTranslatef(0.0, 0.0, lc->anim_z/2);
1478           glRotatef(lc->anim_r/2, 0.0, 0.0, 1.0);
1479           glCallList(lc->star1);
1480
1481           glTranslatef(0.0, 0.0, -lc->anim_z);
1482           glRotatef(-lc->anim_r, 0.0, 0.0, 1.0);
1483           glCallList(lc->star2);
1484           break;
1485
1486         case LAMENT_TETRA_UNE:
1487         case LAMENT_TETRA_USW:
1488         case LAMENT_TETRA_DWN:
1489         case LAMENT_TETRA_DSE:
1490           {
1491             int magic;
1492             GLfloat x, y, z;
1493             switch (lc->type) {
1494             case LAMENT_TETRA_UNE: magic = lc->tetra_une;
1495               x = 1.0; y = 1.0; z = 1.0; break;
1496             case LAMENT_TETRA_USW: magic = lc->tetra_usw;
1497               x = 1.0; y = 1.0; z = -1.0; break;
1498             case LAMENT_TETRA_DWN: magic = lc->tetra_dwn;
1499               x = 1.0; y = -1.0; z = 1.0; break;
1500             case LAMENT_TETRA_DSE: magic = lc->tetra_dse;
1501               x = -1.0; y = 1.0; z = 1.0; break;
1502             default: abort(); break;
1503             }
1504             glCallList(lc->tetra_mid);
1505             if (magic != lc->tetra_une) glCallList(lc->tetra_une);
1506             if (magic != lc->tetra_usw) glCallList(lc->tetra_usw);
1507             if (magic != lc->tetra_dwn) glCallList(lc->tetra_dwn);
1508             if (magic != lc->tetra_dse) glCallList(lc->tetra_dse);
1509             glRotatef(lc->anim_r, x, y, z);
1510             glCallList(magic);
1511           }
1512           break;
1513
1514         case LAMENT_LID_OPEN:
1515         case LAMENT_LID_CLOSE:
1516         case LAMENT_LID_ZOOM:
1517           {
1518             GLfloat d = 0.417;
1519
1520             glTranslatef(lc->anim_z, 0.0, 0.0);
1521
1522             glCallList(lc->lid_0);
1523
1524             glPushMatrix();
1525               glTranslatef(-0.5, -d, 0.0);
1526               glRotatef(-lc->anim_r, 0.0, -1.0, -1.0);
1527               glTranslatef( 0.5,  d, 0.0);
1528               glCallList(lc->lid_1);
1529             glPopMatrix();
1530             glPushMatrix();
1531               glTranslatef(-0.5, -d, 0.0);
1532               glRotatef( lc->anim_r, 0.0, -1.0,   1.0);
1533               glTranslatef( 0.5,  d, 0.0);
1534               glCallList(lc->lid_2);
1535             glPopMatrix();
1536             glPushMatrix();
1537               glTranslatef(-0.5,  d, 0.0);
1538               glRotatef( lc->anim_r, 0.0,  -1.0,  -1.0);
1539               glTranslatef( 0.5, -d, 0.0);
1540               glCallList(lc->lid_3);
1541             glPopMatrix();
1542             glPushMatrix();
1543               glTranslatef(-0.5,  d, 0.0);
1544               glRotatef(-lc->anim_r, 0.0,  -1.0,   1.0);
1545               glTranslatef( 0.5, -d, 0.0);
1546               glCallList(lc->lid_4);
1547             glPopMatrix();
1548           }
1549           break;
1550
1551         case LAMENT_TASER_OUT:
1552         case LAMENT_TASER_SLIDE:
1553         case LAMENT_TASER_SLIDE_IN:
1554         case LAMENT_TASER_IN:
1555
1556           glTranslatef(-lc->anim_z/2, 0.0, 0.0);
1557           glCallList(lc->taser_base);
1558
1559           glTranslatef(lc->anim_z, 0.0, 0.0);
1560           glCallList(lc->taser_lifter);
1561
1562           glTranslatef(0.0, 0.0, lc->anim_y);
1563           glCallList(lc->taser_slider);
1564           break;
1565
1566         default:
1567           abort();
1568           break;
1569         }
1570     }
1571     glPopMatrix();
1572
1573   glPopMatrix();
1574 }
1575
1576
1577 /* Rather than just picking states randomly, pick an ordering randomly, do it,
1578    and then re-randomize.  That way one can be assured of seeing all states in
1579    a short time period, though not always in the same order (it's frustrating
1580    to see it pick the same state 5x in a row.)
1581  */
1582 static void
1583 shuffle_states (lament_configuration *lc)
1584 {
1585   int i;
1586   for (i = 0; i < lc->nstates; i++)
1587     {
1588       int a = random() % lc->nstates;
1589       lament_type swap = lc->states[a];
1590       lc->states[a] = lc->states[i];
1591       lc->states[i] = swap;
1592     }
1593 }
1594
1595
1596 static void
1597 animate(ModeInfo *mi)
1598 {
1599   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1600   int pause = 10;
1601 /*  int pause2 = 60;*/
1602   int pause3 = 120;
1603
1604   switch (lc->type)
1605     {
1606     case LAMENT_BOX:
1607       {
1608         lc->state++;
1609         if (lc->state >= lc->nstates)
1610           {
1611             shuffle_states (lc);
1612             lc->state = 0;
1613           }
1614         lc->type = lc->states[lc->state];
1615
1616         if (lc->type == LAMENT_BOX)
1617           lc->anim_pause = pause3;
1618
1619         lc->anim_r = 0.0;
1620         lc->anim_y = 0.0;
1621         lc->anim_z = 0.0;
1622       }
1623       break;
1624
1625       /* -------------------------------------------------------------- */
1626
1627     case LAMENT_STAR_OUT:
1628       lc->anim_z += 0.01;
1629       if (lc->anim_z >= 1.0)
1630         {
1631           lc->anim_z = 1.0;
1632           lc->type = LAMENT_STAR_ROT;
1633           lc->anim_pause = pause;
1634         }
1635       break;
1636
1637     case LAMENT_STAR_ROT:
1638       lc->anim_r += 1.0;
1639       if (lc->anim_r >= 45.0)
1640         {
1641           lc->anim_r = 45.0;
1642           lc->type = LAMENT_STAR_ROT_IN;
1643           lc->anim_pause = pause;
1644         }
1645       break;
1646
1647     case LAMENT_STAR_ROT_IN:
1648       lc->anim_z -= 0.01;
1649       if (lc->anim_z <= 0.0)
1650         {
1651           lc->anim_z = 0.0;
1652           lc->type = LAMENT_STAR_ROT_OUT;
1653           lc->anim_pause = pause3 * (1 + (random() % 4) + (random() % 4));
1654         }
1655       break;
1656
1657     case LAMENT_STAR_ROT_OUT:
1658       lc->anim_z += 0.01;
1659       if (lc->anim_z >= 1.0)
1660         {
1661           lc->anim_z = 1.0;
1662           lc->type = LAMENT_STAR_UNROT;
1663           lc->anim_pause = pause;
1664         }
1665       break;
1666       
1667     case LAMENT_STAR_UNROT:
1668       lc->anim_r -= 1.0;
1669       if (lc->anim_r <= 0.0)
1670         {
1671           lc->anim_r = 0.0;
1672           lc->type = LAMENT_STAR_IN;
1673           lc->anim_pause = pause;
1674         }
1675       break;
1676
1677     case LAMENT_STAR_IN:
1678       lc->anim_z -= 0.01;
1679       if (lc->anim_z <= 0.0)
1680         {
1681           lc->anim_z = 0.0;
1682           lc->type = LAMENT_BOX;
1683           lc->anim_pause = pause3;
1684         }
1685       break;
1686
1687       /* -------------------------------------------------------------- */
1688
1689     case LAMENT_TETRA_UNE:
1690     case LAMENT_TETRA_USW:
1691     case LAMENT_TETRA_DWN:
1692     case LAMENT_TETRA_DSE:
1693
1694       lc->anim_r += 1.0;
1695       if (lc->anim_r >= 360.0)
1696         {
1697           lc->anim_r = 0.0;
1698           lc->type = LAMENT_BOX;
1699           lc->anim_pause = pause3;
1700         }
1701       else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1702         {
1703           lc->anim_r = 120.0;
1704           lc->anim_pause = pause;
1705         }
1706       else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1707         {
1708           lc->anim_r = 240.0;
1709           lc->anim_pause = pause;
1710         }
1711       break;
1712
1713       /* -------------------------------------------------------------- */
1714
1715     case LAMENT_LID_OPEN:
1716       lc->anim_r += 1.0;
1717
1718       if (lc->anim_r >= 112.0)
1719         {
1720           lc->anim_r = 112.0;
1721           lc->anim_z = 0.0;
1722           lc->anim_pause = pause3;
1723           lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
1724         }
1725       break;
1726
1727     case LAMENT_LID_CLOSE:
1728       lc->anim_r -= 1.0;
1729       if (lc->anim_r <= 0.0)
1730         {
1731           lc->anim_r = 0.0;
1732           lc->type = LAMENT_BOX;
1733           lc->anim_pause = pause3;
1734         }
1735       break;
1736
1737     case LAMENT_LID_ZOOM:
1738       lc->anim_z -= 0.1;
1739       if (lc->anim_z < -50.0)
1740         {
1741           lc->anim_r = 0.0;
1742           lc->anim_z = 0.0;
1743           lc->type = LAMENT_BOX;
1744         }
1745       break;
1746
1747       /* -------------------------------------------------------------- */
1748
1749     case LAMENT_TASER_OUT:
1750       lc->anim_z += 0.0025;
1751       if (lc->anim_z >= 0.25)
1752         {
1753           lc->anim_z = 0.25;
1754           lc->type = LAMENT_TASER_SLIDE;
1755           lc->anim_pause = pause * (1 + (random() % 5) + (random() % 5));
1756         }
1757       break;
1758
1759     case LAMENT_TASER_SLIDE:
1760       lc->anim_y += 0.0025;
1761       if (lc->anim_y >= 0.23)
1762         {
1763           lc->anim_y = 0.23;
1764           lc->type = LAMENT_TASER_SLIDE_IN;
1765           lc->anim_pause = pause3 * (1 + (random() % 5) + (random() % 5));
1766         }
1767       break;
1768
1769     case LAMENT_TASER_SLIDE_IN:
1770       lc->anim_y -= 0.0025;
1771       if (lc->anim_y <= 0.0)
1772         {
1773           lc->anim_y = 0.0;
1774           lc->type = LAMENT_TASER_IN;
1775           lc->anim_pause = pause;
1776         }
1777       break;
1778
1779     case LAMENT_TASER_IN:
1780       lc->anim_z -= 0.0025;
1781       if (lc->anim_z <= 0.0)
1782         {
1783           lc->anim_z = 0.0;
1784           lc->type = LAMENT_BOX;
1785           lc->anim_pause = pause3;
1786         }
1787       break;
1788
1789     default:
1790       abort();
1791       break;
1792     }
1793 }
1794
1795
1796 \f
1797 /* Window management, etc
1798  */
1799
1800 ENTRYPOINT void
1801 reshape_lament(ModeInfo *mi, int width, int height)
1802 {
1803   GLfloat h = (GLfloat) height / (GLfloat) width;
1804   glViewport(0, 0, (GLint) width, (GLint) height);
1805
1806   glMatrixMode(GL_PROJECTION);
1807   glLoadIdentity();
1808   glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1809   glMatrixMode(GL_MODELVIEW);
1810   glLoadIdentity();
1811   glTranslatef(0.0, 0.0, -40.0);
1812   glClear(GL_COLOR_BUFFER_BIT);
1813 }
1814
1815
1816 static void
1817 gl_init(ModeInfo *mi)
1818 {
1819   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1820   Bool wire = MI_IS_WIREFRAME(mi);
1821
1822   if (wire)
1823     do_texture = False;
1824
1825   if (!wire)
1826     {
1827       static const GLfloat pos0[]  = { -4.0,  2.0, 5.0, 1.0 };
1828       static const GLfloat pos1[]  = {  6.0, -1.0, 3.0, 1.0 };
1829
1830       static const GLfloat amb0[]  = { 0.7, 0.7, 0.7, 1.0 };
1831 /*    static const GLfloat amb1[]  = { 0.7, 0.0, 0.0, 1.0 }; */
1832       static const GLfloat dif0[]  = { 1.0, 1.0, 1.0, 1.0 };
1833       static const GLfloat dif1[]  = { 0.3, 0.1, 0.1, 1.0 };
1834
1835       glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1836       glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1837
1838       glLightfv(GL_LIGHT0, GL_AMBIENT,  amb0);
1839 /*    glLightfv(GL_LIGHT1, GL_AMBIENT,  amb1); */
1840       glLightfv(GL_LIGHT0, GL_DIFFUSE,  dif0);
1841       glLightfv(GL_LIGHT1, GL_DIFFUSE,  dif1);
1842       set_colors(exterior_color);
1843
1844       glEnable(GL_LIGHTING);
1845       glEnable(GL_LIGHT0);
1846 /*    glEnable(GL_LIGHT1); */
1847
1848       glEnable(GL_DEPTH_TEST);
1849       glEnable(GL_TEXTURE_2D);
1850       glEnable(GL_NORMALIZE);
1851       glEnable(GL_CULL_FACE);
1852     }
1853
1854   if (do_texture)
1855     {
1856 #ifdef HAVE_GLBINDTEXTURE
1857       int i;
1858       for (i = 0; i < 6; i++)
1859         glGenTextures(1, &lc->texids[i]);
1860
1861       parse_image_data(mi);
1862
1863       glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1864       /* messes up -fps */
1865       /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
1866
1867       for (i = 0; i < 6; i++)
1868         {
1869           int height = lc->texture->width;      /* assume square */
1870           glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1871           set_colors(exterior_color);
1872
1873           clear_gl_error();
1874           glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1875                        lc->texture->width, height, 0,
1876                        GL_RGBA,
1877                        /* GL_UNSIGNED_BYTE, */
1878                        GL_UNSIGNED_INT_8_8_8_8_REV,
1879                        (lc->texture->data +
1880                         (lc->texture->bytes_per_line * height * i)));
1881           check_gl_error("texture");
1882
1883           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1884           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1885           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1886           glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1887         }
1888
1889 #else  /* !HAVE_GLBINDTEXTURE */
1890       fprintf(stderr,
1891               "%s: this version of GL doesn't support multiple texture maps.\n"
1892               "\tGet OpenGL 1.1.\n",
1893               progname);
1894       exit (1);
1895 #endif /* !HAVE_GLBINDTEXTURE */
1896     }
1897
1898   lc->box = glGenLists(16);
1899   lc->star1 = lc->box+1;
1900   lc->star2 = lc->box+2;
1901   lc->tetra_une = lc->box+3;
1902   lc->tetra_usw = lc->box+4;
1903   lc->tetra_dwn = lc->box+5;
1904   lc->tetra_dse = lc->box+6;
1905   lc->tetra_mid = lc->box+7;
1906   lc->lid_0 = lc->box+8;
1907   lc->lid_1 = lc->box+9;
1908   lc->lid_2 = lc->box+10;
1909   lc->lid_3 = lc->box+11;
1910   lc->lid_4 = lc->box+12;
1911   lc->taser_base = lc->box+13;
1912   lc->taser_lifter = lc->box+14;
1913   lc->taser_slider = lc->box+15;
1914
1915   box(mi, wire);
1916   star(mi, True, wire);
1917   star(mi, False, wire);
1918   tetra(mi, wire);
1919   lid(mi, wire);
1920   taser(mi, wire);
1921 }
1922
1923
1924 # ifdef HAVE_MESA_GL
1925
1926 # include <signal.h>
1927
1928 static RETSIGTYPE
1929 lament_signal_kludge (int sig)
1930 {
1931   signal (sig, SIG_DFL);
1932   fprintf (stderr,
1933            "\n"
1934            "%s: dying with signal %d (%s).\n"
1935            "\n"
1936            "\tThis is almost certainly a bug in the Mesa GL library,\n"
1937            "\tespecially if the stack trace in the core file mentions\n"
1938            "\t`lambda_textured_triangle' or `render_quad'.\n"
1939            "\n"
1940            "\tFirst make sure that you have the latest version of Mesa.\n"
1941            "\tIf that doesn't fix it, then I encourage you to report this\n"
1942            "\tbug to the Mesa maintainers at <http://www.mesa3d.org/>.\n"
1943            "\n",
1944            progname,
1945            sig,
1946            (sig == SIGILL ? "SIGILL" :
1947             sig == SIGFPE ? "SIGFPE" :
1948             sig == SIGBUS ? "SIGBUS" :
1949             sig == SIGSEGV ? "SIGSEGV" : "???"));
1950   fflush (stderr);
1951   kill (getpid (), sig);
1952 }
1953
1954 static void
1955 handle_signals (void)
1956 {
1957   signal (SIGILL,  lament_signal_kludge);
1958   signal (SIGFPE,  lament_signal_kludge);
1959   signal (SIGBUS,  lament_signal_kludge);
1960   signal (SIGSEGV, lament_signal_kludge);
1961 }
1962 # endif /* HAVE_MESA_GL */
1963
1964
1965 ENTRYPOINT void
1966 init_lament(ModeInfo *mi)
1967 {
1968   lament_configuration *lc;
1969   if (!lcs)
1970     {
1971       lcs = (lament_configuration *)
1972         calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
1973       if (!lcs)
1974         {
1975           fprintf(stderr, "%s: out of memory\n", progname);
1976           exit(1);
1977         }
1978     }
1979
1980   lc = &lcs[MI_SCREEN(mi)];
1981
1982   {
1983     double rot_speed = 0.5;
1984     lc->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
1985     lc->trackball = gltrackball_init ();
1986   }
1987
1988   lc->type = LAMENT_BOX;
1989   lc->anim_pause = 300 + (random() % 100);
1990
1991   if ((lc->glx_context = init_GL(mi)) != NULL)
1992     {
1993       reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1994       gl_init(mi);
1995     }
1996
1997   lc->states = (lament_type *) calloc (50, sizeof (*lc->states));
1998   lc->nstates = 0;
1999   lc->states[lc->nstates++] = LAMENT_STAR_OUT;
2000   lc->states[lc->nstates++] = LAMENT_STAR_OUT;
2001   lc->states[lc->nstates++] = LAMENT_TETRA_UNE;
2002   lc->states[lc->nstates++] = LAMENT_TETRA_USW;
2003   lc->states[lc->nstates++] = LAMENT_TETRA_DWN;
2004   lc->states[lc->nstates++] = LAMENT_TETRA_DSE;
2005   lc->states[lc->nstates++] = LAMENT_LID_OPEN;
2006   lc->states[lc->nstates++] = LAMENT_LID_OPEN;
2007   lc->states[lc->nstates++] = LAMENT_LID_OPEN;
2008   lc->states[lc->nstates++] = LAMENT_TASER_OUT;
2009   lc->states[lc->nstates++] = LAMENT_TASER_OUT;
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   lc->states[lc->nstates++] = LAMENT_BOX;
2019   lc->states[lc->nstates++] = LAMENT_BOX;
2020   shuffle_states (lc);
2021
2022 # ifdef HAVE_MESA_GL
2023   handle_signals ();
2024 # endif /* HAVE_MESA_GL */
2025 }
2026
2027
2028 ENTRYPOINT void
2029 draw_lament(ModeInfo *mi)
2030 {
2031   lament_configuration *lc = &lcs[MI_SCREEN(mi)];
2032   Display *dpy = MI_DISPLAY(mi);
2033   Window window = MI_WINDOW(mi);
2034
2035   if (!lc->glx_context)
2036     return;
2037
2038   glDrawBuffer(GL_BACK);
2039
2040   glXMakeCurrent(dpy, window, *(lc->glx_context));
2041   draw(mi);
2042   if (mi->fps_p) do_fps (mi);
2043
2044   glFinish();
2045   glXSwapBuffers(dpy, window);
2046
2047   if (lc->anim_pause)
2048     lc->anim_pause--;
2049   else
2050     animate(mi);
2051 }
2052
2053 XSCREENSAVER_MODULE ("Lament", lament)
2054
2055 #endif /* USE_GL */