~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper

« back to all changes in this revision

Viewing changes to hacks/glx/spheremonics.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* xscreensaver, Copyright (c) 2002, 2004 Jamie Zawinski <jwz@jwz.org>
 
2
 *
 
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 
 
9
 * implied warranty.
 
10
 *
 
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.
 
14
 *
 
15
 *  Paul says:
 
16
 *
 
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.
 
21
 *
 
22
 * The formula is quite simple: the form used here is based upon
 
23
 * spherical (polar) coordinates (radius, theta, phi).
 
24
 *
 
25
 *    r = sin(m0 phi)   ^ m1 + 
 
26
 *        cos(m2 phi)   ^ m3 + 
 
27
 *        sin(m4 theta) ^ m5 + 
 
28
 *        cos(m6 theta) ^ m7 
 
29
 *
 
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.
 
34
 *
 
35
 * As the degree increases, the objects become increasingly "pointed"
 
36
 * and a large number of polygons are required to represent the surface
 
37
 * faithfully.
 
38
 *
 
39
 * jwz adds:
 
40
 * 
 
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].
 
45
 *
 
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.
 
49
 *
 
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.
 
52
 *
 
53
 * There tends to be a dark stripe in the colormaps.  I don't know why.
 
54
 * Perhaps utils/colors.c is at fault?
 
55
 *
 
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.
 
61
 */
 
62
 
 
63
#include <X11/Intrinsic.h>
 
64
 
 
65
extern XtAppContext app;
 
66
 
 
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
 
74
 
 
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)"
 
83
 
 
84
#define DEFAULTS        "*delay:        30000       \n" \
 
85
                        "*showFPS:      False       \n" \
 
86
                        "*wireframe:    False       \n" \
 
87
 
 
88
#undef countof
 
89
#define countof(x) (sizeof((x))/sizeof((*x)))
 
90
 
 
91
#include "xlockmore.h"
 
92
#include "glxfonts.h"
 
93
#include "normals.h"
 
94
#include "colors.h"
 
95
#include "rotator.h"
 
96
#include "gltrackball.h"
 
97
#include <ctype.h>
 
98
 
 
99
#ifdef USE_GL /* whole file */
 
100
 
 
101
#include <GL/glu.h>
 
102
 
 
103
typedef struct {
 
104
  GLXContext *glx_context;
 
105
  rotator *rot;
 
106
  trackball_state *trackball;
 
107
  Bool button_down_p;
 
108
 
 
109
  GLuint dlist, dlist2;
 
110
  GLfloat scale;
 
111
  XYZ bbox[2];
 
112
 
 
113
  int resolution;
 
114
  int ncolors;
 
115
  XColor *colors;
 
116
 
 
117
  int m[8];
 
118
  int dm[8];
 
119
  int m_max;
 
120
 
 
121
  int tracer;
 
122
  int mesher;
 
123
  int polys1, polys2;  /* polygon counts */
 
124
 
 
125
  XFontStruct *font;
 
126
  GLuint font_list;
 
127
  int change_tick;
 
128
 
 
129
} spheremonics_configuration;
 
130
 
 
131
static spheremonics_configuration *ccs = NULL;
 
132
 
 
133
static char *do_spin;
 
134
static Bool do_wander;
 
135
static Bool do_bbox;
 
136
static Bool do_grid;
 
137
static int smooth_p;
 
138
static char *static_parms;
 
139
static int res;
 
140
static int duration;
 
141
 
 
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 },
 
156
};
 
157
 
 
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},
 
167
};
 
168
 
 
169
ModeSpecOpt ccs_opts = {countof(opts), opts, countof(vars), vars, NULL};
 
170
 
 
171
 
 
172
/* Window management, etc
 
173
 */
 
174
void
 
175
reshape_spheremonics (ModeInfo *mi, int width, int height)
 
