cd_wavefront.cpp
Go to the documentation of this file.
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 };


convex_decomposition
Author(s): John W. Ratcliff
autogenerated on Sat Jun 8 2019 20:01:17