/* xscreensaver, Copyright (c) 2002-2014 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.
*
* Algorithm by Paul Bourke <pbourke@swin.edu.au>
* http://astronomy.swin.edu.au/~pbourke/geometry/sphericalh/
* Screensaver veneer and parameter selection by jwz.
*
* Paul says:
*
* These closed objects are commonly called spherical harmonics,
* although they are only remotely related to the mathematical
* definition found in the solution to certain wave functions, most
* notable the eigenfunctions of angular momentum operators.
*
* The formula is quite simple: the form used here is based upon
* spherical (polar) coordinates (radius, theta, phi).
*
* r = sin(m0 phi) ^ m1 +
* cos(m2 phi) ^ m3 +
* sin(m4 theta) ^ m5 +
* cos(m6 theta) ^ m7
*
* Where phi ranges from 0 to pi (lines of latitude), and theta ranges
* from 0 to 2 pi (lines of longitude), and r is the radius. The
* parameters m0, m1, m2, m3, m4, m5, m6, and m7 are all integers
* greater than or equal to 0.
*
* As the degree increases, the objects become increasingly "pointed"
* and a large number of polygons are required to represent the surface
* faithfully.
*
* jwz adds:
*
* The eight parameters live in the `cc->m' array.
* Each time we permute the image, we alter *one* of those eight parameters.
* Each time we alter a parameter, we move it in the same direction (either
* toward larger or smaller values) in the range [0, 3].
*
* By altering only one parameter at a time, and only by small amounts,
* we tend to produce successive objects that are pretty similar to each
* other, so you can see a progression.
*
* It'd be nice if they were even closer together, so that it looked more
* like a morph, but, well, that's not how it works.
*
* There tends to be a dark stripe in the colormaps. I don't know why.
* Perhaps utils/colors.c is at fault?
*
* Note that this equation sometimes generates faces that are inside out:
* -parameters 01210111
* To make this work, we need to render back-faces with two-sided lighting:
* figuring out how to correct the winding and normals on those inside out
* surfaces would be too hard.
*/
#define DEFAULTS "*delay: 30000 \n" \
"*showFPS: False \n" \
"*wireframe: False \n" \
"*suppressRotationAnimation: True\n" \
"*labelfont: -*-helvetica-medium-r-normal-*-*-180-*-*-*-*-*-*\n"
# define free_spheremonics 0
# define release_spheremonics 0
#undef countof
#define countof(x) (sizeof((x))/sizeof((*x)))
#include "xlockmore.h"
#include "texfont.h"
#include "normals.h"
#include "colors.h"
#include "rotator.h"
#include "gltrackball.h"
#include <ctype.h>
#ifdef USE_GL /* whole file */
#define DEF_DURATION "100"
#define DEF_SPIN "XYZ"
#define DEF_WANDER "False"
#define DEF_RESOLUTION "64"
#define DEF_BBOX "False"
#define DEF_GRID "True"
#define DEF_SMOOTH "True"
#define DEF_PARMS "(default)"
typedef struct {
GLXContext *glx_context;
rotator *rot;
trackball_state *trackball;
Bool button_down_p;
GLuint dlist, dlist2;
GLfloat scale;
XYZ bbox[2];
int resolution;
int ncolors;
XColor *colors;
int m[8];
int dm[8];
int m_max;
int tracer;
int mesher;
int polys1, polys2; /* polygon counts */
texture_font_data *font_data;
int change_tick;
int done_once;
} spheremonics_configuration;
static spheremonics_configuration *ccs = NULL;
static char *do_spin;
static Bool do_wander;
static Bool do_bbox;
static Bool do_grid;
static int smooth_p;
static char *static_parms;
static int res;
static int duration;
static XrmOptionDescRec opts[] = {
{ "-spin", ".spin", XrmoptionSepArg, 0 },
{ "+spin", ".spin", XrmoptionNoArg, "" },
{ "-wander", ".wander", XrmoptionNoArg, "True" },
{ "+wander", ".wander", XrmoptionNoArg, "False" },
{ "-resolution", ".resolution", XrmoptionSepArg, 0 },
{ "-duration", ".duration", XrmoptionSepArg, 0 },
{ "-bbox", ".bbox", XrmoptionNoArg, "True" },
{ "+bbox", ".bbox", XrmoptionNoArg, "False" },
{ "-grid", ".grid", XrmoptionNoArg, "True" },
{ "+grid", ".grid", XrmoptionNoArg, "False" },
{"-smooth", ".smooth", XrmoptionNoArg, "True" },
{"+smooth", ".smooth", XrmoptionNoArg, "False" },
{ "-parameters", ".parameters", XrmoptionSepArg, 0 },
};
static argtype vars[] = {
{&do_spin, "spin", "Spin", DEF_SPIN, t_String},
{&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
{&res, "resolution", "Resolution", DEF_RESOLUTION, t_Int},
{&duration, "duration", "Duration", DEF_DURATION, t_Int},
{&do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool},
{&do_grid, "grid", "Grid", DEF_GRID, t_Bool},
{&smooth_p, "smooth", "Smooth", DEF_SMOOTH, t_Bool},
{&static_parms, "parameters", "Parameters", DEF_PARMS, t_String},
};
ENTRYPOINT ModeSpecOpt spheremonics_opts = {countof(opts), opts, countof(vars), vars, NULL};
/* Window management, etc
*/
ENTRYPOINT void
reshape_spheremonics (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);
# 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 (1/h, 1/h, 1/h);
}
# endif
glClear(GL_COLOR_BUFFER_BIT);
}
static void
gl_init (ModeInfo *mi)
{
/* spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; */
int wire = MI_IS_WIREFRAME(mi);
static const GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
glEnable(GL_NORMALIZE);
if (!wire)
{
glLightfv(GL_LIGHT0, GL_POSITION, pos);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_DEPTH_TEST);
/* With objects that have proper winding and normals set up on all
their faces, one can cull back-faces; however, these equations
generate objects that are sometimes "inside out", and determining
whether a facet has been inverted like that is really hard.
So we render both front and back faces, at a probable performance
penalty on non-accelerated systems.
When rendering back faces, we also need to do two-sided lighting,
or the fact that the normals are flipped gives us too-dark surfaces
on the inside-out surfaces.
This isn't generally something you'd want, because you end up
with half the lighting dynamic range (kind of.) So if you had
a sphere with correctly pointing normals, and a single light
source, it would be illuminated from two sides. In this case,
though, it saves us from a difficult and time consuming
inside/outside test. And we don't really care about a precise
lighting effect.
*/
glDisable(GL_CULL_FACE);
glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, True);
}
if (smooth_p)
{
glEnable (GL_LINE_SMOOTH);
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable (GL_BLEND);
}
}
/* generate the object */
static XYZ
sphere_eval (double theta, double phi, int *m)
{
double r = 0;
XYZ p;
r += pow (sin(m[0] * phi), (double)m[1]);
r += pow (cos(m[2] * phi), (double)m[3]);
r += pow (sin(m[4] * theta),(double)m[5]);
r += pow (cos(m[6] * theta),(double)m[7]);
p.x = r * sin(phi) * cos(theta);
p.y = r * cos(phi);
p.z = r * sin(phi) * sin(theta);
return (p);
}
static void
do_color (int i, XColor *colors)
{
GLfloat c[4];
c[0] = colors[i].red / 65535.0;
c[1] = colors[i].green / 65535.0;
c[2] = colors[i].blue / 65535.0;
c[3] = 1.0;
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
glColor3f (c[0], c[1], c[2]);
}
static void
draw_circle (ModeInfo *mi, Bool teeth_p)
{
GLfloat th;
int tick = 0;
GLfloat x, y;
GLfloat step = (M_PI / 180);
glBegin(GL_LINE_LOOP);
for (th = 0; th < M_PI*2; th += step*5)
{
GLfloat r1 = 0.5;
x = cos (th);
y = sin (th);
glVertex3f(x*r1, y*r1, 0);
}
glEnd();
if (!teeth_p) return;
glBegin(GL_LINES);
for (th = 0; th < M_PI*2; th += step)
{
GLfloat r1 = 0.5;
GLfloat r2 = r1 - 0.01;
if (! (tick % 10))
r2 -= 0.02;
else if (! (tick % 5))
r2 -= 0.01;
tick++;
x = cos (th);
y = sin (th);
glVertex3f(x*r1, y*r1, 0);
glVertex3f(x*r2, y*r2, 0);
}
glEnd();
}
static void
draw_bounding_box (ModeInfo *mi)
{
/* spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; */
static const GLfloat c1[4] = { 0.2, 0.2, 0.6, 1.0 };
static const GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
int wire = MI_IS_WIREFRAME(mi);
GLfloat x1,y1,z1,x2,y2,z2;
# if 0
x1 = cc->bbox[0].x;
y1 = cc->bbox[0].y;
z1 = cc->bbox[0].z;
x2 = cc->bbox[1].x;
y2 = cc->bbox[1].y;
z2 = cc->bbox[1].z;
# else
x1 = y1 = z1 = -0.5;
x2 = y2 = z2 = 0.5;
# endif
if (do_bbox && !wire)
{
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);
glFrontFace(GL_CCW);
glEnable(GL_CULL_FACE);
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(0, 1, 0);
glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(0, -1, 0);
glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2);
glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(0, 0, 1);
glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(0, 0, -1);
glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2);
glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(1, 0, 0);
glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
glEnd();
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
glNormal3f(-1, 0, 0);
glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2);
glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
glEnd();
glDisable(GL_CULL_FACE);
}
if (do_grid)
{
glDisable (GL_LIGHTING);
glColor3f (c2[0], c2[1], c2[2]);
glPushMatrix();
glBegin(GL_LINES);
glVertex3f(0, -0.66, 0);
glVertex3f(0, 0.66, 0);
glEnd();
draw_circle (mi, True);
glRotatef(90, 1, 0, 0);
draw_circle (mi, True);
glRotatef(90, 0, 1, 0);
draw_circle (mi, True);
glPopMatrix();
}
else
{
#if 0
glBegin(GL_LINES);
if (x1 > 0) x1 = 0; if (x2 < 0) x2 = 0;
if (y1 > 0) y1 = 0; if (y2 < 0) y2 = 0;
if (z1 > 0) z1 = 0; if (z2 < 0) z2 = 0;
glVertex3f(x1, 0, 0); glVertex3f(x2, 0, 0);
glVertex3f(0 , y1, 0); glVertex3f(0, y2, 0);
glVertex3f(0, 0, z1); glVertex3f(0, 0, z2);
glEnd();
#endif
}
}
static void
do_tracer (ModeInfo *mi)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
if (cc->tracer == -1 &&
cc->mesher == -1 &&
!(random() % (duration * 4)))
{
if (random() & 1)
cc->tracer = ((random() & 1) ? 0 : 180);
else
cc->mesher = ((random() % ((duration / 3) + 1)) +
(random() % ((duration / 3) + 1)));
}
if (cc->tracer >= 0)
{
int d = (90 - cc->tracer);
GLfloat th = d * (M_PI / 180);
GLfloat x = cos (th);
GLfloat y = sin (th);
GLfloat s = 1.5 / cc->scale;
if (s > 0.001)
{
static const GLfloat c[4] = { 0.6, 0.5, 1.0, 1.0 };
glDisable (GL_LIGHTING);
glPushMatrix();
glRotatef (90, 1, 0, 0);
glTranslatef (0, 0, y*s/2);
s *= x;
glScalef(s, s, s);
glColor3f (c[0], c[1], c[2]);
draw_circle (mi, False);
glPopMatrix();
if (! MI_IS_WIREFRAME(mi)) glEnable (GL_LIGHTING);
}
cc->tracer += 5;
if (cc->tracer == 180 || cc->tracer == 360)
cc->tracer = -1;
}
}
static int
unit_spheremonics (ModeInfo *mi,
int resolution, Bool wire, int *m, XColor *colors)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
int polys = 0;
int i, j;
double du, dv;
XYZ q[4];
XYZ n[4];
int res = (wire == 2
? resolution / 2
: resolution);
cc->bbox[0].x = cc->bbox[0].y = cc->bbox[0].z = 0;
cc->bbox[1].x = cc->bbox[1].y = cc->bbox[1].z = 0;
du = (M_PI+M_PI) / (double)res; /* Theta */
dv = M_PI / (double)res; /* Phi */
if (wire)
glColor3f (1, 1, 1);
glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
for (i = 0; i < res; i++) {
double u = i * du;
for (j = 0; j < res; j++) {
double v = j * dv;
q[0] = sphere_eval (u, v, m);
n[0] = calc_normal(q[0],
sphere_eval (u+du/10, v, m),
sphere_eval (u, v+dv/10, m));
glNormal3f(n[0].x,n[0].y,n[0].z);
if (!wire) do_color (i, colors);
glVertex3f(q[0].x,q[0].y,q[0].z);
q[1] = sphere_eval (u+du, v, m);
n[1] = calc_normal(q[1],
sphere_eval (u+du+du/10, v, m),
sphere_eval (u+du, v+dv/10, m));
glNormal3f(n[1].x,n[1].y,n[1].z);
if (!wire) do_color ((i+1)%res, colors);
glVertex3f(q[1].x,q[1].y,q[1].z);
q[2] = sphere_eval (u+du, v+dv, m);
n[2] = calc_normal(q[2],
sphere_eval (u+du+du/10, v+dv, m),
sphere_eval (u+du, v+dv+dv/10, m));
glNormal3f(n[2].x,n[2].y,n[2].z);
if (!wire) do_color ((i+1)%res, colors);
glVertex3f(q[2].x,q[2].y,q[2].z);
q[3] = sphere_eval (u,v+dv, m);
n[3] = calc_normal(q[3],
sphere_eval (u+du/10, v+dv, m),
sphere_eval (u, v+dv+dv/10, m));
glNormal3f(n[3].x,n[3].y,n[3].z);
if (!wire) do_color (i, colors);
glVertex3f(q[3].x,q[3].y,q[3].z);
polys++;
# define CHECK_BBOX(N) \
if (q[(N)].x < cc->bbox[0].x) cc->bbox[0].x = q[(N)].x; \
if (q[(N)].y < cc->bbox[0].y) cc->bbox[0].y = q[(N)].y; \
if (q[(N)].z < cc->bbox[0].z) cc->bbox[0].z = q[(N)].z; \
if (q[(N)].x > cc->bbox[1].x) cc->bbox[1].x = q[(N)].x; \
if (q[(N)].y > cc->bbox[1].y) cc->bbox[1].y = q[(N)].y; \
if (q[(N)].z > cc->bbox[1].z) cc->bbox[1].z = q[(N)].z
CHECK_BBOX(0);
CHECK_BBOX(1);
CHECK_BBOX(2);
CHECK_BBOX(3);
# undef CHECK_BBOX
}
}
glEnd();
{
GLfloat w = cc->bbox[1].x - cc->bbox[0].x;
GLfloat h = cc->bbox[1].y - cc->bbox[0].y;
GLfloat d = cc->bbox[1].z - cc->bbox[0].z;
GLfloat wh = (w > h ? w : h);
GLfloat hd = (h > d ? h : d);
GLfloat scale = (wh > hd ? wh : hd);
cc->scale = 1/scale;
if (wire < 2 && (do_bbox || do_grid))
{
GLfloat s = scale * 1.5;
glPushMatrix();
glScalef(s, s, s);
draw_bounding_box (mi);
glPopMatrix();
}
}
return polys;
}
static void
init_colors (ModeInfo *mi)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
int i;
cc->ncolors = cc->resolution;
cc->colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
make_smooth_colormap (0, 0, 0,
cc->colors, &cc->ncolors,
False, 0, False);
/* brighter colors, please... */
for (i = 0; i < cc->ncolors; i++)
{
cc->colors[i].red = (cc->colors[i].red / 2) + 32767;
cc->colors[i].green = (cc->colors[i].green / 2) + 32767;
cc->colors[i].blue = (cc->colors[i].blue / 2) + 32767;
}
}
/* Pick one of the parameters to the function and tweak it up or down.
*/
static void
tweak_parameters (ModeInfo *mi)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
/* If the -parameters command line option was specified, just use that
all the time.
*/
if (static_parms &&
*static_parms &&
!!strcasecmp (static_parms, "(default)"))
{
unsigned long n;
char dummy;
if (8 == sscanf (static_parms, "%d %d %d %d %d %d %d %d %c",
&cc->m[0], &cc->m[1], &cc->m[2], &cc->m[3],
&cc->m[4], &cc->m[5], &cc->m[6], &cc->m[7],
&dummy))
return;
else if (strlen (static_parms) == 8 &&
1 == sscanf (static_parms, "%lu %c", &n, &dummy))
{
const char *s = static_parms;
int i = 0;
while (*s)
cc->m[i++] = (*s++)-'0';
return;
}
fprintf (stderr,
"%s: -parameters must be a string of 8 ints (not \"%s\")\n",
progname, static_parms);
exit (1);
}
static_parms = 0;
# define SHIFT(N) do { \
int n = (N); \
cc->m[n] += cc->dm[n]; \
if (cc->m[n] <= 0) \
cc->m[n] = 0, cc->dm[n] = -cc->dm[n]; \
else if (cc->m[n] >= cc->m_max) \
cc->m[n] = cc->m_max, cc->dm[n] = -cc->dm[n]; \
} while(0)
/* else if (cc->m[n] >= cc->m_max/2 && (! (random() % 3))) \
cc->m[n] = cc->m_max/2, cc->dm[n] = -cc->dm[n]; \
*/
switch(random() % 8)
{
case 0: SHIFT(0); break;
case 1: SHIFT(1); break;
case 2: SHIFT(2); break;
case 3: SHIFT(3); break;
case 4: SHIFT(4); break;
case 5: SHIFT(5); break;
case 6: SHIFT(6); break;
case 7: SHIFT(7); break;
default: abort(); break;
}
# undef SHIFT
#if 0
printf ("%s: state: %d %d %d %d %d %d %d %d\n",
progname,
cc->m[0], cc->m[1], cc->m[2], cc->m[3],
cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
#endif
}
static void
generate_spheremonics (ModeInfo *mi)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
int wire = MI_IS_WIREFRAME(mi);
tweak_parameters (mi);
if (!cc->done_once || (0 == (random() % 20)))
{
init_colors (mi);
cc->done_once = True;
}
{
glNewList(cc->dlist, GL_COMPILE);
cc->polys1 = unit_spheremonics (mi, cc->resolution, wire,cc->m,cc->colors);
glEndList();
glNewList(cc->dlist2, GL_COMPILE);
glPushMatrix();
glScalef (1.05, 1.05, 1.05);
cc->polys2 = unit_spheremonics (mi, cc->resolution, 2, cc->m, cc->colors);
glPopMatrix();
glEndList();
}
}
ENTRYPOINT void
init_spheremonics (ModeInfo *mi)
{
spheremonics_configuration *cc;
MI_INIT (mi, ccs);
cc = &ccs[MI_SCREEN(mi)];
if ((cc->glx_context = init_GL(mi)) != NULL) {
gl_init(mi);
reshape_spheremonics (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
}
{
Bool spinx=False, spiny=False, spinz=False;
double spin_speed = 1.0;
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++;
}
cc->rot = make_rotator (spinx ? spin_speed : 0,
spinz ? spin_speed : 0,
spiny ? spin_speed : 0,
1.0,
do_wander ? wander_speed : 0,
(spinx && spiny && spinz));
cc->trackball = gltrackball_init (True);
}
cc->tracer = -1;
cc->mesher = -1;
cc->resolution = res;
cc->font_data = load_texture_font (mi->dpy, "labelfont");
cc->dlist = glGenLists(1);
cc->dlist2 = glGenLists(1);
cc->m_max = 4; /* 9? */
{
unsigned int i;
for (i = 0; i < countof(cc->dm); i++)
cc->dm[i] = 1; /* going up! */
/* Generate a few more times so we don't always start off with a sphere */
for (i = 0; i < 5; i++)
tweak_parameters (mi);
}
generate_spheremonics(mi);
}
ENTRYPOINT Bool
spheremonics_handle_event (ModeInfo *mi, XEvent *event)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
if (gltrackball_event_handler (event, cc->trackball,
MI_WIDTH (mi), MI_HEIGHT (mi),
&cc->button_down_p))
return True;
else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
{
cc->change_tick = duration;
return True;
}
return False;
}
ENTRYPOINT void
draw_spheremonics (ModeInfo *mi)
{
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
Display *dpy = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
if (!cc->glx_context)
return;
glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(cc->glx_context));
gl_init(mi);
glShadeModel(GL_SMOOTH);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glPushMatrix ();
glScalef(1.1, 1.1, 1.1);
{
double x, y, z;
get_position (cc->rot, &x, &y, &z, !cc->button_down_p);
glTranslatef((x - 0.5) * 8,
(y - 0.5) * 6,
(z - 0.5) * 8);
gltrackball_rotate (cc->trackball);
get_rotation (cc->rot, &x, &y, &z, !cc->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);
}
glScalef(7,7,7);
mi->polygon_count = 0;
glScalef (cc->scale, cc->scale, cc->scale);
glCallList (cc->dlist);
mi->polygon_count += cc->polys1;
if (cc->mesher >= 0 /* || cc->button_down_p */)
{
glDisable (GL_LIGHTING);
glCallList (cc->dlist2);
mi->polygon_count += cc->polys2;
if (cc->mesher >= 0)
cc->mesher--;
}
do_tracer(mi);
if (cc->button_down_p)
{
char buf[200];
sprintf (buf,
((cc->m[0]<10 && cc->m[1]<10 && cc->m[2]<10 && cc->m[3]<10 &&
cc->m[4]<10 && cc->m[5]<10 && cc->m[6]<10 && cc->m[7]<10)
? "%d%d%d%d%d%d%d%d"
: "%d %d %d %d %d %d %d %d"),
cc->m[0], cc->m[1], cc->m[2], cc->m[3],
cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
glColor3f(1.0, 1.0, 0.0);
print_texture_label (mi->dpy, cc->font_data,
mi->xgwa.width, mi->xgwa.height,
1, buf);
}
if (!static_parms)
{
if (cc->change_tick++ >= duration && !cc->button_down_p)
{
generate_spheremonics(mi);
cc->change_tick = 0;
cc->mesher = -1; /* turn off the mesh when switching objects */
}
}
glPopMatrix();
if (mi->fps_p) do_fps (mi);
glFinish();
glXSwapBuffers(dpy, window);
}
XSCREENSAVER_MODULE ("Spheremonics", spheremonics)
#endif /* USE_GL */