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