cd_wavefront.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <assert.h>
  5. #include <ctype.h>
  6. /*----------------------------------------------------------------------
  7. Copyright (c) 2004 Open Dynamics Framework Group
  8. www.physicstools.org
  9. All rights reserved.
  10. Redistribution and use in source and binary forms, with or without modification, are permitted provided
  11. that the following conditions are met:
  12. Redistributions of source code must retain the above copyright notice, this list of conditions
  13. and the following disclaimer.
  14. Redistributions in binary form must reproduce the above copyright notice,
  15. this list of conditions and the following disclaimer in the documentation
  16. and/or other materials provided with the distribution.
  17. Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
  18. be used to endorse or promote products derived from this software without specific prior written permission.
  19. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  20. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  22. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  24. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  25. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. -----------------------------------------------------------------------*/
  27. // http://codesuppository.blogspot.com
  28. //
  29. // mailto: [email protected]
  30. //
  31. // http://www.amillionpixels.us
  32. //
  33. #include "float_math.h"
  34. #include "cd_wavefront.h"
  35. using namespace ConvexDecomposition;
  36. /*----------------------------------------------------------------------
  37. Copyright (c) 2004 Open Dynamics Framework Group
  38. www.physicstools.org
  39. All rights reserved.
  40. Redistribution and use in source and binary forms, with or without modification, are permitted provided
  41. that the following conditions are met:
  42. Redistributions of source code must retain the above copyright notice, this list of conditions
  43. and the following disclaimer.
  44. Redistributions in binary form must reproduce the above copyright notice,
  45. this list of conditions and the following disclaimer in the documentation
  46. and/or other materials provided with the distribution.
  47. Neither the name of the Open Dynamics Framework Group nor the names of its contributors may
  48. be used to endorse or promote products derived from this software without specific prior written permission.
  49. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 'AS IS' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  50. INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  51. DISCLAIMED. IN NO EVENT SHALL THE INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  52. EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  53. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
  54. IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  55. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  56. -----------------------------------------------------------------------*/
  57. #include <vector>
  58. namespace ConvexDecomposition
  59. {
  60. typedef std::vector< int > IntVector;
  61. typedef std::vector< float > FloatVector;
  62. #if defined(__APPLE__) || defined(__CELLOS_LV2__)
  63. #define stricmp(a, b) strcasecmp((a), (b))
  64. #endif
  65. /*******************************************************************/
  66. /******************** InParser.h ********************************/
  67. /*******************************************************************/
  68. class InPlaceParserInterface
  69. {
  70. public:
  71. virtual ~InPlaceParserInterface () {} ;
  72. virtual int ParseLine(int lineno,int argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
  73. };
  74. enum SeparatorType
  75. {
  76. ST_DATA, // is data
  77. ST_HARD, // is a hard separator
  78. ST_SOFT, // is a soft separator
  79. ST_EOS // is a comment symbol, and everything past this character should be ignored
  80. };
  81. class InPlaceParser
  82. {
  83. public:
  84. InPlaceParser(void)
  85. {
  86. Init();
  87. }
  88. InPlaceParser(char *data,int len)
  89. {
  90. Init();
  91. SetSourceData(data,len);
  92. }
  93. InPlaceParser(const char *fname)
  94. {
  95. Init();
  96. SetFile(fname);
  97. }
  98. ~InPlaceParser(void);
  99. void Init(void)
  100. {
  101. mQuoteChar = 34;
  102. mData = 0;
  103. mLen = 0;
  104. mMyAlloc = false;
  105. for (int i=0; i<256; i++)
  106. {
  107. mHard[i] = ST_DATA;
  108. mHardString[i*2] = i;
  109. mHardString[i*2+1] = 0;
  110. }
  111. mHard[0] = ST_EOS;
  112. mHard[32] = ST_SOFT;
  113. mHard[9] = ST_SOFT;
  114. mHard[13] = ST_SOFT;
  115. mHard[10] = ST_SOFT;
  116. }
  117. void SetFile(const char *fname); // use this file as source data to parse.
  118. void SetSourceData(char *data,int len)
  119. {
  120. mData = data;
  121. mLen = len;
  122. mMyAlloc = false;
  123. };
  124. int Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
  125. int ProcessLine(int lineno,char *line,InPlaceParserInterface *callback);
  126. const char ** GetArglist(char *source,int &count); // convert source string into an arg list, this is a destructive parse.
  127. void SetHardSeparator(char c) // add a hard separator
  128. {
  129. mHard[(int)c] = ST_HARD;
  130. }
  131. void SetHard(char c) // add a hard separator
  132. {
  133. mHard[(int)c] = ST_HARD;
  134. }
  135. void SetCommentSymbol(char c) // comment character, treated as 'end of string'
  136. {
  137. mHard[(int)c] = ST_EOS;
  138. }
  139. void ClearHardSeparator(char c)
  140. {
  141. mHard[(int)c] = ST_DATA;
  142. }
  143. void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
  144. bool EOS(char c)
  145. {
  146. if ( mHard[(int)c] == ST_EOS )
  147. {
  148. return true;
  149. }
  150. return false;
  151. }
  152. void SetQuoteChar(char c)
  153. {
  154. mQuoteChar = c;
  155. }
  156. private:
  157. inline char * AddHard(int &argc,const char **argv,char *foo);
  158. inline bool IsHard(char c);
  159. inline char * SkipSpaces(char *foo);
  160. inline bool IsWhiteSpace(char c);
  161. inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
  162. bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
  163. char *mData; // ascii data to parse.
  164. int mLen; // length of data
  165. SeparatorType mHard[256];
  166. char mHardString[256*2];
  167. char mQuoteChar;
  168. };
  169. /*******************************************************************/
  170. /******************** InParser.cpp ********************************/
  171. /*******************************************************************/
  172. void InPlaceParser::SetFile(const char *fname)
  173. {
  174. if ( mMyAlloc )
  175. {
  176. free(mData);
  177. }
  178. mData = 0;
  179. mLen = 0;
  180. mMyAlloc = false;
  181. FILE *fph = fopen(fname,"rb");
  182. if ( fph )
  183. {
  184. fseek(fph,0L,SEEK_END);
  185. mLen = ftell(fph);
  186. fseek(fph,0L,SEEK_SET);
  187. if ( mLen )
  188. {
  189. mData = (char *) malloc(sizeof(char)*(mLen+1));
  190. int ok = fread(mData, mLen, 1, fph);
  191. if ( !ok )
  192. {
  193. free(mData);
  194. mData = 0;
  195. }
  196. else
  197. {
  198. mData[mLen] = 0; // zero byte terminate end of file marker.
  199. mMyAlloc = true;
  200. }
  201. }
  202. fclose(fph);
  203. }
  204. }
  205. InPlaceParser::~InPlaceParser(void)
  206. {
  207. if ( mMyAlloc )
  208. {
  209. free(mData);
  210. }
  211. }
  212. #define MAXARGS 512
  213. bool InPlaceParser::IsHard(char c)
  214. {
  215. return mHard[(int)c] == ST_HARD;
  216. }
  217. char * InPlaceParser::AddHard(int &argc,const char **argv,char *foo)
  218. {
  219. while ( IsHard(*foo) )
  220. {
  221. const char *hard = &mHardString[*foo*2];
  222. if ( argc < MAXARGS )
  223. {
  224. argv[argc++] = hard;
  225. }
  226. foo++;
  227. }
  228. return foo;
  229. }
  230. bool InPlaceParser::IsWhiteSpace(char c)
  231. {
  232. return mHard[(int)c] == ST_SOFT;
  233. }
  234. char * InPlaceParser::SkipSpaces(char *foo)
  235. {
  236. while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
  237. return foo;
  238. }
  239. bool InPlaceParser::IsNonSeparator(char c)
  240. {
  241. if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
  242. return false;
  243. }
  244. int InPlaceParser::ProcessLine(int lineno,char *line,InPlaceParserInterface *callback)
  245. {
  246. int ret = 0;
  247. const char *argv[MAXARGS];
  248. int argc = 0;
  249. char *foo = line;
  250. while ( !EOS(*foo) && argc < MAXARGS )
  251. {
  252. foo = SkipSpaces(foo); // skip any leading spaces
  253. if ( EOS(*foo) ) break;
  254. if ( *foo == mQuoteChar ) // if it is an open quote
  255. {
  256. foo++;
  257. if ( argc < MAXARGS )
  258. {
  259. argv[argc++] = foo;
  260. }
  261. while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
  262. if ( !EOS(*foo) )
  263. {
  264. *foo = 0; // replace close quote with zero byte EOS
  265. foo++;
  266. }
  267. }
  268. else
  269. {
  270. foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
  271. if ( IsNonSeparator(*foo) ) // add non-hard argument.
  272. {
  273. bool quote = false;
  274. if ( *foo == mQuoteChar )
  275. {
  276. foo++;
  277. quote = true;
  278. }
  279. if ( argc < MAXARGS )
  280. {
  281. argv[argc++] = foo;
  282. }
  283. if ( quote )
  284. {
  285. while (*foo && *foo != mQuoteChar ) foo++;
  286. if ( *foo ) *foo = 32;
  287. }
  288. // continue..until we hit an eos ..
  289. while ( !EOS(*foo) ) // until we hit EOS
  290. {
  291. if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
  292. {
  293. *foo = 0;
  294. foo++;
  295. break;
  296. }
  297. else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
  298. {
  299. const char *hard = &mHardString[*foo*2];
  300. *foo = 0;
  301. if ( argc < MAXARGS )
  302. {
  303. argv[argc++] = hard;
  304. }
  305. foo++;
  306. break;
  307. }
  308. foo++;
  309. } // end of while loop...
  310. }
  311. }
  312. }
  313. if ( argc )
  314. {
  315. ret = callback->ParseLine(lineno, argc, argv );
  316. }
  317. return ret;
  318. }
  319. int InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
  320. {
  321. assert( callback );
  322. if ( !mData ) return 0;
  323. int ret = 0;
  324. int lineno = 0;
  325. char *foo = mData;
  326. char *begin = foo;
  327. while ( *foo )
  328. {
  329. if ( *foo == 10 || *foo == 13 )
  330. {
  331. lineno++;
  332. *foo = 0;
  333. if ( *begin ) // if there is any data to parse at all...
  334. {
  335. int v = ProcessLine(lineno,begin,callback);
  336. if ( v ) ret = v;
  337. }
  338. foo++;
  339. if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
  340. begin = foo;
  341. }
  342. else
  343. {
  344. foo++;
  345. }
  346. }
  347. lineno++; // lasst line.
  348. int v = ProcessLine(lineno,begin,callback);
  349. if ( v ) ret = v;
  350. return ret;
  351. }
  352. void InPlaceParser::DefaultSymbols(void)
  353. {
  354. SetHardSeparator(',');
  355. SetHardSeparator('(');
  356. SetHardSeparator(')');
  357. SetHardSeparator('=');
  358. SetHardSeparator('[');
  359. SetHardSeparator(']');
  360. SetHardSeparator('{');
  361. SetHardSeparator('}');
  362. SetCommentSymbol('#');
  363. }
  364. const char ** InPlaceParser::GetArglist(char *line,int &count) // convert source string into an arg list, this is a destructive parse.
  365. {
  366. const char **ret = 0;
  367. const char *argv[MAXARGS];
  368. int argc = 0;
  369. char *foo = line;
  370. while ( !EOS(*foo) && argc < MAXARGS )
  371. {
  372. foo = SkipSpaces(foo); // skip any leading spaces
  373. if ( EOS(*foo) ) break;
  374. if ( *foo == mQuoteChar ) // if it is an open quote
  375. {
  376. foo++;
  377. if ( argc < MAXARGS )
  378. {
  379. argv[argc++] = foo;
  380. }
  381. while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
  382. if ( !EOS(*foo) )
  383. {
  384. *foo = 0; // replace close quote with zero byte EOS
  385. foo++;
  386. }
  387. }
  388. else
  389. {
  390. foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
  391. if ( IsNonSeparator(*foo) ) // add non-hard argument.
  392. {
  393. bool quote = false;
  394. if ( *foo == mQuoteChar )
  395. {
  396. foo++;
  397. quote = true;
  398. }
  399. if ( argc < MAXARGS )
  400. {
  401. argv[argc++] = foo;
  402. }
  403. if ( quote )
  404. {
  405. while (*foo && *foo != mQuoteChar ) foo++;
  406. if ( *foo ) *foo = 32;
  407. }
  408. // continue..until we hit an eos ..
  409. while ( !EOS(*foo) ) // until we hit EOS
  410. {
  411. if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
  412. {
  413. *foo = 0;
  414. foo++;
  415. break;
  416. }
  417. else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
  418. {
  419. const char *hard = &mHardString[*foo*2];
  420. *foo = 0;
  421. if ( argc < MAXARGS )
  422. {
  423. argv[argc++] = hard;
  424. }
  425. foo++;
  426. break;
  427. }
  428. foo++;
  429. } // end of while loop...
  430. }
  431. }
  432. }
  433. count = argc;
  434. if ( argc )
  435. {
  436. ret = argv;
  437. }
  438. return ret;
  439. }
  440. /*******************************************************************/
  441. /******************** Geometry.h ********************************/
  442. /*******************************************************************/
  443. class GeometryVertex
  444. {
  445. public:
  446. float mPos[3];
  447. float mNormal[3];
  448. float mTexel[2];
  449. };
  450. class GeometryInterface
  451. {
  452. public:
  453. virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3) {}
  454. virtual ~GeometryInterface () {}
  455. };
  456. /*******************************************************************/
  457. /******************** Obj.h ********************************/
  458. /*******************************************************************/
  459. class OBJ : public InPlaceParserInterface
  460. {
  461. public:
  462. int LoadMesh(const char *fname,GeometryInterface *callback);
  463. int ParseLine(int lineno,int argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
  464. private:
  465. void getVertex(GeometryVertex &v,const char *face) const;
  466. FloatVector mVerts;
  467. FloatVector mTexels;
  468. FloatVector mNormals;
  469. GeometryInterface *mCallback;
  470. };
  471. /*******************************************************************/
  472. /******************** Obj.cpp ********************************/
  473. /*******************************************************************/
  474. int OBJ::LoadMesh(const char *fname,GeometryInterface *iface)
  475. {
  476. int ret = 0;
  477. mVerts.clear();
  478. mTexels.clear();
  479. mNormals.clear();
  480. mCallback = iface;
  481. InPlaceParser ipp(fname);
  482. ipp.Parse(this);
  483. return ret;
  484. }
  485. //static const char * GetArg(const char **argv,int i,int argc)
  486. //{
  487. // const char * ret = 0;
  488. // if ( i < argc ) ret = argv[i];
  489. // return ret;
  490. //}
  491. void OBJ::getVertex(GeometryVertex &v,const char *face) const
  492. {
  493. v.mPos[0] = 0;
  494. v.mPos[1] = 0;
  495. v.mPos[2] = 0;
  496. v.mTexel[0] = 0;
  497. v.mTexel[1] = 0;
  498. v.mNormal[0] = 0;
  499. v.mNormal[1] = 1;
  500. v.mNormal[2] = 0;
  501. int index = atoi( face )-1;
  502. const char *texel = strstr(face,"/");
  503. if ( texel )
  504. {
  505. int tindex = atoi( texel+1) - 1;
  506. if ( tindex >=0 && tindex < (int)(mTexels.size()/2) )
  507. {
  508. const float *t = &mTexels[tindex*2];
  509. v.mTexel[0] = t[0];
  510. v.mTexel[1] = t[1];
  511. }
  512. const char *normal = strstr(texel+1,"/");
  513. if ( normal )
  514. {
  515. int nindex = atoi( normal+1 ) - 1;
  516. if (nindex >= 0 && nindex < (int)(mNormals.size()/3) )
  517. {
  518. const float *n = &mNormals[nindex*3];
  519. v.mNormal[0] = n[0];
  520. v.mNormal[1] = n[1];
  521. v.mNormal[2] = n[2];
  522. }
  523. }
  524. }
  525. if ( index >= 0 && index < (int)(mVerts.size()/3) )
  526. {
  527. const float *p = &mVerts[index*3];
  528. v.mPos[0] = p[0];
  529. v.mPos[1] = p[1];
  530. v.mPos[2] = p[2];
  531. }
  532. }
  533. int OBJ::ParseLine(int lineno,int argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
  534. {
  535. int ret = 0;
  536. if ( argc >= 1 )
  537. {
  538. const char *foo = argv[0];
  539. if ( *foo != '#' )
  540. {
  541. if ( strcmp(argv[0],"v") == 0 && argc == 4 )
  542. //if ( stricmp(argv[0],"v") == 0 && argc == 4 )
  543. {
  544. float vx = (float) atof( argv[1] );
  545. float vy = (float) atof( argv[2] );
  546. float vz = (float) atof( argv[3] );
  547. mVerts.push_back(vx);
  548. mVerts.push_back(vy);
  549. mVerts.push_back(vz);
  550. }
  551. else if ( strcmp(argv[0],"vt") == 0 && argc == 3 )
  552. // else if ( stricmp(argv[0],"vt") == 0 && argc == 3 )
  553. {
  554. float tx = (float) atof( argv[1] );
  555. float ty = (float) atof( argv[2] );
  556. mTexels.push_back(tx);
  557. mTexels.push_back(ty);
  558. }
  559. // else if ( stricmp(argv[0],"vn") == 0 && argc == 4 )
  560. else if ( strcmp(argv[0],"vn") == 0 && argc == 4 )
  561. {
  562. float normalx = (float) atof(argv[1]);
  563. float normaly = (float) atof(argv[2]);
  564. float normalz = (float) atof(argv[3]);
  565. mNormals.push_back(normalx);
  566. mNormals.push_back(normaly);
  567. mNormals.push_back(normalz);
  568. }
  569. // else if ( stricmp(argv[0],"f") == 0 && argc >= 4 )
  570. else if ( strcmp(argv[0],"f") == 0 && argc >= 4 )
  571. {
  572. GeometryVertex v[32];
  573. int vcount = argc-1;
  574. for (int i=1; i<argc; i++)
  575. {
  576. getVertex(v[i-1],argv[i] );
  577. }
  578. // need to generate a normal!
  579. #if 0 // not currently implemented
  580. if ( mNormals.empty() )
  581. {
  582. Vector3d<float> p1( v[0].mPos );
  583. Vector3d<float> p2( v[1].mPos );
  584. Vector3d<float> p3( v[2].mPos );
  585. Vector3d<float> n;
  586. n.ComputeNormal(p3,p2,p1);
  587. for (int i=0; i<vcount; i++)
  588. {
  589. v[i].mNormal[0] = n.x;
  590. v[i].mNormal[1] = n.y;
  591. v[i].mNormal[2] = n.z;
  592. }
  593. }
  594. #endif
  595. mCallback->NodeTriangle(&v[0],&v[1],&v[2]);
  596. if ( vcount >=3 ) // do the fan
  597. {
  598. for (int i=2; i<(vcount-1); i++)
  599. {
  600. mCallback->NodeTriangle(&v[0],&v[i],&v[i+1]);
  601. }
  602. }
  603. }
  604. }
  605. }
  606. return ret;
  607. }
  608. class BuildMesh : public GeometryInterface
  609. {
  610. public:
  611. int getIndex(const float *p)
  612. {
  613. int vcount = mVertices.size()/3;
  614. if(vcount>0)
  615. {
  616. //New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
  617. const float *v = &mVertices[0];
  618. for (int i=0; i<vcount; i++)
  619. {
  620. if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] ) return i;
  621. v+=3;
  622. }
  623. }
  624. mVertices.push_back( p[0] );
  625. mVertices.push_back( p[1] );
  626. mVertices.push_back( p[2] );
  627. return vcount;
  628. }
  629. virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3)
  630. {
  631. mIndices.push_back( getIndex(v1->mPos) );
  632. mIndices.push_back( getIndex(v2->mPos) );
  633. mIndices.push_back( getIndex(v3->mPos) );
  634. }
  635. const FloatVector& GetVertices(void) const { return mVertices; };
  636. const IntVector& GetIndices(void) const { return mIndices; };
  637. private:
  638. FloatVector mVertices;
  639. IntVector mIndices;
  640. };
  641. WavefrontObj::WavefrontObj(void)
  642. {
  643. mVertexCount = 0;
  644. mTriCount = 0;
  645. mIndices = 0;
  646. mVertices = 0;
  647. }
  648. WavefrontObj::~WavefrontObj(void)
  649. {
  650. delete [] mIndices;
  651. delete [] mVertices;
  652. }
  653. 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.
  654. {
  655. unsigned int ret = 0;
  656. delete [] mVertices;
  657. mVertices = 0;
  658. delete [] mIndices;
  659. mIndices = 0;
  660. mVertexCount = 0;
  661. mTriCount = 0;
  662. BuildMesh bm;
  663. OBJ obj;
  664. obj.LoadMesh(fname,&bm);
  665. const FloatVector &vlist = bm.GetVertices();
  666. const IntVector &indices = bm.GetIndices();
  667. if ( vlist.size() )
  668. {
  669. mVertexCount = vlist.size()/3;
  670. mVertices = new float[mVertexCount*3];
  671. memcpy( mVertices, &vlist[0], sizeof(float)*mVertexCount*3 );
  672. mTriCount = indices.size()/3;
  673. mIndices = new int[mTriCount*3*sizeof(int)];
  674. memcpy(mIndices, &indices[0], sizeof(int)*mTriCount*3);
  675. ret = mTriCount;
  676. }
  677. return ret;
  678. }
  679. }