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