GENEXPLD.C

/******************************Module*Header*******************************\ 
* Module Name: genexpld.c
*
* The Explode style of the 3D Flying Objects screen saver.
*
* Simulation of a sphere that occasionally explodes.
*
* Copyright (c) 1994 Microsoft Corporation
*
\**************************************************************************/

#include <windows.h>
#include <GL\gl.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "ss3dfo.h"

#define RADIUS 0.3
#define STEPS 30
#define MAXPREC20

static MATRIX *faceMat;
static float *xstep;
static float *ystep;
static float *zstep;
static float *xrot;
static float *yrot;
static float *zrot;
static MESH explodeMesh;
static int iPrec = 10;

static BOOL bOpenGL11;

// Data type accepted by glInterleavedArrays
typedef struct _POINT_N3F_V3F {
POINT3D normal;
POINT3D vertex;
} POINT_N3F_V3F;

static POINT_N3F_V3F *pN3V3;

static GLfloat matl1Diffuse[] = {1.0f, 0.8f, 0.0f, 1.0f};
static GLfloat matl2Diffuse[] = {0.8f, 0.8f, 0.8f, 1.0f};
static GLfloat matlSpecular[] = {1.0f, 1.0f, 1.0f, 1.0f};
static GLfloat light0Pos[] = {100.0f, 100.0f, 100.0f, 0.0f};

