1 /* xscreensaver, Copyright (c) 2002 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 * With the hairier objects, some of the faces are inside out. E.g.,
57 * -parameters 01210111
58 * If we turn off GL_CULL_FACE, that object renders more solidly
59 * (indicating wrong winding) and the altered surfaces are too dark
60 * (indicating wrong normals.)
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 ccs_opts xlockmore_opts
73 #define DEF_DURATION "100"
74 #define DEF_SPIN "XYZ"
75 #define DEF_WANDER "False"
76 #define DEF_RESOLUTION "64"
77 #define DEF_BBOX "False"
78 #define DEF_GRID "True"
79 #define DEF_SMOOTH "True"
80 #define DEF_PARMS "(default)"
82 #define DEFAULTS "*delay: 30000 \n" \
83 "*resolution: " DEF_RESOLUTION "\n" \
84 "*showFPS: False \n" \
85 "*wireframe: False \n" \
86 "*duration: " DEF_DURATION "\n" \
87 "*spin: " DEF_SPIN "\n" \
88 "*wander: " DEF_WANDER "\n" \
89 "*bbox: " DEF_BBOX "\n" \
90 "*grid: " DEF_GRID "\n" \
91 "*smooth: " DEF_SMOOTH "\n" \
92 "*parameters: " DEF_PARMS "\n" \
95 #define countof(x) (sizeof((x))/sizeof((*x)))
97 #include "xlockmore.h"
101 #ifdef USE_GL /* whole file */
110 GLXContext *glx_context;
112 GLfloat rotx, roty, rotz; /* current object rotation */
113 GLfloat dx, dy, dz; /* current rotational velocity */
114 GLfloat ddx, ddy, ddz; /* current rotational acceleration */
115 GLfloat d_max; /* max velocity */
116 Bool spin_x, spin_y, spin_z;
118 GLuint dlist, dlist2;
136 } spheremonics_configuration;
138 static spheremonics_configuration *ccs = NULL;
140 static char *do_spin;
141 static Bool do_wander;
145 static char *static_parms;
149 static XrmOptionDescRec opts[] = {
150 { "-spin", ".spin", XrmoptionSepArg, 0 },
151 { "+spin", ".spin", XrmoptionNoArg, "" },
152 { "-wander", ".wander", XrmoptionNoArg, "True" },
153 { "+wander", ".wander", XrmoptionNoArg, "False" },
154 { "-resolution", ".resolution", XrmoptionSepArg, 0 },
155 { "-duration", ".duration", XrmoptionSepArg, 0 },
156 { "-bbox", ".bbox", XrmoptionNoArg, "True" },
157 { "+bbox", ".bbox", XrmoptionNoArg, "False" },
158 { "-grid", ".grid", XrmoptionNoArg, "True" },
159 { "+grid", ".grid", XrmoptionNoArg, "False" },
160 {"-smooth", ".smooth", XrmoptionNoArg, "True" },
161 {"+smooth", ".smooth", XrmoptionNoArg, "False" },
162 { "-parameters", ".parameters", XrmoptionSepArg, 0 },
165 static argtype vars[] = {
166 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_String},
167 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
168 {(caddr_t *) &res, "resolution", "Resolution", DEF_RESOLUTION, t_Int},
169 {(caddr_t *) &duration, "duration", "Duration", DEF_DURATION, t_Int},
170 {(caddr_t *) &do_bbox, "bbox", "BBox", DEF_BBOX, t_Bool},
171 {(caddr_t *) &do_grid, "grid", "Grid", DEF_GRID, t_Bool},
172 {(caddr_t *) &smooth_p, "smooth", "Smooth", DEF_SMOOTH, t_Bool},
173 {(caddr_t *) &static_parms, "parameters", "Parameters", DEF_PARMS, t_String},
176 ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
179 /* Window management, etc
182 reshape_spheremonics (ModeInfo *mi, int width, int height)
184 GLfloat h = (GLfloat) height / (GLfloat) width;
186 glViewport (0, 0, (GLint) width, (GLint) height);
188 glMatrixMode(GL_PROJECTION);
191 gluPerspective( 30.0, 1/h, 1.0, 100.0 );
192 gluLookAt( 0.0, 0.0, 15.0,
195 glMatrixMode(GL_MODELVIEW);
197 glTranslatef(0.0, 0.0, -15.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_CULL_FACE);
217 glEnable(GL_LIGHTING);
219 glEnable(GL_DEPTH_TEST);
224 /* lifted from lament.c */
225 #define RAND(n) ((long) ((random() & 0x7fffffff) % ((long) (n))))
226 #define RANDSIGN() ((random() & 1) ? 1 : -1)
229 rotate(GLfloat *pos, GLfloat *v, GLfloat *dv, GLfloat max_v)
244 if (ppos < 0) abort();
245 if (ppos > 1.0) abort();
246 *pos = (*pos > 0 ? ppos : -ppos);
252 if (*v > max_v || *v < -max_v)
256 /* If it stops, start it going in the other direction. */
263 /* keep going in the same direction */
278 /* Alter direction of rotational acceleration randomly. */
279 if (! (random() % 120))
282 /* Change acceleration very occasionally. */
283 if (! (random() % 200))
287 else if (random() & 1)
295 /* generate the object */
298 sphere_eval (double theta, double phi, int *m)
303 r += pow (sin(m[0] * phi), (double)m[1]);
304 r += pow (cos(m[2] * phi), (double)m[3]);
305 r += pow (sin(m[4] * theta),(double)m[5]);
306 r += pow (cos(m[6] * theta),(double)m[7]);
308 p.x = r * sin(phi) * cos(theta);
310 p.z = r * sin(phi) * sin(theta);
316 /* Normalise a vector */
321 length = sqrt(p->x * p->x + p->y * p->y + p->z * p->z);
333 /*-------------------------------------------------------------------------
334 Calculate the unit normal at p given two other points
335 p1,p2 on the surface. The normal points in the direction
336 of p1 crossproduct p2
339 calc_normal (XYZ p, XYZ p1, XYZ p2)
348 n.x = pa.y * pb.z - pa.z * pb.y;
349 n.y = pa.z * pb.x - pa.x * pb.z;
350 n.z = pa.x * pb.y - pa.y * pb.x;
357 do_color (int i, XColor *colors)
360 c[0] = colors[i].red / 65535.0;
361 c[1] = colors[i].green / 65535.0;
362 c[2] = colors[i].blue / 65535.0;
364 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
365 glColor3f (c[0], c[1], c[2]);
370 draw_circle (ModeInfo *mi, Bool teeth_p)
375 GLfloat step = (M_PI / 180);
377 glBegin(GL_LINE_LOOP);
378 for (th = 0; th < M_PI*2; th += step*5)
383 glVertex3f(x*r1, y*r1, 0);
387 if (!teeth_p) return;
390 for (th = 0; th < M_PI*2; th += step)
393 GLfloat r2 = r1 - 0.01;
396 else if (! (tick % 5))
402 glVertex3f(x*r1, y*r1, 0);
403 glVertex3f(x*r2, y*r2, 0);
410 draw_bounding_box (ModeInfo *mi)
412 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
414 static GLfloat c1[4] = { 0.2, 0.2, 0.6, 1.0 };
415 static GLfloat c2[4] = { 1.0, 0.0, 0.0, 1.0 };
416 int wire = MI_IS_WIREFRAME(mi);
418 GLfloat x1 = cc->bbox[0].x;
419 GLfloat y1 = cc->bbox[0].y;
420 GLfloat z1 = cc->bbox[0].z;
421 GLfloat x2 = cc->bbox[1].x;
422 GLfloat y2 = cc->bbox[1].y;
423 GLfloat z2 = cc->bbox[1].z;
430 if (do_bbox && !wire)
432 glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);
435 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
437 glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
438 glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
440 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
441 glNormal3f(0, -1, 0);
442 glVertex3f(x2, y2, z1); glVertex3f(x2, y2, z2);
443 glVertex3f(x1, y2, z2); glVertex3f(x1, y2, z1);
445 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
447 glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
448 glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
450 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
451 glNormal3f(0, 0, -1);
452 glVertex3f(x1, y2, z2); glVertex3f(x2, y2, z2);
453 glVertex3f(x2, y1, z2); glVertex3f(x1, y1, z2);
455 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
457 glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
458 glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
460 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
461 glNormal3f(-1, 0, 0);
462 glVertex3f(x2, y1, z1); glVertex3f(x2, y1, z2);
463 glVertex3f(x2, y2, z2); glVertex3f(x2, y2, z1);
467 glPushAttrib (GL_LIGHTING);
468 glDisable (GL_LIGHTING);
470 glColor3f (c2[0], c2[1], c2[2]);
476 glVertex3f(0, -0.66, 0);
477 glVertex3f(0, 0.66, 0);
479 draw_circle (mi, True);
480 glRotatef(90, 1, 0, 0);
481 draw_circle (mi, True);
482 glRotatef(90, 0, 1, 0);
483 draw_circle (mi, True);
489 if (x1 > 0) x1 = 0; if (x2 < 0) x2 = 0;
490 if (y1 > 0) y1 = 0; if (y2 < 0) y2 = 0;
491 if (z1 > 0) z1 = 0; if (z2 < 0) z2 = 0;
492 glVertex3f(x1, 0, 0); glVertex3f(x2, 0, 0);
493 glVertex3f(0 , y1, 0); glVertex3f(0, y2, 0);
494 glVertex3f(0, 0, z1); glVertex3f(0, 0, z2);
503 do_tracer (ModeInfo *mi)
505 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
507 if (cc->tracer == -1 &&
509 !(random() % (duration * 4)))
512 cc->tracer = ((random() & 1) ? 0 : 180);
514 cc->mesher = ((random() % ((duration / 3) + 1)) +
515 (random() % ((duration / 3) + 1)));
520 int d = (90 - cc->tracer);
521 GLfloat th = d * (M_PI / 180);
522 GLfloat x = cos (th);
523 GLfloat y = sin (th);
524 GLfloat s = 1.5 / cc->scale;
528 static GLfloat c[4] = { 0.6, 0.5, 1.0, 1.0 };
530 glPushAttrib (GL_LIGHTING);
531 glDisable (GL_LIGHTING);
534 glRotatef (90, 1, 0, 0);
535 glTranslatef (0, 0, y*s/2);
538 glColor3f (c[0], c[1], c[2]);
539 draw_circle (mi, False);
546 if (cc->tracer == 180 || cc->tracer == 360)
553 unit_spheremonics (ModeInfo *mi,
554 int resolution, Bool wire, int *m, XColor *colors)
556 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
566 cc->bbox[0].x = cc->bbox[0].y = cc->bbox[0].z = 0;
567 cc->bbox[1].x = cc->bbox[1].y = cc->bbox[1].z = 0;
569 du = (M_PI+M_PI) / (double)res; /* Theta */
570 dv = M_PI / (double)res; /* Phi */
575 /* mi->polygon_count = 0; */
577 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
579 for (i = 0; i < res; i++) {
581 for (j = 0; j < res; j++) {
583 q[0] = sphere_eval (u, v, m);
584 n[0] = calc_normal(q[0],
585 sphere_eval (u+du/10, v, m),
586 sphere_eval (u, v+dv/10, m));
587 glNormal3f(n[0].x,n[0].y,n[0].z);
588 if (!wire) do_color (i, colors);
589 glVertex3f(q[0].x,q[0].y,q[0].z);
591 q[1] = sphere_eval (u+du, v, m);
592 n[1] = calc_normal(q[1],
593 sphere_eval (u+du+du/10, v, m),
594 sphere_eval (u+du, v+dv/10, m));
595 glNormal3f(n[1].x,n[1].y,n[1].z);
596 if (!wire) do_color ((i+1)%res, colors);
597 glVertex3f(q[1].x,q[1].y,q[1].z);
599 q[2] = sphere_eval (u+du, v+dv, m);
600 n[2] = calc_normal(q[2],
601 sphere_eval (u+du+du/10, v+dv, m),
602 sphere_eval (u+du, v+dv+dv/10, m));
603 glNormal3f(n[2].x,n[2].y,n[2].z);
604 if (!wire) do_color ((i+1)%res, colors);
605 glVertex3f(q[2].x,q[2].y,q[2].z);
607 q[3] = sphere_eval (u,v+dv, m);
608 n[3] = calc_normal(q[3],
609 sphere_eval (u+du/10, v+dv, m),
610 sphere_eval (u, v+dv+dv/10, m));
611 glNormal3f(n[3].x,n[3].y,n[3].z);
612 if (!wire) do_color (i, colors);
613 glVertex3f(q[3].x,q[3].y,q[3].z);
615 /* mi->polygon_count++; */
617 # define CHECK_BBOX(N) \
618 if (q[(N)].x < cc->bbox[0].x) cc->bbox[0].x = q[(N)].x; \
619 if (q[(N)].y < cc->bbox[0].y) cc->bbox[0].y = q[(N)].y; \
620 if (q[(N)].z < cc->bbox[0].z) cc->bbox[0].z = q[(N)].z; \
621 if (q[(N)].x > cc->bbox[1].x) cc->bbox[1].x = q[(N)].x; \
622 if (q[(N)].y > cc->bbox[1].y) cc->bbox[1].y = q[(N)].y; \
623 if (q[(N)].z > cc->bbox[1].z) cc->bbox[1].z = q[(N)].z
635 GLfloat w = cc->bbox[1].x - cc->bbox[0].x;
636 GLfloat h = cc->bbox[1].y - cc->bbox[0].y;
637 GLfloat d = cc->bbox[1].z - cc->bbox[0].z;
638 GLfloat wh = (w > h ? w : h);
639 GLfloat hd = (h > d ? h : d);
640 GLfloat scale = (wh > hd ? wh : hd);
644 if (wire < 2 && (do_bbox || do_grid))
646 GLfloat s = scale * 1.5;
649 draw_bounding_box (mi);
657 init_colors (ModeInfo *mi)
659 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
661 cc->ncolors = cc->resolution;
662 cc->colors = (XColor *) calloc(cc->ncolors, sizeof(XColor));
663 make_smooth_colormap (0, 0, 0,
664 cc->colors, &cc->ncolors,
667 /* brighter colors, please... */
668 for (i = 0; i < cc->ncolors; i++)
670 cc->colors[i].red = (cc->colors[i].red / 2) + 32767;
671 cc->colors[i].green = (cc->colors[i].green / 2) + 32767;
672 cc->colors[i].blue = (cc->colors[i].blue / 2) + 32767;
677 /* Pick one of the parameters to the function and tweak it up or down.
680 tweak_parameters (ModeInfo *mi)
682 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
684 /* If the -parameters command line option was specified, just use that
689 !!strcasecmp (static_parms, "(default)"))
693 if (8 == sscanf (static_parms, "%d %d %d %d %d %d %d %d %c",
694 &cc->m[0], &cc->m[1], &cc->m[2], &cc->m[3],
695 &cc->m[4], &cc->m[5], &cc->m[6], &cc->m[7],
698 else if (strlen (static_parms) == 8 &&
699 1 == sscanf (static_parms, "%lu %c", &n, &dummy))
701 const char *s = static_parms;
704 cc->m[i++] = (*s++)-'0';
708 "%s: -parameters must be a string of 8 ints (not \"%s\")\n",
709 progname, static_parms);
716 # define SHIFT(N) do { \
718 cc->m[n] += cc->dm[n]; \
720 cc->m[n] = 0, cc->dm[n] = -cc->dm[n]; \
721 else if (cc->m[n] >= cc->m_max) \
722 cc->m[n] = cc->m_max, cc->dm[n] = -cc->dm[n]; \
725 /* else if (cc->m[n] >= cc->m_max/2 && (! (random() % 3))) \
726 cc->m[n] = cc->m_max/2, cc->dm[n] = -cc->dm[n]; \
731 case 0: SHIFT(0); break;
732 case 1: SHIFT(1); break;
733 case 2: SHIFT(2); break;
734 case 3: SHIFT(3); break;
735 case 4: SHIFT(4); break;
736 case 5: SHIFT(5); break;
737 case 6: SHIFT(6); break;
738 case 7: SHIFT(7); break;
739 default: abort(); break;
744 printf ("%s: state: %d %d %d %d %d %d %d %d\n",
746 cc->m[0], cc->m[1], cc->m[2], cc->m[3],
747 cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
754 generate_spheremonics (ModeInfo *mi)
756 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
757 int wire = MI_IS_WIREFRAME(mi);
759 tweak_parameters (mi);
762 static Bool done = False;
763 if (!done || (0 == (random() % 20)))
771 glNewList(cc->dlist, GL_COMPILE);
772 unit_spheremonics (mi, cc->resolution, wire, cc->m, cc->colors);
775 glNewList(cc->dlist2, GL_COMPILE);
776 glPushAttrib (GL_LIGHTING);
777 glDisable (GL_LIGHTING);
779 glScalef (1.05, 1.05, 1.05);
780 unit_spheremonics (mi, cc->resolution, 2, cc->m, cc->colors);
791 load_font (ModeInfo *mi, char *res, XFontStruct **fontP, GLuint *dlistP)
793 const char *font = get_string_resource (res, "Font");
798 if (!font) font = "-*-times-bold-r-normal-*-140-*";
800 f = XLoadQueryFont(mi->dpy, font);
801 if (!f) f = XLoadQueryFont(mi->dpy, "fixed");
804 first = f->min_char_or_byte2;
805 last = f->max_char_or_byte2;
808 *dlistP = glGenLists ((GLuint) last+1);
809 check_gl_error ("glGenLists");
810 glXUseXFont(id, first, last-first+1, *dlistP + first);
811 check_gl_error ("glXUseXFont");
817 draw_label (ModeInfo *mi, const char *s)
819 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
822 glPushAttrib(GL_TRANSFORM_BIT | GL_ENABLE_BIT);
823 glDisable(GL_LIGHTING);
824 glDisable(GL_DEPTH_TEST);
825 glMatrixMode(GL_PROJECTION);
828 glMatrixMode(GL_MODELVIEW);
831 gluOrtho2D(0, mi->xgwa.width, 0, mi->xgwa.height);
832 glColor3f(1.0, 1.0, 0.0);
837 - (cc->font->ascent + cc->font->descent)));
838 for (i = 0; i < strlen(s); i++)
839 glCallList (cc->font_list + (int)s[i]);
842 glMatrixMode(GL_PROJECTION);
851 init_spheremonics (ModeInfo *mi)
853 spheremonics_configuration *cc;
856 ccs = (spheremonics_configuration *)
857 calloc (MI_NUM_SCREENS(mi), sizeof (spheremonics_configuration));
859 fprintf(stderr, "%s: out of memory\n", progname);
863 cc = &ccs[MI_SCREEN(mi)];
866 cc = &ccs[MI_SCREEN(mi)];
868 if ((cc->glx_context = init_GL(mi)) != NULL) {
870 reshape_spheremonics (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
875 glEnable (GL_LINE_SMOOTH);
876 glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
877 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
885 if (*s == 'x' || *s == 'X') cc->spin_x = 1;
886 else if (*s == 'y' || *s == 'Y') cc->spin_y = 1;
887 else if (*s == 'z' || *s == 'Z') cc->spin_z = 1;
891 "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
899 cc->rotx = frand(1.0) * RANDSIGN();
900 cc->roty = frand(1.0) * RANDSIGN();
901 cc->rotz = frand(1.0) * RANDSIGN();
903 /* bell curve from 0-6 degrees, avg 3 */
904 cc->dx = (frand(0.4) + frand(0.4) + frand(0.4)) / (360/2);
905 cc->dy = (frand(0.4) + frand(0.4) + frand(0.4)) / (360/2);
906 cc->dz = (frand(0.4) + frand(0.4) + frand(0.4)) / (360/2);
908 cc->d_max = cc->dx * 2;
910 cc->ddx = 0.00006 + frand(0.00003);
911 cc->ddy = 0.00006 + frand(0.00003);
912 cc->ddz = 0.00006 + frand(0.00003);
916 cc->resolution = res;
918 load_font (mi, "labelfont", &cc->font, &cc->font_list);
920 cc->dlist = glGenLists(1);
921 cc->dlist2 = glGenLists(1);
923 cc->m_max = 4; /* 9? */
926 for (i = 0; i < countof(cc->dm); i++)
927 cc->dm[i] = 1; /* going up! */
929 /* Generate a few more times so we don't always start off with a sphere */
930 for (i = 0; i < 5; i++)
931 tweak_parameters (mi);
934 generate_spheremonics(mi);
939 mouse_down_p (ModeInfo *mi)
944 if (!XQueryPointer (MI_DISPLAY(mi), MI_WINDOW(mi),
945 &root, &child, &rx, &ry, &wx, &wy, &mask))
947 if (! (mask & Button1Mask))
954 draw_spheremonics (ModeInfo *mi)
956 spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
957 Display *dpy = MI_DISPLAY(mi);
958 Window window = MI_WINDOW(mi);
961 if (!cc->glx_context)
964 mouse_p = mouse_down_p (mi);
966 glShadeModel(GL_SMOOTH);
968 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
972 glScalef(1.1, 1.1, 1.1);
979 static int frame = 0;
981 # define SINOID(SCALE,SIZE) \
982 ((((1 + sin((frame * (SCALE)) / 2 * M_PI)) / 2.0) * (SIZE)) - (SIZE)/2)
984 x = SINOID(0.0071, 8.0);
985 y = SINOID(0.0053, 6.0);
986 z = SINOID(0.0037, 15.0);
988 glTranslatef(x, y, z);
991 if (cc->spin_x || cc->spin_y || cc->spin_z)
996 if (x < 0) x = 1 - (x + 1);
997 if (y < 0) y = 1 - (y + 1);
998 if (z < 0) z = 1 - (z + 1);
1000 if (cc->spin_x) glRotatef(x * 360, 1.0, 0.0, 0.0);
1001 if (cc->spin_y) glRotatef(y * 360, 0.0, 1.0, 0.0);
1002 if (cc->spin_z) glRotatef(z * 360, 0.0, 0.0, 1.0);
1004 rotate(&cc->rotx, &cc->dx, &cc->ddx, cc->d_max);
1005 rotate(&cc->roty, &cc->dy, &cc->ddy, cc->d_max);
1006 rotate(&cc->rotz, &cc->dz, &cc->ddz, cc->d_max);
1012 glScalef (cc->scale, cc->scale, cc->scale);
1013 glCallList (cc->dlist);
1014 if (cc->mesher >= 0 /* || mouse_p */)
1016 glCallList (cc->dlist2);
1017 if (cc->mesher >= 0)
1026 sprintf (buf, "%d %d %d %d %d %d %d %d",
1027 cc->m[0], cc->m[1], cc->m[2], cc->m[3],
1028 cc->m[4], cc->m[5], cc->m[6], cc->m[7]);
1029 draw_label (mi, buf);
1034 static int tick = 0;
1035 if (tick++ == duration)
1037 generate_spheremonics(mi);
1039 cc->mesher = -1; /* turn off the mesh when switching objects */
1045 if (mi->fps_p) do_fps (mi);
1048 glXSwapBuffers(dpy, window);