176
{
 
177
  GLfloat h = (GLfloat) height / (GLfloat) width;
 
178
 
 
179
  glViewport (0, 0, (GLint) width, (GLint) height);
 
180
 
 
181
  glMatrixMode(GL_PROJECTION);
 
182
  glLoadIdentity();
 
183
  gluPerspective (30.0, 1/h, 1.0, 100.0);
 
184
 
 
185
  glMatrixMode(GL_MODELVIEW);
 
186
  glLoadIdentity();
 
187
  gluLookAt( 0.0, 0.0, 30.0,
 
188
             0.0, 0.0, 0.0,
 
189
             0.0, 1.0, 0.0);
 
190
 
 
191
  glClear(GL_COLOR_BUFFER_BIT);
 
192
}
 
193
 
 
194
 
 
195
static void
 
196
gl_init (ModeInfo *mi)
 
197
{
 
198
/*  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)]; */
 
199
  int wire = MI_IS_WIREFRAME(mi);
 
200
 
 
201
  static GLfloat pos[4] = {5.0, 5.0, 10.0, 1.0};
 
202
 
 
203
  glEnable(GL_NORMALIZE);
 
204
 
 
205
  if (!wire)
 
206
    {
 
207
      glLightfv(GL_LIGHT0, GL_POSITION, pos);
 
208
      glEnable(GL_LIGHTING);
 
209
      glEnable(GL_LIGHT0);
 
210
      glEnable(GL_DEPTH_TEST);
 
211
 
 
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.
 
218
 
 
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.
 
222
 
 
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
 
229
         lighting effect.
 
230
       */
 
231
      glDisable(GL_CULL_FACE);
 
232
      glLightModeli (GL_LIGHT_MODEL_TWO_SIDE, TRUE);
 
233
    }
 
234
}
 
235
 
 
236
 
 
237
 
 
238
/* generate the object */
 
239
 
 
240
static XYZ
 
241
sphere_eval (double theta, double phi, int *m)
 
242
{
 
243
  double r = 0;
 
244
  XYZ p;
 
245
 
 
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]);
 
250
 
 
251
  p.x = r * sin(phi) * cos(theta);
 
252
  p.y = r * cos(phi);
 
253
  p.z = r * sin(phi) * sin(theta);
 
254
 
 
255
  return (p);
 
256
}
 
257
 
 
258
 
 
259
static void
 
260
do_color (int i, XColor *colors)
 
261
{
 
262
  GLfloat c[4];
 
263
  c[0] = colors[i].red   / 65535.0;
 
264
  c[1] = colors[i].green / 65535.0;
 
265
  c[2] = colors[i].blue  / 65535.0;
 
266
  c[3] = 1.0;
 
267
  glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c);
 
268
  glColor3f (c[0], c[1], c[2]);
 
269
}
 
270
 
 
271
 
 
272
static void
 
273
draw_circle (ModeInfo *mi, Bool teeth_p)
 
274
{
 
275
  GLfloat th;
 
276
  int tick = 0;
 
277
  GLfloat x, y;
 
278
  GLfloat step = (M_PI / 180);
 
279
 
 
280
  glBegin(GL_LINE_LOOP);
 
281
  for (th = 0; th < M_PI*2; th += step*5)
 
282
    {
 
283
      GLfloat r1 = 0.5;
 
284
      x = cos (th);
 
285
      y = sin (th);
 
286
      glVertex3f(x*r1, y*r1,  0);
 
287
    }
 
288
  glEnd();
 
289
 
 
290
  if (!teeth_p) return;
 
291
 
 
292
  glBegin(GL_LINES);
 
293
  for (th = 0; th < M_PI*2; th += step)
 
294
    {
 
295
      GLfloat r1 = 0.5;
 
296
      GLfloat r2 = r1 - 0.01;
 
297
      if (! (tick % 10))
 
298
        r2 -= 0.02;
 
299
      else if (! (tick % 5))
 
300
        r2 -= 0.01;
 
301
      tick++;
 
302
 
 
303
      x = cos (th);
 
304
      y = sin (th);
 
305
      glVertex3f(x*r1, y*r1,  0);
 
306
      glVertex3f(x*r2, y*r2,  0);
 
307
    }
 
308
  glEnd();
 
309
}
 
310
 
 
311
 
 
312
static void
 
313
draw_bounding_box (ModeInfo *mi)
 
314
{
 
315
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
316
 
 
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);
 
320
 
 
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;
 
327
 
 
328
#if 1
 
