1 /* xscreensaver, Copyright (c) 1998-2014 Jamie Zawinski <jwz@jwz.org>
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
12 /* Animates Lemarchand's Box, the Lament Configuration. By jwz, 25-Jul-98.
16 * The gold leaf should appear to be raised up from the surface, but
17 I think this isn't possible with OpenGL. No bump maps.
19 * There should be strange lighting effects playing across the surface:
20 electric sparks, or little glittery blobs of light. Maybe like
21 http://www.opengl.org/archives/resources/features/KilgardTechniques/
26 * Needs music. ("Hellraiser Themes" by Coil: TORSO CD161; also
27 duplicated on the "Unnatural History 2" compilation, WORLN M04699.)
30 #define DEFAULTS "*delay: 20000 \n" \
31 "*showFPS: False \n" \
32 "*wireframe: False \n" \
33 "*suppressRotationAnimation: True\n" \
35 # define free_lament 0
36 # define release_lament 0
37 #include "xlockmore.h"
39 #ifdef USE_GL /* whole file */
43 /* #define DEBUG_MODE LAMENT_LEVIATHAN_COLLAPSE */
46 #define countof(x) (sizeof((x))/sizeof((*x)))
48 #define MAX(x, y) ((x) > (y) ? (x) : (y))
50 #define MIN(x, y) ((x) < (y) ? (x) : (y))
52 extern const struct gllist
54 *lament_model_iso_base_a,
55 *lament_model_iso_base_b,
56 *lament_model_iso_den,
57 *lament_model_iso_dse,
58 *lament_model_iso_dwn,
59 *lament_model_iso_swd,
60 *lament_model_iso_une,
61 *lament_model_iso_unw,
62 *lament_model_iso_use,
63 *lament_model_iso_usw,
64 *lament_model_leviathan,
67 *lament_model_lid_base,
70 *lament_model_pillar_a,
71 *lament_model_pillar_b,
72 *lament_model_pillar_base,
75 *lament_model_taser_a,
76 *lament_model_taser_b,
77 *lament_model_taser_base,
78 *lament_model_tetra_base,
79 *lament_model_tetra_dse,
80 *lament_model_tetra_dwn,
81 *lament_model_tetra_une,
82 *lament_model_tetra_usw;
84 static const struct gllist * const *all_objs[] = {
86 &lament_model_iso_base_a,
87 &lament_model_iso_base_b,
88 &lament_model_iso_den,
89 &lament_model_iso_dse,
90 &lament_model_iso_dwn,
91 &lament_model_iso_swd,
92 &lament_model_iso_une,
93 &lament_model_iso_unw,
94 &lament_model_iso_use,
95 &lament_model_iso_usw,
96 &lament_model_leviathan,
99 &lament_model_lid_base,
102 &lament_model_pillar_a,
103 &lament_model_pillar_b,
104 &lament_model_pillar_base,
105 &lament_model_star_d,
106 &lament_model_star_u,
107 &lament_model_taser_a,
108 &lament_model_taser_b,
109 &lament_model_taser_base,
110 &lament_model_tetra_base,
111 &lament_model_tetra_dse,
112 &lament_model_tetra_dwn,
113 &lament_model_tetra_une,
114 &lament_model_tetra_usw
117 typedef enum { /* must be in the same order as in `all_objs'. */
151 #define DEF_TEXTURE "True"
153 static int do_texture;
155 static XrmOptionDescRec opts[] = {
156 {"-texture", ".lament.texture", XrmoptionNoArg, "true" },
157 {"+texture", ".lament.texture", XrmoptionNoArg, "false" },
160 static argtype vars[] = {
161 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
164 ENTRYPOINT ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars, NULL};
166 #include "xpm-ximage.h"
168 #include "gltrackball.h"
172 __extension__ /* don't warn about "string length is greater than the length
173 ISO C89 compilers are required to support" when including
174 the following XPM file... */
176 #include "../images/lament512.xpm"
178 #define RANDSIGN() ((random() & 1) ? 1 : -1)
201 LAMENT_TASER_SLIDE_IN,
211 LAMENT_LEVIATHAN_SPIN,
212 LAMENT_LEVIATHAN_FADE,
213 LAMENT_LEVIATHAN_TWIST,
214 LAMENT_LEVIATHAN_COLLAPSE,
215 LAMENT_LEVIATHAN_EXPAND,
216 LAMENT_LEVIATHAN_UNTWIST,
217 LAMENT_LEVIATHAN_UNFADE,
218 LAMENT_LEVIATHAN_UNSPIN,
222 static const GLfloat exterior_color[] =
223 { 0.33, 0.22, 0.03, 1.00, /* ambient */
224 0.78, 0.57, 0.11, 1.00, /* specular */
225 0.99, 0.91, 0.81, 1.00, /* diffuse */
226 27.80 /* shininess */
228 static const GLfloat interior_color[] =
229 { 0.20, 0.20, 0.15, 1.00, /* ambient */
230 0.40, 0.40, 0.32, 1.00, /* specular */
231 0.99, 0.99, 0.81, 1.00, /* diffuse */
232 50.80 /* shininess */
234 static const GLfloat leviathan_color[] =
235 { 0.30, 0.30, 0.30, 1.00, /* ambient */
236 0.85, 0.85, 0.95, 1.00, /* specular */
237 0.99, 0.99, 0.99, 1.00, /* diffuse */
238 50.80 /* shininess */
240 static const GLfloat black_color[] =
241 { 0.05, 0.05, 0.05, 1.00, /* ambient */
242 0.05, 0.05, 0.05, 1.00, /* specular */
243 0.05, 0.05, 0.05, 1.00, /* diffuse */
244 80.00 /* shininess */
249 GLXContext *glx_context;
251 double rotx, roty, rotz;
252 trackball_state *trackball;
256 GLuint dlists[countof(all_objs)];
257 GLuint polys[countof(all_objs)];
259 XImage *texture; /* image bits */
260 GLuint texids[8]; /* texture map IDs */
261 lament_type type; /* which mode of the object is current */
263 int anim_pause; /* countdown before animating again */
264 GLfloat anim_r, anim_y, anim_z; /* relative position during anims */
270 } lament_configuration;
272 static lament_configuration *lcs = NULL;
276 facing_screen_p (ModeInfo *mi)
279 GLdouble m[16], p[16], x, y, z;
281 glGetDoublev (GL_MODELVIEW_MATRIX, m);
282 glGetDoublev (GL_PROJECTION_MATRIX, p);
283 glGetIntegerv (GL_VIEWPORT, v);
285 /* See if a coordinate 5 units in front of the door is near the
286 center of the screen. */
287 gluProject (0, -5, 0, m, p, v, &x, &y, &z);
288 x = (x / MI_WIDTH(mi)) - 0.5;
289 y = (y / MI_HEIGHT(mi)) - 0.5;
291 facing_p = (z < 0.9 &&
292 x > -0.15 && x < 0.15 &&
293 y > -0.15 && y < 0.15);
296 glBindTexture(GL_TEXTURE_2D, 0);
297 glDisable (GL_LIGHTING);
298 glColor3f (1, (facing_p ? 1 : 0), 0);
300 glVertex3f (0, 0, 0);
301 glVertex3f (0, -5, 0);
303 if (!MI_IS_WIREFRAME(mi)) glEnable (GL_LIGHTING);
304 # endif /* DEBUG_MODE */
311 scale_for_window (ModeInfo *mi)
313 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
315 GLfloat target_size = 1.4 * (lc->texture ? lc->texture->width : 512);
316 GLfloat size = MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi);
319 /* Make it take up roughly the full width of the window. */
322 /* But if the window is wider than tall, make it only take up the
323 height of the window instead.
325 if (MI_WIDTH(mi) > MI_HEIGHT(mi))
326 scale /= MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi);
328 /* If the window is super wide, make it bigger. */
329 if (scale < 8) scale = 8;
331 /* Constrain it to roughly life-sized on the screen, not huge.
334 if (size > 768) /* iPad retina / iPhone 6 */
339 GLfloat max = 500; /* 3" on my screen... */
340 if (target_size > max)
344 /* But if that would make the image larger than target_size, scale it
345 back down again. The image-map bits we have are 512x512, so if the
346 image is magnified a lot, it looks pretty blocky. It's better to
347 have a 512x512 animation on a 1920x1080 screen that looks good
348 than a 1024x1024 animation that looks really pixelated.
350 if (size > target_size)
351 scale *= target_size / size;
353 glScalef (scale, scale, scale);
358 set_colors (const GLfloat *color)
360 glMaterialfv(GL_FRONT, GL_AMBIENT, color + 0);
361 glMaterialfv(GL_FRONT, GL_DIFFUSE, color + 4);
362 glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
363 glMaterialfv(GL_FRONT, GL_SHININESS, color + 12);
367 set_colors_alpha (const GLfloat *color, GLfloat a)
369 GLfloat c[countof(leviathan_color)];
370 memcpy (c, color, sizeof(c));
371 c[3] = c[7] = c[11] = a;
377 which_face (ModeInfo *mi, const GLfloat *f, int *face, int *outerp)
379 GLfloat size = 3; /* 3" square */
380 const GLfloat *n = f; /* normal */
381 const GLfloat *v = f + 3; /* vertex */
382 GLfloat slack = 0.01;
384 /* First look at the normal to determine which direction this triangle
385 is facing (or is most-closely facing).
386 It's an outer surface if it is within epsilon of the cube wall that
387 it is facing. Otherwise, it's an inner surface.
389 if (n[1] < -0.5) *face = 1, *outerp = v[1] < slack; /* S */
390 else if (n[2] > 0.5) *face = 2, *outerp = v[2] > size-slack; /* U */
391 else if (n[1] > 0.5) *face = 3, *outerp = v[1] > size-slack; /* N */
392 else if (n[2] < -0.5) *face = 4, *outerp = v[2] < slack; /* D */
393 else if (n[0] < -0.5) *face = 5, *outerp = v[0] < slack; /* W */
394 else /* (n[0] > 0.5)*/ *face = 6, *outerp = v[0] > size-slack; /* E */
396 /* Faces that don't have normals parallel to the axes aren't external. */
398 (n[0] > -0.95 && n[0] < 0.95 &&
399 n[1] > -0.95 && n[1] < 0.95 &&
400 n[2] > -0.95 && n[2] < 0.95))
406 texturize_vert (ModeInfo *mi, int which, const GLfloat *v)
408 GLfloat size = 3; /* 3" square */
409 GLfloat s = 0, q = 0;
411 /* Texture coordinates are surface coordinates,
412 on the plane of this cube wall. */
415 case 1: s = v[0], q = v[2]; break;
416 case 2: s = v[0], q = v[1]; break;
417 case 3: s = v[0], q = v[2]; q = size - q; break;
418 case 4: s = v[0], q = v[1]; q = size - q; break;
419 case 5: s = v[1], q = v[2]; break;
420 case 6: s = v[1], q = v[2]; break;
421 default: abort(); break;
424 glTexCoord2f (s / size, q / size);
429 leviathan (ModeInfo *mi, GLfloat ratio, GLfloat alpha, Bool top_p)
431 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
432 Bool wire = MI_IS_WIREFRAME(mi);
434 GLfloat z = 2 * ratio;
438 GLfloat th = acos (2 / sqrt (6)); /* Line up with cube's diagonal */
442 glRotatef (-45, 0, 1, 0);
443 glRotatef (-th * 180 / M_PI, 0, 0, 1);
446 glRotatef (180, 0, 0, 1);
448 for (i = 0; i < countof(p); i++)
450 GLfloat th = i * M_PI * 2 / countof(p);
451 p[i].x = cos(th) * r;
452 p[i].y = sin(th) * r;
455 glFrontFace (GL_CCW);
456 for (i = 0; i < countof(p); i++)
458 int j = (i + 1) % countof(p);
470 if (do_texture) /* Leviathan is the final texture */
471 glBindTexture (GL_TEXTURE_2D, lc->texids[countof(lc->texids) - 1]);
473 set_colors (leviathan_color);
475 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
476 glTexCoord2f (0.5, 1);
477 glVertex3f (z, 0, 0);
480 glVertex3f (0, p[i].x, p[i].y);
483 glVertex3f (0, p[j].x, p[j].y);
487 /* Shield for fading */
488 if (alpha < 0.9 && !wire)
493 set_colors_alpha (black_color, 1-alpha);
494 glBindTexture (GL_TEXTURE_2D, 0);
498 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
501 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
503 glVertex3f (z*a, p[j].x * b, p[j].y * b);
504 glVertex3f (z*a, p[i].x * b, p[i].y * b);
505 glVertex3f (0, p[i].x * 1.01, p[i].y * 1.01);
506 glVertex3f (0, p[j].x * 1.01, p[j].y * 1.01);
509 glDisable (GL_BLEND);
518 folding_walls (ModeInfo *mi, GLfloat ratio, Bool top_p)
520 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
521 Bool wire = MI_IS_WIREFRAME(mi);
522 const GLfloat pa[4][2] = {{ -0.5, -0.215833 },
525 { -0.215833, -0.5 }};
526 const int tex[6] = { 0, 5, 1, 4, 2, 3 };
527 const GLfloat top = -pa[0][1];
528 GLfloat end_angle = 30.85;
529 GLfloat rr = sin (ratio / 2 * M_PI);
530 GLfloat offa = 0.15 * rr;
531 GLfloat offb = 0.06 * rr;
540 glRotatef (60, 1, -1, 1);
541 glRotatef (180, 0, 1, 0);
542 glRotatef (90, 1, 0, 0);
546 glRotatef (180, 1, 0, 0);
549 /* Scale down the points near the axis */
555 p[1][0] = pa[1][0] - offb;
557 p[1][2] = pa[1][1] - offa;
559 p[2][0] = pa[2][0] - offa;
561 p[2][2] = pa[2][1] - offb;
570 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
573 for (i = 0; i < 3; i++)
579 glRotatef (-90, 1, 0, 0);
580 glRotatef (180, 1, 1, 0);
584 glRotatef (-90, 1, 0, 0);
585 glRotatef (180, 0, 1, 0);
586 glRotatef (90, 0, 1, 0);
589 glRotatef (-90, 0, 1, 0);
591 glTranslatef (-(top/2 + 0.25), 0.5, -(top/2 + 0.25));
592 glRotatef (-45, 0, 1, 0);
593 glRotatef (ratio * -end_angle, 0, 0, 1);
594 glRotatef (45, 0, 1, 0);
595 glTranslatef (top/2 + 0.25, -0.5, top/2 + 0.25);
597 /* Get the texture coordinates right.
598 This is hairy and incomprehensible. */
600 t[0][0] = pa[0][1] + 0.5; t[0][1] = pa[0][0] + 0.5;
601 t[1][0] = pa[1][1] + 0.5; t[1][1] = pa[1][0] + 0.5;
602 t[2][0] = pa[2][1] + 0.5; t[2][1] = pa[2][0] + 0.5;
603 t[3][0] = pa[3][1] + 0.5; t[3][1] = pa[3][0] + 0.5;
605 if (i == 0 && !top_p)
607 # define SWAP(A,B) A = 1-A, B = 1-B
608 SWAP(t[0][0], t[0][1]);
609 SWAP(t[1][0], t[1][1]);
610 SWAP(t[2][0], t[2][1]);
611 SWAP(t[3][0], t[3][1]);
614 else if (i == 0 && top_p)
617 memcpy (ot, t, sizeof(t));
618 # define SWAP(A,B) A = 1-A, B = 1-B
619 SWAP(t[0][0], ot[2][1]);
620 SWAP(t[1][0], ot[3][1]);
621 SWAP(t[2][0], ot[0][1]);
622 SWAP(t[3][0], ot[1][1]);
628 # define SWAP(A,B) f = A, A = B, B = -f
629 SWAP(t[0][0], t[0][1]);
630 SWAP(t[1][0], t[1][1]);
631 SWAP(t[2][0], t[2][1]);
632 SWAP(t[3][0], t[3][1]);
636 set_colors_alpha (exterior_color, 1-ratio);
637 glBindTexture (GL_TEXTURE_2D, lc->texids[tex[i + (top_p ? 3 : 0)]]);
639 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
640 do_normal (p[0][0], p[0][1], p[0][2],
641 p[1][0], p[1][1], p[1][2],
642 p[2][0], p[2][1], p[2][2]);
643 glTexCoord2fv(t[0]); glVertex3fv(p[0]);
644 glTexCoord2fv(t[1]); glVertex3fv(p[1]);
645 glTexCoord2fv(t[2]); glVertex3fv(p[2]);
646 glTexCoord2fv(t[3]); glVertex3fv(p[3]);
650 /* The triangles between the quads */
652 /* #### There is a fucking gap between the two black triangles
653 that I can't figure out! So instead of drawing the triangles,
654 we build a black shield around the middle bit in leviathan()
655 and count on back-face culling to have roughly the same effect.
660 memcpy (pp, p, sizeof(pp));
661 memcpy (pp[2], pp[1], sizeof(pp[1]));
662 pp[2][0] -= 0.5 * (1-ratio);
663 pp[2][1] -= 0.5 * (1-ratio);
665 glBindTexture (GL_TEXTURE_2D, 0);
666 set_colors_alpha (black_color, 1-ratio);
668 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
669 do_normal (pp[0][0], pp[0][1], pp[0][2],
670 pp[2][0], pp[2][1], pp[2][2],
671 pp[1][0], pp[1][1], pp[1][2]);
683 if (! wire) glDisable (GL_BLEND);
690 lament_sphere (ModeInfo *mi, GLfloat ratio)
692 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
693 Bool wire = MI_IS_WIREFRAME(mi);
694 GLfloat size = 3; /* 3" square */
696 int facets = 16; /* NxN grid on each face */
698 static const GLfloat norms[6][3] = {{ 0, -1, 0 }, { 0, 0, 1 }, { 0, 1, 0 },
699 { 0, 0, -1 }, { -1, 0, 0 }, { 1, 0, 0 }};
700 GLfloat s = 1.0 / facets;
702 /* The ratio used for the normals: linger on the square normals. */
703 GLfloat ratio2 = 1 - sin ((1 - ratio) / 2 * M_PI);
704 GLfloat r1 = 1 - ratio2 / 2;
705 GLfloat r2 = ratio2 / 2;
708 glTranslatef (-0.5, -0.5, -0.5);
709 glScalef (1/size, 1/size, 1/size);
711 set_colors (exterior_color);
713 for (face = 0; face < 6; face++)
716 for (y0 = 0; y0 < 1; y0 += s)
717 for (x0 = 0; x0 < 1; x0 += s)
722 GLfloat pa[4][3]; /* verts of the cube */
723 GLfloat pb[4][3]; /* verts of the transition to the sphere */
725 GLfloat norm[4][3]; /* normals of the transitional verts */
728 frontp = norms[face][0] < 0,
729 pa[0][1] = x0, pa[0][2] = y0, pa[0][0] = (frontp ? 0 : 1),
730 pa[1][1] = x1, pa[1][2] = y0, pa[1][0] = pa[0][0],
731 pa[2][1] = x1, pa[2][2] = y1, pa[2][0] = pa[0][0],
732 pa[3][1] = x0, pa[3][2] = y1, pa[3][0] = pa[0][0];
733 else if (norms[face][1])
734 frontp = norms[face][1] > 0,
735 pa[0][0] = x0, pa[0][2] = y0, pa[0][1] = (frontp ? 1 : 0),
736 pa[1][0] = x1, pa[1][2] = y0, pa[1][1] = pa[0][1],
737 pa[2][0] = x1, pa[2][2] = y1, pa[2][1] = pa[0][1],
738 pa[3][0] = x0, pa[3][2] = y1, pa[3][1] = pa[0][1];
739 else /* (norms[face][2]) */
740 frontp = norms[face][2] < 0,
741 pa[0][0] = x0, pa[0][1] = y0, pa[0][2] = (frontp ? 0 : 1),
742 pa[1][0] = x1, pa[1][1] = y0, pa[1][2] = pa[0][2],
743 pa[2][0] = x1, pa[2][1] = y1, pa[2][2] = pa[0][2],
744 pa[3][0] = x0, pa[3][1] = y1, pa[3][2] = pa[0][2];
746 for (i = 0; i < countof(pa); i++)
747 pa[i][0] *= size, pa[i][1] *= size, pa[i][2] *= size;
749 /* Convert square to sphere by treating as a normalized vector */
750 for (i = 0; i < countof(pa); i++)
752 GLfloat x = (pa[i][0] / size) - 0.5;
753 GLfloat y = (pa[i][1] / size) - 0.5;
754 GLfloat z = (pa[i][2] / size) - 0.5;
755 GLfloat d = sqrt (x*x + y*y + z*z) / 2;
760 pb[i][0] = pa[i][0] + ((x - pa[i][0]) * ratio);
761 pb[i][1] = pa[i][1] + ((y - pa[i][1]) * ratio);
762 pb[i][2] = pa[i][2] + ((z - pa[i][2]) * ratio);
765 /* The normals of an intermediate point are the weighted average
766 of the cube's orthogonal normals, and the sphere's radial
767 normals: early in the sequence, the edges are sharp, but they
768 soften as it expands. */
770 XYZ na, pa0, pa1, pa2;
771 pa0.x = pa[0][0]; pa0.y = pa[0][1]; pa0.z = pa[0][2];
772 pa1.x = pa[1][0]; pa1.y = pa[1][1]; pa1.z = pa[1][2];
773 pa2.x = pa[2][0]; pa2.y = pa[2][1]; pa2.z = pa[2][2];
774 na = calc_normal (pa0, pa1, pa2);
776 for (i = 0; i < countof(pb); i++)
784 d = sqrt (nb.x*nb.x + nb.y*nb.y + nb.z*nb.z); /* normalize */
789 norm[i][0] = (na.x * r1) + (nb.x * r2); /* weighted */
790 norm[i][1] = (na.y * r1) + (nb.y * r2);
791 norm[i][2] = (na.z * r1) + (nb.z * r2);
796 glBindTexture (GL_TEXTURE_2D, lc->texids[face]);
798 glFrontFace (frontp ? GL_CW : GL_CCW);
799 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
801 texturize_vert (mi, face+1, pa[0]);
802 glNormal3fv (norm[0]);
805 texturize_vert (mi, face+1, pa[1]);
806 glNormal3fv (norm[1]);
809 texturize_vert (mi, face+1, pa[2]);
810 glNormal3fv (norm[2]);
813 texturize_vert (mi, face+1, pa[3]);
814 glNormal3fv (norm[3]);
831 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
832 Bool wire = MI_IS_WIREFRAME(mi);
834 mi->polygon_count = 0;
837 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
839 glClear(GL_COLOR_BUFFER_BIT);
843 gltrackball_rotate (lc->trackball);
845 /* Make into the screen be +Y, right be +X, and up be +Z. */
846 glRotatef (-90.0, 1.0, 0.0, 0.0);
848 scale_for_window (mi);
850 /* Apply rotation to the object. */
851 if (lc->type != LAMENT_LID_ZOOM)
852 get_rotation (lc->rot, &lc->rotx, &lc->roty, &lc->rotz,
857 lc->rotx = lc->roty = 0;
861 glRotatef (lc->rotx * 360, 1, 0, 0);
862 glRotatef (lc->roty * 360, 0, 1, 0);
863 glRotatef (lc->rotz * 360, 0, 0, 1);
865 glScalef (0.5, 0.5, 0.5);
870 glCallList (lc->dlists[OBJ_BOX]);
871 mi->polygon_count += lc->polys[OBJ_BOX];
874 case LAMENT_STAR_OUT:
875 case LAMENT_STAR_ROT:
876 case LAMENT_STAR_ROT_IN:
877 case LAMENT_STAR_ROT_OUT:
878 case LAMENT_STAR_UNROT:
880 glTranslatef (0.0, 0.0, lc->anim_z/2);
881 glRotatef (lc->anim_r/2, 0.0, 0.0, 1.0);
882 glCallList (lc->dlists[OBJ_STAR_U]);
883 mi->polygon_count += lc->polys[OBJ_STAR_U];
885 glTranslatef (0.0, 0.0, -lc->anim_z);
886 glRotatef (-lc->anim_r, 0.0, 0.0, 1.0);
887 glCallList (lc->dlists[OBJ_STAR_D]);
888 mi->polygon_count += lc->polys[OBJ_STAR_D];
891 case LAMENT_TETRA_UNE:
892 case LAMENT_TETRA_USW:
893 case LAMENT_TETRA_DWN:
894 case LAMENT_TETRA_DSE:
899 case LAMENT_TETRA_UNE: magic = OBJ_TETRA_UNE; x= 1; y= 1; z= 1; break;
900 case LAMENT_TETRA_USW: magic = OBJ_TETRA_USW; x= 1; y= 1; z=-1; break;
901 case LAMENT_TETRA_DWN: magic = OBJ_TETRA_DWN; x= 1; y=-1; z= 1; break;
902 case LAMENT_TETRA_DSE: magic = OBJ_TETRA_DSE; x=-1; y= 1; z= 1; break;
903 default: abort(); break;
905 glCallList(lc->dlists[OBJ_TETRA_BASE]);
906 mi->polygon_count += lc->polys[OBJ_TETRA_BASE];
907 if (magic != OBJ_TETRA_UNE) glCallList (lc->dlists[OBJ_TETRA_UNE]);
908 if (magic != OBJ_TETRA_USW) glCallList (lc->dlists[OBJ_TETRA_USW]);
909 if (magic != OBJ_TETRA_DWN) glCallList (lc->dlists[OBJ_TETRA_DWN]);
910 if (magic != OBJ_TETRA_DSE) glCallList (lc->dlists[OBJ_TETRA_DSE]);
911 glRotatef (lc->anim_r, x, y, z);
912 glCallList (lc->dlists[magic]);
913 mi->polygon_count += lc->polys[magic] * 3;
917 case LAMENT_LID_OPEN:
918 case LAMENT_LID_CLOSE:
919 case LAMENT_LID_ZOOM:
923 const int lists[4] = { OBJ_LID_A, OBJ_LID_B, OBJ_LID_C, OBJ_LID_D };
925 lc->facing_p = facing_screen_p (mi);
927 if (lc->anim_z < 0.5)
928 glTranslatef (0, -30 * lc->anim_z, 0); /* zoom */
930 glTranslatef (8 * (0.5 - (lc->anim_z - 0.5)), 0, 0);
932 glCallList (lc->dlists[OBJ_LID_BASE]);
933 mi->polygon_count += lc->polys[OBJ_LID_BASE];
934 for (i = 0; i < countof(lists); i++)
937 glRotatef (90 * i, 0, 1, 0);
938 glTranslatef (-d, -0.5, d);
939 glRotatef (-45, 0, 1, 0);
940 glRotatef (-lc->anim_r, 1, 0, 0);
941 glRotatef (45, 0, 1, 0);
942 glTranslatef (d, 0.5, -d);
943 glRotatef (-90 * i, 0, 1, 0);
944 glCallList (lc->dlists[lists[i]]);
945 mi->polygon_count += lc->polys[lists[i]];
953 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
954 glVertex3f (-0.49, 0.49, -0.49);
955 glVertex3f ( 0.49, 0.49, -0.49);
956 glVertex3f ( 0.49, 0.49, 0.49);
957 glVertex3f (-0.49, 0.49, 0.49);
961 # endif /* DEBUG_MODE */
965 case LAMENT_TASER_OUT:
966 case LAMENT_TASER_SLIDE:
967 case LAMENT_TASER_SLIDE_IN:
968 case LAMENT_TASER_IN:
970 glTranslatef (0, -lc->anim_z/2, 0);
971 glCallList (lc->dlists[OBJ_TASER_BASE]);
972 mi->polygon_count += lc->polys[OBJ_TASER_BASE];
974 glTranslatef (0, lc->anim_z, 0);
975 glCallList (lc->dlists[OBJ_TASER_A]);
976 mi->polygon_count += lc->polys[OBJ_TASER_A];
978 glTranslatef (lc->anim_y, 0, 0);
979 glCallList (lc->dlists[OBJ_TASER_B]);
980 mi->polygon_count += lc->polys[OBJ_TASER_B];
983 case LAMENT_PILLAR_OUT:
984 case LAMENT_PILLAR_SPIN:
985 case LAMENT_PILLAR_IN:
987 glCallList (lc->dlists[OBJ_PILLAR_BASE]);
988 mi->polygon_count += lc->polys[OBJ_PILLAR_BASE];
991 if (lc->anim_z == 1 || lc->anim_z == 3)
993 glRotatef (lc->anim_r, 0, 0, 1);
994 glTranslatef (0, 0, lc->anim_y);
996 glCallList (lc->dlists[OBJ_PILLAR_A]);
997 mi->polygon_count += lc->polys[OBJ_PILLAR_A];
1001 if (lc->anim_z == 2 || lc->anim_z == 3)
1003 glRotatef (lc->anim_r, 0, 0, 1);
1004 glTranslatef (0, 0, -lc->anim_y);
1006 glCallList (lc->dlists[OBJ_PILLAR_B]);
1007 mi->polygon_count += lc->polys[OBJ_PILLAR_B];
1011 case LAMENT_SPHERE_OUT:
1012 case LAMENT_SPHERE_IN:
1013 mi->polygon_count += lament_sphere (mi, lc->anim_y);
1016 case LAMENT_LEVIATHAN_SPIN:
1017 case LAMENT_LEVIATHAN_UNSPIN:
1018 case LAMENT_LEVIATHAN_FADE:
1019 case LAMENT_LEVIATHAN_UNFADE:
1020 case LAMENT_LEVIATHAN_TWIST:
1021 case LAMENT_LEVIATHAN_UNTWIST:
1023 /* These normals are hard to compute, so I pulled them from the
1025 const GLfloat axes[6][4] =
1026 {{ OBJ_ISO_UNE, 0.633994, 0.442836, 0.633994 },
1027 { OBJ_ISO_USW, 0.442836, 0.633994, -0.633994 },
1028 { OBJ_ISO_DSE, -0.633994, 0.633994, 0.442836 },
1029 { OBJ_ISO_SWD, -0.633994, -0.442836, -0.633994 },
1030 { OBJ_ISO_DEN, -0.442836, -0.633994, 0.633994 },
1031 { OBJ_ISO_UNW, 0.633994, -0.633994, -0.442836 }};
1034 GLfloat s = (1 - lc->anim_z);
1035 GLfloat s2 = MAX (0, 360 - lc->anim_r) / 360.0;
1039 case LAMENT_LEVIATHAN_SPIN: break;
1040 case LAMENT_LEVIATHAN_UNSPIN: s2 = 1 - s2; break;
1041 default: s2 = 0; blendp = 1; break;
1044 if (wire) blendp = 0;
1046 s = (s * 0.6) + 0.4;
1048 leviathan (mi, 1 - s2, 1, True);
1049 glCallList (lc->dlists[OBJ_ISO_BASE_A]);
1050 mi->polygon_count += lc->polys[OBJ_ISO_BASE_A];
1053 glScalef (s2, s2, s2);
1054 glCallList (lc->dlists[OBJ_ISO_USE]);
1055 mi->polygon_count += lc->polys[OBJ_ISO_USE];
1059 glRotatef (lc->anim_y, 1, -1, 1);
1060 glCallList (lc->dlists[OBJ_ISO_BASE_B]);
1061 mi->polygon_count += lc->polys[OBJ_ISO_BASE_B];
1062 leviathan (mi, 1 - s2, 1, False);
1067 # ifndef HAVE_JWZGLES /* no glBlendColor */
1068 glEnable (GL_BLEND);
1069 glBlendFunc (GL_CONSTANT_ALPHA, GL_SRC_ALPHA);
1070 glBlendColor (1, 1, 1, MAX(0, 1-(lc->anim_z * 3)));
1074 for (i = 0; i < countof(axes); i++)
1077 glRotatef (lc->anim_r, axes[i][1], axes[i][2], axes[i][3]);
1079 glCallList (lc->dlists[(int) axes[i][0]]);
1080 mi->polygon_count += lc->polys[(int) axes[i][0]];
1083 glRotatef (lc->anim_y, 1, -1, 1);
1086 if (blendp) glDisable (GL_BLEND);
1089 glScalef (s2, s2, s2);
1090 glCallList (lc->dlists[OBJ_ISO_DWN]);
1091 mi->polygon_count += lc->polys[OBJ_ISO_DWN];
1096 case LAMENT_LEVIATHAN_COLLAPSE:
1097 case LAMENT_LEVIATHAN_EXPAND:
1100 leviathan (mi, 1, lc->anim_y, True);
1101 glRotatef (180, 1, -1, 1);
1102 leviathan (mi, 1, lc->anim_y, False);
1104 folding_walls (mi, lc->anim_y, True);
1105 folding_walls (mi, lc->anim_y, False);
1118 /* Rather than just picking states randomly, pick an ordering randomly, do it,
1119 and then re-randomize. That way one can be assured of seeing all states in
1120 a short time period, though not always in the same order (it's frustrating
1121 to see it pick the same state 5x in a row.) Though, that can still happen,
1122 since states are in the list multiple times as a way of giving them
1126 shuffle_states (lament_configuration *lc)
1129 for (i = 0; i < lc->nstates; i++)
1131 int a = random() % lc->nstates;
1132 lament_type swap = lc->states[a];
1133 lc->states[a] = lc->states[i];
1134 lc->states[i] = swap;
1140 animate (ModeInfo *mi)
1142 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1145 GLfloat speed = (lc->ffwdp ? 20 : 1);
1152 if (lc->state >= lc->nstates)
1154 shuffle_states (lc);
1157 lc->type = lc->states[lc->state];
1159 if (lc->type == LAMENT_BOX)
1160 lc->anim_pause = pause2;
1168 /* -------------------------------------------------------------- */
1170 case LAMENT_STAR_OUT:
1171 lc->anim_z += 0.01 * speed;
1172 if (lc->anim_z >= 1.0)
1175 lc->type = LAMENT_STAR_ROT;
1176 lc->anim_pause = pause;
1180 case LAMENT_STAR_ROT:
1181 lc->anim_r += 1.0 * speed;
1182 if (lc->anim_r >= 45.0)
1185 lc->type = LAMENT_STAR_ROT_IN;
1186 lc->anim_pause = pause;
1190 case LAMENT_STAR_ROT_IN:
1191 lc->anim_z -= 0.01 * speed;
1192 if (lc->anim_z <= 0.0)
1195 lc->type = LAMENT_STAR_ROT_OUT;
1196 lc->anim_pause = pause2 * (1 + frand(2) + frand(2));
1200 case LAMENT_STAR_ROT_OUT:
1201 lc->anim_z += 0.01 * speed;
1202 if (lc->anim_z >= 1.0)
1205 lc->type = LAMENT_STAR_UNROT;
1206 lc->anim_pause = pause;
1210 case LAMENT_STAR_UNROT:
1211 lc->anim_r -= 1.0 * speed;
1212 if (lc->anim_r <= 0.0)
1215 lc->type = LAMENT_STAR_IN;
1216 lc->anim_pause = pause;
1220 case LAMENT_STAR_IN:
1221 lc->anim_z -= 0.01 * speed;
1222 if (lc->anim_z <= 0.0)
1225 lc->type = LAMENT_BOX;
1226 lc->anim_pause = pause2;
1230 /* -------------------------------------------------------------- */
1232 case LAMENT_TETRA_UNE:
1233 case LAMENT_TETRA_USW:
1234 case LAMENT_TETRA_DWN:
1235 case LAMENT_TETRA_DSE:
1237 lc->anim_r += 1.0 * speed;
1238 if (lc->anim_r >= 360.0)
1241 lc->type = LAMENT_BOX;
1242 lc->anim_pause = pause2;
1244 else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1247 lc->anim_pause = pause;
1249 else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1252 lc->anim_pause = pause;
1256 /* -------------------------------------------------------------- */
1258 case LAMENT_LID_OPEN:
1259 lc->anim_r += 1.0 * speed;
1261 if (lc->anim_r >= 112.0)
1265 lc->anim_pause = pause2;
1266 lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
1270 case LAMENT_LID_CLOSE:
1271 lc->anim_r -= 1.0 * speed;
1272 if (lc->anim_r <= 0.0)
1275 lc->type = LAMENT_BOX;
1276 lc->anim_pause = pause2;
1280 case LAMENT_LID_ZOOM:
1281 lc->anim_z += 0.01 * speed;
1282 if (lc->anim_z > 1.0)
1286 lc->type = LAMENT_BOX;
1290 /* -------------------------------------------------------------- */
1292 case LAMENT_TASER_OUT:
1293 lc->anim_z += 0.005 * speed;
1294 if (lc->anim_z >= 0.5)
1297 lc->type = LAMENT_TASER_SLIDE;
1298 lc->anim_pause = pause * (1 + frand(5) + frand(5));
1302 case LAMENT_TASER_SLIDE:
1303 lc->anim_y += 0.005 * speed;
1304 if (lc->anim_y >= 0.255)
1307 lc->type = LAMENT_TASER_SLIDE_IN;
1308 lc->anim_pause = pause2 * (1 + frand(5) + frand(5));
1312 case LAMENT_TASER_SLIDE_IN:
1313 lc->anim_y -= 0.0025 * speed;
1314 if (lc->anim_y <= 0.0)
1317 lc->type = LAMENT_TASER_IN;
1318 lc->anim_pause = pause;
1322 case LAMENT_TASER_IN:
1323 lc->anim_z -= 0.0025 * speed;
1324 if (lc->anim_z <= 0.0)
1327 lc->type = LAMENT_BOX;
1328 lc->anim_pause = pause2;
1332 /* -------------------------------------------------------------- */
1334 case LAMENT_PILLAR_OUT:
1336 if (lc->anim_y == 0) /* mostly in */
1337 lc->anim_y += 0.005 * ((random() % 5) ? -1 : 1) * speed;
1338 else if (lc->anim_y > 0)
1339 lc->anim_y += 0.005 * speed;
1341 lc->anim_y -= 0.001 * speed;
1343 if (lc->anim_z == 0)
1345 int i = (random() % 7); /* A, B or both */
1346 if (i == 0) lc->anim_z = 3;
1347 else if (i < 5) lc->anim_z = 2;
1348 else lc->anim_z = 1;
1350 /* We can do quarter turns, because it's radially symmetrical. */
1351 lc->anim_r = 90.0 * (1 + frand(6)) * RANDSIGN();
1353 if (lc->anim_y > 0.4)
1356 lc->type = LAMENT_PILLAR_SPIN;
1357 lc->anim_pause = pause;
1359 else if (lc->anim_y < -0.03)
1362 lc->type = LAMENT_PILLAR_SPIN;
1363 lc->anim_pause = pause;
1367 case LAMENT_PILLAR_SPIN:
1369 Bool negp = (lc->anim_r < 0);
1370 lc->anim_r += (negp ? 1 : -1) * speed;
1371 if (negp ? lc->anim_r > 0 : lc->anim_r < 0)
1374 lc->type = LAMENT_PILLAR_IN;
1379 case LAMENT_PILLAR_IN:
1381 Bool negp = (lc->anim_y < 0);
1382 lc->anim_y += (negp ? 1 : -1) * 0.005 * speed;
1383 if (negp ? lc->anim_y > 0 : lc->anim_y < 0)
1387 lc->type = LAMENT_BOX;
1388 lc->anim_pause = pause;
1393 /* -------------------------------------------------------------- */
1395 case LAMENT_SPHERE_OUT:
1397 lc->anim_y += 0.01 * speed;
1398 if (lc->anim_y >= 1)
1401 lc->type = LAMENT_SPHERE_IN;
1402 lc->anim_pause = pause2 * (1 + frand(1) + frand(1));
1407 case LAMENT_SPHERE_IN:
1409 lc->anim_y -= 0.01 * speed;
1410 if (lc->anim_y <= 0)
1413 lc->type = LAMENT_BOX;
1414 lc->anim_pause = pause;
1419 /* -------------------------------------------------------------- */
1421 case LAMENT_LEVIATHAN_SPIN:
1422 lc->anim_r += 3.5 * speed;
1423 if (lc->anim_r >= 360 * 3)
1426 lc->type = LAMENT_LEVIATHAN_FADE;
1431 case LAMENT_LEVIATHAN_FADE:
1432 lc->anim_z += 0.01 * speed;
1433 if (lc->anim_z >= 1)
1436 lc->type = LAMENT_LEVIATHAN_TWIST;
1441 case LAMENT_LEVIATHAN_TWIST:
1442 lc->anim_y += 2 * speed;
1444 if (lc->anim_y >= 180)
1447 lc->type = LAMENT_LEVIATHAN_COLLAPSE;
1452 case LAMENT_LEVIATHAN_COLLAPSE:
1453 lc->anim_y += 0.01 * speed;
1454 if (lc->anim_y >= 1)
1457 lc->type = LAMENT_LEVIATHAN_EXPAND;
1458 lc->anim_pause = pause2 * 4;
1462 case LAMENT_LEVIATHAN_EXPAND:
1463 lc->anim_y -= 0.005 * speed;
1464 if (lc->anim_y <= 0)
1467 lc->type = LAMENT_LEVIATHAN_UNTWIST;
1471 case LAMENT_LEVIATHAN_UNTWIST:
1472 lc->anim_y -= 2 * speed;
1474 if (lc->anim_y <= 0)
1477 lc->type = LAMENT_LEVIATHAN_UNFADE;
1482 case LAMENT_LEVIATHAN_UNFADE:
1483 lc->anim_z -= 0.1 * speed;
1484 if (lc->anim_z <= 0)
1487 lc->type = LAMENT_LEVIATHAN_UNSPIN;
1492 case LAMENT_LEVIATHAN_UNSPIN:
1493 lc->anim_r += 3.5 * speed;
1494 if (lc->anim_r >= 360 * 2)
1497 lc->type = LAMENT_BOX;
1498 lc->anim_pause = pause2;
1511 if (lc->type == LAMENT_BOX)
1512 lc->type = DEBUG_MODE;
1517 while (lc->type != DEBUG_MODE)
1521 # else /* !DEBUG_MODE */
1523 if (lc->ffwdp && lc->type == LAMENT_BOX)
1526 while (lc->type == LAMENT_BOX)
1531 # endif /* !DEBUG_MODE */
1536 gl_init (ModeInfo *mi)
1538 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1539 Bool wire = MI_IS_WIREFRAME(mi);
1547 static const GLfloat pos0[] = { -4.0, 2.0, 5.0, 1.0 };
1548 static const GLfloat pos1[] = { 6.0, -1.0, 3.0, 1.0 };
1550 static const GLfloat amb0[] = { 0.7, 0.7, 0.7, 1.0 };
1551 /* static const GLfloat amb1[] = { 0.7, 0.0, 0.0, 1.0 }; */
1552 static const GLfloat dif0[] = { 1.0, 1.0, 1.0, 1.0 };
1553 static const GLfloat dif1[] = { 0.3, 0.1, 0.1, 1.0 };
1555 glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1556 glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1558 glLightfv(GL_LIGHT0, GL_AMBIENT, amb0);
1559 /* glLightfv(GL_LIGHT1, GL_AMBIENT, amb1); */
1560 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif0);
1561 glLightfv(GL_LIGHT1, GL_DIFFUSE, dif1);
1563 glEnable(GL_LIGHTING);
1564 glEnable(GL_LIGHT0);
1565 /* glEnable(GL_LIGHT1); */
1567 glEnable(GL_DEPTH_TEST);
1568 glEnable(GL_TEXTURE_2D);
1569 glEnable(GL_NORMALIZE);
1570 glEnable(GL_CULL_FACE);
1576 for (i = 0; i < countof(lc->texids); i++)
1577 glGenTextures(1, &lc->texids[i]);
1579 lc->texture = xpm_to_ximage (mi->dpy,
1584 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1585 /* messes up -fps */
1586 /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
1588 for (i = 0; i < countof(lc->texids); i++)
1590 int height = lc->texture->width; /* assume square */
1591 glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1594 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1595 lc->texture->width, height, 0,
1597 /* GL_UNSIGNED_BYTE, */
1598 GL_UNSIGNED_INT_8_8_8_8_REV,
1599 (lc->texture->data +
1600 (lc->texture->bytes_per_line * height * i)));
1601 check_gl_error("texture");
1603 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1604 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1605 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1606 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1607 check_gl_error("texture");
1609 /* This makes scaled pixmaps tolerable to look at. */
1610 # if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT)
1611 # define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT
1613 # ifdef GL_TEXTURE_LOD_BIAS
1614 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25);
1616 clear_gl_error(); /* invalid enum on iPad 3 */
1620 for (i = 0; i < countof(all_objs); i++)
1622 GLfloat s = 1/3.0; /* box is 3" square */
1623 const struct gllist *L = *all_objs[i];
1624 const GLfloat *f = (const GLfloat *) L->data;
1627 lc->dlists[i] = glGenLists(1);
1628 lc->polys[i] = L->points / 3;
1629 glNewList(lc->dlists[i], GL_COMPILE);
1630 if (L->primitive != GL_TRIANGLES) abort();
1631 if (L->format != GL_N3F_V3F) abort();
1634 glTranslatef (-0.5, -0.5, -0.5);
1637 for (j = 0; j < L->points; j += 3)
1640 Bool blackp = (i == OBJ_ISO_BASE_A || i == OBJ_ISO_BASE_B);
1641 which_face (mi, f, &face, &outerp); /* from norm of first vert */
1643 set_colors (outerp ? exterior_color :
1644 blackp ? black_color : interior_color);
1645 glBindTexture (GL_TEXTURE_2D,
1646 (outerp ? lc->texids[face-1] :
1647 blackp ? 0 : lc->texids[6]));
1649 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
1650 if (face) texturize_vert (mi, face, f+3);
1651 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1652 if (face) texturize_vert (mi, face, f+3);
1653 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1654 if (face) texturize_vert (mi, face, f+3);
1655 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1666 lament_handle_event (ModeInfo *mi, XEvent *event)
1668 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1670 if (gltrackball_event_handler (event, lc->trackball,
1671 MI_WIDTH (mi), MI_HEIGHT (mi),
1672 &lc->button_down_p))
1674 else if (event->xany.type == KeyPress)
1678 XLookupString (&event->xkey, &c, 1, &keysym, 0);
1679 if (c == ' ' || c == '\t')
1691 reshape_lament (ModeInfo *mi, int width, int height)
1693 GLfloat h = (GLfloat) height / (GLfloat) width;
1694 glViewport(0, 0, (GLint) width, (GLint) height);
1696 glMatrixMode(GL_PROJECTION);
1698 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1699 glMatrixMode(GL_MODELVIEW);
1701 glTranslatef(0.0, 0.0, -40.0);
1702 glClear(GL_COLOR_BUFFER_BIT);
1707 init_lament (ModeInfo *mi)
1709 lament_configuration *lc;
1713 lc = &lcs[MI_SCREEN(mi)];
1716 double rot_speed = 0.5;
1717 lc->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
1718 lc->trackball = gltrackball_init (True);
1721 lc->type = LAMENT_BOX;
1722 lc->anim_pause = 300 + (random() % 100);
1724 if ((lc->glx_context = init_GL(mi)) != NULL)
1726 reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1730 lc->states = (lament_type *) calloc (200, sizeof (*lc->states));
1733 # define PUSH(N,WHICH) \
1734 for (i = 0; i < N; i++) lc->states[lc->nstates++] = WHICH
1736 PUSH (4, LAMENT_TETRA_UNE); /* most common */
1737 PUSH (4, LAMENT_TETRA_USW);
1738 PUSH (4, LAMENT_TETRA_DWN);
1739 PUSH (4, LAMENT_TETRA_DSE);
1741 PUSH (8, LAMENT_STAR_OUT); /* pretty common */
1742 PUSH (8, LAMENT_TASER_OUT);
1743 PUSH (8, LAMENT_PILLAR_OUT);
1745 PUSH (4, LAMENT_LID_OPEN); /* rare */
1746 PUSH (2, LAMENT_SPHERE_OUT); /* rare */
1747 PUSH (1, LAMENT_LEVIATHAN_SPIN); /* very rare */
1749 PUSH (35, LAMENT_BOX); /* rest state */
1752 shuffle_states (lc);
1755 lc->type = DEBUG_MODE;
1763 draw_lament (ModeInfo *mi)
1765 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1766 Display *dpy = MI_DISPLAY(mi);
1767 Window window = MI_WINDOW(mi);
1769 if (!lc->glx_context)
1772 glDrawBuffer(GL_BACK);
1774 glXMakeCurrent(dpy, window, *(lc->glx_context));
1776 if (mi->fps_p) do_fps (mi);
1779 glXSwapBuffers(dpy, window);
1781 if (!lc->ffwdp && lc->anim_pause)
1787 XSCREENSAVER_MODULE ("Lament", lament)