$search
00001 #include <stdio.h> 00002 #include <stdlib.h> 00003 #include <string.h> 00004 #include <assert.h> 00005 #include <ctype.h> 00006 00007 #pragma warning(disable:4996) 00008 00009 #include "cd_wavefront.h" 00010 00011 00012 using namespace ConvexDecomposition; 00013 00070 #include <vector> 00071 00072 namespace ConvexDecomposition 00073 { 00074 00075 typedef std::vector< int > IntVector; 00076 typedef std::vector< double > FloatVector; 00077 00078 #if defined(__APPLE__) || defined(__CELLOS_LV2__) 00079 #define stricmp(a, b) strcasecmp((a), (b)) 00080 #endif 00081 00082 /*******************************************************************/ 00083 /******************** InParser.h ********************************/ 00084 /*******************************************************************/ 00085 class InPlaceParserInterface 00086 { 00087 public: 00088 virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process 00089 }; 00090 00091 enum SeparatorType 00092 { 00093 ST_DATA, // is data 00094 ST_HARD, // is a hard separator 00095 ST_SOFT, // is a soft separator 00096 ST_EOS // is a comment symbol, and everything past this character should be ignored 00097 }; 00098 00099 class InPlaceParser 00100 { 00101 public: 00102 InPlaceParser(void) 00103 { 00104 Init(); 00105 } 00106 00107 InPlaceParser(char *data,int len) 00108 { 00109 Init(); 00110 SetSourceData(data,len); 00111 } 00112 00113 InPlaceParser(const char *fname) 00114 { 00115 Init(); 00116 SetFile(fname); 00117 } 00118 00119 ~InPlaceParser(void); 00120 00121 void Init(void) 00122 { 00123 mQuoteChar = 34; 00124 mData = 0; 00125 mLen = 0; 00126 mMyAlloc = false; 00127 for (int i=0; i<256; i++) 00128 { 00129 mHard[i] = ST_DATA; 00130 mHardString[i*2] = i; 00131 mHardString[i*2+1] = 0; 00132 } 00133 mHard[0] = ST_EOS; 00134 mHard[32] = ST_SOFT; 00135 mHard[9] = ST_SOFT; 00136 mHard[13] = ST_SOFT; 00137 mHard[10] = ST_SOFT; 00138 } 00139 00140 void SetFile(const char *fname); // use this file as source data to parse. 00141 00142 void SetSourceData(char *data,int len) 00143 { 00144 mData = data; 00145 mLen = len; 00146 mMyAlloc = false; 00147 }; 00148 00149 int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason 00150 00151 int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback); 00152 00153 const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse. 00154 00155 void SetHardSeparator(char c) // add a hard separator 00156 { 00157 mHard[c] = ST_HARD; 00158 } 00159 00160 void SetHard(char c) // add a hard separator 00161 { 00162 mHard[c] = ST_HARD; 00163 } 00164 00165 00166 void SetCommentSymbol(char c) // comment character, treated as 'end of string' 00167 { 00168 mHard[c] = ST_EOS; 00169 } 00170 00171 void ClearHardSeparator(char c) 00172 { 00173 mHard[c] = ST_DATA; 00174 } 00175 00176 00177 void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character. 00178 00179 bool EOS(char c) 00180 { 00181 if ( mHard[c] == ST_EOS ) 00182 { 00183 return true; 00184 } 00185 return false; 00186 } 00187 00188 void SetQuoteChar(char c) 00189 { 00190 mQuoteChar = c; 00191 } 00192 00193 private: 00194 00195 00196 inline char * AddHard(int &argc,const char **argv,char *foo); 00197 inline bool IsHard(char c); 00198 inline char * SkipSpaces(char *foo); 00199 inline bool IsWhiteSpace(char c); 00200 inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft 00201 00202 bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it. 00203 char *mData; // ascii data to parse. 00204 int mLen; // length of data 00205 SeparatorType mHard[256]; 00206 char mHardString[256*2]; 00207 char mQuoteChar; 00208 }; 00209 00210 /*******************************************************************/ 00211 /******************** InParser.cpp ********************************/ 00212 /*******************************************************************/ 00213 void InPlaceParser::SetFile(const char *fname) 00214 { 00215 if ( mMyAlloc ) 00216 { 00217 free(mData); 00218 } 00219 mData = 0; 00220 mLen = 0; 00221 mMyAlloc = false; 00222 00223 00224 FILE *fph = fopen(fname,"rb"); 00225 if ( fph ) 00226 { 00227 fseek(fph,0L,SEEK_END); 00228 mLen = ftell(fph); 00229 fseek(fph,0L,SEEK_SET); 00230 if ( mLen ) 00231 { 00232 mData = (char *) malloc(sizeof(char)*(mLen+1)); 00233 int ok = fread(mData, mLen, 1, fph); 00234 if ( !ok ) 00235 { 00236 free(mData); 00237 mData = 0; 00238 } 00239 else 00240 { 00241 mData[mLen] = 0; // zero byte terminate end of file marker. 00242 mMyAlloc = true; 00243 } 00244 } 00245 fclose(fph); 00246 } 00247 } 00248 00249 InPlaceParser::~InPlaceParser(void) 00250 { 00251 if ( mMyAlloc ) 00252 { 00253 free(mData); 00254 } 00255 } 00256 00257 #define MAXARGS 512 00258 00259 bool InPlaceParser::IsHard(char c) 00260 { 00261 return mHard[c] == ST_HARD; 00262 } 00263 00264 char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo) 00265 { 00266 while ( IsHard(*foo) ) 00267 { 00268 const char *hard = &mHardString[*foo*2]; 00269 if ( argc < MAXARGS ) 00270 { 00271 argv[argc++] = hard; 00272 } 00273 foo++; 00274 } 00275 return foo; 00276 } 00277 00278 bool InPlaceParser::IsWhiteSpace(char c) 00279 { 00280 return mHard[c] == ST_SOFT; 00281 } 00282 00283 char * InPlaceParser::SkipSpaces(char *foo) 00284 { 00285 while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++; 00286 return foo; 00287 } 00288 00289 bool InPlaceParser::IsNonSeparator(char c) 00290 { 00291 if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true; 00292 return false; 00293 } 00294 00295 00296 int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback) 00297 { 00298 int ret = 0; 00299 00300 const char *argv[MAXARGS]; 00301 int argc = 0; 00302 00303 char *foo = line; 00304 00305 while ( !EOS(*foo) && argc < MAXARGS ) 00306 { 00307 00308 foo = SkipSpaces(foo); // skip any leading spaces 00309 00310 if ( EOS(*foo) ) break; 00311 00312 if ( *foo == mQuoteChar ) // if it is an open quote 00313 { 00314 foo++; 00315 if ( argc < MAXARGS ) 00316 { 00317 argv[argc++] = foo; 00318 } 00319 while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; 00320 if ( !EOS(*foo) ) 00321 { 00322 *foo = 0; // replace close quote with zero byte EOS 00323 foo++; 00324 } 00325 } 00326 else 00327 { 00328 00329 foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces 00330 00331 if ( IsNonSeparator(*foo) ) // add non-hard argument. 00332 { 00333 bool quote = false; 00334 if ( *foo == mQuoteChar ) 00335 { 00336 foo++; 00337 quote = true; 00338 } 00339 00340 if ( argc < MAXARGS ) 00341 { 00342 argv[argc++] = foo; 00343 } 00344 00345 if ( quote ) 00346 { 00347 while (*foo && *foo != mQuoteChar ) foo++; 00348 if ( *foo ) *foo = 32; 00349 } 00350 00351 // continue..until we hit an eos .. 00352 while ( !EOS(*foo) ) // until we hit EOS 00353 { 00354 if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit 00355 { 00356 *foo = 0; 00357 foo++; 00358 break; 00359 } 00360 else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument 00361 { 00362 const char *hard = &mHardString[*foo*2]; 00363 *foo = 0; 00364 if ( argc < MAXARGS ) 00365 { 00366 argv[argc++] = hard; 00367 } 00368 foo++; 00369 break; 00370 } 00371 foo++; 00372 } // end of while loop... 00373 } 00374 } 00375 } 00376 00377 if ( argc ) 00378 { 00379 ret = callback->ParseLine(lineno, argc, argv ); 00380 } 00381 00382 return ret; 00383 } 00384 00385 int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason 00386 { 00387 assert( callback ); 00388 if ( !mData ) return 0; 00389 00390 int ret = 0; 00391 00392 int lineno = 0; 00393 00394 char *foo = mData; 00395 char *begin = foo; 00396 00397 00398 while ( *foo ) 00399 { 00400 if ( *foo == 10 || *foo == 13 ) 00401 { 00402 lineno++; 00403 *foo = 0; 00404 00405 if ( *begin ) // if there is any data to parse at all... 00406 { 00407 int v = ProcessLine(lineno,begin,callback); 00408 if ( v ) ret = v; 00409 } 00410 00411 foo++; 00412 if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format... 00413 begin = foo; 00414 } 00415 else 00416 { 00417 foo++; 00418 } 00419 } 00420 00421 lineno++; // lasst line. 00422 00423 int v = ProcessLine(lineno,begin,callback); 00424 if ( v ) ret = v; 00425 return ret; 00426 } 00427 00428 00429 void InPlaceParser::DefaultSymbols(void) 00430 { 00431 SetHardSeparator(','); 00432 SetHardSeparator('('); 00433 SetHardSeparator(')'); 00434 SetHardSeparator('='); 00435 SetHardSeparator('['); 00436 SetHardSeparator(']'); 00437 SetHardSeparator('{'); 00438 SetHardSeparator('}'); 00439 SetCommentSymbol('#'); 00440 } 00441 00442 00443 const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse. 00444 { 00445 const char **ret = 0; 00446 00447 static const char *argv[MAXARGS]; 00448 int argc = 0; 00449 00450 char *foo = line; 00451 00452 while ( !EOS(*foo) && argc < MAXARGS ) 00453 { 00454 00455 foo = SkipSpaces(foo); // skip any leading spaces 00456 00457 if ( EOS(*foo) ) break; 00458 00459 if ( *foo == mQuoteChar ) // if it is an open quote 00460 { 00461 foo++; 00462 if ( argc < MAXARGS ) 00463 { 00464 argv[argc++] = foo; 00465 } 00466 while ( !EOS(*foo) && *foo != mQuoteChar ) foo++; 00467 if ( !EOS(*foo) ) 00468 { 00469 *foo = 0; // replace close quote with zero byte EOS 00470 foo++; 00471 } 00472 } 00473 else 00474 { 00475 00476 foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces 00477 00478 if ( IsNonSeparator(*foo) ) // add non-hard argument. 00479 { 00480 bool quote = false; 00481 if ( *foo == mQuoteChar ) 00482 { 00483 foo++; 00484 quote = true; 00485 } 00486 00487 if ( argc < MAXARGS ) 00488 { 00489 argv[argc++] = foo; 00490 } 00491 00492 if ( quote ) 00493 { 00494 while (*foo && *foo != mQuoteChar ) foo++; 00495 if ( *foo ) *foo = 32; 00496 } 00497 00498 // continue..until we hit an eos .. 00499 while ( !EOS(*foo) ) // until we hit EOS 00500 { 00501 if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit 00502 { 00503 *foo = 0; 00504 foo++; 00505 break; 00506 } 00507 else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument 00508 { 00509 const char *hard = &mHardString[*foo*2]; 00510 *foo = 0; 00511 if ( argc < MAXARGS ) 00512 { 00513 argv[argc++] = hard; 00514 } 00515 foo++; 00516 break; 00517 } 00518 foo++; 00519 } // end of while loop... 00520 } 00521 } 00522 } 00523 00524 count = argc; 00525 if ( argc ) 00526 { 00527 ret = argv; 00528 } 00529 00530 return ret; 00531 } 00532 00533 /*******************************************************************/ 00534 /******************** Geometry.h ********************************/ 00535 /*******************************************************************/ 00536 00537 class GeometryVertex 00538 { 00539 public: 00540 double mPos[3]; 00541 double mNormal[3]; 00542 double mTexel[2]; 00543 }; 00544 00545 00546 class GeometryInterface 00547 { 00548 public: 00549 00550 virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3) 00551 { 00552 } 00553 00554 }; 00555 00556 00557 /*******************************************************************/ 00558 /******************** Obj.h ********************************/ 00559 /*******************************************************************/ 00560 00561 00562 class OBJ : public InPlaceParserInterface 00563 { 00564 public: 00565 int LoadMesh(const char *fname,GeometryInterface *callback); 00566 int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process 00567 private: 00568 00569 void GetVertex(GeometryVertex &v,const char *face) const; 00570 00571 FloatVector mVerts; 00572 FloatVector mTexels; 00573 FloatVector mNormals; 00574 00575 GeometryInterface *mCallback; 00576 friend class WavefrontObj; 00577 }; 00578 00579 00580 /*******************************************************************/ 00581 /******************** Obj.cpp ********************************/ 00582 /*******************************************************************/ 00583 00584 int OBJ::LoadMesh(const char *fname,GeometryInterface *iface) 00585 { 00586 int ret = 0; 00587 00588 mVerts.clear(); 00589 mTexels.clear(); 00590 mNormals.clear(); 00591 00592 mCallback = iface; 00593 00594 InPlaceParser ipp(fname); 00595 00596 ipp.Parse(this); 00597 00598 00599 return ret; 00600 } 00601 00602 static const char * GetArg(const char **argv,int i,int argc) 00603 { 00604 const char * ret = 0; 00605 if ( i < argc ) ret = argv[i]; 00606 return ret; 00607 } 00608 00609 void OBJ::GetVertex(GeometryVertex &v,const char *face) const 00610 { 00611 v.mPos[0] = 0; 00612 v.mPos[1] = 0; 00613 v.mPos[2] = 0; 00614 00615 v.mTexel[0] = 0; 00616 v.mTexel[1] = 0; 00617 00618 v.mNormal[0] = 0; 00619 v.mNormal[1] = 1; 00620 v.mNormal[2] = 0; 00621 00622 int index = atoi( face )-1; 00623 00624 const char *texel = strstr(face,"/"); 00625 00626 if ( texel ) 00627 { 00628 int tindex = atoi( texel+1) - 1; 00629 00630 if ( tindex >=0 && tindex < (int)(mTexels.size()/2) ) 00631 { 00632 const double *t = &mTexels[tindex*2]; 00633 00634 v.mTexel[0] = t[0]; 00635 v.mTexel[1] = t[1]; 00636 00637 } 00638 00639 const char *normal = strstr(texel+1,"/"); 00640 if ( normal ) 00641 { 00642 int nindex = atoi( normal+1 ) - 1; 00643 00644 if (nindex >= 0 && nindex < (int)(mNormals.size()/3) ) 00645 { 00646 const double *n = &mNormals[nindex*3]; 00647 00648 v.mNormal[0] = n[0]; 00649 v.mNormal[1] = n[1]; 00650 v.mNormal[2] = n[2]; 00651 } 00652 } 00653 } 00654 00655 if ( index >= 0 && index < (int)(mVerts.size()/3) ) 00656 { 00657 00658 const double *p = &mVerts[index*3]; 00659 00660 v.mPos[0] = p[0]; 00661 v.mPos[1] = p[1]; 00662 v.mPos[2] = p[2]; 00663 } 00664 00665 } 00666 00667 int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process 00668 { 00669 int ret = 0; 00670 00671 if ( argc >= 1 ) 00672 { 00673 const char *foo = argv[0]; 00674 if ( *foo != '#' ) 00675 { 00676 if ( strcmp(argv[0],"v") == 0 && argc == 4 ) 00677 { 00678 double vx = (double) atof( argv[1] ); 00679 double vy = (double) atof( argv[2] ); 00680 double vz = (double) atof( argv[3] ); 00681 mVerts.push_back(vx); 00682 mVerts.push_back(vy); 00683 mVerts.push_back(vz); 00684 } 00685 else if ( strcmp(argv[0],"vt") == 0 && argc == 3 ) 00686 { 00687 double tx = (double) atof( argv[1] ); 00688 double ty = (double) atof( argv[2] ); 00689 mTexels.push_back(tx); 00690 mTexels.push_back(ty); 00691 } 00692 else if ( strcmp(argv[0],"vn") == 0 && argc == 4 ) 00693 { 00694 double normalx = (double) atof(argv[1]); 00695 double normaly = (double) atof(argv[2]); 00696 double normalz = (double) atof(argv[3]); 00697 mNormals.push_back(normalx); 00698 mNormals.push_back(normaly); 00699 mNormals.push_back(normalz); 00700 } 00701 else if ( strcmp(argv[0],"f") == 0 && argc >= 4 ) 00702 { 00703 GeometryVertex v[32]; 00704 00705 int vcount = argc-1; 00706 00707 for (int i=1; i<argc; i++) 00708 { 00709 GetVertex(v[i-1],argv[i] ); 00710 } 00711 00712 // need to generate a normal! 00713 #if 0 // not currently implemented 00714 if ( mNormals.empty() ) 00715 { 00716 Vector3d<double> p1( v[0].mPos ); 00717 Vector3d<double> p2( v[1].mPos ); 00718 Vector3d<double> p3( v[2].mPos ); 00719 00720 Vector3d<double> n; 00721 n.ComputeNormal(p3,p2,p1); 00722 00723 for (int i=0; i<vcount; i++) 00724 { 00725 v[i].mNormal[0] = n.x; 00726 v[i].mNormal[1] = n.y; 00727 v[i].mNormal[2] = n.z; 00728 } 00729 00730 } 00731 #endif 00732 00733 mCallback->NodeTriangle(&v[0],&v[1],&v[2]); 00734 00735 if ( vcount >=3 ) // do the fan 00736 { 00737 for (int i=2; i<(vcount-1); i++) 00738 { 00739 mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]); 00740 } 00741 } 00742 00743 } 00744 } 00745 } 00746 00747 return ret; 00748 } 00749 00750 00751 00752 00753 class BuildMesh : public GeometryInterface 00754 { 00755 public: 00756 00757 int GetIndex(const double *p) 00758 { 00759 00760 int vcount = mVertices.size()/3; 00761 00762 if(vcount>0) 00763 { 00764 //New MS STL library checks indices in debug build, so zero causes an assert if it is empty. 00765 const double *v = &mVertices[0]; 00766 00767 for (int i=0; i<vcount; i++) 00768 { 00769 if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) return i; 00770 v+=3; 00771 } 00772 } 00773 00774 mVertices.push_back( p[0] ); 00775 mVertices.push_back( p[1] ); 00776 mVertices.push_back( p[2] ); 00777 00778 return vcount; 00779 } 00780 00781 virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3) 00782 { 00783 mIndices.push_back( GetIndex(v1->mPos) ); 00784 mIndices.push_back( GetIndex(v2->mPos) ); 00785 mIndices.push_back( GetIndex(v3->mPos) ); 00786 } 00787 00788 const FloatVector& GetVertices(void) const { return mVertices; }; 00789 const IntVector& GetIndices(void) const { return mIndices; }; 00790 00791 private: 00792 FloatVector mVertices; 00793 IntVector mIndices; 00794 }; 00795 00796 00797 WavefrontObj::WavefrontObj(void) 00798 { 00799 mVertexCount = 0; 00800 mTriCount = 0; 00801 mIndices = 0; 00802 mVertices = 0; 00803 } 00804 00805 WavefrontObj::~WavefrontObj(void) 00806 { 00807 delete mIndices; 00808 delete mVertices; 00809 } 00810 00811 unsigned int WavefrontObj::loadObj(const char *fname) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed. 00812 { 00813 00814 unsigned int ret = 0; 00815 00816 delete mVertices; 00817 mVertices = 0; 00818 delete mIndices; 00819 mIndices = 0; 00820 mVertexCount = 0; 00821 mTriCount = 0; 00822 00823 00824 BuildMesh bm; 00825 00826 OBJ obj; 00827 00828 obj.LoadMesh(fname,&bm); 00829 00830 00831 const FloatVector &vlist = bm.GetVertices(); 00832 const IntVector &indices = bm.GetIndices(); 00833 if ( vlist.size() ) 00834 { 00835 mVertexCount = vlist.size()/3; 00836 mVertices = new double[mVertexCount*3]; 00837 memcpy( mVertices, &vlist[0], sizeof(double)*mVertexCount*3 ); 00838 mTriCount = indices.size()/3; 00839 mIndices = new int[mTriCount*3*sizeof(int)]; 00840 memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3); 00841 ret = mTriCount; 00842 } 00843 else if( obj.mVerts.size() > 0 ) { 00844 // take consecutive vertices 00845 mVertexCount = obj.mVerts.size()/3; 00846 mVertices = new double[mVertexCount*3]; 00847 memcpy( mVertices, &obj.mVerts[0], sizeof(double)*mVertexCount*3 ); 00848 mTriCount = mVertexCount/3; 00849 mIndices = new int[mTriCount*3*sizeof(int)]; 00850 for(int i = 0; i < mVertexCount; ++i) 00851 mIndices[i] = i; 00852 ret = mTriCount; 00853 } 00854 00855 return ret; 00856 } 00857 00858 };