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