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
00084
00085 class InPlaceParserInterface
00086 {
00087 public:
00088 virtual int ParseLine(int lineno,int argc,const char **argv) =0;
00089 };
00090
00091 enum SeparatorType
00092 {
00093 ST_DATA,
00094 ST_HARD,
00095 ST_SOFT,
00096 ST_EOS
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);
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);
00150
00151 int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
00152
00153 const char ** GetArglist(char *source,int &count);
00154
00155 void SetHardSeparator(char c)
00156 {
00157 mHard[c] = ST_HARD;
00158 }
00159
00160 void SetHard(char c)
00161 {
00162 mHard[c] = ST_HARD;
00163 }
00164
00165
00166 void SetCommentSymbol(char c)
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);
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);
00201
00202 bool mMyAlloc;
00203 char *mData;
00204 int mLen;
00205 SeparatorType mHard[256];
00206 char mHardString[256*2];
00207 char mQuoteChar;
00208 };
00209
00210
00211
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;
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);
00309
00310 if ( EOS(*foo) ) break;
00311
00312 if ( *foo == mQuoteChar )
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;
00323 foo++;
00324 }
00325 }
00326 else
00327 {
00328
00329 foo = AddHard(argc,argv,foo);
00330
00331 if ( IsNonSeparator(*foo) )
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
00352 while ( !EOS(*foo) )
00353 {
00354 if ( IsWhiteSpace(*foo) )
00355 {
00356 *foo = 0;
00357 foo++;
00358 break;
00359 }
00360 else if ( IsHard(*foo) )
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 }
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)
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 )
00406 {
00407 int v = ProcessLine(lineno,begin,callback);
00408 if ( v ) ret = v;
00409 }
00410
00411 foo++;
00412 if ( *foo == 10 ) foo++;
00413 begin = foo;
00414 }
00415 else
00416 {
00417 foo++;
00418 }
00419 }
00420
00421 lineno++;
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)
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);
00456
00457 if ( EOS(*foo) ) break;
00458
00459 if ( *foo == mQuoteChar )
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;
00470 foo++;
00471 }
00472 }
00473 else
00474 {
00475
00476 foo = AddHard(argc,argv,foo);
00477
00478 if ( IsNonSeparator(*foo) )
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
00499 while ( !EOS(*foo) )
00500 {
00501 if ( IsWhiteSpace(*foo) )
00502 {
00503 *foo = 0;
00504 foo++;
00505 break;
00506 }
00507 else if ( IsHard(*foo) )
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 }
00520 }
00521 }
00522 }
00523
00524 count = argc;
00525 if ( argc )
00526 {
00527 ret = argv;
00528 }
00529
00530 return ret;
00531 }
00532
00533
00534
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
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);
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
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)
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
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 )
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
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)
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
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 };