summaryrefslogtreecommitdiffstats
path: root/hacks/glx/dymaxionmap.c
diff options
context:
space:
mode:
authorSimon Rettberg2024-09-06 14:42:37 +0200
committerSimon Rettberg2024-09-06 14:42:37 +0200
commitbadef32037f52f79abc1f1440b786cd71afdf270 (patch)
tree412b792d4cab4a7a110db82fcf74fe8a1ac55ec1 /hacks/glx/dymaxionmap.c
parentDelete pre-6.00 files (diff)
downloadxscreensaver-master.tar.gz
xscreensaver-master.tar.xz
xscreensaver-master.zip
Diffstat (limited to 'hacks/glx/dymaxionmap.c')
-rw-r--r--hacks/glx/dymaxionmap.c1652
1 files changed, 0 insertions, 1652 deletions
diff --git a/hacks/glx/dymaxionmap.c b/hacks/glx/dymaxionmap.c
deleted file mode 100644
index 1527daa..0000000
--- a/hacks/glx/dymaxionmap.c
+++ /dev/null
@@ -1,1652 +0,0 @@
-/* dymaxionmap --- Buckminster Fuller's unwrapped icosahedral globe.
- * Copyright (c) 2016-2018 Jamie Zawinski.
- *
- * Permission to use, copy, modify, and distribute this software and its
- * documentation for any purpose and without fee is hereby granted,
- * provided that the above copyright notice appear in all copies and that
- * both that copyright notice and this permission notice appear in
- * supporting documentation.
- *
- * This file is provided AS IS with no warranties of any kind. The author
- * shall have no liability with respect to the infringement of copyrights,
- * trade secrets or any patents by this file or any part thereof. In no
- * event will the author be liable for any lost revenue or profits or
- * other special, indirect and consequential damages.
- */
-
-#define LABEL_FONT "sans-serif bold 24"
-
-#ifdef STANDALONE
-#define DEFAULTS "*delay: 20000 \n" \
- "*showFPS: False \n" \
- "*wireframe: False \n" \
- "*labelFont: " LABEL_FONT "\n"
-# define release_planet 0
-# include "xlockmore.h" /* from the xscreensaver distribution */
-#else /* !STANDALONE */
-# include "xlock.h" /* from the xlockmore distribution */
-#endif /* !STANDALONE */
-
-#ifdef USE_GL /* whole file */
-
-#include "sphere.h"
-#include "normals.h"
-#include "texfont.h"
-#include "dymaxionmap-coords.h"
-
-#define DEF_ROTATE "True"
-#define DEF_ROLL "True"
-#define DEF_WANDER "True"
-#define DEF_TEXTURE "True"
-#define DEF_STARS "True"
-#define DEF_GRID "True"
-#define DEF_SPEED "1.0"
-#define DEF_IMAGE "BUILTIN_FLAT"
-#define DEF_IMAGE2 "NONE"
-#define DEF_FRAMES "720"
-
-#undef BELLRAND
-#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3)
-#undef RANDSIGN
-#define RANDSIGN() ((random() & 1) ? 1 : -1)
-
-static int do_roll;
-static int do_wander;
-static int do_texture;
-static int do_stars;
-static int do_grid;
-static int frames;
-static GLfloat speed;
-static char *which_image;
-static char *which_image2;
-
-static XrmOptionDescRec opts[] = {
- {"-speed", ".speed", XrmoptionSepArg, 0 },
- {"-roll", ".roll", XrmoptionNoArg, "true" },
- {"+roll", ".roll", XrmoptionNoArg, "false" },
- {"-wander", ".wander", XrmoptionNoArg, "true" },
- {"+wander", ".wander", XrmoptionNoArg, "false" },
- {"-texture", ".texture", XrmoptionNoArg, "true" },
- {"+texture", ".texture", XrmoptionNoArg, "false" },
- {"-stars", ".stars", XrmoptionNoArg, "true" },
- {"+stars", ".stars", XrmoptionNoArg, "false" },
- {"-grid", ".grid", XrmoptionNoArg, "true" },
- {"+grid", ".grid", XrmoptionNoArg, "false" },
- {"-flat", ".image", XrmoptionNoArg, "BUILTIN_FLAT" },
- {"-satellite",".image", XrmoptionNoArg, "BUILTIN_SAT" },
- {"-image", ".image", XrmoptionSepArg, 0 },
- {"-image2", ".image2", XrmoptionSepArg, 0 },
- {"-frames", ".frames", XrmoptionSepArg, 0 },
-};
-
-static argtype vars[] = {
- {&speed, "speed", "Speed", DEF_SPEED, t_Float},
- {&do_roll, "roll", "Roll", DEF_ROLL, t_Bool},
- {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
- {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
- {&do_stars, "stars", "Stars", DEF_STARS, t_Bool},
- {&do_grid, "grid", "Grid", DEF_GRID, t_Bool},
- {&which_image, "image", "Image", DEF_IMAGE, t_String},
- {&which_image2,"image2", "Image2", DEF_IMAGE2, t_String},
- {&frames, "frames", "Frames", DEF_FRAMES, t_Int},
-};
-
-ENTRYPOINT ModeSpecOpt planet_opts = {countof(opts), opts, countof(vars), vars, NULL};
-
-#ifdef USE_MODULES
-ModStruct planet_description =
-{"planet", "init_planet", "draw_planet", NULL,
- "draw_planet", "init_planet", "free_planet", &planet_opts,
- 1000, 1, 2, 1, 4, 1.0, "",
- "Buckminster Fuller's unwrapped icosahedral globe", 0, NULL};
-#endif
-
-# ifdef __GNUC__
- __extension__ /* don't warn about "string length is greater than the length
- ISO C89 compilers are required to support" when including
- the following XPM file... */
-# endif
-
-#include "images/gen/earth_flat_png.h"
-#include "images/gen/earth_png.h"
-#include "images/gen/earth_night_png.h"
-#include "images/gen/ground_png.h"
-
-#include "ximage-loader.h"
-#include "rotator.h"
-#include "gltrackball.h"
-
-
-typedef struct {
- GLXContext *glx_context;
- GLuint starlist;
- int starcount;
- rotator *rot, *rot2;
- trackball_state *trackball;
- Bool button_down_p;
- enum { STARTUP, FLAT, FOLD,
- ICO, STEL_IN, AXIS, SPIN, STEL, STEL_OUT,
- ICO2, UNFOLD } state;
- GLfloat ratio;
- GLuint tex1, tex2;
- texture_font_data *font_data;
- int loading_sw, loading_sh;
-
- XImage *day, *night, *dusk, *cvt;
- XImage **images; /* One image for each frame of time-of-day. */
- int nimages;
-
- double current_frame;
- Bool cache_p;
- long delay;
-
-} planetstruct;
-
-
-static planetstruct *planets = NULL;
-
-
-static double
-double_time (void)
-{
- struct timeval now;
-# ifdef GETTIMEOFDAY_TWO_ARGS
- struct timezone tzp;
- gettimeofday(&now, &tzp);
-# else
- gettimeofday(&now);
-# endif
-
- return (now.tv_sec + ((double) now.tv_usec * 0.000001));
-}
-
-
-/* Draw faint latitude and longitude lines into the RGBA XImage.
- */
-static void
-add_grid_lines (XImage *image)
-{
- int i;
- int off = 24;
- for (i = 0; i < 24; i++)
- {
- int x = (i + 0.5) * image->width / (double) 24;
- int y;
- for (y = 0; y < image->height; y++)
- {
- unsigned long rgba = XGetPixel (image, x, y);
- int r = (rgba >> 24) & 0xFF;
- int g = (rgba >> 16) & 0xFF;
- int b = (rgba >> 8) & 0xFF;
- int a = (rgba >> 0) & 0xFF;
- int off2 = (((r + g + b) / 3) < 0x7F ? off : -off);
- r = MAX (0, MIN (0xFF, r + off2));
- g = MAX (0, MIN (0xFF, g + off2));
- b = MAX (0, MIN (0xFF, b + off2));
- XPutPixel (image, x, y, (r << 24) | (g << 16) | (b << 8) | a);
- }
- }
-
- for (i = 1; i < 11; i++)
- {
- int y = i * image->height / (double) 12;
- int x;
- for (x = 0; x < image->width; x++)
- {
- unsigned long rgba = XGetPixel (image, x, y);
- int r = (rgba >> 24) & 0xFF;
- int g = (rgba >> 16) & 0xFF;
- int b = (rgba >> 8) & 0xFF;
- int a = (rgba >> 0) & 0xFF;
- int off2 = (((r + g + b) / 3) < 0x7F ? off : -off);
- r = MAX (0, MIN (0xFF, r + off2));
- g = MAX (0, MIN (0xFF, g + off2));
- b = MAX (0, MIN (0xFF, b + off2));
- XPutPixel (image, x, y, (r << 24) | (g << 16) | (b << 8) | a);
- }
- }
-}
-
-
-static void
-adjust_brightness (XImage *image, double amount)
-{
- uint32_t *in = (uint32_t *) image->data;
- int i;
- int end = image->height * image->bytes_per_line / 4;
- for (i = 0; i < end; i++)
- {
- uint32_t p = *in;
- /* #### Why is this ABGR instead of RGBA? */
- uint32_t a = (p >> 24) & 0xFF;
- uint32_t g = (p >> 16) & 0xFF;
- uint32_t b = (p >> 8) & 0xFF;
- uint32_t r = (p >> 0) & 0xFF;
- r = MAX(0, MIN(0xFF, (long) (r * amount)));
- g = MAX(0, MIN(0xFF, (long) (g * amount)));
- b = MAX(0, MIN(0xFF, (long) (b * amount)));
- p = (a << 24) | (g << 16) | (b << 8) | r;
- *in++ = p;
- }
-}
-
-
-static GLfloat
-vector_angle (XYZ a, XYZ b)
-{
- double La = sqrt (a.x*a.x + a.y*a.y + a.z*a.z);
- double Lb = sqrt (b.x*b.x + b.y*b.y + b.z*b.z);
- double cc, angle;
-
- if (La == 0 || Lb == 0) return 0;
- if (a.x == b.x && a.y == b.y && a.z == b.z) return 0;
-
- /* dot product of two vectors is defined as:
- La * Lb * cos(angle between vectors)
- and is also defined as:
- ax*bx + ay*by + az*bz
- so:
- La * Lb * cos(angle) = ax*bx + ay*by + az*bz
- cos(angle) = (ax*bx + ay*by + az*bz) / (La * Lb)
- angle = acos ((ax*bx + ay*by + az*bz) / (La * Lb));
- */
- cc = (a.x*b.x + a.y*b.y + a.z*b.z) / (La * Lb);
- if (cc > 1) cc = 1; /* avoid fp rounding error (1.000001 => sqrt error) */
- angle = acos (cc);
-
- return (angle);
-}
-
-
-/* Creates a grayscale image encoding the day/night terminator for a random
- axial tilt.
- */
-static XImage *
-create_daylight_mask (Display *dpy, Visual *v, int w, int h)
-{
- XImage *image = XCreateImage (dpy, v, 8, ZPixmap, 0, 0, w, h, 8, 0);
- int x, y;
-# undef sun /* Doh */
- XYZ sun;
- double axial_tilt = frand(23.4) / (180/M_PI) * RANDSIGN();
- double dusk = M_PI * 0.035;
- sun.x = 0;
- sun.y = cos (axial_tilt);
- sun.z = sin (axial_tilt);
-
- image->data = (char *) malloc (image->height * image->bytes_per_line);
-
- for (y = 0; y < image->height; y++)
- {
- double lat = -M_PI_2 + (M_PI * (y / (double) image->height));
- double cosL = cos(lat);
- double sinL = sin(lat);
- for (x = 0; x < image->width; x++)
- {
- double lon = -M_PI_2 + (M_PI * 2 * (x / (double) image->width));
- XYZ v;
- double a;
- unsigned long p;
- v.x = cos(lon) * cosL;
- v.y = sin(lon) * cosL;
- v.z = sinL;
- a = vector_angle (sun, v);
- a -= M_PI_2;
- a = (a < -dusk ? 1 : a >= dusk ? 0 : (dusk - a) / (dusk * 2));
- p = 0xFF & (unsigned long) (a * 0xFF);
- XPutPixel (image, x, y, p);
- }
- }
- return image;
-}
-
-
-static void
-load_images (ModeInfo *mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- int i;
-
- if (which_image && !strcmp (which_image, "BUILTIN_FLAT"))
- {
- which_image = strdup("BUILTIN_FLAT");
- which_image2 = strdup("BUILTIN_FLAT");
- }
- else if (which_image && !strcmp (which_image, "BUILTIN_SAT"))
- {
- which_image = strdup("BUILTIN_DAY");
- which_image2 = strdup("BUILTIN_NIGHT");
- }
-
- if (!which_image) which_image = strdup("");
- if (!which_image2) which_image2 = strdup("");
-
- for (i = 0; i < 2; i++)
- {
- char *s = (i == 0 ? which_image : which_image2);
- XImage *image;
- if (!strcmp (s, "BUILTIN_DAY"))
- image = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
- earth_png, sizeof(earth_png));
- else if (!strcmp (s, "BUILTIN_NIGHT"))
- image = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
- earth_night_png,sizeof(earth_night_png));
- else if (!strcmp (s, "BUILTIN") ||
- !strcmp (s, "BUILTIN_FLAT") ||
- (i == 0 && !strcmp (s, "")))
- image = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
- earth_flat_png, sizeof(earth_flat_png));
- else if (!strcmp (s, "NONE"))
- image = 0;
- else if (*s)
- image = file_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi), s);
- else
- image = 0;
-
- /* if (image) fprintf (stderr, "%s: %d: loaded %s\n", progname, i, s); */
-
- if (i == 0)
- gp->day = image;
- else
- gp->night = image;
- }
-
- if (gp->night && !gp->day)
- gp->day = gp->night, gp->night = 0;
-
- gp->nimages = frames;
- gp->current_frame = random() % gp->nimages;
-
- if (gp->nimages < 1)
- gp->nimages = 1;
-
- if (gp->nimages < 2 && gp->night)
- {
- XDestroyImage (gp->night);
- gp->night = 0;
- gp->nimages = 1;
- }
-
- if (! gp->night)
- gp->nimages = 1;
-
- if (do_grid)
- {
- if (gp->day) add_grid_lines (gp->day);
- if (gp->night) add_grid_lines (gp->night);
- }
-
- if (gp->day && gp->night && !gp->dusk)
- {
- if (gp->day->width != gp->night->width ||
- gp->day->height != gp->night->height)
- {
- fprintf (stderr, "%s: day and night images must be the same size"
- " (%dx%d vs %dx%d)\n", progname,
- gp->day->width, gp->day->height,
- gp->night->width, gp->night->height);
- exit (1);
- }
- gp->dusk = create_daylight_mask (MI_DISPLAY (mi), MI_VISUAL (mi),
- gp->day->width, gp->day->height);
- }
-
- /* Make the day image brighter, because that's easier than doing it
- with GL lights. */
- adjust_brightness (gp->day, 1.4);
-
- if (!strcmp (which_image, which_image2))
- /* If day and night are the same image, make night way darker. */
- adjust_brightness (gp->night, 0.2);
- else if (gp->night)
- /* Otherwise make it just a little darker. */
- adjust_brightness (gp->night, 0.7);
-
-
- gp->images = (XImage **) calloc (gp->nimages, sizeof(*gp->images));
-
- /* Create 'cvt', a map that projects each pixel from Equirectangular to
- Dymaxion. It is 2x the width/height of the source images. We iterate
- by half pixel to make sure we hit every pixel in 'out'. It would be
- cleaner to iterate over 'out' instead of over 'in' but
- dymaxionmap-coords.c only goes forward. This is... not super fast.
- */
- {
- double W = 5.5;
- double H = 3 * sqrt(3)/2;
- int x2, y2;
- int w = gp->day->width;
- int h = gp->day->height;
- uint32_t *out;
-
- gp->cvt = XCreateImage (MI_DISPLAY(mi), MI_VISUAL(mi), 32, ZPixmap, 0, 0,
- gp->day->width*2, gp->day->height*2, 32, 0);
- gp->cvt->data = (char *)
- malloc (gp->cvt->height * gp->cvt->bytes_per_line);
- out = (uint32_t *) gp->cvt->data;
-
- for (y2 = 0; y2 < h*2; y2++)
- {
- double y = (double) y2/2;
- double lat = -90 + (180 * (y / (double) h));
- for (x2 = 0; x2 < w*2; x2++)
- {
- double x = (double) x2/2;
- double lon = -180 + (360 * x / w);
- double ox, oy;
- dymaxion_convert (lon, lat, &ox, &oy);
- ox = w - (w * ox / W);
- oy = (h * oy / H);
-
- *out++ = (((((uint32_t) ox) & 0xFFFF) << 16) |
- ((((uint32_t) oy) & 0xFFFF)));
- }
- }
- }
-
- /* A 128 GB iPhone 6s dies at around 540 frames, ~1 GB of XImages.
- A 16 GB iPad Air 2 dies at around 320 frames, ~640 MB.
- Caching on mobile doesn't matter much: we can just run at 100% CPU.
-
- On some systems it would be more efficient to cache the images inside
- a texture on the GPU instead of moving it from RAM to GPU every few
- frames; but on other systems, we'd just run out of GPU memory instead. */
- {
- unsigned long cache_size = (gp->day->width * gp->day->height * 4 *
- gp->nimages);
-# ifdef HAVE_MOBILE
- unsigned long max = 320 * 1024 * 1024L; /* 320 MB */
-# else
- /*unsigned long max = 2 * 1024 * 1024 * 1024L;*/ /* 2 GB */
- unsigned long max = 0x80000000L; /* 2 GB */
-# endif
- gp->cache_p = (cache_size < max);
- }
-}
-
-
-static void
-cache_current_frame (ModeInfo *mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- XImage *blended, *dymaxion;
- int i, x, y, w, h, end, xoff;
- uint32_t *day, *night, *cvt, *out;
- uint8_t *dusk;
-
- if (gp->images[(int) gp->current_frame])
- return;
-
- xoff = (gp->dusk
- ? gp->dusk->width * ((double) gp->current_frame / gp->nimages)
- : 0);
-
- w = gp->day->width;
- h = gp->day->height;
-
- if (!gp->night)
- blended = gp->day;
- else
- {
- /* Blend the foreground and background images through the dusk map.
- */
- blended = XCreateImage (MI_DISPLAY(mi), MI_VISUAL(mi),
- gp->day->depth, ZPixmap, 0, 0, w, h, 32, 0);
- if (!blended) abort();
- blended->data = (char *) malloc (h * blended->bytes_per_line);
- if (!blended->data) abort();
-
- end = blended->height * blended->bytes_per_line / 4;
- day = (uint32_t *) gp->day->data;
- night = (uint32_t *) gp->night->data;
- dusk = (uint8_t *) gp->dusk->data;
- out = (uint32_t *) blended->data;
-
- for (i = 0; i < end; i++)
- {
- uint32_t d = *day++;
- uint32_t n = *night++;
- uint32_t x = i % w;
- uint32_t y = i / w;
- double r = dusk[y * w + ((x + xoff) % w)] / 256.0;
- double r2 = 1-r;
-# define ADD(M) (((unsigned long) \
- ((((d >> M) & 0xFF) * r) + \
- (((n >> M) & 0xFF) * r2))) \
- << M)
- /* #### Why is this ABGR instead of RGBA? */
- *out++ = (0xFF << 24) | ADD(16) | ADD(8) | ADD(0);
-# undef ADD
- }
- }
-
- /* Convert blended Equirectangular to Dymaxion through the 'cvt' map.
- */
- dymaxion = XCreateImage (MI_DISPLAY(mi), MI_VISUAL(mi),
- gp->day->depth, ZPixmap, 0, 0, w, h, 32, 0);
- dymaxion->data = (char *) calloc (h, dymaxion->bytes_per_line);
-
- day = (uint32_t *) blended->data;
- out = (uint32_t *) dymaxion->data;
- cvt = (uint32_t *) gp->cvt->data;
-
- for (y = 0; y < h*2; y++)
- for (x = 0; x < w*2; x++)
- {
- unsigned long m = *cvt++;
- unsigned long dx = (m >> 16) & 0xFFFF;
- unsigned long dy = m & 0xFFFF;
- unsigned long p = day[(y>>1) * w + (x>>1)];
- unsigned long p2 = out[dy * w + dx];
- if (p2 & 0xFF000000)
- /* RGBA nonzero alpha: initialized. Average with existing,
- otherwise the grid lines look terrible. */
- p = (((((p>>24) & 0xFF) + ((p2>>24) & 0xFF)) >> 1) << 24 |
- ((((p>>16) & 0xFF) + ((p2>>16) & 0xFF)) >> 1) << 16 |
- ((((p>> 8) & 0xFF) + ((p2>> 8) & 0xFF)) >> 1) << 8 |
- ((((p>> 0) & 0xFF) + ((p2>> 0) & 0xFF)) >> 1) << 0);
- out[dy * w + dx] = p;
- }
-
- /* Fill in the triangles that are not a part of The World with the
- color of the ocean to avoid texture-tearing on the folded edges.
- */
- out = (uint32_t *) dymaxion->data;
- end = dymaxion->height * dymaxion->bytes_per_line / 4;
- {
- double lat = -48.44, lon = -123.39; /* R'Lyeh */
- int x = (lon + 180) * blended->width / 360.0;
- int y = (lat + 90) * blended->height / 180.0;
- unsigned long ocean = XGetPixel (gp->day, x, y);
- for (i = 0; i < end; i++)
- {
- uint32_t p = *out;
- if (! (p & 0xFF000000)) /* AGBR */
- *out = ocean;
- out++;
- }
- }
-
- if (blended != gp->day)
- XDestroyImage (blended);
-
- gp->images[(int) gp->current_frame] = dymaxion;
-
- if (!gp->cache_p) /* Keep only one image around; recompute every time. */
- {
- i = ((int) gp->current_frame) - 1;
- if (i < 0) i = gp->nimages - 1;
- if (gp->images[i])
- {
- XDestroyImage (gp->images[i]);
- gp->images[i] = 0;
- }
- }
-}
-
-
-static void
-setup_texture (ModeInfo * mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- XImage *ground;
-
- glGenTextures (1, &gp->tex1);
- glBindTexture (GL_TEXTURE_2D, gp->tex1);
-
- /* Must be after glBindTexture */
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- load_images (mi);
-
- glGenTextures (1, &gp->tex2);
- glBindTexture (GL_TEXTURE_2D, gp->tex2);
-
- /* Must be after glBindTexture */
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- /* The underground image can go on flat, without the dymaxion transform. */
- ground = image_data_to_ximage (MI_DISPLAY (mi), MI_VISUAL (mi),
- ground_png, sizeof(ground_png));
- clear_gl_error();
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- /* glPixelStorei(GL_UNPACK_ROW_LENGTH, ground->width); */
- glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
- ground->width, ground->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, ground->data);
- check_gl_error ("ground texture");
- XDestroyImage (ground);
-}
-
-
-static void
-init_stars (ModeInfo *mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- int i, j;
- int width = MI_WIDTH(mi);
- int height = MI_HEIGHT(mi);
- int size = (width > height ? width : height);
- int nstars = size * size / 80;
- int max_size = 3;
- GLfloat inc = 0.5;
- int steps = max_size / inc;
- GLfloat scale = 1;
-
- if (MI_WIDTH(mi) > 2560) { /* Retina displays */
- scale *= 2;
- nstars /= 2;
- }
-
- gp->starlist = glGenLists(1);
- glNewList(gp->starlist, GL_COMPILE);
- for (j = 1; j <= steps; j++)
- {
- glPointSize(inc * j * scale);
- glBegin (GL_POINTS);
- for (i = 0; i < nstars / steps; i++)
- {
- GLfloat d = 0.1;
- GLfloat r = 0.15 + frand(0.3);
- GLfloat g = r + frand(d) - d;
- GLfloat b = r + frand(d) - d;
-
- GLfloat x = frand(1)-0.5;
- GLfloat y = frand(1)-0.5;
- GLfloat z = ((random() & 1)
- ? frand(1)-0.5
- : (BELLRAND(1)-0.5)/12); /* milky way */
- d = sqrt (x*x + y*y + z*z);
- x /= d;
- y /= d;
- z /= d;
- glColor3f (r, g, b);
- glVertex3f (x, y, z);
- gp->starcount++;
- }
- glEnd ();
- }
- glEndList ();
-
- check_gl_error("stars initialization");
-}
-
-
-ENTRYPOINT void
-reshape_planet (ModeInfo *mi, int width, int height)
-{
- GLfloat h = (GLfloat) height / (GLfloat) width;
-
- glViewport(0, 0, (GLint) width, (GLint) height);
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glFrustum(-1.0, 1.0, -h, h, 5.0, 200.0);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- glTranslatef(0.0, 0.0, -40);
-
-# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
- {
- int o = (int) current_device_rotation();
- if (o != 0 && o != 180 && o != -180)
- glScalef (h, h, h);
- }
-# endif
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-}
-
-
-static void
-do_normal2 (ModeInfo *mi, Bool frontp, XYZ a, XYZ b, XYZ c)
-{
- XYZ n = (frontp
- ? calc_normal (a, b, c)
- : calc_normal (b, a, c));
- glNormal3f (n.x, n.y, n.z);
-
-# if 0
- if (frontp && MI_IS_WIREFRAME(mi))
- {
- glBegin (GL_LINES);
- glVertex3f ((a.x + b.x + c.x) / 3,
- (a.y + b.y + c.y) / 3,
- (a.z + b.z + c.z) / 3);
- glVertex3f ((a.x + b.x + c.x) / 3 + n.x,
- (a.y + b.y + c.y) / 3 + n.y,
- (a.z + b.z + c.z) / 3 + n.z);
- glEnd();
- }
-# endif
-}
-
-
-static void
-triangle0 (ModeInfo *mi, Bool frontp, GLfloat stel_ratio, int facemask,
- XYZ *corners_ret)
-{
- /* Render a triangle as six sub-triangles.
- Facemask bits 0-5 indicate which sub-triangle to draw.
-
- A
- / \
- / | \
- / | \
- / 0 | 1 \
- E /_ | _\ F
- / \_ | _/ \
- / 5 \D/ 2 \
- / / | \ \
- / / 4 | 3 \ \
- / / | \ \
- B ----------------------- C
- G
- */
-
- Bool wire = MI_IS_WIREFRAME(mi);
- GLfloat h = sqrt(3) / 2;
- GLfloat h2 = sqrt(h*h - (h/2)*(h/2)) - 0.5;
- XYZ A, B, C, D, E, F, G;
- XYZ tA, tB, tC, tD, tE, tF, tG;
- XYZ a, b, c;
- XYZ ta, tb, tc;
- A.x = 0; A.y = h; A.z = 0;
- B.x = -0.5, B.y = 0; B.z = 0;
- C.x = 0.5, C.y = 0; C.z = 0;
- D.x = 0; D.y = h/3; D.z = 0;
- E.x = -h2; E.y = h/2; E.z = 0;
- F.x = h2; F.y = h/2; F.z = 0;
- G.x = 0; G.y = 0; G.z = 0;
-
- /* When tweaking object XY to stellate, don't change texture coordinates. */
- tA = A; tB = B; tC = C; tD = D; tE = E; tF = F; tG = G;
-
- /* Eyeballed this to find the depth of stellation that seems to most
- approximate a sphere.
- */
- D.z = 0.193 * stel_ratio;
-
- /* We want to raise E, F and G as well but we can't just shift Z:
- we need to keep them on the same vector from the center of the sphere,
- which means also changing F and G's X and Y.
- */
- E.z = F.z = G.z = 0.132 * stel_ratio;
- {
- double magic_x = 0.044;
- double magic_y = 0.028;
- /* G.x stays 0 */
- G.y -= sqrt (magic_x*magic_x + magic_y*magic_y) * stel_ratio;
- E.x -= magic_x * stel_ratio;
- E.y += magic_y * stel_ratio;
- F.x += magic_x * stel_ratio;
- F.y += magic_y * stel_ratio;
- }
-
-
- if (facemask & 1<<0)
- {
- a = E; b = D; c = A;
- ta = tE; tb = tD; tc = tA;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<1)
- {
- a = D; b = F; c = A;
- ta = tD; tb = tF; tc = tA;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<2)
- {
- a = D; b = C; c = F;
- ta = tD; tb = tC; tc = tF;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<3)
- {
- a = G; b = C; c = D;
- ta = tG; tb = tC; tc = tD;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<4)
- {
- a = B; b = G; c = D;
- ta = tB; tb = tG; tc = tD;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<5)
- {
- a = B; b = D; c = E;
- ta = tB; tb = tD; tc = tE;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
- if (facemask & 1<<6)
- {
- a = E; b = D; c = A;
- ta = tE; tb = tD; tc = tA;
- do_normal2 (mi, frontp, a, b, c);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
- glTexCoord2f (ta.x, ta.y); glVertex3f (a.x, a.y, a.z);
- glTexCoord2f (tb.x, tb.y); glVertex3f (b.x, b.y, b.z);
- glTexCoord2f (tc.x, tc.y); glVertex3f (c.x, c.y, c.z);
- glEnd();
- mi->polygon_count++;
- }
-
- if (corners_ret)
- {
- corners_ret[0] = A;
- corners_ret[1] = B;
- corners_ret[2] = C;
- corners_ret[3] = D;
- corners_ret[4] = E;
- corners_ret[5] = F;
- corners_ret[6] = G;
- }
-}
-
-
-/* The segments, numbered arbitrarily from the top left:
- ________ _ ________
- \ /\ /\ \ |\ /
- \ 0 / \ / \3> | \ 5 /
- \ / 1 \ / 2 \| ..|4 \ /-6-..
- ___________\/______\/______\/______\/______\
- | /\ /\ /\ /\ /\
- |7 / \ 9 / \ 11 / \ 13 / \ 15 / \
- | / 8 \ / 10 \ / 12 \ / 14 \ / 16 \
- |/______\/______\/______\/______\/______\
- \ /\ / /\ /\
- \ 17 / \ 18 / / \ 20 / \
- \ / \ / / 19 \ / 21 \
- \/ \/ /______\/______\
-
- Each triangle can be connected to at most two other triangles.
- We start from the middle, #12, and work our way to the edges.
- Its centroid is 0,0.
-
- (Note that dymaxionmap-coords.c uses a different numbering system.)
- */
-static void
-triangle (ModeInfo *mi, int which, Bool frontp,
- GLfloat fold_ratio, GLfloat stel_ratio)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- const GLfloat fg[] = { 1, 1, 1, 1 };
- const GLfloat bg[] = { 0.3, 0.3, 0.3, 1 };
- int a = -1, b = -1;
- GLfloat max = acos (sqrt(5)/3);
- GLfloat rot = -max * fold_ratio / (M_PI/180);
- Bool wire = MI_IS_WIREFRAME(mi);
- XYZ corners[7];
-
- glColor3fv (fg);
- if (!wire)
- glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, fg);
-
- switch (which) {
- case 3: /* One third of the face. */
- triangle0 (mi, frontp, stel_ratio, 1<<3 | 1<<4, corners);
- break;
- case 4: /* Two thirds of the face: convex. */
- triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3 | 1<<4, corners);
- break;
- case 6: /* One half of the face. */
- triangle0 (mi, frontp, stel_ratio, 1<<1 | 1<<2 | 1<<3, corners);
- break;
- case 7: /* One half of the face. */
- triangle0 (mi, frontp, stel_ratio, 1<<2 | 1<<3 | 1<<4, corners);
- break;
- default: /* Full face. */
- triangle0 (mi, frontp, stel_ratio, 0x3F, corners);
- break;
- }
-
- if (wire)
- {
- char tag[20];
- glColor3fv (bg);
- sprintf (tag, "%d", which);
- glPushMatrix();
- glTranslatef (-0.1, 0.2, 0);
- glScalef (0.005, 0.005, 0.005);
- print_texture_string (gp->font_data, tag);
- glPopMatrix();
- mi->polygon_count++;
- }
-
-
- /* The connection hierarchy of the faces starting at the middle, #12. */
- switch (which) {
- case 0: break;
- case 1: a = 0; b = -1; break;
- case 2: a = -1; b = 3; break;
- case 3: break;
- case 4: a = -1; b = 5; break;
- case 5: a = -1; b = 6; break;
- case 7: break;
- case 6: break;
- case 8: a = 17; b = 7; break;
- case 9: a = 8; b = -1; break;
- case 10: a = 18; b = 9; break;
- case 11: a = 10; b = 1; break;
- case 12: a = 11; b = 13; break;
- case 13: a = 2; b = 14; break;
- case 14: a = 15; b = 20; break;
- case 15: a = 4; b = 16; break;
- case 16: break;
- case 17: break;
- case 18: break;
- case 19: break;
- case 20: a = 21; b = 19; break;
- case 21: break;
- default: abort(); break;
- }
-
- if (a != -1)
- {
- glPushMatrix();
- glTranslatef (-0.5, 0, 0); /* Move model matrix to upper left */
- glRotatef (60, 0, 0, 1);
- glTranslatef ( 0.5, 0, 0);
-
- glMatrixMode(GL_TEXTURE);
- /* glPushMatrix(); */
- glTranslatef (-0.5, 0, 0); /* Move texture matrix the same way */
- glRotatef (60, 0, 0, 1);
- glTranslatef ( 0.5, 0, 0);
-
- glMatrixMode(GL_MODELVIEW);
-
- glRotatef (rot, 1, 0, 0);
- triangle (mi, a, frontp, fold_ratio, stel_ratio);
-
- /* This should just be a PopMatrix on the TEXTURE stack, but
- fucking iOS has GL_MAX_TEXTURE_STACK_DEPTH == 4! WTF!
- So we have to undo our rotations and translations manually.
- */
- glMatrixMode(GL_TEXTURE);
- /* glPopMatrix(); */
- glTranslatef (-0.5, 0, 0);
- glRotatef (-60, 0, 0, 1);
- glTranslatef (0.5, 0, 0);
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
- if (b != -1)
- {
- glPushMatrix();
- glTranslatef (0.5, 0, 0); /* Move model matrix to upper right */
- glRotatef (-60, 0, 0, 1);
- glTranslatef (-0.5, 0, 0);
-
- glMatrixMode(GL_TEXTURE);
- /* glPushMatrix(); */
- glTranslatef (0.5, 0, 0); /* Move texture matrix the same way */
- glRotatef (-60, 0, 0, 1);
- glTranslatef (-0.5, 0, 0);
-
- glMatrixMode(GL_MODELVIEW);
-
- glRotatef (rot, 1, 0, 0);
- triangle (mi, b, frontp, fold_ratio, stel_ratio);
-
- /* See above. Grr. */
- glMatrixMode(GL_TEXTURE);
- /* glPopMatrix(); */
- glTranslatef (0.5, 0, 0);
- glRotatef (60, 0, 0, 1);
- glTranslatef (-0.5, 0, 0);
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
-
- /* Draw a border around the edge of the world.
- */
- if (!wire && frontp && stel_ratio == 0 && fold_ratio < 0.95)
- {
- int edges = 0;
- GLfloat c[] = { 0, 0.2, 0.5, 1 };
- c[3] = 1-fold_ratio;
-
- switch (which)
- {
- case 0: edges = 1<<0 | 1<<2; break;
- case 1: edges = 1<<2; break;
- case 2: edges = 1<<0; break;
- case 3: edges = 1<<3 | 1<<4; break;
- case 4: edges = 1<<3 | 1<<5; break;
- case 5: edges = 1<<0 | 1<<6; break;
- case 6: edges = 1<<2 | 1<<7; break;
- case 16: edges = 1<<0 | 1<<2; break;
- case 21: edges = 1<<0 | 1<<2; break;
- case 19: edges = 1<<0 | 1<<2; break;
- case 12: edges = 1<<1; break;
- case 18: edges = 1<<0 | 1<<2; break;
- case 17: edges = 1<<0 | 1<<2; break;
- case 7: edges = 1<<8 | 1<<9; break;
- case 9: edges = 1<<2; break;
- default: break;
- }
-
- glDisable (GL_TEXTURE_2D);
- glDisable (GL_LIGHTING);
- glLineWidth (2);
- glColor4fv (c);
- glBegin (GL_LINES);
- if (edges & 1<<0)
- {
- glVertex3f (corners[0].x, corners[0].y, corners[0].z);
- glVertex3f (corners[1].x, corners[1].y, corners[1].z);
- }
- if (edges & 1<<1)
- {
- glVertex3f (corners[1].x, corners[1].y, corners[1].z);
- glVertex3f (corners[2].x, corners[2].y, corners[2].z);
- }
- if (edges & 1<<2)
- {
- glVertex3f (corners[2].x, corners[2].y, corners[2].z);
- glVertex3f (corners[0].x, corners[0].y, corners[0].z);
- }
- if (edges & 1<<3)
- {
- glVertex3f (corners[1].x, corners[1].y, corners[1].z);
- glVertex3f (corners[3].x, corners[3].y, corners[3].z);
- }
- if (edges & 1<<4)
- {
- glVertex3f (corners[3].x, corners[3].y, corners[3].z);
- glVertex3f (corners[2].x, corners[2].y, corners[2].z);
- }
- if (edges & 1<<5)
- {
- glVertex3f (corners[3].x, corners[3].y, corners[3].z);
- glVertex3f (corners[0].x, corners[0].y, corners[0].z);
- }
- if (edges & 1<<6)
- {
- glVertex3f (corners[0].x, corners[0].y, corners[0].z);
- glVertex3f (corners[5].x, corners[5].y, corners[5].z);
- }
- if (edges & 1<<7)
- {
- glVertex3f (corners[0].x, corners[0].y, corners[0].z);
- glVertex3f (corners[6].x, corners[6].y, corners[6].z);
- }
- if (edges & 1<<8)
- {
- glVertex3f (corners[1].x, corners[1].y, corners[1].z);
- glVertex3f (corners[5].x, corners[5].y, corners[5].z);
- }
- if (edges & 1<<9)
- {
- glVertex3f (corners[5].x, corners[5].y, corners[5].z);
- glVertex3f (corners[2].x, corners[2].y, corners[2].z);
- }
- glEnd();
- glEnable (GL_TEXTURE_2D);
- glEnable (GL_LIGHTING);
- }
-}
-
-
-static void
-draw_triangles (ModeInfo *mi, GLfloat fold_ratio, GLfloat stel_ratio)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- Bool wire = MI_IS_WIREFRAME(mi);
- GLfloat h = sqrt(3) / 2;
- GLfloat c = h / 3;
-
- glTranslatef (0, -h/3, 0); /* Center on face 12 */
-
- /* When closed, center on midpoint of icosahedron. Eyeballed this. */
- glTranslatef (0, 0, fold_ratio * 0.754);
-
- glFrontFace (GL_CCW);
-
- /* Adjust the texture matrix so that it has the same coordinate space
- as the model. */
-
- glMatrixMode(GL_TEXTURE);
- glPushMatrix();
- {
- GLfloat texw = 5.5;
- GLfloat texh = 3 * h;
- GLfloat midx = 2.5;
- GLfloat midy = 3 * c;
- glScalef (1/texw, -1/texh, 1);
- glTranslatef (midx, midy, 0);
- }
- glMatrixMode(GL_MODELVIEW);
-
-
-
- /* Front faces */
-
- if (wire)
- glDisable (GL_TEXTURE_2D);
- else if (do_texture)
- {
- glEnable (GL_TEXTURE_2D);
- glBindTexture (GL_TEXTURE_2D, gp->tex1);
- }
- else
- glDisable (GL_TEXTURE_2D);
-
- triangle (mi, 12, True, fold_ratio, stel_ratio);
-
- /* Back faces */
-
- if (wire)
- glDisable (GL_TEXTURE_2D);
- else if (do_texture)
- {
- glEnable (GL_TEXTURE_2D);
- glBindTexture (GL_TEXTURE_2D, gp->tex2);
- }
- else
- glDisable (GL_TEXTURE_2D);
-
- glFrontFace (GL_CW);
-
- triangle (mi, 12, False, fold_ratio, 0);
-
- glMatrixMode(GL_TEXTURE);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
-}
-
-
-static void
-align_axis (ModeInfo *mi, int undo)
-{
- /* Rotate so that an axis is lined up with the north and south poles
- on the map, which are not in the center of their faces, or any
- other easily computable spot. */
-
- GLfloat r1 = 20.5;
- GLfloat r2 = 28.5;
-
- if (undo)
- {
- glRotatef (-r2, 0, 1, 0);
- glRotatef ( r2, 1, 0, 0);
- glRotatef (-r1, 1, 0, 0);
- }
- else
- {
- glRotatef (r1, 1, 0, 0);
- glRotatef (-r2, 1, 0, 0);
- glRotatef ( r2, 0, 1, 0);
- }
-}
-
-
-static void
-draw_axis (ModeInfo *mi)
-{
- GLfloat s;
- glDisable (GL_TEXTURE_2D);
- glDisable (GL_LIGHTING);
- glPushMatrix();
-
- align_axis (mi, 0);
- glTranslatef (0.34, 0.39, -0.61);
-
- s = 0.96;
- glScalef (s, s, s); /* tighten up the enclosing sphere */
-
- glLineWidth (1);
- glColor3f (0.5, 0.5, 0);
-
- glRotatef (90, 1, 0, 0); /* unit_sphere is off by 90 */
- glRotatef (9.5, 0, 1, 0); /* line up the time zones */
- glFrontFace (GL_CCW);
- unit_sphere (12, 24, True);
- glBegin(GL_LINES);
- glVertex3f(0, -2, 0);
- glVertex3f(0, 2, 0);
- glEnd();
-
- glPopMatrix();
-}
-
-
-
-
-ENTRYPOINT Bool
-planet_handle_event (ModeInfo *mi, XEvent *event)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
-
- if (gltrackball_event_handler (event, gp->trackball,
- MI_WIDTH (mi), MI_HEIGHT (mi),
- &gp->button_down_p))
- return True;
- else if (event->xany.type == KeyPress)
- {
- KeySym keysym;
- char c = 0;
- XLookupString (&event->xkey, &c, 1, &keysym, 0);
- if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
- {
- int i;
- double cf = gp->current_frame;
-
- /* Switch between the satellite and flat map, preserving position. */
- if (gp->day) XDestroyImage (gp->day);
- if (gp->night) XDestroyImage (gp->night);
- if (gp->cvt) XDestroyImage (gp->cvt);
- gp->day = 0;
- gp->night = 0;
- gp->cvt = 0;
-
- for (i = 0; i < gp->nimages; i++)
- if (gp->images[i]) XDestroyImage (gp->images[i]);
- free (gp->images);
- gp->images = 0;
-
- which_image = strdup (!strcmp (which_image, "BUILTIN_DAY")
- ? "BUILTIN_FLAT" : "BUILTIN_DAY");
- which_image2 = strdup (!strcmp (which_image2, "BUILTIN_NIGHT")
- ? "BUILTIN_FLAT" : "BUILTIN_NIGHT");
- load_images (mi);
- gp->current_frame = cf;
-# if 0
- switch (gp->state) {
- case FLAT: case ICO: case STEL: case AXIS: case ICO2:
- gp->ratio = 1;
- break;
- default:
- break;
- }
-# endif
- return True;
- }
- }
-
- return False;
-}
-
-
-ENTRYPOINT void
-init_planet (ModeInfo * mi)
-{
- planetstruct *gp;
- int screen = MI_SCREEN(mi);
- Bool wire = MI_IS_WIREFRAME(mi);
-
- MI_INIT (mi, planets);
- gp = &planets[screen];
-
- if ((gp->glx_context = init_GL(mi)) != NULL) {
- reshape_planet(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
- }
-
- gp->state = STARTUP;
- gp->ratio = 0;
- gp->font_data = load_texture_font (mi->dpy, "labelFont");
- gp->delay = MI_DELAY(mi);
-
- {
- double spin_speed = 0.1;
- double wander_speed = 0.002;
- gp->rot = make_rotator (do_roll ? spin_speed : 0,
- do_roll ? spin_speed : 0,
- 0, 1,
- do_wander ? wander_speed : 0,
- False);
- gp->rot2 = make_rotator (0, 0, 0, 0, wander_speed, False);
- gp->trackball = gltrackball_init (True);
- }
-
- if (wire)
- do_texture = False;
-
- if (do_texture)
- setup_texture (mi);
-
- if (do_stars)
- init_stars (mi);
-
- glEnable (GL_DEPTH_TEST);
- glEnable (GL_NORMALIZE);
- glEnable (GL_CULL_FACE);
-
- if (!wire)
- {
- GLfloat pos[4] = {1, 1, 1, 0};
- GLfloat amb[4] = {0, 0, 0, 1};
- GLfloat dif[4] = {1, 1, 1, 1};
- GLfloat spc[4] = {0, 1, 1, 1};
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glLightfv(GL_LIGHT0, GL_POSITION, pos);
- glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
- }
-}
-
-
-static GLfloat
-ease_fn (GLfloat r)
-{
- return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */
-}
-
-
-static GLfloat
-ease_ratio (GLfloat r)
-{
- GLfloat ease = 0.35;
- if (r <= 0) return 0;
- else if (r >= 1) return 1;
- else if (r <= ease) return ease * ease_fn (r / ease);
- else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease);
- else return r;
-}
-
-
-ENTRYPOINT void
-draw_planet (ModeInfo * mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- int wire = MI_IS_WIREFRAME(mi);
- Display *dpy = MI_DISPLAY(mi);
- Window window = MI_WINDOW(mi);
- long delay = gp->delay;
- double x, y, z;
-
- if (!gp->glx_context)
- return;
-
- glDrawBuffer(GL_BACK);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glXMakeCurrent (dpy, window, *gp->glx_context);
-
- mi->polygon_count = 0;
-
- if (! gp->button_down_p)
- switch (gp->state) {
- case STARTUP: gp->ratio += speed * 0.01; break;
- case FLAT: gp->ratio += speed * 0.005 *
- /* Stay flat longer if animating day and night. */
- (gp->nimages <= 1 ? 1 : 0.3);
- break;
- case FOLD: gp->ratio += speed * 0.01; break;
- case ICO: gp->ratio += speed * 0.01; break;
- case STEL_IN: gp->ratio += speed * 0.05; break;
- case STEL: gp->ratio += speed * 0.01; break;
- case STEL_OUT: gp->ratio += speed * 0.07; break;
- case ICO2: gp->ratio += speed * 0.07; break;
- case AXIS: gp->ratio += speed * 0.02; break;
- case SPIN: gp->ratio += speed * 0.005; break;
- case UNFOLD: gp->ratio += speed * 0.01; break;
- default: abort();
- }
-
- if (gp->ratio > 1.0)
- {
- gp->ratio = 0;
- switch (gp->state) {
- case STARTUP: gp->state = FLAT; break;
- case FLAT: gp->state = FOLD; break;
- case FOLD: gp->state = ICO; break;
- case ICO: gp->state = STEL_IN; break;
- case STEL_IN: gp->state = STEL; break;
- case STEL:
- {
- int i = (random() << 9) % 7;
- gp->state = (i < 3 ? STEL_OUT :
- i < 6 ? SPIN : AXIS);
- }
- break;
- case AXIS: gp->state = STEL_OUT; break;
- case SPIN: gp->state = STEL_OUT; break;
- case STEL_OUT: gp->state = ICO2; break;
- case ICO2: gp->state = UNFOLD; break;
- case UNFOLD: gp->state = FLAT; break;
- default: abort();
- }
- }
-
- glEnable(GL_LINE_SMOOTH);
- glEnable(GL_POINT_SMOOTH);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- glCullFace(GL_BACK);
-
- glPushMatrix();
-
- gltrackball_rotate (gp->trackball);
- glRotatef (current_device_rotation(), 0, 0, 1);
-
-# ifdef HAVE_MOBILE /* Fill more of the screen. */
- {
- int size = MI_WIDTH(mi) < MI_HEIGHT(mi)
- ? MI_WIDTH(mi) : MI_HEIGHT(mi);
- GLfloat s = (size > 768 ? 1.4 : /* iPad */
- 2); /* iPhone */
- glScalef (s, s, s);
- if (MI_WIDTH(mi) < MI_HEIGHT(mi))
- glRotatef (90, 0, 0, 1);
- }
-# endif
-
- if (gp->state != STARTUP)
- {
- get_position (gp->rot, &x, &y, &z, !gp->button_down_p);
- x = (x - 0.5) * 3;
- y = (y - 0.5) * 3;
- z = 0;
- glTranslatef(x, y, z);
- }
-
- if (do_roll && gp->state != STARTUP)
- {
- double max = 65;
- get_position (gp->rot2, &x, &y, 0, !gp->button_down_p);
- glRotatef (max/2 - x*max, 1, 0, 0);
- glRotatef (max/2 - y*max, 0, 1, 0);
- }
-
- if (do_stars)
- {
- glDisable(GL_TEXTURE_2D);
- glDisable(GL_LIGHTING);
- glPushMatrix();
- glScalef (60, 60, 60);
- glRotatef (90, 1, 0, 0);
- glRotatef (35, 1, 0, 0);
- glCallList (gp->starlist);
- mi->polygon_count += gp->starcount;
- glPopMatrix();
- glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- if (! wire)
- {
- glEnable (GL_LIGHTING);
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
- if (do_texture)
- glEnable(GL_TEXTURE_2D);
-
- if (do_texture /* && !gp->button_down_p */)
- {
- int i;
- int prev = gp->current_frame;
-
- /* By default, advance terminator by about an hour every 5 seconds. */
- gp->current_frame += 0.1 * speed * (gp->nimages / 360.0);
- while (gp->current_frame >= gp->nimages)
- gp->current_frame -= gp->nimages;
- i = gp->current_frame;
-
- /* Load the current image into the texture.
- */
- if (i != prev || !gp->images[i])
- {
- double start = double_time();
- cache_current_frame (mi);
-
- glBindTexture (GL_TEXTURE_2D, gp->tex1);
-
- /* Must be after glBindTexture */
- glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA,
- gp->images[i]->width,
- gp->images[i]->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE,
- gp->images[i]->data);
- check_gl_error ("texture");
-
- /* If caching the image took a bunch of time, deduct that from
- our per-frame delay to keep the timing a little smoother. */
- delay -= 1000000 * (double_time() - start);
- if (delay < 0) delay = 0;
- }
- }
-
- glTranslatef (-0.5, -0.4, 0);
- glScalef (2.6, 2.6, 2.6);
-
- {
- GLfloat fold_ratio = 0;
- GLfloat stel_ratio = 0;
- switch (gp->state) {
- case FOLD: fold_ratio = gp->ratio; break;
- case UNFOLD: fold_ratio = 1 - gp->ratio; break;
- case ICO: case ICO2: fold_ratio = 1; break;
- case STEL: case AXIS: case SPIN: fold_ratio = 1; stel_ratio = 1; break;
- case STEL_IN: fold_ratio = 1; stel_ratio = gp->ratio; break;
- case STEL_OUT: fold_ratio = 1; stel_ratio = 1 - gp->ratio; break;
- case STARTUP: /* Tilt in from flat */
- glRotatef (-90 * ease_ratio (1 - gp->ratio), 1, 0, 0);
- break;
-
- default: break;
- }
-
-# ifdef HAVE_MOBILE /* Enlarge the icosahedron a bit to make it more visible */
- {
- GLfloat s = 1 + 1.3 * ease_ratio (fold_ratio);
- glScalef (s, s, s);
- }
-# endif
-
- if (gp->state == SPIN)
- {
- align_axis (mi, 0);
- glRotatef (ease_ratio (gp->ratio) * 360 * 3, 0, 0, 1);
- align_axis (mi, 1);
- }
-
- draw_triangles (mi, ease_ratio (fold_ratio), ease_ratio (stel_ratio));
-
- if (gp->state == AXIS)
- draw_axis(mi);
- }
-
- glPopMatrix();
-
- if (mi->fps_p) do_fps (mi);
- glFinish();
- glXSwapBuffers(dpy, window);
-
- MI_DELAY(mi) = delay;
-}
-
-
-ENTRYPOINT void
-free_planet (ModeInfo * mi)
-{
- planetstruct *gp = &planets[MI_SCREEN(mi)];
- int i;
-
- if (!gp->glx_context) return;
- glXMakeCurrent (MI_DISPLAY(mi), MI_WINDOW(mi), *gp->glx_context);
-
- if (gp->font_data) free_texture_font (gp->font_data);
- if (gp->trackball) gltrackball_free (gp->trackball);
- if (gp->rot) free_rotator (gp->rot);
- if (gp->rot2) free_rotator (gp->rot2);
-
- if (gp->day) XDestroyImage (gp->day);
- if (gp->night) XDestroyImage (gp->night);
- if (gp->dusk) XDestroyImage (gp->dusk);
- if (gp->cvt) XDestroyImage (gp->cvt);
-
- if (gp->images) {
- for (i = 0; i < gp->nimages; i++)
- if (gp->images[i]) XDestroyImage (gp->images[i]);
- free (gp->images);
- }
-
- if (glIsList(gp->starlist)) glDeleteLists(gp->starlist, 1);
- if (gp->tex1) glDeleteTextures (1, &gp->tex1);
- if (gp->tex2) glDeleteTextures (1, &gp->tex2);
-}
-
-
-XSCREENSAVER_MODULE_2 ("DymaxionMap", dymaxionmap, planet)
-
-#endif