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 refresh_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 /* Constrain it to roughly life-sized on the screen, not huge.
331 if (size > 768) /* iPad retina / iPhone 6 */
336 GLfloat max = 500; /* 3" on my screen... */
337 if (target_size > max)
341 /* But if that would make the image larger than target_size, scale it
342 back down again. The image-map bits we have are 512x512, so if the
343 image is magnified a lot, it looks pretty blocky. It's better to
344 have a 512x512 animation on a 1920x1080 screen that looks good
345 than a 1024x1024 animation that looks really pixelated.
347 if (size > target_size)
348 scale *= target_size / size;
350 glScalef (scale, scale, scale);
355 set_colors (const GLfloat *color)
357 glMaterialfv(GL_FRONT, GL_AMBIENT, color + 0);
358 glMaterialfv(GL_FRONT, GL_DIFFUSE, color + 4);
359 glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
360 glMaterialfv(GL_FRONT, GL_SHININESS, color + 12);
364 set_colors_alpha (const GLfloat *color, GLfloat a)
366 GLfloat c[countof(leviathan_color)];
367 memcpy (c, color, sizeof(c));
368 c[3] = c[7] = c[11] = a;
374 which_face (ModeInfo *mi, const GLfloat *f, int *face, int *outerp)
376 GLfloat size = 3; /* 3" square */
377 const GLfloat *n = f; /* normal */
378 const GLfloat *v = f + 3; /* vertex */
379 GLfloat slack = 0.01;
381 /* First look at the normal to determine which direction this triangle
382 is facing (or is most-closely facing).
383 It's an outer surface if it is within epsilon of the cube wall that
384 it is facing. Otherwise, it's an inner surface.
386 if (n[1] < -0.5) *face = 1, *outerp = v[1] < slack; /* S */
387 else if (n[2] > 0.5) *face = 2, *outerp = v[2] > size-slack; /* U */
388 else if (n[1] > 0.5) *face = 3, *outerp = v[1] > size-slack; /* N */
389 else if (n[2] < -0.5) *face = 4, *outerp = v[2] < slack; /* D */
390 else if (n[0] < -0.5) *face = 5, *outerp = v[0] < slack; /* W */
391 else /* (n[0] > 0.5)*/ *face = 6, *outerp = v[0] > size-slack; /* E */
393 /* Faces that don't have normals parallel to the axes aren't external. */
395 (n[0] > -0.95 && n[0] < 0.95 &&
396 n[1] > -0.95 && n[1] < 0.95 &&
397 n[2] > -0.95 && n[2] < 0.95))
403 texturize_vert (ModeInfo *mi, int which, const GLfloat *v)
405 GLfloat size = 3; /* 3" square */
406 GLfloat s = 0, q = 0;
408 /* Texture coordinates are surface coordinates,
409 on the plane of this cube wall. */
412 case 1: s = v[0], q = v[2]; break;
413 case 2: s = v[0], q = v[1]; break;
414 case 3: s = v[0], q = v[2]; q = size - q; break;
415 case 4: s = v[0], q = v[1]; q = size - q; break;
416 case 5: s = v[1], q = v[2]; break;
417 case 6: s = v[1], q = v[2]; break;
418 default: abort(); break;
421 glTexCoord2f (s / size, q / size);
426 leviathan (ModeInfo *mi, GLfloat ratio, GLfloat alpha, Bool top_p)
428 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
429 Bool wire = MI_IS_WIREFRAME(mi);
431 GLfloat z = 2 * ratio;
435 GLfloat th = acos (2 / sqrt (6)); /* Line up with cube's diagonal */
439 glRotatef (-45, 0, 1, 0);
440 glRotatef (-th * 180 / M_PI, 0, 0, 1);
443 glRotatef (180, 0, 0, 1);
445 for (i = 0; i < countof(p); i++)
447 GLfloat th = i * M_PI * 2 / countof(p);
448 p[i].x = cos(th) * r;
449 p[i].y = sin(th) * r;
452 glFrontFace (GL_CCW);
453 for (i = 0; i < countof(p); i++)
455 int j = (i + 1) % countof(p);
467 if (do_texture) /* Leviathan is the final texture */
468 glBindTexture (GL_TEXTURE_2D, lc->texids[countof(lc->texids) - 1]);
470 set_colors (leviathan_color);
472 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
473 glTexCoord2f (0.5, 1);
474 glVertex3f (z, 0, 0);
477 glVertex3f (0, p[i].x, p[i].y);
480 glVertex3f (0, p[j].x, p[j].y);
484 /* Shield for fading */
485 if (alpha < 0.9 && !wire)
490 set_colors_alpha (black_color, 1-alpha);
491 glBindTexture (GL_TEXTURE_2D, 0);
495 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
498 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
500 glVertex3f (z*a, p[j].x * b, p[j].y * b);
501 glVertex3f (z*a, p[i].x * b, p[i].y * b);
502 glVertex3f (0, p[i].x * 1.01, p[i].y * 1.01);
503 glVertex3f (0, p[j].x * 1.01, p[j].y * 1.01);
506 glDisable (GL_BLEND);
515 folding_walls (ModeInfo *mi, GLfloat ratio, Bool top_p)
517 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
518 Bool wire = MI_IS_WIREFRAME(mi);
519 const GLfloat pa[4][2] = {{ -0.5, -0.215833 },
522 { -0.215833, -0.5 }};
523 const int tex[6] = { 0, 5, 1, 4, 2, 3 };
524 const GLfloat top = -pa[0][1];
525 GLfloat end_angle = 30.85;
526 GLfloat rr = sin (ratio / 2 * M_PI);
527 GLfloat offa = 0.15 * rr;
528 GLfloat offb = 0.06 * rr;
537 glRotatef (60, 1, -1, 1);
538 glRotatef (180, 0, 1, 0);
539 glRotatef (90, 1, 0, 0);
543 glRotatef (180, 1, 0, 0);
546 /* Scale down the points near the axis */
552 p[1][0] = pa[1][0] - offb;
554 p[1][2] = pa[1][1] - offa;
556 p[2][0] = pa[2][0] - offa;
558 p[2][2] = pa[2][1] - offb;
567 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
570 for (i = 0; i < 3; i++)
576 glRotatef (-90, 1, 0, 0);
577 glRotatef (180, 1, 1, 0);
581 glRotatef (-90, 1, 0, 0);
582 glRotatef (180, 0, 1, 0);
583 glRotatef (90, 0, 1, 0);
586 glRotatef (-90, 0, 1, 0);
588 glTranslatef (-(top/2 + 0.25), 0.5, -(top/2 + 0.25));
589 glRotatef (-45, 0, 1, 0);
590 glRotatef (ratio * -end_angle, 0, 0, 1);
591 glRotatef (45, 0, 1, 0);
592 glTranslatef (top/2 + 0.25, -0.5, top/2 + 0.25);
594 /* Get the texture coordinates right.
595 This is hairy and incomprehensible. */
597 t[0][0] = pa[0][1] + 0.5; t[0][1] = pa[0][0] + 0.5;
598 t[1][0] = pa[1][1] + 0.5; t[1][1] = pa[1][0] + 0.5;
599 t[2][0] = pa[2][1] + 0.5; t[2][1] = pa[2][0] + 0.5;
600 t[3][0] = pa[3][1] + 0.5; t[3][1] = pa[3][0] + 0.5;
602 if (i == 0 && !top_p)
604 # define SWAP(A,B) A = 1-A, B = 1-B
605 SWAP(t[0][0], t[0][1]);
606 SWAP(t[1][0], t[1][1]);
607 SWAP(t[2][0], t[2][1]);
608 SWAP(t[3][0], t[3][1]);
611 else if (i == 0 && top_p)
614 memcpy (ot, t, sizeof(t));
615 # define SWAP(A,B) A = 1-A, B = 1-B
616 SWAP(t[0][0], ot[2][1]);
617 SWAP(t[1][0], ot[3][1]);
618 SWAP(t[2][0], ot[0][1]);
619 SWAP(t[3][0], ot[1][1]);
625 # define SWAP(A,B) f = A, A = B, B = -f
626 SWAP(t[0][0], t[0][1]);
627 SWAP(t[1][0], t[1][1]);
628 SWAP(t[2][0], t[2][1]);
629 SWAP(t[3][0], t[3][1]);
633 set_colors_alpha (exterior_color, 1-ratio);
634 glBindTexture (GL_TEXTURE_2D, lc->texids[tex[i + (top_p ? 3 : 0)]]);
636 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
637 do_normal (p[0][0], p[0][1], p[0][2],
638 p[1][0], p[1][1], p[1][2],
639 p[2][0], p[2][1], p[2][2]);
640 glTexCoord2fv(t[0]); glVertex3fv(p[0]);
641 glTexCoord2fv(t[1]); glVertex3fv(p[1]);
642 glTexCoord2fv(t[2]); glVertex3fv(p[2]);
643 glTexCoord2fv(t[3]); glVertex3fv(p[3]);
647 /* The triangles between the quads */
649 /* #### There is a fucking gap between the two black triangles
650 that I can't figure out! So instead of drawing the triangles,
651 we build a black shield around the middle bit in leviathan()
652 and count on back-face culling to have roughly the same effect.
657 memcpy (pp, p, sizeof(pp));
658 memcpy (pp[2], pp[1], sizeof(pp[1]));
659 pp[2][0] -= 0.5 * (1-ratio);
660 pp[2][1] -= 0.5 * (1-ratio);
662 glBindTexture (GL_TEXTURE_2D, 0);
663 set_colors_alpha (black_color, 1-ratio);
665 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
666 do_normal (pp[0][0], pp[0][1], pp[0][2],
667 pp[2][0], pp[2][1], pp[2][2],
668 pp[1][0], pp[1][1], pp[1][2]);
680 if (! wire) glDisable (GL_BLEND);
687 lament_sphere (ModeInfo *mi, GLfloat ratio)
689 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
690 Bool wire = MI_IS_WIREFRAME(mi);
691 GLfloat size = 3; /* 3" square */
693 int facets = 16; /* NxN grid on each face */
695 static const GLfloat norms[6][3] = {{ 0, -1, 0 }, { 0, 0, 1 }, { 0, 1, 0 },
696 { 0, 0, -1 }, { -1, 0, 0 }, { 1, 0, 0 }};
697 GLfloat s = 1.0 / facets;
699 /* The ratio used for the normals: linger on the square normals. */
700 GLfloat ratio2 = 1 - sin ((1 - ratio) / 2 * M_PI);
701 GLfloat r1 = 1 - ratio2 / 2;
702 GLfloat r2 = ratio2 / 2;
705 glTranslatef (-0.5, -0.5, -0.5);
706 glScalef (1/size, 1/size, 1/size);
708 set_colors (exterior_color);
710 for (face = 0; face < 6; face++)
713 for (y0 = 0; y0 < 1; y0 += s)
714 for (x0 = 0; x0 < 1; x0 += s)
719 GLfloat pa[4][3]; /* verts of the cube */
720 GLfloat pb[4][3]; /* verts of the transition to the sphere */
722 GLfloat norm[4][3]; /* normals of the transitional verts */
725 frontp = norms[face][0] < 0,
726 pa[0][1] = x0, pa[0][2] = y0, pa[0][0] = (frontp ? 0 : 1),
727 pa[1][1] = x1, pa[1][2] = y0, pa[1][0] = pa[0][0],
728 pa[2][1] = x1, pa[2][2] = y1, pa[2][0] = pa[0][0],
729 pa[3][1] = x0, pa[3][2] = y1, pa[3][0] = pa[0][0];
730 else if (norms[face][1])
731 frontp = norms[face][1] > 0,
732 pa[0][0] = x0, pa[0][2] = y0, pa[0][1] = (frontp ? 1 : 0),
733 pa[1][0] = x1, pa[1][2] = y0, pa[1][1] = pa[0][1],
734 pa[2][0] = x1, pa[2][2] = y1, pa[2][1] = pa[0][1],
735 pa[3][0] = x0, pa[3][2] = y1, pa[3][1] = pa[0][1];
736 else /* (norms[face][2]) */
737 frontp = norms[face][2] < 0,
738 pa[0][0] = x0, pa[0][1] = y0, pa[0][2] = (frontp ? 0 : 1),
739 pa[1][0] = x1, pa[1][1] = y0, pa[1][2] = pa[0][2],
740 pa[2][0] = x1, pa[2][1] = y1, pa[2][2] = pa[0][2],
741 pa[3][0] = x0, pa[3][1] = y1, pa[3][2] = pa[0][2];
743 for (i = 0; i < countof(pa); i++)
744 pa[i][0] *= size, pa[i][1] *= size, pa[i][2] *= size;
746 /* Convert square to sphere by treating as a normalized vector */
747 for (i = 0; i < countof(pa); i++)
749 GLfloat x = (pa[i][0] / size) - 0.5;
750 GLfloat y = (pa[i][1] / size) - 0.5;
751 GLfloat z = (pa[i][2] / size) - 0.5;
752 GLfloat d = sqrt (x*x + y*y + z*z) / 2;
757 pb[i][0] = pa[i][0] + ((x - pa[i][0]) * ratio);
758 pb[i][1] = pa[i][1] + ((y - pa[i][1]) * ratio);
759 pb[i][2] = pa[i][2] + ((z - pa[i][2]) * ratio);
762 /* The normals of an intermediate point are the weighted average
763 of the cube's orthogonal normals, and the sphere's radial
764 normals: early in the sequence, the edges are sharp, but they
765 soften as it expands. */
767 XYZ na, pa0, pa1, pa2;
768 pa0.x = pa[0][0]; pa0.y = pa[0][1]; pa0.z = pa[0][2];
769 pa1.x = pa[1][0]; pa1.y = pa[1][1]; pa1.z = pa[1][2];
770 pa2.x = pa[2][0]; pa2.y = pa[2][1]; pa2.z = pa[2][2];
771 na = calc_normal (pa0, pa1, pa2);
773 for (i = 0; i < countof(pb); i++)
781 d = sqrt (nb.x*nb.x + nb.y*nb.y + nb.z*nb.z); /* normalize */
786 norm[i][0] = (na.x * r1) + (nb.x * r2); /* weighted */
787 norm[i][1] = (na.y * r1) + (nb.y * r2);
788 norm[i][2] = (na.z * r1) + (nb.z * r2);
793 glBindTexture (GL_TEXTURE_2D, lc->texids[face]);
795 glFrontFace (frontp ? GL_CW : GL_CCW);
796 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
798 texturize_vert (mi, face+1, pa[0]);
799 glNormal3fv (norm[0]);
802 texturize_vert (mi, face+1, pa[1]);
803 glNormal3fv (norm[1]);
806 texturize_vert (mi, face+1, pa[2]);
807 glNormal3fv (norm[2]);
810 texturize_vert (mi, face+1, pa[3]);
811 glNormal3fv (norm[3]);
828 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
829 Bool wire = MI_IS_WIREFRAME(mi);
831 mi->polygon_count = 0;
834 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
836 glClear(GL_COLOR_BUFFER_BIT);
840 gltrackball_rotate (lc->trackball);
842 /* Make into the screen be +Y, right be +X, and up be +Z. */
843 glRotatef (-90.0, 1.0, 0.0, 0.0);
845 scale_for_window (mi);
847 /* Apply rotation to the object. */
848 if (lc->type != LAMENT_LID_ZOOM)
849 get_rotation (lc->rot, &lc->rotx, &lc->roty, &lc->rotz,
854 lc->rotx = lc->roty = 0;
858 glRotatef (lc->rotx * 360, 1, 0, 0);
859 glRotatef (lc->roty * 360, 0, 1, 0);
860 glRotatef (lc->rotz * 360, 0, 0, 1);
862 glScalef (0.5, 0.5, 0.5);
867 glCallList (lc->dlists[OBJ_BOX]);
868 mi->polygon_count += lc->polys[OBJ_BOX];
871 case LAMENT_STAR_OUT:
872 case LAMENT_STAR_ROT:
873 case LAMENT_STAR_ROT_IN:
874 case LAMENT_STAR_ROT_OUT:
875 case LAMENT_STAR_UNROT:
877 glTranslatef (0.0, 0.0, lc->anim_z/2);
878 glRotatef (lc->anim_r/2, 0.0, 0.0, 1.0);
879 glCallList (lc->dlists[OBJ_STAR_U]);
880 mi->polygon_count += lc->polys[OBJ_STAR_U];
882 glTranslatef (0.0, 0.0, -lc->anim_z);
883 glRotatef (-lc->anim_r, 0.0, 0.0, 1.0);
884 glCallList (lc->dlists[OBJ_STAR_D]);
885 mi->polygon_count += lc->polys[OBJ_STAR_D];
888 case LAMENT_TETRA_UNE:
889 case LAMENT_TETRA_USW:
890 case LAMENT_TETRA_DWN:
891 case LAMENT_TETRA_DSE:
896 case LAMENT_TETRA_UNE: magic = OBJ_TETRA_UNE; x= 1; y= 1; z= 1; break;
897 case LAMENT_TETRA_USW: magic = OBJ_TETRA_USW; x= 1; y= 1; z=-1; break;
898 case LAMENT_TETRA_DWN: magic = OBJ_TETRA_DWN; x= 1; y=-1; z= 1; break;
899 case LAMENT_TETRA_DSE: magic = OBJ_TETRA_DSE; x=-1; y= 1; z= 1; break;
900 default: abort(); break;
902 glCallList(lc->dlists[OBJ_TETRA_BASE]);
903 mi->polygon_count += lc->polys[OBJ_TETRA_BASE];
904 if (magic != OBJ_TETRA_UNE) glCallList (lc->dlists[OBJ_TETRA_UNE]);
905 if (magic != OBJ_TETRA_USW) glCallList (lc->dlists[OBJ_TETRA_USW]);
906 if (magic != OBJ_TETRA_DWN) glCallList (lc->dlists[OBJ_TETRA_DWN]);
907 if (magic != OBJ_TETRA_DSE) glCallList (lc->dlists[OBJ_TETRA_DSE]);
908 glRotatef (lc->anim_r, x, y, z);
909 glCallList (lc->dlists[magic]);
910 mi->polygon_count += lc->polys[magic] * 3;
914 case LAMENT_LID_OPEN:
915 case LAMENT_LID_CLOSE:
916 case LAMENT_LID_ZOOM:
920 const int lists[4] = { OBJ_LID_A, OBJ_LID_B, OBJ_LID_C, OBJ_LID_D };
922 lc->facing_p = facing_screen_p (mi);
924 if (lc->anim_z < 0.5)
925 glTranslatef (0, -30 * lc->anim_z, 0); /* zoom */
927 glTranslatef (8 * (0.5 - (lc->anim_z - 0.5)), 0, 0);
929 glCallList (lc->dlists[OBJ_LID_BASE]);
930 mi->polygon_count += lc->polys[OBJ_LID_BASE];
931 for (i = 0; i < countof(lists); i++)
934 glRotatef (90 * i, 0, 1, 0);
935 glTranslatef (-d, -0.5, d);
936 glRotatef (-45, 0, 1, 0);
937 glRotatef (-lc->anim_r, 1, 0, 0);
938 glRotatef (45, 0, 1, 0);
939 glTranslatef (d, 0.5, -d);
940 glRotatef (-90 * i, 0, 1, 0);
941 glCallList (lc->dlists[lists[i]]);
942 mi->polygon_count += lc->polys[lists[i]];
950 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
951 glVertex3f (-0.49, 0.49, -0.49);
952 glVertex3f ( 0.49, 0.49, -0.49);
953 glVertex3f ( 0.49, 0.49, 0.49);
954 glVertex3f (-0.49, 0.49, 0.49);
958 # endif /* DEBUG_MODE */
962 case LAMENT_TASER_OUT:
963 case LAMENT_TASER_SLIDE:
964 case LAMENT_TASER_SLIDE_IN:
965 case LAMENT_TASER_IN:
967 glTranslatef (0, -lc->anim_z/2, 0);
968 glCallList (lc->dlists[OBJ_TASER_BASE]);
969 mi->polygon_count += lc->polys[OBJ_TASER_BASE];
971 glTranslatef (0, lc->anim_z, 0);
972 glCallList (lc->dlists[OBJ_TASER_A]);
973 mi->polygon_count += lc->polys[OBJ_TASER_A];
975 glTranslatef (lc->anim_y, 0, 0);
976 glCallList (lc->dlists[OBJ_TASER_B]);
977 mi->polygon_count += lc->polys[OBJ_TASER_B];
980 case LAMENT_PILLAR_OUT:
981 case LAMENT_PILLAR_SPIN:
982 case LAMENT_PILLAR_IN:
984 glCallList (lc->dlists[OBJ_PILLAR_BASE]);
985 mi->polygon_count += lc->polys[OBJ_PILLAR_BASE];
988 if (lc->anim_z == 1 || lc->anim_z == 3)
990 glRotatef (lc->anim_r, 0, 0, 1);
991 glTranslatef (0, 0, lc->anim_y);
993 glCallList (lc->dlists[OBJ_PILLAR_A]);
994 mi->polygon_count += lc->polys[OBJ_PILLAR_A];
998 if (lc->anim_z == 2 || lc->anim_z == 3)
1000 glRotatef (lc->anim_r, 0, 0, 1);
1001 glTranslatef (0, 0, -lc->anim_y);
1003 glCallList (lc->dlists[OBJ_PILLAR_B]);
1004 mi->polygon_count += lc->polys[OBJ_PILLAR_B];
1008 case LAMENT_SPHERE_OUT:
1009 case LAMENT_SPHERE_IN:
1010 mi->polygon_count += lament_sphere (mi, lc->anim_y);
1013 case LAMENT_LEVIATHAN_SPIN:
1014 case LAMENT_LEVIATHAN_UNSPIN:
1015 case LAMENT_LEVIATHAN_FADE:
1016 case LAMENT_LEVIATHAN_UNFADE:
1017 case LAMENT_LEVIATHAN_TWIST:
1018 case LAMENT_LEVIATHAN_UNTWIST:
1020 /* These normals are hard to compute, so I pulled them from the
1022 const GLfloat axes[6][4] =
1023 {{ OBJ_ISO_UNE, 0.633994, 0.442836, 0.633994 },
1024 { OBJ_ISO_USW, 0.442836, 0.633994, -0.633994 },
1025 { OBJ_ISO_DSE, -0.633994, 0.633994, 0.442836 },
1026 { OBJ_ISO_SWD, -0.633994, -0.442836, -0.633994 },
1027 { OBJ_ISO_DEN, -0.442836, -0.633994, 0.633994 },
1028 { OBJ_ISO_UNW, 0.633994, -0.633994, -0.442836 }};
1031 GLfloat s = (1 - lc->anim_z);
1032 GLfloat s2 = MAX (0, 360 - lc->anim_r) / 360.0;
1036 case LAMENT_LEVIATHAN_SPIN: break;
1037 case LAMENT_LEVIATHAN_UNSPIN: s2 = 1 - s2; break;
1038 default: s2 = 0; blendp = 1; break;
1041 if (wire) blendp = 0;
1043 s = (s * 0.6) + 0.4;
1045 leviathan (mi, 1 - s2, 1, True);
1046 glCallList (lc->dlists[OBJ_ISO_BASE_A]);
1047 mi->polygon_count += lc->polys[OBJ_ISO_BASE_A];
1050 glScalef (s2, s2, s2);
1051 glCallList (lc->dlists[OBJ_ISO_USE]);
1052 mi->polygon_count += lc->polys[OBJ_ISO_USE];
1056 glRotatef (lc->anim_y, 1, -1, 1);
1057 glCallList (lc->dlists[OBJ_ISO_BASE_B]);
1058 mi->polygon_count += lc->polys[OBJ_ISO_BASE_B];
1059 leviathan (mi, 1 - s2, 1, False);
1064 # ifndef HAVE_JWZGLES /* no glBlendColor */
1065 glEnable (GL_BLEND);
1066 glBlendFunc (GL_CONSTANT_ALPHA, GL_SRC_ALPHA);
1067 glBlendColor (1, 1, 1, MAX(0, 1-(lc->anim_z * 3)));
1071 for (i = 0; i < countof(axes); i++)
1074 glRotatef (lc->anim_r, axes[i][1], axes[i][2], axes[i][3]);
1076 glCallList (lc->dlists[(int) axes[i][0]]);
1077 mi->polygon_count += lc->polys[(int) axes[i][0]];
1080 glRotatef (lc->anim_y, 1, -1, 1);
1083 if (blendp) glDisable (GL_BLEND);
1086 glScalef (s2, s2, s2);
1087 glCallList (lc->dlists[OBJ_ISO_DWN]);
1088 mi->polygon_count += lc->polys[OBJ_ISO_DWN];
1093 case LAMENT_LEVIATHAN_COLLAPSE:
1094 case LAMENT_LEVIATHAN_EXPAND:
1097 leviathan (mi, 1, lc->anim_y, True);
1098 glRotatef (180, 1, -1, 1);
1099 leviathan (mi, 1, lc->anim_y, False);
1101 folding_walls (mi, lc->anim_y, True);
1102 folding_walls (mi, lc->anim_y, False);
1115 /* Rather than just picking states randomly, pick an ordering randomly, do it,
1116 and then re-randomize. That way one can be assured of seeing all states in
1117 a short time period, though not always in the same order (it's frustrating
1118 to see it pick the same state 5x in a row.) Though, that can still happen,
1119 since states are in the list multiple times as a way of giving them
1123 shuffle_states (lament_configuration *lc)
1126 for (i = 0; i < lc->nstates; i++)
1128 int a = random() % lc->nstates;
1129 lament_type swap = lc->states[a];
1130 lc->states[a] = lc->states[i];
1131 lc->states[i] = swap;
1137 animate (ModeInfo *mi)
1139 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1142 GLfloat speed = (lc->ffwdp ? 20 : 1);
1149 if (lc->state >= lc->nstates)
1151 shuffle_states (lc);
1154 lc->type = lc->states[lc->state];
1156 if (lc->type == LAMENT_BOX)
1157 lc->anim_pause = pause2;
1165 /* -------------------------------------------------------------- */
1167 case LAMENT_STAR_OUT:
1168 lc->anim_z += 0.01 * speed;
1169 if (lc->anim_z >= 1.0)
1172 lc->type = LAMENT_STAR_ROT;
1173 lc->anim_pause = pause;
1177 case LAMENT_STAR_ROT:
1178 lc->anim_r += 1.0 * speed;
1179 if (lc->anim_r >= 45.0)
1182 lc->type = LAMENT_STAR_ROT_IN;
1183 lc->anim_pause = pause;
1187 case LAMENT_STAR_ROT_IN:
1188 lc->anim_z -= 0.01 * speed;
1189 if (lc->anim_z <= 0.0)
1192 lc->type = LAMENT_STAR_ROT_OUT;
1193 lc->anim_pause = pause2 * (1 + frand(2) + frand(2));
1197 case LAMENT_STAR_ROT_OUT:
1198 lc->anim_z += 0.01 * speed;
1199 if (lc->anim_z >= 1.0)
1202 lc->type = LAMENT_STAR_UNROT;
1203 lc->anim_pause = pause;
1207 case LAMENT_STAR_UNROT:
1208 lc->anim_r -= 1.0 * speed;
1209 if (lc->anim_r <= 0.0)
1212 lc->type = LAMENT_STAR_IN;
1213 lc->anim_pause = pause;
1217 case LAMENT_STAR_IN:
1218 lc->anim_z -= 0.01 * speed;
1219 if (lc->anim_z <= 0.0)
1222 lc->type = LAMENT_BOX;
1223 lc->anim_pause = pause2;
1227 /* -------------------------------------------------------------- */
1229 case LAMENT_TETRA_UNE:
1230 case LAMENT_TETRA_USW:
1231 case LAMENT_TETRA_DWN:
1232 case LAMENT_TETRA_DSE:
1234 lc->anim_r += 1.0 * speed;
1235 if (lc->anim_r >= 360.0)
1238 lc->type = LAMENT_BOX;
1239 lc->anim_pause = pause2;
1241 else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1244 lc->anim_pause = pause;
1246 else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1249 lc->anim_pause = pause;
1253 /* -------------------------------------------------------------- */
1255 case LAMENT_LID_OPEN:
1256 lc->anim_r += 1.0 * speed;
1258 if (lc->anim_r >= 112.0)
1262 lc->anim_pause = pause2;
1263 lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
1267 case LAMENT_LID_CLOSE:
1268 lc->anim_r -= 1.0 * speed;
1269 if (lc->anim_r <= 0.0)
1272 lc->type = LAMENT_BOX;
1273 lc->anim_pause = pause2;
1277 case LAMENT_LID_ZOOM:
1278 lc->anim_z += 0.01 * speed;
1279 if (lc->anim_z > 1.0)
1283 lc->type = LAMENT_BOX;
1287 /* -------------------------------------------------------------- */
1289 case LAMENT_TASER_OUT:
1290 lc->anim_z += 0.005 * speed;
1291 if (lc->anim_z >= 0.5)
1294 lc->type = LAMENT_TASER_SLIDE;
1295 lc->anim_pause = pause * (1 + frand(5) + frand(5));
1299 case LAMENT_TASER_SLIDE:
1300 lc->anim_y += 0.005 * speed;
1301 if (lc->anim_y >= 0.255)
1304 lc->type = LAMENT_TASER_SLIDE_IN;
1305 lc->anim_pause = pause2 * (1 + frand(5) + frand(5));
1309 case LAMENT_TASER_SLIDE_IN:
1310 lc->anim_y -= 0.0025 * speed;
1311 if (lc->anim_y <= 0.0)
1314 lc->type = LAMENT_TASER_IN;
1315 lc->anim_pause = pause;
1319 case LAMENT_TASER_IN:
1320 lc->anim_z -= 0.0025 * speed;
1321 if (lc->anim_z <= 0.0)
1324 lc->type = LAMENT_BOX;
1325 lc->anim_pause = pause2;
1329 /* -------------------------------------------------------------- */
1331 case LAMENT_PILLAR_OUT:
1333 if (lc->anim_y == 0) /* mostly in */
1334 lc->anim_y += 0.005 * ((random() % 5) ? -1 : 1) * speed;
1335 else if (lc->anim_y > 0)
1336 lc->anim_y += 0.005 * speed;
1338 lc->anim_y -= 0.001 * speed;
1340 if (lc->anim_z == 0)
1342 int i = (random() % 7); /* A, B or both */
1343 if (i == 0) lc->anim_z = 3;
1344 else if (i < 5) lc->anim_z = 2;
1345 else lc->anim_z = 1;
1347 /* We can do quarter turns, because it's radially symmetrical. */
1348 lc->anim_r = 90.0 * (1 + frand(6)) * RANDSIGN();
1350 if (lc->anim_y > 0.4)
1353 lc->type = LAMENT_PILLAR_SPIN;
1354 lc->anim_pause = pause;
1356 else if (lc->anim_y < -0.03)
1359 lc->type = LAMENT_PILLAR_SPIN;
1360 lc->anim_pause = pause;
1364 case LAMENT_PILLAR_SPIN:
1366 Bool negp = (lc->anim_r < 0);
1367 lc->anim_r += (negp ? 1 : -1) * speed;
1368 if (negp ? lc->anim_r > 0 : lc->anim_r < 0)
1371 lc->type = LAMENT_PILLAR_IN;
1376 case LAMENT_PILLAR_IN:
1378 Bool negp = (lc->anim_y < 0);
1379 lc->anim_y += (negp ? 1 : -1) * 0.005 * speed;
1380 if (negp ? lc->anim_y > 0 : lc->anim_y < 0)
1384 lc->type = LAMENT_BOX;
1385 lc->anim_pause = pause;
1390 /* -------------------------------------------------------------- */
1392 case LAMENT_SPHERE_OUT:
1394 lc->anim_y += 0.01 * speed;
1395 if (lc->anim_y >= 1)
1398 lc->type = LAMENT_SPHERE_IN;
1399 lc->anim_pause = pause2 * (1 + frand(1) + frand(1));
1404 case LAMENT_SPHERE_IN:
1406 lc->anim_y -= 0.01 * speed;
1407 if (lc->anim_y <= 0)
1410 lc->type = LAMENT_BOX;
1411 lc->anim_pause = pause;
1416 /* -------------------------------------------------------------- */
1418 case LAMENT_LEVIATHAN_SPIN:
1419 lc->anim_r += 3.5 * speed;
1420 if (lc->anim_r >= 360 * 3)
1423 lc->type = LAMENT_LEVIATHAN_FADE;
1428 case LAMENT_LEVIATHAN_FADE:
1429 lc->anim_z += 0.01 * speed;
1430 if (lc->anim_z >= 1)
1433 lc->type = LAMENT_LEVIATHAN_TWIST;
1438 case LAMENT_LEVIATHAN_TWIST:
1439 lc->anim_y += 2 * speed;
1441 if (lc->anim_y >= 180)
1444 lc->type = LAMENT_LEVIATHAN_COLLAPSE;
1449 case LAMENT_LEVIATHAN_COLLAPSE:
1450 lc->anim_y += 0.01 * speed;
1451 if (lc->anim_y >= 1)
1454 lc->type = LAMENT_LEVIATHAN_EXPAND;
1455 lc->anim_pause = pause2 * 4;
1459 case LAMENT_LEVIATHAN_EXPAND:
1460 lc->anim_y -= 0.005 * speed;
1461 if (lc->anim_y <= 0)
1464 lc->type = LAMENT_LEVIATHAN_UNTWIST;
1468 case LAMENT_LEVIATHAN_UNTWIST:
1469 lc->anim_y -= 2 * speed;
1471 if (lc->anim_y <= 0)
1474 lc->type = LAMENT_LEVIATHAN_UNFADE;
1479 case LAMENT_LEVIATHAN_UNFADE:
1480 lc->anim_z -= 0.1 * speed;
1481 if (lc->anim_z <= 0)
1484 lc->type = LAMENT_LEVIATHAN_UNSPIN;
1489 case LAMENT_LEVIATHAN_UNSPIN:
1490 lc->anim_r += 3.5 * speed;
1491 if (lc->anim_r >= 360 * 2)
1494 lc->type = LAMENT_BOX;
1495 lc->anim_pause = pause2;
1508 if (lc->type == LAMENT_BOX)
1509 lc->type = DEBUG_MODE;
1514 while (lc->type != DEBUG_MODE)
1518 # else /* !DEBUG_MODE */
1520 if (lc->ffwdp && lc->type == LAMENT_BOX)
1523 while (lc->type == LAMENT_BOX)
1528 # endif /* !DEBUG_MODE */
1533 gl_init (ModeInfo *mi)
1535 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1536 Bool wire = MI_IS_WIREFRAME(mi);
1544 static const GLfloat pos0[] = { -4.0, 2.0, 5.0, 1.0 };
1545 static const GLfloat pos1[] = { 6.0, -1.0, 3.0, 1.0 };
1547 static const GLfloat amb0[] = { 0.7, 0.7, 0.7, 1.0 };
1548 /* static const GLfloat amb1[] = { 0.7, 0.0, 0.0, 1.0 }; */
1549 static const GLfloat dif0[] = { 1.0, 1.0, 1.0, 1.0 };
1550 static const GLfloat dif1[] = { 0.3, 0.1, 0.1, 1.0 };
1552 glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1553 glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1555 glLightfv(GL_LIGHT0, GL_AMBIENT, amb0);
1556 /* glLightfv(GL_LIGHT1, GL_AMBIENT, amb1); */
1557 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif0);
1558 glLightfv(GL_LIGHT1, GL_DIFFUSE, dif1);
1560 glEnable(GL_LIGHTING);
1561 glEnable(GL_LIGHT0);
1562 /* glEnable(GL_LIGHT1); */
1564 glEnable(GL_DEPTH_TEST);
1565 glEnable(GL_TEXTURE_2D);
1566 glEnable(GL_NORMALIZE);
1567 glEnable(GL_CULL_FACE);
1573 for (i = 0; i < countof(lc->texids); i++)
1574 glGenTextures(1, &lc->texids[i]);
1576 lc->texture = xpm_to_ximage (mi->dpy,
1581 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1582 /* messes up -fps */
1583 /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
1585 for (i = 0; i < countof(lc->texids); i++)
1587 int height = lc->texture->width; /* assume square */
1588 glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1591 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1592 lc->texture->width, height, 0,
1594 /* GL_UNSIGNED_BYTE, */
1595 GL_UNSIGNED_INT_8_8_8_8_REV,
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 lcs = (lament_configuration *)
1711 calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
1714 fprintf(stderr, "%s: out of memory\n", progname);
1719 lc = &lcs[MI_SCREEN(mi)];
1722 double rot_speed = 0.5;
1723 lc->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
1724 lc->trackball = gltrackball_init (True);
1727 lc->type = LAMENT_BOX;
1728 lc->anim_pause = 300 + (random() % 100);
1730 if ((lc->glx_context = init_GL(mi)) != NULL)
1732 reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1736 lc->states = (lament_type *) calloc (200, sizeof (*lc->states));
1739 # define PUSH(N,WHICH) \
1740 for (i = 0; i < N; i++) lc->states[lc->nstates++] = WHICH
1742 PUSH (4, LAMENT_TETRA_UNE); /* most common */
1743 PUSH (4, LAMENT_TETRA_USW);
1744 PUSH (4, LAMENT_TETRA_DWN);
1745 PUSH (4, LAMENT_TETRA_DSE);
1747 PUSH (8, LAMENT_STAR_OUT); /* pretty common */
1748 PUSH (8, LAMENT_TASER_OUT);
1749 PUSH (8, LAMENT_PILLAR_OUT);
1751 PUSH (4, LAMENT_LID_OPEN); /* rare */
1752 PUSH (2, LAMENT_SPHERE_OUT); /* rare */
1753 PUSH (1, LAMENT_LEVIATHAN_SPIN); /* very rare */
1755 PUSH (35, LAMENT_BOX); /* rest state */
1758 shuffle_states (lc);
1761 lc->type = DEBUG_MODE;
1769 draw_lament (ModeInfo *mi)
1771 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1772 Display *dpy = MI_DISPLAY(mi);
1773 Window window = MI_WINDOW(mi);
1775 if (!lc->glx_context)
1778 glDrawBuffer(GL_BACK);
1780 glXMakeCurrent(dpy, window, *(lc->glx_context));
1782 if (mi->fps_p) do_fps (mi);
1785 glXSwapBuffers(dpy, window);
1787 if (!lc->ffwdp && lc->anim_pause)
1793 XSCREENSAVER_MODULE ("Lament", lament)