1 /* dymaxionmap --- Buckminster Fuller's unwrapped icosahedral globe.
2 * Copyright (c) 2016-2018 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 release_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", NULL,
92 "draw_planet", "init_planet", "free_planet", &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/gen/dymaxionmap_png.h"
103 #include "images/gen/ground_png.h"
105 #include "ximage-loader.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_png_texture (ModeInfo *mi, const unsigned char *png_data,
132 unsigned long data_size)
134 XImage *image = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
135 png_data, data_size);
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,
144 GL_RGBA, GL_UNSIGNED_BYTE, image->data);
145 sprintf (buf, "builtin texture (%dx%d)", image->width, image->height);
151 setup_file_texture (ModeInfo *mi, char *filename)
153 Display *dpy = mi->dpy;
154 Visual *visual = mi->xgwa.visual;
157 XImage *image = file_to_ximage (dpy, visual, filename);
158 if (!image) return False;
161 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
162 glPixelStorei(GL_UNPACK_ROW_LENGTH, image->width);
163 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
164 image->width, image->height, 0,
165 GL_RGBA, GL_UNSIGNED_BYTE, image->data);
166 sprintf (buf, "texture: %.100s (%dx%d)",
167 filename, image->width, image->height);
174 setup_texture(ModeInfo * mi)
176 planetstruct *gp = &planets[MI_SCREEN(mi)];
178 glGenTextures (1, &gp->tex1);
179 glBindTexture (GL_TEXTURE_2D, gp->tex1);
181 /* Must be after glBindTexture */
182 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
183 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
184 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
185 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
186 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
190 !strcmp(which_image, "BUILTIN"))
193 setup_png_texture (mi, dymaxionmap_png, sizeof(dymaxionmap_png));
197 if (! setup_file_texture (mi, which_image))
201 glGenTextures (1, &gp->tex2);
202 glBindTexture (GL_TEXTURE_2D, gp->tex2);
204 /* Must be after glBindTexture */
205 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
206 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
207 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
208 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
209 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
211 setup_png_texture (mi, ground_png, sizeof(ground_png));
213 check_gl_error("texture initialization");
215 /* Need to flip the texture top for bottom for some reason. */
216 glMatrixMode (GL_TEXTURE);
218 glMatrixMode (GL_MODELVIEW);
223 init_stars (ModeInfo *mi)
225 planetstruct *gp = &planets[MI_SCREEN(mi)];
227 int width = MI_WIDTH(mi);
228 int height = MI_HEIGHT(mi);
229 int size = (width > height ? width : height);
230 int nstars = size * size / 80;
233 int steps = max_size / inc;
236 if (MI_WIDTH(mi) > 2560) { /* Retina displays */
241 gp->starlist = glGenLists(1);
242 glNewList(gp->starlist, GL_COMPILE);
243 for (j = 1; j <= steps; j++)
245 glPointSize(inc * j * scale);
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, 200.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 MI_INIT (mi, planets);
780 gp = &planets[screen];
782 if ((gp->glx_context = init_GL(mi)) != NULL) {
783 reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
788 gp->font_data = load_texture_font (mi->dpy, "labelFont");
791 double spin_speed = 0.1;
792 double wander_speed = 0.002;
793 gp->rot = make_rotator (do_roll ? spin_speed : 0,
794 do_roll ? spin_speed : 0,
796 do_wander ? wander_speed : 0,
798 gp->trackball = gltrackball_init (True);
810 glEnable (GL_DEPTH_TEST);
811 glEnable (GL_NORMALIZE);
812 glEnable (GL_CULL_FACE);
816 GLfloat pos[4] = {0.4, 0.2, 0.4, 0.0};
817 GLfloat amb[4] = {0.4, 0.4, 0.4, 1.0};
818 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
819 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
821 glEnable(GL_LIGHTING);
823 glLightfv(GL_LIGHT0, GL_POSITION, pos);
824 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
825 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
826 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
834 return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */
839 ease_ratio (GLfloat r)
842 if (r <= 0) return 0;
843 else if (r >= 1) return 1;
844 else if (r <= ease) return ease * ease_fn (r / ease);
845 else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease);
851 draw_planet (ModeInfo * mi)
853 planetstruct *gp = &planets[MI_SCREEN(mi)];
854 int wire = MI_IS_WIREFRAME(mi);
855 Display *dpy = MI_DISPLAY(mi);
856 Window window = MI_WINDOW(mi);
859 if (!gp->glx_context)
862 glDrawBuffer(GL_BACK);
863 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
865 glXMakeCurrent (dpy, window, *(gp->glx_context));
867 mi->polygon_count = 0;
869 if (! gp->button_down_p)
871 case STARTUP: gp->ratio += speed * 0.01; break;
872 case FLAT: gp->ratio += speed * 0.005; break;
873 case FOLD: gp->ratio += speed * 0.01; break;
874 case ICO: gp->ratio += speed * 0.01; break;
875 case STEL_IN: gp->ratio += speed * 0.05; break;
876 case STEL: gp->ratio += speed * 0.01; break;
877 case STEL_OUT: gp->ratio += speed * 0.07; break;
878 case ICO2: gp->ratio += speed * 0.07; break;
879 case AXIS: gp->ratio += speed * 0.02; break;
880 case SPIN: gp->ratio += speed * 0.005; break;
881 case UNFOLD: gp->ratio += speed * 0.01; break;
889 case STARTUP: gp->state = FLAT; break;
890 case FLAT: gp->state = FOLD; break;
891 case FOLD: gp->state = ICO; break;
892 case ICO: gp->state = STEL_IN; break;
893 case STEL_IN: gp->state = STEL; break;
896 int i = (random() << 9) % 7;
897 gp->state = (i < 3 ? STEL_OUT :
898 i < 6 ? SPIN : AXIS);
901 case AXIS: gp->state = STEL_OUT; break;
902 case SPIN: gp->state = STEL_OUT; break;
903 case STEL_OUT: gp->state = ICO2; break;
904 case ICO2: gp->state = UNFOLD; break;
905 case UNFOLD: gp->state = FLAT; break;
910 glEnable(GL_LINE_SMOOTH);
911 glEnable(GL_POINT_SMOOTH);
912 glEnable(GL_DEPTH_TEST);
913 glEnable(GL_CULL_FACE);
918 gltrackball_rotate (gp->trackball);
919 glRotatef (current_device_rotation(), 0, 0, 1);
921 if (gp->state != STARTUP)
923 get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
927 glTranslatef(x, y, z);
930 if (do_roll && gp->state != STARTUP)
932 get_rotation (gp->rot, &x, &y, 0, !gp->button_down_p);
933 glRotatef (x * 360, 1.0, 0.0, 0.0);
934 glRotatef (y * 360, 0.0, 1.0, 0.0);
939 glDisable(GL_TEXTURE_2D);
940 glDisable(GL_LIGHTING);
942 glScalef (60, 60, 60);
943 glRotatef (90, 1, 0, 0);
944 glRotatef (35, 1, 0, 0);
945 glCallList (gp->starlist);
946 mi->polygon_count += gp->starcount;
948 glClear(GL_DEPTH_BUFFER_BIT);
952 glEnable (GL_LIGHTING);
955 glEnable(GL_TEXTURE_2D);
957 glScalef (2.6, 2.6, 2.6);
960 GLfloat fold_ratio = 0;
961 GLfloat stel_ratio = 0;
963 case FOLD: fold_ratio = gp->ratio; break;
964 case UNFOLD: fold_ratio = 1 - gp->ratio; break;
965 case ICO: case ICO2: fold_ratio = 1; break;
966 case STEL: case AXIS: case SPIN: fold_ratio = 1; stel_ratio = 1; break;
967 case STEL_IN: fold_ratio = 1; stel_ratio = gp->ratio; break;
968 case STEL_OUT: fold_ratio = 1; stel_ratio = 1 - gp->ratio; break;
969 case STARTUP: /* Tilt in from flat */
970 glRotatef (-90 * ease_ratio (1 - gp->ratio), 1, 0, 0);
976 # ifdef HAVE_MOBILE /* Enlarge the icosahedron a bit to make it more visible */
978 GLfloat s = 1 + 1.3 * ease_ratio (fold_ratio);
983 if (gp->state == SPIN)
986 glRotatef (ease_ratio (gp->ratio) * 360 * 3, 0, 0, 1);
990 draw_triangles (mi, ease_ratio (fold_ratio), ease_ratio (stel_ratio));
992 if (gp->state == AXIS)
998 if (mi->fps_p) do_fps (mi);
1000 glXSwapBuffers(dpy, window);
1005 free_planet (ModeInfo * mi)
1007 planetstruct *gp = &planets[MI_SCREEN(mi)];
1009 if (gp->glx_context) {
1010 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(gp->glx_context));
1012 if (glIsList(gp->starlist))
1013 glDeleteLists(gp->starlist, 1);
1018 XSCREENSAVER_MODULE_2 ("DymaxionMap", dymaxionmap, planet)