summaryrefslogtreecommitdiffstats
path: root/hacks/glx/crumbler.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/crumbler.c')
-rw-r--r--hacks/glx/crumbler.c922
1 files changed, 0 insertions, 922 deletions
diff --git a/hacks/glx/crumbler.c b/hacks/glx/crumbler.c
deleted file mode 100644
index fccee8d..0000000
--- a/hacks/glx/crumbler.c
+++ /dev/null
@@ -1,922 +0,0 @@
-/* crumbler, Copyright (c) 2018 Jamie Zawinski <jwz@jwz.org>
- *
- * 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" \
- "*showFPS: False \n" \
- "*wireframe: False \n" \
- "*suppressRotationAnimation: True\n" \
-
-# define release_crumbler 0
-
-#include "xlockmore.h"
-#include "colors.h"
-#include "rotator.h"
-#include "quickhull.h"
-#include "gltrackball.h"
-#include <ctype.h>
-
-#ifdef USE_GL /* whole file */
-
-
-#define DEF_SPIN "True"
-#define DEF_WANDER "True"
-#define DEF_SPEED "1.0"
-#define DEF_DENSITY "1.0"
-#define DEF_FRACTURE "0"
-
-#undef RANDSIGN
-#define RANDSIGN() ((random() & 1) ? 1 : -1)
-
-typedef struct {
- qh_vertex_t *verts; /* interior point cloud */
- int nverts, onverts;
- qh_vertex_t min, max; /* enclosing box */
- qh_vertex_t mid, vec;
- int polygon_count;
- GLuint dlist;
- int color;
- int color_shift;
-} chunk;
-
-typedef struct {
- GLXContext *glx_context;
- rotator *rot;
- trackball_state *trackball;
- enum { IDLE, SPLIT, PAUSE, FLEE, ZOOM } state;
- GLfloat tick;
- Bool button_down_p;
- int nchunks;
- chunk **chunks;
- chunk *ghost;
-
- int ncolors;
- XColor *colors;
-} crumbler_configuration;
-
-static crumbler_configuration *bps = NULL;
-
-static Bool do_spin;
-static GLfloat speed;
-static GLfloat density;
-static int fracture;
-static Bool do_wander;
-
-static XrmOptionDescRec opts[] = {
- { "-spin", ".spin", XrmoptionNoArg, "True" },
- { "+spin", ".spin", XrmoptionNoArg, "False" },
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-density", ".density", XrmoptionSepArg, 0 },
- { "-fracture",".fracture",XrmoptionSepArg, 0 },
- { "-wander", ".wander", XrmoptionNoArg, "True" },
- { "+wander", ".wander", XrmoptionNoArg, "False" }
-};
-
-static argtype vars[] = {
- {&do_spin, "spin", "Spin", DEF_SPIN, t_Bool},
- {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
- {&speed, "speed", "Speed", DEF_SPEED, t_Float},
- {&density, "density", "Density", DEF_DENSITY, t_Float},
- {&fracture, "fracture","Fracture",DEF_FRACTURE,t_Int},
-};
-
-ENTRYPOINT ModeSpecOpt crumbler_opts = {countof(opts), opts, countof(vars), vars, NULL};
-
-
-/* Create a roughly spherical cloud of N random points.
- */
-static void
-make_point_cloud (qh_vertex_t *verts, int nverts)
-{
- int i = 0;
- while (i < nverts)
- {
- verts[i].x = (0.5 - frand(1.0));
- verts[i].y = (0.5 - frand(1.0));
- verts[i].z = (0.5 - frand(1.0));
- if ((verts[i].x * verts[i].x +
- verts[i].y * verts[i].y +
- verts[i].z * verts[i].z)
- < 0.25)
- i++;
- }
-}
-
-static void crumbler_oom (void)
-{
-# ifdef HAVE_JWXYZ
- jwxyz_abort ("%s: out of memory, try reducing 'density'", progname);
-# else
- fprintf (stderr, "%s: out of memory, try reducing 'density'\n", progname);
- exit (1);
-# endif
-}
-
-
-static chunk *
-make_chunk (void)
-{
- chunk *c = (chunk *) calloc (1, sizeof(*c));
- if (!c) crumbler_oom();
- c->dlist = glGenLists (1);
- c->color_shift = 1 + (random() % 3) * RANDSIGN();
- return c;
-}
-
-/* Return False if out of memory */
-static Bool
-render_chunk (ModeInfo *mi, chunk *c)
-{
- int wire = MI_IS_WIREFRAME(mi);
- int i, j;
- qh_mesh_t m;
- GLfloat d;
-
- if (c->nverts <= 3)
- {
- fprintf (stderr, "%s: nverts %d\n", progname, c->nverts);
- abort();
- }
-
- c->polygon_count = 0;
- c->min.x = c->min.y = c->min.z = 999999;
- c->max.x = c->max.y = c->max.z = -999999;
-
- for (i = 0; i < c->nverts; i++)
- {
- if (c->verts[i].x < c->min.x) c->min.x = c->verts[i].x;
- if (c->verts[i].y < c->min.y) c->min.y = c->verts[i].y;
- if (c->verts[i].z < c->min.z) c->min.z = c->verts[i].z;
- if (c->verts[i].x > c->max.x) c->max.x = c->verts[i].x;
- if (c->verts[i].y > c->max.y) c->max.y = c->verts[i].y;
- if (c->verts[i].z > c->max.z) c->max.z = c->verts[i].z;
- }
-
- c->mid.x = (c->max.x + c->min.x) / 2;
- c->mid.y = (c->max.y + c->min.y) / 2;
- c->mid.z = (c->max.z + c->min.z) / 2;
-
- /* midpoint as normalized vector from origin */
- d = sqrt (c->mid.x * c->mid.x +
- c->mid.y * c->mid.y +
- c->mid.z * c->mid.z);
- c->vec.x = c->mid.x / d;
- c->vec.y = c->mid.y / d;
- c->vec.z = c->mid.z / d;
-
- if (c->nverts <= 3)
- {
- fprintf (stderr, "%s: nverts %d\n", progname, c->nverts);
- abort();
- }
-
- m = qh_quickhull3d (c->verts, c->nverts);
-
- if (!m.vertices) /* out of memory */
- {
- qh_free_mesh (m);
- return False;
- }
-
- glNewList (c->dlist, GL_COMPILE);
- if (! wire) glBegin (GL_TRIANGLES);
- for (i = 0, j = 0; i < m.nindices; i += 3, j++)
- {
- qh_vertex_t *v0 = &m.vertices[m.indices[i+0]];
- qh_vertex_t *v1 = &m.vertices[m.indices[i+1]];
- qh_vertex_t *v2 = &m.vertices[m.indices[i+2]];
- qh_vec3_t *n = &m.normals[m.normalindices[j]];
-
- if (i+2 >= m.nindices) abort();
- if (j >= m.nnormals) abort();
-
- glNormal3f (n->x, n->y, n->z);
- if (wire) glBegin(GL_LINE_LOOP);
- glVertex3f (v0->x, v0->y, v0->z);
- glVertex3f (v1->x, v1->y, v1->z);
- glVertex3f (v2->x, v2->y, v2->z);
- if (wire) glEnd();
- c->polygon_count++;
- }
- if (! wire) glEnd();
-
- if (wire)
- {
- glPointSize (1);
- glColor3f (0, 1, 0);
- glBegin (GL_POINTS);
- for (i = 0; i < c->nverts; i++)
- {
- if (i > 0 && i == c->onverts)
- {
- glEnd();
- glColor3f (1, 0, 0);
- glBegin (GL_POINTS);
- }
- glVertex3f (c->verts[i].x, c->verts[i].y, c->verts[i].z);
- }
- glEnd();
- }
-
- glEndList();
-
- qh_free_mesh (m);
- return True;
-}
-
-
-static void
-free_chunk (chunk *c)
-{
- if (c->dlist)
- glDeleteLists (c->dlist, 1);
- free (c->verts);
- free (c);
-}
-
-
-/* Make sure the chunk contains at least N points.
- As we subdivide, the number of points is reduced.
- This adds new points to the interior that do not
- affect the shape of the outer hull.
- */
-static void
-pad_chunk (chunk *c, int min)
-{
- /* Allocate a new array of size N
- Copy the old points into it
- while size < N
- pick two random points
- add a point that is somewhere along the line between them
- (that point will still be inside the old hull)
- */
- qh_vertex_t *verts;
- int i;
- if (c->nverts >= min) return;
- if (c->nverts <= 3) abort();
- verts = (qh_vertex_t *) calloc (min, sizeof(*verts));
- if (!verts) crumbler_oom();
- memcpy (verts, c->verts, c->nverts * sizeof(*verts));
- i = c->nverts;
- while (i < min)
- {
- qh_vertex_t v;
- int j0, j1;
- GLfloat r;
- j0 = random() % c->nverts;
- do {
- j1 = random() % c->nverts;
- } while (j0 == j1);
-
- r = 0.2 + frand(0.6);
-# undef R
-# define R(F) v.F = c->verts[j0].F + \
- r * (fabs (c->verts[j1].F - c->verts[j0].F)) \
- * (c->verts[j0].F > c->verts[j1].F ? -1 : 1)
- R(x);
- R(y);
- R(z);
-# undef R
-
- /* Sometimes quickhull.c is giving us concave and un-closed polygons.
- Maybe it gets confused if there are duplicate points? So reject
- this point if it is within epsilon of any earlier point.
- */
-# if 0 /* Nope, that's not it. */
- {
- Bool ok = True;
- int j;
- for (j = 0; j < i; j++)
- {
-
- double X = c->verts[j].x - v.x;
- double Y = c->verts[j].y - v.y;
- double Z = c->verts[j].z - v.z;
- double d2 = X*X + Y*Y + Z*Z;
- if (d2 < 0.0001)
- {
- /* fprintf (stderr, "## REJ %f\n",d2); */
- ok = False;
- break;
- }
- }
- if (! ok) continue;
- }
-# endif
-
- verts[i++] = v;
- }
-
-#if 0
- fprintf (stdout, " int n = %d;\n", min);
- fprintf (stdout, " qh_vertex_t v[] = {");
- for (i = 0; i < min; i++)
- fprintf(stdout,"{%f,%f,%f},", verts[i].x, verts[i].y, verts[i].z);
- fprintf (stdout, "};\n\n");
-#endif
-
- free (c->verts);
- c->verts = verts;
- c->onverts = c->nverts;
- c->nverts = min;
-
-#if 0
- qh_vertex_t *verts2 = (qh_vertex_t *) calloc (n, sizeof(*verts2));
- if (!verts2) crumbler_oom();
- memcpy (verts2, v, n * sizeof(*verts2));
- free (c->verts);
- c->verts = verts2;
- c->onverts = 0;
- c->nverts = n;
-#endif
-}
-
-
-/* Returns a list of N new chunks.
- */
-static chunk **
-split_chunk (ModeInfo *mi, chunk *c, int nchunks)
-{
- /* Pick N key-points from the cloud.
- Create N new chunks.
- For each old point:
- It goes in chunk N if it is closest to key-point N.
- Free old chunk.
- for each new chunk
- render_chunk
- */
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
- chunk **chunks;
- int *keys;
- int i, j;
- int retries = 0;
-
- RETRY:
- chunks = (chunk **) calloc (nchunks, sizeof(*chunks));
- if (!chunks) crumbler_oom();
- keys = (int *) calloc (nchunks, sizeof(*keys));
- if (!keys) crumbler_oom();
-
- for (i = 0; i < nchunks; i++)
- {
- /* Fill keys with random numbers that are not duplicates. */
- Bool ok = True;
- chunk *c2 = 0;
- if (nchunks >= c->nverts)
- {
- fprintf (stderr, "%s: nverts %d nchunks %d\n", progname,
- c->nverts, nchunks);
- abort();
- }
- do {
- keys[i] = random() % c->nverts;
- ok = True;
- for (j = 0; j < i; j++)
- if (keys[i] == keys[j])
- {
- ok = False;
- break;
- }
- } while (!ok);
-
- c2 = make_chunk();
- chunks[i] = c2;
- chunks[i]->nverts = 0;
- c2->verts = (qh_vertex_t *) calloc (c->nverts, sizeof(*c2->verts));
- if (!c2->verts) crumbler_oom();
- c2->color = (c->color + (random() % (1 + (bp->ncolors / 3))))
- % bp->ncolors;
- }
-
- /* Add the verts to the approprate chunks
- */
- for (i = 0; i < c->nverts; i++)
- {
- qh_vertex_t *v0 = &c->verts[i];
- int target_chunk = -1;
- double target_d2 = 9999999;
- chunk *c2 = 0;
-
- for (j = 0; j < nchunks; j++)
- {
- qh_vertex_t *v1 = &c->verts[keys[j]];
- double X = v1->x - v0->x;
- double Y = v1->y - v0->y;
- double Z = v1->z - v0->z;
- double d2 = X*X + Y*Y + Z*Z;
- if (d2 < target_d2)
- {
- target_d2 = d2;
- target_chunk = j;
- }
- }
- if (target_chunk == -1) abort();
-
- c2 = chunks[target_chunk];
- c2->verts[c2->nverts++] = *v0;
- if (c2->nverts > c->nverts) abort();
- }
-
- free (keys);
- keys = 0;
-
- for (i = 0; i < nchunks; i++)
- {
- chunk *c2 = chunks[i];
-
- /* It is possible that the keys we have chosen have resulted in one or
- more cells that have 3 or fewer points in them. If that's the case,
- re-randomize.
- */
- if (c2->nverts <= 3)
- {
- for (j = 0; j < nchunks; j++)
- free_chunk (chunks[j]);
- free (chunks);
- chunks = 0;
- if (retries++ > 100)
- {
- fprintf(stderr, "%s: unsplittable\n", progname);
- abort();
- }
- goto RETRY;
- }
-
- if (i == 0) /* The one we're gonna keep */
- pad_chunk (c2, c->nverts);
- if (! render_chunk (mi, c2))
- crumbler_oom(); /* We are too far in to recover from this */
- }
-
- return chunks;
-}
-
-
-static void
-tick_crumbler (ModeInfo *mi)
-{
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
- GLfloat ts;
-
- if (bp->button_down_p) return;
-
- switch (bp->state) {
- case IDLE: ts = 0.02; break;
- case SPLIT: ts = 0.01; break;
- case PAUSE: ts = 0.008; break;
- case FLEE: ts = 0.005; break;
- case ZOOM: ts = 0.03; break;
- default: abort(); break;
- }
-
- bp->tick += ts * speed;
-
- if (bp->tick < 1) return;
-
- bp->tick = 0;
- bp->state = (bp->state + 1) % (ZOOM + 1);
-
- switch (bp->state) {
- case IDLE:
- {
- chunk *c = bp->chunks[0];
- int i;
-
- /* We already animated it zooming to full size. Now make it real. */
- GLfloat X = (c->max.x - c->min.x);
- GLfloat Y = (c->max.y - c->min.y);
- GLfloat Z = (c->max.z - c->min.z);
- GLfloat s = 1 / MAX(X, MAX(Y, Z));
-
- for (i = 0; i < c->nverts; i++)
- {
- c->verts[i].x *= s;
- c->verts[i].y *= s;
- c->verts[i].z *= s;
- }
-
- /* Re-render it to move the verts in the display list too.
- This also recomputes min, max and mid.
- */
- if (! render_chunk (mi, c))
- crumbler_oom(); /* We are too far in to recover from this */
- break;
- }
-
- case SPLIT:
- {
- chunk *c = bp->chunks[0];
- int frac = (fracture >= 2 ? fracture : 2 + (2 * (random() % 5)));
- chunk **chunks = split_chunk (mi, c, frac);
- if (bp->nchunks != 1) abort();
- if (bp->ghost) abort();
- bp->ghost = c;
- free (bp->chunks);
- bp->chunks = chunks;
- bp->nchunks = frac;
- break;
- }
-
- case PAUSE:
- break;
-
- case FLEE:
- if (bp->ghost) free_chunk (bp->ghost);
- bp->ghost = 0;
- break;
-
- case ZOOM:
- {
- chunk *c = bp->chunks[0];
- int i;
- for (i = 1; i < bp->nchunks; i++)
- free_chunk (bp->chunks[i]);
- bp->nchunks = 1;
-
- /* We already animated the remaining chunk moving toward the origin.
- Make it real.
- */
- for (i = 0; i < c->nverts; i++)
- {
- c->verts[i].x -= c->mid.x;
- c->verts[i].y -= c->mid.y;
- c->verts[i].z -= c->mid.z;
- }
-
- /* Re-render it to move the verts in the display list too.
- This also recomputes min, max and mid (now 0).
- */
- if (! render_chunk (mi, c))
- crumbler_oom(); /* We are too far in to recover from this */
- break;
- }
-
- default: abort(); break;
- }
-}
-
-
-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;
-}
-
-
-/* Window management, etc
- */
-ENTRYPOINT void
-reshape_crumbler (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, (GLint) width, (GLint) height);
-
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- gluPerspective (30.0, 1/h, 1.0, 100.0);
-
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
- gluLookAt( 0.0, 0.0, 30.0,
- 0.0, 0.0, 0.0,
- 0.0, 1.0, 0.0);
-
- {
- GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi)
- ? (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi))
- : 1);
- glScalef (s, s, s);
- }
-
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-
-ENTRYPOINT Bool
-crumbler_handle_event (ModeInfo *mi, XEvent *event)
-{
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
-
- if (gltrackball_event_handler (event, bp->trackball,
- MI_WIDTH (mi), MI_HEIGHT (mi),
- &bp->button_down_p))
- return True;
-
- return False;
-}
-
-
-ENTRYPOINT void
-init_crumbler (ModeInfo *mi)
-{
- crumbler_configuration *bp;
- int wire = MI_IS_WIREFRAME(mi);
- int i;
-
- MI_INIT (mi, bps);
- bp = &bps[MI_SCREEN(mi)];
-
- bp->glx_context = init_GL(mi);
-
- reshape_crumbler (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-
- if (!wire)
- {
- GLfloat pos[4] = {1.0, 1.0, 1.0, 0.0};
- GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
- GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
- GLfloat spc[4] = {0.0, 1.0, 1.0, 1.0};
-
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
-
- glLightfv(GL_LIGHT0, GL_POSITION, pos);
- glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
-
- glEnable (GL_BLEND);
- glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
- }
-
- {
- double spin_speed = 0.5 * speed;
- double spin_accel = 0.3;
- double wander_speed = 0.01 * speed;
-
- bp->rot = make_rotator (do_spin ? spin_speed : 0,
- do_spin ? spin_speed : 0,
- do_spin ? spin_speed : 0,
- spin_accel,
- do_wander ? wander_speed : 0,
- True);
- bp->trackball = gltrackball_init (True);
- }
-
- bp->ncolors = 1024;
- bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
- if (!bp->colors) crumbler_oom();
- make_smooth_colormap (0, 0, 0,
- bp->colors, &bp->ncolors,
- False, 0, False);
-
- /* brighter colors, please... */
- for (i = 0; i < bp->ncolors; i++)
- {
-# undef R
-# define R(F) F = 65535 * (0.3 + 0.7 * ((F) / 65535.0))
- R (bp->colors[i].red);
- R (bp->colors[i].green);
- R (bp->colors[i].blue);
-# undef R
- }
-
- {
- double d2 = density;
- chunk *c;
-
- bp->nchunks = 1;
- bp->chunks = (chunk **) calloc (bp->nchunks, sizeof(*bp->chunks));
- if (! bp->chunks) crumbler_oom();
-
- c = make_chunk();
- if (! c) crumbler_oom();
-
- bp->chunks[0] = c;
-
- while (1)
- {
- c->nverts = 4500 * d2;
- c->verts = (qh_vertex_t *) calloc (c->nverts, sizeof(*c->verts));
- if (c->verts)
- {
- make_point_cloud (c->verts, c->nverts);
-
- /* Let's shrink it to a point then zoom in. */
- bp->state = ZOOM;
- bp->tick = 0;
- for (i = 0; i < c->nverts; i++)
- {
- c->verts[i].x /= 500;
- c->verts[i].y /= 500;
- c->verts[i].z /= 500;
- }
-
- if (! render_chunk (mi, c))
- {
- free (c->verts);
- c->verts = 0;
- }
- }
-
- if (c->verts)
- break;
-
- if (d2 < 0.1)
- crumbler_oom();
- d2 *= 0.9;
- }
-
- if (density != d2)
- fprintf (stderr,
- "%s: out of memory: reduced density from %.01f to %0.1f\n",
- progname, density, d2);
- }
-}
-
-
-static void
-draw_chunk (ModeInfo *mi, chunk *c, GLfloat alpha)
-{
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
- GLfloat color[4];
-
- color[0] = bp->colors[c->color].red / 65536.0;
- color[1] = bp->colors[c->color].green / 65536.0;
- color[2] = bp->colors[c->color].blue / 65536.0;
- color[3] = alpha;
- glColor4fv (color);
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
-
- c->color += c->color_shift;
- while (c->color < 0) c->color += bp->ncolors;
- while (c->color >= bp->ncolors) c->color -= bp->ncolors;
-
- glCallList (c->dlist);
- mi->polygon_count += c->polygon_count;
-}
-
-
-ENTRYPOINT void
-draw_crumbler (ModeInfo *mi)
-{
- int wire = MI_IS_WIREFRAME(mi);
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
- Display *dpy = MI_DISPLAY(mi);
- Window window = MI_WINDOW(mi);
- GLfloat alpha = 1;
- int i;
-
- static const GLfloat bspec[4] = {1.0, 1.0, 1.0, 1.0};
- static const GLfloat bshiny = 128.0;
-
- if (!bp->glx_context)
- return;
-
- glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
-
- tick_crumbler (mi);
-
- glShadeModel(GL_SMOOTH);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_NORMALIZE);
- glEnable(GL_CULL_FACE);
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glPushMatrix ();
-
- {
- double x, y, z;
- get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
- glTranslatef((x - 0.5) * 8,
- (y - 0.5) * 8,
- (z - 0.5) * 15);
-
- gltrackball_rotate (bp->trackball);
-
- get_rotation (bp->rot, &x, &y, &z, !bp->button_down_p);
- glRotatef (x * 360, 1.0, 0.0, 0.0);
- glRotatef (y * 360, 0.0, 1.0, 0.0);
- glRotatef (z * 360, 0.0, 0.0, 1.0);
- }
-
- mi->polygon_count = 0;
-
- glMaterialfv (GL_FRONT, GL_SPECULAR, bspec);
- glMateriali (GL_FRONT, GL_SHININESS, bshiny);
-
- if (do_wander)
- glScalef (10, 10, 10);
- else
- glScalef (13, 13, 13);
-
- alpha = 1;
- for (i = 0; i < bp->nchunks; i++)
- {
- chunk *c = bp->chunks[i];
-
- glPushMatrix();
-
- switch (bp->state) {
- case FLEE:
- {
- GLfloat r = ease_ratio (bp->tick);
- /* Move everybody toward the origin, so that chunk #0 ends up
- centered there. */
- glTranslatef (-r * c->mid.x,
- -r * c->mid.y,
- -r * c->mid.z);
- if (i != 0)
- {
- /* Move this chunk away from the center, along a vector from
- the origin to its midpoint. */
- GLfloat d2 = r * 6;
- glTranslatef (c->vec.x * d2, c->vec.y * d2, c->vec.z * d2);
- alpha = 1 - r;
- }
- }
- break;
-
- case ZOOM:
- {
- chunk *c = bp->chunks[0];
- GLfloat X = (c->max.x - c->min.x);
- GLfloat Y = (c->max.y - c->min.y);
- GLfloat Z = (c->max.z - c->min.z);
- GLfloat size0 = MAX(X, MAX(Y, Z));
- GLfloat size1 = 1.0;
- GLfloat r = 1 - ease_ratio (bp->tick);
- GLfloat s = 1 / (size0 + r * (size1 - size0));
- glScalef (s, s, s);
- }
- break;
-
- default:
- break;
- }
-
- draw_chunk (mi, c, alpha);
- glPopMatrix();
- }
-
- /* Draw the old one, fading out. */
- if (!wire && bp->state == SPLIT && bp->ghost)
- {
- GLfloat s;
- /* alpha = 1 - bp->tick; */
- alpha = 1;
- /* s = 0.7 + (0.3 * ease_ratio (1-bp->tick)); */
- s = 2 * ease_ratio ((1-bp->tick) / 2);
- s *= 1.01;
- glScalef (s, s, s);
- draw_chunk (mi, bp->ghost, alpha);
- }
-
- glPopMatrix ();
-
- if (mi->fps_p) do_fps (mi);
- glFinish();
-
- glXSwapBuffers(dpy, window);
-}
-
-
-ENTRYPOINT void
-free_crumbler (ModeInfo *mi)
-{
- crumbler_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
- if (!bp->glx_context) return;
- glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
- if (bp->trackball) gltrackball_free (bp->trackball);
- if (bp->rot) free_rotator (bp->rot);
- if (bp->colors) free (bp->colors);
- for (i = 0; i < bp->nchunks; i++)
- free_chunk (bp->chunks[i]);
- if (bp->chunks) free (bp->chunks);
-}
-
-
-XSCREENSAVER_MODULE ("Crumbler", crumbler)
-
-#endif /* USE_GL */