329
  x1 = y1 = z1 = -0.5;
 
330
  x2 = y2 = z2 =  0.5;
 
331
#endif
 
332
 
 
333
  if (do_bbox && !wire)
 
334
    {
 
335
      glMaterialfv (GL_FRONT, GL_AMBIENT_AND_DIFFUSE, c1);
 
336
      glFrontFace(GL_CCW);
 
337
 
 
338
      glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
 
339
      glNormal3f(0, 1, 0);
 
340
      glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z2);
 
341
      glVertex3f(x2, y1, z2); glVertex3f(x2, y1, z1);
 
342
      glEnd();
 
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);
 
347
      glEnd();
 
348
      glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
 
349
      glNormal3f(0, 0, 1);
 
350
      glVertex3f(x1, y1, z1); glVertex3f(x2, y1, z1);
 
351
      glVertex3f(x2, y2, z1); glVertex3f(x1, y2, z1);
 
352
      glEnd();
 
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);
 
357
      glEnd();
 
358
      glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
 
359
      glNormal3f(1, 0, 0);
 
360
      glVertex3f(x1, y2, z1); glVertex3f(x1, y2, z2);
 
361
      glVertex3f(x1, y1, z2); glVertex3f(x1, y1, z1);
 
362
      glEnd();
 
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);
 
367
      glEnd();
 
368
    }
 
369
 
 
370
  glPushAttrib (GL_LIGHTING);
 
371
  glDisable (GL_LIGHTING);
 
372
 
 
373
  glColor3f (c2[0], c2[1], c2[2]);
 
374
 
 
375
  if (do_grid)
 
376
    {
 
377
      glPushMatrix();
 
378
      glBegin(GL_LINES);
 
379
      glVertex3f(0, -0.66, 0);
 
380
      glVertex3f(0,  0.66, 0); 
 
381
      glEnd();
 
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);
 
387
      glPopMatrix();
 
388
    }
 
389
  else
 
390
    {
 
391
      glBegin(GL_LINES);
 
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); 
 
398
      glEnd();
 
399
    }
 
400
 
 
401
  glPopAttrib();
 
402
}
 
403
 
 
404
 
 
405
static void
 
406
do_tracer (ModeInfo *mi)
 
407
{
 
408
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
409
 
 
410
  if (cc->tracer == -1 &&
 
411
      cc->mesher == -1 &&
 
412
      !(random() % (duration * 4)))
 
413
    {
 
414
      if (random() & 1)
 
415
        cc->tracer = ((random() & 1) ? 0 : 180);
 
416
      else
 
417
        cc->mesher = ((random() % ((duration / 3) + 1)) +
 
418
                      (random() % ((duration / 3) + 1)));
 
419
    }
 
420
 
 
421
  if (cc->tracer >= 0)
 
422
    {
 
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;
 
428
 
 
429
      if (s > 0.001)
 
430
        {
 
431
          static GLfloat c[4] = { 0.6, 0.5, 1.0, 1.0 };
 
432
 
 
433
          glPushAttrib (GL_LIGHTING);
 
434
          glDisable (GL_LIGHTING);
 
435
 
 
436
          glPushMatrix();
 
437
          glRotatef (90, 1, 0, 0);
 
438
          glTranslatef (0, 0, y*s/2);
 
439
          s *= x;
 
440
          glScalef(s, s, s);
 
441
          glColor3f (c[0], c[1], c[2]);
 
442
          draw_circle (mi, False);
 
443
          glPopMatrix();
 
444
 
 
445
          glPopAttrib();
 
446
        }
 
447
 
 
448
      cc->tracer += 5;
 
449
      if (cc->tracer == 180 || cc->tracer == 360)
 
450
        cc->tracer = -1;
 
451
    }
 
452
}
 
453
 
 
454
 
 
455
static int
 
456
unit_spheremonics (ModeInfo *mi,
 
457
                   int resolution, Bool wire, int *m, XColor *colors)
 
