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 # define refresh_lament 0
34 # define release_lament 0
35 #include "xlockmore.h"
37 #ifdef USE_GL /* whole file */
41 /* #define DEBUG_MODE LAMENT_LEVIATHAN_COLLAPSE */
44 #define countof(x) (sizeof((x))/sizeof((*x)))
46 #define MAX(x, y) ((x) > (y) ? (x) : (y))
48 #define MIN(x, y) ((x) < (y) ? (x) : (y))
50 extern const struct gllist
52 *lament_model_iso_base_a,
53 *lament_model_iso_base_b,
54 *lament_model_iso_den,
55 *lament_model_iso_dse,
56 *lament_model_iso_dwn,
57 *lament_model_iso_swd,
58 *lament_model_iso_une,
59 *lament_model_iso_unw,
60 *lament_model_iso_use,
61 *lament_model_iso_usw,
62 *lament_model_leviathan,
65 *lament_model_lid_base,
68 *lament_model_pillar_a,
69 *lament_model_pillar_b,
70 *lament_model_pillar_base,
73 *lament_model_taser_a,
74 *lament_model_taser_b,
75 *lament_model_taser_base,
76 *lament_model_tetra_base,
77 *lament_model_tetra_dse,
78 *lament_model_tetra_dwn,
79 *lament_model_tetra_une,
80 *lament_model_tetra_usw;
82 static const struct gllist * const *all_objs[] = {
84 &lament_model_iso_base_a,
85 &lament_model_iso_base_b,
86 &lament_model_iso_den,
87 &lament_model_iso_dse,
88 &lament_model_iso_dwn,
89 &lament_model_iso_swd,
90 &lament_model_iso_une,
91 &lament_model_iso_unw,
92 &lament_model_iso_use,
93 &lament_model_iso_usw,
94 &lament_model_leviathan,
97 &lament_model_lid_base,
100 &lament_model_pillar_a,
101 &lament_model_pillar_b,
102 &lament_model_pillar_base,
103 &lament_model_star_d,
104 &lament_model_star_u,
105 &lament_model_taser_a,
106 &lament_model_taser_b,
107 &lament_model_taser_base,
108 &lament_model_tetra_base,
109 &lament_model_tetra_dse,
110 &lament_model_tetra_dwn,
111 &lament_model_tetra_une,
112 &lament_model_tetra_usw
115 typedef enum { /* must be in the same order as in `all_objs'. */
149 #define DEF_TEXTURE "True"
151 static int do_texture;
153 static XrmOptionDescRec opts[] = {
154 {"-texture", ".lament.texture", XrmoptionNoArg, "true" },
155 {"+texture", ".lament.texture", XrmoptionNoArg, "false" },
158 static argtype vars[] = {
159 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
162 ENTRYPOINT ModeSpecOpt lament_opts = {countof(opts), opts, countof(vars), vars, NULL};
164 #include "xpm-ximage.h"
166 #include "gltrackball.h"
170 __extension__ /* don't warn about "string length is greater than the length
171 ISO C89 compilers are required to support" when including
172 the following XPM file... */
174 #include "../images/lament512.xpm"
176 #define RANDSIGN() ((random() & 1) ? 1 : -1)
199 LAMENT_TASER_SLIDE_IN,
209 LAMENT_LEVIATHAN_SPIN,
210 LAMENT_LEVIATHAN_FADE,
211 LAMENT_LEVIATHAN_TWIST,
212 LAMENT_LEVIATHAN_COLLAPSE,
213 LAMENT_LEVIATHAN_EXPAND,
214 LAMENT_LEVIATHAN_UNTWIST,
215 LAMENT_LEVIATHAN_UNFADE,
216 LAMENT_LEVIATHAN_UNSPIN,
220 static const GLfloat exterior_color[] =
221 { 0.33, 0.22, 0.03, 1.00, /* ambient */
222 0.78, 0.57, 0.11, 1.00, /* specular */
223 0.99, 0.91, 0.81, 1.00, /* diffuse */
224 27.80 /* shininess */
226 static const GLfloat interior_color[] =
227 { 0.20, 0.20, 0.15, 1.00, /* ambient */
228 0.40, 0.40, 0.32, 1.00, /* specular */
229 0.99, 0.99, 0.81, 1.00, /* diffuse */
230 50.80 /* shininess */
232 static const GLfloat leviathan_color[] =
233 { 0.30, 0.30, 0.30, 1.00, /* ambient */
234 0.85, 0.85, 0.95, 1.00, /* specular */
235 0.99, 0.99, 0.99, 1.00, /* diffuse */
236 50.80 /* shininess */
238 static const GLfloat black_color[] =
239 { 0.05, 0.05, 0.05, 1.00, /* ambient */
240 0.05, 0.05, 0.05, 1.00, /* specular */
241 0.05, 0.05, 0.05, 1.00, /* diffuse */
242 80.00 /* shininess */
247 GLXContext *glx_context;
249 double rotx, roty, rotz;
250 trackball_state *trackball;
254 GLuint dlists[countof(all_objs)];
255 GLuint polys[countof(all_objs)];
257 XImage *texture; /* image bits */
258 GLuint texids[8]; /* texture map IDs */
259 lament_type type; /* which mode of the object is current */
261 int anim_pause; /* countdown before animating again */
262 GLfloat anim_r, anim_y, anim_z; /* relative position during anims */
268 } lament_configuration;
270 static lament_configuration *lcs = NULL;
274 facing_screen_p (ModeInfo *mi)
277 GLdouble m[16], p[16], x, y, z;
279 glGetDoublev (GL_MODELVIEW_MATRIX, m);
280 glGetDoublev (GL_PROJECTION_MATRIX, p);
281 glGetIntegerv (GL_VIEWPORT, v);
283 /* See if a coordinate 5 units in front of the door is near the
284 center of the screen. */
285 gluProject (0, -5, 0, m, p, v, &x, &y, &z);
286 x = (x / MI_WIDTH(mi)) - 0.5;
287 y = (y / MI_HEIGHT(mi)) - 0.5;
289 facing_p = (z < 0.9 &&
290 x > -0.15 && x < 0.15 &&
291 y > -0.15 && y < 0.15);
294 glBindTexture(GL_TEXTURE_2D, 0);
295 glDisable (GL_LIGHTING);
296 glColor3f (1, (facing_p ? 1 : 0), 0);
298 glVertex3f (0, 0, 0);
299 glVertex3f (0, -5, 0);
301 if (!MI_IS_WIREFRAME(mi)) glEnable (GL_LIGHTING);
302 # endif /* DEBUG_MODE */
309 scale_for_window (ModeInfo *mi)
311 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
313 GLfloat target_size = 1.4 * (lc->texture ? lc->texture->width : 512);
314 GLfloat size = MI_WIDTH(mi) < MI_HEIGHT(mi) ? MI_WIDTH(mi) : MI_HEIGHT(mi);
317 /* Make it take up roughly the full width of the window. */
320 /* But if the window is wider than tall, make it only take up the
321 height of the window instead.
323 if (MI_WIDTH(mi) > MI_HEIGHT(mi))
324 scale /= MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi);
326 /* Constrain it to roughly life-sized on the screen, not huge.
329 if (size > 768) /* iPad retina */
334 GLfloat max = 500; /* 3" on my screen... */
335 if (target_size > max)
339 /* But if that would make the image larger than target_size, scale it
340 back down again. The image-map bits we have are 512x512, so if the
341 image is magnified a lot, it looks pretty blocky. It's better to
342 have a 512x512 animation on a 1920x1080 screen that looks good
343 than a 1024x1024 animation that looks really pixelated.
345 if (size > target_size)
346 scale *= target_size / size;
348 glScalef (scale, scale, scale);
353 set_colors (const GLfloat *color)
355 glMaterialfv(GL_FRONT, GL_AMBIENT, color + 0);
356 glMaterialfv(GL_FRONT, GL_DIFFUSE, color + 4);
357 glMaterialfv(GL_FRONT, GL_SPECULAR, color + 8);
358 glMaterialfv(GL_FRONT, GL_SHININESS, color + 12);
362 set_colors_alpha (const GLfloat *color, GLfloat a)
364 GLfloat c[countof(leviathan_color)];
365 memcpy (c, color, sizeof(c));
366 c[3] = c[7] = c[11] = a;
372 which_face (ModeInfo *mi, const GLfloat *f, int *face, int *outerp)
374 GLfloat size = 3; /* 3" square */
375 const GLfloat *n = f; /* normal */
376 const GLfloat *v = f + 3; /* vertex */
377 GLfloat slack = 0.01;
379 /* First look at the normal to determine which direction this triangle
380 is facing (or is most-closely facing).
381 It's an outer surface if it is within epsilon of the cube wall that
382 it is facing. Otherwise, it's an inner surface.
384 if (n[1] < -0.5) *face = 1, *outerp = v[1] < slack; /* S */
385 else if (n[2] > 0.5) *face = 2, *outerp = v[2] > size-slack; /* U */
386 else if (n[1] > 0.5) *face = 3, *outerp = v[1] > size-slack; /* N */
387 else if (n[2] < -0.5) *face = 4, *outerp = v[2] < slack; /* D */
388 else if (n[0] < -0.5) *face = 5, *outerp = v[0] < slack; /* W */
389 else /* (n[0] > 0.5)*/ *face = 6, *outerp = v[0] > size-slack; /* E */
391 /* Faces that don't have normals parallel to the axes aren't external. */
393 (n[0] > -0.95 && n[0] < 0.95 &&
394 n[1] > -0.95 && n[1] < 0.95 &&
395 n[2] > -0.95 && n[2] < 0.95))
401 texturize_vert (ModeInfo *mi, int which, const GLfloat *v)
403 GLfloat size = 3; /* 3" square */
404 GLfloat s = 0, q = 0;
406 /* Texture coordinates are surface coordinates,
407 on the plane of this cube wall. */
410 case 1: s = v[0], q = v[2]; break;
411 case 2: s = v[0], q = v[1]; break;
412 case 3: s = v[0], q = v[2]; q = size - q; break;
413 case 4: s = v[0], q = v[1]; q = size - q; break;
414 case 5: s = v[1], q = v[2]; break;
415 case 6: s = v[1], q = v[2]; break;
416 default: abort(); break;
419 glTexCoord2f (s / size, q / size);
424 leviathan (ModeInfo *mi, GLfloat ratio, GLfloat alpha, Bool top_p)
426 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
427 Bool wire = MI_IS_WIREFRAME(mi);
429 GLfloat z = 2 * ratio;
433 GLfloat th = acos (2 / sqrt (6)); /* Line up with cube's diagonal */
437 glRotatef (-45, 0, 1, 0);
438 glRotatef (-th * 180 / M_PI, 0, 0, 1);
441 glRotatef (180, 0, 0, 1);
443 for (i = 0; i < countof(p); i++)
445 GLfloat th = i * M_PI * 2 / countof(p);
446 p[i].x = cos(th) * r;
447 p[i].y = sin(th) * r;
450 glFrontFace (GL_CCW);
451 for (i = 0; i < countof(p); i++)
453 int j = (i + 1) % countof(p);
465 if (do_texture) /* Leviathan is the final texture */
466 glBindTexture (GL_TEXTURE_2D, lc->texids[countof(lc->texids) - 1]);
468 set_colors (leviathan_color);
470 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
471 glTexCoord2f (0.5, 1);
472 glVertex3f (z, 0, 0);
475 glVertex3f (0, p[i].x, p[i].y);
478 glVertex3f (0, p[j].x, p[j].y);
482 /* Shield for fading */
483 if (alpha < 0.9 && !wire)
488 set_colors_alpha (black_color, 1-alpha);
489 glBindTexture (GL_TEXTURE_2D, 0);
493 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
496 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
498 glVertex3f (z*a, p[j].x * b, p[j].y * b);
499 glVertex3f (z*a, p[i].x * b, p[i].y * b);
500 glVertex3f (0, p[i].x * 1.01, p[i].y * 1.01);
501 glVertex3f (0, p[j].x * 1.01, p[j].y * 1.01);
504 glDisable (GL_BLEND);
513 folding_walls (ModeInfo *mi, GLfloat ratio, Bool top_p)
515 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
516 Bool wire = MI_IS_WIREFRAME(mi);
517 const GLfloat pa[4][2] = {{ -0.5, -0.215833 },
520 { -0.215833, -0.5 }};
521 const int tex[6] = { 0, 5, 1, 4, 2, 3 };
522 const GLfloat top = -pa[0][1];
523 GLfloat end_angle = 30.85;
524 GLfloat rr = sin (ratio / 2 * M_PI);
525 GLfloat offa = 0.15 * rr;
526 GLfloat offb = 0.06 * rr;
535 glRotatef (60, 1, -1, 1);
536 glRotatef (180, 0, 1, 0);
537 glRotatef (90, 1, 0, 0);
541 glRotatef (180, 1, 0, 0);
544 /* Scale down the points near the axis */
550 p[1][0] = pa[1][0] - offb;
552 p[1][2] = pa[1][1] - offa;
554 p[2][0] = pa[2][0] - offa;
556 p[2][2] = pa[2][1] - offb;
565 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
568 for (i = 0; i < 3; i++)
574 glRotatef (-90, 1, 0, 0);
575 glRotatef (180, 1, 1, 0);
579 glRotatef (-90, 1, 0, 0);
580 glRotatef (180, 0, 1, 0);
581 glRotatef (90, 0, 1, 0);
584 glRotatef (-90, 0, 1, 0);
586 glTranslatef (-(top/2 + 0.25), 0.5, -(top/2 + 0.25));
587 glRotatef (-45, 0, 1, 0);
588 glRotatef (ratio * -end_angle, 0, 0, 1);
589 glRotatef (45, 0, 1, 0);
590 glTranslatef (top/2 + 0.25, -0.5, top/2 + 0.25);
592 /* Get the texture coordinates right.
593 This is hairy and incomprehensible. */
595 t[0][0] = pa[0][1] + 0.5; t[0][1] = pa[0][0] + 0.5;
596 t[1][0] = pa[1][1] + 0.5; t[1][1] = pa[1][0] + 0.5;
597 t[2][0] = pa[2][1] + 0.5; t[2][1] = pa[2][0] + 0.5;
598 t[3][0] = pa[3][1] + 0.5; t[3][1] = pa[3][0] + 0.5;
600 if (i == 0 && !top_p)
602 # define SWAP(A,B) A = 1-A, B = 1-B
603 SWAP(t[0][0], t[0][1]);
604 SWAP(t[1][0], t[1][1]);
605 SWAP(t[2][0], t[2][1]);
606 SWAP(t[3][0], t[3][1]);
609 else if (i == 0 && top_p)
612 memcpy (ot, t, sizeof(t));
613 # define SWAP(A,B) A = 1-A, B = 1-B
614 SWAP(t[0][0], ot[2][1]);
615 SWAP(t[1][0], ot[3][1]);
616 SWAP(t[2][0], ot[0][1]);
617 SWAP(t[3][0], ot[1][1]);
623 # define SWAP(A,B) f = A, A = B, B = -f
624 SWAP(t[0][0], t[0][1]);
625 SWAP(t[1][0], t[1][1]);
626 SWAP(t[2][0], t[2][1]);
627 SWAP(t[3][0], t[3][1]);
631 set_colors_alpha (exterior_color, 1-ratio);
632 glBindTexture (GL_TEXTURE_2D, lc->texids[tex[i + (top_p ? 3 : 0)]]);
634 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
635 do_normal (p[0][0], p[0][1], p[0][2],
636 p[1][0], p[1][1], p[1][2],
637 p[2][0], p[2][1], p[2][2]);
638 glTexCoord2fv(t[0]); glVertex3fv(p[0]);
639 glTexCoord2fv(t[1]); glVertex3fv(p[1]);
640 glTexCoord2fv(t[2]); glVertex3fv(p[2]);
641 glTexCoord2fv(t[3]); glVertex3fv(p[3]);
645 /* The triangles between the quads */
647 /* #### There is a fucking gap between the two black triangles
648 that I can't figure out! So instead of drawing the triangles,
649 we build a black shield around the middle bit in leviathan()
650 and count on back-face culling to have roughly the same effect.
655 memcpy (pp, p, sizeof(pp));
656 memcpy (pp[2], pp[1], sizeof(pp[1]));
657 pp[2][0] -= 0.5 * (1-ratio);
658 pp[2][1] -= 0.5 * (1-ratio);
660 glBindTexture (GL_TEXTURE_2D, 0);
661 set_colors_alpha (black_color, 1-ratio);
663 glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLES);
664 do_normal (pp[0][0], pp[0][1], pp[0][2],
665 pp[2][0], pp[2][1], pp[2][2],
666 pp[1][0], pp[1][1], pp[1][2]);
678 if (! wire) glDisable (GL_BLEND);
685 lament_sphere (ModeInfo *mi, GLfloat ratio)
687 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
688 Bool wire = MI_IS_WIREFRAME(mi);
689 GLfloat size = 3; /* 3" square */
691 int facets = 16; /* NxN grid on each face */
693 static const GLfloat norms[6][3] = {{ 0, -1, 0 }, { 0, 0, 1 }, { 0, 1, 0 },
694 { 0, 0, -1 }, { -1, 0, 0 }, { 1, 0, 0 }};
695 GLfloat s = 1.0 / facets;
697 /* The ratio used for the normals: linger on the square normals. */
698 GLfloat ratio2 = 1 - sin ((1 - ratio) / 2 * M_PI);
699 GLfloat r1 = 1 - ratio2 / 2;
700 GLfloat r2 = ratio2 / 2;
703 glTranslatef (-0.5, -0.5, -0.5);
704 glScalef (1/size, 1/size, 1/size);
706 set_colors (exterior_color);
708 for (face = 0; face < 6; face++)
711 for (y0 = 0; y0 < 1; y0 += s)
712 for (x0 = 0; x0 < 1; x0 += s)
717 GLfloat pa[4][3]; /* verts of the cube */
718 GLfloat pb[4][3]; /* verts of the transition to the sphere */
720 GLfloat norm[4][3]; /* normals of the transitional verts */
723 frontp = norms[face][0] < 0,
724 pa[0][1] = x0, pa[0][2] = y0, pa[0][0] = (frontp ? 0 : 1),
725 pa[1][1] = x1, pa[1][2] = y0, pa[1][0] = pa[0][0],
726 pa[2][1] = x1, pa[2][2] = y1, pa[2][0] = pa[0][0],
727 pa[3][1] = x0, pa[3][2] = y1, pa[3][0] = pa[0][0];
728 else if (norms[face][1])
729 frontp = norms[face][1] > 0,
730 pa[0][0] = x0, pa[0][2] = y0, pa[0][1] = (frontp ? 1 : 0),
731 pa[1][0] = x1, pa[1][2] = y0, pa[1][1] = pa[0][1],
732 pa[2][0] = x1, pa[2][2] = y1, pa[2][1] = pa[0][1],
733 pa[3][0] = x0, pa[3][2] = y1, pa[3][1] = pa[0][1];
734 else /* (norms[face][2]) */
735 frontp = norms[face][2] < 0,
736 pa[0][0] = x0, pa[0][1] = y0, pa[0][2] = (frontp ? 0 : 1),
737 pa[1][0] = x1, pa[1][1] = y0, pa[1][2] = pa[0][2],
738 pa[2][0] = x1, pa[2][1] = y1, pa[2][2] = pa[0][2],
739 pa[3][0] = x0, pa[3][1] = y1, pa[3][2] = pa[0][2];
741 for (i = 0; i < countof(pa); i++)
742 pa[i][0] *= size, pa[i][1] *= size, pa[i][2] *= size;
744 /* Convert square to sphere by treating as a normalized vector */
745 for (i = 0; i < countof(pa); i++)
747 GLfloat x = (pa[i][0] / size) - 0.5;
748 GLfloat y = (pa[i][1] / size) - 0.5;
749 GLfloat z = (pa[i][2] / size) - 0.5;
750 GLfloat d = sqrt (x*x + y*y + z*z) / 2;
755 pb[i][0] = pa[i][0] + ((x - pa[i][0]) * ratio);
756 pb[i][1] = pa[i][1] + ((y - pa[i][1]) * ratio);
757 pb[i][2] = pa[i][2] + ((z - pa[i][2]) * ratio);
760 /* The normals of an intermediate point are the weighted average
761 of the cube's orthogonal normals, and the sphere's radial
762 normals: early in the sequence, the edges are sharp, but they
763 soften as it expands. */
765 XYZ na, pa0, pa1, pa2;
766 pa0.x = pa[0][0]; pa0.y = pa[0][1]; pa0.z = pa[0][2];
767 pa1.x = pa[1][0]; pa1.y = pa[1][1]; pa1.z = pa[1][2];
768 pa2.x = pa[2][0]; pa2.y = pa[2][1]; pa2.z = pa[2][2];
769 na = calc_normal (pa0, pa1, pa2);
771 for (i = 0; i < countof(pb); i++)
779 d = sqrt (nb.x*nb.x + nb.y*nb.y + nb.z*nb.z); /* normalize */
784 norm[i][0] = (na.x * r1) + (nb.x * r2); /* weighted */
785 norm[i][1] = (na.y * r1) + (nb.y * r2);
786 norm[i][2] = (na.z * r1) + (nb.z * r2);
791 glBindTexture (GL_TEXTURE_2D, lc->texids[face]);
793 glFrontFace (frontp ? GL_CW : GL_CCW);
794 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
796 texturize_vert (mi, face+1, pa[0]);
797 glNormal3fv (norm[0]);
800 texturize_vert (mi, face+1, pa[1]);
801 glNormal3fv (norm[1]);
804 texturize_vert (mi, face+1, pa[2]);
805 glNormal3fv (norm[2]);
808 texturize_vert (mi, face+1, pa[3]);
809 glNormal3fv (norm[3]);
826 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
827 Bool wire = MI_IS_WIREFRAME(mi);
829 mi->polygon_count = 0;
832 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
834 glClear(GL_COLOR_BUFFER_BIT);
838 gltrackball_rotate (lc->trackball);
840 /* Make into the screen be +Y, right be +X, and up be +Z. */
841 glRotatef (-90.0, 1.0, 0.0, 0.0);
843 scale_for_window (mi);
845 /* Apply rotation to the object. */
846 if (lc->type != LAMENT_LID_ZOOM)
847 get_rotation (lc->rot, &lc->rotx, &lc->roty, &lc->rotz,
852 lc->rotx = lc->roty = 0;
856 glRotatef (lc->rotx * 360, 1, 0, 0);
857 glRotatef (lc->roty * 360, 0, 1, 0);
858 glRotatef (lc->rotz * 360, 0, 0, 1);
860 glScalef (0.5, 0.5, 0.5);
865 glCallList (lc->dlists[OBJ_BOX]);
866 mi->polygon_count += lc->polys[OBJ_BOX];
869 case LAMENT_STAR_OUT:
870 case LAMENT_STAR_ROT:
871 case LAMENT_STAR_ROT_IN:
872 case LAMENT_STAR_ROT_OUT:
873 case LAMENT_STAR_UNROT:
875 glTranslatef (0.0, 0.0, lc->anim_z/2);
876 glRotatef (lc->anim_r/2, 0.0, 0.0, 1.0);
877 glCallList (lc->dlists[OBJ_STAR_U]);
878 mi->polygon_count += lc->polys[OBJ_STAR_U];
880 glTranslatef (0.0, 0.0, -lc->anim_z);
881 glRotatef (-lc->anim_r, 0.0, 0.0, 1.0);
882 glCallList (lc->dlists[OBJ_STAR_D]);
883 mi->polygon_count += lc->polys[OBJ_STAR_D];
886 case LAMENT_TETRA_UNE:
887 case LAMENT_TETRA_USW:
888 case LAMENT_TETRA_DWN:
889 case LAMENT_TETRA_DSE:
894 case LAMENT_TETRA_UNE: magic = OBJ_TETRA_UNE; x= 1; y= 1; z= 1; break;
895 case LAMENT_TETRA_USW: magic = OBJ_TETRA_USW; x= 1; y= 1; z=-1; break;
896 case LAMENT_TETRA_DWN: magic = OBJ_TETRA_DWN; x= 1; y=-1; z= 1; break;
897 case LAMENT_TETRA_DSE: magic = OBJ_TETRA_DSE; x=-1; y= 1; z= 1; break;
898 default: abort(); break;
900 glCallList(lc->dlists[OBJ_TETRA_BASE]);
901 mi->polygon_count += lc->polys[OBJ_TETRA_BASE];
902 if (magic != OBJ_TETRA_UNE) glCallList (lc->dlists[OBJ_TETRA_UNE]);
903 if (magic != OBJ_TETRA_USW) glCallList (lc->dlists[OBJ_TETRA_USW]);
904 if (magic != OBJ_TETRA_DWN) glCallList (lc->dlists[OBJ_TETRA_DWN]);
905 if (magic != OBJ_TETRA_DSE) glCallList (lc->dlists[OBJ_TETRA_DSE]);
906 glRotatef (lc->anim_r, x, y, z);
907 glCallList (lc->dlists[magic]);
908 mi->polygon_count += lc->polys[magic] * 3;
912 case LAMENT_LID_OPEN:
913 case LAMENT_LID_CLOSE:
914 case LAMENT_LID_ZOOM:
918 const int lists[4] = { OBJ_LID_A, OBJ_LID_B, OBJ_LID_C, OBJ_LID_D };
920 lc->facing_p = facing_screen_p (mi);
922 if (lc->anim_z < 0.5)
923 glTranslatef (0, -30 * lc->anim_z, 0); /* zoom */
925 glTranslatef (8 * (0.5 - (lc->anim_z - 0.5)), 0, 0);
927 glCallList (lc->dlists[OBJ_LID_BASE]);
928 mi->polygon_count += lc->polys[OBJ_LID_BASE];
929 for (i = 0; i < countof(lists); i++)
932 glRotatef (90 * i, 0, 1, 0);
933 glTranslatef (-d, -0.5, d);
934 glRotatef (-45, 0, 1, 0);
935 glRotatef (-lc->anim_r, 1, 0, 0);
936 glRotatef (45, 0, 1, 0);
937 glTranslatef (d, 0.5, -d);
938 glRotatef (-90 * i, 0, 1, 0);
939 glCallList (lc->dlists[lists[i]]);
940 mi->polygon_count += lc->polys[lists[i]];
948 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
949 glVertex3f (-0.49, 0.49, -0.49);
950 glVertex3f ( 0.49, 0.49, -0.49);
951 glVertex3f ( 0.49, 0.49, 0.49);
952 glVertex3f (-0.49, 0.49, 0.49);
956 # endif /* DEBUG_MODE */
960 case LAMENT_TASER_OUT:
961 case LAMENT_TASER_SLIDE:
962 case LAMENT_TASER_SLIDE_IN:
963 case LAMENT_TASER_IN:
965 glTranslatef (0, -lc->anim_z/2, 0);
966 glCallList (lc->dlists[OBJ_TASER_BASE]);
967 mi->polygon_count += lc->polys[OBJ_TASER_BASE];
969 glTranslatef (0, lc->anim_z, 0);
970 glCallList (lc->dlists[OBJ_TASER_A]);
971 mi->polygon_count += lc->polys[OBJ_TASER_A];
973 glTranslatef (lc->anim_y, 0, 0);
974 glCallList (lc->dlists[OBJ_TASER_B]);
975 mi->polygon_count += lc->polys[OBJ_TASER_B];
978 case LAMENT_PILLAR_OUT:
979 case LAMENT_PILLAR_SPIN:
980 case LAMENT_PILLAR_IN:
982 glCallList (lc->dlists[OBJ_PILLAR_BASE]);
983 mi->polygon_count += lc->polys[OBJ_PILLAR_BASE];
986 if (lc->anim_z == 1 || lc->anim_z == 3)
988 glRotatef (lc->anim_r, 0, 0, 1);
989 glTranslatef (0, 0, lc->anim_y);
991 glCallList (lc->dlists[OBJ_PILLAR_A]);
992 mi->polygon_count += lc->polys[OBJ_PILLAR_A];
996 if (lc->anim_z == 2 || lc->anim_z == 3)
998 glRotatef (lc->anim_r, 0, 0, 1);
999 glTranslatef (0, 0, -lc->anim_y);
1001 glCallList (lc->dlists[OBJ_PILLAR_B]);
1002 mi->polygon_count += lc->polys[OBJ_PILLAR_B];
1006 case LAMENT_SPHERE_OUT:
1007 case LAMENT_SPHERE_IN:
1008 mi->polygon_count += lament_sphere (mi, lc->anim_y);
1011 case LAMENT_LEVIATHAN_SPIN:
1012 case LAMENT_LEVIATHAN_UNSPIN:
1013 case LAMENT_LEVIATHAN_FADE:
1014 case LAMENT_LEVIATHAN_UNFADE:
1015 case LAMENT_LEVIATHAN_TWIST:
1016 case LAMENT_LEVIATHAN_UNTWIST:
1018 /* These normals are hard to compute, so I pulled them from the
1020 const GLfloat axes[6][4] =
1021 {{ OBJ_ISO_UNE, 0.633994, 0.442836, 0.633994 },
1022 { OBJ_ISO_USW, 0.442836, 0.633994, -0.633994 },
1023 { OBJ_ISO_DSE, -0.633994, 0.633994, 0.442836 },
1024 { OBJ_ISO_SWD, -0.633994, -0.442836, -0.633994 },
1025 { OBJ_ISO_DEN, -0.442836, -0.633994, 0.633994 },
1026 { OBJ_ISO_UNW, 0.633994, -0.633994, -0.442836 }};
1029 GLfloat s = (1 - lc->anim_z);
1030 GLfloat s2 = MAX (0, 360 - lc->anim_r) / 360.0;
1034 case LAMENT_LEVIATHAN_SPIN: break;
1035 case LAMENT_LEVIATHAN_UNSPIN: s2 = 1 - s2; break;
1036 default: s2 = 0; blendp = 1; break;
1039 if (wire) blendp = 0;
1041 s = (s * 0.6) + 0.4;
1043 leviathan (mi, 1 - s2, 1, True);
1044 glCallList (lc->dlists[OBJ_ISO_BASE_A]);
1045 mi->polygon_count += lc->polys[OBJ_ISO_BASE_A];
1048 glScalef (s2, s2, s2);
1049 glCallList (lc->dlists[OBJ_ISO_USE]);
1050 mi->polygon_count += lc->polys[OBJ_ISO_USE];
1054 glRotatef (lc->anim_y, 1, -1, 1);
1055 glCallList (lc->dlists[OBJ_ISO_BASE_B]);
1056 mi->polygon_count += lc->polys[OBJ_ISO_BASE_B];
1057 leviathan (mi, 1 - s2, 1, False);
1062 # ifndef HAVE_JWZGLES /* no glBlendColor */
1063 glEnable (GL_BLEND);
1064 glBlendFunc (GL_CONSTANT_ALPHA, GL_SRC_ALPHA);
1065 glBlendColor (1, 1, 1, MAX(0, 1-(lc->anim_z * 3)));
1069 for (i = 0; i < countof(axes); i++)
1072 glRotatef (lc->anim_r, axes[i][1], axes[i][2], axes[i][3]);
1074 glCallList (lc->dlists[(int) axes[i][0]]);
1075 mi->polygon_count += lc->polys[(int) axes[i][0]];
1078 glRotatef (lc->anim_y, 1, -1, 1);
1081 if (blendp) glDisable (GL_BLEND);
1084 glScalef (s2, s2, s2);
1085 glCallList (lc->dlists[OBJ_ISO_DWN]);
1086 mi->polygon_count += lc->polys[OBJ_ISO_DWN];
1091 case LAMENT_LEVIATHAN_COLLAPSE:
1092 case LAMENT_LEVIATHAN_EXPAND:
1095 leviathan (mi, 1, lc->anim_y, True);
1096 glRotatef (180, 1, -1, 1);
1097 leviathan (mi, 1, lc->anim_y, False);
1099 folding_walls (mi, lc->anim_y, True);
1100 folding_walls (mi, lc->anim_y, False);
1113 /* Rather than just picking states randomly, pick an ordering randomly, do it,
1114 and then re-randomize. That way one can be assured of seeing all states in
1115 a short time period, though not always in the same order (it's frustrating
1116 to see it pick the same state 5x in a row.) Though, that can still happen,
1117 since states are in the list multiple times as a way of giving them
1121 shuffle_states (lament_configuration *lc)
1124 for (i = 0; i < lc->nstates; i++)
1126 int a = random() % lc->nstates;
1127 lament_type swap = lc->states[a];
1128 lc->states[a] = lc->states[i];
1129 lc->states[i] = swap;
1135 animate (ModeInfo *mi)
1137 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1140 GLfloat speed = (lc->ffwdp ? 20 : 1);
1147 if (lc->state >= lc->nstates)
1149 shuffle_states (lc);
1152 lc->type = lc->states[lc->state];
1154 if (lc->type == LAMENT_BOX)
1155 lc->anim_pause = pause2;
1163 /* -------------------------------------------------------------- */
1165 case LAMENT_STAR_OUT:
1166 lc->anim_z += 0.01 * speed;
1167 if (lc->anim_z >= 1.0)
1170 lc->type = LAMENT_STAR_ROT;
1171 lc->anim_pause = pause;
1175 case LAMENT_STAR_ROT:
1176 lc->anim_r += 1.0 * speed;
1177 if (lc->anim_r >= 45.0)
1180 lc->type = LAMENT_STAR_ROT_IN;
1181 lc->anim_pause = pause;
1185 case LAMENT_STAR_ROT_IN:
1186 lc->anim_z -= 0.01 * speed;
1187 if (lc->anim_z <= 0.0)
1190 lc->type = LAMENT_STAR_ROT_OUT;
1191 lc->anim_pause = pause2 * (1 + frand(2) + frand(2));
1195 case LAMENT_STAR_ROT_OUT:
1196 lc->anim_z += 0.01 * speed;
1197 if (lc->anim_z >= 1.0)
1200 lc->type = LAMENT_STAR_UNROT;
1201 lc->anim_pause = pause;
1205 case LAMENT_STAR_UNROT:
1206 lc->anim_r -= 1.0 * speed;
1207 if (lc->anim_r <= 0.0)
1210 lc->type = LAMENT_STAR_IN;
1211 lc->anim_pause = pause;
1215 case LAMENT_STAR_IN:
1216 lc->anim_z -= 0.01 * speed;
1217 if (lc->anim_z <= 0.0)
1220 lc->type = LAMENT_BOX;
1221 lc->anim_pause = pause2;
1225 /* -------------------------------------------------------------- */
1227 case LAMENT_TETRA_UNE:
1228 case LAMENT_TETRA_USW:
1229 case LAMENT_TETRA_DWN:
1230 case LAMENT_TETRA_DSE:
1232 lc->anim_r += 1.0 * speed;
1233 if (lc->anim_r >= 360.0)
1236 lc->type = LAMENT_BOX;
1237 lc->anim_pause = pause2;
1239 else if (lc->anim_r > 119.0 && lc->anim_r <= 120.0)
1242 lc->anim_pause = pause;
1244 else if (lc->anim_r > 239.0 && lc->anim_r <= 240.0)
1247 lc->anim_pause = pause;
1251 /* -------------------------------------------------------------- */
1253 case LAMENT_LID_OPEN:
1254 lc->anim_r += 1.0 * speed;
1256 if (lc->anim_r >= 112.0)
1260 lc->anim_pause = pause2;
1261 lc->type = (lc->facing_p ? LAMENT_LID_ZOOM : LAMENT_LID_CLOSE);
1265 case LAMENT_LID_CLOSE:
1266 lc->anim_r -= 1.0 * speed;
1267 if (lc->anim_r <= 0.0)
1270 lc->type = LAMENT_BOX;
1271 lc->anim_pause = pause2;
1275 case LAMENT_LID_ZOOM:
1276 lc->anim_z += 0.01 * speed;
1277 if (lc->anim_z > 1.0)
1281 lc->type = LAMENT_BOX;
1285 /* -------------------------------------------------------------- */
1287 case LAMENT_TASER_OUT:
1288 lc->anim_z += 0.005 * speed;
1289 if (lc->anim_z >= 0.5)
1292 lc->type = LAMENT_TASER_SLIDE;
1293 lc->anim_pause = pause * (1 + frand(5) + frand(5));
1297 case LAMENT_TASER_SLIDE:
1298 lc->anim_y += 0.005 * speed;
1299 if (lc->anim_y >= 0.255)
1302 lc->type = LAMENT_TASER_SLIDE_IN;
1303 lc->anim_pause = pause2 * (1 + frand(5) + frand(5));
1307 case LAMENT_TASER_SLIDE_IN:
1308 lc->anim_y -= 0.0025 * speed;
1309 if (lc->anim_y <= 0.0)
1312 lc->type = LAMENT_TASER_IN;
1313 lc->anim_pause = pause;
1317 case LAMENT_TASER_IN:
1318 lc->anim_z -= 0.0025 * speed;
1319 if (lc->anim_z <= 0.0)
1322 lc->type = LAMENT_BOX;
1323 lc->anim_pause = pause2;
1327 /* -------------------------------------------------------------- */
1329 case LAMENT_PILLAR_OUT:
1331 if (lc->anim_y == 0) /* mostly in */
1332 lc->anim_y += 0.005 * ((random() % 5) ? -1 : 1) * speed;
1333 else if (lc->anim_y > 0)
1334 lc->anim_y += 0.005 * speed;
1336 lc->anim_y -= 0.001 * speed;
1338 if (lc->anim_z == 0)
1340 int i = (random() % 7); /* A, B or both */
1341 if (i == 0) lc->anim_z = 3;
1342 else if (i < 5) lc->anim_z = 2;
1343 else lc->anim_z = 1;
1345 /* We can do quarter turns, because it's radially symmetrical. */
1346 lc->anim_r = 90.0 * (1 + frand(6)) * RANDSIGN();
1348 if (lc->anim_y > 0.4)
1351 lc->type = LAMENT_PILLAR_SPIN;
1352 lc->anim_pause = pause;
1354 else if (lc->anim_y < -0.03)
1357 lc->type = LAMENT_PILLAR_SPIN;
1358 lc->anim_pause = pause;
1362 case LAMENT_PILLAR_SPIN:
1364 Bool negp = (lc->anim_r < 0);
1365 lc->anim_r += (negp ? 1 : -1) * speed;
1366 if (negp ? lc->anim_r > 0 : lc->anim_r < 0)
1369 lc->type = LAMENT_PILLAR_IN;
1374 case LAMENT_PILLAR_IN:
1376 Bool negp = (lc->anim_y < 0);
1377 lc->anim_y += (negp ? 1 : -1) * 0.005 * speed;
1378 if (negp ? lc->anim_y > 0 : lc->anim_y < 0)
1382 lc->type = LAMENT_BOX;
1383 lc->anim_pause = pause;
1388 /* -------------------------------------------------------------- */
1390 case LAMENT_SPHERE_OUT:
1392 lc->anim_y += 0.01 * speed;
1393 if (lc->anim_y >= 1)
1396 lc->type = LAMENT_SPHERE_IN;
1397 lc->anim_pause = pause2 * (1 + frand(1) + frand(1));
1402 case LAMENT_SPHERE_IN:
1404 lc->anim_y -= 0.01 * speed;
1405 if (lc->anim_y <= 0)
1408 lc->type = LAMENT_BOX;
1409 lc->anim_pause = pause;
1414 /* -------------------------------------------------------------- */
1416 case LAMENT_LEVIATHAN_SPIN:
1417 lc->anim_r += 3.5 * speed;
1418 if (lc->anim_r >= 360 * 3)
1421 lc->type = LAMENT_LEVIATHAN_FADE;
1426 case LAMENT_LEVIATHAN_FADE:
1427 lc->anim_z += 0.01 * speed;
1428 if (lc->anim_z >= 1)
1431 lc->type = LAMENT_LEVIATHAN_TWIST;
1436 case LAMENT_LEVIATHAN_TWIST:
1437 lc->anim_y += 2 * speed;
1439 if (lc->anim_y >= 180)
1442 lc->type = LAMENT_LEVIATHAN_COLLAPSE;
1447 case LAMENT_LEVIATHAN_COLLAPSE:
1448 lc->anim_y += 0.01 * speed;
1449 if (lc->anim_y >= 1)
1452 lc->type = LAMENT_LEVIATHAN_EXPAND;
1453 lc->anim_pause = pause2 * 4;
1457 case LAMENT_LEVIATHAN_EXPAND:
1458 lc->anim_y -= 0.005 * speed;
1459 if (lc->anim_y <= 0)
1462 lc->type = LAMENT_LEVIATHAN_UNTWIST;
1466 case LAMENT_LEVIATHAN_UNTWIST:
1467 lc->anim_y -= 2 * speed;
1469 if (lc->anim_y <= 0)
1472 lc->type = LAMENT_LEVIATHAN_UNFADE;
1477 case LAMENT_LEVIATHAN_UNFADE:
1478 lc->anim_z -= 0.1 * speed;
1479 if (lc->anim_z <= 0)
1482 lc->type = LAMENT_LEVIATHAN_UNSPIN;
1487 case LAMENT_LEVIATHAN_UNSPIN:
1488 lc->anim_r += 3.5 * speed;
1489 if (lc->anim_r >= 360 * 2)
1492 lc->type = LAMENT_BOX;
1493 lc->anim_pause = pause2;
1506 if (lc->type == LAMENT_BOX)
1507 lc->type = DEBUG_MODE;
1512 while (lc->type != DEBUG_MODE)
1516 # else /* !DEBUG_MODE */
1518 if (lc->ffwdp && lc->type == LAMENT_BOX)
1521 while (lc->type == LAMENT_BOX)
1526 # endif /* !DEBUG_MODE */
1531 gl_init (ModeInfo *mi)
1533 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1534 Bool wire = MI_IS_WIREFRAME(mi);
1542 static const GLfloat pos0[] = { -4.0, 2.0, 5.0, 1.0 };
1543 static const GLfloat pos1[] = { 6.0, -1.0, 3.0, 1.0 };
1545 static const GLfloat amb0[] = { 0.7, 0.7, 0.7, 1.0 };
1546 /* static const GLfloat amb1[] = { 0.7, 0.0, 0.0, 1.0 }; */
1547 static const GLfloat dif0[] = { 1.0, 1.0, 1.0, 1.0 };
1548 static const GLfloat dif1[] = { 0.3, 0.1, 0.1, 1.0 };
1550 glLightfv(GL_LIGHT0, GL_POSITION, pos0);
1551 glLightfv(GL_LIGHT1, GL_POSITION, pos1);
1553 glLightfv(GL_LIGHT0, GL_AMBIENT, amb0);
1554 /* glLightfv(GL_LIGHT1, GL_AMBIENT, amb1); */
1555 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif0);
1556 glLightfv(GL_LIGHT1, GL_DIFFUSE, dif1);
1558 glEnable(GL_LIGHTING);
1559 glEnable(GL_LIGHT0);
1560 /* glEnable(GL_LIGHT1); */
1562 glEnable(GL_DEPTH_TEST);
1563 glEnable(GL_TEXTURE_2D);
1564 glEnable(GL_NORMALIZE);
1565 glEnable(GL_CULL_FACE);
1571 for (i = 0; i < countof(lc->texids); i++)
1572 glGenTextures(1, &lc->texids[i]);
1574 lc->texture = xpm_to_ximage (mi->dpy,
1579 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
1580 /* messes up -fps */
1581 /* glPixelStorei(GL_UNPACK_ROW_LENGTH, lc->texture->width); */
1583 for (i = 0; i < countof(lc->texids); i++)
1585 int height = lc->texture->width; /* assume square */
1586 glBindTexture(GL_TEXTURE_2D, lc->texids[i]);
1589 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
1590 lc->texture->width, height, 0,
1592 /* GL_UNSIGNED_BYTE, */
1593 GL_UNSIGNED_INT_8_8_8_8_REV,
1594 (lc->texture->data +
1595 (lc->texture->bytes_per_line * height * i)));
1596 check_gl_error("texture");
1598 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
1599 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
1600 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
1601 glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
1602 check_gl_error("texture");
1604 /* This makes scaled pixmaps tolerable to look at. */
1605 # if !defined(GL_TEXTURE_LOD_BIAS) && defined(GL_TEXTURE_LOD_BIAS_EXT)
1606 # define GL_TEXTURE_LOD_BIAS GL_TEXTURE_LOD_BIAS_EXT
1608 # ifdef GL_TEXTURE_LOD_BIAS
1609 glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, 0.25);
1611 clear_gl_error(); /* invalid enum on iPad 3 */
1615 for (i = 0; i < countof(all_objs); i++)
1617 GLfloat s = 1/3.0; /* box is 3" square */
1618 const struct gllist *L = *all_objs[i];
1619 const GLfloat *f = (const GLfloat *) L->data;
1622 lc->dlists[i] = glGenLists(1);
1623 lc->polys[i] = L->points / 3;
1624 glNewList(lc->dlists[i], GL_COMPILE);
1625 if (L->primitive != GL_TRIANGLES) abort();
1626 if (L->format != GL_N3F_V3F) abort();
1629 glTranslatef (-0.5, -0.5, -0.5);
1632 for (j = 0; j < L->points; j += 3)
1635 Bool blackp = (i == OBJ_ISO_BASE_A || i == OBJ_ISO_BASE_B);
1636 which_face (mi, f, &face, &outerp); /* from norm of first vert */
1638 set_colors (outerp ? exterior_color :
1639 blackp ? black_color : interior_color);
1640 glBindTexture (GL_TEXTURE_2D,
1641 (outerp ? lc->texids[face-1] :
1642 blackp ? 0 : lc->texids[6]));
1644 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
1645 if (face) texturize_vert (mi, face, f+3);
1646 glNormal3fv (f); f += 3; glVertex3fv (f); f += 3;
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;
1661 lament_handle_event (ModeInfo *mi, XEvent *event)
1663 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1665 if (gltrackball_event_handler (event, lc->trackball,
1666 MI_WIDTH (mi), MI_HEIGHT (mi),
1667 &lc->button_down_p))
1669 else if (event->xany.type == KeyPress)
1673 XLookupString (&event->xkey, &c, 1, &keysym, 0);
1674 if (c == ' ' || c == '\t')
1686 reshape_lament (ModeInfo *mi, int width, int height)
1688 GLfloat h = (GLfloat) height / (GLfloat) width;
1689 glViewport(0, 0, (GLint) width, (GLint) height);
1691 glMatrixMode(GL_PROJECTION);
1693 glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
1694 glMatrixMode(GL_MODELVIEW);
1696 glTranslatef(0.0, 0.0, -40.0);
1697 glClear(GL_COLOR_BUFFER_BIT);
1702 init_lament (ModeInfo *mi)
1704 lament_configuration *lc;
1708 lcs = (lament_configuration *)
1709 calloc(MI_NUM_SCREENS(mi), sizeof (lament_configuration));
1712 fprintf(stderr, "%s: out of memory\n", progname);
1717 lc = &lcs[MI_SCREEN(mi)];
1720 double rot_speed = 0.5;
1721 lc->rot = make_rotator (rot_speed, rot_speed, rot_speed, 1, 0, True);
1722 lc->trackball = gltrackball_init (True);
1725 lc->type = LAMENT_BOX;
1726 lc->anim_pause = 300 + (random() % 100);
1728 if ((lc->glx_context = init_GL(mi)) != NULL)
1730 reshape_lament(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
1734 lc->states = (lament_type *) calloc (200, sizeof (*lc->states));
1737 # define PUSH(N,WHICH) \
1738 for (i = 0; i < N; i++) lc->states[lc->nstates++] = WHICH
1740 PUSH (4, LAMENT_TETRA_UNE); /* most common */
1741 PUSH (4, LAMENT_TETRA_USW);
1742 PUSH (4, LAMENT_TETRA_DWN);
1743 PUSH (4, LAMENT_TETRA_DSE);
1745 PUSH (8, LAMENT_STAR_OUT); /* pretty common */
1746 PUSH (8, LAMENT_TASER_OUT);
1747 PUSH (8, LAMENT_PILLAR_OUT);
1749 PUSH (4, LAMENT_LID_OPEN); /* rare */
1750 PUSH (2, LAMENT_SPHERE_OUT); /* rare */
1751 PUSH (1, LAMENT_LEVIATHAN_SPIN); /* very rare */
1753 PUSH (35, LAMENT_BOX); /* rest state */
1756 shuffle_states (lc);
1759 lc->type = DEBUG_MODE;
1767 draw_lament (ModeInfo *mi)
1769 lament_configuration *lc = &lcs[MI_SCREEN(mi)];
1770 Display *dpy = MI_DISPLAY(mi);
1771 Window window = MI_WINDOW(mi);
1773 if (!lc->glx_context)
1776 glDrawBuffer(GL_BACK);
1778 glXMakeCurrent(dpy, window, *(lc->glx_context));
1780 if (mi->fps_p) do_fps (mi);
1783 glXSwapBuffers(dpy, window);
1785 if (!lc->ffwdp && lc->anim_pause)
1791 XSCREENSAVER_MODULE ("Lament", lament)