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 "*resolution: " DEF_RESOLUTION "\n" \
86 "*showFPS: False \n" \
87 "*wireframe: False \n" \
88 "*duration: " DEF_DURATION "\n" \
89 "*spin: " DEF_SPIN "\n" \
90 "*wander: " DEF_WANDER "\n" \
91 "*bbox: " DEF_BBOX "\n" \
92 "*grid: " DEF_GRID "\n" \
93 "*smooth: " DEF_SMOOTH "\n" \
94 "*parameters: " DEF_PARMS "\n" \
97 #define countof(x) (sizeof((x))/sizeof((*x)))
99 #include "xlockmore.h"
100 #include "glxfonts.h"
104 #include "gltrackball.h"
107 #ifdef USE_GL /* whole file */
112 GLXContext *glx_context;
114 trackball_state *trackball;
117 GLuint dlist, dlist2;
131 int polys1, polys2; /* polygon counts */
137 } spheremonics_configuration;
139 static spheremonics_configuration *ccs = NULL;
141 static char *do_spin;
142 static Bool do_wander;
146 static char *static_parms;
150 static XrmOptionDescRec opts[] = {
151 { "-spin", ".spin", XrmoptionSepArg, 0 },
152 { "+spin", ".spin", XrmoptionNoArg, "" },
153 { "-wander", ".wander", XrmoptionNoArg, "True" },
154 { "+wander", ".wander", XrmoptionNoArg, "False" },
155 { "-resolution", ".resolution", XrmoptionSepArg, 0 },
156 { "-duration", ".duration", XrmoptionSepArg, 0 },
157 { "-bbox", ".bbox", XrmoptionNoArg, "True" },
158 { "+bbox", ".bbox", XrmoptionNoArg, "False" },
159 { "-grid", ".grid", XrmoptionNoArg, "True" },
160 { "+grid", ".grid", XrmoptionNoArg, "False" },
161 {"-smooth", ".smooth", XrmoptionNoArg, "True" },
162 {"+smooth", ".smooth", XrmoptionNoArg, "False" },
163 { "-parameters", ".parameters", XrmoptionSepArg, 0 },
166 static argtype vars[] = {
167 {&do_spin, "spin", "Spin", DEF_SPIN, t_String},
168 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
169 {&res, "resolution", "Resolution", DEF_RESOLUTION, t_Int},
170 {&duration, "duration", "Duration", DEF_DURATION, t_Int},
171 {&do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool},
172 {&do_grid, "grid", "Grid", DEF_GRID, t_Bool},
173 {&smooth_p, "smooth", "Smooth", DEF_SMOOTH, t_Bool},
174 {&static_parms, "parameters", "Parameters", DEF_PARMS, t_String},
177 ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
180 /* Window management, etc
183 reshape_spheremonics (ModeInfo *mi, int width, int height)
185 GLfloat h = (GLfloat) height / (GLfloat) width;
187 glViewport (0, 0, (GLint) width, (GLint) height);
189 glMatrixMode(GL_PROJECTION);
191 gluPerspective (30.0, 1/h, 1.0, 100.0);
193 glMatrixMode(GL_MODELVIEW);
195 gluLookAt( 0.0, 0.0, 30.0,
199 glClear(GL_COLOR_BUFFER_BIT);
204 gl_init (ModeInfo *mi)
206 /* spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; */
207 int wire = MI_IS_WIREFRAME(mi);
209 static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
211 glEnable(GL_NORMALIZE);
215 glLightfv(GL_LIGHT0, GL_POSITION, pos);
216 glEnable(GL_LIGHTING);
218 glEnable(GL_DEPTH_TEST);
220 /* With objects that have proper winding and normals set up on all
221 their faces, one can cull back-faces; however, these equations
222 generate objects that are sometimes "inside out", and determining
223 whether a facet has been inverted like that is really hard.
224 So we render both front and back faces, at a probable performance
225 penalty on non-accelerated systems.
227 When rendering back faces, we also need to do two-sided lighting,
228 or the fact that the normals are flipped gives us too-dark surfaces
229 on the inside-out surfaces.
231 This isn't generally something you'd want, because you end up
232 with half the lighting dynamic range (kind of.) So if you had
233 a sphere with correctly pointing normals, and a single light
234 source, it would be illuminated from two sides. In this case,
235 though, it saves us from a difficult and time consuming
236 inside/outside test. And we don't really care about a precise
239 glDisable(GL_CULL_FACE);
240 glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, TRUE);
246 /* generate the object */
249 sphere_eval (double theta, double phi, int *m)
254 r += pow (sin(m[0] * phi), (double)m[1]);
255 r += pow (cos(m[2] * phi), (double)m[3]);
256 r += pow (sin(m[4] * theta),(double)m[5]);
257 r += pow (cos(m[6] * theta),(double)m[7]);
259 p.x = r * sin(phi) * cos(theta);
261 p.z = r * sin(phi) * sin(theta);
268 do_color (int i, XColor *colors)
271 c[0] = colors[i].red / 65535.0;
272 c[1] = colors[i].green / 65535.0;
273 c[2] = colors[i].blue / 65535.0;
275 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
276 glColor3f (c[0], c[1], c[2]);
281 draw_circle (ModeInfo *mi, Bool teeth_p)
286 GLfloat step = (M_PI / 180);
288 glBegin(GL_LINE_LOOP);
289 for (th = 0; th < M_PI*2; th += step*5)
294 glVertex3f(x*r1, y*r1, 0);
298 if (!teeth_p) return;
301 for (th = 0; th < M_PI*2; th += step)
304 GLfloat r2 = r1 - 0.01;
307 else if (! (tick % 5))
313 glVertex3f(x*r1, y*r1, 0);
314 glVertex3f(x*r2, y*r2, 0);
321 draw_bounding_box (ModeInfo *mi)
323 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
325 static GLfloat c1[4] = { 0.2, 0.2, 0.6, 1.0 };
326 static GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
327 int wire = MI_IS_WIREFRAME(mi);
329 GLfloat x1 = cc->bbox[0].x;
330 GLfloat y1 = cc->bbox[0].y;
331 GLfloat z1 = cc->bbox[0].z;
332 GLfloat x2 = cc->bbox[1].x;
333 GLfloat y2 = cc->bbox[1].y;
334 GLfloat z2 = cc->bbox[1].z;
341 if (do_bbox && !wire)
343 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);
346 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
348 glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
349 glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
351 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
352 glNormal3f(0, -1, 0);
353 glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2);
354 glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1);
356 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
358 glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
359 glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
361 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
362 glNormal3f(0, 0, -1);
363 glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2);
364 glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
366 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
368 glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
369 glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
371 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
372 glNormal3f(-1, 0, 0);
373 glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2);
374 glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
378 glPushAttrib (GL_LIGHTING);
379 glDisable (GL_LIGHTING);
381 glColor3f (c2[0], c2[1], c2[2]);
387 glVertex3f(0, -0.66, 0);
388 glVertex3f(0, 0.66, 0);
390 draw_circle (mi, True);
391 glRotatef(90, 1, 0, 0);
392 draw_circle (mi, True);
393 glRotatef(90, 0, 1, 0);
394 draw_circle (mi, True);
400 if (x1 > 0) x1 = 0; if (x2 < 0) x2 = 0;
401 if (y1 > 0) y1 = 0; if (y2 < 0) y2 = 0;
402 if (z1 > 0) z1 = 0; if (z2 < 0) z2 = 0;
403 glVertex3f(x1, 0, 0); glVertex3f(x2, 0, 0);
404 glVertex3f(0 , y1, 0); glVertex3f(0, y2, 0);
405 glVertex3f(0, 0, z1); glVertex3f(0, 0, z2);
414 do_tracer (ModeInfo *mi)
416 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
418 if (cc->tracer == -1 &&
420 !(random() % (duration * 4)))
423 cc->tracer = ((random() & 1) ? 0 : 180);
425 cc->mesher = ((random() % ((duration / 3) + 1)) +
426 (random() % ((duration / 3) + 1)));
431 int d = (90 - cc->tracer);
432 GLfloat th = d * (M_PI / 180);
433 GLfloat x = cos (th);
434 GLfloat y = sin (th);
435 GLfloat s = 1.5 / cc->scale;
439 static GLfloat c[4] = { 0.6, 0.5, 1.0, 1.0 };
441 glPushAttrib (GL_LIGHTING);
442 glDisable (GL_LIGHTING);
445 glRotatef (90, 1, 0, 0);
446 glTranslatef (0, 0, y*s/2);
449 glColor3f (c[0], c[1], c[2]);
450 draw_circle (mi, False);
457 if (cc->tracer == 180 || cc->tracer == 360)
464 unit_spheremonics (ModeInfo *mi,
465 int resolution, Bool wire, int *m, XColor *colors)
467 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
477 cc->bbox[0].x = cc->bbox[0].y = cc->bbox[0].z = 0;
478 cc->bbox[1].x = cc->bbox[1].y = cc->bbox[1].z = 0;
480 du = (M_PI+M_PI) / (double)res; /* Theta */
481 dv = M_PI / (double)res; /* Phi */
486 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
488 for (i = 0; i < res; i++) {
490 for (j = 0; j < res; j++) {
492 q[0] = sphere_eval (u, v, m);
493 n[0] = calc_normal(q[0],
494 sphere_eval (u+du/10, v, m),
495 sphere_eval (u, v+dv/10, m));
496 glNormal3f(n[0].x,n[0].y,n[0].z);
497 if (!wire) do_color (i, colors);
498 glVertex3f(q[0].x,q[0].y,q[0].z);
500 q[1] = sphere_eval (u+du, v, m);
501 n[1] = calc_normal(q[1],
502 sphere_eval (u+du+du/10, v, m),
503 sphere_eval (u+du, v+dv/10, m));
504 glNormal3f(n[1].x,n[1].y,n[1].z);
505 if (!wire) do_color ((i+1)%res, colors);
506 glVertex3f(q[1].x,q[1].y,q[1].z);
508 q[2] = sphere_eval (u+du, v+dv, m);
509 n[2] = calc_normal(q[2],
510 sphere_eval (u+du+du/10, v+dv, m),
511 sphere_eval (u+du, v+dv+dv/10, m));
512 glNormal3f(n[2].x,n[2].y,n[2].z);
513 if (!wire) do_color ((i+1)%res, colors);
514 glVertex3f(q[2].x,q[2].y,q[2].z);
516 q[3] = sphere_eval (u,v+dv, m);
517 n[3] = calc_normal(q[3],
518 sphere_eval (u+du/10, v+dv, m),
519 sphere_eval (u, v+dv+dv/10, m));
520 glNormal3f(n[3].x,n[3].y,n[3].z);
521 if (!wire) do_color (i, colors);
522 glVertex3f(q[3].x,q[3].y,q[3].z);
526 # define CHECK_BBOX(N) \
527 if (q[(N)].x < cc->bbox[0].x) cc->bbox[0].x = q[(N)].x; \
528 if (q[(N)].y < cc->bbox[0].y) cc->bbox[0].y = q[(N)].y; \
529 if (q[(N)].z < cc->bbox[0].z) cc->bbox[0].z = q[(N)].z; \
530 if (q[(N)].x > cc->bbox[1].x) cc->bbox[1].x = q[(N)].x; \
531 if (q[(N)].y > cc->bbox[1].y) cc->bbox[1].y = q[(N)].y; \
532 if (q[(N)].z > cc->bbox[1].z) cc->bbox[1].z = q[(N)].z
544 GLfloat w = cc->bbox[1].x - cc->bbox[0].x;
545 GLfloat h = cc->bbox[1].y - cc->bbox[0].y;
546 GLfloat d = cc->bbox[1].z - cc->bbox[0].z;
547 GLfloat wh = (w > h ? w : h);
548 GLfloat hd = (h > d ? h : d);
549 GLfloat scale = (wh > hd ? wh : hd);
553 if (wire < 2 && (do_bbox || do_grid))
555 GLfloat s = scale * 1.5;
558 draw_bounding_box (mi);
567 init_colors (ModeInfo *mi)
569 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
571 cc->ncolors = cc->resolution;
572 cc->colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
573 make_smooth_colormap (0, 0, 0,
574 cc->colors, &cc->ncolors,
577 /* brighter colors, please... */
578 for (i = 0; i < cc->ncolors; i++)
580 cc->colors[i].red = (cc->colors[i].red / 2) + 32767;
581 cc->colors[i].green = (cc->colors[i].green / 2) + 32767;
582 cc->colors[i].blue = (cc->colors[i].blue / 2) + 32767;
587 /* Pick one of the parameters to the function and tweak it up or down.
590 tweak_parameters (ModeInfo *mi)
592 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
594 /* If the -parameters command line option was specified, just use that
599 !!strcasecmp (static_parms, "(default)"))
603 if (8 == sscanf (static_parms, "%d %d %d %d %d %d %d %d %c",
604 &cc->m[0], &cc->m[1], &cc->m[2], &cc->m[3],
605 &cc->m[4], &cc->m[5], &cc->m[6], &cc->m[7],
608 else if (strlen (static_parms) == 8 &&
609 1 == sscanf (static_parms, "%lu %c", &n, &dummy))
611 const char *s = static_parms;
614 cc->m[i++] = (*s++)-'0';
618 "%s: -parameters must be a string of 8 ints (not \"%s\")\n",
619 progname, static_parms);
626 # define SHIFT(N) do { \
628 cc->m[n] += cc->dm[n]; \
630 cc->m[n] = 0, cc->dm[n] = -cc->dm[n]; \
631 else if (cc->m[n] >= cc->m_max) \
632 cc->m[n] = cc->m_max, cc->dm[n] = -cc->dm[n]; \
635 /* else if (cc->m[n] >= cc->m_max/2 && (! (random() % 3))) \
636 cc->m[n] = cc->m_max/2, cc->dm[n] = -cc->dm[n]; \
641 case 0: SHIFT(0); break;
642 case 1: SHIFT(1); break;
643 case 2: SHIFT(2); break;
644 case 3: SHIFT(3); break;
645 case 4: SHIFT(4); break;
646 case 5: SHIFT(5); break;
647 case 6: SHIFT(6); break;
648 case 7: SHIFT(7); break;
649 default: abort(); break;
654 printf ("%s: state: %d %d %d %d %d %d %d %d\n",
656 cc->m[0], cc->m[1], cc->m[2], cc->m[3],
657 cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
664 generate_spheremonics (ModeInfo *mi)
666 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
667 int wire = MI_IS_WIREFRAME(mi);
669 tweak_parameters (mi);
672 static Bool done = False;
673 if (!done || (0 == (random() % 20)))
681 glNewList(cc->dlist, GL_COMPILE);
682 cc->polys1 = unit_spheremonics (mi, cc->resolution, wire,cc->m,cc->colors);
685 glNewList(cc->dlist2, GL_COMPILE);
686 glPushAttrib (GL_LIGHTING);
687 glDisable (GL_LIGHTING);
689 glScalef (1.05, 1.05, 1.05);
690 cc->polys2 = unit_spheremonics (mi, cc->resolution, 2, cc->m, cc->colors);
701 init_spheremonics (ModeInfo *mi)
703 spheremonics_configuration *cc;
706 ccs = (spheremonics_configuration *)
707 calloc (MI_NUM_SCREENS(mi), sizeof (spheremonics_configuration));
709 fprintf(stderr, "%s: out of memory\n", progname);
713 cc = &ccs[MI_SCREEN(mi)];
716 cc = &ccs[MI_SCREEN(mi)];
718 if ((cc->glx_context = init_GL(mi)) != NULL) {
720 reshape_spheremonics (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
725 glEnable (GL_LINE_SMOOTH);
726 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
727 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
732 Bool spinx=False, spiny=False, spinz=False;
733 double spin_speed = 1.0;
734 double wander_speed = 0.03;
739 if (*s == 'x' || *s == 'X') spinx = True;
740 else if (*s == 'y' || *s == 'Y') spiny = True;
741 else if (*s == 'z' || *s == 'Z') spinz = True;
745 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
752 cc->rot = make_rotator (spinx ? spin_speed : 0,
753 spinz ? spin_speed : 0,
754 spiny ? spin_speed : 0,
756 do_wander ? wander_speed : 0,
757 (spinx && spiny && spinz));
758 cc->trackball = gltrackball_init ();
764 cc->resolution = res;
766 load_font (mi->dpy, "labelfont", &cc->font, &cc->font_list);
768 cc->dlist = glGenLists(1);
769 cc->dlist2 = glGenLists(1);
771 cc->m_max = 4; /* 9? */
774 for (i = 0; i < countof(cc->dm); i++)
775 cc->dm[i] = 1; /* going up! */
777 /* Generate a few more times so we don't always start off with a sphere */
778 for (i = 0; i < 5; i++)
779 tweak_parameters (mi);
782 generate_spheremonics(mi);
787 spheremonics_handle_event (ModeInfo *mi, XEvent *event)
789 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
791 if (event->xany.type == ButtonPress &&
792 event->xbutton.button == Button1)
794 cc->button_down_p = True;
795 gltrackball_start (cc->trackball,
796 event->xbutton.x, event->xbutton.y,
797 MI_WIDTH (mi), MI_HEIGHT (mi));
800 else if (event->xany.type == ButtonRelease &&
801 event->xbutton.button == Button1)
803 cc->button_down_p = False;
806 else if (event->xany.type == ButtonPress &&
807 (event->xbutton.button == Button4 ||
808 event->xbutton.button == Button5))
810 gltrackball_mousewheel (cc->trackball, event->xbutton.button, 10,
811 !!event->xbutton.state);
814 else if (event->xany.type == KeyPress)
818 XLookupString (&event->xkey, &c, 1, &keysym, 0);
820 if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
822 cc->change_tick = duration;
826 else if (event->xany.type == MotionNotify &&
829 gltrackball_track (cc->trackball,
830 event->xmotion.x, event->xmotion.y,
831 MI_WIDTH (mi), MI_HEIGHT (mi));
840 draw_spheremonics (ModeInfo *mi)
842 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
843 Display *dpy = MI_DISPLAY(mi);
844 Window window = MI_WINDOW(mi);
846 if (!cc->glx_context)
849 glShadeModel(GL_SMOOTH);
851 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
855 glScalef(1.1, 1.1, 1.1);
859 get_position (cc->rot, &x, &y, &z, !cc->button_down_p);
860 glTranslatef((x - 0.5) * 8,
864 gltrackball_rotate (cc->trackball);
866 get_rotation (cc->rot, &x, &y, &z, !cc->button_down_p);
867 glRotatef (x * 360, 1.0, 0.0, 0.0);
868 glRotatef (y * 360, 0.0, 1.0, 0.0);
869 glRotatef (z * 360, 0.0, 0.0, 1.0);
874 mi->polygon_count = 0;
876 glScalef (cc->scale, cc->scale, cc->scale);
877 glCallList (cc->dlist);
878 mi->polygon_count += cc->polys1;
880 if (cc->mesher >= 0 /* || mouse_p */)
882 glCallList (cc->dlist2);
883 mi->polygon_count += cc->polys2;
890 if (cc->button_down_p)
894 ((cc->m[0]<10 && cc->m[1]<10 && cc->m[2]<10 && cc->m[3]<10 &&
895 cc->m[4]<10 && cc->m[5]<10 && cc->m[6]<10 && cc->m[7]<10)
897 : "%d %d %d %d %d %d %d %d"),
898 cc->m[0], cc->m[1], cc->m[2], cc->m[3],
899 cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
901 glColor3f(1.0, 1.0, 0.0);
902 print_gl_string (mi->dpy, cc->font, cc->font_list,
903 mi->xgwa.width, mi->xgwa.height,
904 10, mi->xgwa.height - 10,
910 if (cc->change_tick++ >= duration && !cc->button_down_p)
912 generate_spheremonics(mi);
914 cc->mesher = -1; /* turn off the mesh when switching objects */
920 if (mi->fps_p) do_fps (mi);
923 glXSwapBuffers(dpy, window);