#include #include #include #include #include #include #include #include #include #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 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 Reshape(GLsizei w, GLsizei h) { glViewport(0, 0, w, h); } void Keyd(void) { fDisplayList = !fDisplayList; ResetTotals(); } void 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; } else if (!strcmp(*argv, "-nodlist")) { fDisplayList = FALSE; } } 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); }