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