summaryrefslogtreecommitdiffstats
path: root/hacks/glx/superquadrics.c
diff options
context:
space:
mode:
Diffstat (limited to 'hacks/glx/superquadrics.c')
-rw-r--r--hacks/glx/superquadrics.c807
1 files changed, 807 insertions, 0 deletions
diff --git a/hacks/glx/superquadrics.c b/hacks/glx/superquadrics.c
new file mode 100644
index 0000000..3c08335
--- /dev/null
+++ b/hacks/glx/superquadrics.c
@@ -0,0 +1,807 @@
+/* -*- Mode: C; tab-width: 4 -*- */
+/* superquadrics --- 3D mathematical shapes */
+
+#if 0
+static const char sccsid[] = "@(#)superquadrics.c 4.07 97/11/24 xlockmore";
+#endif
+
+/*-
+ * Permission to use, copy, modify, and distribute this software and its
+ * documentation for any purpose and without fee is hereby granted,
+ * provided that the above copyright notice appear in all copies and that
+ * both that copyright notice and this permission notice appear in
+ * supporting documentation.
+ *
+ * This file is provided AS IS with no warranties of any kind. The author
+ * shall have no liability with respect to the infringement of copyrights,
+ * trade secrets or any patents by this file or any part thereof. In no
+ * event will the author be liable for any lost revenue or profits or
+ * other special, indirect and consequential damages.
+ *
+ * Superquadrics were invented by Dr. Alan Barr of Caltech University.
+ * They were first published in "Computer Graphics and Applications",
+ * volume 1, number 1, 1981, in the article "Superquadrics and Angle-
+ * Preserving Transformations." Dr. Barr based the Superquadrics on
+ * Piet Hein's "super ellipses." Super ellipses are like 2D ellipses,
+ * except that the formula includes an exponent, raising its X and Y
+ * values to a (fractional) power, and allowing them to gradually
+ * change from round to square edges. Superquadrics extend this
+ * idea into 3 dimensions, using two exponents to modify a
+ * quadric surface in a similar fashion.
+ *
+ * Revision History:
+ * 30-Mar-97: Turned into a module for xlockmore 4.02 alpha. The code
+ * is almost unrecognizable now from the first revision, except for
+ * a few remaining two-letter variable names. I still don't have
+ * the normal vectors working right (I wrote the buggy normal vector
+ * code myself, can you tell?)
+ * 07-Jan-97: A legend reborn; Superquadrics make an appearance as a
+ * real OpenGL program written in C. I can even render them with
+ * proper lighting and specular highlights. Gee, they look almost
+ * as good now as the original color plates of them that my uncle
+ * showed me as a child in 1981. I don't know what computer hardware
+ * he was using at the time, but it's taken a couple decades for the
+ * PC clone hardware to catch up to it.
+ * 05-Jan-97: After almost a decade, Superquadrics had almost faded away
+ * into the myths and folklore of all the things my brother and I played
+ * with on computers when we were kids with too much time on our hands.
+ * I had since gotten involved in Unix, OpenGL, and other things.
+ * A sudden flash of inspiration caused me to dig out the old Pascal
+ * source code, run it through p2c, and start ripping away the old
+ * wireframe rendering code, to be replaced by OpenGL.
+ * Late 1989 or early 1990: Around this time I did the Turbo Pascal
+ * port of the Superquadrics. Unfortunately, many of the original variable
+ * names remained the same from the C= 64 original. This was unfortunate
+ * because BASIC on the c64 only allowed 2-letter, global variable names.
+ * But the speed improvement over BASIC was very impressive at the time.
+ * Thanksgiving, 1987: Written. My uncle Al, who invented Superquadrics some
+ * years earlier, came to visit us. I was a high school kid at the time,
+ * with nothing more than a Commodore 64. Somehow we wrote this program,
+ * (he did the math obviously, I just coded it into BASIC for the c64).
+ * Yeah, 320x200 resolution, colorless white wireframe, and half an hour
+ * rendering time per superquadric. PLOT x,y. THOSE were the days.
+ * In the following years I would port Superquadrics to AppleBASIC,
+ * AmigaBASIC, and then Turbo Pascal for IBM clones. 5 minutes on a 286!
+ * Talk about fast rendering! But these days, when my Pentium 166 runs
+ * the same program, the superquadric will already be waiting on the
+ * screen before my monitor can change frequency from text to graphics
+ * mode. Can't time the number of minutes that way! Darn ;)
+ *
+ * Ed Mackey
+ */
+
+#ifdef STANDALONE
+# define DEFAULTS "*delay: 40000 \n" \
+ "*count: 25 \n" \
+ "*cycles: 40 \n" \
+ "*showFPS: False \n" \
+ "*wireframe: False \n" \
+ "*suppressRotationAnimation: True\n" \
+
+# define free_superquadrics 0
+# define release_superquadrics 0
+# define superquadrics_handle_event 0
+# include "xlockmore.h" /* from the xscreensaver distribution */
+#else /* !STANDALONE */
+# include "xlock.h" /* from the xlockmore distribution */
+#endif /* !STANDALONE */
+
+#ifdef USE_GL
+
+/*-
+ * Note for low-CPU-speed machines: If your frame rate is so low that
+ * attempts at animation appear futile, try using "-cycles 1", which puts
+ * Superquadrics into kind of a slide-show mode. It will still use up
+ * all of your CPU power, but it may look nicer.
+ */
+
+#define DEF_SPINSPEED "5.0"
+
+static float spinspeed;
+
+static XrmOptionDescRec opts[] =
+{
+ {"-spinspeed", ".superquadrics.spinspeed", XrmoptionSepArg, 0}
+};
+static argtype vars[] =
+{
+ {&spinspeed, "spinspeed", "Spinspeed", DEF_SPINSPEED, t_Float}
+};
+static OptionStruct desc[] =
+{
+ {"-spinspeed num", "speed of rotation, in degrees per frame"}
+};
+
+ENTRYPOINT ModeSpecOpt superquadrics_opts =
+{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
+
+#ifdef USE_MODULES
+ModStruct superquadrics_description =
+{"superquadrics", "init_superquadrics", "draw_superquadrics", NULL,
+ "refresh_superquadrics", "init_superquadrics", NULL, &superquadrics_opts,
+ 1000, 25, 40, 1, 4, 1.0, "",
+ "Shows 3D mathematical shapes", 0, NULL};
+
+#endif
+
+#define MaxRes 50
+#define MinRes 5
+
+typedef double dimi[MaxRes + 1];
+
+typedef struct {
+ double xExponent, yExponent;
+ GLfloat r[4], g[4], b[4];
+ long Mode;
+ int rotx, rotz;
+} state;
+
+typedef struct {
+ GLXContext *glx_context;
+ int dist, wireframe, flatshade, shownorms, maxcount, maxwait;
+ int counter, viewcount, viewwait, mono;
+ GLfloat curmat[4][4], rotx, roty, rotz, spinspeed;
+ /* In dimi: the first letter stands for cosine/sine, the second
+ * stands for North, South, East, or West. I think.
+ */
+ dimi cs, se, sw, sn, ss, ce, cw, cn, Prevxx, Prevyy, Prevzz,
+ Prevxn, Prevyn, Prevzn;
+ double xExponent, yExponent, Mode;
+ int resolution;
+ state now, later;
+
+ int pats[4][4];
+ int cullmode;
+
+} superquadricsstruct;
+
+static superquadricsstruct *superquadrics = NULL;
+
+#define CLIP_NORMALS 10000.0
+
+static void ReshapeSuperquadrics(int w, int h);
+
+static int
+myrand(int range)
+{
+ return ((int) (((float) range) * LRAND() / (MAXRAND)));
+}
+
+static float
+myrandreal(void)
+{
+ return (LRAND() / (MAXRAND));
+}
+
+/* Some old, old, OLD code follows. Ahh this takes me back..... */
+
+/* Output from p2c, the Pascal-to-C translator */
+/* From input file "squad.pas" */
+
+static double
+XtoY(double x, double y)
+{
+ double z, a;
+
+ /* This is NOT your typical raise-X-to-the-Y-power function. Do not attempt
+ * to replace this with a standard exponent function. If you must, just
+ * replace the "a = exp(y * log(z));" line with something faster.
+ */
+
+ z = fabs(x);
+ if (z < 1e-20) {
+ a = 0.0;
+ return a;
+ }
+ a = exp(y * log(z));
+ if (a > CLIP_NORMALS)
+ a = CLIP_NORMALS;
+ if (x < 0)
+ a = -a;
+ return a;
+}
+
+
+static double
+Sine(double x, double e)
+{
+ /* This is just the sine wave raised to the exponent. BUT, you can't
+ * raise negative numbers to fractional exponents. So we have a special
+ * XtoY routune which handles it in a way useful to superquadrics.
+ */
+
+ return (XtoY(sin(x), e));
+}
+
+
+static double
+Cosine(double x, double e)
+{
+ return (XtoY(cos(x), e));
+}
+
+
+static void
+MakeUpStuff(int allstuff, superquadricsstruct * sp)
+{
+ int dostuff;
+ int t, pat;
+ GLfloat r, g, b, r2, g2, b2;
+
+ /* randomize it. */
+
+ if (sp->maxcount < 2)
+ allstuff = 1;
+ dostuff = allstuff * 15;
+ if (!dostuff) {
+ dostuff = myrand(3) + 1;
+ if (myrand(2) || (dostuff & 1))
+ dostuff |= 4;
+ if (myrand(2))
+ dostuff |= 8;
+ }
+ if (dostuff & 1) {
+ sp->later.xExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
+ sp->later.yExponent = (((long) floor(myrandreal() * 250 + 0.5)) / 100.0) + 0.1;
+
+ /* Increase the 2.0 .. 2.5 range to 2.0 .. 3.0 */
+ if (sp->later.xExponent > 2.0)
+ sp->later.xExponent = (sp->later.xExponent * 2.0) - 2.0;
+ if (sp->later.yExponent > 2.0)
+ sp->later.yExponent = (sp->later.yExponent * 2.0) - 2.0;
+ }
+ if (dostuff & 2) {
+ do {
+ sp->later.Mode = myrand(3L) + 1;
+ } while (!allstuff && (sp->later.Mode == sp->now.Mode));
+ /* On init: make sure it can stay in mode 1 if it feels like it. */
+ }
+ if (dostuff & 4) {
+ if (sp->mono) {
+ if (sp->wireframe) {
+ b = g = r = 1.0;
+ b2 = g2 = r2 = 1.0;
+ } else {
+ b = g = r = (GLfloat) (140 + myrand(100)) / 255.0;
+ b2 = g2 = r2 = ((r > 0.69) ? (1.0 - r) : r);
+ }
+ } else {
+ r = (GLfloat) (40 + myrand(200)) / 255.0;
+ g = (GLfloat) (40 + myrand(200)) / 255.0;
+ b = (GLfloat) (40 + myrand(200)) / 255.0;
+
+ r2 = ((myrand(4) && ((r < 0.31) || (r > 0.69))) ? (1.0 - r) : r);
+ g2 = ((myrand(4) && ((g < 0.31) || (g > 0.69))) ? (1.0 - g) : g);
+ b2 = ((myrand(4) && ((b < 0.31) || (b > 0.69))) ? (1.0 - b) : b);
+ }
+
+ pat = myrand(4);
+ for (t = 0; t < 4; ++t) {
+ sp->later.r[t] = sp->pats[pat][t] ? r : r2;
+ sp->later.g[t] = sp->pats[pat][t] ? g : g2;
+ sp->later.b[t] = sp->pats[pat][t] ? b : b2;
+ }
+ }
+ if (dostuff & 8) {
+ sp->later.rotx = myrand(360) - 180;
+ sp->later.rotz = myrand(160) - 80;
+ }
+}
+
+static void
+inputs(superquadricsstruct * sp)
+{
+ int iv;
+ double u, v, mode3, cn3, inverter2, flatu, flatv;
+
+ if (sp->Mode < 1.000001) {
+ mode3 = 1.0;
+ cn3 = 0.0;
+ inverter2 = 1.0;
+ } else if (sp->Mode < 2.000001) {
+ mode3 = 1.0;
+ cn3 = (sp->Mode - 1.0) * 1.5;
+ inverter2 = (sp->Mode - 1.0) * -2.0 + 1.0;
+ } else {
+ mode3 = (sp->Mode - 1.0);
+ cn3 = (sp->Mode - 2.0) / 2.0 + 1.5;
+ inverter2 = -1.0;
+ }
+
+ if (sp->flatshade) {
+ flatu = M_PI / (sp->resolution - 1);
+ flatv = mode3 * M_PI / ((sp->resolution - 1) * 2);
+ } else {
+ flatu = flatv = 0.0;
+ }
+
+ /* (void) printf("Calculating....\n"); */
+ for (iv = 1; iv <= sp->resolution; iv++) {
+
+ /* u ranges from PI down to -PI */
+ u = (1 - iv) * 2 * M_PI / (sp->resolution - 1) + M_PI;
+
+ /* v ranges from PI/2 down to -PI/2 */
+ v = (1 - iv) * mode3 * M_PI / (sp->resolution - 1) + M_PI * (mode3 / 2.0);
+
+ /* Use of xExponent */
+ sp->se[iv] = Sine(u, sp->xExponent);
+ sp->ce[iv] = Cosine(u, sp->xExponent);
+ sp->sn[iv] = Sine(v, sp->yExponent);
+ sp->cn[iv] = Cosine(v, sp->yExponent) * inverter2 + cn3;
+
+ /* Normal vector computations only */
+ sp->sw[iv] = Sine(u + flatu, 2 - sp->xExponent);
+ sp->cw[iv] = Cosine(u + flatu, 2 - sp->xExponent);
+ sp->ss[iv] = Sine(v + flatv, 2 - sp->yExponent) * inverter2;
+ sp->cs[iv] = Cosine(v + flatv, 2 - sp->yExponent);
+ } /* next */
+
+ /* Now fix up the endpoints */
+ sp->se[sp->resolution] = sp->se[1];
+ sp->ce[sp->resolution] = sp->ce[1];
+
+ if (sp->Mode > 2.999999) {
+ sp->sn[sp->resolution] = sp->sn[1];
+ sp->cn[sp->resolution] = sp->cn[1];
+ }
+}
+
+
+static int
+DoneScale(superquadricsstruct * sp)
+{
+ double xx, yy, zz, xp = 0, yp = 0, zp = 0, xn, yn, zn, xnp = 0,
+ ynp = 0, znp = 0;
+ int ih, iv;
+ int polys = 0;
+
+ /* Hey don't knock my 2-letter variable names. Simon's BASIC rules, man! ;-> */
+ /* Just kidding..... */
+ int toggle = 0;
+
+ for (ih = 1; ih <= sp->resolution; ih++) {
+ toggle ^= 2;
+ for (iv = 1; iv <= sp->resolution; iv++) {
+ toggle ^= 1;
+ if (sp->wireframe)
+ glColor3f(sp->curmat[toggle][0], sp->curmat[toggle][1], sp->curmat[toggle][2]);
+ else
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, sp->curmat[toggle]);
+
+ xx = sp->cn[iv] * sp->ce[ih];
+ zz = sp->cn[iv] * sp->se[ih];
+ yy = sp->sn[iv];
+
+ if (sp->wireframe) {
+ if ((ih > 1) || (iv > 1)) {
+ glBegin(GL_LINES);
+ if (ih > 1) {
+ glVertex3f(xx, yy, zz);
+ glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
+ polys++;
+ }
+ if (iv > 1) {
+ glVertex3f(xx, yy, zz);
+ glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
+ polys++;
+ }
+/* PURIFY 4.0.1 reports an unitialized memory read on the next line when using
+ * MesaGL 2.2 and -mono. This has been fixed in MesaGL 2.3 and later. */
+ glEnd();
+ }
+ } else {
+ if ((sp->cs[iv] > 1e+10) || (sp->cs[iv] < -1e+10)) {
+ xn = sp->cs[iv];
+ zn = sp->cs[iv];
+ yn = sp->ss[iv];
+ } else {
+ xn = sp->cs[iv] * sp->cw[ih];
+ zn = sp->cs[iv] * sp->sw[ih];
+ yn = sp->ss[iv];
+ }
+ if ((ih > 1) && (iv > 1)) {
+ glNormal3f(xn, yn, zn);
+ glBegin(GL_POLYGON);
+ glVertex3f(xx, yy, zz);
+ if (!sp->flatshade)
+ glNormal3f(sp->Prevxn[iv], sp->Prevyn[iv], sp->Prevzn[iv]);
+ glVertex3f(sp->Prevxx[iv], sp->Prevyy[iv], sp->Prevzz[iv]);
+ if (!sp->flatshade)
+ glNormal3f(xnp, ynp, znp);
+ glVertex3f(xp, yp, zp);
+ if (!sp->flatshade)
+ glNormal3f(sp->Prevxn[iv - 1], sp->Prevyn[iv - 1], sp->Prevzn[iv - 1]);
+ glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
+ polys++;
+ glEnd();
+ }
+ if (sp->shownorms) {
+ if (!sp->flatshade)
+ glShadeModel(GL_FLAT);
+ glDisable(GL_LIGHTING);
+ glBegin(GL_LINES);
+ glVertex3f(xx, yy, zz);
+ glVertex3f(xx + xn, yy + yn, zz + zn);
+ polys++;
+ glEnd();
+ if (!sp->flatshade)
+ glShadeModel(GL_SMOOTH);
+ glEnable(GL_LIGHTING);
+ }
+ xnp = sp->Prevxn[iv];
+ ynp = sp->Prevyn[iv];
+ znp = sp->Prevzn[iv];
+ sp->Prevxn[iv] = xn;
+ sp->Prevyn[iv] = yn;
+ sp->Prevzn[iv] = zn;
+ }
+
+ xp = sp->Prevxx[iv];
+ yp = sp->Prevyy[iv];
+ zp = sp->Prevzz[iv];
+ sp->Prevxx[iv] = xx;
+ sp->Prevyy[iv] = yy;
+ sp->Prevzz[iv] = zz;
+
+ } /* next */
+ } /* next */
+ return polys;
+}
+
+/**** End of really old code ****/
+
+static void
+SetCull(int init, superquadricsstruct * sp)
+{
+ if (init) {
+ glDisable(GL_CULL_FACE);
+ sp->cullmode = 0;
+ return;
+ }
+ if (sp->Mode < 1.0001) {
+ if (sp->cullmode != 1) {
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+ sp->cullmode = 1;
+ }
+ } else if (sp->Mode > 2.9999) {
+ if (sp->cullmode != 2) {
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_FRONT);
+ sp->cullmode = 2;
+ }
+ } else {
+ if (sp->cullmode) {
+ glDisable(GL_CULL_FACE);
+ sp->cullmode = 0;
+ }
+ }
+}
+
+static void
+SetCurrentShape(superquadricsstruct * sp)
+{
+ int t;
+
+ sp->xExponent = sp->now.xExponent = sp->later.xExponent;
+ sp->yExponent = sp->now.yExponent = sp->later.yExponent;
+
+ for (t = 0; t < 4; ++t) {
+ sp->curmat[t][0] = sp->now.r[t] = sp->later.r[t];
+ sp->curmat[t][1] = sp->now.g[t] = sp->later.g[t];
+ sp->curmat[t][2] = sp->now.b[t] = sp->later.b[t];
+ }
+
+ sp->Mode = (double) (sp->now.Mode = sp->later.Mode);
+ sp->rotx = sp->now.rotx = sp->later.rotx;
+ sp->rotz = sp->now.rotz = sp->later.rotz;
+
+ sp->counter = -sp->maxwait;
+
+ inputs(sp);
+}
+
+static void
+NextSuperquadric(superquadricsstruct * sp)
+{
+ double fnow, flater;
+ int t;
+
+ sp->roty -= sp->spinspeed;
+ while (sp->roty >= 360.0)
+ sp->roty -= 360.0;
+ while (sp->roty < 0.0)
+ sp->roty += 360.0;
+
+ --sp->viewcount;
+
+ if (sp->counter > 0) {
+ if (--sp->counter == 0) {
+ SetCurrentShape(sp);
+ if (sp->counter == 0) { /* Happens if sp->maxwait == 0 */
+ MakeUpStuff(0, sp);
+ sp->counter = sp->maxcount;
+ }
+ } else {
+ fnow = (double) sp->counter / (double) sp->maxcount;
+ flater = (double) (sp->maxcount - sp->counter) / (double) sp->maxcount;
+ sp->xExponent = sp->now.xExponent * fnow + sp->later.xExponent * flater;
+ sp->yExponent = sp->now.yExponent * fnow + sp->later.yExponent * flater;
+
+ for (t = 0; t < 4; ++t) {
+ sp->curmat[t][0] = sp->now.r[t] * fnow + sp->later.r[t] * flater;
+ sp->curmat[t][1] = sp->now.g[t] * fnow + sp->later.g[t] * flater;
+ sp->curmat[t][2] = sp->now.b[t] * fnow + sp->later.b[t] * flater;
+ }
+
+ sp->Mode = (double) sp->now.Mode * fnow + (double) sp->later.Mode * flater;
+ sp->rotx = (double) sp->now.rotx * fnow + (double) sp->later.rotx * flater;
+ sp->rotz = (double) sp->now.rotz * fnow + (double) sp->later.rotz * flater;
+
+ inputs(sp);
+ }
+ } else {
+ if (++sp->counter >= 0) {
+ MakeUpStuff(0, sp);
+ sp->counter = sp->maxcount;
+ }
+ }
+}
+
+static int
+DisplaySuperquadrics(ModeInfo *mi)
+{
+ superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
+ int polys = 0;
+ glDrawBuffer(GL_BACK);
+ if (sp->wireframe)
+ glClear(GL_COLOR_BUFFER_BIT);
+ else
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ if (sp->viewcount < 1) {
+ sp->viewcount = sp->viewwait;
+/* ReshapeSuperquadrics(-1, -1);*/
+ }
+ glPushMatrix();
+ glTranslatef(0.0, 0.0, -((GLfloat) (sp->dist) / 16.0) - (sp->Mode * 3.0 - 1.0)); /* viewing transform */
+ glRotatef(sp->rotx, 1.0, 0.0, 0.0); /* pitch */
+ glRotatef(sp->rotz, 0.0, 0.0, 1.0); /* bank */
+ glRotatef(sp->roty, 0.0, 1.0, 0.0); /* "spin", like heading but comes after P & B */
+
+ SetCull(0, sp);
+
+ glScalef(0.7, 0.7, 0.7); /* jwz: scale it down a bit */
+
+# ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
+ {
+ GLfloat h = MI_HEIGHT(mi) / (GLfloat) MI_WIDTH(mi);
+ int o = (int) current_device_rotation();
+ if (o != 0 && o != 180 && o != -180)
+ glScalef (1/h, 1/h, 1/h);
+ }
+# endif
+
+ polys = DoneScale(sp);
+
+ glPopMatrix();
+
+ /* Remember to flush & swap the buffers after calling this function! */
+ return polys;
+}
+
+static int
+NextSuperquadricDisplay(ModeInfo *mi)
+{
+ superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
+ NextSuperquadric(sp);
+ return DisplaySuperquadrics(mi);
+}
+
+#define MINSIZE 200
+static void
+ReshapeSuperquadrics(int w, int h)
+{
+#if 0
+ int maxsize, cursize;
+
+ maxsize = (w < h) ? w : h;
+ if (maxsize <= MINSIZE) {
+ cursize = maxsize;
+ } else {
+ cursize = myrand(maxsize - MINSIZE) + MINSIZE;
+ }
+ if ((w > cursize) && (h > cursize)) {
+ glViewport(myrand(w - cursize), myrand(h - cursize), cursize, cursize);
+ w = h = cursize;
+ } else {
+ glViewport(0, 0, w, h);
+ }
+#else
+ int y = 0;
+
+ if (w > h * 5) { /* tiny window: show middle */
+ h = w;
+ y = -h/2;
+ }
+
+ glViewport(0, y, w, h);
+#endif
+
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ gluPerspective(15.0, (GLfloat) w / (GLfloat) h, 0.1, 200.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+}
+
+static void
+InitSuperquadrics(int wfmode, int snorm, int res, int count, float speed, superquadricsstruct * sp)
+{
+ GLfloat ambient[] =
+ {0.4, 0.4, 0.4, 1.0};
+ GLfloat position[] =
+ {10.0, 1.0, 1.0, 10.0};
+ GLfloat mat_diffuse[] =
+ {1.0, 0.5, 0.5, 1.0};
+ GLfloat mat_specular[] =
+ {0.8, 0.8, 0.8, 1.0};
+ GLfloat mat_shininess[] =
+ {50.0};
+
+ int t;
+
+ for (t = 0; t < 4; ++t) {
+ sp->curmat[t][0] = 0.0;
+ sp->curmat[t][1] = 0.0;
+ sp->curmat[t][2] = 0.0;
+ sp->curmat[t][3] = 1.0;
+ }
+
+ sp->rotx = 35.0;
+ sp->roty = 0.0;
+ sp->rotz = 0.0;
+ sp->dist = (16 << 3);
+ sp->wireframe = sp->flatshade = sp->shownorms = 0;
+ sp->maxcount = count;
+ if (sp->maxcount < 1)
+ sp->maxcount = 1;
+ sp->maxwait = sp->maxcount >> 1;
+ SetCull(1, sp);
+
+ sp->mono = 0;
+ sp->spinspeed = speed;
+ sp->viewcount = sp->viewwait = (sp->maxcount < 2) ? 1 : (sp->maxcount << 3);
+
+ if (res < MinRes)
+ res = MinRes;
+ if (res > MaxRes)
+ res = MaxRes;
+ sp->resolution = res;
+
+ if (wfmode == 2)
+ sp->flatshade = 1;
+ else if (wfmode)
+ sp->wireframe = 1;
+
+ if (snorm)
+ sp->shownorms = 1;
+
+ glClearDepth(1.0);
+
+ if (sp->wireframe) {
+ glShadeModel(GL_FLAT);
+ glDisable(GL_LIGHTING);
+ glColor3f(mat_diffuse[0], mat_diffuse[1], mat_diffuse[2]);
+ } else {
+ if (sp->flatshade) {
+ glShadeModel(GL_FLAT);
+ position[0] = 1.0;
+ position[3] = 0.0;
+ }
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glDepthFunc(GL_LEQUAL);
+ glEnable(GL_DEPTH_TEST);
+
+ glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);
+ glLightfv(GL_LIGHT0, GL_POSITION, position);
+
+ /*glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, mat_diffuse); */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+ glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
+
+ glFrontFace(GL_CW);
+ glEnable(GL_NORMALIZE);
+ }
+
+ MakeUpStuff(1, sp);
+ SetCurrentShape(sp);
+ MakeUpStuff(1, sp); /* Initialize it */
+ sp->counter = sp->maxcount;
+}
+
+/* End of superquadrics main functions */
+
+ENTRYPOINT void
+init_superquadrics(ModeInfo * mi)
+{
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+ int screen = MI_SCREEN(mi);
+
+ superquadricsstruct *sp;
+
+ MI_INIT (mi, superquadrics);
+ sp = &superquadrics[screen];
+ sp->mono = (MI_IS_MONO(mi) ? 1 : 0);
+
+ sp->pats[1][1] = 1;
+ sp->pats[1][3] = 1;
+ sp->pats[2][2] = 1;
+ sp->pats[2][3] = 1;
+ sp->pats[3][1] = 1;
+ sp->pats[3][2] = 1;
+
+/* {0, 0, 0, 0},
+ {0, 1, 0, 1},
+ {0, 0, 1, 1},
+ {0, 1, 1, 0}
+ */
+
+ if ((sp->glx_context = init_GL(mi)) != NULL) {
+
+ InitSuperquadrics(MI_IS_WIREFRAME(mi), 0,
+ MI_COUNT(mi), MI_CYCLES(mi), spinspeed, sp);
+ ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
+
+ DisplaySuperquadrics(mi);
+ glFinish();
+ glXSwapBuffers(display, window);
+ } else {
+ MI_CLEARWINDOW(mi);
+ }
+}
+
+ENTRYPOINT void
+draw_superquadrics(ModeInfo * mi)
+{
+ superquadricsstruct *sp = &superquadrics[MI_SCREEN(mi)];
+ Display *display = MI_DISPLAY(mi);
+ Window window = MI_WINDOW(mi);
+
+ if (!sp->glx_context)
+ return;
+
+ glXMakeCurrent(display, window, *(sp->glx_context));
+
+ mi->polygon_count = NextSuperquadricDisplay(mi);
+
+ if (mi->fps_p) do_fps (mi);
+ glFinish();
+ glXSwapBuffers(display, window);
+}
+
+#ifndef STANDALONE
+ENTRYPOINT void
+refresh_superquadrics(ModeInfo * mi)
+{
+ /* Nothing happens here */
+}
+#endif
+
+ENTRYPOINT void
+reshape_superquadrics(ModeInfo * mi, int width, int height)
+{
+ ReshapeSuperquadrics(MI_WIDTH(mi), MI_HEIGHT(mi));
+}
+
+
+#endif
+
+/* End of superquadrics.c */
+
+XSCREENSAVER_MODULE ("Superquadrics", superquadrics)