458
{
 
459
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
460
  int polys = 0;
 
461
  int i, j;
 
462
  double du, dv;
 
463
  XYZ q[4];
 
464
  XYZ n[4];
 
465
  int res = (wire == 2
 
466
             ? resolution / 2
 
467
             : resolution);
 
468
 
 
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;
 
471
 
 
472
  du = (M_PI+M_PI) / (double)res; /* Theta */
 
473
  dv = M_PI        / (double)res; /* Phi   */
 
474
 
 
475
  if (wire)
 
476
    glColor3f (1, 1, 1);
 
477
 
 
478
  glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
 
479
 
 
480
  for (i = 0; i < res; i++) {
 
481
    double u = i * du;
 
482
    for (j = 0; j < res; j++) {
 
483
      double v = j * dv;
 
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);
 
491
 
 
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);
 
499
 
 
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);
 
507
 
 
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);
 
515
 
 
516
      polys++;
 
517
 
 
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
 
525
 
 
526
      CHECK_BBOX(0);
 
527
      CHECK_BBOX(1);
 
528
      CHECK_BBOX(2);
 
529
      CHECK_BBOX(3);
 
530
# undef CHECK_BBOX
 
531
    }
 
532
  }
 
533
  glEnd();
 
534
 
 
535
  {
 
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);
 
542
 
 
543
    cc->scale = 1/scale;
 
544
 
 
545
    if (wire < 2 && (do_bbox || do_grid))
 
546
      {
 
547
        GLfloat s = scale * 1.5;
 
548
        glPushMatrix();
 
549
        glScalef(s, s, s);
 
550
        draw_bounding_box (mi);
 
551
        glPopMatrix();
 
552
      }
 
553
  }
 
554
  return polys;
 
555
}
 
556
 
 
557
 
 
558
static void
 
559
init_colors (ModeInfo *mi)
 
560
{
 
561
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
562
  int i;
 
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, 
 
567
                        False, 0, False);
 
568
 
 
569
  /* brighter colors, please... */
 
570
  for (i = 0; i < cc->ncolors; i++)
 
571
    {
 
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;
 
575
    }
 
576
}
 
577
 
 
578
 
 
579
/* Pick one of the parameters to the function and tweak it up or down.
 
580
 */
 
581
static void
 
582
tweak_parameters (ModeInfo *mi)
 
583
{
 
584
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
585
 
 
586
  /* If the -parameters command line option was specified, just use that
 
587
     all the time.
 
588
   */
 
589
  if (static_parms &&
 
590
      *static_parms &&
 
591
      !!strcasecmp (static_parms, "(default)"))
 
592
    {
 
593
      unsigned long n;
 
594
      char dummy;
 
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],
 
598
                       &dummy))
 
599
        return;
 
600
      else if (strlen (static_parms) == 8 &&
 
601
               1 == sscanf (static_parms, "%lu %c", &n, &dummy))
 
602
        {
 
603
          const char *s = static_parms;
 
604
          int i = 0;
 
605
          while (*s)
 
606
            cc->m[i++] = (*s++)-'0';
 
607
          return;
 
608
        }
 
609
      fprintf (stderr,
 
610
               "%s: -parameters must be a string of 8 ints (not \"%s\")\n",
 
611
               progname, static_parms);
 
612
      exit (1);
 
613
    }
 
614
 
 
615
  static_parms = 0;
 
616
 
 
617
 
 
618
# define SHIFT(N) do { \
 
619
    int n = (N); \
 
620
    cc->m[n] += cc->dm[n]; \
 
621
    if (cc->m[n] <= 0) \
 
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]; \
 
625
  } while(0)
 
626
 
 
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]; \
 
629
*/
 
630
 
 
631
  switch(random() % 8)
 
632
    {
 
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;
 
642
    }
 
643
# undef SHIFT
 
644
 
 
645
#if 0
 
646
    printf ("%s: state: %d %d %d %d %d %d %d %d\n",
 
647
            progname,
 
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]);
 
650
#endif
 
651
 
 
652
}
 
653
 
 
654
 
 
655
static void
 
656
generate_spheremonics (ModeInfo *mi)
 
