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