VASPHERE.C

#include <stdlib.h> 
#include <stdio.h>
#include <math.h>
#include <string.h>
#include <time.h>

#include <windows.h>
#include <gl\gl.h>
#include <gl\glu.h>
#include <gl\glaux.h>

#define PI ((float)3.14159265358979323846)

#define WIDTH 512
#define HEIGHT 512

#define COMPUTE_SPHERE_VERTICES(rings, sections) \
(((rings)+1)*(sections)+2)
#define COMPUTE_SPHERE_TRIANGLES(rings, sections) \
(((rings)+1)*(sections)*2)
#define RINGS 50
#define SECTIONS 50
#define SVERTICES COMPUTE_SPHERE_VERTICES(RINGS, SECTIONS)
#define STRIANGLES COMPUTE_SPHERE_TRIANGLES(RINGS, SECTIONS)

#define RGB_COLOR(red, green, blue) \
(((DWORD)(BYTE)(red) << 0) | \
((DWORD)(BYTE)(green) << 8) | \
((DWORD)(BYTE)(blue) << 16))

#define FRANDOM(x) (((float)rand() / RAND_MAX) * (x))

#define DROT 10.0f

#define NLISTS 3

typedef struct
{
float fX, fY, fZ;
float fNx, fNy, fNz;
DWORD dwColor;
} VERTEX;

typedef struct
{
int iV1;
int iV2;
int iV3;
} TRIANGLE;

typedef struct _SPHERE
{
GLfloat fXr, fYr, fZr;
GLfloat fDXr, fDYr, fDZr;
} SPHERE;

SPHERE sphere;

BOOL fSingle = FALSE;
BOOL fDisplayList = TRUE;

int iCurrentType = 0;
GLint dlLists[NLISTS];
char *pszListType[NLISTS] =
{
"Vertex Array", "Direct Triangles", "Direct Strips"
};

void DrawVertexArray(void);
void DrawTriangles(void);
void DrawStrips(void);
void (*pfnDraw[NLISTS])(void) =
{
DrawVertexArray, DrawTriangles, DrawStrips
};

VERTEX vtxSphere[SVERTICES];
TRIANGLE triSphere[STRIANGLES];

void *Malloc(size_t cb)
{
void *pv;

pv = malloc(cb);
if (pv == NULL)
{
printf("Unable to alloc %d bytes\n", cb);
exit(1);
}
return pv;
}

void GenerateSphere(float fRadius, int iRings, int iSections,
VERTEX *pvtx, TRIANGLE *ptri)
{
float fTheta, fPhi; /* Angles used to sweep around sphere */
float fDTheta, fDPhi; /* Angle between each section and ring */
float fX, fY, fZ, fV, fRSinTheta; /* Temporary variables */
int i, j, n, m; /* counters */
int iVert, iTri; /* Internal vertex and triangle count */

iTri = COMPUTE_SPHERE_TRIANGLES(iRings, iSections);
iVert = COMPUTE_SPHERE_VERTICES(iRings, iSections);

/*
* Generate vertices at the top and bottom points.
*/
pvtx[0].fX = 0.0f;
pvtx[0].fY = fRadius;
pvtx[0].fZ = 0.0f;
pvtx[0].fNx = 0.0f;
pvtx[0].fNy = 1.0f;
pvtx[0].fNz = 0.0f;
pvtx[0].dwColor = RGB_COLOR(0, 0, 255);
pvtx[iVert - 1].fX = 0.0f;
pvtx[iVert - 1].fY = -fRadius;
pvtx[iVert - 1].fZ = 0.0f;
pvtx[iVert - 1].fNx = 0.0f;
pvtx[iVert - 1].fNy = -1.0f;
pvtx[iVert - 1].fNz = 0.0f;
pvtx[iVert - 1].dwColor = RGB_COLOR(0, 255, 0);

/*
* Generate vertex points for rings
*/
fDTheta = PI / (float) (iRings + 2);
fDPhi = 2.0f * PI / (float) iSections;
n = 1; /* vertex being generated, begins at 1 to skip top point */
fTheta = fDTheta;

for (i = 0; i <= iRings; i++)
{
fY = (float)(fRadius * cos(fTheta)); /* y is the same for each ring */
fV = fTheta / PI; /* v is the same for each ring */
fRSinTheta = (float)(fRadius * sin(fTheta));
fPhi = 0.0f;

for (j = 0; j < iSections; j++)
{
fX = (float)(fRSinTheta * sin(fPhi));
fZ = (float)(fRSinTheta * cos(fPhi));
pvtx[n].fX = fX;
pvtx[n].fZ = fZ;
pvtx[n].fY = fY;
pvtx[n].fNx = fX / fRadius;
pvtx[n].fNy = fY / fRadius;
pvtx[n].fNz = fZ / fRadius;
if (n & 1)
{
pvtx[n].dwColor = RGB_COLOR(0, 0, 255);
}
else
{
pvtx[n].dwColor = RGB_COLOR(0, 255, 0);
}
fPhi += fDPhi;
n++;
}

fTheta += fDTheta;
}

/*
* Generate triangles for top and bottom caps.
*/
for (i = 0; i < iSections; i++)
{
ptri[i].iV1 = 0;
ptri[i].iV2 = i + 1;
ptri[i].iV3 = 1 + ((i + 1) % iSections);
ptri[iTri - iSections + i].iV1 = iVert - 1;
ptri[iTri - iSections + i].iV2 = iVert - 2 - i;
ptri[iTri - iSections + i].iV3 = iVert - 2 - ((1 + i) % iSections);
}

/*
* Generate triangles for the rings
*/
m = 1; /* first vertex in current ring,begins at 1 to skip top point*/
n = iSections; /* triangle being generated, skip the top cap */

for (i = 0; i < iRings; i++)
{
for (j = 0; j < iSections; j++)
{
ptri[n].iV1 = m + j;
ptri[n].iV2 = m + iSections + j;
ptri[n].iV3 = m + iSections + ((j + 1) % iSections);
ptri[n + 1].iV1 = ptri[n].iV1;
ptri[n + 1].iV2 = ptri[n].iV3;
ptri[n + 1].iV3 = m + ((j + 1) % iSections);
n += 2;
}

m += iSections;
}
}