657
{
 
658
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
659
  int wire = MI_IS_WIREFRAME(mi);
 
660
 
 
661
  tweak_parameters (mi);
 
662
 
 
663
  {
 
664
    static Bool done = False;
 
665
    if (!done || (0 == (random() % 20)))
 
666
      {
 
667
        init_colors (mi);
 
668
        done = True;
 
669
      }
 
670
  }
 
671
 
 
672
  {
 
673
    glNewList(cc->dlist, GL_COMPILE);
 
674
    cc->polys1 = unit_spheremonics (mi, cc->resolution, wire,cc->m,cc->colors);
 
675
    glEndList();
 
676
 
 
677
    glNewList(cc->dlist2, GL_COMPILE);
 
678
    glPushAttrib (GL_LIGHTING);
 
679
    glDisable (GL_LIGHTING);
 
680
    glPushMatrix();
 
681
    glScalef (1.05, 1.05, 1.05);
 
682
    cc->polys2 = unit_spheremonics (mi, cc->resolution, 2, cc->m, cc->colors);
 
683
    glPopMatrix();
 
684
    glPopAttrib();
 
685
    glEndList();
 
686
  }
 
687
}
 
688
 
 
689
 
 
690
 
 
691
 
 
692
void 
 
693
init_spheremonics (ModeInfo *mi)
 
694
{
 
695
  spheremonics_configuration *cc;
 
696
 
 
697
  if (!ccs) {
 
698
    ccs = (spheremonics_configuration *)
 
699
      calloc (MI_NUM_SCREENS(mi), sizeof (spheremonics_configuration));
 
700
    if (!ccs) {
 
701
      fprintf(stderr, "%s: out of memory\n", progname);
 
702
      exit(1);
 
703
    }
 
704
 
 
705
    cc = &ccs[MI_SCREEN(mi)];
 
706
  }
 
707
 
 
708
  cc = &ccs[MI_SCREEN(mi)];
 
709
 
 
710
  if ((cc->glx_context = init_GL(mi)) != NULL) {
 
711
    gl_init(mi);
 
712
    reshape_spheremonics (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
 
713
  }
 
714
 
 
715
  if (smooth_p) 
 
716
    {
 
717
      glEnable (GL_LINE_SMOOTH);
 
718
      glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
 
719
      glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
 
720
      glEnable (GL_BLEND);
 
721
    }
 
722
 
 
723
  {
 
724
    Bool spinx=False, spiny=False, spinz=False;
 
725
    double spin_speed   = 1.0;
 
726
    double wander_speed = 0.03;
 
727
 
 
728
    char *s = do_spin;
 
729
    while (*s)
 
730
      {
 
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;
 
734
        else
 
735
          {
 
736
            fprintf (stderr,
 
737
         "%s: spin must contain only the characters X, Y, or Z (not \"%s\")\n",
 
738
                     progname, do_spin);
 
739
            exit (1);
 
740
          }
 
741
        s++;
 
742
      }
 
743
 
 
744
    cc->rot = make_rotator (spinx ? spin_speed : 0,
 
745
                            spinz ? spin_speed : 0,
 
746
                            spiny ? spin_speed : 0,
 
747
                            1.0,
 
748
                            do_wander ? wander_speed : 0,
 
749
                            (spinx && spiny && spinz));
 
750
    cc->trackball = gltrackball_init ();
 
751
  }
 
752
 
 
753
  cc->tracer = -1;
 
754
  cc->mesher = -1;
 
755
 
 
756
  cc->resolution = res;
 
757
 
 
758
  load_font (mi->dpy, "labelfont", &cc->font, &cc->font_list);
 
759
 
 
760
  cc->dlist = glGenLists(1);
 
761
  cc->dlist2 = glGenLists(1);
 
762
 
 
763
  cc->m_max = 4; /* 9? */
 
764
  {
 
765
    unsigned int i;
 
766
    for (i = 0; i < countof(cc->dm); i++)
 
767
      cc->dm[i] = 1;  /* going up! */
 
768
 
 
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);
 
772
  }
 
773
 
 
774
  generate_spheremonics(mi);
 
775
}
 
776
 
 
777
 
 
778
Bool
 
779
spheremonics_handle_event (ModeInfo *mi, XEvent *event)
 
780
{
 
781
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
782
 
 
783
  if (event->xany.type == ButtonPress &&
 
784
      event->xbutton.button == Button1)
 
785
    {
 
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));
 
