/******************************Module*Header*******************************\ * Module Name: mesh.c * * Routines to create a mesh representation of a 3D object and to turn it * into an OpenGL description. * * Copyright (c) 1994 Microsoft Corporation * \**************************************************************************/ #include #include #include #include #include #include #include "D3DSaver.h" #include "FlyingObjects.h" #include "mesh.h" #define ZERO_EPS 0.00000001 /******************************Public*Routine******************************\ * newMesh * * Allocate memory for the mesh structure to accomodate the specified number * of points and faces. * \**************************************************************************/ BOOL newMesh(MESH *mesh, int numFaces, int numPts) { mesh->numFaces = 0; mesh->numPoints = 0; if (numPts) { mesh->pts = (POINT3D*)SaverAlloc((LONG)numPts * (LONG)sizeof(POINT3D)); if( mesh->pts == NULL ) return FALSE; mesh->norms = (POINT3D*)SaverAlloc((LONG)numPts * (LONG)sizeof(POINT3D)); if( mesh->norms == NULL ) return FALSE; } mesh->faces = (MFACE*)SaverAlloc((LONG)numFaces * (LONG)sizeof(MFACE)); if (mesh->faces == NULL ) return FALSE; return TRUE; } /******************************Public*Routine******************************\ * delMesh * * Delete the allocated portions of the MESH structure. * \**************************************************************************/ void delMesh(MESH *mesh) { SaverFree(mesh->pts); SaverFree(mesh->norms); SaverFree(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 to accumulate the average * normal at each vertex). Normalization of the normals is the * responsibility of the caller. * \**************************************************************************/ 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 the vertices are within ZERO_EPS of each other, then its the same // vertex. 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. * \**************************************************************************/ #define MAXPREC 40 void revolveSurface(MESH *mesh, POINT3D *curve, int steps) { int i; int j; int facecount = 0; double rotation = 0.0; double rotInc; double cosVal; double sinVal; int stepsSqr; POINT3D norm; POINT3D a[MAXPREC + 1]; POINT3D b[MAXPREC + 1]; if (steps > MAXPREC) steps = MAXPREC; rotInc = (2.0 * PI) / (double)(steps - 1); stepsSqr = steps * steps; newMesh(mesh, stepsSqr, 4 * stepsSqr); for (j = 0; j < steps; j++, rotation += rotInc) { cosVal = cos(rotation); sinVal = sin(rotation); for (i = 0; i < steps; i++) { a[i].x = (float) (curve[i].x * cosVal + curve[i].z * sinVal); a[i].y = (float) (curve[i].y); a[i].z = (float) (curve[i].z * cosVal - curve[i].x * sinVal); } cosVal = cos(rotation + rotInc); sinVal = sin(rotation + rotInc); for (i = 0; i < steps; i++) { b[i].x = (float) (curve[i].x * cosVal + curve[i].z * sinVal); b[i].y = (float) (curve[i].y); b[i].z = (float) (curve[i].z * cosVal - curve[i].x * sinVal); } for (i = 0; i < (steps - 1); i++) { ss_calcNorm(&norm, &b[i + 1], &b[i], &a[i]); if ((norm.x * norm.x) + (norm.y * norm.y) + (norm.z * norm.z) < 0.9) ss_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++; } } ss_normalizeNorms(mesh->norms, mesh->numPoints); } HRESULT RenderMesh3( MESH* pMesh, BOOL bSmooth ) { HRESULT hr; INT numPrims = 0; INT numIndices = 0; INT numVertices = 0; WORD iVertexA, iVertexB, iVertexC, iVertexD; INT a,b,c,d; MFACE *faces; m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX ); WORD* i; MYVERTEX* v; hr = m_pVB->Lock( 0, 0, (BYTE**)&v, 0 ); hr = m_pIB->Lock( 0, MAX_INDICES, (BYTE**)&i, 0 ); faces = pMesh->faces; for( int iFace = 0; iFace < pMesh->numFaces; iFace++ ) { a = faces[iFace].p[0]; b = faces[iFace].p[1]; c = faces[iFace].p[2]; d = faces[iFace].p[3]; v[numVertices].p = pMesh->pts[a]; v[numVertices].n = bSmooth ? pMesh->norms[a] : faces[iFace].norm; iVertexA = numVertices++; v[numVertices].p = pMesh->pts[b]; v[numVertices].n = bSmooth ? pMesh->norms[b] : faces[iFace].norm; iVertexB = numVertices++; v[numVertices].p = pMesh->pts[c]; v[numVertices].n = bSmooth ? pMesh->norms[c] : faces[iFace].norm; iVertexC = numVertices++; v[numVertices].p = pMesh->pts[d]; v[numVertices].n = bSmooth ? pMesh->norms[d] : faces[iFace].norm; iVertexD = numVertices++; i[numIndices++] = iVertexA; i[numIndices++] = iVertexB; i[numIndices++] = iVertexC; numPrims++; i[numIndices++] = iVertexC; i[numIndices++] = iVertexB; i[numIndices++] = iVertexD; numPrims++; } hr = m_pVB->Unlock(); hr = m_pIB->Unlock(); hr = m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(MYVERTEX) ); hr = m_pd3dDevice->SetIndices( m_pIB, 0 ); hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, numVertices, 0, numPrims ); return hr; } HRESULT RenderMesh3Backsides( MESH* pMesh, BOOL bSmooth ) { HRESULT hr; INT numPrims = 0; INT numIndices = 0; INT numVertices = 0; WORD iVertexA, iVertexB, iVertexC, iVertexD; INT a,b,c,d; MFACE *faces; m_pd3dDevice->SetVertexShader( D3DFVF_MYVERTEX ); WORD* i; MYVERTEX* v; hr = m_pVB->Lock( 0, 0, (BYTE**)&v, 0 ); hr = m_pIB->Lock( 0, MAX_INDICES, (BYTE**)&i, 0 ); faces = pMesh->faces; for( int iFace = 0; iFace < pMesh->numFaces; iFace++ ) { a = faces[iFace].p[0]; b = faces[iFace].p[1]; c = faces[iFace].p[2]; d = faces[iFace].p[3]; v[numVertices].p = pMesh->pts[a]; v[numVertices].n = bSmooth ? -pMesh->norms[a] : -faces[iFace].norm; iVertexA = numVertices++; v[numVertices].p = pMesh->pts[b]; v[numVertices].n = bSmooth ? -pMesh->norms[b] : -faces[iFace].norm; iVertexB = numVertices++; v[numVertices].p = pMesh->pts[c]; v[numVertices].n = bSmooth ? -pMesh->norms[c] : -faces[iFace].norm; iVertexC = numVertices++; v[numVertices].p = pMesh->pts[d]; v[numVertices].n = bSmooth ? -pMesh->norms[d] : -faces[iFace].norm; iVertexD = numVertices++; i[numIndices++] = iVertexB; i[numIndices++] = iVertexA; i[numIndices++] = iVertexC; numPrims++; i[numIndices++] = iVertexB; i[numIndices++] = iVertexC; i[numIndices++] = iVertexD; numPrims++; } hr = m_pVB->Unlock(); hr = m_pIB->Unlock(); hr = m_pd3dDevice->SetStreamSource( 0, m_pVB, sizeof(MYVERTEX) ); hr = m_pd3dDevice->SetIndices( m_pIB, 0 ); hr = m_pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, numVertices, 0, numPrims ); return hr; }