void InitSphere(void)
{
GenerateSphere(1.0f, RINGS, SECTIONS, vtxSphere, triSphere);

glVertexPointer(3, GL_FLOAT, sizeof(VERTEX), &vtxSphere[0].fX);
glNormalPointer(GL_FLOAT, sizeof(VERTEX), &vtxSphere[0].fNx);
glColorPointer(3, GL_UNSIGNED_BYTE, sizeof(VERTEX), &vtxSphere[0].dwColor);

srand(time(NULL));
sphere.fXr = 0.0f;
sphere.fYr = 0.0f;
sphere.fZr = 0.0f;
sphere.fDXr = DROT - FRANDOM(2 * DROT);
sphere.fDYr = DROT - FRANDOM(2 * DROT);
sphere.fDZr = DROT - FRANDOM(2 * DROT);
}

void UpdateSphere(void)
{
sphere.fXr += sphere.fDXr;
sphere.fYr += sphere.fDYr;
sphere.fZr += sphere.fDZr;
}

void DrawVertexArray(void)
{
glDrawElements(GL_TRIANGLES, STRIANGLES*3, GL_UNSIGNED_INT, triSphere);
}

void Vertex(int iVert)
{
VERTEX *pvtx;

pvtx = &vtxSphere[iVert];
glColor3ubv((GLubyte *)&pvtx->dwColor);
glNormal3fv(&pvtx->fNx);
glVertex3fv(&pvtx->fX);
}

void DrawTriangles(void)
{
int iVert, *pidx;

glBegin(GL_TRIANGLES);
pidx = (int *)&triSphere[0];
for (iVert = 0; iVert < STRIANGLES*3; iVert++)
{
Vertex(*pidx++);
}
glEnd();
}

void DrawStrips(void)
{
int iIdxBase;
int iRing, iSection;

// Triangle fans for top and bottom caps
glBegin(GL_TRIANGLE_FAN);

Vertex(0);
iIdxBase = 1;
for (iSection = 0; iSection <= SECTIONS; iSection++)
{
Vertex(iIdxBase+(iSection % SECTIONS));
}

glEnd();

glBegin(GL_TRIANGLE_FAN);

Vertex(SVERTICES-1);
iIdxBase = SVERTICES-SECTIONS-1;
for (iSection = SECTIONS; iSection >= 0 ; iSection--)
{
Vertex(iIdxBase+(iSection % SECTIONS));
}

glEnd();

// Triangle strips for each ring
iIdxBase = 1;
for (iRing = 0; iRing < RINGS; iRing++)
{
glBegin(GL_TRIANGLE_STRIP);

for (iSection = 0; iSection <= SECTIONS; iSection++)
{
Vertex(iIdxBase+(iSection % SECTIONS));
Vertex(iIdxBase+(iSection % SECTIONS)+SECTIONS);
}

glEnd();

iIdxBase += SECTIONS;
}
}

