1
/* xscreensaver, Copyright (c) 2002, 2004 Jamie Zawinski <jwz@jwz.org>
3
* Permission to use, copy, modify, distribute, and sell this software and its
4
* documentation for any purpose is hereby granted without fee, provided that
5
* the above copyright notice appear in all copies and that both that
6
* copyright notice and this permission notice appear in supporting
7
* documentation. No representations are made about the suitability of this
8
* software for any purpose. It is provided "as is" without express or
11
* Algorithm by Paul Bourke <pbourke@swin.edu.au>
12
* http://astronomy.swin.edu.au/~pbourke/geometry/sphericalh/
13
* Screensaver veneer and parameter selection by jwz.
17
* These closed objects are commonly called spherical harmonics,
18
* although they are only remotely related to the mathematical
19
* definition found in the solution to certain wave functions, most
20
* notable the eigenfunctions of angular momentum operators.
22
* The formula is quite simple: the form used here is based upon
23
* spherical (polar) coordinates (radius, theta, phi).
25
* r = sin(m0 phi) ^ m1 +
27
* sin(m4 theta) ^ m5 +
30
* Where phi ranges from 0 to pi (lines of latitude), and theta ranges
31
* from 0 to 2 pi (lines of longitude), and r is the radius. The
32
* parameters m0, m1, m2, m3, m4, m5, m6, and m7 are all integers
33
* greater than or equal to 0.
35
* As the degree increases, the objects become increasingly "pointed"
36
* and a large number of polygons are required to represent the surface
41
* The eight parameters live in the `cc->m' array.
42
* Each time we permute the image, we alter *one* of those eight parameters.
43
* Each time we alter a parameter, we move it in the same direction (either
44
* toward larger or smaller values) in the range [0, 3].
46
* By altering only one parameter at a time, and only by small amounts,
47
* we tend to produce successive objects that are pretty similar to each
48
* other, so you can see a progression.
50
* It'd be nice if they were even closer together, so that it looked more
51
* like a morph, but, well, that's not how it works.
53
* There tends to be a dark stripe in the colormaps. I don't know why.
54
* Perhaps utils/colors.c is at fault?
56
* Note that this equation sometimes generates faces that are inside out:
57
* -parameters 01210111
58
* To make this work, we need to render back-faces with two-sided lighting:
59
* figuring out how to correct the winding and normals on those inside out
60
* surfaces would be too hard.
63
#include <X11/Intrinsic.h>
65
extern XtAppContext app;
67
#define PROGCLASS "Spheremonics"
68
#define HACK_INIT init_spheremonics
69
#define HACK_DRAW draw_spheremonics
70
#define HACK_RESHAPE reshape_spheremonics
71
#define HACK_HANDLE_EVENT spheremonics_handle_event
72
#define EVENT_MASK PointerMotionMask
73
#define ccs_opts xlockmore_opts
75
#define DEF_DURATION "100"
76
#define DEF_SPIN "XYZ"
77
#define DEF_WANDER "False"
78
#define DEF_RESOLUTION "64"
79
#define DEF_BBOX "False"
80
#define DEF_GRID "True"
81
#define DEF_SMOOTH "True"
82
#define DEF_PARMS "(default)"
84
#define DEFAULTS "*delay: 30000 \n" \
85
"*showFPS: False \n" \
86
"*wireframe: False \n" \
89
#define countof(x) (sizeof((x))/sizeof((*x)))
91
#include "xlockmore.h"
96
#include "gltrackball.h"
99
#ifdef USE_GL /* whole file */
104
GLXContext *glx_context;
106
trackball_state *trackball;
109
GLuint dlist, dlist2;
123
int polys1, polys2; /* polygon counts */
129
} spheremonics_configuration;
131
static spheremonics_configuration *ccs = NULL;
133
static char *do_spin;
134
static Bool do_wander;
138
static char *static_parms;
142
static XrmOptionDescRec opts[] = {
143
{ "-spin", ".spin", XrmoptionSepArg, 0 },
144
{ "+spin", ".spin", XrmoptionNoArg, "" },
145
{ "-wander", ".wander", XrmoptionNoArg, "True" },
146
{ "+wander", ".wander", XrmoptionNoArg, "False" },
147
{ "-resolution", ".resolution", XrmoptionSepArg, 0 },
148
{ "-duration", ".duration", XrmoptionSepArg, 0 },
149
{ "-bbox", ".bbox", XrmoptionNoArg, "True" },
150
{ "+bbox", ".bbox", XrmoptionNoArg, "False" },
151
{ "-grid", ".grid", XrmoptionNoArg, "True" },
152
{ "+grid", ".grid", XrmoptionNoArg, "False" },
153
{"-smooth", ".smooth", XrmoptionNoArg, "True" },
154
{"+smooth", ".smooth", XrmoptionNoArg, "False" },
155
{ "-parameters", ".parameters", XrmoptionSepArg, 0 },
158
static argtype vars[] = {
159
{&do_spin, "spin", "Spin", DEF_SPIN, t_String},
160
{&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
161
{&res, "resolution", "Resolution", DEF_RESOLUTION, t_Int},
162
{&duration, "duration", "Duration", DEF_DURATION, t_Int},
163
{&do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool},
164
{&do_grid, "grid", "Grid", DEF_GRID, t_Bool},
165
{&smooth_p, "smooth", "Smooth", DEF_SMOOTH, t_Bool},
166
{&static_parms, "parameters", "Parameters", DEF_PARMS, t_String},
169
ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
172
/* Window management, etc
175
reshape_spheremonics (ModeInfo *mi, int width, int height)
177
GLfloat h = (GLfloat) height / (GLfloat) width;
179
glViewport (0, 0, (GLint) width, (GLint) height);
181
glMatrixMode(GL_PROJECTION);
183
gluPerspective (30.0, 1/h, 1.0, 100.0);
185
glMatrixMode(GL_MODELVIEW);
187
gluLookAt( 0.0, 0.0, 30.0,
191
glClear(GL_COLOR_BUFFER_BIT);
196
gl_init (ModeInfo *mi)
198
/* spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; */
199
int wire = MI_IS_WIREFRAME(mi);
201
static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
203
glEnable(GL_NORMALIZE);
207
glLightfv(GL_LIGHT0, GL_POSITION, pos);
208
glEnable(GL_LIGHTING);
210
glEnable(GL_DEPTH_TEST);
212
/* With objects that have proper winding and normals set up on all
213
their faces, one can cull back-faces; however, these equations
214
generate objects that are sometimes "inside out", and determining
215
whether a facet has been inverted like that is really hard.
216
So we render both front and back faces, at a probable performance
217
penalty on non-accelerated systems.
219
When rendering back faces, we also need to do two-sided lighting,
220
or the fact that the normals are flipped gives us too-dark surfaces
221
on the inside-out surfaces.
223
This isn't generally something you'd want, because you end up
224
with half the lighting dynamic range (kind of.) So if you had
225
a sphere with correctly pointing normals, and a single light
226
source, it would be illuminated from two sides. In this case,
227
though, it saves us from a difficult and time consuming
228
inside/outside test. And we don't really care about a precise
231
glDisable(GL_CULL_FACE);
232
glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, TRUE);
238
/* generate the object */
241
sphere_eval (double theta, double phi, int *m)
246
r += pow (sin(m[0] * phi), (double)m[1]);
247
r += pow (cos(m[2] * phi), (double)m[3]);
248
r += pow (sin(m[4] * theta),(double)m[5]);
249
r += pow (cos(m[6] * theta),(double)m[7]);
251
p.x = r * sin(phi) * cos(theta);
253
p.z = r * sin(phi) * sin(theta);
260
do_color (int i, XColor *colors)
263
c[0] = colors[i].red / 65535.0;
264
c[1] = colors[i].green / 65535.0;
265
c[2] = colors[i].blue / 65535.0;
267
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
268
glColor3f (c[0], c[1], c[2]);
273
draw_circle (ModeInfo *mi, Bool teeth_p)
278
GLfloat step = (M_PI / 180);
280
glBegin(GL_LINE_LOOP);
281
for (th = 0; th < M_PI*2; th += step*5)
286
glVertex3f(x*r1, y*r1, 0);
290
if (!teeth_p) return;
293
for (th = 0; th < M_PI*2; th += step)
296
GLfloat r2 = r1 - 0.01;
299
else if (! (tick % 5))
305
glVertex3f(x*r1, y*r1, 0);
306
glVertex3f(x*r2, y*r2, 0);
313
draw_bounding_box (ModeInfo *mi)
315
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
317
static GLfloat c1[4] = { 0.2, 0.2, 0.6, 1.0 };
318
static GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
319
int wire = MI_IS_WIREFRAME(mi);
321
GLfloat x1 = cc->bbox[0].x;
322
GLfloat y1 = cc->bbox[0].y;
323
GLfloat z1 = cc->bbox[0].z;
324
GLfloat x2 = cc->bbox[1].x;
325
GLfloat y2 = cc->bbox[1].y;
326
GLfloat z2 = cc->bbox[1].z;
333
if (do_bbox && !wire)
335
glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);
338
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
340
glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
341
glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
343
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
344
glNormal3f(0, -1, 0);
345
glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2);
346
glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1);
348
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
350
glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
351
glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
353
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
354
glNormal3f(0, 0, -1);
355
glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2);
356
glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
358
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
360
glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
361
glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
363
glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
364
glNormal3f(-1, 0, 0);
365
glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2);
366
glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
370
glPushAttrib (GL_LIGHTING);
371
glDisable (GL_LIGHTING);
373
glColor3f (c2[0], c2[1], c2[2]);
379
glVertex3f(0, -0.66, 0);
380
glVertex3f(0, 0.66, 0);
382
draw_circle (mi, True);
383
glRotatef(90, 1, 0, 0);
384
draw_circle (mi, True);
385
glRotatef(90, 0, 1, 0);
386
draw_circle (mi, True);
392
if (x1 > 0) x1 = 0; if (x2 < 0) x2 = 0;
393
if (y1 > 0) y1 = 0; if (y2 < 0) y2 = 0;
394
if (z1 > 0) z1 = 0; if (z2 < 0) z2 = 0;
395
glVertex3f(x1, 0, 0); glVertex3f(x2, 0, 0);
396
glVertex3f(0 , y1, 0); glVertex3f(0, y2, 0);
397
glVertex3f(0, 0, z1); glVertex3f(0, 0, z2);
406
do_tracer (ModeInfo *mi)
408
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
410
if (cc->tracer == -1 &&
412
!(random() % (duration * 4)))
415
cc->tracer = ((random() & 1) ? 0 : 180);
417
cc->mesher = ((random() % ((duration / 3) + 1)) +
418
(random() % ((duration / 3) + 1)));
423
int d = (90 - cc->tracer);
424
GLfloat th = d * (M_PI / 180);
425
GLfloat x = cos (th);
426
GLfloat y = sin (th);
427
GLfloat s = 1.5 / cc->scale;
431
static GLfloat c[4] = { 0.6, 0.5, 1.0, 1.0 };
433
glPushAttrib (GL_LIGHTING);
434
glDisable (GL_LIGHTING);
437
glRotatef (90, 1, 0, 0);
438
glTranslatef (0, 0, y*s/2);
441
glColor3f (c[0], c[1], c[2]);
442
draw_circle (mi, False);
449
if (cc->tracer == 180 || cc->tracer == 360)
456
unit_spheremonics (ModeInfo *mi,
457
int resolution, Bool wire, int *m, XColor *colors)
459
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
469
cc->bbox[0].x = cc->bbox[0].y = cc->bbox[0].z = 0;
470
cc->bbox[1].x = cc->bbox[1].y = cc->bbox[1].z = 0;
472
du = (M_PI+M_PI) / (double)res; /* Theta */
473
dv = M_PI / (double)res; /* Phi */
478
glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
480
for (i = 0; i < res; i++) {
482
for (j = 0; j < res; j++) {
484
q[0] = sphere_eval (u, v, m);
485
n[0] = calc_normal(q[0],
486
sphere_eval (u+du/10, v, m),
487
sphere_eval (u, v+dv/10, m));
488
glNormal3f(n[0].x,n[0].y,n[0].z);
489
if (!wire) do_color (i, colors);
490
glVertex3f(q[0].x,q[0].y,q[0].z);
492
q[1] = sphere_eval (u+du, v, m);
493
n[1] = calc_normal(q[1],
494
sphere_eval (u+du+du/10, v, m),
495
sphere_eval (u+du, v+dv/10, m));
496
glNormal3f(n[1].x,n[1].y,n[1].z);
497
if (!wire) do_color ((i+1)%res, colors);
498
glVertex3f(q[1].x,q[1].y,q[1].z);
500
q[2] = sphere_eval (u+du, v+dv, m);
501
n[2] = calc_normal(q[2],
502
sphere_eval (u+du+du/10, v+dv, m),
503
sphere_eval (u+du, v+dv+dv/10, m));
504
glNormal3f(n[2].x,n[2].y,n[2].z);
505
if (!wire) do_color ((i+1)%res, colors);
506
glVertex3f(q[2].x,q[2].y,q[2].z);
508
q[3] = sphere_eval (u,v+dv, m);
509
n[3] = calc_normal(q[3],
510
sphere_eval (u+du/10, v+dv, m),
511
sphere_eval (u, v+dv+dv/10, m));
512
glNormal3f(n[3].x,n[3].y,n[3].z);
513
if (!wire) do_color (i, colors);
514
glVertex3f(q[3].x,q[3].y,q[3].z);
518
# define CHECK_BBOX(N) \
519
if (q[(N)].x < cc->bbox[0].x) cc->bbox[0].x = q[(N)].x; \
520
if (q[(N)].y < cc->bbox[0].y) cc->bbox[0].y = q[(N)].y; \
521
if (q[(N)].z < cc->bbox[0].z) cc->bbox[0].z = q[(N)].z; \
522
if (q[(N)].x > cc->bbox[1].x) cc->bbox[1].x = q[(N)].x; \
523
if (q[(N)].y > cc->bbox[1].y) cc->bbox[1].y = q[(N)].y; \
524
if (q[(N)].z > cc->bbox[1].z) cc->bbox[1].z = q[(N)].z
536
GLfloat w = cc->bbox[1].x - cc->bbox[0].x;
537
GLfloat h = cc->bbox[1].y - cc->bbox[0].y;
538
GLfloat d = cc->bbox[1].z - cc->bbox[0].z;
539
GLfloat wh = (w > h ? w : h);
540
GLfloat hd = (h > d ? h : d);
541
GLfloat scale = (wh > hd ? wh : hd);
545
if (wire < 2 && (do_bbox || do_grid))
547
GLfloat s = scale * 1.5;
550
draw_bounding_box (mi);
559
init_colors (ModeInfo *mi)
561
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
563
cc->ncolors = cc->resolution;
564
cc->colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
565
make_smooth_colormap (0, 0, 0,
566
cc->colors, &cc->ncolors,
569
/* brighter colors, please... */
570
for (i = 0; i < cc->ncolors; i++)
572
cc->colors[i].red = (cc->colors[i].red / 2) + 32767;
573
cc->colors[i].green = (cc->colors[i].green / 2) + 32767;
574
cc->colors[i].blue = (cc->colors[i].blue / 2) + 32767;
579
/* Pick one of the parameters to the function and tweak it up or down.
582
tweak_parameters (ModeInfo *mi)
584
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
586
/* If the -parameters command line option was specified, just use that
591
!!strcasecmp (static_parms, "(default)"))
595
if (8 == sscanf (static_parms, "%d %d %d %d %d %d %d %d %c",
596
&cc->m[0], &cc->m[1], &cc->m[2], &cc->m[3],
597
&cc->m[4], &cc->m[5], &cc->m[6], &cc->m[7],
600
else if (strlen (static_parms) == 8 &&
601
1 == sscanf (static_parms, "%lu %c", &n, &dummy))
603
const char *s = static_parms;
606
cc->m[i++] = (*s++)-'0';
610
"%s: -parameters must be a string of 8 ints (not \"%s\")\n",
611
progname, static_parms);
618
# define SHIFT(N) do { \
620
cc->m[n] += cc->dm[n]; \
622
cc->m[n] = 0, cc->dm[n] = -cc->dm[n]; \
623
else if (cc->m[n] >= cc->m_max) \
624
cc->m[n] = cc->m_max, cc->dm[n] = -cc->dm[n]; \
627
/* else if (cc->m[n] >= cc->m_max/2 && (! (random() % 3))) \
628
cc->m[n] = cc->m_max/2, cc->dm[n] = -cc->dm[n]; \
633
case 0: SHIFT(0); break;
634
case 1: SHIFT(1); break;
635
case 2: SHIFT(2); break;
636
case 3: SHIFT(3); break;
637
case 4: SHIFT(4); break;
638
case 5: SHIFT(5); break;
639
case 6: SHIFT(6); break;
640
case 7: SHIFT(7); break;
641
default: abort(); break;
646
printf ("%s: state: %d %d %d %d %d %d %d %d\n",
648
cc->m[0], cc->m[1], cc->m[2], cc->m[3],
649
cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
656
generate_spheremonics (ModeInfo *mi)
658
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
659
int wire = MI_IS_WIREFRAME(mi);
661
tweak_parameters (mi);
664
static Bool done = False;
665
if (!done || (0 == (random() % 20)))
673
glNewList(cc->dlist, GL_COMPILE);
674
cc->polys1 = unit_spheremonics (mi, cc->resolution, wire,cc->m,cc->colors);
677
glNewList(cc->dlist2, GL_COMPILE);
678
glPushAttrib (GL_LIGHTING);
679
glDisable (GL_LIGHTING);
681
glScalef (1.05, 1.05, 1.05);
682
cc->polys2 = unit_spheremonics (mi, cc->resolution, 2, cc->m, cc->colors);
693
init_spheremonics (ModeInfo *mi)
695
spheremonics_configuration *cc;
698
ccs = (spheremonics_configuration *)
699
calloc (MI_NUM_SCREENS(mi), sizeof (spheremonics_configuration));
701
fprintf(stderr, "%s: out of memory\n", progname);
705
cc = &ccs[MI_SCREEN(mi)];
708
cc = &ccs[MI_SCREEN(mi)];
710
if ((cc->glx_context = init_GL(mi)) != NULL) {
712
reshape_spheremonics (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
717
glEnable (GL_LINE_SMOOTH);
718
glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
719
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
724
Bool spinx=False, spiny=False, spinz=False;
725
double spin_speed = 1.0;
726
double wander_speed = 0.03;
731
if (*s == 'x' || *s == 'X') spinx = True;
732
else if (*s == 'y' || *s == 'Y') spiny = True;
733
else if (*s == 'z' || *s == 'Z') spinz = True;
737
"%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
744
cc->rot = make_rotator (spinx ? spin_speed : 0,
745
spinz ? spin_speed : 0,
746
spiny ? spin_speed : 0,
748
do_wander ? wander_speed : 0,
749
(spinx && spiny && spinz));
750
cc->trackball = gltrackball_init ();
756
cc->resolution = res;
758
load_font (mi->dpy, "labelfont", &cc->font, &cc->font_list);
760
cc->dlist = glGenLists(1);
761
cc->dlist2 = glGenLists(1);
763
cc->m_max = 4; /* 9? */
766
for (i = 0; i < countof(cc->dm); i++)
767
cc->dm[i] = 1; /* going up! */
769
/* Generate a few more times so we don't always start off with a sphere */
770
for (i = 0; i < 5; i++)
771
tweak_parameters (mi);
774
generate_spheremonics(mi);
779
spheremonics_handle_event (ModeInfo *mi, XEvent *event)
781
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
783
if (event->xany.type == ButtonPress &&
784
event->xbutton.button == Button1)
786
cc->button_down_p = True;
787
gltrackball_start (cc->trackball,
788
event->xbutton.x, event->xbutton.y,
789
MI_WIDTH (mi), MI_HEIGHT (mi));
792
else if (event->xany.type == ButtonRelease &&
793
event->xbutton.button == Button1)
795
cc->button_down_p = False;
798
else if (event->xany.type == ButtonPress &&
799
(event->xbutton.button == Button4 ||
800
event->xbutton.button == Button5))
802
gltrackball_mousewheel (cc->trackball, event->xbutton.button, 10,
803
!!event->xbutton.state);
806
else if (event->xany.type == KeyPress)
810
XLookupString (&event->xkey, &c, 1, &keysym, 0);
812
if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
814
cc->change_tick = duration;
818
else if (event->xany.type == MotionNotify &&
821
gltrackball_track (cc->trackball,
822
event->xmotion.x, event->xmotion.y,
823
MI_WIDTH (mi), MI_HEIGHT (mi));
832
draw_spheremonics (ModeInfo *mi)
834
spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
835
Display *dpy = MI_DISPLAY(mi);
836
Window window = MI_WINDOW(mi);
838
if (!cc->glx_context)
841
glShadeModel(GL_SMOOTH);
843
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
847
glScalef(1.1, 1.1, 1.1);
851
get_position (cc->rot, &x, &y, &z, !cc->button_down_p);
852
glTranslatef((x - 0.5) * 8,
856
gltrackball_rotate (cc->trackball);
858
get_rotation (cc->rot, &x, &y, &z, !cc->button_down_p);
859
glRotatef (x * 360, 1.0, 0.0, 0.0);
860
glRotatef (y * 360, 0.0, 1.0, 0.0);
861
glRotatef (z * 360, 0.0, 0.0, 1.0);
866
mi->polygon_count = 0;
868
glScalef (cc->scale, cc->scale, cc->scale);
869
glCallList (cc->dlist);
870
mi->polygon_count += cc->polys1;
872
if (cc->mesher >= 0 /* || mouse_p */)
874
glCallList (cc->dlist2);
875
mi->polygon_count += cc->polys2;
882
if (cc->button_down_p)
886
((cc->m[0]<10 && cc->m[1]<10 && cc->m[2]<10 && cc->m[3]<10 &&
887
cc->m[4]<10 && cc->m[5]<10 && cc->m[6]<10 && cc->m[7]<10)
889
: "%d %d %d %d %d %d %d %d"),
890
cc->m[0], cc->m[1], cc->m[2], cc->m[3],
891
cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
893
glColor3f(1.0, 1.0, 0.0);
894
print_gl_string (mi->dpy, cc->font, cc->font_list,
895
mi->xgwa.width, mi->xgwa.height,
896
10, mi->xgwa.height - 10,
902
if (cc->change_tick++ >= duration && !cc->button_down_p)
904
generate_spheremonics(mi);
906
cc->mesher = -1; /* turn off the mesh when switching objects */
912
if (mi->fps_p) do_fps (mi);
915
glXSwapBuffers(dpy, window);