792 lines
21 KiB
C
792 lines
21 KiB
C
|
/* -*- Mode: C; tab-width: 4 -*- */
|
||
|
/* superquadrics --- 3D mathematical shapes */
|
||
|
|
||
|
#if !defined( lint ) && !defined( SABER )
|
||
|
static const char sccsid[] = "@(#)superquadrics.c 5.01 2001/03/01 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:
|
||
|
* 01-Mar-2001: Added FPS stuff - Eric Lassauge <lassauge AT users.sourceforge.net>
|
||
|
* 01-Nov-2000: Allocation checks
|
||
|
* 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 VMS
|
||
|
/*-
|
||
|
* due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
|
||
|
* otherwise caddr_t is not defined correctly
|
||
|
*/
|
||
|
|
||
|
#include <X11/Intrinsic.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef STANDALONE
|
||
|
# define MODE_superquadrics
|
||
|
# define PROGCLASS "Superquadrics"
|
||
|
# define HACK_INIT init_superquadrics
|
||
|
# define HACK_DRAW draw_superquadrics
|
||
|
# define superquadrics_opts xlockmore_opts
|
||
|
# define DEFAULTS "*delay: 40000 \n" \
|
||
|
"*count: 25 \n" \
|
||
|
"*cycles: 40 \n" \
|
||
|
"*showfps: False \n" \
|
||
|
"*wireframe: False \n"
|
||
|
# include "xlockmore.h" /* from the xscreensaver distribution */
|
||
|
#else /* !STANDALONE */
|
||
|
# include "xlock.h" /* from the xlockmore distribution */
|
||
|
# include "visgl.h"
|
||
|
#endif /* !STANDALONE */
|
||
|
|
||
|
#ifdef MODE_superquadrics
|
||
|
|
||
|
/*-
|
||
|
* 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[] =
|
||
|
{
|
||
|
{(char *) "-spinspeed",(char *) ".superquadrics.spinspeed", XrmoptionSepArg, (caddr_t) NULL}
|
||
|
};
|
||
|
static argtype vars[] =
|
||
|
{
|
||
|
{(void *) & spinspeed, (char *) "spinspeed", (char *) "Spinspeed", (char *)DEF_SPINSPEED, t_Float}
|
||
|
};
|
||
|
static OptionStruct desc[] =
|
||
|
{
|
||
|
{(char *) "-spinspeed num", (char *) "speed of rotation, in degrees per frame"}
|
||
|
};
|
||
|
|
||
|
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", "release_superquadrics",
|
||
|
"refresh_superquadrics", "init_superquadrics", (char *) NULL, &superquadrics_opts,
|
||
|
40000, 25, 40, 1, 4, 1.0, "",
|
||
|
"Shows 3D mathematical shapes", 0, NULL};
|
||
|
|
||
|
#endif
|
||
|
|
||
|
#include <GL/glu.h>
|
||
|
|
||
|
#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;
|
||
|
} superquadricsstruct;
|
||
|
|
||
|
static superquadricsstruct *superquadrics = (superquadricsstruct *) 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)
|
||
|
{
|
||
|
static int pats[4][4] =
|
||
|
{
|
||
|
{0, 0, 0, 0},
|
||
|
{0, 1, 0, 1},
|
||
|
{0, 0, 1, 1},
|
||
|
{0, 1, 1, 0}
|
||
|
};
|
||
|
|
||
|
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] = pats[pat][t] ? r : r2;
|
||
|
sp->later.g[t] = pats[pat][t] ? g : g2;
|
||
|
sp->later.b[t] = 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 void
|
||
|
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;
|
||
|
|
||
|
/* 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]);
|
||
|
}
|
||
|
if (iv > 1) {
|
||
|
glVertex3f(xx, yy, zz);
|
||
|
glVertex3f(sp->Prevxx[iv - 1], sp->Prevyy[iv - 1], sp->Prevzz[iv - 1]);
|
||
|
}
|
||
|
/* 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]);
|
||
|
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);
|
||
|
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 */
|
||
|
}
|
||
|
|
||
|
/**** End of really old code ****/
|
||
|
|
||
|
static void
|
||
|
SetCull(int init, superquadricsstruct * sp)
|
||
|
{
|
||
|
static int cullmode;
|
||
|
|
||
|
if (init) {
|
||
|
cullmode = 0;
|
||
|
return;
|
||
|
}
|
||
|
if (sp->Mode < 1.0001) {
|
||
|
if (cullmode != 1) {
|
||
|
glEnable(GL_CULL_FACE);
|
||
|
glCullFace(GL_BACK);
|
||
|
cullmode = 1;
|
||
|
}
|
||
|
} else if (sp->Mode > 2.9999) {
|
||
|
if (cullmode != 2) {
|
||
|
glEnable(GL_CULL_FACE);
|
||
|
glCullFace(GL_FRONT);
|
||
|
cullmode = 2;
|
||
|
}
|
||
|
} else {
|
||
|
if (cullmode) {
|
||
|
glDisable(GL_CULL_FACE);
|
||
|
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 void
|
||
|
DisplaySuperquadrics(superquadricsstruct * sp)
|
||
|
{
|
||
|
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);
|
||
|
|
||
|
DoneScale(sp);
|
||
|
|
||
|
glPopMatrix();
|
||
|
|
||
|
/* Remember to flush & swap the buffers after calling this function! */
|
||
|
}
|
||
|
|
||
|
static void
|
||
|
NextSuperquadricDisplay(superquadricsstruct * sp)
|
||
|
{
|
||
|
NextSuperquadric(sp);
|
||
|
DisplaySuperquadrics(sp);
|
||
|
}
|
||
|
|
||
|
#define MINSIZE 200
|
||
|
static void
|
||
|
ReshapeSuperquadrics(int w, int h)
|
||
|
{
|
||
|
static int last_w = 0, last_h = 0;
|
||
|
int maxsize, cursize;
|
||
|
|
||
|
if (w < 0) {
|
||
|
w = last_w;
|
||
|
h = last_h;
|
||
|
} else {
|
||
|
last_w = w;
|
||
|
last_h = h;
|
||
|
}
|
||
|
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);
|
||
|
}
|
||
|
glMatrixMode(GL_PROJECTION);
|
||
|
glLoadIdentity();
|
||
|
gluPerspective(30.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][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->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;
|
||
|
|
||
|
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 */
|
||
|
|
||
|
void
|
||
|
init_superquadrics(ModeInfo * mi)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
int screen = MI_SCREEN(mi);
|
||
|
|
||
|
superquadricsstruct *sp;
|
||
|
|
||
|
if (superquadrics == NULL) {
|
||
|
if ((superquadrics = (superquadricsstruct *) calloc(MI_NUM_SCREENS(mi),
|
||
|
sizeof (superquadricsstruct))) == NULL)
|
||
|
return;
|
||
|
}
|
||
|
sp = &superquadrics[screen];
|
||
|
sp->mono = (MI_IS_MONO(mi) ? 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(sp);
|
||
|
glFinish();
|
||
|
glXSwapBuffers(display, window);
|
||
|
} else {
|
||
|
MI_CLEARWINDOW(mi);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
draw_superquadrics(ModeInfo * mi)
|
||
|
{
|
||
|
Display *display = MI_DISPLAY(mi);
|
||
|
Window window = MI_WINDOW(mi);
|
||
|
superquadricsstruct *sp;
|
||
|
|
||
|
if (superquadrics == NULL)
|
||
|
return;
|
||
|
sp = &superquadrics[MI_SCREEN(mi)];
|
||
|
|
||
|
MI_IS_DRAWN(mi) = True;
|
||
|
if (!sp->glx_context)
|
||
|
return;
|
||
|
|
||
|
glXMakeCurrent(display, window, *(sp->glx_context));
|
||
|
|
||
|
NextSuperquadricDisplay(sp);
|
||
|
|
||
|
if (MI_IS_FPS(mi)) do_fps (mi);
|
||
|
glFinish();
|
||
|
glXSwapBuffers(display, window);
|
||
|
}
|
||
|
|
||
|
void
|
||
|
refresh_superquadrics(ModeInfo * mi)
|
||
|
{
|
||
|
/* Nothing happens here */
|
||
|
}
|
||
|
|
||
|
void
|
||
|
release_superquadrics(ModeInfo * mi)
|
||
|
{
|
||
|
if (superquadrics != NULL) {
|
||
|
free(superquadrics);
|
||
|
superquadrics = (superquadricsstruct *) NULL;
|
||
|
}
|
||
|
FreeAllGL(mi);
|
||
|
}
|
||
|
|
||
|
|
||
|
#endif
|
||
|
|
||
|
/* End of superquadrics.c */
|