From 6a32252403781b303d4ebd195932ce39c5b1c08e Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Tue, 30 Jul 2019 16:03:58 +0200 Subject: Update to 5.43 --- hacks/glx/gravitywell.c | 767 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 767 insertions(+) create mode 100644 hacks/glx/gravitywell.c (limited to 'hacks/glx/gravitywell.c') diff --git a/hacks/glx/gravitywell.c b/hacks/glx/gravitywell.c new file mode 100644 index 0000000..7078764 --- /dev/null +++ b/hacks/glx/gravitywell.c @@ -0,0 +1,767 @@ +/* gravitywell, Copyright (c) 2019 Jamie Zawinski + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. No representations are made about the suitability of this + * software for any purpose. It is provided "as is" without express or + * implied warranty. + */ + +#define DEFAULTS "*delay: 30000 \n" \ + "*count: 15 \n" \ + "*gridColor: #00FF00\n" \ + "*gridColor2: #FF0000\n" \ + "*showFPS: False \n" \ + "*wireframe: False \n" + +# define release_gw 0 +#undef countof +#define countof(x) (sizeof((x))/sizeof((*x))) + +#define DEF_SPEED "1.0" +#define DEF_RESOLUTION "1.0" +#define DEF_GRID_SIZE "1.0" + +#include "xlockmore.h" +#include "gltrackball.h" +#include "colors.h" +#include "hsv.h" + +#include + +#define ASSERT(x) + +#ifdef USE_GL /* whole file */ + +typedef struct { + GLfloat mass; + GLfloat ro2, rm2, ri2; /* outer/middle/inner */ + GLfloat ro, radius; + GLfloat x, y, dx, dy; + GLfloat surface_gravity, depth; +} star; + +typedef struct { + GLXContext *glx_context; + trackball_state *user_trackball; + Bool button_down_p; + int nstars; + star *stars; + int grid_w, grid_h; + GLfloat *grid; + char *segs; + GLfloat *vtx, *col; + GLfloat color[4]; + int ncolors; + XColor *colors; +} gw_configuration; + +static gw_configuration *bps = NULL; + +static GLfloat speed, resolution, grid_size; + +#define RESOLUTION_BASE 512 +#define GRID_SIZE_BASE 7 +#define SPEED_BASE 2.5 +#define MASS_EPSILON 0.03 +#define SLOPE_EPSILON 0.06 +#define GRID_SEG 16u /* Power-of-two here is faster. */ +#define MAX_MASS_COLOR 120 + +static XrmOptionDescRec opts[] = { + { "-speed", ".speed", XrmoptionSepArg, 0 }, + { "-resolution", ".resolution", XrmoptionSepArg, 0 }, + { "-grid-size", ".gridSize", XrmoptionSepArg, 0 }, +}; + +static argtype vars[] = { + {&speed, "speed", "Speed", DEF_SPEED, t_Float}, + {&resolution, "resolution", "Resolution", DEF_RESOLUTION, t_Float}, + {&grid_size, "gridSize", "GridSize", DEF_GRID_SIZE, t_Float}, +}; + +ENTRYPOINT ModeSpecOpt gw_opts = { + countof(opts), opts, countof(vars), vars, NULL}; + + +#define MAX(a,b) ((a)>(b)?(a):(b)) +#define MIN(a,b) ((a)<(b)?(a):(b)) +#define WCLIP(x,hi) MIN(MAX((int)(x),0),(hi)) + +/* Window management, etc + */ +ENTRYPOINT void +reshape_gw (ModeInfo *mi, int width, int height) +{ + GLfloat h = (GLfloat) height / (GLfloat) width; + int y = 0; + + if (width > height * 5) { /* tiny window: show middle */ + height = width * 9/16; + y = -height/2; + h = height / (GLfloat) width; + } + + glViewport (0, y, width, height); + + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective (40, 1/h, 10, 1000); + + glMatrixMode(GL_MODELVIEW); + glLoadIdentity(); + gluLookAt( 0, 0, 30, + 0, 0, 0, + 0, 1, 0); + + glClear(GL_COLOR_BUFFER_BIT); +} + + +ENTRYPOINT Bool +gw_handle_event (ModeInfo *mi, XEvent *event) +{ + gw_configuration *bp = &bps[MI_SCREEN(mi)]; + + if (gltrackball_event_handler (event, bp->user_trackball, + MI_WIDTH (mi), MI_HEIGHT (mi), + &bp->button_down_p)) + return True; + return False; +} + + +static void +parse_color (ModeInfo *mi, char *key, GLfloat color[4]) +{ + XColor xcolor; + char *string = get_string_resource (mi->dpy, key, "Color"); + if (!XParseColor (mi->dpy, mi->xgwa.colormap, string, &xcolor)) + { + fprintf (stderr, "%s: unparsable color in %s: %s\n", progname, + key, string); + exit (1); + } + free (string); + + color[0] = xcolor.red / 65536.0; + color[1] = xcolor.green / 65536.0; + color[2] = xcolor.blue / 65536.0; + color[3] = 1; +} + + +static void +new_star (const gw_configuration *bp, star *s) +{ + int w = bp->grid_w * GRID_SEG; + + s->radius = 2 * (2 + frand(3) + frand(3) + frand(3)); + s->mass = s->radius * 150 * (2 + frand(3) + frand(3) + frand(3)); + + s->ro2 = s->mass / MASS_EPSILON; + s->ro = sqrt (s->ro2); + s->rm2 = pow (s->mass * (2.0f / SLOPE_EPSILON), 2.0f / 3.0f); + s->ri2 = s->radius * s->radius; + if (s->rm2 < s->ri2) + s->rm2 = s->ri2; + if (s->ro2 < s->rm2) + s->ro2 = s->rm2; + + s->x = w * (s == bp->stars ? 0.5 : (0.35 + frand(0.3))); + s->dx = ((frand(1.0) - 0.5) * 0.1) / resolution; + s->dy = (0.1 + frand(0.6)) / resolution; + + /* What the experienced gravitation would be at the surface of the + star, were the mass actually held in a singularity at its center. + */ + s->surface_gravity = s->mass / s->ri2; + s->depth = s->surface_gravity; +} + + +static void +move_stars (ModeInfo *mi) +{ + gw_configuration *bp = &bps[MI_SCREEN(mi)]; + int w = bp->grid_w * GRID_SEG; + int h = bp->grid_h * GRID_SEG; + int i; + + for (i = 0; i < bp->nstars; i++) + { + star *s = &bp->stars[i]; + /* Move stars off screen until most of their influence fades */ + GLfloat off = speed * SPEED_BASE * resolution; + s->x += s->dx * off; + s->y += s->dy * off; + + if (s->x < -s->ro || + s->y < -s->ro || + s->x >= w + s->ro || + s->y >= h + s->ro) + { + new_star (bp, s); + s->y = -s->ro; + } + } +} + + +static void +calc_o (gw_configuration *bp, GLfloat mass, GLfloat cx, GLfloat y02, + unsigned from, unsigned to) +{ + GLfloat x0 = cx - from * GRID_SEG; + GLfloat g0 = mass / (x0*x0 + y02); + unsigned x; + + ASSERT (to <= bp->grid_w || to <= bp->grid_h); + + for (x = from; x < to; x++) + { + GLfloat *g = &bp->grid[x * GRID_SEG]; + GLfloat g1; + + x0 = cx - (x + 1) * GRID_SEG; + g1 = mass / (x0*x0 + y02); + + g[0] += g0; + if (bp->segs[x]) + { + GLfloat d = (g1 - g0) / GRID_SEG; + unsigned i; + for(i = 1; i != GRID_SEG; i++) + { + g0 += d; + g[i] += g0; + } + } + g0 = g1; + } +} + + +static void +make_hires (gw_configuration *bp, unsigned from, unsigned to, unsigned w) +{ + unsigned x; + + /* One bigger than from/to so that there's a good angle between the middle + and inner zones. + + Don't make the last GRID_SEG high-res. This keeps the length consistent. + */ + if (from) + from--; + from = MIN(from / GRID_SEG, w - 1); + to = MIN(to / GRID_SEG + 1, w - 1); + + ASSERT (to <= bp->grid_w - 1 || to <= bp->grid_h - 1); + + for (x = from; x < to; x++) + { + if (! bp->segs[x]) + { + GLfloat *g = &bp->grid[x * GRID_SEG]; + GLfloat g0 = g[0], g1 = g[GRID_SEG]; + GLfloat d = (g1 - g0) / GRID_SEG; + unsigned i; + for (i = 1; i != GRID_SEG; i++) + { + g0 += d; + g[i] = g0; + } + bp->segs[x] = True; + } + } +} + + +static void +calc_m (gw_configuration *bp, GLfloat mass, GLfloat cx, GLfloat y02, + unsigned from, unsigned to) +{ + GLfloat *gridp = bp->grid; + unsigned x; + + ASSERT (to <= bp->grid_w * GRID_SEG + 1 || to <= bp->grid_h * GRID_SEG + 1); + + for (x = from; x < to; x++) + { + /* Inverse square of distance from mass as a point source */ + GLfloat x0 = cx - x; + gridp[x] += mass / (x0*x0 + y02); + } +} + + +#define EASE(r) (sin ((r) * M_PI_2)) + +static void +draw_row (ModeInfo *mi, int w, int y, Bool swap) +{ + gw_configuration *bp = &bps[MI_SCREEN(mi)]; + int i; + int x; + int polys; + int w2 = w * GRID_SEG; + + GLfloat *vtx_x; + GLfloat *vtx_y; + GLfloat *gridp = bp->grid; + memset (gridp, 0, w2 * sizeof(*gridp)); + memset (bp->segs, 0, w); + + for (i = 0; i < bp->nstars; i++) + { + star *s = &bp->stars[i]; + GLfloat cx, cy; + unsigned olo, ohi, mlo, mhi, ilo, ihi; + GLfloat mass, max; + /* Move stars off screen until most of their influence fades */ + GLfloat ro, rm, ri; + + GLfloat y0; + GLfloat y02; + + if (swap) + { + cy = s->x; + cx = s->y; + } + else + { + cx = s->x; + cy = s->y; + } + mass = s->mass; + max = s->surface_gravity; + + y0 = cy - y; + y02 = y0 * y0; + + if (y02 > s->ro2) continue; + + ro = sqrtf (s->ro2 - y02); + olo = WCLIP((cx - ro) / GRID_SEG + 1, w); /* GLfloat -> int */ + ohi = WCLIP((cx + ro) / GRID_SEG + 1, w); + + rm = s->rm2 > y02 ? sqrtf (s->rm2 - y02) : 0; + mlo = WCLIP((cx - rm) + 1, w2); + mhi = WCLIP((cx + rm) + 1, w2); + + ASSERT (mlo <= mhi); + + if (mlo != mhi) + { + ri = s->ri2 > y02 ? sqrtf (s->ri2 - y02) : 0; + ilo = WCLIP(cx - ri + 1, w2); + ihi = WCLIP(cx + ri + 1, w2); + + mlo -= mlo % GRID_SEG; + mhi += GRID_SEG - 1; + mhi -= mhi % GRID_SEG; + + /* These go first. */ + make_hires (bp, mlo, ilo, w); + make_hires (bp, ihi, mhi, w); + + calc_m (bp, mass, cx, y02, mlo, ilo); + calc_m (bp, mass, cx, y02, ihi, mhi); + + /* This does a bit more work than it needs to. */ + for (x = ilo; x < ihi; x++) + gridp[x] += max; + } + + calc_o (bp, mass, cx, y02, olo, mlo / GRID_SEG); + calc_o (bp, mass, cx, y02, mhi / GRID_SEG, ohi); + } + + if (swap) + { + vtx_y = bp->vtx; + vtx_x = bp->vtx + 1; + } + else + { + vtx_x = bp->vtx; + vtx_y = bp->vtx + 1; + } + +# define COLOR_CODE 0 + +# if COLOR_CODE + { + unsigned grid_max = bp->grid_w > bp->grid_h ? bp->grid_w : bp->grid_h; + GLfloat *color = malloc(sizeof(GLfloat) * 4 * (grid_max * GRID_SEG + 1)); + glEnableClientState (GL_COLOR_ARRAY); + glColorPointer (4, GL_FLOAT, 0, color); +# endif + + ASSERT (! bp->segs[w - 1]); + + polys = 0; + for (x = 0; x != w; x++) + { + if (! bp->segs[x]) + { + int ci; + size_t vp = polys * 3; + size_t cp = polys * 4; +# if COLOR_CODE + GLfloat slope = 0; + if (x != 0) + slope += fabs(gridp[x * GRID_SEG] - gridp[(x - 1) * GRID_SEG]); + if (x != w - 1) + slope += fabs(gridp[(x + 1) * GRID_SEG] - gridp[x * GRID_SEG]); + slope = 1 - (slope / (SLOPE_EPSILON * 2)); + + color[cp] = slope; + color[cp + 1] = slope; + color[cp + 2] = 1; + color[cp + 3] = 1; +# endif + vtx_x[vp] = x * GRID_SEG; + bp->vtx[vp + 2] = gridp[x * GRID_SEG]; + polys += 1; + + ci = EASE (bp->vtx[vp + 2] / MAX_MASS_COLOR) * bp->ncolors; + bp->col[cp] = bp->colors[ci].red / 65536.0; + bp->col[cp+1] = bp->colors[ci].green / 65536.0; + bp->col[cp+2] = bp->colors[ci].blue / 65536.0; + bp->col[cp+3] = 1; + } + else + { + for(i = 0; i != GRID_SEG; i++) + { + int ci; + size_t vp = (polys + i) * 3; + size_t cp = (polys + i) * 4; +# if COLOR_CODE + color[cp] = 1; + color[cp + 1] = 0.75; + color[cp + 2] = 0; + color[cp + 3] = 1; +# endif + vtx_x[vp] = x * GRID_SEG + i; + bp->vtx[vp + 2] = gridp[x * GRID_SEG + i]; + + ci = EASE (bp->vtx[vp + 2] / MAX_MASS_COLOR) * bp->ncolors; + bp->col[cp] = bp->colors[ci].red / 65536.0; + bp->col[cp+1] = bp->colors[ci].green / 65536.0; + bp->col[cp+2] = bp->colors[ci].blue / 65536.0; + bp->col[cp+3] = 1; + } + polys += GRID_SEG; + } + } + + for (i = 0; i < polys; i++) + vtx_y[i * 3] = y; /* + random() * (MASS_EPSILON / (MAXRAND)); */ + + mi->polygon_count += polys; + glDrawArrays (GL_LINE_STRIP, 0, polys); + +# if COLOR_CODE + glDisableClientState (GL_COLOR_ARRAY); + free (color); + } +# endif +} + + +ENTRYPOINT void +init_gw (ModeInfo *mi) +{ + gw_configuration *bp; + unsigned grid_max, vtx_max; + int i; + MI_INIT (mi, bps); + + bp = &bps[MI_SCREEN(mi)]; + + bp->glx_context = init_GL(mi); + + reshape_gw (mi, MI_WIDTH(mi), MI_HEIGHT(mi)); + + glShadeModel(GL_SMOOTH); + + glEnable(GL_DEPTH_TEST); + glEnable(GL_NORMALIZE); + glEnable(GL_CULL_FACE); + + { + int h1, h2; + double s1, v1, s2, v2; + GLfloat color2[4]; + parse_color (mi, "gridColor", bp->color); + parse_color (mi, "gridColor2", color2); + rgb_to_hsv (bp->color[0] * 65536, + bp->color[1] * 65536, + bp->color[2] * 65536, + &h1, &s1, &v1); + rgb_to_hsv (color2[0] * 65536, + color2[1] * 65536, + color2[2] * 65536, + &h2, &s2, &v2); + bp->ncolors = 128; + bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor)); + make_color_ramp (0, 0, 0, + h1, s1, v1, h2, s2, v2, + bp->colors, &bp->ncolors, + False, 0, False); + } + + bp->user_trackball = gltrackball_init (False); + + bp->grid_w = (RESOLUTION_BASE * resolution) / GRID_SEG; + if (bp->grid_w < 2) bp->grid_w = 2; + bp->grid_h = bp->grid_w; + + grid_max = bp->grid_w > bp->grid_h ? bp->grid_w : bp->grid_h; + vtx_max = grid_max * GRID_SEG; + bp->grid = (GLfloat *) calloc (vtx_max, sizeof(*bp->grid)); + bp->vtx = (GLfloat *) calloc (vtx_max * 3, sizeof(*bp->vtx)); + bp->col = (GLfloat *) calloc (vtx_max * 4, sizeof(*bp->col)); + bp->segs = (char *) calloc (grid_max, sizeof(*bp->segs)); + if (! bp->grid || ! bp->vtx || ! bp->col || ! bp->segs) abort(); + + bp->nstars = MI_COUNT(mi); + bp->stars = (star *) calloc (bp->nstars, sizeof (star)); + + for (i = 0; i < bp->nstars; i++) + { + star *s = &bp->stars[i]; + new_star (bp, s); + s->y = frand(s->ro * 2 + bp->grid_h * GRID_SEG) - s->ro; + } + + /* Let's tilt the floor a little. */ + gltrackball_reset (bp->user_trackball, + -0.4 + frand(0.8), + -0.3 + frand(0.2)); +} + + +ENTRYPOINT void +draw_gw (ModeInfo *mi) +{ + gw_configuration *bp = &bps[MI_SCREEN(mi)]; + int wire = MI_IS_WIREFRAME(mi); + Display *dpy = MI_DISPLAY(mi); + Window window = MI_WINDOW(mi); + int gridmod = grid_size * GRID_SIZE_BASE; + int x, y, i; + int sample_x, sample_y; + GLfloat sample_z = -1; + + if (!bp->glx_context) + return; + + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glPushMatrix (); + +# ifdef HAVE_MOBILE + glRotatef (current_device_rotation(), 0, 0, 1); /* right side up */ +# endif + + gltrackball_rotate (bp->user_trackball); + +#if 0 + glScalef(0.05/resolution, 0.05/resolution, 0.05/resolution); +#endif + + glRotatef (90, 1, 0, 0); + glTranslatef (-bp->grid_w * (GRID_SEG / 2.0f), + -bp->grid_h * (GRID_SEG * 0.75f), + 3); + +#if 0 + glColor3f(1,0,0); + glPushMatrix(); + glTranslatef(0,0,0); + glScalef (bp->grid_w * GRID_SEG, + bp->grid_w * GRID_SEG, + bp->grid_w * GRID_SEG); + glDisable (GL_FOG); + glBegin(GL_LINE_LOOP); + glVertex3f(0, 0, 0); + glVertex3f(1, 0, 0); + glVertex3f(1, 1, 0); + glVertex3f(.4, 1, 0); + glVertex3f(.5, .5, 0); + glVertex3f(.6, 1, 0); + glVertex3f(0, 1, 0); + glEnd(); + glPopMatrix(); + glColor3f(0,1,0); + if (!wire) glEnable (GL_FOG); +#endif + + if (!wire) + { + GLfloat fog_color[4] = { 0, 0, 0, 1 }; + + glLineWidth (2); + glEnable (GL_LINE_SMOOTH); + glHint (GL_LINE_SMOOTH_HINT, GL_NICEST); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glEnable (GL_BLEND); + + glFogi (GL_FOG_MODE, GL_EXP2); + glFogfv (GL_FOG_COLOR, fog_color); + glFogf (GL_FOG_DENSITY, 0.005); + glEnable (GL_FOG); + } + + glEnableClientState (GL_COLOR_ARRAY); + glEnableClientState (GL_VERTEX_ARRAY); + glColorPointer (4, GL_FLOAT, 0, bp->col); + glVertexPointer (3, GL_FLOAT, 0, bp->vtx); + + /* Somewhere near the midpoint of the view */ + sample_x = ((int) (bp->grid_w * GRID_SEG * 0.5) / gridmod) * gridmod; + sample_y = ((int) (bp->grid_h * GRID_SEG * 0.75) / GRID_SEG) * GRID_SEG; + + /* Find the cumulative gravitational effect at the midpoint of each star, + for the depth of the foot-circle. This duplicates some of the draw_row() + logic. */ + for (i = 0; i < bp->nstars; i++) + { + star *s0 = &bp->stars[i]; + GLfloat x0 = s0->x; + GLfloat y0 = s0->y; + int j; + s0->depth = s0->surface_gravity; + for (j = 0; j < bp->nstars; j++) + { + star *s1; + GLfloat x1, y1, d2; + if (i == j) continue; + s1 = &bp->stars[j]; + x1 = s1->x; + y1 = s1->y; + d2 = (x1-x0)*(x1-x0) + (y1-y0)*(y1-y0); + s0->depth += s1->mass / d2; + } + } + + mi->polygon_count = 0; + for (y = 0; y < (bp->grid_h - 1) * GRID_SEG; y += gridmod) + draw_row (mi, bp->grid_w, y, False); + for (x = 0; x < (bp->grid_w - 1) * GRID_SEG; x += gridmod) + { + draw_row (mi, bp->grid_h, x, True); + if (x == sample_x) + sample_z = bp->grid[sample_y]; + } + + if (mi->fps_p) + { + /* Mass of Sol is 2x10^30kg, or 332 kilo-Earths. + But I'm not sure what the funniest number to put here is. */ + /* mi->recursion_depth = (int) sample_z/4; */ + mi->recursion_depth = (int) (sample_z * 30000); + glColor4fv (bp->color); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, bp->color); + glBegin(GL_LINES); + glVertex3f (sample_x-0.15, sample_y-0.15, sample_z); + glVertex3f (sample_x+0.15, sample_y+0.15, sample_z); + glVertex3f (sample_x-0.15, sample_y+0.15, sample_z); + glVertex3f (sample_x+0.15, sample_y-0.15, sample_z); + glEnd(); + } + + /* Draw a circle around the "footprint" at the bottom of the gravity well. + */ + for (i = 0; i < bp->nstars; i++) + { + int steps = 16; + star *s = &bp->stars[i]; + GLfloat th, color[4]; + int ci; + ci = EASE (s->depth / MAX_MASS_COLOR) * bp->ncolors; + color[0] = bp->colors[ci].red / 65536.0; + color[1] = bp->colors[ci].green / 65536.0; + color[2] = bp->colors[ci].blue / 65536.0; + color[3] = 1; + glColor4fv (color); + glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); + glPushMatrix(); + glTranslatef (s->x, s->y, 0); + glBegin (GL_LINE_LOOP); + for (th = 0; th < M_PI * 2; th += M_PI/steps) + glVertex3f (s->radius * cos(th), s->radius * sin(th), s->depth); + glEnd(); + glPopMatrix(); + mi->polygon_count += steps; + } + +#if 0 + { + for (i = 0; i < bp->nstars; i++) + { + star *s = &bp->stars[i]; + GLfloat maxr = sqrt (s->mass / MASS_EPSILON); + GLfloat th; + glPushMatrix(); + glTranslatef (s->x, s->y, 0); + glColor3f(0, 0, 1); + glBegin (GL_LINE_LOOP); + for (th = 0; th < M_PI * 2; th += M_PI/32) + glVertex3f (s->radius * cos(th), s->radius * sin(th), 0); + glEnd(); + glColor3f(0, 0, 0.5); + glBegin (GL_LINE_LOOP); + for (th = 0; th < M_PI * 2; th += M_PI/32) + glVertex3f (maxr * cos(th), maxr * sin(th), 0); + glEnd(); + glBegin (GL_LINES); + glVertex3f ( 3000 * s->dx, 3000 * s->dy, 0); + glVertex3f (-3000 * s->dx, -3000 * s->dy, 0); + glEnd(); + glPopMatrix(); + } + } +#endif + + glPopMatrix (); + + if (! bp->button_down_p) + move_stars (mi); + + if (mi->fps_p) do_fps (mi); + glFinish(); + + glXSwapBuffers(dpy, window); +} + + +ENTRYPOINT void +free_gw (ModeInfo *mi) +{ + gw_configuration *bp = &bps[MI_SCREEN(mi)]; + + if (!bp->glx_context) return; + glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context); + + if (bp->user_trackball) gltrackball_free (bp->user_trackball); + if (bp->stars) free (bp->stars); + if (bp->grid) free (bp->grid); + if (bp->vtx) free (bp->vtx); + if (bp->col) free (bp->col); + if (bp->segs) free (bp->segs); + if (bp->colors) free (bp->colors); +} + +XSCREENSAVER_MODULE_2 ("GravityWell", gravitywell, gw) + +#endif /* USE_GL */ -- cgit v1.2.3-55-g7522