790
      return True;
 
791
    }
 
792
  else if (event->xany.type == ButtonRelease &&
 
793
           event->xbutton.button == Button1)
 
794
    {
 
795
      cc->button_down_p = False;
 
796
      return True;
 
797
    }
 
798
  else if (event->xany.type == ButtonPress &&
 
799
           (event->xbutton.button == Button4 ||
 
800
            event->xbutton.button == Button5))
 
801
    {
 
802
      gltrackball_mousewheel (cc->trackball, event->xbutton.button, 10,
 
803
                              !!event->xbutton.state);
 
804
      return True;
 
805
    }
 
806
  else if (event->xany.type == KeyPress)
 
807
    {
 
808
      KeySym keysym;
 
809
      char c = 0;
 
810
      XLookupString (&event->xkey, &c, 1, &keysym, 0);
 
811
 
 
812
      if (c == ' ' || c == '\t' || c == '\r' || c == '\n')
 
813
        {
 
814
          cc->change_tick = duration;
 
815
          return True;
 
816
        }
 
817
    }
 
818
  else if (event->xany.type == MotionNotify &&
 
819
           cc->button_down_p)
 
820
    {
 
821
      gltrackball_track (cc->trackball,
 
822
                         event->xmotion.x, event->xmotion.y,
 
823
                         MI_WIDTH (mi), MI_HEIGHT (mi));
 
824
      return True;
 
825
    }
 
826
 
 
827
  return False;
 
828
}
 
829
 
 
830
 
 
831
void
 
832
draw_spheremonics (ModeInfo *mi)
 
833
{
 
834
  spheremonics_configuration *cc = &ccs[MI_SCREEN(mi)];
 
835
  Display *dpy = MI_DISPLAY(mi);
 
836
  Window window = MI_WINDOW(mi);
 
837
 
 
838
  if (!cc->glx_context)
 
839
    return;
 
840
 
 
841
  glShadeModel(GL_SMOOTH);
 
842
 
 
843
  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
844
 
 
845
  glPushMatrix ();
 
846
 
 
847
  glScalef(1.1, 1.1, 1.1);
 
848
 
 
849
  {
 
850
    double x, y, z;
 
851
    get_position (cc->rot, &x, &y, &z, !cc->button_down_p);
 
852
    glTranslatef((x - 0.5) * 8,
 
853
                 (y - 0.5) * 6,
 
854
                 (z - 0.5) * 8);
 
855
 
 
856
    gltrackball_rotate (cc->trackball);
 
857
 
 
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);
 
862
  }
 
863
 
 
864
  glScalef(7,7,7);
 
865
 
 
866
  mi->polygon_count = 0;
 
867
 
 
868
  glScalef (cc->scale, cc->scale, cc->scale);
 
869
  glCallList (cc->dlist);
 
870
  mi->polygon_count += cc->polys1;
 
871
 
 
872
  if (cc->mesher >= 0 /* || mouse_p */)
 
873
    {
 
874
      glCallList (cc->dlist2);
 
875
      mi->polygon_count += cc->polys2;
 
876
      if (cc->mesher >= 0)
 
877
        cc->mesher--;
 
878
    }
 
879
  do_tracer(mi);
 
880
 
 
881
 
 
882
  if (cc->button_down_p)
 
883
    {
 
884
      char buf[200];
 
885
      sprintf (buf,
 
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)
 
888
                ? "%d%d%d%d%d%d%d%d"
 
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]);
 
892
 
 
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,
 
897
                       buf);
 
898
    }
 
899
 
 
900
  if (!static_parms)
 
901
    {
 
902
      if (cc->change_tick++ >= duration && !cc->button_down_p)
 
903
        {
 
904
          generate_spheremonics(mi);
 
905
          cc->change_tick = 0;
 
906
          cc->mesher = -1;  /* turn off the mesh when switching objects */
 
907
        }
 
908
    }
 
909
 
 
910
  glPopMatrix();
 
911
 
 
912
  if (mi->fps_p) do_fps (mi);
 
913
  glFinish();
 
914
 
 
915
  glXSwapBuffers(dpy, window);
 
916
}
 
917
 
 
918
#endif /* USE_GL */