1 /* dymaxionmap --- Buckminster Fuller's unwrapped icosahedral globe.
2 * Copyright (c) 2016 Jamie Zawinski.
4 * Permission to use, copy, modify, and distribute this software and its
5 * documentation for any purpose and without fee is hereby granted,
6 * provided that the above copyright notice appear in all copies and that
7 * both that copyright notice and this permission notice appear in
8 * supporting documentation.
10 * This file is provided AS IS with no warranties of any kind. The author
11 * shall have no liability with respect to the infringement of copyrights,
12 * trade secrets or any patents by this file or any part thereof. In no
13 * event will the author be liable for any lost revenue or profits or
14 * other special, indirect and consequential damages.
17 #define LABEL_FONT "-*-helvetica-bold-r-normal-*-*-240-*-*-*-*-*-*"
20 #define DEFAULTS "*delay: 20000 \n" \
21 "*showFPS: False \n" \
22 "*wireframe: False \n" \
23 "*labelFont: " LABEL_FONT "\n"
24 # define refresh_planet 0
25 # include "xlockmore.h" /* from the xscreensaver distribution */
26 #else /* !STANDALONE */
27 # include "xlock.h" /* from the xlockmore distribution */
28 #endif /* !STANDALONE */
30 #ifdef USE_GL /* whole file */
38 # include <X11/Xmu/Drawing.h>
40 # include <Xmu/Drawing.h>
44 #define DEF_ROTATE "True"
45 #define DEF_ROLL "True"
46 #define DEF_WANDER "True"
47 #define DEF_TEXTURE "True"
48 #define DEF_STARS "True"
49 #define DEF_SPEED "1.0"
50 #define DEF_IMAGE "BUILTIN"
53 #define countof(x) (sizeof((x))/sizeof((*x)))
56 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
60 static int do_texture;
63 static char *which_image;
65 static XrmOptionDescRec opts[] = {
66 {"-speed", ".dymaxionmap.speed", XrmoptionSepArg, 0 },
67 {"-roll", ".dymaxionmap.roll", XrmoptionNoArg, "true" },
68 {"+roll", ".dymaxionmap.roll", XrmoptionNoArg, "false" },
69 {"-wander", ".dymaxionmap.wander", XrmoptionNoArg, "true" },
70 {"+wander", ".dymaxionmap.wander", XrmoptionNoArg, "false" },
71 {"-texture", ".dymaxionmap.texture", XrmoptionNoArg, "true" },
72 {"+texture", ".dymaxionmap.texture", XrmoptionNoArg, "false" },
73 {"-stars", ".dymaxionmap.stars", XrmoptionNoArg, "true" },
74 {"+stars", ".dymaxionmap.stars", XrmoptionNoArg, "false" },
75 {"-image", ".dymaxionmap.image", XrmoptionSepArg, 0 },
78 static argtype vars[] = {
79 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
80 {&do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
81 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
82 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
83 {&do_stars, "stars", "Stars", DEF_STARS, t_Bool},
84 {&which_image, "image", "Image", DEF_IMAGE, t_String},
87 ENTRYPOINT ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
90 ModStruct planet_description =
91 {"planet", "init_planet", "draw_planet", "release_planet",
92 "draw_planet", "init_planet", NULL, &planet_opts,
93 1000, 1, 2, 1, 4, 1.0, "",
94 "Buckminster Fuller's unwrapped icosahedral globe", 0, NULL};
98 __extension__ /* don't warn about "string length is greater than the length
99 ISO C89 compilers are required to support" when including
100 the following XPM file... */
102 #include "../images/dymaxionmap.xpm"
103 #include "../images/ground.xpm"
105 #include "xpm-ximage.h"
107 #include "gltrackball.h"
111 GLXContext *glx_context;
115 trackball_state *trackball;
117 enum { STARTUP, FLAT, FOLD,
118 ICO, STEL_IN, AXIS, SPIN, STEL, STEL_OUT,
119 ICO2, UNFOLD } state;
122 texture_font_data *font_data;
126 static planetstruct *planets = NULL;
129 /* Set up and enable texturing on our object */
131 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
133 XImage *image = xpm_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
134 MI_COLORMAP (mi), xpm_data);
137 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
139 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
141 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
142 image->width, image->height, 0,
144 /* GL_UNSIGNED_BYTE, */
145 GL_UNSIGNED_INT_8_8_8_8_REV,
147 sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
153 setup_file_texture (ModeInfo *mi, char *filename)
155 Display *dpy = mi->dpy;
156 Visual *visual = mi->xgwa.visual;
159 Colormap cmap = mi->xgwa.colormap;
160 XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
161 if (!image) return False;
164 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
165 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
166 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
167 image->width, image->height, 0,
169 /* GL_UNSIGNED_BYTE, */
170 GL_UNSIGNED_INT_8_8_8_8_REV,
172 sprintf (buf, "texture: %.100s (%dx%d)",
173 filename, image->width, image->height);
180 setup_texture(ModeInfo * mi)
182 planetstruct *gp = &planets[MI_SCREEN(mi)];
184 glGenTextures (1, &gp->tex1);
185 glBindTexture (GL_TEXTURE_2D, gp->tex1);
187 /* Must be after glBindTexture */
188 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
189 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
190 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
191 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
192 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
196 !strcmp(which_image, "BUILTIN"))
199 setup_xpm_texture (mi, dymaxionmap_xpm);
203 if (! setup_file_texture (mi, which_image))
207 glGenTextures (1, &gp->tex2);
208 glBindTexture (GL_TEXTURE_2D, gp->tex2);
210 /* Must be after glBindTexture */
211 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
212 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
213 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
214 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
215 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
217 setup_xpm_texture (mi, ground);
219 check_gl_error("texture initialization");
221 /* Need to flip the texture top for bottom for some reason. */
222 glMatrixMode (GL_TEXTURE);
224 glMatrixMode (GL_MODELVIEW);
229 init_stars (ModeInfo *mi)
231 planetstruct *gp = &planets[MI_SCREEN(mi)];
233 int width = MI_WIDTH(mi);
234 int height = MI_HEIGHT(mi);
235 int size = (width > height ? width : height);
236 int nstars = size * size / 80;
239 int steps = max_size / inc;
241 gp->starlist = glGenLists(1);
242 glNewList(gp->starlist, GL_COMPILE);
243 for (j = 1; j <= steps; j++)
245 glPointSize(inc * j);
247 for (i = 0; i < nstars / steps; i++)
250 GLfloat r = 0.15 + frand(0.3);
251 GLfloat g = r + frand(d) - d;
252 GLfloat b = r + frand(d) - d;
254 GLfloat x = frand(1)-0.5;
255 GLfloat y = frand(1)-0.5;
256 GLfloat z = ((random() & 1)
258 : (BELLRAND(1)-0.5)/12); /* milky way */
259 d = sqrt (x*x + y*y + z*z);
264 glVertex3f (x, y, z);
271 check_gl_error("stars initialization");
276 reshape_planet (ModeInfo *mi, int width, int height)
278 GLfloat h = (GLfloat) height / (GLfloat) width;
280 glViewport(0, 0, (GLint) width, (GLint) height);
281 glMatrixMode(GL_PROJECTION);
283 glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
284 glMatrixMode(GL_MODELVIEW);
286 glTranslatef(0.0, 0.0, -40);
288 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
290 int o = (int) current_device_rotation();
291 if (o != 0 && o != 180 && o != -180)
296 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
301 do_normal2 (Bool frontp, XYZ a, XYZ b, XYZ c)
304 do_normal (a.x, a.y, a.z,
308 do_normal (b.x, b.y, b.z,
315 triangle0 (ModeInfo *mi, Bool frontp, GLfloat stel_ratio, int bitmask)
317 /* Render a triangle as six sub-triangles:
330 B ----------------------- C
334 Bool wire = MI_IS_WIREFRAME(mi);
335 GLfloat h = sqrt(3) / 2;
336 GLfloat h2 = sqrt(h*h - (h/2)*(h/2)) - 0.5;
337 XYZ A, B, C, D, E, F, G;
338 XYZ tA, tB, tC, tD, tE, tF, tG;
341 A.x = 0; A.y = h; A.z = 0;
342 B.x = -0.5, B.y = 0; B.z = 0;
343 C.x = 0.5, C.y = 0; C.z = 0;
344 D.x = 0; D.y = h/3; D.z = 0;
345 E.x = -h2; E.y = h/2; E.z = 0;
346 F.x = h2; F.y = h/2; F.z = 0;
347 G.x = 0; G.y = 0; G.z = 0;
349 /* When tweaking object XY to stellate, don't change texture coordinates. */
350 tA = A; tB = B; tC = C; tD = D; tE = E; tF = F; tG = G;
352 /* Eyeballed this to find the depth of stellation that seems to most
353 approximate a sphere.
355 D.z = 0.193 * stel_ratio;
357 /* We want to raise E, F and G as well but we can't just shift Z:
358 we need to keep them on the same vector from the center of the sphere,
359 which means also changing F and G's X and Y.
361 E.z = F.z = G.z = 0.132 * stel_ratio;
363 double magic_x = 0.044;
364 double magic_y = 0.028;
366 G.y -= sqrt (magic_x*magic_x + magic_y*magic_y) * stel_ratio;
367 E.x -= magic_x * stel_ratio;
368 E.y += magic_y * stel_ratio;
369 F.x += magic_x * stel_ratio;
370 F.y += magic_y * stel_ratio;
376 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
378 ta = tE; tb = tD; tc = tA;
379 do_normal2 (frontp, a, b, c);
380 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
381 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
382 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
388 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
390 ta = tD; tb = tF; tc = tA;
391 do_normal2 (frontp, a, b, c);
392 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
393 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
394 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
400 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
402 ta = tD; tb = tC; tc = tF;
403 do_normal2 (frontp, a, b, c);
404 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
405 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
406 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
412 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
414 ta = tG; tb = tC; tc = tD;
415 do_normal2 (frontp, a, b, c);
416 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
417 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
418 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
424 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
426 ta = tB; tb = tG; tc = tD;
427 do_normal2 (frontp, a, b, c);
428 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
429 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
430 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
436 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
438 ta = tB; tb = tD; tc = tE;
439 do_normal2 (frontp, a, b, c);
440 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
441 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
442 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
448 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
450 ta = tE; tb = tD; tc = tA;
451 do_normal2 (frontp, a, b, c);
452 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
453 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
454 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
461 /* The segments, numbered arbitrarily from the top left:
464 \ 0 / \ / \3> | \ 5 /
465 \ / 1 \ / 2 \| ..|4 \ /-6-..
466 ___________\/______\/______\/______\/______\
468 |7 / \ 9 / \ 11 / \ 13 / \ 15 / \
469 | / 8 \ / 10 \ / 12 \ / 14 \ / 16 \
470 |/______\/______\/______\/______\/______\
472 \ 17 / \ 18 / / \ 20 / \
473 \ / \ / / 19 \ / 21 \
474 \/ \/ /______\/______\
476 Each triangle can be connected to at most two other triangles.
477 We start from the middle, #12, and work our way to the edges.
481 triangle (ModeInfo *mi, int which, Bool frontp,
482 GLfloat fold_ratio, GLfloat stel_ratio)
484 planetstruct *gp = &planets[MI_SCREEN(mi)];
485 const GLfloat fg[3] = { 1, 1, 1 };
486 const GLfloat bg[3] = { 0.3, 0.3, 0.3 };
488 GLfloat max = acos (sqrt(5)/3);
489 GLfloat rot = -max * fold_ratio / (M_PI/180);
490 Bool wire = MI_IS_WIREFRAME(mi);
496 case 3: /* One third of the face. */
497 triangle0 (mi, frontp, stel_ratio, 1<<3 | 1<<4);
499 case 4: /* Two thirds of the face: convex. */
500 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3 | 1<<4);
502 case 6: /* One half of the face. */
503 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3);
505 case 7: /* One half of the face. */
506 triangle0 (mi, frontp, stel_ratio, 1<<2 | 1<<3 | 1<<4);
508 default: /* Full face. */
509 triangle0 (mi, frontp, stel_ratio, 0x3F);
517 sprintf (tag, "%d", which);
519 glTranslatef (-0.1, 0.2, 0);
520 glScalef (0.005, 0.005, 0.005);
521 print_texture_string (gp->font_data, tag);
527 /* The connection hierarchy of the faces starting at the middle, #12. */
530 case 1: a = 0; b = -1; break;
531 case 2: a = -1; b = 3; break;
533 case 4: a = -1; b = 5; break;
534 case 5: a = -1; b = 6; break;
537 case 8: a = 17; b = 7; break;
538 case 9: a = 8; b = -1; break;
539 case 10: a = 18; b = 9; break;
540 case 11: a = 10; b = 1; break;
541 case 12: a = 11; b = 13; break;
542 case 13: a = 2; b = 14; break;
543 case 14: a = 15; b = 20; break;
544 case 15: a = 4; b = 16; break;
549 case 20: a = 21; b = 19; break;
551 default: abort(); break;
557 glTranslatef (-0.5, 0, 0); /* Move model matrix to upper left */
558 glRotatef (60, 0, 0, 1);
559 glTranslatef ( 0.5, 0, 0);
561 glMatrixMode(GL_TEXTURE);
562 /* glPushMatrix(); */
563 glTranslatef (-0.5, 0, 0); /* Move texture matrix the same way */
564 glRotatef (60, 0, 0, 1);
565 glTranslatef ( 0.5, 0, 0);
567 glMatrixMode(GL_MODELVIEW);
569 glRotatef (rot, 1, 0, 0);
570 triangle (mi, a, frontp, fold_ratio, stel_ratio);
572 /* This should just be a PopMatrix on the TEXTURE stack, but
573 fucking iOS has GL_MAX_TEXTURE_STACK_DEPTH == 4! WTF!
574 So we have to undo our rotations and translations manually.
576 glMatrixMode(GL_TEXTURE);
578 glTranslatef (-0.5, 0, 0);
579 glRotatef (-60, 0, 0, 1);
580 glTranslatef (0.5, 0, 0);
582 glMatrixMode(GL_MODELVIEW);
589 glTranslatef (0.5, 0, 0); /* Move model matrix to upper right */
590 glRotatef (-60, 0, 0, 1);
591 glTranslatef (-0.5, 0, 0);
593 glMatrixMode(GL_TEXTURE);
594 /* glPushMatrix(); */
595 glTranslatef (0.5, 0, 0); /* Move texture matrix the same way */
596 glRotatef (-60, 0, 0, 1);
597 glTranslatef (-0.5, 0, 0);
599 glMatrixMode(GL_MODELVIEW);
601 glRotatef (rot, 1, 0, 0);
602 triangle (mi, b, frontp, fold_ratio, stel_ratio);
604 /* See above. Grr. */
605 glMatrixMode(GL_TEXTURE);
607 glTranslatef (0.5, 0, 0);
608 glRotatef (60, 0, 0, 1);
609 glTranslatef (-0.5, 0, 0);
611 glMatrixMode(GL_MODELVIEW);
618 draw_triangles (ModeInfo *mi, GLfloat fold_ratio, GLfloat stel_ratio)
620 planetstruct *gp = &planets[MI_SCREEN(mi)];
621 Bool wire = MI_IS_WIREFRAME(mi);
622 GLfloat h = sqrt(3) / 2;
625 glTranslatef (0, -h/3, 0); /* Center on face 12 */
627 /* When closed, center on midpoint of icosahedron. Eyeballed this. */
628 glTranslatef (0, 0, fold_ratio * 0.754);
630 glFrontFace (GL_CCW);
632 /* Adjust the texture matrix so that it has the same coordinate space
635 glMatrixMode(GL_TEXTURE);
639 GLfloat texh = 3 * h;
641 GLfloat midy = 3 * c;
642 glScalef (1/texw, -1/texh, 1);
643 glTranslatef (midx, midy, 0);
645 glMatrixMode(GL_MODELVIEW);
652 glDisable (GL_TEXTURE_2D);
655 glEnable (GL_TEXTURE_2D);
656 glBindTexture (GL_TEXTURE_2D, gp->tex1);
659 glDisable (GL_TEXTURE_2D);
661 triangle (mi, 12, True, fold_ratio, stel_ratio);
666 glDisable (GL_TEXTURE_2D);
669 glEnable (GL_TEXTURE_2D);
670 glBindTexture (GL_TEXTURE_2D, gp->tex2);
673 glDisable (GL_TEXTURE_2D);
677 triangle (mi, 12, False, fold_ratio, 0);
679 glMatrixMode(GL_TEXTURE);
681 glMatrixMode(GL_MODELVIEW);
686 align_axis (ModeInfo *mi, int undo)
688 /* Rotate so that an axis is lined up with the north and south poles
689 on the map, which are not in the center of their faces, or any
690 other easily computable spot. */
697 glRotatef (-r2, 0, 1, 0);
698 glRotatef ( r2, 1, 0, 0);
699 glRotatef (-r1, 1, 0, 0);
703 glRotatef (r1, 1, 0, 0);
704 glRotatef (-r2, 1, 0, 0);
705 glRotatef ( r2, 0, 1, 0);
711 draw_axis (ModeInfo *mi)
714 glDisable (GL_TEXTURE_2D);
715 glDisable (GL_LIGHTING);
719 glTranslatef (0.34, 0.39, -0.61);
722 glScalef (s, s, s); /* tighten up the enclosing sphere */
724 glColor3f (0.5, 0.5, 0);
726 glRotatef (90, 1, 0, 0); /* unit_sphere is off by 90 */
727 glRotatef (9.5, 0, 1, 0); /* line up the time zones */
728 glFrontFace (GL_CCW);
729 unit_sphere (12, 24, True);
731 glVertex3f(0, -2, 0);
742 planet_handle_event (ModeInfo *mi, XEvent *event)
744 planetstruct *gp = &planets[MI_SCREEN(mi)];
746 if (gltrackball_event_handler (event, gp->trackball,
747 MI_WIDTH (mi), MI_HEIGHT (mi),
750 else if (event->xany.type == KeyPress)
754 XLookupString (&event->xkey, &c, 1, &keysym, 0);
755 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
758 case FLAT: case ICO: case STEL: case AXIS: case ICO2:
773 init_planet (ModeInfo * mi)
776 int screen = MI_SCREEN(mi);
777 Bool wire = MI_IS_WIREFRAME(mi);
779 if (planets == NULL) {
780 if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
781 sizeof (planetstruct))) == NULL)
784 gp = &planets[screen];
786 if ((gp->glx_context = init_GL(mi)) != NULL) {
787 reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
792 gp->font_data = load_texture_font (mi->dpy, "labelFont");
795 double spin_speed = 0.1;
796 double wander_speed = 0.002;
797 gp->rot = make_rotator (do_roll ? spin_speed : 0,
798 do_roll ? spin_speed : 0,
800 do_wander ? wander_speed : 0,
802 gp->trackball = gltrackball_init (True);
814 glEnable (GL_DEPTH_TEST);
815 glEnable (GL_NORMALIZE);
816 glEnable (GL_CULL_FACE);
820 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
821 GLfloat amb[4] = {0.4, 0.4, 0.4, 1.0};
822 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
823 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
825 glEnable(GL_LIGHTING);
827 glLightfv(GL_LIGHT0, GL_POSITION, pos);
828 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
829 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
830 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
838 return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */
843 ease_ratio (GLfloat r)
846 if (r <= 0) return 0;
847 else if (r >= 1) return 1;
848 else if (r <= ease) return ease * ease_fn (r / ease);
849 else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease);
855 draw_planet (ModeInfo * mi)
857 planetstruct *gp = &planets[MI_SCREEN(mi)];
858 int wire = MI_IS_WIREFRAME(mi);
859 Display *dpy = MI_DISPLAY(mi);
860 Window window = MI_WINDOW(mi);
863 if (!gp->glx_context)
866 glDrawBuffer(GL_BACK);
867 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
869 glXMakeCurrent (dpy, window, *(gp->glx_context));
871 mi->polygon_count = 0;
873 if (! gp->button_down_p)
875 case STARTUP: gp->ratio += speed * 0.01; break;
876 case FLAT: gp->ratio += speed * 0.005; break;
877 case FOLD: gp->ratio += speed * 0.01; break;
878 case ICO: gp->ratio += speed * 0.01; break;
879 case STEL_IN: gp->ratio += speed * 0.05; break;
880 case STEL: gp->ratio += speed * 0.01; break;
881 case STEL_OUT: gp->ratio += speed * 0.07; break;
882 case ICO2: gp->ratio += speed * 0.07; break;
883 case AXIS: gp->ratio += speed * 0.02; break;
884 case SPIN: gp->ratio += speed * 0.005; break;
885 case UNFOLD: gp->ratio += speed * 0.01; break;
893 case STARTUP: gp->state = FLAT; break;
894 case FLAT: gp->state = FOLD; break;
895 case FOLD: gp->state = ICO; break;
896 case ICO: gp->state = STEL_IN; break;
897 case STEL_IN: gp->state = STEL; break;
900 int i = (random() << 9) % 7;
901 gp->state = (i < 3 ? STEL_OUT :
902 i < 6 ? SPIN : AXIS);
905 case AXIS: gp->state = STEL_OUT; break;
906 case SPIN: gp->state = STEL_OUT; break;
907 case STEL_OUT: gp->state = ICO2; break;
908 case ICO2: gp->state = UNFOLD; break;
909 case UNFOLD: gp->state = FLAT; break;
914 glEnable(GL_LINE_SMOOTH);
915 glEnable(GL_POINT_SMOOTH);
916 glEnable(GL_DEPTH_TEST);
917 glEnable(GL_CULL_FACE);
922 gltrackball_rotate (gp->trackball);
923 glRotatef (current_device_rotation(), 0, 0, 1);
925 if (gp->state != STARTUP)
927 get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
931 glTranslatef(x, y, z);
934 if (do_roll && gp->state != STARTUP)
936 get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
937 glRotatef (x * 360, 1.0, 0.0, 0.0);
938 glRotatef (y * 360, 0.0, 1.0, 0.0);
943 glDisable(GL_TEXTURE_2D);
944 glDisable(GL_LIGHTING);
946 glScalef (60, 60, 60);
947 glRotatef (90, 1, 0, 0);
948 glRotatef (35, 1, 0, 0);
949 glCallList (gp->starlist);
950 mi->polygon_count += gp->starcount;
952 glClear(GL_DEPTH_BUFFER_BIT);
956 glEnable (GL_LIGHTING);
959 glEnable(GL_TEXTURE_2D);
961 glScalef (2.6, 2.6, 2.6);
964 GLfloat fold_ratio = 0;
965 GLfloat stel_ratio = 0;
967 case FOLD: fold_ratio = gp->ratio; break;
968 case UNFOLD: fold_ratio = 1 - gp->ratio; break;
969 case ICO: case ICO2: fold_ratio = 1; break;
970 case STEL: case AXIS: case SPIN: fold_ratio = 1; stel_ratio = 1; break;
971 case STEL_IN: fold_ratio = 1; stel_ratio = gp->ratio; break;
972 case STEL_OUT: fold_ratio = 1; stel_ratio = 1 - gp->ratio; break;
973 case STARTUP: /* Tilt in from flat */
974 glRotatef (-90 * ease_ratio (1 - gp->ratio), 1, 0, 0);
980 # ifdef HAVE_MOBILE /* Enlarge the icosahedron a bit to make it more visible */
982 GLfloat s = 1 + 1.3 * ease_ratio (fold_ratio);
987 if (gp->state == SPIN)
990 glRotatef (ease_ratio (gp->ratio) * 360 * 3, 0, 0, 1);
994 draw_triangles (mi, ease_ratio (fold_ratio), ease_ratio (stel_ratio));
996 if (gp->state == AXIS)
1002 if (mi->fps_p) do_fps (mi);
1004 glXSwapBuffers(dpy, window);
1009 release_planet (ModeInfo * mi)
1011 if (planets != NULL) {
1014 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1015 planetstruct *gp = &planets[screen];
1017 if (gp->glx_context) {
1018 /* Display lists MUST be freed while their glXContext is current. */
1019 /* but this gets a BadMatch error. -jwz */
1020 /*glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));*/
1022 if (glIsList(gp->starlist))
1023 glDeleteLists(gp->starlist, 1);
1026 (void) free((void *) planets);
1033 XSCREENSAVER_MODULE_2 ("DymaxionMap", dymaxionmap, planet)