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