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 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
138 image->width, image->height, 0,
140 /* GL_UNSIGNED_BYTE, */
141 GL_UNSIGNED_INT_8_8_8_8_REV,
143 sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
146 /* setup parameters for texturing */
147 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
148 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
149 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
150 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
151 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
152 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
157 setup_file_texture (ModeInfo *mi, char *filename)
159 Display *dpy = mi->dpy;
160 Visual *visual = mi->xgwa.visual;
163 Colormap cmap = mi->xgwa.colormap;
164 XImage *image = xpm_file_to_ximage (dpy, visual, cmap, filename);
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);
176 /* setup parameters for texturing */
177 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
178 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
180 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
181 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
182 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
183 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
184 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
189 setup_texture(ModeInfo * mi)
191 planetstruct *gp = &planets[MI_SCREEN(mi)];
195 !strcmp(which_image, "BUILTIN"))
197 glGenTextures (1, &gp->tex1);
198 glBindTexture (GL_TEXTURE_2D, gp->tex1);
199 setup_xpm_texture (mi, dymaxionmap_xpm);
203 glGenTextures (1, &gp->tex1);
204 glBindTexture (GL_TEXTURE_2D, gp->tex1);
205 setup_file_texture (mi, which_image);
208 glGenTextures (1, &gp->tex2);
209 glBindTexture (GL_TEXTURE_2D, gp->tex2);
210 setup_xpm_texture (mi, ground);
212 check_gl_error("texture initialization");
214 /* Need to flip the texture top for bottom for some reason. */
215 glMatrixMode (GL_TEXTURE);
217 glMatrixMode (GL_MODELVIEW);
222 init_stars (ModeInfo *mi)
224 planetstruct *gp = &planets[MI_SCREEN(mi)];
226 int width = MI_WIDTH(mi);
227 int height = MI_HEIGHT(mi);
228 int size = (width > height ? width : height);
229 int nstars = size * size / 80;
232 int steps = max_size / inc;
234 gp->starlist = glGenLists(1);
235 glNewList(gp->starlist, GL_COMPILE);
236 for (j = 1; j <= steps; j++)
238 glPointSize(inc * j);
240 for (i = 0; i < nstars / steps; i++)
243 GLfloat r = 0.15 + frand(0.3);
244 GLfloat g = r + frand(d) - d;
245 GLfloat b = r + frand(d) - d;
247 GLfloat x = frand(1)-0.5;
248 GLfloat y = frand(1)-0.5;
249 GLfloat z = ((random() & 1)
251 : (BELLRAND(1)-0.5)/12); /* milky way */
252 d = sqrt (x*x + y*y + z*z);
257 glVertex3f (x, y, z);
264 check_gl_error("stars initialization");
269 reshape_planet (ModeInfo *mi, int width, int height)
271 GLfloat h = (GLfloat) height / (GLfloat) width;
273 glViewport(0, 0, (GLint) width, (GLint) height);
274 glMatrixMode(GL_PROJECTION);
276 glFrustum(-1.0, 1.0, -h, h, 5.0, 100.0);
277 glMatrixMode(GL_MODELVIEW);
279 glTranslatef(0.0, 0.0, -40);
281 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
283 int o = (int) current_device_rotation();
284 if (o != 0 && o != 180 && o != -180)
289 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
294 do_normal2 (Bool frontp, XYZ a, XYZ b, XYZ c)
297 do_normal (a.x, a.y, a.z,
301 do_normal (b.x, b.y, b.z,
308 triangle0 (ModeInfo *mi, Bool frontp, GLfloat stel_ratio, int bitmask)
310 /* Render a triangle as six sub-triangles:
323 B ----------------------- C
327 Bool wire = MI_IS_WIREFRAME(mi);
328 GLfloat h = sqrt(3) / 2;
329 GLfloat h2 = sqrt(h*h - (h/2)*(h/2)) - 0.5;
330 XYZ A, B, C, D, E, F, G;
331 XYZ tA, tB, tC, tD, tE, tF, tG;
334 A.x = 0; A.y = h; A.z = 0;
335 B.x = -0.5, B.y = 0; B.z = 0;
336 C.x = 0.5, C.y = 0; C.z = 0;
337 D.x = 0; D.y = h/3; D.z = 0;
338 E.x = -h2; E.y = h/2; E.z = 0;
339 F.x = h2; F.y = h/2; F.z = 0;
340 G.x = 0; G.y = 0; G.z = 0;
342 /* When tweaking object XY to stellate, don't change texture coordinates. */
343 tA = A; tB = B; tC = C; tD = D; tE = E; tF = F; tG = G;
345 /* Eyeballed this to find the depth of stellation that seems to most
346 approximate a sphere.
348 D.z = 0.193 * stel_ratio;
350 /* We want to raise E, F and G as well but we can't just shift Z:
351 we need to keep them on the same vector from the center of the sphere,
352 which means also changing F and G's X and Y.
354 E.z = F.z = G.z = 0.132 * stel_ratio;
356 double magic_x = 0.044;
357 double magic_y = 0.028;
359 G.y -= sqrt (magic_x*magic_x + magic_y*magic_y) * stel_ratio;
360 E.x -= magic_x * stel_ratio;
361 E.y += magic_y * stel_ratio;
362 F.x += magic_x * stel_ratio;
363 F.y += magic_y * stel_ratio;
369 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
371 ta = tE; tb = tD; tc = tA;
372 do_normal2 (frontp, a, b, c);
373 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
374 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
375 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
381 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
383 ta = tD; tb = tF; tc = tA;
384 do_normal2 (frontp, a, b, c);
385 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
386 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
387 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
393 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
395 ta = tD; tb = tC; tc = tF;
396 do_normal2 (frontp, a, b, c);
397 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
398 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
399 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
405 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
407 ta = tG; tb = tC; tc = tD;
408 do_normal2 (frontp, a, b, c);
409 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
410 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
411 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
417 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
419 ta = tB; tb = tG; tc = tD;
420 do_normal2 (frontp, a, b, c);
421 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
422 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
423 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
429 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
431 ta = tB; tb = tD; tc = tE;
432 do_normal2 (frontp, a, b, c);
433 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
434 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
435 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
441 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
443 ta = tE; tb = tD; tc = tA;
444 do_normal2 (frontp, a, b, c);
445 glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
446 glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
447 glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
454 /* The segments, numbered arbitrarily from the top left:
457 \ 0 / \ / \3> | \ 5 /
458 \ / 1 \ / 2 \| ..|4 \ /-6-..
459 ___________\/______\/______\/______\/______\
461 |7 / \ 9 / \ 11 / \ 13 / \ 15 / \
462 | / 8 \ / 10 \ / 12 \ / 14 \ / 16 \
463 |/______\/______\/______\/______\/______\
465 \ 17 / \ 18 / / \ 20 / \
466 \ / \ / / 19 \ / 21 \
467 \/ \/ /______\/______\
469 Each triangle can be connected to at most two other triangles.
470 We start from the middle, #12, and work our way to the edges.
474 triangle (ModeInfo *mi, int which, Bool frontp,
475 GLfloat fold_ratio, GLfloat stel_ratio)
477 planetstruct *gp = &planets[MI_SCREEN(mi)];
478 const GLfloat fg[3] = { 1, 1, 1 };
479 const GLfloat bg[3] = { 0.3, 0.3, 0.3 };
481 GLfloat max = acos (sqrt(5)/3);
482 GLfloat rot = -max * fold_ratio / (M_PI/180);
483 Bool wire = MI_IS_WIREFRAME(mi);
489 case 3: /* One third of the face. */
490 triangle0 (mi, frontp, stel_ratio, 1<<3 | 1<<4);
492 case 4: /* Two thirds of the face: convex. */
493 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3 | 1<<4);
495 case 6: /* One half of the face. */
496 triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3);
498 case 7: /* One half of the face. */
499 triangle0 (mi, frontp, stel_ratio, 1<<2 | 1<<3 | 1<<4);
501 default: /* Full face. */
502 triangle0 (mi, frontp, stel_ratio, 0x3F);
510 sprintf (tag, "%d", which);
512 glTranslatef (-0.1, 0.2, 0);
513 glScalef (0.005, 0.005, 0.005);
514 print_texture_string (gp->font_data, tag);
520 /* The connection hierarchy of the faces starting at the middle, #12. */
523 case 1: a = 0; b = -1; break;
524 case 2: a = -1; b = 3; break;
526 case 4: a = -1; b = 5; break;
527 case 5: a = -1; b = 6; break;
530 case 8: a = 17; b = 7; break;
531 case 9: a = 8; b = -1; break;
532 case 10: a = 18; b = 9; break;
533 case 11: a = 10; b = 1; break;
534 case 12: a = 11; b = 13; break;
535 case 13: a = 2; b = 14; break;
536 case 14: a = 15; b = 20; break;
537 case 15: a = 4; b = 16; break;
542 case 20: a = 21; b = 19; break;
544 default: abort(); break;
550 glTranslatef (-0.5, 0, 0); /* Move model matrix to upper left */
551 glRotatef (60, 0, 0, 1);
552 glTranslatef ( 0.5, 0, 0);
554 glMatrixMode(GL_TEXTURE);
555 /* glPushMatrix(); */
556 glTranslatef (-0.5, 0, 0); /* Move texture matrix the same way */
557 glRotatef (60, 0, 0, 1);
558 glTranslatef ( 0.5, 0, 0);
560 glMatrixMode(GL_MODELVIEW);
562 glRotatef (rot, 1, 0, 0);
563 triangle (mi, a, frontp, fold_ratio, stel_ratio);
565 /* This should just be a PopMatrix on the TEXTURE stack, but
566 fucking iOS has GL_MAX_TEXTURE_STACK_DEPTH == 4! WTF!
567 So we have to undo our rotations and translations manually.
569 glMatrixMode(GL_TEXTURE);
571 glTranslatef (-0.5, 0, 0);
572 glRotatef (-60, 0, 0, 1);
573 glTranslatef (0.5, 0, 0);
575 glMatrixMode(GL_MODELVIEW);
582 glTranslatef (0.5, 0, 0); /* Move model matrix to upper right */
583 glRotatef (-60, 0, 0, 1);
584 glTranslatef (-0.5, 0, 0);
586 glMatrixMode(GL_TEXTURE);
587 /* glPushMatrix(); */
588 glTranslatef (0.5, 0, 0); /* Move texture matrix the same way */
589 glRotatef (-60, 0, 0, 1);
590 glTranslatef (-0.5, 0, 0);
592 glMatrixMode(GL_MODELVIEW);
594 glRotatef (rot, 1, 0, 0);
595 triangle (mi, b, frontp, fold_ratio, stel_ratio);
597 /* See above. Grr. */
598 glMatrixMode(GL_TEXTURE);
600 glTranslatef (0.5, 0, 0);
601 glRotatef (60, 0, 0, 1);
602 glTranslatef (-0.5, 0, 0);
604 glMatrixMode(GL_MODELVIEW);
611 draw_triangles (ModeInfo *mi, GLfloat fold_ratio, GLfloat stel_ratio)
613 planetstruct *gp = &planets[MI_SCREEN(mi)];
614 Bool wire = MI_IS_WIREFRAME(mi);
615 GLfloat h = sqrt(3) / 2;
618 glTranslatef (0, -h/3, 0); /* Center on face 12 */
620 /* When closed, center on midpoint of icosahedron. Eyeballed this. */
621 glTranslatef (0, 0, fold_ratio * 0.754);
623 glFrontFace (GL_CCW);
625 /* Adjust the texture matrix so that it has the same coordinate space
628 glMatrixMode(GL_TEXTURE);
632 GLfloat texh = 3 * h;
634 GLfloat midy = 3 * c;
635 glScalef (1/texw, -1/texh, 1);
636 glTranslatef (midx, midy, 0);
638 glMatrixMode(GL_MODELVIEW);
645 glDisable (GL_TEXTURE_2D);
648 glEnable (GL_TEXTURE_2D);
649 glBindTexture (GL_TEXTURE_2D, gp->tex1);
652 glDisable (GL_TEXTURE_2D);
654 triangle (mi, 12, True, fold_ratio, stel_ratio);
659 glDisable (GL_TEXTURE_2D);
662 glEnable (GL_TEXTURE_2D);
663 glBindTexture (GL_TEXTURE_2D, gp->tex2);
666 glDisable (GL_TEXTURE_2D);
670 triangle (mi, 12, False, fold_ratio, 0);
672 glMatrixMode(GL_TEXTURE);
674 glMatrixMode(GL_MODELVIEW);
679 align_axis (ModeInfo *mi, int undo)
681 /* Rotate so that an axis is lined up with the north and south poles
682 on the map, which are not in the center of their faces, or any
683 other easily computable spot. */
690 glRotatef (-r2, 0, 1, 0);
691 glRotatef ( r2, 1, 0, 0);
692 glRotatef (-r1, 1, 0, 0);
696 glRotatef (r1, 1, 0, 0);
697 glRotatef (-r2, 1, 0, 0);
698 glRotatef ( r2, 0, 1, 0);
704 draw_axis (ModeInfo *mi)
707 glDisable (GL_TEXTURE_2D);
708 glDisable (GL_LIGHTING);
712 glTranslatef (0.34, 0.39, -0.61);
715 glScalef (s, s, s); /* tighten up the enclosing sphere */
717 glColor3f (0.5, 0.5, 0);
719 glRotatef (90, 1, 0, 0); /* unit_sphere is off by 90 */
720 glRotatef (9.5, 0, 1, 0); /* line up the time zones */
721 glFrontFace (GL_CCW);
722 unit_sphere (12, 24, True);
724 glVertex3f(0, -2, 0);
735 planet_handle_event (ModeInfo *mi, XEvent *event)
737 planetstruct *gp = &planets[MI_SCREEN(mi)];
739 if (gltrackball_event_handler (event, gp->trackball,
740 MI_WIDTH (mi), MI_HEIGHT (mi),
743 else if (event->xany.type == KeyPress)
747 XLookupString (&event->xkey, &c, 1, &keysym, 0);
748 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
751 case FLAT: case ICO: case STEL: case AXIS: case ICO2:
766 init_planet (ModeInfo * mi)
769 int screen = MI_SCREEN(mi);
770 Bool wire = MI_IS_WIREFRAME(mi);
772 if (planets == NULL) {
773 if ((planets = (planetstruct *) calloc(MI_NUM_SCREENS(mi),
774 sizeof (planetstruct))) == NULL)
777 gp = &planets[screen];
779 if ((gp->glx_context = init_GL(mi)) != NULL) {
780 reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
785 gp->font_data = load_texture_font (mi->dpy, "labelFont");
788 double spin_speed = 0.1;
789 double wander_speed = 0.002;
790 gp->rot = make_rotator (do_roll ? spin_speed : 0,
791 do_roll ? spin_speed : 0,
793 do_wander ? wander_speed : 0,
795 gp->trackball = gltrackball_init (True);
807 glEnable (GL_DEPTH_TEST);
808 glEnable (GL_NORMALIZE);
809 glEnable (GL_CULL_FACE);
813 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
814 GLfloat amb[4] = {0.4, 0.4, 0.4, 1.0};
815 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
816 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
818 glEnable(GL_LIGHTING);
820 glLightfv(GL_LIGHT0, GL_POSITION, pos);
821 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
822 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
823 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
831 return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */
836 ease_ratio (GLfloat r)
839 if (r <= 0) return 0;
840 else if (r >= 1) return 1;
841 else if (r <= ease) return ease * ease_fn (r / ease);
842 else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease);
848 draw_planet (ModeInfo * mi)
850 planetstruct *gp = &planets[MI_SCREEN(mi)];
851 int wire = MI_IS_WIREFRAME(mi);
852 Display *dpy = MI_DISPLAY(mi);
853 Window window = MI_WINDOW(mi);
856 if (!gp->glx_context)
859 glDrawBuffer(GL_BACK);
860 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
862 glXMakeCurrent (dpy, window, *(gp->glx_context));
864 mi->polygon_count = 0;
866 if (! gp->button_down_p)
868 case STARTUP: gp->ratio += speed * 0.01; break;
869 case FLAT: gp->ratio += speed * 0.005; break;
870 case FOLD: gp->ratio += speed * 0.01; break;
871 case ICO: gp->ratio += speed * 0.01; break;
872 case STEL_IN: gp->ratio += speed * 0.05; break;
873 case STEL: gp->ratio += speed * 0.01; break;
874 case STEL_OUT: gp->ratio += speed * 0.07; break;
875 case ICO2: gp->ratio += speed * 0.07; break;
876 case AXIS: gp->ratio += speed * 0.02; break;
877 case SPIN: gp->ratio += speed * 0.005; break;
878 case UNFOLD: gp->ratio += speed * 0.01; break;
886 case STARTUP: gp->state = FLAT; break;
887 case FLAT: gp->state = FOLD; break;
888 case FOLD: gp->state = ICO; break;
889 case ICO: gp->state = STEL_IN; break;
890 case STEL_IN: gp->state = STEL; break;
893 int i = (random() << 9) % 7;
894 gp->state = (i < 3 ? STEL_OUT :
895 i < 6 ? SPIN : AXIS);
898 case AXIS: gp->state = STEL_OUT; break;
899 case SPIN: gp->state = STEL_OUT; break;
900 case STEL_OUT: gp->state = ICO2; break;
901 case ICO2: gp->state = UNFOLD; break;
902 case UNFOLD: gp->state = FLAT; break;
907 glEnable(GL_LINE_SMOOTH);
908 glEnable(GL_POINT_SMOOTH);
909 glEnable(GL_DEPTH_TEST);
910 glEnable(GL_CULL_FACE);
915 gltrackball_rotate (gp->trackball);
916 glRotatef (current_device_rotation(), 0, 0, 1);
918 if (gp->state != STARTUP)
920 get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
924 glTranslatef(x, y, z);
927 if (do_roll && gp->state != STARTUP)
929 get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
930 glRotatef (x * 360, 1.0, 0.0, 0.0);
931 glRotatef (y * 360, 0.0, 1.0, 0.0);
936 glDisable(GL_TEXTURE_2D);
937 glDisable(GL_LIGHTING);
939 glScalef (60, 60, 60);
940 glRotatef (90, 1, 0, 0);
941 glRotatef (35, 1, 0, 0);
942 glCallList (gp->starlist);
943 mi->polygon_count += gp->starcount;
945 glClear(GL_DEPTH_BUFFER_BIT);
949 glEnable (GL_LIGHTING);
952 glEnable(GL_TEXTURE_2D);
954 glScalef (2.6, 2.6, 2.6);
957 GLfloat fold_ratio = 0;
958 GLfloat stel_ratio = 0;
960 case FOLD: fold_ratio = gp->ratio; break;
961 case UNFOLD: fold_ratio = 1 - gp->ratio; break;
962 case ICO: case ICO2: fold_ratio = 1; break;
963 case STEL: case AXIS: case SPIN: fold_ratio = 1; stel_ratio = 1; break;
964 case STEL_IN: fold_ratio = 1; stel_ratio = gp->ratio; break;
965 case STEL_OUT: fold_ratio = 1; stel_ratio = 1 - gp->ratio; break;
966 case STARTUP: /* Tilt in from flat */
967 glRotatef (-90 * ease_ratio (1 - gp->ratio), 1, 0, 0);
973 # ifdef HAVE_MOBILE /* Enlarge the icosahedron a bit to make it more visible */
975 GLfloat s = 1 + 1.3 * ease_ratio (fold_ratio);
980 if (gp->state == SPIN)
983 glRotatef (ease_ratio (gp->ratio) * 360 * 3, 0, 0, 1);
987 draw_triangles (mi, ease_ratio (fold_ratio), ease_ratio (stel_ratio));
989 if (gp->state == AXIS)
995 if (mi->fps_p) do_fps (mi);
997 glXSwapBuffers(dpy, window);
1002 release_planet (ModeInfo * mi)
1004 if (planets != NULL) {
1007 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1008 planetstruct *gp = &planets[screen];
1010 if (gp->glx_context) {
1011 /* Display lists MUST be freed while their glXContext is current. */
1012 /* but this gets a BadMatch error. -jwz */
1013 /*glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));*/
1015 if (glIsList(gp->starlist))
1016 glDeleteLists(gp->starlist, 1);
1019 (void) free((void *) planets);
1026 XSCREENSAVER_MODULE_2 ("DymaxionMap", dymaxionmap, planet)