/******************************Module*Header*******************************\
* Module Name: genlem.c
*
* The Twist style of the 3D Flying Objects screen saver.
*
* Solid model of a 3D lemniscate.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/
#include <stdlib.h>
#include <windows.h>
#include <GL\gl.h>
#include <string.h>
#include <math.h>
#include "ss3dfo.h"
#include "mesh.h"
#define ROT_PREC 10
#define NORMS(x, y) lemMesh.norms[((x) * iPrec) + y]
#define GRID(x, y) lemMesh.pts[((x) * iPrec) + y]
static MESH lemMesh;
static POINT3D basis[ROT_PREC];
static double zrot = 0.2;
static int iPrec = 32;
static double *lemX;
static double *lemY;
static double *lemXT;
static double *lemYT;
static void getLem(double index, double max, double *angle, double *r)
{
double a, sina;
a = (index * PI) / (max - 1.0);
if (a >= PI)
a -= PI;
if (a > PI / 2.0) {
*angle = (2.0 * PI) - a;
sina = sin( 2.0 * *angle );
if( sina < 0.0 )
sina = 0.0; // protect against sqrt fpe
*r = 0.5 * sqrt(sina);
} else {
*angle = a;
sina = sin( 2.0 * *angle );
if( sina < 0.0 )
sina = 0.0;
*r = 0.5 * sqrt(sina);
}
}
static void initLemCoords(int iMax)
{
int i;
double max = (double)iMax;
double angle;
double r;
for (i = 0; i < iMax; i++) {
getLem((double)i, (double)iPrec, &angle, &r);
lemX[i] = r * cos(angle);
lemY[i] = r * sin(angle);
getLem((double)i + 0.00001, (double)iPrec, &angle, &r);
lemXT[i] = r * cos(angle);
lemYT[i] = r * sin(angle);
}
}
void genLemniscate(void)
{
int i;
int j;
double posInc = 2.0 / (float)iPrec;
int facecount = 0;
int ptcount = 0;
POINT3D norm;
static float twistFact = 0.0f;
static float twistFactAdd = 0.05f;
POINT3D a[ROT_PREC];
POINT3D b[ROT_PREC];
MATRIX matrix;
MESH *mesh = &lemMesh;
mesh->numPoints = 0;
mesh->numFaces = 0;
for (i = 0; i < (iPrec - 1) * (ROT_PREC - 1); i++)
mesh->norms[i] = ss_ptZero;
for (i = 0; i < (iPrec - 1); i++) {
double x1, y1, x2, y2;
double len;
double sinAngle;
double rotZ;
int id[4];
x1 = lemX[i];
y1 = lemY[i];
x2 = lemXT[i];
y2 = lemYT[i];
x2 -= x1;
y2 -= y1;
len = sqrt(x2 * x2 + y2 * y2);
if (len > 0.0)
sinAngle = y2 / len;
else
sinAngle = 0.0;
if (y2 < 0.0)
sinAngle = -sinAngle;
rotZ = asin(sinAngle);
if (x2 < 0.0)
rotZ = PI - rotZ;
if (y2 < 0.0)
rotZ = -rotZ;
if (rotZ < 0.0)
rotZ = 2.0 * PI + rotZ;
ss_matrixIdent(&matrix);
ss_matrixRotate(&matrix, 0.0, 0.0, -rotZ);
ss_matrixTranslate(&matrix, x1, y1,
twistFact * cos((2.0 * PI * (float)i) / ((float)iPrec - 1)));
for (j = 0; j < ROT_PREC; j++)
ss_xformPoint(&a[j], &basis[j], &matrix);
x1 = lemX[i+1];
y1 = lemY[i+1];
x2 = lemXT[i+1];
y2 = lemYT[i+1];
x2 -= x1;
y2 -= y1;
len = sqrt(x2 * x2 + y2 * y2);
if (len > 0.0)
sinAngle = y2 / len;
else
sinAngle = 0.0;
if (y2 < 0.0)
sinAngle = -sinAngle;
rotZ = asin(sinAngle);
if (x2 < 0.0)
rotZ = PI - rotZ;
if (y2 < 0.0)
rotZ = -rotZ;
if (rotZ < 0.0)
rotZ = 2.0 * PI + rotZ;
ss_matrixIdent(&matrix);
ss_matrixRotate(&matrix, 0.0, 0.0, -rotZ);
ss_matrixTranslate(&matrix, x1, y1,
twistFact * cos((2.0 * PI * ((float)i + 1.0)) / ((float)iPrec - 1)));
for (j = 0; j < ROT_PREC; j++)
ss_xformPoint(&b[j], &basis[j], &matrix);
memcpy(&mesh->pts[ptcount], &a, sizeof(POINT3D) * (ROT_PREC - 1));
ptcount += (ROT_PREC - 1);
mesh->numPoints += (ROT_PREC - 1);
for (j = 0; j < (ROT_PREC - 1); j++) {
int k;
int jj;
if (j == (ROT_PREC - 2))
jj = 0;
else
jj = j + 1;
ss_calcNorm(&norm, &b[j + 1], &b[j], &a[j]);
mesh->faces[facecount].material = 3;
mesh->faces[facecount].norm = norm;
if (i == iPrec - 2) {
id[0] = mesh->faces[facecount].p[0] = j;
id[1] = mesh->faces[facecount].p[1] = jj;
} else {
id[0] = mesh->faces[facecount].p[0] = ptcount + j;
id[1] = mesh->faces[facecount].p[1] = ptcount + jj;
}
id[2] = mesh->faces[facecount].p[2] = ptcount - (ROT_PREC - 1) + j;
id[3] = mesh->faces[facecount].p[3] = ptcount - (ROT_PREC - 1) + jj;
for (k = 0; k < 4; k++) {
POINT3D *pn = &mesh->norms[id[k]];
pn->x += norm.x;
pn->y += norm.y;
pn->z += norm.z;
}
mesh->numFaces++;
facecount++;
}
}
ss_normalizeNorms(lemMesh.norms, lemMesh.numPoints);
if (twistFact >= 1.0f)
twistFactAdd = -0.01f;
else if (twistFact <= -1.0f)
twistFactAdd = 0.01f;
twistFact += twistFactAdd;
}
void initLemScene()
{
int i;
RGBA lightAmbient = {0.0f, 0.0f, 0.0f, 1.0f};
iPrec = (int)(fTesselFact * 32.5);
if (iPrec < 5)
iPrec = 5;
lemX = SaverAlloc(sizeof(double) * iPrec);
lemY = SaverAlloc(sizeof(double) * iPrec);
lemXT = SaverAlloc(sizeof(double) * iPrec);
lemYT = SaverAlloc(sizeof(double) * iPrec);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.5, 1.5, -1.5, 1.5, 0.0, 3.0);
glTranslatef(0.0f, 0.0f, -1.5f);
newMesh(&lemMesh, (ROT_PREC - 1) * (iPrec - 1) ,
(ROT_PREC - 1) * (iPrec - 1));
for (i = 0; i < ROT_PREC; i++) {
basis[i].x = 0.0f;
basis[i].y = (float) (0.15 * cos((i * 2.0 * PI) / (ROT_PREC - 1.0)));
basis[i].z = (float) (0.15 * sin((i * 2.0 * PI) / (ROT_PREC - 1.0)));
}
initLemCoords(iPrec);
glFrontFace(GL_CW);
glEnable(GL_CULL_FACE);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, (GLfloat *) &lightAmbient);
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE,
(GLfloat *) &Material[3].kd);
}
void delLemScene()
{
delMesh(&lemMesh);
SaverFree(lemX);
SaverFree(lemY);
SaverFree(lemXT);
SaverFree(lemYT);
}
void updateLemScene(int flags)
{
static double mxrot = 0.0;
static double myrot = 0.0;
static double mzrot = 0.0;
static double mxrotInc = 0.0;
static double myrotInc = 0.1;
static double zrotInc = 0.1;
static double mzrotInc = 0.0;
static int h = 0;
RGBA color;
MATRIX model;
mxrot += mxrotInc;
myrot += myrotInc;
mzrot += mzrotInc;
if( gbBounce ) {
// floating window bounced off an edge
if (mxrotInc) {
mxrotInc = 0.0;
myrotInc = 0.1;
} else if (myrotInc) {
myrotInc = 0.0;
mzrotInc = 0.1;
} else if (mzrotInc) {
mzrotInc = 0.0;
mxrotInc = 0.1;
}
gbBounce = FALSE;
}
zrot += zrotInc;
if (zrot >= PI / 4.0) {
zrot = PI / 4.0;
zrotInc = -0.03;
} else if (zrot <= -PI / 4.0) {
zrot = -PI / 4.0;
zrotInc = 0.03;
}
genLemniscate();
if (bColorCycle) {
ss_HsvToRgb((float)h, 1.0f, 1.0f, &color );
glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &color);
h++;
h %= 360;
}
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1.5, 1.5, -1.5, 1.5, 0.0, 3.0);
glTranslatef(0.0f, 0.0f, -1.5f);
glRotatef((GLfloat) (zrot * (180.0 / PI)), 0.0f, 1.0f, 0.0f);
glRotatef(50.0f, 1.0f, 0.0f, 0.0f);
glRotatef(50.0f, 0.0f, 0.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, -0.5f, 0.0f);
glRotatef((GLfloat) (mxrot * (180.0 / PI)), 1.0f, 0.0f, 0.0f);
glRotatef((GLfloat) (myrot * (180.0 / PI)), 0.0f, 1.0f, 0.0f);
glRotatef((GLfloat) (mzrot * (180.0 / PI)), 0.0f, 0.0f, 1.0f);
ss_matrixIdent(&model);
ss_matrixRotate(&model, mxrot, myrot, mzrot);
ss_matrixTranslate(&model, 0.0, -0.5, 0.0);
updateObject(&lemMesh, bSmoothShading);
}