AaronCameron.net
Not Left, nor right. Just correct.
Not a Member? - Login or Create an Account
Monday the 6th of February 2012 @ 09:17am
Front Page Journal Projects Your Profile About
[]

LibN2L-4 Library Code Reference

Classes
Compounds
Files
Members
Method Index
Full Reference

cRWavefrontModel.cpp

Go to the documentation of this file.
00001 /************************************************************************
00002 Nova-2 Library (libN2L, or simply n2l) Game development C++ Library
00003 Copyright (C) 2003  Aaron Cameron
00004 
00005 This library is free software; you can redistribute it and/or
00006 modify it under the terms of the GNU Lesser General Public
00007 License as published by the Free Software Foundation; either
00008 version 2.1 of the License, or (at your option) any later version.
00009 
00010 This library is distributed in the hope that it will be useful,
00011 but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013 Lesser General Public License for more details.
00014 
00015 You should have received a copy of the GNU Lesser General Public
00016 License along with this library; if not, write to the Free Software
00017 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00018 
00019 A copy of the GNU Lesser General Public License has been provided with
00020 this library in the file 'COPYING'.
00021 
00022 Contact information for the author of this library has been provided
00023 with this library in the file 'AUTHOR'.
00024 ************************************************************************/
00025 #include "renderTools/cRWavefrontModel.h"
00026 
00027 #include "n2l/vfs.h"
00028 #include "n2l/materials.h"
00029 
00030 using namespace std;
00031 
00032 namespace n2l
00033 {
00034 
00035     /******************************************************************/
00036     cRWavefrontModel::cRWavefrontModel( const cVfsNodeInterface & iFile ) :
00037         mVertices(0),
00038         mNormals(0),
00039         mUVCoords(0),
00040         mFaceIndices(0),
00041         mNormalIndices(0),
00042         mUVIndices(0),
00043         mNumVertices(0),
00044         mNumNormals(0),
00045         mNumUVCoords(0),
00046         mNumFaces(0)
00047     {
00048         load(iFile);
00049     }
00050 
00051     /******************************************************************/
00052     cRWavefrontModel::cRWavefrontModel( const cRWavefrontModel & iModel ) :
00053         mVertices(0),
00054         mNormals(0),
00055         mUVCoords(0),
00056         mFaceIndices(0),
00057         mNormalIndices(0),
00058         mUVIndices(0),
00059         mNumVertices(0),
00060         mNumNormals(0),
00061         mNumUVCoords(0),
00062         mNumFaces(0)
00063     {
00064         *this = iModel;
00065     }
00066 
00067     /******************************************************************/
00068     cRWavefrontModel::~cRWavefrontModel()
00069     {
00070         free();
00071     }
00072 
00073     /******************************************************************/
00074     void cRWavefrontModel::load( const cVfsNodeInterface & iFile )
00075     {
00076         // Clear out whatever we're currently holding.
00077         free();
00078         
00079         // Make sure that the node is like a file.
00080         if (!iFile.likeFile())
00081             throw cBadDataUseException( "cRWavefrontModel::load",
00082                                         "Vfs Node isn\'t like a file" );
00083         tVfsFileBuffer buffer( iFile.buffer() );
00084 
00085         // Scan the file twice, once to find out array sizes, file
00086         // indicies and line types and the second time to parse
00087         // the values found.
00088         tVfsFileBuffer::size_type pos(0);
00089         vector<tFileLine> lines;
00090         do {
00091             // How long is the line?
00092             const tVfsFileBuffer::size_type EndOfLinePos( buffer.find_first_of("#\n\r",pos) );
00093             if (EndOfLinePos==tVfsFileBuffer::npos) {
00094                 pos = tVfsFileBuffer::npos;
00095                 continue;
00096             }
00097         
00098             // Find the control token.
00099             const tVfsFileBuffer::size_type STokenPos( buffer.find_first_not_of(" \t",pos) );
00100             if (EndOfLinePos==tVfsFileBuffer::npos) {
00101                 // Could be a blank line, so just skip and try again.
00102                 continue;
00103             }
00104 
00105             const tVfsFileBuffer::size_type ETokenPos( buffer.find_first_of(" \t",STokenPos) );
00106             if (ETokenPos==tVfsFileBuffer::npos) {
00107                 pos = tVfsFileBuffer::npos;
00108                 continue;
00109             }
00110             const tString ControlToken( buffer.substr(STokenPos,ETokenPos-STokenPos) );
00111 
00112             tFileLine line;
00113             line.mSPos = buffer.find_first_not_of(" \t",ETokenPos);
00114             line.mEPos = EndOfLinePos;
00115             if (ControlToken=="v") {
00116                 line.mType = Type_Vertex;
00117                 ++mNumVertices;
00118                 lines.push_back(line);
00119 
00120             } else if (ControlToken=="vn") {
00121                 line.mType = Type_VertexNormal;
00122                 ++mNumNormals;
00123                 lines.push_back(line);
00124 
00125             } else if (ControlToken=="vt") {
00126                 line.mType = Type_TextureCoord;
00127                 ++mNumUVCoords;
00128                 lines.push_back(line);
00129 
00130             } else if (ControlToken=="f") {
00131                 line.mType = Type_Face;
00132                 ++mNumFaces;
00133                 lines.push_back(line);
00134 
00135             } else if (ControlToken=="g") {
00136 //              cout << "Loaded group: " << buffer.substr(line.mSPos,line.mEPos-line.mSPos) << endl;
00137             }
00138 
00139             // All done, advance
00140             if (buffer[EndOfLinePos]=='\n') { 
00141                 pos = EndOfLinePos+1;
00142 
00143             } else {
00144                 // It was a comment, we have to seek the real end of line
00145                 const tVfsFileBuffer::size_type RealEndOfLinePos( buffer.find("\n",EndOfLinePos+1) );
00146                 if (RealEndOfLinePos!=tVfsFileBuffer::npos) pos = RealEndOfLinePos+1;
00147                 else pos = tVfsFileBuffer::npos;
00148             }
00149         } while (tVfsFileBuffer::npos != pos);
00150 
00151         if (!mNumVertices)
00152             throw cParsingException("cRWavefrontModel::load",
00153                                     "Models must have at least one vertex" );
00154         if (!mNumFaces)
00155             throw cParsingException("cRWavefrontModel::load",
00156                                     "Models must have at least one face" );
00157 
00158         // Allocate space in our arrays
00159         mVertices = new tVector3f[ mNumVertices ];
00160         mFaceIndices = new tVector3u[ mNumFaces ];
00161 
00162         if (mNumNormals) {
00163             mNormals = new tVector3f[ mNumNormals ];
00164             mNormalIndices = new tVector3u[ mNumFaces ];
00165         }
00166         
00167         if (mNumUVCoords) {
00168             mUVCoords = new tVector2f[ mNumUVCoords ];
00169             mUVIndices = new tVector3u[ mNumFaces ];
00170         }
00171 
00172         // Scan the lines again building our internal structures.
00173         tUint vIndex(0);
00174         tUint vnIndex(0);
00175         tUint uvIndex(0);
00176         tUint faceIndex(0);
00177         vector<tString> tempTokens;
00178 
00179         const tUint MasterListSize( lines.size() );
00180         for (tUint lineNum = 0; lineNum!=MasterListSize; ++lineNum) {
00181             const tUint SPos( lines[lineNum].mSPos );
00182             const tUint EPos( lines[lineNum].mEPos );
00183 
00184             tempTokens.clear();
00185             switch (lines[lineNum].mType)
00186             {
00187                 case Type_Vertex:
00188                     explode( buffer.substr(SPos,EPos-SPos),
00189                              tempTokens, ' ', '\0', '\0', false );
00190                     if (tempTokens.size()!=3)
00191                         throw cParsingException("cRWavefrontModel::load",
00192                                                 "Vertex lines must have exactly "
00193                                                 "3 components" );
00194                     mVertices[vIndex].set(  asFloat(tempTokens[0]),
00195                                             asFloat(tempTokens[1]),
00196                                             asFloat(tempTokens[2]) );
00197                     ++vIndex;
00198                     break;
00199 
00200                 case Type_VertexNormal:
00201                     explode( buffer.substr(SPos,EPos-SPos),
00202                              tempTokens, ' ', '\0', '\0', false );
00203                     if (tempTokens.size()!=3)
00204                         throw cParsingException("cRWavefrontModel::load",
00205                                                 "Vertex normals must have exactly "
00206                                                 "3 components" );
00207                     mNormals[vnIndex].set(  asFloat(tempTokens[0]),
00208                                             asFloat(tempTokens[1]),
00209                                             asFloat(tempTokens[2]) );
00210                     ++vnIndex;
00211                     break;
00212 
00213                 case Type_TextureCoord:
00214                     explode( buffer.substr(SPos,EPos-SPos),
00215                              tempTokens, ' ', '\0', '\0', false );
00216                     if (tempTokens.size()!=2)
00217                         throw cParsingException("cRWavefrontModel::load",
00218                                                 "Texture UV coordinates must have exactly "
00219                                                 "2 components" );
00220                     mUVCoords[uvIndex].set( asFloat(tempTokens[0]),
00221                                             asFloat(tempTokens[1]) );
00222                     ++uvIndex;
00223                     break;
00224 
00225                 case Type_Face: {
00226                     // Faces have the format v[/[vt]/vn]
00227                     // eg.  f 7     # just a vertex
00228                     //      f 7//1  # vertex and normal
00229                     //      
00230                     //      f 7/3/1 # vertex, texture uv and normal
00231 
00232                     explode( buffer.substr(SPos,EPos-SPos),
00233                              tempTokens, ' ', '\0', '\0', false );
00234                     
00235                     if (tempTokens.size()!=3)
00236                         throw cParsingException("cRWavefrontModel::load",
00237                                                 "Faces must have exactly "
00238                                                 "3 groups" );
00239 
00240                     vector<tString> groupTokens;
00241                     // Step through the groups
00242                     for (tUint g=0; g<3; ++g) {
00243                         groupTokens.clear();
00244                         explode( tempTokens[g], groupTokens, '/', '\0', '\0', false );
00245                         if (mNumNormals && groupTokens.size()!=3)
00246                             throw cParsingException("cRWavefrontModel::load",
00247                                                     "Groups with normals should have "
00248                                                     "exactly 3 sub-components" );
00249                         else if (!mNumNormals && mNumUVCoords && groupTokens.size()!=2)
00250                             throw cParsingException("cRWavefrontModel::load",
00251                                                     "Groups with uv and no normals should have "
00252                                                     "exactly 2 sub-components" );
00253                         else if (!mNumNormals && !mNumUVCoords && groupTokens.size()!=1)
00254                             throw cParsingException("cRWavefrontModel::load",
00255                                                     "Groups with no uv and no normals should have "
00256                                                     "exactly 1 sub-components" );
00257 
00258                         mFaceIndices[faceIndex][g] = asUint32(groupTokens[0])-1;
00259                         if (mFaceIndices[faceIndex][g]>=mNumVertices)
00260                             throw cParsingException("cRWavefrontModel::load",
00261                                                     "Calculated vertex index was out of range",
00262                                                     buffer.substr(SPos,EPos-SPos),asString(lineNum) );
00263                         if (mNumUVCoords) {
00264                             mUVIndices[faceIndex][g] = asUint32(groupTokens[1])-1;
00265                             if (mUVIndices[faceIndex][g]>=mNumUVCoords)
00266                                 throw cParsingException("cRWavefrontModel::load",
00267                                                         "Calculated UV index was out of range",
00268                                                         buffer.substr(SPos,EPos-SPos),asString(lineNum) );
00269                         }
00270                         if (mNumNormals) {
00271                             mNormalIndices[faceIndex][g] = asUint32(groupTokens[2])-1;
00272                             if (mNormalIndices[faceIndex][g]>=mNumNormals)
00273                                 throw cParsingException("cRWavefrontModel::load",
00274                                                         "Calculated Normal index was out of range",
00275                                                         buffer.substr(SPos,EPos-SPos),asString(lineNum) );
00276                         }
00277 
00278 
00279                     } // for (tUint g=0; g<3; ++g) 
00280 
00281                     ++faceIndex;
00282                     break;
00283                 } // case Type_Face:
00284 
00285                 default:
00286                     throw cParsingException("cRWavefrontModel::load",
00287                                             "Pre-scan registered an unknown type" );
00288             } // switch
00289         } // for (vector<tFileLine>::con...
00290 
00291     }
00292 
00293     /******************************************************************/
00294     void cRWavefrontModel::centerAroundOrigin()
00295     {
00296         if (!mNumVertices)
00297             throw cBadDataUseException( "cRWavefrontModel::centerAroundOrigin",
00298                                         "Tried to modify a model with no vertices" );
00299         // Re-orient the object so it is centered on the origin
00300         tVector3f minV,maxV;
00301         getMinMaxVectors(minV,maxV);
00302         const tVector3f ModelCenter( minV+((maxV-minV)*0.5f) );
00303         for (tUint v=0; v<mNumVertices; ++v)
00304             mVertices[v] -= ModelCenter;
00305     }
00306 
00307 
00308     /******************************************************************/
00309     void cRWavefrontModel::normalizeDimensions()
00310     {
00311         if (!mNumVertices)
00312             throw cBadDataUseException( "cRWavefrontModel::centerAroundOrigin",
00313                                         "Tried to modify a model with no vertices" );
00314         const tVector3f AllScale( tVector3f(1.0f,1.0f,1.0f)/dimensions() );
00315         const tFloat ScaleFactor( n2l_min( n2l_min(AllScale.x(),AllScale.y()), AllScale.z() ) );
00316         const tVector3f ScaleVector( ScaleFactor,ScaleFactor,ScaleFactor );
00317         scale( ScaleVector );
00318     }
00319 
00320     /* ************************************************************ */
00321     void cRWavefrontModel::scale( const tVector3f & iScale )
00322     {
00323         if (!mNumVertices)
00324             throw cBadDataUseException( "cRWavefrontModel::scale",
00325                                         "Tried to modify a model with no vertices" );
00326         for (tUint v=0; v<mNumVertices; ++v)
00327             mVertices[v] *= iScale;
00328     }
00329 
00330     /* ************************************************************ */
00331     const tVector3f cRWavefrontModel::dimensions() const
00332     {
00333         if (!mNumVertices)
00334             throw cBadDataUseException( "cRWavefrontModel::dimensions",
00335                                         "Tried to modify a model with no vertices" );
00336         tVector3f minV,maxV;
00337         getMinMaxVectors(minV,maxV);
00338         return maxV-minV;
00339     }
00340 
00341     /* ************************************************************ */
00342     void cRWavefrontModel::getMinMaxVectors( tVector3f & oMin, tVector3f & oMax ) const
00343     {
00344         oMin = mVertices[0];
00345         oMax = mVertices[0];
00346         for (tUint v=1; v<mNumVertices; ++v) {
00347             oMin.set(   n2l_min(mVertices[v].x(),oMin.x()),
00348                         n2l_min(mVertices[v].y(),oMin.y()),
00349                         n2l_min(mVertices[v].z(),oMin.z()) );
00350             oMax.set(   n2l_max(mVertices[v].x(),oMax.x()),
00351                         n2l_max(mVertices[v].y(),oMax.y()),
00352                         n2l_max(mVertices[v].z(),oMax.z()) );
00353         }
00354     }
00355 
00356     /* ************************************************************ */
00357     void cRWavefrontModel::render(  const cAutoPtr<const cGLTexture> & i_iTexture,
00358                                     const tRenderOptions iOptions ) const
00359     {
00360         if (!mNumFaces)
00361             throw cBadDataUseException( "cRWavefrontModel::render",
00362                                         "Tried to render a model with no faces" );
00363 
00364         const tBool Textured( mNumUVCoords && i_iTexture.isSet() && !(iOptions & R_NoTextures) );
00365         const tBool Normals( mNumNormals && !(iOptions & R_NoNormals) );
00366         const tBool VertLighting( !(iOptions & R_FaceLighting) );
00367 
00368         if (Textured) {
00369             glEnable( GL_TEXTURE_2D );
00370             i_iTexture->bind();
00371         }
00372         glEnable( GL_DEPTH_TEST );
00373         glCullFace(GL_BACK);
00374         glEnable(GL_CULL_FACE);
00375 
00376         // Lets render the retarded thing.
00377         if (iOptions & R_Wireframe)
00378             glBegin( GL_LINE_STRIP );
00379         else glBegin( GL_TRIANGLES );
00380 
00381         const tVector3u *uvInd(0);
00382         const tVector3u *normInd(0);
00383         const tVector3u *faceInd(0);
00384         
00385         for (tUint f=0; f<mNumFaces; ++f) {
00386             if (Textured) uvInd = &mUVIndices[f];
00387             if (Normals) normInd = &mNormalIndices[f];
00388             faceInd = &mFaceIndices[f];
00389 
00390             if (Normals)    mNormals[ normInd->x() ].glNormal3f();
00391             if (Textured)   mUVCoords[ uvInd->x() ].glTexCoord2f();
00392             mVertices[ faceInd->x() ].glVertex3f();
00393 
00394             if (Normals && VertLighting)    mNormals[ normInd->y() ].glNormal3f();
00395             if (Textured)   mUVCoords[ uvInd->y() ].glTexCoord2f();
00396             mVertices[ faceInd->y() ].glVertex3f();
00397 
00398             if (Normals && VertLighting)    mNormals[ normInd->z() ].glNormal3f();
00399             if (Textured)   mUVCoords[ uvInd->z() ].glTexCoord2f();
00400             mVertices[ faceInd->z() ].glVertex3f();
00401         }
00402 
00403         glEnd();
00404 
00405         glDisable( GL_CULL_FACE );
00406         glDisable( GL_DEPTH_TEST );
00407         if (Textured)
00408             glDisable( GL_TEXTURE_2D );
00409     }
00410 
00411 
00412     /* ************************************************************ */
00413     cRWavefrontModel & cRWavefrontModel::operator =( const cRWavefrontModel & iModel )
00414     {
00415         // Self assignment check
00416         if (this == &iModel) return *this;
00417 
00418         // Clear our current copy.
00419         free();
00420 
00421         // Is our target blank?
00422         if (!iModel.mNumVertices) return *this;
00423 
00424         // Copy the counts.
00425         mNumVertices = iModel.mNumVertices;
00426         mNumNormals = iModel.mNumNormals;
00427         mNumUVCoords = iModel.mNumUVCoords;
00428         mNumFaces = iModel.mNumFaces;
00429 
00430         // We have something to copy, then.
00431         mVertices = new tVector3f[ mNumVertices ];
00432         mFaceIndices = new tVector3u[ mNumFaces ];
00433         memcpy( (void*)(mVertices), (void*)(iModel.mVertices), sizeof(tVector3f)*mNumVertices );
00434         memcpy( (void*)(mFaceIndices), (void*)(iModel.mFaceIndices), sizeof(tVector3u)*mNumFaces );
00435 
00436         if (mNumNormals) {
00437             mNormals = new tVector3f[ mNumNormals ];
00438             mNormalIndices = new tVector3u[ mNumFaces ];
00439 
00440             memcpy( (void*)(mNormals), (void*)(iModel.mNormals), sizeof(tVector3f)*mNumNormals );
00441             memcpy( (void*)(mNormalIndices), (void*)(iModel.mNormalIndices), sizeof(tVector3u)*mNumFaces );
00442         }
00443 
00444         if (mNumUVCoords) {
00445             mUVCoords = new tVector2f[ mNumUVCoords ];
00446             mUVIndices = new tVector3u[ mNumFaces ];
00447             
00448             memcpy( (void*)(mUVCoords), (void*)(iModel.mUVCoords), sizeof(tVector2f)*mNumUVCoords );
00449             memcpy( (void*)(mUVIndices), (void*)(iModel.mUVIndices), sizeof(tVector3u)*mNumFaces );
00450         }
00451 
00452          return *this;
00453     }
00454 
00455 
00456     /* ************************************************************ */
00457     const tString cRWavefrontModel::dump() const
00458     {
00459         tString temp( "cRWavefrontModel(\n" );
00460         temp += "\tNum Vert.:\t\t";
00461         temp += asString(mNumVertices) + "\n";
00462         
00463         temp += "\tNum UV Co.:\t\t";
00464         temp += asString(mNumUVCoords) + "\n";
00465         
00466         temp += "\tNum Norms:\t\t";
00467         temp += asString(mNumNormals) + "\n";
00468         
00469         temp += "\tNum Faces\t\t";
00470         temp += asString(mNumFaces) + "\n";
00471 
00472         temp += ")";
00473         return temp;
00474     }
00475 
00476     /******************************************************************/
00477     const tString & cRWavefrontModel::vfsType() const
00478     {
00479         return VfsFileType_Wavefront;
00480     }
00481 
00482     /******************************************************************/
00483     void cRWavefrontModel::free()
00484     {
00485         if (mVertices) delete []mVertices;
00486         if (mNormals) delete []mNormals;
00487         if (mUVCoords) delete []mUVCoords;
00488 
00489         if (mFaceIndices) delete []mFaceIndices;
00490         if (mNormalIndices) delete []mNormalIndices;
00491         if (mUVIndices) delete []mUVIndices;
00492 
00493         mVertices = 0;
00494         mNormals = 0;
00495         mUVCoords = 0;
00496         
00497         mFaceIndices = 0;
00498         mNormalIndices = 0;
00499         mUVIndices = 0;
00500         
00501         mNumFaces = 0;
00502     }
00503     
00504 
00505 } // namespace n2l
©2012 Aaron Cameron