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