1 /* xscreensaver, Copyright (c) 1998-2018 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 "ximage-loader.h"
168 #include "gltrackball.h"
171 #include "images/gen/lament512_png.h"
173 #define RANDSIGN() ((random() & 1) ? 1 : -1)
196 LAMENT_TASER_SLIDE_IN,
206 LAMENT_LEVIATHAN_SPIN,
207 LAMENT_LEVIATHAN_FADE,
208 LAMENT_LEVIATHAN_TWIST,
209 LAMENT_LEVIATHAN_COLLAPSE,
210 LAMENT_LEVIATHAN_EXPAND,
211 LAMENT_LEVIATHAN_UNTWIST,
212 LAMENT_LEVIATHAN_UNFADE,
213 LAMENT_LEVIATHAN_UNSPIN,
217 static const GLfloat exterior_color[] =
218 { 0.33, 0.22, 0.03, 1.00, /* ambient */
219 0.78, 0.57, 0.11, 1.00, /* specular */
220 0.99, 0.91, 0.81, 1.00, /* diffuse */
221 27.80 /* shininess */
223 static const GLfloat interior_color[] =
224 { 0.20, 0.20, 0.15, 1.00, /* ambient */
225 0.40, 0.40, 0.32, 1.00, /* specular */
226 0.99, 0.99, 0.81, 1.00, /* diffuse */
227 50.80 /* shininess */
229 static const GLfloat leviathan_color[] =
230 { 0.30, 0.30, 0.30, 1.00, /* ambient */
231 0.85, 0.85, 0.95, 1.00, /* specular */
232 0.99, 0.99, 0.99, 1.00, /* diffuse */
233 50.80 /* shininess */
235 static const GLfloat black_color[] =
236 { 0.05, 0.05, 0.05, 1.00, /* ambient */
237 0.05, 0.05, 0.05, 1.00, /* specular */
238 0.05, 0.05, 0.05, 1.00, /* diffuse */
239 80.00 /* shininess */
244 GLXContext *glx_context;
246 double rotx, roty, rotz;
247 trackball_state *trackball;
251 GLuint dlists[countof(all_objs)];
252 GLuint polys[countof(all_objs)];
254 XImage *texture; /* image bits */
255 GLuint texids[8]; /* texture map IDs */
256 lament_type type; /* which mode of the object is current */
258 int anim_pause; /* countdown before animating again */
259 GLfloat anim_r, anim_y, anim_z; /* relative position during anims */
265 } lament_configuration;
267 static lament_configuration *lcs = NULL;
271 facing_screen_p (ModeInfo *mi)
274 GLdouble m[16], p[16], x, y, z;
276 glGetDoublev (GL_MODELVIEW_MATRIX, m);
277 glGetDoublev (GL_PROJECTION_MATRIX, p);
278 glGetIntegerv (GL_VIEWPORT, v);
280 /* See if a coordinate 5 units in front of the door is near the
281 center of the screen. */
282 gluProject (0, -5, 0, m, p, v, &x, &y, &z);
283 x = (x / MI_WIDTH(mi)) - 0.5;
284 y = (y / MI_HEIGHT(mi)) - 0.5;
286 facing_p = (z < 0.9 &&
287 x > -0.15 && x < 0.15 &&
288 y > -0.15 && y < 0.15);
291 glBindTexture(GL_TEXTURE_2D, 0);
292 glDisable (GL_LIGHTING);
293 glColor3f (1, (facing_p ? 1 : 0), 0);
295 glVertex3f (0, 0, 0);
296 glVertex3f (0, -5, 0);
298 if (!MI_IS_WIREFRAME(mi)) glEnable (GL_LIGHTING);
299 # endif /* DEBUG_MODE */
306 scale_for_window (ModeInfo *mi)
308 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
310 GLfloat target_size = 1.4 * (lc->texture ? lc->texture->width : 512);
311 GLfloat size = MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi);
314 /* Make it take up roughly the full width of the window. */
317 /* But if the window is wider than tall, make it only take up the
318 height of the window instead.
320 if (MI_WIDTH(mi) > MI_HEIGHT(mi))
321 scale /= MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi);
323 /* If the window is super wide, make it bigger. */
324 if (scale < 8) scale = 8;
326 /* Constrain it to roughly life-sized on the screen, not huge.
329 if (size > 768) /* iPad retina / iPhone 6 */
334 GLfloat max = 500; /* 3" on my screen... */
336 if (MI_WIDTH(mi) > 2560) { /* Retina displays */
341 if (target_size > max)
345 /* But if that would make the image larger than target_size, scale it
346 back down again. The image-map bits we have are 512x512, so if the
347 image is magnified a lot, it looks pretty blocky. It's better to
348 have a 512x512 animation on a 1920x1080 screen that looks good
349 than a 1024x1024 animation that looks really pixelated.
351 if (size > target_size)
352 scale *= target_size / size;
354 glScalef (scale, scale, scale);
359 set_colors (const GLfloat *color)
361 glMaterialfv(GL_FRONT, GL_AMBIENT, color + 0);
362 glMaterialfv(GL_FRONT, GL_DIFFUSE, color + 4);
363 glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
364 glMaterialfv(GL_FRONT, GL_SHININESS, color + 12);
368 set_colors_alpha (const GLfloat *color, GLfloat a)
370 GLfloat c[countof(leviathan_color)];
371 memcpy (c, color, sizeof(c));
372 c[3] = c[7] = c[11] = a;
378 which_face (ModeInfo *mi, const GLfloat *f, int *face, int *outerp)
380 GLfloat size = 3; /* 3" square */
381 const GLfloat *n = f; /* normal */
382 const GLfloat *v = f + 3; /* vertex */
383 GLfloat slack = 0.01;
385 /* First look at the normal to determine which direction this triangle
386 is facing (or is most-closely facing).
387 It's an outer surface if it is within epsilon of the cube wall that
388 it is facing. Otherwise, it's an inner surface.
390 if (n[1] < -0.5) *face = 1, *outerp = v[1] < slack; /* S */
391 else if (n[2] > 0.5) *face = 2, *outerp = v[2] > size-slack; /* U */
392 else if (n[1] > 0.5) *face = 3, *outerp = v[1] > size-slack; /* N */
393 else if (n[2] < -0.5) *face = 4, *outerp = v[2] < slack; /* D */
394 else if (n[0] < -0.5) *face = 5, *outerp = v[0] < slack; /* W */
395 else /* (n[0] > 0.5)*/ *face = 6, *outerp = v[0] > size-slack; /* E */
397 /* Faces that don't have normals parallel to the axes aren't external. */
399 (n[0] > -0.95 && n[0] < 0.95 &&
400 n[1] > -0.95 && n[1] < 0.95 &&
401 n[2] > -0.95 && n[2] < 0.95))
407 texturize_vert (ModeInfo *mi, int which, const GLfloat *v)
409 GLfloat size = 3; /* 3" square */
410 GLfloat s = 0, q = 0;
412 /* Texture coordinates are surface coordinates,
413 on the plane of this cube wall. */
416 case 1: s = v[0], q = v[2]; break;
417 case 2: s = v[0], q = v[1]; break;
418 case 3: s = v[0], q = v[2]; q = size - q; break;
419 case 4: s = v[0], q = v[1]; q = size - q; break;
420 case 5: s = v[1], q = v[2]; break;
421 case 6: s = v[1], q = v[2]; break;
422 default: abort(); break;
425 glTexCoord2f (s / size, q / size);
430 leviathan (ModeInfo *mi, GLfloat ratio, GLfloat alpha, Bool top_p)
432 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
433 Bool wire = MI_IS_WIREFRAME(mi);
435 GLfloat z = 2 * ratio;
439 GLfloat th = acos (2 / sqrt (6)); /* Line up with cube's diagonal */
443 glRotatef (-45, 0, 1, 0);
444 glRotatef (-th * 180 / M_PI, 0, 0, 1);
447 glRotatef (180, 0, 0, 1);
449 for (i = 0; i < countof(p); i++)
451 GLfloat th = i * M_PI * 2 / countof(p);
452 p[i].x = cos(th) * r;
453 p[i].y = sin(th) * r;
456 glFrontFace (GL_CCW);
457 for (i = 0; i < countof(p); i++)
459 int j = (i + 1) % countof(p);
471 if (do_texture) /* Leviathan is the final texture */
472 glBindTexture (GL_TEXTURE_2D, lc->texids[countof(lc->texids) - 1]);
474 set_colors (leviathan_color);
476 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
477 glTexCoord2f (0.5, 1);
478 glVertex3f (z, 0, 0);
481 glVertex3f (0, p[i].x, p[i].y);
484 glVertex3f (0, p[j].x, p[j].y);
488 /* Shield for fading */
489 if (alpha < 0.9 && !wire)
494 set_colors_alpha (black_color, 1-alpha);
495 glBindTexture (GL_TEXTURE_2D, 0);
499 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
502 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
504 glVertex3f (z*a, p[j].x * b, p[j].y * b);
505 glVertex3f (z*a, p[i].x * b, p[i].y * b);
506 glVertex3f (0, p[i].x * 1.01, p[i].y * 1.01);
507 glVertex3f (0, p[j].x * 1.01, p[j].y * 1.01);
510 glDisable (GL_BLEND);
519 folding_walls (ModeInfo *mi, GLfloat ratio, Bool top_p)
521 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
522 Bool wire = MI_IS_WIREFRAME(mi);
523 const GLfloat pa[4][2] = {{ -0.5, -0.215833 },
526 { -0.215833, -0.5 }};
527 const int tex[6] = { 0, 5, 1, 4, 2, 3 };
528 const GLfloat top = -pa[0][1];
529 GLfloat end_angle = 30.85;
530 GLfloat rr = sin (ratio / 2 * M_PI);
531 GLfloat offa = 0.15 * rr;
532 GLfloat offb = 0.06 * rr;
541 glRotatef (60, 1, -1, 1);
542 glRotatef (180, 0, 1, 0);
543 glRotatef (90, 1, 0, 0);
547 glRotatef (180, 1, 0, 0);
550 /* Scale down the points near the axis */
556 p[1][0] = pa[1][0] - offb;
558 p[1][2] = pa[1][1] - offa;
560 p[2][0] = pa[2][0] - offa;
562 p[2][2] = pa[2][1] - offb;
571 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
574 for (i = 0; i < 3; i++)
580 glRotatef (-90, 1, 0, 0);
581 glRotatef (180, 1, 1, 0);
585 glRotatef (-90, 1, 0, 0);
586 glRotatef (180, 0, 1, 0);
587 glRotatef (90, 0, 1, 0);
590 glRotatef (-90, 0, 1, 0);
592 glTranslatef (-(top/2 + 0.25), 0.5, -(top/2 + 0.25));
593 glRotatef (-45, 0, 1, 0);
594 glRotatef (ratio * -end_angle, 0, 0, 1);
595 glRotatef (45, 0, 1, 0);
596 glTranslatef (top/2 + 0.25, -0.5, top/2 + 0.25);
598 /* Get the texture coordinates right.
599 This is hairy and incomprehensible. */
601 t[0][0] = pa[0][1] + 0.5; t[0][1] = pa[0][0] + 0.5;
602 t[1][0] = pa[1][1] + 0.5; t[1][1] = pa[1][0] + 0.5;
603 t[2][0] = pa[2][1] + 0.5; t[2][1] = pa[2][0] + 0.5;
604 t[3][0] = pa[3][1] + 0.5; t[3][1] = pa[3][0] + 0.5;
606 if (i == 0 && !top_p)
608 # define SWAP(A,B) A = 1-A, B = 1-B
609 SWAP(t[0][0], t[0][1]);
610 SWAP(t[1][0], t[1][1]);
611 SWAP(t[2][0], t[2][1]);
612 SWAP(t[3][0], t[3][1]);
615 else if (i == 0 && top_p)
618 memcpy (ot, t, sizeof(t));
619 # define SWAP(A,B) A = 1-A, B = 1-B
620 SWAP(t[0][0], ot[2][1]);
621 SWAP(t[1][0], ot[3][1]);
622 SWAP(t[2][0], ot[0][1]);
623 SWAP(t[3][0], ot[1][1]);
629 # define SWAP(A,B) f = A, A = B, B = -f
630 SWAP(t[0][0], t[0][1]);
631 SWAP(t[1][0], t[1][1]);
632 SWAP(t[2][0], t[2][1]);
633 SWAP(t[3][0], t[3][1]);
637 set_colors_alpha (exterior_color, 1-ratio);
638 glBindTexture (GL_TEXTURE_2D, lc->texids[tex[i + (top_p ? 3 : 0)]]);
640 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
641 do_normal (p[0][0], p[0][1], p[0][2],
642 p[1][0], p[1][1], p[1][2],
643 p[2][0], p[2][1], p[2][2]);
644 glTexCoord2fv(t[0]); glVertex3fv(p[0]);
645 glTexCoord2fv(t[1]); glVertex3fv(p[1]);
646 glTexCoord2fv(t[2]); glVertex3fv(p[2]);
647 glTexCoord2fv(t[3]); glVertex3fv(p[3]);
651 /* The triangles between the quads */
653 /* #### There is a fucking gap between the two black triangles
654 that I can't figure out! So instead of drawing the triangles,
655 we build a black shield around the middle bit in leviathan()
656 and count on back-face culling to have roughly the same effect.
661 memcpy (pp, p, sizeof(pp));
662 memcpy (pp[2], pp[1], sizeof(pp[1]));
663 pp[2][0] -= 0.5 * (1-ratio);
664 pp[2][1] -= 0.5 * (1-ratio);
666 glBindTexture (GL_TEXTURE_2D, 0);
667 set_colors_alpha (black_color, 1-ratio);
669 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
670 do_normal (pp[0][0], pp[0][1], pp[0][2],
671 pp[2][0], pp[2][1], pp[2][2],
672 pp[1][0], pp[1][1], pp[1][2]);
684 if (! wire) glDisable (GL_BLEND);
691 lament_sphere (ModeInfo *mi, GLfloat ratio)
693 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
694 Bool wire = MI_IS_WIREFRAME(mi);
695 GLfloat size = 3; /* 3" square */
697 int facets = 16; /* NxN grid on each face */
699 static const GLfloat norms[6][3] = {{ 0, -1, 0 }, { 0, 0, 1 }, { 0, 1, 0 },
700 { 0, 0, -1 }, { -1, 0, 0 }, { 1, 0, 0 }};
701 GLfloat s = 1.0 / facets;
703 /* The ratio used for the normals: linger on the square normals. */
704 GLfloat ratio2 = 1 - sin ((1 - ratio) / 2 * M_PI);
705 GLfloat r1 = 1 - ratio2 / 2;
706 GLfloat r2 = ratio2 / 2;
709 glTranslatef (-0.5, -0.5, -0.5);
710 glScalef (1/size, 1/size, 1/size);
712 set_colors (exterior_color);
714 for (face = 0; face < 6; face++)
717 for (y0 = 0; y0 < 1; y0 += s)
718 for (x0 = 0; x0 < 1; x0 += s)
723 GLfloat pa[4][3]; /* verts of the cube */
724 GLfloat pb[4][3]; /* verts of the transition to the sphere */
726 GLfloat norm[4][3]; /* normals of the transitional verts */
729 frontp = norms[face][0] < 0,
730 pa[0][1] = x0, pa[0][2] = y0, pa[0][0] = (frontp ? 0 : 1),
731 pa[1][1] = x1, pa[1][2] = y0, pa[1][0] = pa[0][0],
732 pa[2][1] = x1, pa[2][2] = y1, pa[2][0] = pa[0][0],
733 pa[3][1] = x0, pa[3][2] = y1, pa[3][0] = pa[0][0];
734 else if (norms[face][1])
735 frontp = norms[face][1] > 0,
736 pa[0][0] = x0, pa[0][2] = y0, pa[0][1] = (frontp ? 1 : 0),
737 pa[1][0] = x1, pa[1][2] = y0, pa[1][1] = pa[0][1],
738 pa[2][0] = x1, pa[2][2] = y1, pa[2][1] = pa[0][1],
739 pa[3][0] = x0, pa[3][2] = y1, pa[3][1] = pa[0][1];
740 else /* (norms[face][2]) */
741 frontp = norms[face][2] < 0,
742 pa[0][0] = x0, pa[0][1] = y0, pa[0][2] = (frontp ? 0 : 1),
743 pa[1][0] = x1, pa[1][1] = y0, pa[1][2] = pa[0][2],
744 pa[2][0] = x1, pa[2][1] = y1, pa[2][2] = pa[0][2],
745 pa[3][0] = x0, pa[3][1] = y1, pa[3][2] = pa[0][2];
747 for (i = 0; i < countof(pa); i++)
748 pa[i][0] *= size, pa[i][1] *= size, pa[i][2] *= size;
750 /* Convert square to sphere by treating as a normalized vector */
751 for (i = 0; i < countof(pa); i++)
753 GLfloat x = (pa[i][0] / size) - 0.5;
754 GLfloat y = (pa[i][1] / size) - 0.5;
755 GLfloat z = (pa[i][2] / size) - 0.5;
756 GLfloat d = sqrt (x*x + y*y + z*z) / 2;
761 pb[i][0] = pa[i][0] + ((x - pa[i][0]) * ratio);
762 pb[i][1] = pa[i][1] + ((y - pa[i][1]) * ratio);
763 pb[i][2] = pa[i][2] + ((z - pa[i][2]) * ratio);
766 /* The normals of an intermediate point are the weighted average
767 of the cube's orthogonal normals, and the sphere's radial
768 normals: early in the sequence, the edges are sharp, but they
769 soften as it expands. */
771 XYZ na, pa0, pa1, pa2;
772 pa0.x = pa[0][0]; pa0.y = pa[0][1]; pa0.z = pa[0][2];
773 pa1.x = pa[1][0]; pa1.y = pa[1][1]; pa1.z = pa[1][2];
774 pa2.x = pa[2][0]; pa2.y = pa[2][1]; pa2.z = pa[2][2];
775 na = calc_normal (pa0, pa1, pa2);
777 for (i = 0; i < countof(pb); i++)
785 d = sqrt (nb.x*nb.x + nb.y*nb.y + nb.z*nb.z); /* normalize */
790 norm[i][0] = (na.x * r1) + (nb.x * r2); /* weighted */
791 norm[i][1] = (na.y * r1) + (nb.y * r2);
792 norm[i][2] = (na.z * r1) + (nb.z * r2);
797 glBindTexture (GL_TEXTURE_2D, lc->texids[face]);
799 glFrontFace (frontp ? GL_CW : GL_CCW);
800 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
802 texturize_vert (mi, face+1, pa[0]);
803 glNormal3fv (norm[0]);
806 texturize_vert (mi, face+1, pa[1]);
807 glNormal3fv (norm[1]);
810 texturize_vert (mi, face+1, pa[2]);
811 glNormal3fv (norm[2]);
814 texturize_vert (mi, face+1, pa[3]);
815 glNormal3fv (norm[3]);
832 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
833 Bool wire = MI_IS_WIREFRAME(mi);
835 mi->polygon_count = 0;
838 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
840 glClear(GL_COLOR_BUFFER_BIT);
844 gltrackball_rotate (lc->trackball);
846 /* Make into the screen be +Y, right be +X, and up be +Z. */
847 glRotatef (-90.0, 1.0, 0.0, 0.0);
849 scale_for_window (mi);
851 /* Apply rotation to the object. */
852 if (lc->type != LAMENT_LID_ZOOM)
853 get_rotation (lc->rot, &lc->rotx, &lc->roty, &lc->rotz,
858 lc->rotx = lc->roty = 0;
862 glRotatef (lc->rotx * 360, 1, 0, 0);
863 glRotatef (lc->roty * 360, 0, 1, 0);
864 glRotatef (lc->rotz * 360, 0, 0, 1);
866 glScalef (0.5, 0.5, 0.5);
871 glCallList (lc->dlists[OBJ_BOX]);
872 mi->polygon_count += lc->polys[OBJ_BOX];
875 case LAMENT_STAR_OUT:
876 case LAMENT_STAR_ROT:
877 case LAMENT_STAR_ROT_IN:
878 case LAMENT_STAR_ROT_OUT:
879 case LAMENT_STAR_UNROT:
881 glTranslatef (0.0, 0.0, lc->anim_z/2);
882 glRotatef (lc->anim_r/2, 0.0, 0.0, 1.0);
883 glCallList (lc->dlists[OBJ_STAR_U]);
884 mi->polygon_count += lc->polys[OBJ_STAR_U];
886 glTranslatef (0.0, 0.0, -lc->anim_z);
887 glRotatef (-lc->anim_r, 0.0, 0.0, 1.0);
888 glCallList (lc->dlists[OBJ_STAR_D]);
889 mi->polygon_count += lc->polys[OBJ_STAR_D];
892 case LAMENT_TETRA_UNE:
893 case LAMENT_TETRA_USW:
894 case LAMENT_TETRA_DWN:
895 case LAMENT_TETRA_DSE:
900 case LAMENT_TETRA_UNE: magic = OBJ_TETRA_UNE; x= 1; y= 1; z= 1; break;
901 case LAMENT_TETRA_USW: magic = OBJ_TETRA_USW; x= 1; y= 1; z=-1; break;
902 case LAMENT_TETRA_DWN: magic = OBJ_TETRA_DWN; x= 1; y=-1; z= 1; break;
903 case LAMENT_TETRA_DSE: magic = OBJ_TETRA_DSE; x=-1; y= 1; z= 1; break;
904 default: abort(); break;
906 glCallList(lc->dlists[OBJ_TETRA_BASE]);
907 mi->polygon_count += lc->polys[OBJ_TETRA_BASE];
908 if (magic != OBJ_TETRA_UNE) glCallList (lc->dlists[OBJ_TETRA_UNE]);
909 if (magic != OBJ_TETRA_USW) glCallList (lc->dlists[OBJ_TETRA_USW]);
910 if (magic != OBJ_TETRA_DWN) glCallList (lc->dlists[OBJ_TETRA_DWN]);
911 if (magic != OBJ_TETRA_DSE) glCallList (lc->dlists[OBJ_TETRA_DSE]);
912 glRotatef (lc->anim_r, x, y, z);
913 glCallList (lc->dlists[magic]);
914 mi->polygon_count += lc->polys[magic] * 3;
918 case LAMENT_LID_OPEN:
919 case LAMENT_LID_CLOSE:
920 case LAMENT_LID_ZOOM:
924 const int lists[4] = { OBJ_LID_A, OBJ_LID_B, OBJ_LID_C, OBJ_LID_D };
926 lc->facing_p = facing_screen_p (mi);
928 if (lc->anim_z < 0.5)
929 glTranslatef (0, -30 * lc->anim_z, 0); /* zoom */
931 glTranslatef (8 * (0.5 - (lc->anim_z - 0.5)), 0, 0);
933 glCallList (lc->dlists[OBJ_LID_BASE]);
934 mi->polygon_count += lc->polys[OBJ_LID_BASE];
935 for (i = 0; i < countof(lists); i++)
938 glRotatef (90 * i, 0, 1, 0);
939 glTranslatef (-d, -0.5, d);
940 glRotatef (-45, 0, 1, 0);
941 glRotatef (-lc->anim_r, 1, 0, 0);
942 glRotatef (45, 0, 1, 0);
943 glTranslatef (d, 0.5, -d);
944 glRotatef (-90 * i, 0, 1, 0);
945 glCallList (lc->dlists[lists[i]]);
946 mi->polygon_count += lc->polys[lists[i]];
954 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
955 glVertex3f (-0.49, 0.49, -0.49);
956 glVertex3f ( 0.49, 0.49, -0.49);
957 glVertex3f ( 0.49, 0.49, 0.49);
958 glVertex3f (-0.49, 0.49, 0.49);
962 # endif /* DEBUG_MODE */
966 case LAMENT_TASER_OUT:
967 case LAMENT_TASER_SLIDE:
968 case LAMENT_TASER_SLIDE_IN:
969 case LAMENT_TASER_IN:
971 glTranslatef (0, -lc->anim_z/2, 0);
972 glCallList (lc->dlists[OBJ_TASER_BASE]);
973 mi->polygon_count += lc->polys[OBJ_TASER_BASE];
975 glTranslatef (0, lc->anim_z, 0);
976 glCallList (lc->dlists[OBJ_TASER_A]);
977 mi->polygon_count += lc->polys[OBJ_TASER_A];
979 glTranslatef (lc->anim_y, 0, 0);
980 glCallList (lc->dlists[OBJ_TASER_B]);
981 mi->polygon_count += lc->polys[OBJ_TASER_B];
984 case LAMENT_PILLAR_OUT:
985 case LAMENT_PILLAR_SPIN:
986 case LAMENT_PILLAR_IN:
988 glCallList (lc->dlists[OBJ_PILLAR_BASE]);
989 mi->polygon_count += lc->polys[OBJ_PILLAR_BASE];
992 if (lc->anim_z == 1 || lc->anim_z == 3)
994 glRotatef (lc->anim_r, 0, 0, 1);
995 glTranslatef (0, 0, lc->anim_y);
997 glCallList (lc->dlists[OBJ_PILLAR_A]);
998 mi->polygon_count += lc->polys[OBJ_PILLAR_A];
1002 if (lc->anim_z == 2 || lc->anim_z == 3)
1004 glRotatef (lc->anim_r, 0, 0, 1);
1005 glTranslatef (0, 0, -lc->anim_y);
1007 glCallList (lc->dlists[OBJ_PILLAR_B]);
1008 mi->polygon_count += lc->polys[OBJ_PILLAR_B];
1012 case LAMENT_SPHERE_OUT:
1013 case LAMENT_SPHERE_IN:
1014 mi->polygon_count += lament_sphere (mi, lc->anim_y);
1017 case LAMENT_LEVIATHAN_SPIN:
1018 case LAMENT_LEVIATHAN_UNSPIN:
1019 case LAMENT_LEVIATHAN_FADE:
1020 case LAMENT_LEVIATHAN_UNFADE:
1021 case LAMENT_LEVIATHAN_TWIST:
1022 case LAMENT_LEVIATHAN_UNTWIST:
1024 /* These normals are hard to compute, so I pulled them from the
1026 const GLfloat axes[6][4] =
1027 {{ OBJ_ISO_UNE, 0.633994, 0.442836, 0.633994 },
1028 { OBJ_ISO_USW, 0.442836, 0.633994, -0.633994 },
1029 { OBJ_ISO_DSE, -0.633994, 0.633994, 0.442836 },
1030 { OBJ_ISO_SWD, -0.633994, -0.442836, -0.633994 },
1031 { OBJ_ISO_DEN, -0.442836, -0.633994, 0.633994 },
1032 { OBJ_ISO_UNW, 0.633994, -0.633994, -0.442836 }};
1035 GLfloat s = (1 - lc->anim_z);
1036 GLfloat s2 = MAX (0, 360 - lc->anim_r) / 360.0;
1040 case LAMENT_LEVIATHAN_SPIN: break;
1041 case LAMENT_LEVIATHAN_UNSPIN: s2 = 1 - s2; break;
1042 default: s2 = 0; blendp = 1; break;
1045 if (wire) blendp = 0;
1047 s = (s * 0.6) + 0.4;
1049 leviathan (mi, 1 - s2, 1, True);
1050 glCallList (lc->dlists[OBJ_ISO_BASE_A]);
1051 mi->polygon_count += lc->polys[OBJ_ISO_BASE_A];
1054 glScalef (s2, s2, s2);
1055 glCallList (lc->dlists[OBJ_ISO_USE]);
1056 mi->polygon_count += lc->polys[OBJ_ISO_USE];
1060 glRotatef (lc->anim_y, 1, -1, 1);
1061 glCallList (lc->dlists[OBJ_ISO_BASE_B]);
1062 mi->polygon_count += lc->polys[OBJ_ISO_BASE_B];
1063 leviathan (mi, 1 - s2, 1, False);
1068 # ifndef HAVE_JWZGLES /* no glBlendColor */
1069 glEnable (GL_BLEND);
1070 glBlendFunc (GL_CONSTANT_ALPHA, GL_SRC_ALPHA);
1071 glBlendColor (1, 1, 1, MAX(0, 1-(lc->anim_z * 3)));
1075 for (i = 0; i < countof(axes); i++)
1078 glRotatef (lc->anim_r, axes[i][1], axes[i][2], axes[i][3]);
1080 glCallList (lc->dlists[(int) axes[i][0]]);
1081 mi->polygon_count += lc->polys[(int) axes[i][0]];
1084 glRotatef (lc->anim_y, 1, -1, 1);
1087 if (blendp) glDisable (GL_BLEND);
1090 glScalef (s2, s2, s2);
1091 glCallList (lc->dlists[OBJ_ISO_DWN]);
1092 mi->polygon_count += lc->polys[OBJ_ISO_DWN];
1097 case LAMENT_LEVIATHAN_COLLAPSE:
1098 case LAMENT_LEVIATHAN_EXPAND:
1101 leviathan (mi, 1, lc->anim_y, True);
1102 glRotatef (180, 1, -1, 1);
1103 leviathan (mi, 1, lc->anim_y, False);
1105 folding_walls (mi, lc->anim_y, True);
1106 folding_walls (mi, lc->anim_y, False);
1119 /* Rather than just picking states randomly, pick an ordering randomly, do it,
1120 and then re-randomize. That way one can be assured of seeing all states in
1121 a short time period, though not always in the same order (it's frustrating
1122 to see it pick the same state 5x in a row.) Though, that can still happen,
1123 since states are in the list multiple times as a way of giving them
1127 shuffle_states (lament_configuration *lc)
1130 for (i = 0; i < lc->nstates; i++)
1132 int a = random() % lc->nstates;
1133 lament_type swap = lc->states[a];
1134 lc->states[a] = lc->states[i];
1135 lc->states[i] = swap;
1141 animate (ModeInfo *mi)
1143 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1146 GLfloat speed = (lc->ffwdp ? 20 : 1);
1153 if (lc->state >= lc->nstates)
1155 shuffle_states (lc);
1158 lc->type = lc->states[lc->state];
1160 if (lc->type == LAMENT_BOX)
1161 lc->anim_pause = pause2;
1169 /* -------------------------------------------------------------- */
1171 case LAMENT_STAR_OUT:
1172 lc->anim_z += 0.01 * speed;
1173 if (lc->anim_z >= 1.0)
1176 lc->type = LAMENT_STAR_ROT;
1177 lc->anim_pause = pause;
1181 case LAMENT_STAR_ROT:
1182 lc->anim_r += 1.0 * speed;
1183 if (lc->anim_r >= 45.0)
1186 lc->type = LAMENT_STAR_ROT_IN;
1187 lc->anim_pause = pause;
1191 case LAMENT_STAR_ROT_IN:
1192 lc->anim_z -= 0.01 * speed;
1193 if (lc->anim_z <= 0.0)
1196 lc->type = LAMENT_STAR_ROT_OUT;
1197 lc->anim_pause = pause2 * (1 + frand(2) + frand(2));
1201 case LAMENT_STAR_ROT_OUT:
1202 lc->anim_z += 0.01 * speed;
1203 if (lc->anim_z >= 1.0)
1206 lc->type = LAMENT_STAR_UNROT;
1207 lc->anim_pause = pause;
1211 case LAMENT_STAR_UNROT:
1212 lc->anim_r -= 1.0 * speed;
1213 if (lc->anim_r <= 0.0)
1216 lc->type = LAMENT_STAR_IN;
1217 lc->anim_pause = pause;
1221 case LAMENT_STAR_IN:
1222 lc->anim_z -= 0.01 * speed;
1223 if (lc->anim_z <= 0.0)
1226 lc->type = LAMENT_BOX;
1227 lc->anim_pause = pause2;
1231 /* -------------------------------------------------------------- */
1233 case LAMENT_TETRA_UNE:
1234 case LAMENT_TETRA_USW:
1235 case LAMENT_TETRA_DWN:
1236 case LAMENT_TETRA_DSE:
1238 lc->anim_r += 1.0 * speed;
1239 if (lc->anim_r >= 360.0)
1242 lc->type = LAMENT_BOX;
1243 lc->anim_pause = pause2;
1245 else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1248 lc->anim_pause = pause;
1250 else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1253 lc->anim_pause = pause;
1257 /* -------------------------------------------------------------- */
1259 case LAMENT_LID_OPEN:
1260 lc->anim_r += 1.0 * speed;
1262 if (lc->anim_r >= 112.0)
1266 lc->anim_pause = pause2;
1267 lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
1271 case LAMENT_LID_CLOSE:
1272 lc->anim_r -= 1.0 * speed;
1273 if (lc->anim_r <= 0.0)
1276 lc->type = LAMENT_BOX;
1277 lc->anim_pause = pause2;
1281 case LAMENT_LID_ZOOM:
1282 lc->anim_z += 0.01 * speed;
1283 if (lc->anim_z > 1.0)
1287 lc->type = LAMENT_BOX;
1291 /* -------------------------------------------------------------- */
1293 case LAMENT_TASER_OUT:
1294 lc->anim_z += 0.005 * speed;
1295 if (lc->anim_z >= 0.5)
1298 lc->type = LAMENT_TASER_SLIDE;
1299 lc->anim_pause = pause * (1 + frand(5) + frand(5));
1303 case LAMENT_TASER_SLIDE:
1304 lc->anim_y += 0.005 * speed;
1305 if (lc->anim_y >= 0.255)
1308 lc->type = LAMENT_TASER_SLIDE_IN;
1309 lc->anim_pause = pause2 * (1 + frand(5) + frand(5));
1313 case LAMENT_TASER_SLIDE_IN:
1314 lc->anim_y -= 0.0025 * speed;
1315 if (lc->anim_y <= 0.0)
1318 lc->type = LAMENT_TASER_IN;
1319 lc->anim_pause = pause;
1323 case LAMENT_TASER_IN:
1324 lc->anim_z -= 0.0025 * speed;
1325 if (lc->anim_z <= 0.0)
1328 lc->type = LAMENT_BOX;
1329 lc->anim_pause = pause2;
1333 /* -------------------------------------------------------------- */
1335 case LAMENT_PILLAR_OUT:
1337 if (lc->anim_y == 0) /* mostly in */
1338 lc->anim_y += 0.005 * ((random() % 5) ? -1 : 1) * speed;
1339 else if (lc->anim_y > 0)
1340 lc->anim_y += 0.005 * speed;
1342 lc->anim_y -= 0.001 * speed;
1344 if (lc->anim_z == 0)
1346 int i = (random() % 7); /* A, B or both */
1347 if (i == 0) lc->anim_z = 3;
1348 else if (i < 5) lc->anim_z = 2;
1349 else lc->anim_z = 1;
1351 /* We can do quarter turns, because it's radially symmetrical. */
1352 lc->anim_r = 90.0 * (1 + frand(6)) * RANDSIGN();
1354 if (lc->anim_y > 0.4)
1357 lc->type = LAMENT_PILLAR_SPIN;
1358 lc->anim_pause = pause;
1360 else if (lc->anim_y < -0.03)
1363 lc->type = LAMENT_PILLAR_SPIN;
1364 lc->anim_pause = pause;
1368 case LAMENT_PILLAR_SPIN:
1370 Bool negp = (lc->anim_r < 0);
1371 lc->anim_r += (negp ? 1 : -1) * speed;
1372 if (negp ? lc->anim_r > 0 : lc->anim_r < 0)
1375 lc->type = LAMENT_PILLAR_IN;
1380 case LAMENT_PILLAR_IN:
1382 Bool negp = (lc->anim_y < 0);
1383 lc->anim_y += (negp ? 1 : -1) * 0.005 * speed;
1384 if (negp ? lc->anim_y > 0 : lc->anim_y < 0)
1388 lc->type = LAMENT_BOX;
1389 lc->anim_pause = pause;
1394 /* -------------------------------------------------------------- */
1396 case LAMENT_SPHERE_OUT:
1398 lc->anim_y += 0.01 * speed;
1399 if (lc->anim_y >= 1)
1402 lc->type = LAMENT_SPHERE_IN;
1403 lc->anim_pause = pause2 * (1 + frand(1) + frand(1));
1408 case LAMENT_SPHERE_IN:
1410 lc->anim_y -= 0.01 * speed;
1411 if (lc->anim_y <= 0)
1414 lc->type = LAMENT_BOX;
1415 lc->anim_pause = pause;
1420 /* -------------------------------------------------------------- */
1422 case LAMENT_LEVIATHAN_SPIN:
1423 lc->anim_r += 3.5 * speed;
1424 if (lc->anim_r >= 360 * 3)
1427 lc->type = LAMENT_LEVIATHAN_FADE;
1432 case LAMENT_LEVIATHAN_FADE:
1433 lc->anim_z += 0.01 * speed;
1434 if (lc->anim_z >= 1)
1437 lc->type = LAMENT_LEVIATHAN_TWIST;
1442 case LAMENT_LEVIATHAN_TWIST:
1443 lc->anim_y += 2 * speed;
1445 if (lc->anim_y >= 180)
1448 lc->type = LAMENT_LEVIATHAN_COLLAPSE;
1453 case LAMENT_LEVIATHAN_COLLAPSE:
1454 lc->anim_y += 0.01 * speed;
1455 if (lc->anim_y >= 1)
1458 lc->type = LAMENT_LEVIATHAN_EXPAND;
1459 lc->anim_pause = pause2 * 4;
1463 case LAMENT_LEVIATHAN_EXPAND:
1464 lc->anim_y -= 0.005 * speed;
1465 if (lc->anim_y <= 0)
1468 lc->type = LAMENT_LEVIATHAN_UNTWIST;
1472 case LAMENT_LEVIATHAN_UNTWIST:
1473 lc->anim_y -= 2 * speed;
1475 if (lc->anim_y <= 0)
1478 lc->type = LAMENT_LEVIATHAN_UNFADE;
1483 case LAMENT_LEVIATHAN_UNFADE:
1484 lc->anim_z -= 0.1 * speed;
1485 if (lc->anim_z <= 0)
1488 lc->type = LAMENT_LEVIATHAN_UNSPIN;
1493 case LAMENT_LEVIATHAN_UNSPIN:
1494 lc->anim_r += 3.5 * speed;
1495 if (lc->anim_r >= 360 * 2)
1498 lc->type = LAMENT_BOX;
1499 lc->anim_pause = pause2;
1512 if (lc->type == LAMENT_BOX)
1513 lc->type = DEBUG_MODE;
1518 while (lc->type != DEBUG_MODE)
1522 # else /* !DEBUG_MODE */
1524 if (lc->ffwdp && lc->type == LAMENT_BOX)
1527 while (lc->type == LAMENT_BOX)
1532 # endif /* !DEBUG_MODE */
1537 gl_init (ModeInfo *mi)
1539 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1540 Bool wire = MI_IS_WIREFRAME(mi);
1548 static const GLfloat pos0[] = { -4.0, 2.0, 5.0, 1.0 };
1549 static const GLfloat pos1[] = { 6.0, -1.0, 3.0, 1.0 };
1551 static const GLfloat amb0[] = { 0.7, 0.7, 0.7, 1.0 };
1552 /* static const GLfloat amb1[] = { 0.7, 0.0, 0.0, 1.0 }; */
1553 static const GLfloat dif0[] = { 1.0, 1.0, 1.0, 1.0 };
1554 static const GLfloat dif1[] = { 0.3, 0.1, 0.1, 1.0 };
1556 glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1557 glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1559 glLightfv(GL_LIGHT0, GL_AMBIENT, amb0);
1560 /* glLightfv(GL_LIGHT1, GL_AMBIENT, amb1); */
1561 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif0);
1562 glLightfv(GL_LIGHT1, GL_DIFFUSE, dif1);
1564 glEnable(GL_LIGHTING);
1565 glEnable(GL_LIGHT0);
1566 /* glEnable(GL_LIGHT1); */
1568 glEnable(GL_DEPTH_TEST);
1569 glEnable(GL_TEXTURE_2D);
1570 glEnable(GL_NORMALIZE);
1571 glEnable(GL_CULL_FACE);
1577 for (i = 0; i < countof(lc->texids); i++)
1578 glGenTextures(1, &lc->texids[i]);
1580 lc->texture = image_data_to_ximage (mi->dpy, mi->xgwa.visual,
1581 lament512_png, sizeof(lament512_png));
1583 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1584 /* messes up -fps */
1585 /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
1587 for (i = 0; i < countof(lc->texids); i++)
1589 int height = lc->texture->width; /* assume square */
1590 glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1593 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1594 lc->texture->width, height, 0,
1595 GL_RGBA, GL_UNSIGNED_BYTE,
1596 (lc->texture->data +
1597 (lc->texture->bytes_per_line * height * i)));
1598 check_gl_error("texture");
1600 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1601 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1602 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1603 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1604 check_gl_error("texture");
1606 /* This makes scaled pixmaps tolerable to look at. */
1607 # if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT)
1608 # define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT
1610 # ifdef GL_TEXTURE_LOD_BIAS
1611 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25);
1613 clear_gl_error(); /* invalid enum on iPad 3 */
1617 for (i = 0; i < countof(all_objs); i++)
1619 GLfloat s = 1/3.0; /* box is 3" square */
1620 const struct gllist *L = *all_objs[i];
1621 const GLfloat *f = (const GLfloat *) L->data;
1624 lc->dlists[i] = glGenLists(1);
1625 lc->polys[i] = L->points / 3;
1626 glNewList(lc->dlists[i], GL_COMPILE);
1627 if (L->primitive != GL_TRIANGLES) abort();
1628 if (L->format != GL_N3F_V3F) abort();
1631 glTranslatef (-0.5, -0.5, -0.5);
1634 for (j = 0; j < L->points; j += 3)
1637 Bool blackp = (i == OBJ_ISO_BASE_A || i == OBJ_ISO_BASE_B);
1638 which_face (mi, f, &face, &outerp); /* from norm of first vert */
1640 set_colors (outerp ? exterior_color :
1641 blackp ? black_color : interior_color);
1642 glBindTexture (GL_TEXTURE_2D,
1643 (outerp ? lc->texids[face-1] :
1644 blackp ? 0 : lc->texids[6]));
1646 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
1647 if (face) texturize_vert (mi, face, f+3);
1648 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1649 if (face) texturize_vert (mi, face, f+3);
1650 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1651 if (face) texturize_vert (mi, face, f+3);
1652 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
1663 lament_handle_event (ModeInfo *mi, XEvent *event)
1665 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1667 if (gltrackball_event_handler (event, lc->trackball,
1668 MI_WIDTH (mi), MI_HEIGHT (mi),
1669 &lc->button_down_p))
1671 else if (event->xany.type == KeyPress)
1675 XLookupString (&event->xkey, &c, 1, &keysym, 0);
1676 if (c == ' ' || c == '\t')
1688 reshape_lament (ModeInfo *mi, int width, int height)
1690 GLfloat h = (GLfloat) height / (GLfloat) width;
1691 glViewport(0, 0, (GLint) width, (GLint) height);
1693 glMatrixMode(GL_PROJECTION);
1695 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1696 glMatrixMode(GL_MODELVIEW);
1698 glTranslatef(0.0, 0.0, -40.0);
1699 glClear(GL_COLOR_BUFFER_BIT);
1704 init_lament (ModeInfo *mi)
1706 lament_configuration *lc;
1710 lc = &lcs[MI_SCREEN(mi)];
1713 double rot_speed = 0.5;
1714 lc->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
1715 lc->trackball = gltrackball_init (True);
1718 lc->type = LAMENT_BOX;
1719 lc->anim_pause = 300 + (random() % 100);
1721 if ((lc->glx_context = init_GL(mi)) != NULL)
1723 reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1727 lc->states = (lament_type *) calloc (200, sizeof (*lc->states));
1730 # define PUSH(N,WHICH) \
1731 for (i = 0; i < N; i++) lc->states[lc->nstates++] = WHICH
1733 PUSH (4, LAMENT_TETRA_UNE); /* most common */
1734 PUSH (4, LAMENT_TETRA_USW);
1735 PUSH (4, LAMENT_TETRA_DWN);
1736 PUSH (4, LAMENT_TETRA_DSE);
1738 PUSH (8, LAMENT_STAR_OUT); /* pretty common */
1739 PUSH (8, LAMENT_TASER_OUT);
1740 PUSH (8, LAMENT_PILLAR_OUT);
1742 PUSH (4, LAMENT_LID_OPEN); /* rare */
1743 PUSH (2, LAMENT_SPHERE_OUT); /* rare */
1744 PUSH (1, LAMENT_LEVIATHAN_SPIN); /* very rare */
1746 PUSH (35, LAMENT_BOX); /* rest state */
1749 shuffle_states (lc);
1752 lc->type = DEBUG_MODE;
1760 draw_lament (ModeInfo *mi)
1762 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1763 Display *dpy = MI_DISPLAY(mi);
1764 Window window = MI_WINDOW(mi);
1766 if (!lc->glx_context)
1769 glDrawBuffer(GL_BACK);
1771 glXMakeCurrent(dpy, window, *(lc->glx_context));
1773 if (mi->fps_p) do_fps (mi);
1776 glXSwapBuffers(dpy, window);
1778 if (!lc->ffwdp && lc->anim_pause)
1784 XSCREENSAVER_MODULE ("Lament", lament)