022392c114e64bb7bd43e861b878aa7babb06f64
[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 /*-
74  * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
75  * otherwise caddr_t is not defined correctly
76  */
77
78 #include <X11/Intrinsic.h>
79
80 #ifdef STANDALONE
81 # define PROGCLASS                                      "Superquadrics"
82 # define HACK_INIT                                      init_superquadrics
83 # define HACK_DRAW                                      draw_superquadrics
84 # define superquadrics_opts                     xlockmore_opts
85 # define DEFAULTS       "*delay:                40000   \n"                     \
86                                         "*count:                25      \n"                     \
87                                         "*cycles:               40      \n"                     \
88                                         "*showFPS:      False   \n"                     \
89                                         "*wireframe:    False   \n"
90 # include "xlockmore.h"                         /* from the xscreensaver distribution */
91 #else  /* !STANDALONE */
92 # include "xlock.h"                                     /* from the xlockmore distribution */
93 #endif /* !STANDALONE */
94
95 #ifdef USE_GL
96
97 /*-
98  * Note for low-CPU-speed machines:  If your frame rate is so low that
99  * attempts at animation appear futile, try using "-cycles 1", which puts
100  * Superquadrics into kind of a slide-show mode.  It will still use up
101  * all of your CPU power, but it may look nicer.
102  */
103
104 #define DEF_SPINSPEED  "5.0"
105
106 static float spinspeed;
107
108 static XrmOptionDescRec opts[] =
109 {
110   {"-spinspeed", ".superquadrics.spinspeed", XrmoptionSepArg, (caddr_t) NULL}
111 };
112 static argtype vars[] =
113 {
114   {&spinspeed, "spinspeed", "Spinspeed", DEF_SPINSPEED, t_Float}
115 };
116 static OptionStruct desc[] =
117 {
118         {"-spinspeed num", "speed of rotation, in degrees per frame"}
119 };
120
121 ModeSpecOpt superquadrics_opts =
122 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
123
124 #ifdef USE_MODULES
125 ModStruct   superquadrics_description =
126 {"superquadrics", "init_superquadrics", "draw_superquadrics", "release_superquadrics",
127  "refresh_superquadrics", "init_superquadrics", NULL, &superquadrics_opts,
128  1000, 25, 40, 1, 4, 1.0, "",
129  "Shows 3D mathematical shapes", 0, NULL};
130
131 #endif
132
133 #include <GL/glu.h>
134
135 #define MaxRes          50
136 #define MinRes          5
137
138 typedef double dimi[MaxRes + 1];
139
140 typedef struct {
141         double      xExponent, yExponent;
142         GLfloat     r[4], g[4], b[4];
143         long        Mode;
144         int         rotx, rotz;
145 } state;
146
147 typedef struct {
148         GLXContext *glx_context;
149         int         dist, wireframe, flatshade, shownorms, maxcount, maxwait;
150         int         counter, viewcount, viewwait, mono;
151         GLfloat     curmat[4][4], rotx, roty, rotz, spinspeed;
152         /* In dimi: the first letter stands for cosine/sine, the second
153          *          stands for North, South, East, or West.  I think.
154          */
155         dimi        cs, se, sw, sn, ss, ce, cw, cn, Prevxx, Prevyy, Prevzz,
156                     Prevxn, Prevyn, Prevzn;
157         double      xExponent, yExponent, Mode;
158         int         resolution;
159         state       now, later;
160 } superquadricsstruct;
161
162 static superquadricsstruct *superquadrics = NULL;
163
164 #define CLIP_NORMALS 10000.0
165
166 static void ReshapeSuperquadrics(int w, int h);
167
168 static int
169 myrand(int range)
170 {
171         return ((int) (((float) range) * LRAND() / (MAXRAND)));
172 }
173
174 static float
175 myrandreal(void)
176 {
177         return (LRAND() / (MAXRAND));
178 }
179
180 /* Some old, old, OLD code follows.  Ahh this takes me back..... */
181
182 /* Output from p2c, the Pascal-to-C translator */
183 /* From input file "squad.pas" */
184
185 static double
186 XtoY(double x, double y)
187 {
188         double      z, a;
189
190         /* This is NOT your typical raise-X-to-the-Y-power function.  Do not attempt
191          * to replace this with a standard exponent function.  If you must, just
192          * replace the "a = exp(y * log(z));" line with something faster.
193          */
194
195         z = fabs(x);
196         if (z < 1e-20) {
197                 a = 0.0;
198                 return a;
199         }
200         a = exp(y * log(z));
201         if (a > CLIP_NORMALS)
202                 a = CLIP_NORMALS;
203         if (x < 0)
204                 a = -a;
205         return a;
206 }
207
208
209 static double
210 Sine(double x, double e)
211 {
212         /* This is just the sine wave raised to the exponent.  BUT, you can't
213          * raise negative numbers to fractional exponents.  So we have a special
214          * XtoY routune which handles it in a way useful to superquadrics.
215          */
216
217         return (XtoY(sin(x), e));
218 }
219
220
221 static double
222 Cosine(double x, double e)
223 {
224         return (XtoY(cos(x), e));
225 }
226
227
228 static void
229 MakeUpStuff(int allstuff, superquadricsstruct * sp)
230 {
231         static int  pats[4][4] =
232         {
233                 {0, 0, 0, 0},
234                 {0, 1, 0, 1},
235                 {0, 0, 1, 1},
236                 {0, 1, 1, 0}
237         };
238
239         int         dostuff;
240         int         t, pat;
241         GLfloat     r, g, b, r2, g2, b2;
242
243         /* randomize it. */
244
245         if (sp->maxcount < 2)
246                 allstuff = 1;
247         dostuff = allstuff * 15;
248         if (!dostuff) {
249                 dostuff = myrand(3) + 1;
250                 if (myrand(2) || (dostuff & 1))
251                         dostuff |= 4;
252                 if (myrand(2))
253                         dostuff |= 8;
254         }
255         if (dostuff & 1) {
256                 sp->later.xExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
257                 sp->later.yExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
258
259                 /* Increase the 2.0 .. 2.5 range to 2.0 .. 3.0 */
260                 if (sp->later.xExponent > 2.0)
261                         sp->later.xExponent = (sp->later.xExponent * 2.0) - 2.0;
262                 if (sp->later.yExponent > 2.0)
263                         sp->later.yExponent = (sp->later.yExponent * 2.0) - 2.0;
264         }
265         if (dostuff & 2) {
266                 do {
267                         sp->later.Mode = myrand(3L) + 1;
268                 } while (!allstuff && (sp->later.Mode == sp->now.Mode));
269                 /* On init: make sure it can stay in mode 1 if it feels like it. */
270         }
271         if (dostuff & 4) {
272                 if (sp->mono) {
273                         if (sp->wireframe) {
274                                 b = g = r = 1.0;
275                                 b2 = g2 = r2 = 1.0;
276                         } else {
277                                 b = g = r = (GLfloat) (140 + myrand(100)) / 255.0;
278                                 b2 = g2 = r2 = ((r > 0.69) ? (1.0 - r) : r);
279                         }
280                 } else {
281                         r = (GLfloat) (40 + myrand(200)) / 255.0;
282                         g = (GLfloat) (40 + myrand(200)) / 255.0;
283                         b = (GLfloat) (40 + myrand(200)) / 255.0;
284
285                         r2 = ((myrand(4) && ((r < 0.31) || (r > 0.69))) ? (1.0 - r) : r);
286                         g2 = ((myrand(4) && ((g < 0.31) || (g > 0.69))) ? (1.0 - g) : g);
287                         b2 = ((myrand(4) && ((b < 0.31) || (b > 0.69))) ? (1.0 - b) : b);
288                 }
289
290                 pat = myrand(4);
291                 for (t = 0; t < 4; ++t) {
292                         sp->later.r[t] = pats[pat][t] ? r : r2;
293                         sp->later.g[t] = pats[pat][t] ? g : g2;
294                         sp->later.b[t] = pats[pat][t] ? b : b2;
295                 }
296         }
297         if (dostuff & 8) {
298                 sp->later.rotx = myrand(360) - 180;
299                 sp->later.rotz = myrand(160) - 80;
300         }
301 }
302
303 static void
304 inputs(superquadricsstruct * sp)
305 {
306         int         iv;
307         double      u, v, mode3, cn3, inverter2, flatu, flatv;
308
309         if (sp->Mode < 1.000001) {
310                 mode3 = 1.0;
311                 cn3 = 0.0;
312                 inverter2 = 1.0;
313         } else if (sp->Mode < 2.000001) {
314                 mode3 = 1.0;
315                 cn3 = (sp->Mode - 1.0) * 1.5;
316                 inverter2 = (sp->Mode - 1.0) * -2.0 + 1.0;
317         } else {
318                 mode3 = (sp->Mode - 1.0);
319                 cn3 = (sp->Mode - 2.0) / 2.0 + 1.5;
320                 inverter2 = -1.0;
321         }
322
323         if (sp->flatshade) {
324                 flatu = M_PI / (sp->resolution - 1);
325                 flatv = mode3 * M_PI / ((sp->resolution - 1) * 2);
326         } else {
327                 flatu = flatv = 0.0;
328         }
329
330         /* (void) printf("Calculating....\n"); */
331         for (iv = 1; iv <= sp->resolution; iv++) {
332
333                 /* u ranges from PI down to -PI */
334                 u = (1 - iv) * 2 * M_PI / (sp->resolution - 1) + M_PI;
335
336                 /* v ranges from PI/2 down to -PI/2 */
337                 v = (1 - iv) * mode3 * M_PI / (sp->resolution - 1) + M_PI * (mode3 / 2.0);
338
339                 /* Use of xExponent */
340                 sp->se[iv] = Sine(u, sp->xExponent);
341                 sp->ce[iv] = Cosine(u, sp->xExponent);
342                 sp->sn[iv] = Sine(v, sp->yExponent);
343                 sp->cn[iv] = Cosine(v, sp->yExponent) * inverter2 + cn3;
344
345                 /* Normal vector computations only */
346                 sp->sw[iv] = Sine(u + flatu, 2 - sp->xExponent);
347                 sp->cw[iv] = Cosine(u + flatu, 2 - sp->xExponent);
348                 sp->ss[iv] = Sine(v + flatv, 2 - sp->yExponent) * inverter2;
349                 sp->cs[iv] = Cosine(v + flatv, 2 - sp->yExponent);
350         }                       /* next */
351
352         /* Now fix up the endpoints */
353         sp->se[sp->resolution] = sp->se[1];
354         sp->ce[sp->resolution] = sp->ce[1];
355
356         if (sp->Mode > 2.999999) {
357                 sp->sn[sp->resolution] = sp->sn[1];
358                 sp->cn[sp->resolution] = sp->cn[1];
359         }
360 }
361
362
363 static void
364 DoneScale(superquadricsstruct * sp)
365 {
366         double      xx, yy, zz, xp = 0, yp = 0, zp = 0, xn, yn, zn, xnp = 0,
367                     ynp = 0, znp = 0;
368         int         ih, iv;
369
370         /* Hey don't knock my 2-letter variable names.  Simon's BASIC rules, man! ;-> */
371         /* Just kidding..... */
372         int         toggle = 0;
373
374         for (ih = 1; ih <= sp->resolution; ih++) {
375                 toggle ^= 2;
376                 for (iv = 1; iv <= sp->resolution; iv++) {
377                         toggle ^= 1;
378                         if (sp->wireframe)
379                                 glColor3f(sp->curmat[toggle][0], sp->curmat[toggle][1], sp->curmat[toggle][2]);
380                         else
381                                 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sp->curmat[toggle]);
382
383                         xx = sp->cn[iv] * sp->ce[ih];
384                         zz = sp->cn[iv] * sp->se[ih];
385                         yy = sp->sn[iv];
386
387                         if (sp->wireframe) {
388                                 if ((ih > 1) || (iv > 1)) {
389                                         glBegin(GL_LINES);
390                                         if (ih > 1) {
391                                                 glVertex3f(xx, yy, zz);
392                                                 glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
393                                         }
394                                         if (iv > 1) {
395                                                 glVertex3f(xx, yy, zz);
396                                                 glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
397                                         }
398 /* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
399    * MesaGL 2.2 and -mono.  This has been fixed in MesaGL 2.3 and later. */
400                                         glEnd();
401                                 }
402                         } else {
403                                 if ((sp->cs[iv] > 1e+10) || (sp->cs[iv] < -1e+10)) {
404                                         xn = sp->cs[iv];
405                                         zn = sp->cs[iv];
406                                         yn = sp->ss[iv];
407                                 } else {
408                                         xn = sp->cs[iv] * sp->cw[ih];
409                                         zn = sp->cs[iv] * sp->sw[ih];
410                                         yn = sp->ss[iv];
411                                 }
412                                 if ((ih > 1) && (iv > 1)) {
413                                         glNormal3f(xn, yn, zn);
414                                         glBegin(GL_POLYGON);
415                                         glVertex3f(xx, yy, zz);
416                                         if (!sp->flatshade)
417                                                 glNormal3f(sp->Prevxn[iv], sp->Prevyn[iv], sp->Prevzn[iv]);
418                                         glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
419                                         if (!sp->flatshade)
420                                                 glNormal3f(xnp, ynp, znp);
421                                         glVertex3f(xp, yp, zp);
422                                         if (!sp->flatshade)
423                                                 glNormal3f(sp->Prevxn[iv - 1], sp->Prevyn[iv - 1], sp->Prevzn[iv - 1]);
424                                         glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
425                                         glEnd();
426                                 }
427                                 if (sp->shownorms) {
428                                         if (!sp->flatshade)
429                                                 glShadeModel(GL_FLAT);
430                                         glDisable(GL_LIGHTING);
431                                         glBegin(GL_LINES);
432                                         glVertex3f(xx, yy, zz);
433                                         glVertex3f(xx + xn, yy + yn, zz + zn);
434                                         glEnd();
435                                         if (!sp->flatshade)
436                                                 glShadeModel(GL_SMOOTH);
437                                         glEnable(GL_LIGHTING);
438                                 }
439                                 xnp = sp->Prevxn[iv];
440                                 ynp = sp->Prevyn[iv];
441                                 znp = sp->Prevzn[iv];
442                                 sp->Prevxn[iv] = xn;
443                                 sp->Prevyn[iv] = yn;
444                                 sp->Prevzn[iv] = zn;
445                         }
446
447                         xp = sp->Prevxx[iv];
448                         yp = sp->Prevyy[iv];
449                         zp = sp->Prevzz[iv];
450                         sp->Prevxx[iv] = xx;
451                         sp->Prevyy[iv] = yy;
452                         sp->Prevzz[iv] = zz;
453
454                 }               /* next */
455         }                       /* next */
456 }
457
458 /**** End of really old code ****/
459
460 static void
461 SetCull(int init, superquadricsstruct * sp)
462 {
463         static int  cullmode;
464
465         if (init) {
466                 cullmode = 0;
467                 return;
468         }
469         if (sp->Mode < 1.0001) {
470                 if (cullmode != 1) {
471                         glEnable(GL_CULL_FACE);
472                         glCullFace(GL_BACK);
473                         cullmode = 1;
474                 }
475         } else if (sp->Mode > 2.9999) {
476                 if (cullmode != 2) {
477                         glEnable(GL_CULL_FACE);
478                         glCullFace(GL_FRONT);
479                         cullmode = 2;
480                 }
481         } else {
482                 if (cullmode) {
483                         glDisable(GL_CULL_FACE);
484                         cullmode = 0;
485                 }
486         }
487 }
488
489 static void
490 SetCurrentShape(superquadricsstruct * sp)
491 {
492         int         t;
493
494         sp->xExponent = sp->now.xExponent = sp->later.xExponent;
495         sp->yExponent = sp->now.yExponent = sp->later.yExponent;
496
497         for (t = 0; t < 4; ++t) {
498                 sp->curmat[t][0] = sp->now.r[t] = sp->later.r[t];
499                 sp->curmat[t][1] = sp->now.g[t] = sp->later.g[t];
500                 sp->curmat[t][2] = sp->now.b[t] = sp->later.b[t];
501         }
502
503         sp->Mode = (double) (sp->now.Mode = sp->later.Mode);
504         sp->rotx = sp->now.rotx = sp->later.rotx;
505         sp->rotz = sp->now.rotz = sp->later.rotz;
506
507         sp->counter = -sp->maxwait;
508
509         inputs(sp);
510 }
511
512 static void
513 NextSuperquadric(superquadricsstruct * sp)
514 {
515         double      fnow, flater;
516         int         t;
517
518         sp->roty -= sp->spinspeed;
519         while (sp->roty >= 360.0)
520                 sp->roty -= 360.0;
521         while (sp->roty < 0.0)
522                 sp->roty += 360.0;
523
524         --sp->viewcount;
525
526         if (sp->counter > 0) {
527                 if (--sp->counter == 0) {
528                         SetCurrentShape(sp);
529                         if (sp->counter == 0) {         /* Happens if sp->maxwait == 0 */
530                                 MakeUpStuff(0, sp);
531                                 sp->counter = sp->maxcount;
532                         }
533                 } else {
534                         fnow = (double) sp->counter / (double) sp->maxcount;
535                         flater = (double) (sp->maxcount - sp->counter) / (double) sp->maxcount;
536                         sp->xExponent = sp->now.xExponent * fnow + sp->later.xExponent * flater;
537                         sp->yExponent = sp->now.yExponent * fnow + sp->later.yExponent * flater;
538
539                         for (t = 0; t < 4; ++t) {
540                                 sp->curmat[t][0] = sp->now.r[t] * fnow + sp->later.r[t] * flater;
541                                 sp->curmat[t][1] = sp->now.g[t] * fnow + sp->later.g[t] * flater;
542                                 sp->curmat[t][2] = sp->now.b[t] * fnow + sp->later.b[t] * flater;
543                         }
544
545                         sp->Mode = (double) sp->now.Mode * fnow + (double) sp->later.Mode * flater;
546                         sp->rotx = (double) sp->now.rotx * fnow + (double) sp->later.rotx * flater;
547                         sp->rotz = (double) sp->now.rotz * fnow + (double) sp->later.rotz * flater;
548
549                         inputs(sp);
550                 }
551         } else {
552                 if (++sp->counter >= 0) {
553                         MakeUpStuff(0, sp);
554                         sp->counter = sp->maxcount;
555                 }
556         }
557 }
558
559 static void
560 DisplaySuperquadrics(superquadricsstruct * sp)
561 {
562         glDrawBuffer(GL_BACK);
563         if (sp->wireframe)
564                 glClear(GL_COLOR_BUFFER_BIT);
565         else
566                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
567
568         if (sp->viewcount < 1) {
569                 sp->viewcount = sp->viewwait;
570                 ReshapeSuperquadrics(-1, -1);
571         }
572         glPushMatrix();
573         glTranslatef(0.0, 0.0, -((GLfloat) (sp->dist) / 16.0) - (sp->Mode * 3.0 - 1.0));        /* viewing transform  */
574         glRotatef(sp->rotx, 1.0, 0.0, 0.0);     /* pitch */
575         glRotatef(sp->rotz, 0.0, 0.0, 1.0);     /* bank */
576         glRotatef(sp->roty, 0.0, 1.0, 0.0);     /* "spin", like heading but comes after P & B */
577
578         SetCull(0, sp);
579
580         DoneScale(sp);
581
582         glPopMatrix();
583
584         /* Remember to flush & swap the buffers after calling this function! */
585 }
586
587 static void
588 NextSuperquadricDisplay(superquadricsstruct * sp)
589 {
590         NextSuperquadric(sp);
591         DisplaySuperquadrics(sp);
592 }
593
594 #define MINSIZE 200
595 static void
596 ReshapeSuperquadrics(int w, int h)
597 {
598         static int  last_w = 0, last_h = 0;
599         int         maxsize, cursize;
600
601         if (w < 0) {
602                 w = last_w;
603                 h = last_h;
604         } else {
605                 last_w = w;
606                 last_h = h;
607         }
608         maxsize = (w < h) ? w : h;
609         if (maxsize <= MINSIZE) {
610                 cursize = maxsize;
611         } else {
612                 cursize = myrand(maxsize - MINSIZE) + MINSIZE;
613         }
614         if ((w > cursize) && (h > cursize)) {
615                 glViewport(myrand(w - cursize), myrand(h - cursize), cursize, cursize);
616                 w = h = cursize;
617         } else {
618                 glViewport(0, 0, w, h);
619         }
620         glMatrixMode(GL_PROJECTION);
621         glLoadIdentity();
622         gluPerspective(30.0, (GLfloat) w / (GLfloat) h, 0.1, 200.0);
623         glMatrixMode(GL_MODELVIEW);
624         glLoadIdentity();
625 }
626
627 static void
628 InitSuperquadrics(int wfmode, int snorm, int res, int count, float speed, superquadricsstruct * sp)
629 {
630         GLfloat     ambient[] =
631         {0.4, 0.4, 0.4, 1.0};
632         GLfloat     position[] =
633         {10.0, 1.0, 1.0, 10.0};
634         GLfloat     mat_diffuse[] =
635         {1.0, 0.5, 0.5, 1.0};
636         GLfloat     mat_specular[] =
637         {0.8, 0.8, 0.8, 1.0};
638         GLfloat     mat_shininess[] =
639         {50.0};
640
641         int         t;
642
643         for (t = 0; t < 4; ++t)
644                 sp->curmat[t][3] = 1.0;
645
646         sp->rotx = 35.0;
647         sp->roty = 0.0;
648         sp->rotz = 0.0;
649         sp->dist = (16 << 3);
650         sp->wireframe = sp->flatshade = sp->shownorms = 0;
651         sp->maxcount = count;
652         if (sp->maxcount < 1)
653                 sp->maxcount = 1;
654         sp->maxwait = sp->maxcount >> 1;
655         SetCull(1, sp);
656
657         sp->spinspeed = speed;
658         sp->viewcount = sp->viewwait = (sp->maxcount < 2) ? 1 : (sp->maxcount << 3);
659
660         if (res < MinRes)
661                 res = MinRes;
662         if (res > MaxRes)
663                 res = MaxRes;
664         sp->resolution = res;
665
666         if (wfmode == 2)
667                 sp->flatshade = 1;
668         else if (wfmode)
669                 sp->wireframe = 1;
670
671         if (snorm)
672                 sp->shownorms = 1;
673
674         if (sp->wireframe) {
675                 glShadeModel(GL_FLAT);
676                 glDisable(GL_LIGHTING);
677                 glColor3f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2]);
678         } else {
679                 if (sp->flatshade) {
680                         glShadeModel(GL_FLAT);
681                         position[0] = 1.0;
682                         position[3] = 0.0;
683                 }
684                 glEnable(GL_LIGHTING);
685                 glEnable(GL_LIGHT0);
686                 glDepthFunc(GL_LEQUAL);
687                 glEnable(GL_DEPTH_TEST);
688
689                 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
690                 glLightfv(GL_LIGHT0, GL_POSITION, position);
691
692                 /*glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diffuse); */
693                 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
694                 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
695
696                 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
697
698                 glFrontFace(GL_CW);
699                 glEnable(GL_NORMALIZE);
700         }
701
702         MakeUpStuff(1, sp);
703         SetCurrentShape(sp);
704         MakeUpStuff(1, sp);     /* Initialize it */
705         sp->counter = sp->maxcount;
706 }
707
708 /* End of superquadrics main functions */
709
710 void
711 init_superquadrics(ModeInfo * mi)
712 {
713         Display    *display = MI_DISPLAY(mi);
714         Window      window = MI_WINDOW(mi);
715         int         screen = MI_SCREEN(mi);
716
717         superquadricsstruct *sp;
718
719         if (superquadrics == NULL) {
720                 if ((superquadrics = (superquadricsstruct *) calloc(MI_NUM_SCREENS(mi),
721                                       sizeof (superquadricsstruct))) == NULL)
722                         return;
723         }
724         sp = &superquadrics[screen];
725         sp->mono = (MI_IS_MONO(mi) ? 1 : 0);
726
727         if ((sp->glx_context = init_GL(mi)) != NULL) {
728
729                 InitSuperquadrics(MI_IS_WIREFRAME(mi), 0,
730                                   MI_COUNT(mi), MI_CYCLES(mi), spinspeed, sp);
731                 ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
732
733                 DisplaySuperquadrics(sp);
734                 glFinish();
735                 glXSwapBuffers(display, window);
736         } else {
737                 MI_CLEARWINDOW(mi);
738         }
739 }
740
741 void
742 draw_superquadrics(ModeInfo * mi)
743 {
744         superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
745         Display    *display = MI_DISPLAY(mi);
746         Window      window = MI_WINDOW(mi);
747
748         if (!sp->glx_context)
749                 return;
750
751         glXMakeCurrent(display, window, *(sp->glx_context));
752
753         NextSuperquadricDisplay(sp);
754
755     if (mi->fps_p) do_fps (mi);
756         glFinish();
757         glXSwapBuffers(display, window);
758 }
759
760 void
761 refresh_superquadrics(ModeInfo * mi)
762 {
763         /* Nothing happens here */
764 }
765
766 void
767 release_superquadrics(ModeInfo * mi)
768 {
769         if (superquadrics != NULL) {
770                 (void) free((void *) superquadrics);
771                 superquadrics = NULL;
772         }
773         FreeAllGL(mi);
774 }
775
776
777 #endif
778
779 /* End of superquadrics.c */