/* xscreensaver, Copyright (c) 2002-2014 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. * * Algorithm by Paul Bourke * 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 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 #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); } ENTRYPOINT void free_spheremonics (ModeInfo *mi) { spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; if (!cc->glx_context) return; glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *cc->glx_context); if (cc->colors) free (cc->colors); if (cc->trackball) gltrackball_free (cc->trackball); if (cc->rot) free_rotator (cc->rot); if (cc->font_data) free_texture_font (cc->font_data); if (glIsList(cc->dlist)) glDeleteLists(cc->dlist, 1); if (glIsList(cc->dlist2)) glDeleteLists(cc->dlist2, 1); } XSCREENSAVER_MODULE ("Spheremonics", spheremonics) #endif /* USE_GL */