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