From http://www.jwz.org/xscreensaver/xscreensaver-5.38.tar.gz
[xscreensaver] / hacks / glx / superquadrics.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* superquadrics --- 3D mathematical shapes */
3
4 #if 0
5 static const char sccsid[] = "@(#)superquadrics.c       4.07 97/11/24 xlockmore";
6 #endif
7
8 /*-
9  * Permission to use, copy, modify, and distribute this software and its
10  * documentation for any purpose and without fee is hereby granted,
11  * provided that the above copyright notice appear in all copies and that
12  * both that copyright notice and this permission notice appear in
13  * supporting documentation.
14  *
15  * This file is provided AS IS with no warranties of any kind.  The author
16  * shall have no liability with respect to the infringement of copyrights,
17  * trade secrets or any patents by this file or any part thereof.  In no
18  * event will the author be liable for any lost revenue or profits or
19  * other special, indirect and consequential damages.
20  *
21  * Superquadrics were invented by Dr. Alan Barr of Caltech University.
22  * They were first published in "Computer Graphics and Applications",
23  * volume 1, number 1, 1981, in the article "Superquadrics and Angle-
24  * Preserving Transformations."  Dr. Barr based the Superquadrics on
25  * Piet Hein's "super ellipses."  Super ellipses are like 2D ellipses,
26  * except that the formula includes an exponent, raising its X and Y
27  * values to a (fractional) power, and allowing them to gradually
28  * change from round to square edges.  Superquadrics extend this
29  * idea into 3 dimensions, using two exponents to modify a
30  * quadric surface in a similar fashion.
31  *
32  * Revision History:
33  * 30-Mar-97: Turned into a module for xlockmore 4.02 alpha.  The code
34  *    is almost unrecognizable now from the first revision, except for
35  *    a few remaining two-letter variable names.  I still don't have
36  *    the normal vectors working right (I wrote the buggy normal vector
37  *    code myself, can you tell?)
38  * 07-Jan-97: A legend reborn; Superquadrics make an appearance as a
39  *    real OpenGL program written in C.  I can even render them with
40  *    proper lighting and specular highlights.  Gee, they look almost
41  *    as good now as the original color plates of them that my uncle
42  *    showed me as a child in 1981.  I don't know what computer hardware
43  *    he was using at the time, but it's taken a couple decades for the
44  *    PC clone hardware to catch up to it.
45  * 05-Jan-97: After almost a decade, Superquadrics had almost faded away
46  *    into the myths and folklore of all the things my brother and I played
47  *    with on computers when we were kids with too much time on our hands.
48  *    I had since gotten involved in Unix, OpenGL, and other things.
49  *    A sudden flash of inspiration caused me to dig out the old Pascal
50  *    source code, run it through p2c, and start ripping away the old
51  *    wireframe rendering code, to be replaced by OpenGL.
52  * Late 1989 or early 1990:  Around this time I did the Turbo Pascal
53  *    port of the Superquadrics.  Unfortunately, many of the original variable
54  *    names remained the same from the C= 64 original.  This was unfortunate
55  *    because BASIC on the c64 only allowed 2-letter, global variable names.
56  *    But the speed improvement over BASIC was very impressive at the time.
57  * Thanksgiving, 1987: Written.  My uncle Al, who invented Superquadrics some
58  *    years earlier, came to visit us.  I was a high school kid at the time,
59  *    with nothing more than a Commodore 64.  Somehow we wrote this program,
60  *    (he did the math obviously, I just coded it into BASIC for the c64).
61  *    Yeah, 320x200 resolution, colorless white wireframe, and half an hour
62  *    rendering time per superquadric.  PLOT x,y.  THOSE were the days.
63  *    In the following years I would port Superquadrics to AppleBASIC,
64  *    AmigaBASIC, and then Turbo Pascal for IBM clones.  5 minutes on a 286!
65  *    Talk about fast rendering!  But these days, when my Pentium 166 runs
66  *    the same program, the superquadric will already be waiting on the
67  *    screen before my monitor can change frequency from text to graphics
68  *    mode.  Can't time the number of minutes that way!  Darn ;)
69  *
70  * Ed Mackey
71  */
72
73 #ifdef STANDALONE
74 # define DEFAULTS       "*delay:                40000   \n"                     \
75                                         "*count:                25      \n"                     \
76                                         "*cycles:               40      \n"                     \
77                                         "*showFPS:      False   \n"                     \
78                                         "*wireframe:    False   \n"                     \
79                                         "*suppressRotationAnimation: True\n" \
80
81 # define free_superquadrics 0
82 # define release_superquadrics 0
83 # define superquadrics_handle_event 0
84 # include "xlockmore.h"                         /* from the xscreensaver distribution */
85 #else  /* !STANDALONE */
86 # include "xlock.h"                                     /* from the xlockmore distribution */
87 #endif /* !STANDALONE */
88
89 #ifdef USE_GL
90
91 /*-
92  * Note for low-CPU-speed machines:  If your frame rate is so low that
93  * attempts at animation appear futile, try using "-cycles 1", which puts
94  * Superquadrics into kind of a slide-show mode.  It will still use up
95  * all of your CPU power, but it may look nicer.
96  */
97
98 #define DEF_SPINSPEED  "5.0"
99
100 static float spinspeed;
101
102 static XrmOptionDescRec opts[] =
103 {
104   {"-spinspeed", ".superquadrics.spinspeed", XrmoptionSepArg, 0}
105 };
106 static argtype vars[] =
107 {
108   {&spinspeed, "spinspeed", "Spinspeed", DEF_SPINSPEED, t_Float}
109 };
110 static OptionStruct desc[] =
111 {
112         {"-spinspeed num", "speed of rotation, in degrees per frame"}
113 };
114
115 ENTRYPOINT ModeSpecOpt superquadrics_opts =
116 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
117
118 #ifdef USE_MODULES
119 ModStruct   superquadrics_description =
120 {"superquadrics", "init_superquadrics", "draw_superquadrics", NULL,
121  "refresh_superquadrics", "init_superquadrics", NULL, &superquadrics_opts,
122  1000, 25, 40, 1, 4, 1.0, "",
123  "Shows 3D mathematical shapes", 0, NULL};
124
125 #endif
126
127 #define MaxRes          50
128 #define MinRes          5
129
130 typedef double dimi[MaxRes + 1];
131
132 typedef struct {
133         double      xExponent, yExponent;
134         GLfloat     r[4], g[4], b[4];
135         long        Mode;
136         int         rotx, rotz;
137 } state;
138
139 typedef struct {
140         GLXContext *glx_context;
141         int         dist, wireframe, flatshade, shownorms, maxcount, maxwait;
142         int         counter, viewcount, viewwait, mono;
143         GLfloat     curmat[4][4], rotx, roty, rotz, spinspeed;
144         /* In dimi: the first letter stands for cosine/sine, the second
145          *          stands for North, South, East, or West.  I think.
146          */
147         dimi        cs, se, sw, sn, ss, ce, cw, cn, Prevxx, Prevyy, Prevzz,
148                     Prevxn, Prevyn, Prevzn;
149         double      xExponent, yExponent, Mode;
150         int         resolution;
151         state       now, later;
152
153     int         pats[4][4];
154         int             cullmode;
155
156 } superquadricsstruct;
157
158 static superquadricsstruct *superquadrics = NULL;
159
160 #define CLIP_NORMALS 10000.0
161
162 static void ReshapeSuperquadrics(int w, int h);
163
164 static int
165 myrand(int range)
166 {
167         return ((int) (((float) range) * LRAND() / (MAXRAND)));
168 }
169
170 static float
171 myrandreal(void)
172 {
173         return (LRAND() / (MAXRAND));
174 }
175
176 /* Some old, old, OLD code follows.  Ahh this takes me back..... */
177
178 /* Output from p2c, the Pascal-to-C translator */
179 /* From input file "squad.pas" */
180
181 static double
182 XtoY(double x, double y)
183 {
184         double      z, a;
185
186         /* This is NOT your typical raise-X-to-the-Y-power function.  Do not attempt
187          * to replace this with a standard exponent function.  If you must, just
188          * replace the "a = exp(y * log(z));" line with something faster.
189          */
190
191         z = fabs(x);
192         if (z < 1e-20) {
193                 a = 0.0;
194                 return a;
195         }
196         a = exp(y * log(z));
197         if (a > CLIP_NORMALS)
198                 a = CLIP_NORMALS;
199         if (x < 0)
200                 a = -a;
201         return a;
202 }
203
204
205 static double
206 Sine(double x, double e)
207 {
208         /* This is just the sine wave raised to the exponent.  BUT, you can't
209          * raise negative numbers to fractional exponents.  So we have a special
210          * XtoY routune which handles it in a way useful to superquadrics.
211          */
212
213         return (XtoY(sin(x), e));
214 }
215
216
217 static double
218 Cosine(double x, double e)
219 {
220         return (XtoY(cos(x), e));
221 }
222
223
224 static void
225 MakeUpStuff(int allstuff, superquadricsstruct * sp)
226 {
227         int         dostuff;
228         int         t, pat;
229         GLfloat     r, g, b, r2, g2, b2;
230
231         /* randomize it. */
232
233         if (sp->maxcount < 2)
234                 allstuff = 1;
235         dostuff = allstuff * 15;
236         if (!dostuff) {
237                 dostuff = myrand(3) + 1;
238                 if (myrand(2) || (dostuff & 1))
239                         dostuff |= 4;
240                 if (myrand(2))
241                         dostuff |= 8;
242         }
243         if (dostuff & 1) {
244                 sp->later.xExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
245                 sp->later.yExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
246
247                 /* Increase the 2.0 .. 2.5 range to 2.0 .. 3.0 */
248                 if (sp->later.xExponent > 2.0)
249                         sp->later.xExponent = (sp->later.xExponent * 2.0) - 2.0;
250                 if (sp->later.yExponent > 2.0)
251                         sp->later.yExponent = (sp->later.yExponent * 2.0) - 2.0;
252         }
253         if (dostuff & 2) {
254                 do {
255                         sp->later.Mode = myrand(3L) + 1;
256                 } while (!allstuff && (sp->later.Mode == sp->now.Mode));
257                 /* On init: make sure it can stay in mode 1 if it feels like it. */
258         }
259         if (dostuff & 4) {
260                 if (sp->mono) {
261                         if (sp->wireframe) {
262                                 b = g = r = 1.0;
263                                 b2 = g2 = r2 = 1.0;
264                         } else {
265                                 b = g = r = (GLfloat) (140 + myrand(100)) / 255.0;
266                                 b2 = g2 = r2 = ((r > 0.69) ? (1.0 - r) : r);
267                         }
268                 } else {
269                         r = (GLfloat) (40 + myrand(200)) / 255.0;
270                         g = (GLfloat) (40 + myrand(200)) / 255.0;
271                         b = (GLfloat) (40 + myrand(200)) / 255.0;
272
273                         r2 = ((myrand(4) && ((r < 0.31) || (r > 0.69))) ? (1.0 - r) : r);
274                         g2 = ((myrand(4) && ((g < 0.31) || (g > 0.69))) ? (1.0 - g) : g);
275                         b2 = ((myrand(4) && ((b < 0.31) || (b > 0.69))) ? (1.0 - b) : b);
276                 }
277
278                 pat = myrand(4);
279                 for (t = 0; t < 4; ++t) {
280                         sp->later.r[t] = sp->pats[pat][t] ? r : r2;
281                         sp->later.g[t] = sp->pats[pat][t] ? g : g2;
282                         sp->later.b[t] = sp->pats[pat][t] ? b : b2;
283                 }
284         }
285         if (dostuff & 8) {
286                 sp->later.rotx = myrand(360) - 180;
287                 sp->later.rotz = myrand(160) - 80;
288         }
289 }
290
291 static void
292 inputs(superquadricsstruct * sp)
293 {
294         int         iv;
295         double      u, v, mode3, cn3, inverter2, flatu, flatv;
296
297         if (sp->Mode < 1.000001) {
298                 mode3 = 1.0;
299                 cn3 = 0.0;
300                 inverter2 = 1.0;
301         } else if (sp->Mode < 2.000001) {
302                 mode3 = 1.0;
303                 cn3 = (sp->Mode - 1.0) * 1.5;
304                 inverter2 = (sp->Mode - 1.0) * -2.0 + 1.0;
305         } else {
306                 mode3 = (sp->Mode - 1.0);
307                 cn3 = (sp->Mode - 2.0) / 2.0 + 1.5;
308                 inverter2 = -1.0;
309         }
310
311         if (sp->flatshade) {
312                 flatu = M_PI / (sp->resolution - 1);
313                 flatv = mode3 * M_PI / ((sp->resolution - 1) * 2);
314         } else {
315                 flatu = flatv = 0.0;
316         }
317
318         /* (void) printf("Calculating....\n"); */
319         for (iv = 1; iv <= sp->resolution; iv++) {
320
321                 /* u ranges from PI down to -PI */
322                 u = (1 - iv) * 2 * M_PI / (sp->resolution - 1) + M_PI;
323
324                 /* v ranges from PI/2 down to -PI/2 */
325                 v = (1 - iv) * mode3 * M_PI / (sp->resolution - 1) + M_PI * (mode3 / 2.0);
326
327                 /* Use of xExponent */
328                 sp->se[iv] = Sine(u, sp->xExponent);
329                 sp->ce[iv] = Cosine(u, sp->xExponent);
330                 sp->sn[iv] = Sine(v, sp->yExponent);
331                 sp->cn[iv] = Cosine(v, sp->yExponent) * inverter2 + cn3;
332
333                 /* Normal vector computations only */
334                 sp->sw[iv] = Sine(u + flatu, 2 - sp->xExponent);
335                 sp->cw[iv] = Cosine(u + flatu, 2 - sp->xExponent);
336                 sp->ss[iv] = Sine(v + flatv, 2 - sp->yExponent) * inverter2;
337                 sp->cs[iv] = Cosine(v + flatv, 2 - sp->yExponent);
338         }                       /* next */
339
340         /* Now fix up the endpoints */
341         sp->se[sp->resolution] = sp->se[1];
342         sp->ce[sp->resolution] = sp->ce[1];
343
344         if (sp->Mode > 2.999999) {
345                 sp->sn[sp->resolution] = sp->sn[1];
346                 sp->cn[sp->resolution] = sp->cn[1];
347         }
348 }
349
350
351 static int
352 DoneScale(superquadricsstruct * sp)
353 {
354         double      xx, yy, zz, xp = 0, yp = 0, zp = 0, xn, yn, zn, xnp = 0,
355                     ynp = 0, znp = 0;
356         int         ih, iv;
357     int polys = 0;
358
359         /* Hey don't knock my 2-letter variable names.  Simon's BASIC rules, man! ;-> */
360         /* Just kidding..... */
361         int         toggle = 0;
362
363         for (ih = 1; ih <= sp->resolution; ih++) {
364                 toggle ^= 2;
365                 for (iv = 1; iv <= sp->resolution; iv++) {
366                         toggle ^= 1;
367                         if (sp->wireframe)
368                                 glColor3f(sp->curmat[toggle][0], sp->curmat[toggle][1], sp->curmat[toggle][2]);
369                         else
370                                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sp->curmat[toggle]);
371
372                         xx = sp->cn[iv] * sp->ce[ih];
373                         zz = sp->cn[iv] * sp->se[ih];
374                         yy = sp->sn[iv];
375
376                         if (sp->wireframe) {
377                                 if ((ih > 1) || (iv > 1)) {
378                                         glBegin(GL_LINES);
379                                         if (ih > 1) {
380                                                 glVertex3f(xx, yy, zz);
381                                                 glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
382                         polys++;
383                                         }
384                                         if (iv > 1) {
385                                                 glVertex3f(xx, yy, zz);
386                                                 glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
387                         polys++;
388                                         }
389 /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
390    * MesaGL 2.2 and -mono.  This has been fixed in MesaGL 2.3 and later. */
391                                         glEnd();
392                                 }
393                         } else {
394                                 if ((sp->cs[iv] > 1e+10) || (sp->cs[iv] < -1e+10)) {
395                                         xn = sp->cs[iv];
396                                         zn = sp->cs[iv];
397                                         yn = sp->ss[iv];
398                                 } else {
399                                         xn = sp->cs[iv] * sp->cw[ih];
400                                         zn = sp->cs[iv] * sp->sw[ih];
401                                         yn = sp->ss[iv];
402                                 }
403                                 if ((ih > 1) && (iv > 1)) {
404                                         glNormal3f(xn, yn, zn);
405                                         glBegin(GL_POLYGON);
406                                         glVertex3f(xx, yy, zz);
407                                         if (!sp->flatshade)
408                                                 glNormal3f(sp->Prevxn[iv], sp->Prevyn[iv], sp->Prevzn[iv]);
409                                         glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
410                                         if (!sp->flatshade)
411                                                 glNormal3f(xnp, ynp, znp);
412                                         glVertex3f(xp, yp, zp);
413                                         if (!sp->flatshade)
414                                                 glNormal3f(sp->Prevxn[iv - 1], sp->Prevyn[iv - 1], sp->Prevzn[iv - 1]);
415                                         glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
416                     polys++;
417                                         glEnd();
418                                 }
419                                 if (sp->shownorms) {
420                                         if (!sp->flatshade)
421                                                 glShadeModel(GL_FLAT);
422                                         glDisable(GL_LIGHTING);
423                                         glBegin(GL_LINES);
424                                         glVertex3f(xx, yy, zz);
425                                         glVertex3f(xx + xn, yy + yn, zz + zn);
426                     polys++;
427                                         glEnd();
428                                         if (!sp->flatshade)
429                                                 glShadeModel(GL_SMOOTH);
430                                         glEnable(GL_LIGHTING);
431                                 }
432                                 xnp = sp->Prevxn[iv];
433                                 ynp = sp->Prevyn[iv];
434                                 znp = sp->Prevzn[iv];
435                                 sp->Prevxn[iv] = xn;
436                                 sp->Prevyn[iv] = yn;
437                                 sp->Prevzn[iv] = zn;
438                         }
439
440                         xp = sp->Prevxx[iv];
441                         yp = sp->Prevyy[iv];
442                         zp = sp->Prevzz[iv];
443                         sp->Prevxx[iv] = xx;
444                         sp->Prevyy[iv] = yy;
445                         sp->Prevzz[iv] = zz;
446
447                 }               /* next */
448         }                       /* next */
449     return polys;
450 }
451
452 /**** End of really old code ****/
453
454 static void
455 SetCull(int init, superquadricsstruct * sp)
456 {
457         if (init) {
458         glDisable(GL_CULL_FACE);
459                 sp->cullmode = 0;
460                 return;
461         }
462         if (sp->Mode < 1.0001) {
463                 if (sp->cullmode != 1) {
464                         glEnable(GL_CULL_FACE);
465                         glCullFace(GL_BACK);
466                         sp->cullmode = 1;
467                 }
468         } else if (sp->Mode > 2.9999) {
469                 if (sp->cullmode != 2) {
470                         glEnable(GL_CULL_FACE);
471                         glCullFace(GL_FRONT);
472                         sp->cullmode = 2;
473                 }
474         } else {
475                 if (sp->cullmode) {
476                         glDisable(GL_CULL_FACE);
477                         sp->cullmode = 0;
478                 }
479         }
480 }
481
482 static void
483 SetCurrentShape(superquadricsstruct * sp)
484 {
485         int         t;
486
487         sp->xExponent = sp->now.xExponent = sp->later.xExponent;
488         sp->yExponent = sp->now.yExponent = sp->later.yExponent;
489
490         for (t = 0; t < 4; ++t) {
491                 sp->curmat[t][0] = sp->now.r[t] = sp->later.r[t];
492                 sp->curmat[t][1] = sp->now.g[t] = sp->later.g[t];
493                 sp->curmat[t][2] = sp->now.b[t] = sp->later.b[t];
494         }
495
496         sp->Mode = (double) (sp->now.Mode = sp->later.Mode);
497         sp->rotx = sp->now.rotx = sp->later.rotx;
498         sp->rotz = sp->now.rotz = sp->later.rotz;
499
500         sp->counter = -sp->maxwait;
501
502         inputs(sp);
503 }
504
505 static void
506 NextSuperquadric(superquadricsstruct * sp)
507 {
508         double      fnow, flater;
509         int         t;
510
511         sp->roty -= sp->spinspeed;
512         while (sp->roty >= 360.0)
513                 sp->roty -= 360.0;
514         while (sp->roty < 0.0)
515                 sp->roty += 360.0;
516
517         --sp->viewcount;
518
519         if (sp->counter > 0) {
520                 if (--sp->counter == 0) {
521                         SetCurrentShape(sp);
522                         if (sp->counter == 0) {         /* Happens if sp->maxwait == 0 */
523                                 MakeUpStuff(0, sp);
524                                 sp->counter = sp->maxcount;
525                         }
526                 } else {
527                         fnow = (double) sp->counter / (double) sp->maxcount;
528                         flater = (double) (sp->maxcount - sp->counter) / (double) sp->maxcount;
529                         sp->xExponent = sp->now.xExponent * fnow + sp->later.xExponent * flater;
530                         sp->yExponent = sp->now.yExponent * fnow + sp->later.yExponent * flater;
531
532                         for (t = 0; t < 4; ++t) {
533                                 sp->curmat[t][0] = sp->now.r[t] * fnow + sp->later.r[t] * flater;
534                                 sp->curmat[t][1] = sp->now.g[t] * fnow + sp->later.g[t] * flater;
535                                 sp->curmat[t][2] = sp->now.b[t] * fnow + sp->later.b[t] * flater;
536                         }
537
538                         sp->Mode = (double) sp->now.Mode * fnow + (double) sp->later.Mode * flater;
539                         sp->rotx = (double) sp->now.rotx * fnow + (double) sp->later.rotx * flater;
540                         sp->rotz = (double) sp->now.rotz * fnow + (double) sp->later.rotz * flater;
541
542                         inputs(sp);
543                 }
544         } else {
545                 if (++sp->counter >= 0) {
546                         MakeUpStuff(0, sp);
547                         sp->counter = sp->maxcount;
548                 }
549         }
550 }
551
552 static int
553 DisplaySuperquadrics(ModeInfo *mi)
554 {
555         superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
556     int polys = 0;
557         glDrawBuffer(GL_BACK);
558         if (sp->wireframe)
559                 glClear(GL_COLOR_BUFFER_BIT);
560         else
561                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
562
563         if (sp->viewcount < 1) {
564                 sp->viewcount = sp->viewwait;
565 /*              ReshapeSuperquadrics(-1, -1);*/
566         }
567         glPushMatrix();
568         glTranslatef(0.0, 0.0, -((GLfloat) (sp->dist) / 16.0) - (sp->Mode * 3.0 - 1.0));        /* viewing transform  */
569         glRotatef(sp->rotx, 1.0, 0.0, 0.0);     /* pitch */
570         glRotatef(sp->rotz, 0.0, 0.0, 1.0);     /* bank */
571         glRotatef(sp->roty, 0.0, 1.0, 0.0);     /* "spin", like heading but comes after P & B */
572
573         SetCull(0, sp);
574
575     glScalef(0.7, 0.7, 0.7);  /* jwz: scale it down a bit */
576
577 # ifdef HAVE_MOBILE     /* Keep it the same relative size when rotated. */
578   {
579     GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
580     int o = (int) current_device_rotation();
581     if (o != 0 && o != 180 && o != -180)
582       glScalef (1/h, 1/h, 1/h);
583   }
584 # endif
585
586         polys = DoneScale(sp);
587
588         glPopMatrix();
589
590         /* Remember to flush & swap the buffers after calling this function! */
591     return polys;
592 }
593
594 static int
595 NextSuperquadricDisplay(ModeInfo *mi)
596 {
597         superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
598         NextSuperquadric(sp);
599         return DisplaySuperquadrics(mi);
600 }
601
602 #define MINSIZE 200
603 static void
604 ReshapeSuperquadrics(int w, int h)
605 {
606 #if 0
607         int         maxsize, cursize;
608
609         maxsize = (w < h) ? w : h;
610         if (maxsize <= MINSIZE) {
611                 cursize = maxsize;
612         } else {
613                 cursize = myrand(maxsize - MINSIZE) + MINSIZE;
614         }
615         if ((w > cursize) && (h > cursize)) {
616                 glViewport(myrand(w - cursize), myrand(h - cursize), cursize, cursize);
617                 w = h = cursize;
618         } else {
619                 glViewport(0, 0, w, h);
620         }
621 #else
622     int y = 0;
623
624     if (w > h * 5) {   /* tiny window: show middle */
625       h = w;
626       y = -h/2;
627     }
628
629     glViewport(0, y, w, h);
630 #endif
631
632         glMatrixMode(GL_PROJECTION);
633         glLoadIdentity();
634         gluPerspective(15.0, (GLfloat) w / (GLfloat) h, 0.1, 200.0);
635         glMatrixMode(GL_MODELVIEW);
636         glLoadIdentity();
637 }
638
639 static void
640 InitSuperquadrics(int wfmode, int snorm, int res, int count, float speed, superquadricsstruct * sp)
641 {
642         GLfloat     ambient[] =
643         {0.4, 0.4, 0.4, 1.0};
644         GLfloat     position[] =
645         {10.0, 1.0, 1.0, 10.0};
646         GLfloat     mat_diffuse[] =
647         {1.0, 0.5, 0.5, 1.0};
648         GLfloat     mat_specular[] =
649         {0.8, 0.8, 0.8, 1.0};
650         GLfloat     mat_shininess[] =
651         {50.0};
652
653         int         t;
654
655         for (t = 0; t < 4; ++t) {
656                 sp->curmat[t][0] = 0.0;
657                 sp->curmat[t][1] = 0.0;
658                 sp->curmat[t][2] = 0.0;
659                 sp->curmat[t][3] = 1.0;
660     }
661
662         sp->rotx = 35.0;
663         sp->roty = 0.0;
664         sp->rotz = 0.0;
665         sp->dist = (16 << 3);
666         sp->wireframe = sp->flatshade = sp->shownorms = 0;
667         sp->maxcount = count;
668         if (sp->maxcount < 1)
669                 sp->maxcount = 1;
670         sp->maxwait = sp->maxcount >> 1;
671         SetCull(1, sp);
672
673     sp->mono = 0;
674         sp->spinspeed = speed;
675         sp->viewcount = sp->viewwait = (sp->maxcount < 2) ? 1 : (sp->maxcount << 3);
676
677         if (res < MinRes)
678                 res = MinRes;
679         if (res > MaxRes)
680                 res = MaxRes;
681         sp->resolution = res;
682
683         if (wfmode == 2)
684                 sp->flatshade = 1;
685         else if (wfmode)
686                 sp->wireframe = 1;
687
688         if (snorm)
689                 sp->shownorms = 1;
690
691     glClearDepth(1.0);
692
693         if (sp->wireframe) {
694                 glShadeModel(GL_FLAT);
695                 glDisable(GL_LIGHTING);
696                 glColor3f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2]);
697         } else {
698                 if (sp->flatshade) {
699                         glShadeModel(GL_FLAT);
700                         position[0] = 1.0;
701                         position[3] = 0.0;
702                 }
703                 glEnable(GL_LIGHTING);
704                 glEnable(GL_LIGHT0);
705                 glDepthFunc(GL_LEQUAL);
706                 glEnable(GL_DEPTH_TEST);
707
708                 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
709                 glLightfv(GL_LIGHT0, GL_POSITION, position);
710
711                 /*glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diffuse); */
712                 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
713                 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
714
715                 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
716
717                 glFrontFace(GL_CW);
718                 glEnable(GL_NORMALIZE);
719         }
720
721         MakeUpStuff(1, sp);
722         SetCurrentShape(sp);
723         MakeUpStuff(1, sp);     /* Initialize it */
724         sp->counter = sp->maxcount;
725 }
726
727 /* End of superquadrics main functions */
728
729 ENTRYPOINT void
730 init_superquadrics(ModeInfo * mi)
731 {
732         Display    *display = MI_DISPLAY(mi);
733         Window      window = MI_WINDOW(mi);
734         int         screen = MI_SCREEN(mi);
735
736         superquadricsstruct *sp;
737
738         MI_INIT (mi, superquadrics);
739         sp = &superquadrics[screen];
740         sp->mono = (MI_IS_MONO(mi) ? 1 : 0);
741
742     sp->pats[1][1] = 1;
743     sp->pats[1][3] = 1;
744     sp->pats[2][2] = 1;
745     sp->pats[2][3] = 1;
746     sp->pats[3][1] = 1;
747     sp->pats[3][2] = 1;
748
749 /*              {0, 0, 0, 0},
750                 {0, 1, 0, 1},
751                 {0, 0, 1, 1},
752                 {0, 1, 1, 0}
753  */
754
755         if ((sp->glx_context = init_GL(mi)) != NULL) {
756
757                 InitSuperquadrics(MI_IS_WIREFRAME(mi), 0,
758                                   MI_COUNT(mi), MI_CYCLES(mi), spinspeed, sp);
759                 ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
760
761                 DisplaySuperquadrics(mi);
762                 glFinish();
763                 glXSwapBuffers(display, window);
764         } else {
765                 MI_CLEARWINDOW(mi);
766         }
767 }
768
769 ENTRYPOINT void
770 draw_superquadrics(ModeInfo * mi)
771 {
772         superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
773         Display    *display = MI_DISPLAY(mi);
774         Window      window = MI_WINDOW(mi);
775
776         if (!sp->glx_context)
777                 return;
778
779         glXMakeCurrent(display, window, *(sp->glx_context));
780
781     mi->polygon_count = NextSuperquadricDisplay(mi);
782
783     if (mi->fps_p) do_fps (mi);
784         glFinish();
785         glXSwapBuffers(display, window);
786 }
787
788 #ifndef STANDALONE
789 ENTRYPOINT void
790 refresh_superquadrics(ModeInfo * mi)
791 {
792         /* Nothing happens here */
793 }
794 #endif
795
796 ENTRYPOINT void
797 reshape_superquadrics(ModeInfo * mi, int width, int height)
798 {
799   ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
800 }
801
802
803 #endif
804
805 /* End of superquadrics.c */
806
807 XSCREENSAVER_MODULE ("Superquadrics", superquadrics)