void Init(void)
{
float fv4[4];
int iv1[1];
int i;
GLint dlBase;

InitSphere();

fv4[0] = 0.05f;
fv4[1] = 0.05f;
fv4[2] = 0.05f;
fv4[3] = 1.0f;
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, fv4);

fv4[0] = 0.0f;
fv4[1] = 1.0f;
fv4[2] = 1.0f;
fv4[3] = 0.0f;
glLightfv(GL_LIGHT0, GL_POSITION, fv4);
fv4[0] = 0.9f;
fv4[1] = 0.9f;
fv4[2] = 0.9f;
fv4[3] = 1.0f;
glLightfv(GL_LIGHT0, GL_DIFFUSE, fv4);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHTING);

fv4[0] = 0.6f;
fv4[1] = 0.6f;
fv4[2] = 0.6f;
fv4[3] = 1.0f;
glMaterialfv(GL_FRONT, GL_SPECULAR, fv4);
iv1[0] = 40;
glMaterialiv(GL_FRONT, GL_SHININESS, iv1);

glEnable(GL_CULL_FACE);

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);

glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
glEnable(GL_COLOR_MATERIAL);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45, 1, .01, 15);
gluLookAt(0, 0, 10, 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW);

dlBase = glGenLists(NLISTS);
for (i = 0; i < NLISTS; i++)
{
dlLists[i] = dlBase+i;
glNewList(dlLists[i], GL_COMPILE);
pfnDraw[i]();
glEndList();
}
}

DWORD dwTotalMillis = 0;
int iTotalTriangles = 0;

void ResetTotals(void)
{
dwTotalMillis = 0;
iTotalTriangles = 0;
}

void CALLBACK Redraw(void)
{
DWORD dwMillis;
char szMsg[80];

dwMillis = GetTickCount();

glClear(GL_COLOR_BUFFER_BIT);

glLoadIdentity();
glRotatef(sphere.fXr, 1.0f, 0.0f, 0.0f);
glRotatef(sphere.fYr, 0.0f, 1.0f, 0.0f);
glRotatef(sphere.fZr, 0.0f, 0.0f, 1.0f);

if (fDisplayList)
{
glCallList(dlLists[iCurrentType]);
}
else
{
pfnDraw[iCurrentType]();
}

UpdateSphere();

if (fSingle)
{
glFlush();
}
else
{
auxSwapBuffers();
}

dwMillis = GetTickCount()-dwMillis;

dwTotalMillis += dwMillis;
iTotalTriangles += STRIANGLES;

if (dwTotalMillis > 1000)
{
sprintf(szMsg, "%s%s: %.3lf tri/sec",
fDisplayList ? "Display List " : "",
pszListType[iCurrentType],
(double)iTotalTriangles*1000.0/dwTotalMillis);
SetWindowText(auxGetHWND(), szMsg);

ResetTotals();
}
}

void CALLBACK Reshape(GLsizei w, GLsizei h)
{
glViewport(0, 0, w, h);
}

void CALLBACK Keyd(void)
{
fDisplayList = !fDisplayList;
ResetTotals();
}

void CALLBACK KeySPACE(void)
{
iCurrentType = (iCurrentType+1) % NLISTS;
ResetTotals();
}

void _CRTAPI1 main(int argc, char **argv)
{
GLenum eMode;

while (--argc > 0)
{
argv++;

if (!strcmp(*argv, "-sb"))
{
fSingle = TRUE;
}
}

auxInitPosition(10, 10, WIDTH, HEIGHT);
eMode = AUX_RGB;
if (!fSingle)
{
eMode |= AUX_DOUBLE;
}
auxInitDisplayMode(eMode);
auxInitWindow("Vertex Array/Direct Comparison");

auxReshapeFunc(Reshape);
auxIdleFunc(Redraw);

auxKeyFunc(AUX_d, Keyd);
auxKeyFunc(AUX_SPACE, KeySPACE);

Init();
auxMainLoop(Redraw);
}