summaryrefslogtreecommitdiffstats
path: root/hacks/glx/lavalite.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/lavalite.c')
-rw-r--r--hacks/glx/lavalite.c1550
1 files changed, 0 insertions, 1550 deletions
diff --git a/hacks/glx/lavalite.c b/hacks/glx/lavalite.c
deleted file mode 100644
index 825a389..0000000
--- a/hacks/glx/lavalite.c
+++ /dev/null
@@ -1,1550 +0,0 @@
-/* lavalite --- 3D Simulation a Lava Lite, written by jwz.
- *
- * This software Copyright (c) 2002-2017 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.
- *
- * LAVA®, LAVA LITE®, LAVA WORLD INTERNATIONAL® and the configuration of the
- * LAVA® brand motion lamp are registered trademarks of Haggerty Enterprises,
- * Inc. The configuration of the globe and base of the motion lamp are
- * registered trademarks of Haggerty Enterprises, Inc. in the U.S.A. and in
- * other countries around the world.
- *
- * Official Lava Lite web site: http://www.lavaworld.com/
- *
- * Implementation details:
- *
- * The blobs are generated using metaballs. For an explanation of what
- * those are, see http://astronomy.swin.edu.au/~pbourke/modelling/implicitsurf/
- * or http://www.fifi.org/doc/povray-manual/pov30005.htm
- *
- * Basically, each bubble of lava is a few (4) overlapping spherical metaballs
- * of various sizes following similar but slightly different steep, slow
- * parabolic arcs from the bottom to the top and back.
- *
- * We then polygonize the surface of the lava using the marching squares
- * algorithm implemented in marching.c.
- *
- * Like real lavalites, this program is very slow.
- *
- * Surprisingly, it's loading the CPU and not the graphics engine: the speed
- * bottleneck is in *computing* the scene rather than *rendering* it. We
- * actually don't use a huge number of polygons, but computing the mesh for
- * the surface takes a lot of cycles.
- *
- * I eliminated all the square roots, but there is still a lot of
- * floating-point multiplication in here. I tried optimizing away the
- * fp divisions, but that didn't seem to make a difference.
- *
- * -style lamp shape: classic, giant, cone, rocket, or random.
- * -speed frequency at which new blobs launch.
- * -resolution density of the polygon mesh.
- * -count max number of blobs allowed at once.
- * -wander, -spin whether to roll the scene around the screen.
- * -lava-color color of the blobbies
- * -fluid-color color of the stuff the blobbies float in
- * -base-color color of the base of the lamp
- * -table-color color of the table under the lamp
- * -impatient at startup, skip forward in the animation so
- * that at least one blob is fully exposed.
- *
- * TODO:
- *
- * - make the table look better, somehow.
- * - should the lava be emissive? should the one at the bottom be
- * more brightly colored than the ones at the top? light distance?
- * - is there some way to put a specular reflection on the front glass
- * itself? Maybe render it twice with FRONT/BACK tweaked, or alpha
- * with depth buffering turned off?
- */
-
-#define DEFAULTS "*delay: 30000 \n" \
- "*showFPS: False \n" \
- "*wireframe: False \n" \
- "*geometry: 600x900\n" \
- "*count: " DEF_COUNT " \n" \
-
-# define release_lavalite 0
-
-
-#define BLOBS_PER_GROUP 4
-
-#define GRAVITY 0.000013 /* odwnward acceleration */
-#define CONVECTION 0.005 /* initial upward velocity (bell curve) */
-#define TILT 0.00166666 /* horizontal velocity (bell curve) */
-
-#undef ABS
-#define ABS(n) ((n)<0?-(n):(n))
-#undef SIGNOF
-#define SIGNOF(n) ((n)<0?-1:1)
-
-#include "xlockmore.h"
-#include "marching.h"
-#include "rotator.h"
-#include "gltrackball.h"
-#include "ximage-loader.h"
-#include <ctype.h>
-
-#ifdef USE_GL /* whole file */
-
-
-#define DEF_SPIN "Z"
-#define DEF_WANDER "False"
-#define DEF_SPEED "0.003"
-#define DEF_RESOLUTION "40"
-#define DEF_SMOOTH "True"
-#define DEF_COUNT "3"
-#define DEF_STYLE "random"
-#define DEF_IMPATIENT "False"
-#define DEF_LCOLOR "#FF0000" /* lava */
-#define DEF_FCOLOR "#00AAFF" /* fluid */
-#define DEF_BCOLOR "#666666" /* base */
-#define DEF_TCOLOR "#000000" /*"#00FF00"*/ /* table */
-
-#define DEF_FTEX "(none)"
-#define DEF_BTEX "(none)"
-#define DEF_TTEX "(none)"
-
-typedef struct metaball metaball;
-
-struct metaball {
-
- Bool alive_p;
- Bool static_p;
-
- double r; /* hard radius */
- double R; /* radius of field of influence */
-
- double z; /* vertical position */
- double pos_r; /* position on horizontal circle */
- double pos_th; /* position on horizontal circle */
- double dr, dz; /* current velocity */
-
- double x, y; /* h planar position - compused from the above */
-
- metaball *leader; /* stay close to this other ball */
-};
-
-
-typedef enum { CLASSIC = 0, GIANT, CONE, ROCKET } lamp_style;
-typedef enum { CAP = 100, BOTTLE, BASE } lamp_part;
-
-typedef struct {
- lamp_part part;
- GLfloat elevation;
- GLfloat radius;
- GLfloat texture_elevation;
-} lamp_geometry;
-
-static const lamp_geometry classic_lamp[] = {
- { CAP, 1.16, 0.089, 0.00 },
- { BOTTLE, 0.97, 0.120, 0.40 },
- { BOTTLE, 0.13, 0.300, 0.87 },
- { BOTTLE, 0.07, 0.300, 0.93 },
- { BASE, 0.00, 0.280, 0.00 },
- { BASE, -0.40, 0.120, 0.50 },
- { BASE, -0.80, 0.280, 1.00 },
- { 0, 0, 0, 0 },
-};
-
-static const lamp_geometry giant_lamp[] = {
- { CAP, 1.12, 0.105, 0.00 },
- { BOTTLE, 0.97, 0.130, 0.30 },
- { BOTTLE, 0.20, 0.300, 0.87 },
- { BOTTLE, 0.15, 0.300, 0.93 },
- { BASE, 0.00, 0.230, 0.00 },
- { BASE, -0.18, 0.140, 0.20 },
- { BASE, -0.80, 0.280, 1.00 },
- { 0, 0, 0, 0 },
-};
-
-static const lamp_geometry cone_lamp[] = {
- { CAP, 1.35, 0.001, 0.00 },
- { CAP, 1.35, 0.020, 0.00 },
- { CAP, 1.30, 0.055, 0.05 },
- { BOTTLE, 0.97, 0.120, 0.40 },
- { BOTTLE, 0.13, 0.300, 0.87 },
- { BASE, 0.00, 0.300, 0.00 },
- { BASE, -0.04, 0.320, 0.04 },
- { BASE, -0.60, 0.420, 0.50 },
- { 0, 0, 0, 0 },
-};
-
-static const lamp_geometry rocket_lamp[] = {
- { CAP, 1.35, 0.001, 0.00 },
- { CAP, 1.34, 0.020, 0.00 },
- { CAP, 1.30, 0.055, 0.05 },
- { BOTTLE, 0.97, 0.120, 0.40 },
- { BOTTLE, 0.13, 0.300, 0.87 },
- { BOTTLE, 0.07, 0.300, 0.93 },
- { BASE, 0.00, 0.280, 0.00 },
- { BASE, -0.50, 0.180, 0.50 },
- { BASE, -0.75, 0.080, 0.75 },
- { BASE, -0.80, 0.035, 0.80 },
- { BASE, -0.90, 0.035, 1.00 },
- { 0, 0, 0, 0 },
-};
-
-
-
-typedef struct {
- GLXContext *glx_context;
- lamp_style style;
- const lamp_geometry *model;
- rotator *rot;
- rotator *rot2;
- trackball_state *trackball;
- Bool button_down_p;
-
- GLfloat max_bottle_radius; /* radius of widest part of the bottle */
-
- GLfloat launch_chance; /* how often to percolate */
- int blobs_per_group; /* how many metaballs we launch at once */
- Bool just_started_p; /* so we launch some goo right away */
-
- int grid_size; /* resolution for marching-cubes */
- int nballs;
- metaball *balls;
-
- GLuint bottle_list;
- GLuint ball_list;
-
- int bottle_poly_count; /* polygons in the bottle only */
-
-} lavalite_configuration;
-
-static lavalite_configuration *bps = NULL;
-
-static char *do_spin;
-static char *do_style;
-static GLfloat speed;
-static Bool do_wander;
-static int resolution;
-static Bool do_smooth;
-static Bool do_impatient;
-
-static char *lava_color_str, *fluid_color_str, *base_color_str,
- *table_color_str;
-static char *fluid_tex, *base_tex, *table_tex;
-
-static GLfloat lava_color[4], fluid_color[4], base_color[4], table_color[4];
-
-static const GLfloat lava_spec[4] = {1.0, 1.0, 1.0, 1.0};
-static const GLfloat lava_shininess = 128.0;
-static const GLfloat foot_color[4] = {0.2, 0.2, 0.2, 1.0};
-
-static const GLfloat light0_pos[4] = {-0.6, 0.0, 1.0, 0.0};
-static const GLfloat light1_pos[4] = { 1.0, 0.0, 0.2, 0.0};
-static const GLfloat light2_pos[4] = { 0.6, 0.0, 1.0, 0.0};
-
-
-
-static XrmOptionDescRec opts[] = {
- { "-style", ".style", XrmoptionSepArg, 0 },
- { "-spin", ".spin", XrmoptionSepArg, 0 },
- { "+spin", ".spin", XrmoptionNoArg, "" },
- { "-speed", ".speed", XrmoptionSepArg, 0 },
- { "-wander", ".wander", XrmoptionNoArg, "True" },
- { "+wander", ".wander", XrmoptionNoArg, "False" },
- { "-resolution", ".resolution", XrmoptionSepArg, 0 },
- { "-smooth", ".smooth", XrmoptionNoArg, "True" },
- { "+smooth", ".smooth", XrmoptionNoArg, "False" },
- { "-impatient", ".impatient", XrmoptionNoArg, "True" },
- { "+impatient", ".impatient", XrmoptionNoArg, "False" },
-
- { "-lava-color", ".lavaColor", XrmoptionSepArg, 0 },
- { "-fluid-color", ".fluidColor", XrmoptionSepArg, 0 },
- { "-base-color", ".baseColor", XrmoptionSepArg, 0 },
- { "-table-color", ".tableColor", XrmoptionSepArg, 0 },
-
- { "-fluid-texture",".fluidTexture", XrmoptionSepArg, 0 },
- { "-base-texture", ".baseTexture", XrmoptionSepArg, 0 },
- { "-table-texture",".tableTexture", XrmoptionSepArg, 0 },
-};
-
-static argtype vars[] = {
- {&do_style, "style", "Style", DEF_STYLE, t_String},
- {&do_spin, "spin", "Spin", DEF_SPIN, t_String},
- {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
- {&speed, "speed", "Speed", DEF_SPEED, t_Float},
- {&resolution, "resolution", "Resolution", DEF_RESOLUTION, t_Int},
- {&do_smooth, "smooth", "Smooth", DEF_SMOOTH, t_Bool},
- {&do_impatient, "impatient", "Impatient", DEF_IMPATIENT, t_Bool},
-
- {&lava_color_str, "lavaColor", "LavaColor", DEF_LCOLOR, t_String},
- {&fluid_color_str, "fluidColor", "FluidColor", DEF_FCOLOR, t_String},
- {&base_color_str, "baseColor", "BaseColor", DEF_BCOLOR, t_String},
- {&table_color_str, "tableColor", "TableColor", DEF_TCOLOR, t_String},
-
- {&fluid_tex, "fluidTexture", "FluidTexture", DEF_FTEX, t_String},
- {&base_tex, "baseTexture", "BaseTexture", DEF_BTEX, t_String},
- {&table_tex, "tableTexture", "BaseTexture", DEF_TTEX, t_String},
-};
-
-ENTRYPOINT ModeSpecOpt lavalite_opts = {countof(opts), opts, countof(vars), vars, NULL};
-
-
-/* Window management, etc
- */
-ENTRYPOINT void
-reshape_lavalite (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 * 3;
- 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);
-
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-
-
-/* Textures
- */
-
-static Bool
-load_texture (ModeInfo *mi, const char *filename)
-{
- Display *dpy = mi->dpy;
- Visual *visual = mi->xgwa.visual;
- char buf[1024];
- XImage *image;
-
- if (!filename ||
- !*filename ||
- !strcasecmp (filename, "(none)"))
- {
- glDisable (GL_TEXTURE_2D);
- return False;
- }
-
- image = file_to_ximage (dpy, visual, filename);
- if (!image) return False;
-
- clear_gl_error();
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
- image->width, image->height, 0,
- GL_RGBA, GL_UNSIGNED_BYTE, image->data);
- sprintf (buf, "texture: %.100s (%dx%d)",
- filename, image->width, image->height);
- check_gl_error(buf);
-
- glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
- glPixelStorei (GL_UNPACK_ROW_LENGTH, image->width);
- 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);
-
- glEnable (GL_TEXTURE_2D);
- return True;
-}
-
-
-
-/* Generating the lamp's bottle, caps, and base.
- */
-
-static int
-draw_disc (GLfloat r, GLfloat z, int faces, Bool up_p, Bool wire)
-{
- int j;
- GLfloat th;
- GLfloat step = M_PI * 2 / faces;
- int polys = 0;
- GLfloat x, y;
-
- glFrontFace (up_p ? GL_CW : GL_CCW);
- glNormal3f (0, (up_p ? 1 : -1), 0);
- glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLES);
-
- x = r;
- y = 0;
-
- for (j = 0, th = 0; j <= faces; j++)
- {
- glTexCoord2f (-j / (GLfloat) faces, 1);
- glVertex3f (0, z, 0);
-
- glTexCoord2f (-j / (GLfloat) faces, 0);
- glVertex3f (x, z, y);
-
- th += step;
- x = r * cos (th);
- y = r * sin (th);
-
- glTexCoord2f (-j / (GLfloat) faces, 0);
- glVertex3f (x, z, y);
-
- polys++;
- }
- glEnd();
-
- return polys;
-}
-
-
-static int
-draw_tube (GLfloat r0, GLfloat r1,
- GLfloat z0, GLfloat z1,
- GLfloat t0, GLfloat t1,
- int faces, Bool inside_out_p, Bool smooth_p, Bool wire)
-{
- int polys = 0;
- GLfloat th;
- GLfloat x, y, x0=0, y0=0;
- GLfloat step = M_PI * 2 / faces;
- GLfloat s2 = step/2;
- int i;
-
- glFrontFace (inside_out_p ? GL_CW : GL_CCW);
- glBegin (wire ? GL_LINES : (smooth_p ? GL_QUAD_STRIP : GL_QUADS));
-
- th = 0;
- x = 1;
- y = 0;
-
- if (!smooth_p)
- {
- x0 = cos (s2);
- y0 = sin (s2);
- }
-
- if (smooth_p) faces++;
-
- for (i = 0; i < faces; i++)
- {
- int nsign = (inside_out_p ? -1 : 1);
-
- if (smooth_p)
- glNormal3f (x * nsign, z1, y * nsign);
- else
- glNormal3f (x0 * nsign, z1, y0 * nsign);
-
- glTexCoord2f (nsign * -i / (GLfloat) faces, 1-t1);
- glVertex3f (x * r1, z1, y * r1);
-
- glTexCoord2f (nsign * -i / (GLfloat) faces, 1-t0);
- glVertex3f (x * r0, z0, y * r0);
-
- th += step;
- x = cos (th);
- y = sin (th);
-
- if (!smooth_p)
- {
- x0 = cos (th + s2);
- y0 = sin (th + s2);
-
- glTexCoord2f (nsign * -(i+1) / (double) faces, 1-t0);
- glVertex3f (x * r0, z0, y * r0);
-
- glTexCoord2f (nsign * -(i+1) / (double) faces, 1-t1);
- glVertex3f (x * r1, z1, y * r1);
- }
-
- polys++;
- }
- glEnd();
-
- return polys;
-}
-
-
-static int
-draw_table (GLfloat z, Bool wire)
-{
- GLfloat faces = 6;
- GLfloat step = M_PI * 2 / faces;
- GLfloat s = 8;
- GLfloat th;
- int j;
- int polys = 0;
-
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_color);
-
- glFrontFace(GL_CW);
- glNormal3f(0, 1, 0);
- glBegin(wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
-
- if (! wire)
- {
- glTexCoord2f (-0.5, 0.5);
- glVertex3f(0, z, 0);
- }
-
- for (j = 0, th = 0; j <= faces; j++)
- {
- GLfloat x = cos (th);
- GLfloat y = sin (th);
- glTexCoord2f (-(x+1)/2.0, (y+1)/2.0);
- glVertex3f(x*s, z, y*s);
- th += step;
- polys++;
- }
- glEnd();
- return polys;
-}
-
-
-static int
-draw_wing (GLfloat w, GLfloat h, GLfloat d, Bool wire)
-{
- static const int coords[2][8][2] = {
- { { 0, 0 },
- { 10, 10 },
- { 20, 23 },
- { 30, 41 },
- { 40, 64 },
- { 45, 81 },
- { 50, 103 },
- { 53, 134 } },
- { { 0, 54 },
- { 10, 57 },
- { 20, 64 },
- { 30, 75 },
- { 40, 92 },
- { 45, 104 },
- { 50, 127 },
- { 51, 134 }
- }
- };
-
- int polys = 0;
- int maxx = coords[0][countof(coords[0])-1][0];
- int maxy = coords[0][countof(coords[0])-1][1];
- unsigned int x;
-
- for (x = 1; x < countof(coords[0]); x++)
- {
- GLfloat px0 = (GLfloat) coords[0][x-1][0] / maxx * w;
- GLfloat py0 = (GLfloat) coords[0][x-1][1] / maxy * h;
- GLfloat px1 = (GLfloat) coords[1][x-1][0] / maxx * w;
- GLfloat py1 = (GLfloat) coords[1][x-1][1] / maxy * h;
- GLfloat px2 = (GLfloat) coords[0][x ][0] / maxx * w;
- GLfloat py2 = (GLfloat) coords[0][x ][1] / maxy * h;
- GLfloat px3 = (GLfloat) coords[1][x ][0] / maxx * w;
- GLfloat py3 = (GLfloat) coords[1][x ][1] / maxy * h;
- GLfloat zz = d/2;
-
- /* Left side
- */
- glFrontFace (GL_CW);
- glNormal3f (0, 0, -1);
- glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
-
- glTexCoord2f (px0, py0); glVertex3f (px0, -py0, -zz);
- glTexCoord2f (px1, py1); glVertex3f (px1, -py1, -zz);
- glTexCoord2f (px3, py3); glVertex3f (px3, -py3, -zz);
- glTexCoord2f (px2, py2); glVertex3f (px2, -py2, -zz);
- polys++;
- glEnd();
-
- /* Right side
- */
- glFrontFace (GL_CCW);
- glNormal3f (0, 0, -1);
- glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
- glTexCoord2f(px0, py0); glVertex3f (px0, -py0, zz);
- glTexCoord2f(px1, py1); glVertex3f (px1, -py1, zz);
- glTexCoord2f(px3, py3); glVertex3f (px3, -py3, zz);
- glTexCoord2f(px2, py2); glVertex3f (px2, -py2, zz);
- polys++;
- glEnd();
-
- /* Top edge
- */
- glFrontFace (GL_CCW);
- glNormal3f (1, -1, 0); /* #### wrong */
- glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
- glTexCoord2f(px0, py0); glVertex3f (px0, -py0, -zz);
- glTexCoord2f(px0, py0); glVertex3f (px0, -py0, zz);
- glTexCoord2f(px2, py2); glVertex3f (px2, -py2, zz);
- glTexCoord2f(px2, py2); glVertex3f (px2, -py2, -zz);
- polys++;
- glEnd();
-
- /* Bottom edge
- */
- glFrontFace (GL_CW);
- glNormal3f (-1, 1, 0); /* #### wrong */
- glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
- glTexCoord2f(px1, py1); glVertex3f (px1, -py1, -zz);
- glTexCoord2f(px1, py1); glVertex3f (px1, -py1, zz);
- glTexCoord2f(px3, py3); glVertex3f (px3, -py3, zz);
- glTexCoord2f(px3, py3); glVertex3f (px3, -py3, -zz);
- polys++;
- glEnd();
-
-
- }
-
- return polys;
-
-}
-
-
-static void
-generate_bottle (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- int wire = MI_IS_WIREFRAME(mi);
- int faces = resolution * 1.5;
- Bool smooth = do_smooth;
-
- const lamp_geometry *top_slice = bp->model;
- const char *current_texture = 0;
- lamp_part last_part = 0;
-
- if (faces < 3) faces = 3;
- else if (wire && faces > 20) faces = 20;
- else if (faces > 60) faces = 60;
-
- bp->bottle_poly_count = 0;
-
- glNewList (bp->bottle_list, GL_COMPILE);
- glPushMatrix();
-
- glRotatef (90, 1, 0, 0);
- glTranslatef (0, -0.5, 0);
-
- /* All parts of the lamp use the same specularity and shininess. */
- glMaterialfv (GL_FRONT, GL_SPECULAR, lava_spec);
- glMateriali (GL_FRONT, GL_SHININESS, lava_shininess);
-
- while (1)
- {
- const lamp_geometry *bot_slice = top_slice + 1;
-
- const char *texture = 0;
- GLfloat *color = 0;
- GLfloat t0, t1;
-
- glDisable (GL_LIGHT2);
-
- switch (top_slice->part)
- {
- case CAP:
- case BASE:
- texture = base_tex;
- color = base_color;
- break;
- case BOTTLE:
- texture = fluid_tex;
- color = fluid_color;
- if (!wire) glEnable (GL_LIGHT2); /* light2 affects only fluid */
- break;
- default:
- abort();
- break;
- }
-
- if (!wire && texture && texture != current_texture)
- {
- current_texture = texture;
- load_texture (mi, current_texture);
- }
-
- /* Color the discs darker than the tube walls. */
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, foot_color);
-
- /* Do a top disc if this is the first slice of the CAP or BASE.
- */
- if ((top_slice->part == CAP && last_part == 0) ||
- (top_slice->part == BASE && last_part == BOTTLE))
- bp->bottle_poly_count +=
- draw_disc (top_slice->radius, top_slice->elevation, faces,
- True, wire);
-
- /* Do a bottom disc if this is the last slice of the CAP or BASE.
- */
- if ((top_slice->part == CAP && bot_slice->part == BOTTLE) ||
- (top_slice->part == BASE && bot_slice->part == 0))
- {
- const lamp_geometry *sl = (bot_slice->part == 0
- ? top_slice : bot_slice);
- bp->bottle_poly_count +=
- draw_disc (sl->radius, sl->elevation, faces, False, wire);
- }
-
- if (bot_slice->part == 0) /* done! */
- break;
-
- /* Do a tube or cone
- */
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color);
-
- t0 = top_slice->texture_elevation;
- t1 = bot_slice->texture_elevation;
-
- /* Restart the texture coordinates for the glass.
- */
- if (top_slice->part == BOTTLE)
- {
- Bool first_p = (top_slice[-1].part != BOTTLE);
- Bool last_p = (bot_slice->part != BOTTLE);
- if (first_p) t0 = 0;
- if (last_p) t1 = 1;
- }
-
- bp->bottle_poly_count +=
- draw_tube (top_slice->radius, bot_slice->radius,
- top_slice->elevation, bot_slice->elevation,
- t0, t1,
- faces,
- (top_slice->part == BOTTLE),
- smooth, wire);
-
- last_part = top_slice->part;
- top_slice++;
- }
-
- if (bp->style == ROCKET)
- {
- int i;
- for (i = 0; i < 3; i++)
- {
- glPushMatrix();
- glRotatef (120 * i, 0, 1, 0);
- glTranslatef (0.14, -0.05, 0);
- bp->bottle_poly_count += draw_wing (0.4, 0.95, 0.02, wire);
- glPopMatrix();
- }
- glTranslatef (0, -0.1, 0); /* move floor down a little */
- }
-
-
- if (!wire) load_texture (mi, table_tex);
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, table_color);
- bp->bottle_poly_count += draw_table (top_slice->elevation, wire);
-
-
- glPopMatrix ();
- glDisable (GL_TEXTURE_2D); /* done with textured objects */
- glEndList ();
-}
-
-
-
-
-/* Generating blobbies
- */
-
-static double
-bellrand (double extent) /* like frand(), but a bell curve. */
-{
- return (((frand(extent) + frand(extent) + frand(extent)) / 3)
- - (extent/2));
-}
-
-
-static void move_ball (ModeInfo *mi, metaball *b);
-
-/* Bring a ball into play, and re-randomize its values.
- */
-static void
-reset_ball (ModeInfo *mi, metaball *b)
-{
-/* lavalite_configuration *bp = &bps[MI_SCREEN(mi)]; */
-
- b->r = 0.00001;
- b->R = 0.12 + bellrand(0.10);
-
- b->pos_r = bellrand (0.9);
- b->pos_th = frand(M_PI*2);
- b->z = 0;
-
- b->dr = bellrand(TILT);
- b->dz = CONVECTION;
-
- b->leader = 0;
-
- if (!b->alive_p)
- b->alive_p = True;
-
- move_ball (mi, b);
-}
-
-
-/* returns the first metaball that is not in use, or 0.
- */
-static metaball *
-get_ball (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
- for (i = 0; i < bp->nballs; i++)
- {
- metaball *b = &bp->balls[i];
- if (!b->alive_p)
- return b;
- }
- return 0;
-}
-
-
-/* Generate the blobs that don't move: the ones at teh top and bottom
- that are part of the scenery.
- */
-static void
-generate_static_blobs (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- metaball *b0, *b1;
- int i;
-
- b0 = get_ball (mi);
- if (!b0) abort();
- b0->static_p = True;
- b0->alive_p = True;
- b0->R = 0.6;
- b0->r = 0.3;
-
- /* the giant blob at the bottom of the bottle.
- */
- b0->pos_r = 0;
- b0->pos_th = 0;
- b0->dr = 0;
- b0->dz = 0;
- b0->x = 0;
- b0->y = 0;
- b0->z = -0.43;
-
- /* the small blob at the top of the bottle.
- */
- b1 = get_ball (mi);
- if (!b1) abort();
-
- *b1 = *b0;
- b1->R = 0.16;
- b1->r = 0.135;
- b1->z = 1.078;
-
- /* Some extra blobs at the bottom of the bottle, to jumble the surface.
- */
- for (i = 0; i < bp->blobs_per_group; i++)
- {
- b1 = get_ball (mi);
- if (!b1) abort();
- reset_ball (mi, b1);
- b1->static_p = True;
- b1->z = frand(0.04);
- b1->dr = 0;
- b1->dz = 0;
- }
-}
-
-
-static GLfloat
-max_bottle_radius (lavalite_configuration *bp)
-{
- GLfloat r = 0;
- const lamp_geometry *slice;
- for (slice = bp->model; slice->part != 0; slice++)
- {
- if (slice->part == BOTTLE && slice->radius > r)
- r = slice->radius; /* top */
- if (slice[1].radius > r)
- r = slice[1].radius; /* bottom */
- }
- return r;
-}
-
-
-static GLfloat
-bottle_radius_at (lavalite_configuration *bp, GLfloat z)
-{
- GLfloat topz = -999, botz = -999, topr = 0, botr = 0;
- const lamp_geometry *slice;
- GLfloat ratio;
-
- for (slice = bp->model; slice->part != 0; slice++)
- if (z > slice->elevation)
- {
- slice--;
- topz = slice->elevation;
- topr = slice->radius;
- break;
- }
- if (topz == -999) return 0;
-
- for (; slice->part != 0; slice++)
- if (z > slice->elevation)
- {
- botz = slice->elevation;
- botr = slice->radius;
- break;
- }
- if (botz == -999) return 0;
-
- ratio = (z - botz) / (topz - botz);
-
- return (botr + ((topr - botr) * ratio));
-}
-
-
-static void
-move_ball (ModeInfo *mi, metaball *b)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- double gravity = GRAVITY;
- double real_r;
-
- if (b->static_p) return;
-
- b->pos_r += b->dr;
- b->z += b->dz;
-
- b->dz -= gravity;
-
- if (b->pos_r > 0.9)
- {
- b->pos_r = 0.9;
- b->dr = -b->dr;
- }
- else if (b->pos_r < 0)
- {
- b->pos_r = -b->pos_r;
- b->dr = -b->dr;
- }
-
- real_r = b->pos_r * bottle_radius_at (bp, b->z);
-
- b->x = cos (b->pos_th) * real_r;
- b->y = sin (b->pos_th) * real_r;
-
- if (b->z < -b->R) /* dropped below bottom of glass - turn it off */
- b->alive_p = False;
-}
-
-
-/* This function makes sure that balls that are part of a group always stay
- relatively close to each other.
- */
-static void
-clamp_balls (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
- for (i = 0; i < bp->nballs; i++)
- {
- metaball *b = &bp->balls[i];
- if (b->alive_p && b->leader)
- {
- double zslack = 0.1;
- double minz = b->leader->z - zslack;
- double maxz = b->leader->z + zslack;
-
- /* Try to keep the Z values near those of the leader.
- Don't let it go out of range (above or below) and clamp it
- if it does. If we've clamped it, make sure dz will be
- moving it in the right direction (back toward the leader.)
-
- We aren't currently clamping r, only z -- doesn't seem to
- be needed.
-
- This is kind of flaky, I think. Sometimes you can see
- the blobbies "twitch". That's no good.
- */
-
- if (b->z < minz)
- {
- if (b->dz < 0) b->dz = -b->dz;
- b->z = minz - b->dz;
- }
-
- if (b->z > maxz)
- {
- if (b->dz > 0) b->dz = -b->dz;
- b->z = maxz + b->dz;
- }
- }
- }
-}
-
-
-static void
-move_balls (ModeInfo *mi) /* for great justice */
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- int i;
- for (i = 0; i < bp->nballs; i++)
- {
- metaball *b = &bp->balls[i];
- if (b->alive_p)
- move_ball (mi, b);
- }
-
- clamp_balls (mi);
-}
-
-
-
-/* Rendering blobbies using marching cubes.
- */
-
-static double
-compute_metaball_influence (lavalite_configuration *bp,
- double x, double y, double z,
- int nballs, metaball *balls)
-{
- double vv = 0;
- int i;
-
- for (i = 0; i < nballs; i++)
- {
- metaball *b = &balls[i];
- double dx, dy, dz;
- double d2, r, R, r2, R2;
-
- if (!b->alive_p) continue;
-
- dx = x - b->x;
- dy = y - b->y;
- dz = z - b->z;
- R = b->R;
-
- if (dx > R || dx < -R || /* quick check before multiplying */
- dy > R || dy < -R ||
- dz > R || dz < -R)
- continue;
-
- d2 = (dx*dx + dy*dy + dz*dz);
- r = b->r;
-
- r2 = r*r;
- R2 = R*R;
-
- if (d2 <= r2) /* (d <= r) inside the hard radius */
- vv += 1;
- else if (d2 > R2) /* (d > R) outside the radius of influence */
- ;
- else /* somewhere in between: linear drop-off from r=1 to R=0 */
- {
- /* was: vv += 1 - ((d-r) / (R-r)); */
- vv += 1 - ((d2-r2) / (R2-r2));
- }
- }
-
- return vv;
-}
-
-
-/* callback for marching_cubes() */
-static void *
-obj_init (double grid_size, void *closure)
-{
- lavalite_configuration *bp = (lavalite_configuration *) closure;
- bp->grid_size = grid_size;
-
- return closure;
-}
-
-
-/* Returns True if the given point is outside of the glass tube.
- */
-static double
-clipped_by_glass_p (double x, double y, double z,
- lavalite_configuration *bp)
-{
- double d2, or, or2, ir2;
-
- or = bp->max_bottle_radius;
-
- if (x > or || x < -or || /* quick check before multiplying */
- y > or || y < -or)
- return 0;
-
- d2 = (x*x + y*y);
- or = bottle_radius_at (bp, z);
-
- or2 = or*or;
-
- if (d2 > or2) /* (sqrt(d) > or) */
- return 0;
-
- ir2 = or2 * 0.7;
-
- if (d2 > ir2) /* (sqrt(d) > ir) */
- {
- double dr1 = or2;
- double dr2 = ir2;
- /* was: (1 - (d-ratio2) / (ratio1-ratio2)) */
- return (1 - (d2-dr2) / (dr1-dr2));
- }
-
- return 1;
-}
-
-
-
-/* callback for marching_cubes() */
-static double
-obj_compute (double x, double y, double z, void *closure)
-{
- lavalite_configuration *bp = (lavalite_configuration *) closure;
- double clip;
-
- x /= bp->grid_size; /* convert from 0-N to 0-1. */
- y /= bp->grid_size;
- z /= bp->grid_size;
-
- x -= 0.5; /* X and Y range from -.5 to +.5; z ranges from 0-1. */
- y -= 0.5;
-
- clip = clipped_by_glass_p (x, y, z, bp);
- if (clip == 0) return 0;
-
- return (clip *
- compute_metaball_influence (bp, x, y, z, bp->nballs, bp->balls));
-}
-
-
-/* callback for marching_cubes() */
-static void
-obj_free (void *closure)
-{
-}
-
-
-/* Send a new blob travelling upward.
- This blob will actually be composed of N metaballs that are near
- each other.
- */
-static void
-launch_balls (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- metaball *b0 = get_ball (mi);
- int i;
-
- if (!b0) return;
- reset_ball (mi, b0);
-
- for (i = 0; i < bp->blobs_per_group; i++)
- {
- metaball *b1 = get_ball (mi);
- if (!b1) break;
- *b1 = *b0;
-
- reset_ball (mi, b1);
- b1->leader = b0;
-
-# define FROB(FIELD,AMT) \
- b1->FIELD += (bellrand(AMT) * b0->FIELD)
-
- /* FROB (pos_r, 0.7); */
- /* FROB (pos_th, 0.7); */
- FROB (dr, 0.8);
- FROB (dz, 0.6);
-# undef FROB
- }
-
-}
-
-
-static void
-animate_lava (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- int wire = MI_IS_WIREFRAME(mi);
- Bool just_started_p = bp->just_started_p;
-
- double isolevel = 0.3;
-
- /* Maybe bubble a new blobby to the surface.
- */
- if (just_started_p ||
- frand(1.0) < bp->launch_chance)
- {
- bp->just_started_p = False;
- launch_balls (mi);
-
- if (do_impatient && just_started_p)
- while (1)
- {
- int i;
- move_balls (mi);
- for (i = 0; i < bp->nballs; i++)
- {
- metaball *b = &bp->balls[i];
- if (b->alive_p && !b->static_p && !b->leader &&
- b->z > 0.5)
- goto DONE;
- }
- }
- DONE: ;
- }
-
- move_balls (mi);
-
- glNewList (bp->ball_list, GL_COMPILE);
- glPushMatrix();
-
- glMaterialfv (GL_FRONT, GL_SPECULAR, lava_spec);
- glMateriali (GL_FRONT, GL_SHININESS, lava_shininess);
- glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, lava_color);
-
- /* For the blobbies, the origin is on the axis at the bottom of the
- glass bottle; and the top of the bottle is +1 on Z.
- */
- glTranslatef (0, 0, -0.5);
-
- mi->polygon_count = 0;
- {
- double s;
- if (bp->grid_size == 0) bp->grid_size = 1; /* first time through */
- s = 1.0/bp->grid_size;
-
- glPushMatrix();
- glTranslatef (-0.5, -0.5, 0);
- glScalef (s, s, s);
- marching_cubes (resolution, isolevel, wire, do_smooth,
- obj_init, obj_compute, obj_free, bp,
- &mi->polygon_count);
- glPopMatrix();
- }
-
- mi->polygon_count += bp->bottle_poly_count;
-
- glPopMatrix();
- glEndList ();
-}
-
-
-
-/* Startup initialization
- */
-
-ENTRYPOINT Bool
-lavalite_handle_event (ModeInfo *mi, XEvent *event)
-{
- lavalite_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;
-}
-
-
-static void
-parse_color (ModeInfo *mi, const char *name, const char *s, GLfloat *a)
-{
- XColor c;
- a[3] = 1.0; /* alpha */
-
- if (! XParseColor (MI_DISPLAY(mi), MI_COLORMAP(mi), s, &c))
- {
- fprintf (stderr, "%s: can't parse %s color %s", progname, name, s);
- exit (1);
- }
- a[0] = c.red / 65536.0;
- a[1] = c.green / 65536.0;
- a[2] = c.blue / 65536.0;
-}
-
-
-ENTRYPOINT void
-init_lavalite (ModeInfo *mi)
-{
- lavalite_configuration *bp;
- int wire = MI_IS_WIREFRAME(mi);
-
- MI_INIT (mi, bps);
-
- bp = &bps[MI_SCREEN(mi)];
-
- bp->glx_context = init_GL(mi);
-
- reshape_lavalite (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
-
- {
- char *s = do_style;
- if (!s || !*s || !strcasecmp (s, "classic")) bp->style = CLASSIC;
- else if (!strcasecmp (s, "giant")) bp->style = GIANT;
- else if (!strcasecmp (s, "cone")) bp->style = CONE;
- else if (!strcasecmp (s, "rocket")) bp->style = ROCKET;
- else if (!strcasecmp (s, "random"))
- {
- if (random() & 1) bp->style = CLASSIC; /* half the time */
- else bp->style = (random() % ((int) ROCKET+1));
- }
- else
- {
- fprintf (stderr,
- "%s: style must be Classic, Giant, Cone, or Rocket (not \"%s\")\n",
- progname, s);
- exit (1);
- }
- }
-
- parse_color (mi, "lava", lava_color_str, lava_color);
- parse_color (mi, "fluid", fluid_color_str, fluid_color);
- parse_color (mi, "base", base_color_str, base_color);
- parse_color (mi, "table", table_color_str, table_color);
-
- if (!wire)
- {
- GLfloat amb[4] = {0.0, 0.0, 0.0, 1.0};
- GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
- GLfloat spc0[4] = {0.0, 1.0, 1.0, 1.0};
- GLfloat spc1[4] = {1.0, 0.0, 1.0, 1.0};
-
- glEnable(GL_LIGHTING);
- glEnable(GL_LIGHT0);
- glEnable(GL_LIGHT1);
- glEnable(GL_DEPTH_TEST);
- glEnable(GL_CULL_FACE);
- glEnable(GL_NORMALIZE);
- glShadeModel(GL_SMOOTH);
-
- glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT0, GL_SPECULAR, spc0);
-
- glLightfv(GL_LIGHT1, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT1, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT1, GL_SPECULAR, spc1);
-
- glLightfv(GL_LIGHT2, GL_AMBIENT, amb);
- glLightfv(GL_LIGHT2, GL_DIFFUSE, dif);
- glLightfv(GL_LIGHT2, GL_SPECULAR, spc0);
- }
-
- {
- Bool spinx=False, spiny=False, spinz=False;
- double spin_speed = 0.4;
- double wander_speed = 0.03;
-
- char *s = do_spin;
- while (*s)
- {
- if (*s == 'x' || *s == 'X') spinx = True;
- else if (*s == 'y' || *s == 'Y') spiny = True;
- else if (*s == 'z' || *s == 'Z') spinz = True;
- else if (*s == '0') ;
- else
- {
- fprintf (stderr,
- "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
- progname, do_spin);
- exit (1);
- }
- s++;
- }
-
- bp->rot = make_rotator (spinx ? spin_speed : 0,
- spiny ? spin_speed : 0,
- spinz ? spin_speed : 0,
- 1.0,
- do_wander ? wander_speed : 0,
- False);
- bp->rot2 = make_rotator (spin_speed, 0, 0,
- 1, 0.1,
- False);
- bp->trackball = gltrackball_init (False);
-
- /* Tilt the scene a bit: lean the normal lamps toward the viewer,
- and the huge lamps away. */
- gltrackball_reset (bp->trackball,
- -0.3 + frand(0.6),
- (bp->style == ROCKET || bp->style == GIANT
- ? frand (0.2)
- : -frand (0.6)));
- }
-
- switch (bp->style)
- {
- case CLASSIC: bp->model = classic_lamp; break;
- case GIANT: bp->model = giant_lamp; break;
- case CONE: bp->model = cone_lamp; break;
- case ROCKET: bp->model = rocket_lamp; break;
- default: abort(); break;
- }
-
- bp->max_bottle_radius = max_bottle_radius (bp);
-
- bp->launch_chance = speed;
- bp->blobs_per_group = BLOBS_PER_GROUP;
- bp->just_started_p = True;
-
- bp->nballs = (((MI_COUNT (mi) + 1) * bp->blobs_per_group)
- + 2);
- bp->balls = (metaball *) calloc (sizeof(*bp->balls), bp->nballs+1);
-
- bp->bottle_list = glGenLists (1);
- bp->ball_list = glGenLists (1);
-
- generate_bottle (mi);
- generate_static_blobs (mi);
-}
-
-
-/* Render one frame
- */
-
-ENTRYPOINT void
-draw_lavalite (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- Display *dpy = MI_DISPLAY(mi);
- Window window = MI_WINDOW(mi);
-
- if (!bp->glx_context)
- return;
-
- glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
-
- glMatrixMode (GL_MODELVIEW);
- glPushMatrix ();
-
- {
- double cx, cy, cz; /* camera position, 0-1. */
- double px, py, pz; /* object position, 0-1. */
- double rx, ry, rz; /* object rotation, 0-1. */
-
- get_position (bp->rot2, 0, &cy, &cz, !bp->button_down_p);
- get_rotation (bp->rot2, &cx, 0, 0, !bp->button_down_p);
-
- get_position (bp->rot, &px, &py, &pz, !bp->button_down_p);
- get_rotation (bp->rot, &rx, &ry, &rz, !bp->button_down_p);
-
-#if 1
- cx = 0.5;
- cy = 0.5;
- cz = 1.0;
-
-#else /* #### this crud doesn't really work yet */
-
-
- /* We have c[xyz] parameters describing a camera position, but we don't
- want to just map those to points in space: the lamp doesn't look very
- good from the inside, or from underneath...
-
- Good observation points form a ring around the lamp: basically, a
- torus ringing the lamp, parallel to the lamp's floor.
-
- We interpret cz as distance from the origin.
- cy as elevation.
- cx is then used as position in the torus (theta).
- */
-
- {
- double cx2, cy2, cz2;
- double d;
-
- cx2 = 0.5;
- cy2 = 0.5;
- cz2 = 1.0;
-
- cy2 = (cy * 0.4); /* cam elevation: 0.0 (table) - 0.4 up. */
- d = 0.9 + cz; /* cam distance: 0.9 - 1.9. */
-
- cz2 = 0.5 + (d * cos (cx * M_PI * 2));
- cx2 = 0.5 + (d * sin (cx * M_PI * 2));
-
-
- cx = cx2;
- cy = cy2;
- cz = cz2;
- }
-#endif /* 0 */
-
- glLoadIdentity();
- glRotatef(current_device_rotation(), 0, 0, 1);
-
- gluLookAt ((cx - 0.5) * 8, /* Position the camera */
- (cy - 0.5) * 8,
- (cz - 0.5) * 8,
- 0, 0, 0,
- 0, 1, 0);
-
- gltrackball_rotate (bp->trackball); /* Apply mouse-based camera position */
-
- glRotatef (-90, 1, 0, 0); /* Right side up */
-
-
- /* Place the lights relative to the object, before the object has
- been rotated or wandered within the scene. */
- glLightfv(GL_LIGHT0, GL_POSITION, light0_pos);
- glLightfv(GL_LIGHT1, GL_POSITION, light1_pos);
- glLightfv(GL_LIGHT2, GL_POSITION, light2_pos);
-
-
- /* Position the lamp in the scene according to the "wander" settings */
- glTranslatef ((px - 0.5), (py - 0.5), (pz - 0.5));
-
- /* Rotate the object according to the "spin" settings */
- glRotatef (rx * 360, 1.0, 0.0, 0.0);
- glRotatef (ry * 360, 0.0, 1.0, 0.0);
- glRotatef (rz * 360, 0.0, 0.0, 1.0);
-
- /* Move the lamp up slightly: make 0,0 be at its vertical center. */
- switch (bp->style)
- {
- case CLASSIC: glTranslatef (0, 0, 0.33); break;
- case GIANT: glTranslatef (0, 0, 0.33); break;
- case CONE: glTranslatef (0, 0, 0.16); break;
- case ROCKET: glTranslatef (0, 0, 0.30);
- glScalef (0.85,0.85,0.85); break;
- default: abort(); break;
- }
- }
-
- animate_lava (mi);
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glCallList (bp->bottle_list);
- glCallList (bp->ball_list);
- glPopMatrix ();
-
- if (mi->fps_p) do_fps (mi);
- glFinish();
-
- glXSwapBuffers(dpy, window);
-}
-
-
-ENTRYPOINT void
-free_lavalite (ModeInfo *mi)
-{
- lavalite_configuration *bp = &bps[MI_SCREEN(mi)];
- if (!bp->glx_context) return;
- glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *bp->glx_context);
- if (bp->balls) free (bp->balls);
- if (bp->trackball) gltrackball_free (bp->trackball);
- if (bp->rot) free_rotator (bp->rot);
- if (bp->rot2) free_rotator (bp->rot2);
- if (glIsList(bp->bottle_list)) glDeleteLists(bp->bottle_list, 1);
- if (glIsList(bp->ball_list)) glDeleteLists(bp->ball_list, 1);
-}
-
-XSCREENSAVER_MODULE ("Lavalite", lavalite)
-
-#endif /* USE_GL */