void genExplode()
{
int i;
POINT3D circle[MAXPREC+1];
double angle;
double step = -PI / (float)(iPrec - 1);
double start = PI / 2.0;

for (i = 0, angle = start; i < iPrec; i++, angle += step) {
circle[i].x = (float) (RADIUS * cos(angle));
circle[i].y = (float) (RADIUS * sin(angle));
circle[i].z = 0.0f;
}

revolveSurface(&explodeMesh, circle, iPrec);

for (i = 0; i < explodeMesh.numFaces; i++) {
ss_matrixIdent(&faceMat[i]);
xstep[i] = (float)(((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));
ystep[i] = (float)(((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));
zstep[i] = (float)(((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));
xrot[i] = 0.0f;
yrot[i] = 0.0f;
zrot[i] = 0.0f;
}
}

void initExplodeScene()
{
iPrec = (int)(fTesselFact * 10.5);
if (iPrec < 5)
iPrec = 5;
if (iPrec > MAXPREC)
iPrec = MAXPREC;

faceMat = (MATRIX *)SaverAlloc((iPrec * iPrec) *
(4 * 4 * sizeof(float)));
xstep = SaverAlloc(iPrec * iPrec * sizeof(float));
ystep = SaverAlloc(iPrec * iPrec * sizeof(float));
zstep = SaverAlloc(iPrec * iPrec * sizeof(float));
xrot = SaverAlloc(iPrec * iPrec * sizeof(float));
yrot = SaverAlloc(iPrec * iPrec * sizeof(float));
zrot = SaverAlloc(iPrec * iPrec * sizeof(float));

genExplode();

// Find out the OpenGL version that we are running on.
bOpenGL11 = ss_fOnGL11();

// Setup the data arrays.
pN3V3 = SaverAlloc(explodeMesh.numFaces * 4 * sizeof(POINT_N3F_V3F));

// If we are running on OpenGL 1.1, use the new vertex array functions.
if (bOpenGL11) {
glInterleavedArrays(GL_N3F_V3F, 0, pN3V3);
}

glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, matl1Diffuse);
glMaterialfv(GL_FRONT, GL_SPECULAR, matlSpecular);
glMaterialf(GL_FRONT, GL_SHININESS, 100.0f);

glMaterialfv(GL_BACK, GL_AMBIENT_AND_DIFFUSE, matl2Diffuse);
glMaterialfv(GL_BACK, GL_SPECULAR, matlSpecular);
glMaterialf(GL_BACK, GL_SHININESS, 60.0f);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glFrustum(-0.33, 0.33, -0.33, 0.33, 0.3, 3.0);

glTranslatef(0.0f, 0.0f, -1.5f);
}


void delExplodeScene()
{
delMesh(&explodeMesh);

SaverFree(faceMat);
SaverFree(xstep);
SaverFree(ystep);
SaverFree(zstep);
SaverFree(xrot);
SaverFree(yrot);
SaverFree(zrot);
SaverFree(pN3V3);
}

void updateExplodeScene(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 mzrotInc = 0.0;
static float maxR;
static float r = 0.0f;
static float rotZ = 0.0f;
static int count = 0;
static int direction = 1;
static int restCount = 0;
static float lightSpin = 0.0f;
static float spinDelta = 5.0f;
static int h = 0;
static RGBA color;
int i;
MFACE *faces;
POINT_N3F_V3F *pn3v3;


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;
}

mxrot += mxrotInc;
myrot += myrotInc;
mzrot += mzrotInc;

if (bColorCycle || h == 0) {
ss_HsvToRgb((float)h, 1.0f, 1.0f, &color);

glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, (GLfloat *) &color);

h++;
h %= 360;
}

glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glRotatef(-lightSpin, 0.0f, 1.0f, 0.0f);
glLightfv(GL_LIGHT0, GL_POSITION, light0Pos);
lightSpin += spinDelta;
if ((lightSpin > 90.0) || (lightSpin < 0.0))
spinDelta = -spinDelta;
glPopMatrix();

if (!bOpenGL11) {
glBegin(GL_QUADS);
}

for(
i = 0, faces = explodeMesh.faces, pn3v3 = pN3V3;
i < explodeMesh.numFaces;
i++, faces++, pn3v3 += 4
) {
int a, b, c, d;
int j;
POINT3D vector;

ss_matrixIdent(&faceMat[i]);
ss_matrixRotate(&faceMat[i], xrot[i], yrot[i], zrot[i]);

if (restCount)
;
else {
xrot[i] += (xstep[i]);
yrot[i] += (ystep[i]);
zrot[i] += (zstep[i]);
}

a = faces->p[0];
b = faces->p[1];
c = faces->p[3];
d = faces->p[2];

memcpy(&pn3v3[0].vertex, (explodeMesh.pts + a), sizeof(POINT3D));
memcpy(&pn3v3[1].vertex, (explodeMesh.pts + b), sizeof(POINT3D));
memcpy(&pn3v3[2].vertex, (explodeMesh.pts + c), sizeof(POINT3D));
memcpy(&pn3v3[3].vertex, (explodeMesh.pts + d), sizeof(POINT3D));

vector.x = pn3v3[0].vertex.x;
vector.y = pn3v3[0].vertex.y;
vector.z = pn3v3[0].vertex.z;

for (j = 0; j < 4; j++) {
pn3v3[j].vertex.x -= vector.x;
pn3v3[j].vertex.y -= vector.y;
pn3v3[j].vertex.z -= vector.z;
ss_xformPoint((POINT3D *)&pn3v3[j].vertex, (POINT3D *)&pn3v3[j].vertex, &faceMat[i]);
pn3v3[j].vertex.x += vector.x + (vector.x * r);
pn3v3[j].vertex.y += vector.y + (vector.y * r);
pn3v3[j].vertex.z += vector.z + (vector.z * r);
}
if (bSmoothShading) {
memcpy(&pn3v3[0].normal, (explodeMesh.norms + a), sizeof(POINT3D));
memcpy(&pn3v3[1].normal, (explodeMesh.norms + b), sizeof(POINT3D));
memcpy(&pn3v3[2].normal, (explodeMesh.norms + c), sizeof(POINT3D));
memcpy(&pn3v3[3].normal, (explodeMesh.norms + d), sizeof(POINT3D));

for (j = 0; j < 4; j++)
ss_xformNorm((POINT3D *)&pn3v3[j].normal, (POINT3D *)&pn3v3[j].normal, &faceMat[i]);
} else {
memcpy(&pn3v3[0].normal, &faces->norm, sizeof(POINT3D));
ss_xformNorm((POINT3D *)&pn3v3[0].normal, (POINT3D *)&pn3v3[0].normal, &faceMat[i]);
memcpy(&pn3v3[1].normal, &pn3v3[0].normal, sizeof(POINT3D));
memcpy(&pn3v3[2].normal, &pn3v3[0].normal, sizeof(POINT3D));
memcpy(&pn3v3[3].normal, &pn3v3[0].normal, sizeof(POINT3D));
}

if (!bOpenGL11) {
if (bSmoothShading) {
glNormal3fv((GLfloat *)&pn3v3[0].normal);
glVertex3fv((GLfloat *)&pn3v3[0].vertex);
glNormal3fv((GLfloat *)&pn3v3[1].normal);
glVertex3fv((GLfloat *)&pn3v3[1].vertex);
glNormal3fv((GLfloat *)&pn3v3[2].normal);
glVertex3fv((GLfloat *)&pn3v3[2].vertex);
glNormal3fv((GLfloat *)&pn3v3[3].normal);
glVertex3fv((GLfloat *)&pn3v3[3].vertex);
} else {
glNormal3fv((GLfloat *)&pn3v3[0].normal);
glVertex3fv((GLfloat *)&pn3v3[0].vertex);
glVertex3fv((GLfloat *)&pn3v3[1].vertex);
glVertex3fv((GLfloat *)&pn3v3[2].vertex);
glVertex3fv((GLfloat *)&pn3v3[3].vertex);
}
}
}

if (bOpenGL11) {
glDrawArrays(GL_QUADS, 0, explodeMesh.numFaces * 4);
} else {
glEnd();
}

if (restCount) {
restCount--;
goto resting;
}

if (direction) {
maxR = r;
r += (float) (0.3 * pow((double)(STEPS - count) / (double)STEPS, 4.0));
} else {
r -= (float) (maxR / (double)(STEPS));
}

count++;
if (count > STEPS) {
direction ^= 1;
count = 0;

if (direction == 1) {
restCount = 10;
r = 0.0f;

for (i = 0; i < explodeMesh.numFaces; i++) {
ss_matrixIdent(&faceMat[i]);
xstep[i] = (float) (((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));
ystep[i] = (float) (((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));
zstep[i] = (float) (((float)(rand() & 0x3) * PI) / ((float)STEPS + 1.0));

xrot[i] = 0.0f;
yrot[i] = 0.0f;
zrot[i] = 0.0f;
}
}
}

resting:
;
}