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 # define release_planet 0
26 # include "xlockmore.h" /* from the xscreensaver distribution */
27 #else /* !STANDALONE */
28 # include "xlock.h" /* from the xlockmore distribution */
29 #endif /* !STANDALONE */
31 #ifdef USE_GL /* whole file */
39 # include <X11/Xmu/Drawing.h>
41 # include <Xmu/Drawing.h>
45 #define DEF_ROTATE "True"
46 #define DEF_ROLL "True"
47 #define DEF_WANDER "True"
48 #define DEF_TEXTURE "True"
49 #define DEF_STARS "True"
50 #define DEF_SPEED "1.0"
51 #define DEF_IMAGE "BUILTIN"
54 #define countof(x) (sizeof((x))/sizeof((*x)))
57 #define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
61 static int do_texture;
64 static char *which_image;
66 static XrmOptionDescRec opts[] = {
67 {"-speed", ".dymaxionmap.speed", XrmoptionSepArg, 0 },
68 {"-roll", ".dymaxionmap.roll", XrmoptionNoArg, "true" },
69 {"+roll", ".dymaxionmap.roll", XrmoptionNoArg, "false" },
70 {"-wander", ".dymaxionmap.wander", XrmoptionNoArg, "true" },
71 {"+wander", ".dymaxionmap.wander", XrmoptionNoArg, "false" },
72 {"-texture", ".dymaxionmap.texture", XrmoptionNoArg, "true" },
73 {"+texture", ".dymaxionmap.texture", XrmoptionNoArg, "false" },
74 {"-stars", ".dymaxionmap.stars", XrmoptionNoArg, "true" },
75 {"+stars", ".dymaxionmap.stars", XrmoptionNoArg, "false" },
76 {"-image", ".dymaxionmap.image", XrmoptionSepArg, 0 },
79 static argtype vars[] = {
80 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
81 {&do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
82 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
83 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
84 {&do_stars, "stars", "Stars", DEF_STARS, t_Bool},
85 {&which_image, "image", "Image", DEF_IMAGE, t_String},
88 ENTRYPOINT ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
91 ModStruct planet_description =
92 {"planet", "init_planet", "draw_planet", NULL,
93 "draw_planet", "init_planet", NULL, &planet_opts,
94 1000, 1, 2, 1, 4, 1.0, "",
95 "Buckminster Fuller's unwrapped icosahedral globe", 0, NULL};
99 __extension__ /* don't warn about "string length is greater than the length
100 ISO C89 compilers are required to support" when including
101 the following XPM file... */
103 #include "../images/dymaxionmap.xpm"
104 #include "../images/ground.xpm"
106 #include "xpm-ximage.h"
108 #include "gltrackball.h"
112 GLXContext *glx_context;
116 trackball_state *trackball;
118 enum { STARTUP, FLAT, FOLD,
119 ICO, STEL_IN, AXIS, SPIN, STEL, STEL_OUT,
120 ICO2, UNFOLD } state;
123 texture_font_data *font_data;
127 static planetstruct *planets = NULL;
130 /* Set up and enable texturing on our object */
132 setup_xpm_texture (ModeInfo *mi, char **xpm_data)
134 XImage *image = xpm_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
135 MI_COLORMAP (mi), xpm_data);
138 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
140 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
142 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
143 image->width, image->height, 0,
145 /* GL_UNSIGNED_BYTE, */
146 GL_UNSIGNED_INT_8_8_8_8_REV,
148 sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
154 setup_file_texture (ModeInfo *mi, char *filename)
156 Display *dpy = mi->dpy;
157 Visual *visual = mi->xgwa.visual;
160 Colormap cmap = mi->xgwa.colormap;
161 XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
162 if (!image) return False;
165 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
166 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
167 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
168 image->width, image->height, 0,
170 /* GL_UNSIGNED_BYTE, */
171 GL_UNSIGNED_INT_8_8_8_8_REV,
173 sprintf (buf, "texture: %.100s (%dx%d)",
174 filename, image->width, image->height);
181 setup_texture(ModeInfo * mi)
183 planetstruct *gp = &planets[MI_SCREEN(mi)];
185 glGenTextures (1, &gp->tex1);
186 glBindTexture (GL_TEXTURE_2D, gp->tex1);
188 /* Must be after glBindTexture */
189 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
190 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
191 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
192 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
193 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
197 !strcmp(which_image, "BUILTIN"))
200 setup_xpm_texture (mi, dymaxionmap_xpm);
204 if (! setup_file_texture (mi, which_image))
208 glGenTextures (1, &gp->tex2);
209 glBindTexture (GL_TEXTURE_2D, gp->tex2);
211 /* Must be after glBindTexture */
212 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
213 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
214 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
215 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
216 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
218 setup_xpm_texture (mi, ground);
220 check_gl_error("texture initialization");
222 /* Need to flip the texture top for bottom for some reason. */
223 glMatrixMode (GL_TEXTURE);
225 glMatrixMode (GL_MODELVIEW);
230 init_stars (ModeInfo *mi)
232 planetstruct *gp = &planets[MI_SCREEN(mi)];
234 int width = MI_WIDTH(mi);
235 int height = MI_HEIGHT(mi);
236 int size = (width > height ? width : height);
237 int nstars = size * size / 80;
240 int steps = max_size / inc;
242 gp->starlist = glGenLists(1);
243 glNewList(gp->starlist, GL_COMPILE);
244 for (j = 1; j <= steps; j++)
246 glPointSize(inc * j);
248 for (i = 0; i < nstars / steps; i++)
251 GLfloat r = 0.15 + frand(0.3);
252 GLfloat g = r + frand(d) - d;
253 GLfloat b = r + frand(d) - d;
255 GLfloat x = frand(1)-0.5;
256 GLfloat y = frand(1)-0.5;
257 GLfloat z = ((random() & 1)
259 : (BELLRAND(1)-0.5)/12); /* milky way */
260 d = sqrt (x*x + y*y + z*z);
265 glVertex3f (x, y, z);
272 check_gl_error("stars initialization");
277 reshape_planet (ModeInfo *mi, int width, int height)
279 GLfloat h = (GLfloat) height / (GLfloat) width;
281 glViewport(0, 0, (GLint) width, (GLint) height);
282 glMatrixMode(GL_PROJECTION);
284 glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
285 glMatrixMode(GL_MODELVIEW);
287 glTranslatef(0.0, 0.0, -40);
289 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
291 int o = (int) current_device_rotation();
292 if (o != 0 && o != 180 && o != -180)
297 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
302 do_normal2 (Bool frontp, XYZ a, XYZ b, XYZ c)
305 do_normal (a.x, a.y, a.z,
309 do_normal (b.x, b.y, b.z,
316 triangle0 (ModeInfo *mi, Bool frontp, GLfloat stel_ratio, int bitmask)
318 /* Render a triangle as six sub-triangles:
331 B ----------------------- C
335 Bool wire = MI_IS_WIREFRAME(mi);
336 GLfloat h = sqrt(3) / 2;
337 GLfloat h2 = sqrt(h*h - (h/2)*(h/2)) - 0.5;
338 XYZ A, B, C, D, E, F, G;
339 XYZ tA, tB, tC, tD, tE, tF, tG;
342 A.x = 0; A.y = h; A.z = 0;
343 B.x = -0.5, B.y = 0; B.z = 0;
344 C.x = 0.5, C.y = 0; C.z = 0;
345 D.x = 0; D.y = h/3; D.z = 0;
346 E.x = -h2; E.y = h/2; E.z = 0;
347 F.x = h2; F.y = h/2; F.z = 0;
348 G.x = 0; G.y = 0; G.z = 0;
350 /* When tweaking object XY to stellate, don't change texture coordinates. */
351 tA = A; tB = B; tC = C; tD = D; tE = E; tF = F; tG = G;
353 /* Eyeballed this to find the depth of stellation that seems to most
354 approximate a sphere.
356 D.z = 0.193 * stel_ratio;
358 /* We want to raise E, F and G as well but we can't just shift Z:
359 we need to keep them on the same vector from the center of the sphere,
360 which means also changing F and G's X and Y.
362 E.z = F.z = G.z = 0.132 * stel_ratio;
364 double magic_x = 0.044;
365 double magic_y = 0.028;
367 G.y -= sqrt (magic_x*magic_x + magic_y*magic_y) * stel_ratio;
368 E.x -= magic_x * stel_ratio;
369 E.y += magic_y * stel_ratio;
370 F.x += magic_x * stel_ratio;
371 F.y += magic_y * stel_ratio;
377 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
379 ta = tE; tb = tD; tc = tA;
380 do_normal2 (frontp, a, b, c);
381 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
382 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
383 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
389 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
391 ta = tD; tb = tF; tc = tA;
392 do_normal2 (frontp, a, b, c);
393 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
394 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
395 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
401 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
403 ta = tD; tb = tC; tc = tF;
404 do_normal2 (frontp, a, b, c);
405 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
406 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
407 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
413 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
415 ta = tG; tb = tC; tc = tD;
416 do_normal2 (frontp, a, b, c);
417 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
418 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
419 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
425 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
427 ta = tB; tb = tG; tc = tD;
428 do_normal2 (frontp, a, b, c);
429 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
430 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
431 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
437 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
439 ta = tB; tb = tD; tc = tE;
440 do_normal2 (frontp, a, b, c);
441 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
442 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
443 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
449 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
451 ta = tE; tb = tD; tc = tA;
452 do_normal2 (frontp, a, b, c);
453 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
454 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
455 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
462 /* The segments, numbered arbitrarily from the top left:
465 \ 0 / \ / \3> | \ 5 /
466 \ / 1 \ / 2 \| ..|4 \ /-6-..
467 ___________\/______\/______\/______\/______\
469 |7 / \ 9 / \ 11 / \ 13 / \ 15 / \
470 | / 8 \ / 10 \ / 12 \ / 14 \ / 16 \
471 |/______\/______\/______\/______\/______\
473 \ 17 / \ 18 / / \ 20 / \
474 \ / \ / / 19 \ / 21 \
475 \/ \/ /______\/______\
477 Each triangle can be connected to at most two other triangles.
478 We start from the middle, #12, and work our way to the edges.
482 triangle (ModeInfo *mi, int which, Bool frontp,
483 GLfloat fold_ratio, GLfloat stel_ratio)
485 planetstruct *gp = &planets[MI_SCREEN(mi)];
486 const GLfloat fg[3] = { 1, 1, 1 };
487 const GLfloat bg[3] = { 0.3, 0.3, 0.3 };
489 GLfloat max = acos (sqrt(5)/3);
490 GLfloat rot = -max * fold_ratio / (M_PI/180);
491 Bool wire = MI_IS_WIREFRAME(mi);
497 case 3: /* One third of the face. */
498 triangle0 (mi, frontp, stel_ratio, 1<<3 | 1<<4);
500 case 4: /* Two thirds of the face: convex. */
501 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3 | 1<<4);
503 case 6: /* One half of the face. */
504 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3);
506 case 7: /* One half of the face. */
507 triangle0 (mi, frontp, stel_ratio, 1<<2 | 1<<3 | 1<<4);
509 default: /* Full face. */
510 triangle0 (mi, frontp, stel_ratio, 0x3F);
518 sprintf (tag, "%d", which);
520 glTranslatef (-0.1, 0.2, 0);
521 glScalef (0.005, 0.005, 0.005);
522 print_texture_string (gp->font_data, tag);
528 /* The connection hierarchy of the faces starting at the middle, #12. */
531 case 1: a = 0; b = -1; break;
532 case 2: a = -1; b = 3; break;
534 case 4: a = -1; b = 5; break;
535 case 5: a = -1; b = 6; break;
538 case 8: a = 17; b = 7; break;
539 case 9: a = 8; b = -1; break;
540 case 10: a = 18; b = 9; break;
541 case 11: a = 10; b = 1; break;
542 case 12: a = 11; b = 13; break;
543 case 13: a = 2; b = 14; break;
544 case 14: a = 15; b = 20; break;
545 case 15: a = 4; b = 16; break;
550 case 20: a = 21; b = 19; break;
552 default: abort(); break;
558 glTranslatef (-0.5, 0, 0); /* Move model matrix to upper left */
559 glRotatef (60, 0, 0, 1);
560 glTranslatef ( 0.5, 0, 0);
562 glMatrixMode(GL_TEXTURE);
563 /* glPushMatrix(); */
564 glTranslatef (-0.5, 0, 0); /* Move texture matrix the same way */
565 glRotatef (60, 0, 0, 1);
566 glTranslatef ( 0.5, 0, 0);
568 glMatrixMode(GL_MODELVIEW);
570 glRotatef (rot, 1, 0, 0);
571 triangle (mi, a, frontp, fold_ratio, stel_ratio);
573 /* This should just be a PopMatrix on the TEXTURE stack, but
574 fucking iOS has GL_MAX_TEXTURE_STACK_DEPTH == 4! WTF!
575 So we have to undo our rotations and translations manually.
577 glMatrixMode(GL_TEXTURE);
579 glTranslatef (-0.5, 0, 0);
580 glRotatef (-60, 0, 0, 1);
581 glTranslatef (0.5, 0, 0);
583 glMatrixMode(GL_MODELVIEW);
590 glTranslatef (0.5, 0, 0); /* Move model matrix to upper right */
591 glRotatef (-60, 0, 0, 1);
592 glTranslatef (-0.5, 0, 0);
594 glMatrixMode(GL_TEXTURE);
595 /* glPushMatrix(); */
596 glTranslatef (0.5, 0, 0); /* Move texture matrix the same way */
597 glRotatef (-60, 0, 0, 1);
598 glTranslatef (-0.5, 0, 0);
600 glMatrixMode(GL_MODELVIEW);
602 glRotatef (rot, 1, 0, 0);
603 triangle (mi, b, frontp, fold_ratio, stel_ratio);
605 /* See above. Grr. */
606 glMatrixMode(GL_TEXTURE);
608 glTranslatef (0.5, 0, 0);
609 glRotatef (60, 0, 0, 1);
610 glTranslatef (-0.5, 0, 0);
612 glMatrixMode(GL_MODELVIEW);
619 draw_triangles (ModeInfo *mi, GLfloat fold_ratio, GLfloat stel_ratio)
621 planetstruct *gp = &planets[MI_SCREEN(mi)];
622 Bool wire = MI_IS_WIREFRAME(mi);
623 GLfloat h = sqrt(3) / 2;
626 glTranslatef (0, -h/3, 0); /* Center on face 12 */
628 /* When closed, center on midpoint of icosahedron. Eyeballed this. */
629 glTranslatef (0, 0, fold_ratio * 0.754);
631 glFrontFace (GL_CCW);
633 /* Adjust the texture matrix so that it has the same coordinate space
636 glMatrixMode(GL_TEXTURE);
640 GLfloat texh = 3 * h;
642 GLfloat midy = 3 * c;
643 glScalef (1/texw, -1/texh, 1);
644 glTranslatef (midx, midy, 0);
646 glMatrixMode(GL_MODELVIEW);
653 glDisable (GL_TEXTURE_2D);
656 glEnable (GL_TEXTURE_2D);
657 glBindTexture (GL_TEXTURE_2D, gp->tex1);
660 glDisable (GL_TEXTURE_2D);
662 triangle (mi, 12, True, fold_ratio, stel_ratio);
667 glDisable (GL_TEXTURE_2D);
670 glEnable (GL_TEXTURE_2D);
671 glBindTexture (GL_TEXTURE_2D, gp->tex2);
674 glDisable (GL_TEXTURE_2D);
678 triangle (mi, 12, False, fold_ratio, 0);
680 glMatrixMode(GL_TEXTURE);
682 glMatrixMode(GL_MODELVIEW);
687 align_axis (ModeInfo *mi, int undo)
689 /* Rotate so that an axis is lined up with the north and south poles
690 on the map, which are not in the center of their faces, or any
691 other easily computable spot. */
698 glRotatef (-r2, 0, 1, 0);
699 glRotatef ( r2, 1, 0, 0);
700 glRotatef (-r1, 1, 0, 0);
704 glRotatef (r1, 1, 0, 0);
705 glRotatef (-r2, 1, 0, 0);
706 glRotatef ( r2, 0, 1, 0);
712 draw_axis (ModeInfo *mi)
715 glDisable (GL_TEXTURE_2D);
716 glDisable (GL_LIGHTING);
720 glTranslatef (0.34, 0.39, -0.61);
723 glScalef (s, s, s); /* tighten up the enclosing sphere */
725 glColor3f (0.5, 0.5, 0);
727 glRotatef (90, 1, 0, 0); /* unit_sphere is off by 90 */
728 glRotatef (9.5, 0, 1, 0); /* line up the time zones */
729 glFrontFace (GL_CCW);
730 unit_sphere (12, 24, True);
732 glVertex3f(0, -2, 0);
743 planet_handle_event (ModeInfo *mi, XEvent *event)
745 planetstruct *gp = &planets[MI_SCREEN(mi)];
747 if (gltrackball_event_handler (event, gp->trackball,
748 MI_WIDTH (mi), MI_HEIGHT (mi),
751 else if (event->xany.type == KeyPress)
755 XLookupString (&event->xkey, &c, 1, &keysym, 0);
756 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
759 case FLAT: case ICO: case STEL: case AXIS: case ICO2:
773 static void free_planet (ModeInfo * mi);
777 init_planet (ModeInfo * mi)
780 int screen = MI_SCREEN(mi);
781 Bool wire = MI_IS_WIREFRAME(mi);
783 MI_INIT (mi, planets, free_planet);
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 free_planet (ModeInfo * mi)
1011 planetstruct *gp = &planets[MI_SCREEN(mi)];
1013 if (gp->glx_context) {
1014 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));
1016 if (glIsList(gp->starlist))
1017 glDeleteLists(gp->starlist, 1);
1022 XSCREENSAVER_MODULE_2 ("DymaxionMap", dymaxionmap, planet)