![[]](/images/special/trans.gif)
LibN2L-4 Library Code ReferenceClassesCompounds Files Members Method Index Full Reference cRWavefrontModel.cppGo 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 |