/******************************Module*Header*******************************\ * Module Name: mesh.c * * Surface of revolution support routines. Adapted from OttoB's screen saver * code. * * Created: 14-May-1994 17:40:51 * * Copyright (c) 1994 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include "mesh.h" #include "globals.h" /******************************Public*Routine******************************\ * newMesh * * Allocate memory for the mesh structure to accomodate the specified number * of points and faces. * * numAxial is the number of tiers (or rings) in the surface of revolution * (can be thought of as the number of faces "high" in the axial direction. * * numCircum is the number of faces around the circumference. * * In other words, if the surface of revolution were unrolled, the dimensions * of the mesh would by numAxial by numCircum. * * History: * 14-May-1994 -by- Gilman Wong [gilmanw] * Taken from OttoB's screen saver utility code. \**************************************************************************/ BOOL newMesh(MESH *mesh, int numAxial, int numCircum) { int nFaces = numAxial * numCircum; int nPts = 4 * nFaces; mesh->numFaces = 0; mesh->numPoints = 0; mesh->numFacesAxial = numAxial; mesh->numFacesCircum = numCircum; if (nPts) { mesh->pts = LocalAlloc(LMEM_FIXED, (LONG)nPts * (LONG)sizeof(POINT3D)); mesh->norms = LocalAlloc(LMEM_FIXED, (LONG)nPts * (LONG)sizeof(POINT3D)); } mesh->faces = LocalAlloc(LMEM_FIXED, (LONG)nFaces * (LONG)sizeof(MFACE)); // Did all the memory get allocated? if ( (!nPts || (mesh->pts && mesh->norms)) && mesh->faces ) return TRUE; else { if (nPts) { if (mesh->pts) LocalFree(mesh->pts); if (mesh->norms) LocalFree(mesh->norms); } if (mesh->faces) LocalFree(mesh->faces); return FALSE; } } /******************************Public*Routine******************************\ * delMesh * * Delete the allocated portions of the MESH structure. * * History: * 14-May-1994 -by- Gilman Wong [gilmanw] * Taken from OttoB's screen saver utility code. \**************************************************************************/ void delMesh(MESH *mesh) { LocalFree(mesh->pts); LocalFree(mesh->norms); LocalFree(mesh->faces); } /******************************Public*Routine******************************\ * iPtInList * * Add a vertex and its normal to the mesh. If the vertex already exists, * add in the normal to the existing normal (we want the average normal * at the vertex). * * History: * 14-May-1994 -by- Gilman Wong [gilmanw] * Taken from OttoB's screen saver utility code. \**************************************************************************/ static int iPtInList(MESH *mesh, POINT3D *p, POINT3D *norm, int start) { int i; POINT3D *pts = mesh->pts + start; for (i = start; i < mesh->numPoints; i++, pts++) { //if ((pts->x == p->x) && (pts->y == p->y) && (pts->z == p->z)) { if ( fabs(pts->x - p->x) < ZERO_EPS && fabs(pts->y - p->y) < ZERO_EPS && fabs(pts->z - p->z) < ZERO_EPS ) { mesh->norms[i].x += norm->x; mesh->norms[i].y += norm->y; mesh->norms[i].z += norm->z; return i; } } mesh->pts[i] = *p; mesh->norms[i] = *norm; mesh->numPoints++; return i; } /******************************Public*Routine******************************\ * revolveSurface * * Takes the set of points in curve and fills the mesh structure with a * surface of revolution. The surface consists of quads made up of the * points in curve rotated about the y-axis. The number of increments * in the revolution is determined by the steps parameter. * * Returns: * TRUE if successful, FALSE otherwise. * * History: * 14-May-1994 -by- Gilman Wong [gilmanw] * Taken from OttoB's screen saver utility code. \**************************************************************************/ BOOL revolveSurface(MESH *mesh, CURVE *curve, int steps) { BOOL bRet = FALSE; int i; int j; int facecount = 0; double rotation = 0.0; double rotInc; double cosVal; double sinVal; POINT3D norm; POINT3D *a = (POINT3D *) NULL; POINT3D *b = (POINT3D *) NULL; // Allocate temp memory for curve points rotated about y-axis. a = (POINT3D *) LocalAlloc(LMEM_FIXED, 2*curve->numPoints*sizeof(POINT3D)); if (!a) goto revolveSurface_cleanup; b = a + curve->numPoints; // Rotation increment. //rotInc = (2.0 * PI) / (double)(steps - 1); rotInc = (2.0 * PI) / (double) steps; // Allocate mesh structure. if (!newMesh(mesh, (curve->numPoints - 1), steps)) goto revolveSurface_cleanup; // Rotate the curve in increments of rotInc. for (j = 0; j < steps; j++, rotation += rotInc) { // Compute the quads at the current rotation. To do this, we need to // compute the curve at rotation and rotation+rotInc. cosVal = cos(rotation); sinVal = sin(rotation); for (i = 0; i < curve->numPoints; i++) { a[i].x = (float) (curve->pts[i].x * cosVal + curve->pts[i].z * sinVal); a[i].y = (float) (curve->pts[i].y); a[i].z = (float) (curve->pts[i].z * cosVal - curve->pts[i].x * sinVal); } cosVal = cos(rotation + rotInc); sinVal = sin(rotation + rotInc); for (i = 0; i < curve->numPoints; i++) { b[i].x = (float) (curve->pts[i].x * cosVal + curve->pts[i].z * sinVal); b[i].y = (float) (curve->pts[i].y); b[i].z = (float) (curve->pts[i].z * cosVal - curve->pts[i].x * sinVal); } for (i = 0; i < (curve->numPoints - 1); i++) { calcNorm(&norm, &b[i + 1], &b[i], &a[i]); if ((norm.x * norm.x) + (norm.y * norm.y) + (norm.z * norm.z) < 0.9) calcNorm(&norm, &a[i], &a[i+1], &b[i + 1]); mesh->faces[facecount].material = j & 7; mesh->faces[facecount].norm = norm; mesh->faces[facecount].p[0] = iPtInList(mesh, &b[i], &norm, 0); mesh->faces[facecount].p[1] = iPtInList(mesh, &a[i], &norm, 0); mesh->faces[facecount].p[2] = iPtInList(mesh, &b[i + 1], &norm, 0); mesh->faces[facecount].p[3] = iPtInList(mesh, &a[i + 1], &norm, 0); mesh->numFaces++; facecount++; } } normalizeNorms(mesh->norms, mesh->numPoints); bRet = TRUE; revolveSurface_cleanup: if (a) LocalFree(a); return bRet; } void updateObject(MESH *mesh, BOOL bSmooth) { int i, j; int cnt; int a, b, c, d; int aOffs, bOffs, cOffs, dOffs; MFACE *faces; POINT3D *pp; POINT3D *pn; MATERIAL *pmatl; int lastC, lastD; pp = mesh->pts; pn = mesh->norms; glBegin(GL_QUAD_STRIP); for (i = 0, faces = mesh->faces, lastC = faces->p[0], lastD = faces->p[1]; i < mesh->numFaces; i++, faces++) { a = faces->p[0]; b = faces->p[1]; if (!bSmooth) { if ((a != lastC) || (b != lastD)) { glNormal3fv((GLfloat *)&(faces - 1)->norm); glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2))); glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2))); glEnd(); glBegin(GL_QUAD_STRIP); } glNormal3fv((GLfloat *)&faces->norm); glVertex3fv((GLfloat *)((char *)pp + (a << 3) + (a << 2))); glVertex3fv((GLfloat *)((char *)pp + (b << 3) + (b << 2))); } else { if ((a != lastC) || (b != lastD)) { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); glNormal3fv((GLfloat *)((char *)pn + cOffs)); glVertex3fv((GLfloat *)((char *)pp + cOffs)); glNormal3fv((GLfloat *)((char *)pn + dOffs)); glVertex3fv((GLfloat *)((char *)pp + dOffs)); glEnd(); glBegin(GL_QUAD_STRIP); } aOffs = (a << 3) + (a << 2); bOffs = (b << 3) + (b << 2); glNormal3fv((GLfloat *)((char *)pn + aOffs)); glVertex3fv((GLfloat *)((char *)pp + aOffs)); glNormal3fv((GLfloat *)((char *)pn + bOffs)); glVertex3fv((GLfloat *)((char *)pp + bOffs)); } lastC = faces->p[2]; lastD = faces->p[3]; } if (!bSmooth) { glNormal3fv((GLfloat *)&(faces - 1)->norm); glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2))); glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2))); } else { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); glNormal3fv((GLfloat *)((char *)pn + cOffs)); glVertex3fv((GLfloat *)((char *)pp + cOffs)); glNormal3fv((GLfloat *)((char *)pn + dOffs)); glVertex3fv((GLfloat *)((char *)pp + dOffs)); } glEnd(); } void MakeList(GLuint listID, MESH *mesh) { int i, j; int cnt; int a, b, c, d; int aOffs, bOffs, cOffs, dOffs; MFACE *faces; BOOL bSmooth; POINT3D *pp; POINT3D *pn; MATERIAL *pmatl; GLint shadeModel; int lastC, lastD; //glGetIntegerv(GL_SHADE_MODEL, &shadeModel); //bSmooth = (shadeModel == GL_SMOOTH); bSmooth = (gShadeMode == SHADE_SMOOTH_BOTH); if (bSmooth) MakeListAxial(listID, mesh); glNewList(listID, GL_COMPILE); pp = mesh->pts; pn = mesh->norms; glBegin(GL_QUAD_STRIP); for (i = 0; i < mesh->numFacesAxial; i++) { for (j = 0, faces = &mesh->faces[i], lastC = faces->p[1], lastD = faces->p[3]; j < mesh->numFacesCircum; j++, faces += mesh->numFacesAxial) { a = faces->p[1]; b = faces->p[3]; if (!bSmooth) { if ((a != lastC) || (b != lastD)) { //glNormal3fv((GLfloat *)&((faces - 1)->norm)); glNormal3fv((GLfloat *)&(mesh->faces[i].norm)); glVertex3fv((GLfloat *) &pp[lastC]); glVertex3fv((GLfloat *) &pp[lastD]); //glVertex3fv((GLfloat *)((char *)pp + // (lastC << 3) + (lastC << 2))); //glVertex3fv((GLfloat *)((char *)pp + // (lastD << 3) + (lastD << 2))); glEnd(); glBegin(GL_QUAD_STRIP); } glNormal3fv((GLfloat *)&faces->norm); glVertex3fv((GLfloat *) &pp[a]); glVertex3fv((GLfloat *) &pp[b]); //glVertex3fv((GLfloat *)((char *)pp + (a << 3) + (a << 2))); //glVertex3fv((GLfloat *)((char *)pp + (b << 3) + (b << 2))); } else { if ((a != lastC) || (b != lastD)) { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); glNormal3fv((GLfloat *) &pn[lastC]); glVertex3fv((GLfloat *) &pp[lastC]); glNormal3fv((GLfloat *) &pn[lastD]); glVertex3fv((GLfloat *) &pp[lastD]); //glNormal3fv((GLfloat *)((char *)pn + cOffs)); //glVertex3fv((GLfloat *)((char *)pp + cOffs)); //glNormal3fv((GLfloat *)((char *)pn + dOffs)); //glVertex3fv((GLfloat *)((char *)pp + dOffs)); glEnd(); glBegin(GL_QUAD_STRIP); } aOffs = (a << 3) + (a << 2); bOffs = (b << 3) + (b << 2); glNormal3fv((GLfloat *) &pn[a]); glVertex3fv((GLfloat *) &pp[a]); glNormal3fv((GLfloat *) &pn[b]); glVertex3fv((GLfloat *) &pp[b]); //glNormal3fv((GLfloat *)((char *)pn + aOffs)); //glVertex3fv((GLfloat *)((char *)pp + aOffs)); //glNormal3fv((GLfloat *)((char *)pn + bOffs)); //glVertex3fv((GLfloat *)((char *)pp + bOffs)); } lastC = faces->p[0]; lastD = faces->p[2]; } if (!bSmooth) { glNormal3fv((GLfloat *)&(mesh->faces[i].norm)); glVertex3fv((GLfloat *) &pp[lastC]); glVertex3fv((GLfloat *) &pp[lastD]); //glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2))); //glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2))); } else { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); glNormal3fv((GLfloat *) &pn[lastC]); glVertex3fv((GLfloat *) &pp[lastC]); glNormal3fv((GLfloat *) &pn[lastD]); glVertex3fv((GLfloat *) &pp[lastD]); //glNormal3fv((GLfloat *)((char *)pn + cOffs)); //glVertex3fv((GLfloat *)((char *)pp + cOffs)); //glNormal3fv((GLfloat *)((char *)pn + dOffs)); //glVertex3fv((GLfloat *)((char *)pp + dOffs)); } } glEnd(); glEndList(); } // This version builds the strip along the axial direction. void MakeListAxial(GLuint listID, MESH *mesh) { int i, j; int cnt; int a, b, c, d; int aOffs, bOffs, cOffs, dOffs; MFACE *faces; BOOL bSmooth; POINT3D *pp; POINT3D *pn; MATERIAL *pmatl; GLint shadeModel; int lastC, lastD; glGetIntegerv(GL_SHADE_MODEL, &shadeModel); bSmooth = (shadeModel == GL_SMOOTH); glNewList(listID, GL_COMPILE); pp = mesh->pts; pn = mesh->norms; glBegin(GL_QUAD_STRIP); for (i = 0, faces = mesh->faces, lastC = faces->p[0], lastD = faces->p[1]; i < mesh->numFaces; i++, faces++) { a = faces->p[0]; b = faces->p[1]; if (!bSmooth) { if ((a != lastC) || (b != lastD)) { glNormal3fv((GLfloat *)&((faces - 1)->norm)); glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2))); glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2))); glEnd(); glBegin(GL_QUAD_STRIP); } glNormal3fv((GLfloat *)&faces->norm); //glVertex3fv((GLfloat *) &pp[a]); //glVertex3fv((GLfloat *) &pp[b]); glVertex3fv((GLfloat *)((char *)pp + (a << 3) + (a << 2))); glVertex3fv((GLfloat *)((char *)pp + (b << 3) + (b << 2))); } else { if ((a != lastC) || (b != lastD)) { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); //glNormal3fv((GLfloat *) &pn[c]); //glVertex3fv((GLfloat *) &pp[c]); //glNormal3fv((GLfloat *) &pn[d]); //glVertex3fv((GLfloat *) &pp[d]); glNormal3fv((GLfloat *)((char *)pn + cOffs)); glVertex3fv((GLfloat *)((char *)pp + cOffs)); glNormal3fv((GLfloat *)((char *)pn + dOffs)); glVertex3fv((GLfloat *)((char *)pp + dOffs)); glEnd(); glBegin(GL_QUAD_STRIP); } aOffs = (a << 3) + (a << 2); bOffs = (b << 3) + (b << 2); //glNormal3fv((GLfloat *) &pn[a]); //glVertex3fv((GLfloat *) &pp[a]); //glNormal3fv((GLfloat *) &pn[b]); //glVertex3fv((GLfloat *) &pp[b]); glNormal3fv((GLfloat *)((char *)pn + aOffs)); glVertex3fv((GLfloat *)((char *)pp + aOffs)); glNormal3fv((GLfloat *)((char *)pn + bOffs)); glVertex3fv((GLfloat *)((char *)pp + bOffs)); } lastC = faces->p[2]; lastD = faces->p[3]; } if (!bSmooth) { glNormal3fv((GLfloat *)&((faces - 1)->norm)); glVertex3fv((GLfloat *)((char *)pp + (lastC << 3) + (lastC << 2))); glVertex3fv((GLfloat *)((char *)pp + (lastD << 3) + (lastD << 2))); } else { cOffs = (lastC << 3) + (lastC << 2); dOffs = (lastD << 3) + (lastD << 2); glNormal3fv((GLfloat *)((char *)pn + cOffs)); glVertex3fv((GLfloat *)((char *)pp + cOffs)); glNormal3fv((GLfloat *)((char *)pn + dOffs)); glVertex3fv((GLfloat *)((char *)pp + dOffs)); } glEnd(); glEndList(); }