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