diff options
Diffstat (limited to 'lib/TriangleMesh.cpp')
-rw-r--r-- | lib/TriangleMesh.cpp | 154 |
1 files changed, 154 insertions, 0 deletions
diff --git a/lib/TriangleMesh.cpp b/lib/TriangleMesh.cpp new file mode 100644 index 0000000..92d7e89 --- /dev/null +++ b/lib/TriangleMesh.cpp @@ -0,0 +1,154 @@ +/* + * TriangleMesh.cpp + * + * Copyright 2007 Richard S. Wright Jr.. All rights reserved. + * This class allows you to simply add triangles as if this class were a + * container. The AddTriangle() function searches the current list of triangles + * and determines if the vertex/normal/texcoord is a duplicate. If so, it addes + * an entry to the index array instead of the list of vertices. + * When finished, call EndMesh() to free up extra unneeded memory that is reserved + * as workspace when you call BeginMesh(). + * + * This class can easily be extended to contain other vertex attributes, and to + * save itself and load itself from disk (thus forming the beginnings of a custom + * model file format). + */ + +#include "TriangleMesh.h" + +/////////////////////////////////////////////////////////// +// Constructor, does what constructors do... set everything to zero or NULL +CTriangleMesh::CTriangleMesh(void) +{ + pIndexes = NULL; + pVerts = NULL; + pNorms = NULL; + pTexCoords = NULL; + + nMaxIndexes = 0; + nNumIndexes = 0; + nNumVerts = 0; +} + +//////////////////////////////////////////////////////////// +// Free any dynamically allocated memory. For those C programmers +// coming to C++, it is perfectly valid to delete a NULL pointer. +CTriangleMesh::~CTriangleMesh(void) +{ + delete [] pIndexes; + delete [] pVerts; + delete [] pNorms; + delete [] pTexCoords; +} + +//////////////////////////////////////////////////////////// +// Start assembling a mesh. You need to specify a maximum amount +// of indexes that you expect. The EndMesh will clean up any uneeded +// memory. This is far better than shreading your heap with STL containers... +// At least that's my humble opinion. +void CTriangleMesh::BeginMesh(GLuint nMaxVerts) +{ + // Just in case this gets called more than once... + delete [] pIndexes; + delete [] pVerts; + delete [] pNorms; + delete [] pTexCoords; + + nMaxIndexes = nMaxVerts; + nNumIndexes = 0; + nNumVerts = 0; + + // Allocate new blocks + pIndexes = new GLushort[nMaxIndexes]; + pVerts = new M3DVector3f[nMaxIndexes]; + pNorms = new M3DVector3f[nMaxIndexes]; + pTexCoords = new M3DVector2f[nMaxIndexes]; +} + +///////////////////////////////////////////////////////////////// +// Add a triangle to the mesh. This searches the current list for identical +// (well, almost identical - these are floats you know...) verts. If one is found, it +// is added to the index array. If not, it is added to both the index array and the vertex +// array grows by one as well. +void CTriangleMesh::AddTriangle(M3DVector3f verts[3], M3DVector3f vNorms[3], M3DVector2f vTexCoords[3]) +{ + const float e = 0.000001; // How small a difference to equate + + // First thing we do is make sure the normals are unit length! + // It's almost always a good idea to work with pre-normalized normals + m3dNormalizeVector(vNorms[0]); + m3dNormalizeVector(vNorms[1]); + m3dNormalizeVector(vNorms[2]); + + + // Search for match - triangle consists of three verts + for (GLuint iVertex = 0; iVertex < 3; iVertex++) + { + GLuint iMatch = 0; + for (iMatch = 0; iMatch < nNumVerts; iMatch++) + { + // If the vertex positions are the same + if (m3dCloseEnough(pVerts[iMatch][0], verts[iVertex][0], e) && + m3dCloseEnough(pVerts[iMatch][1], verts[iVertex][1], e) && + m3dCloseEnough(pVerts[iMatch][2], verts[iVertex][2], e) && + + // AND the Normal is the same... + m3dCloseEnough(pNorms[iMatch][0], vNorms[iVertex][0], e) && + m3dCloseEnough(pNorms[iMatch][1], vNorms[iVertex][1], e) && + m3dCloseEnough(pNorms[iMatch][2], vNorms[iVertex][2], e) && + + // And Texture is the same... + m3dCloseEnough(pTexCoords[iMatch][0], vTexCoords[iVertex][0], e) && + m3dCloseEnough(pTexCoords[iMatch][1], vTexCoords[iVertex][1], e)) + { + // Then add the index only + pIndexes[nNumIndexes] = iMatch; + nNumIndexes++; + break; + } + } + + // No match for this vertex, add to end of list + if (iMatch == nNumVerts) + { + memcpy(pVerts[nNumVerts], verts[iVertex], sizeof(M3DVector3f)); + memcpy(pNorms[nNumVerts], vNorms[iVertex], sizeof(M3DVector3f)); + memcpy(pTexCoords[nNumVerts], &vTexCoords[iVertex], sizeof(M3DVector2f)); + pIndexes[nNumIndexes] = nNumVerts; + nNumIndexes++; + nNumVerts++; + } + } +} + +////////////////////////////////////////////////////////////////// +// Compact the data. This is a nice utility, but you should really +// save the results of the indexing for future use if the model data +// is static (doesn't change). +void CTriangleMesh::EndMesh(void) +{ + // Allocate smaller arrays + GLushort *pPackedIndexes = new GLushort[nNumIndexes]; + M3DVector3f *pPackedVerts = new M3DVector3f[nNumVerts]; + M3DVector3f *pPackedNorms = new M3DVector3f[nNumVerts]; + M3DVector2f *pPackedTex = new M3DVector2f[nNumVerts]; + + // Copy data to smaller arrays + memcpy(pPackedIndexes, pIndexes, sizeof(GLushort)*nNumIndexes); + memcpy(pPackedVerts, pVerts, sizeof(M3DVector3f)*nNumVerts); + memcpy(pPackedNorms, pNorms, sizeof(M3DVector3f)*nNumVerts); + memcpy(pPackedTex, pTexCoords, sizeof(M3DVector2f)*nNumVerts); + + // Free older, larger arrays + delete [] pIndexes; + delete [] pVerts; + delete [] pNorms; + delete [] pTexCoords; + + // Reasign pointers + pIndexes = pPackedIndexes; + pVerts = pPackedVerts; + pNorms = pPackedNorms; + pTexCoords = pPackedTex; +} + |