2
0

wavefront.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852
  1. /*
  2. wavefront.cpp : A very small code snippet to read a Wavefront OBJ file into memory.
  3. */
  4. /*!
  5. **
  6. ** Copyright (c) 2009 by John W. Ratcliff mailto:[email protected]
  7. **
  8. ** Portions of this source has been released with the PhysXViewer application, as well as
  9. ** Rocket, CreateDynamics, ODF, and as a number of sample code snippets.
  10. **
  11. ** If you find this code useful or you are feeling particularily generous I would
  12. ** ask that you please go to http://www.amillionpixels.us and make a donation
  13. ** to Troy DeMolay.
  14. **
  15. ** DeMolay is a youth group for young men between the ages of 12 and 21.
  16. ** It teaches strong moral principles, as well as leadership skills and
  17. ** public speaking. The donations page uses the 'pay for pixels' paradigm
  18. ** where, in this case, a pixel is only a single penny. Donations can be
  19. ** made for as small as $4 or as high as a $100 block. Each person who donates
  20. ** will get a link to their own site as well as acknowledgement on the
  21. ** donations blog located here http://www.amillionpixels.blogspot.com/
  22. **
  23. ** If you wish to contact me you can use the following methods:
  24. **
  25. ** Skype ID: jratcliff63367
  26. ** Yahoo: jratcliff63367
  27. ** AOL: jratcliff1961
  28. ** email: [email protected]
  29. **
  30. **
  31. ** The MIT license:
  32. **
  33. ** Permission is hereby granted, free of charge, to any person obtaining a copy
  34. ** of this software and associated documentation files (the "Software"), to deal
  35. ** in the Software without restriction, including without limitation the rights
  36. ** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  37. ** copies of the Software, and to permit persons to whom the Software is furnished
  38. ** to do so, subject to the following conditions:
  39. **
  40. ** The above copyright notice and this permission notice shall be included in all
  41. ** copies or substantial portions of the Software.
  42. ** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  43. ** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  44. ** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  45. ** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  46. ** WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
  47. ** CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  48. */
  49. #ifndef __PPCGEKKO__
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include <string.h>
  53. #include <assert.h>
  54. #include <ctype.h>
  55. #include "wavefront.h"
  56. #include <vector>
  57. typedef std::vector< NxI32 > IntVector;
  58. typedef std::vector< NxF32 > FloatVector;
  59. #pragma warning(disable:4996)
  60. namespace WAVEFRONT
  61. {
  62. /*******************************************************************/
  63. /******************** InParser.h ********************************/
  64. /*******************************************************************/
  65. class InPlaceParserInterface
  66. {
  67. public:
  68. virtual NxI32 ParseLine(NxI32 lineno,NxI32 argc,const char **argv) =0; // return TRUE to continue parsing, return FALSE to abort parsing process
  69. };
  70. enum SeparatorType
  71. {
  72. ST_DATA, // is data
  73. ST_HARD, // is a hard separator
  74. ST_SOFT, // is a soft separator
  75. ST_EOS // is a comment symbol, and everything past this character should be ignored
  76. };
  77. class InPlaceParser
  78. {
  79. public:
  80. InPlaceParser(void)
  81. {
  82. Init();
  83. }
  84. InPlaceParser(char *data,NxI32 len)
  85. {
  86. Init();
  87. SetSourceData(data,len);
  88. }
  89. InPlaceParser(const char *fname)
  90. {
  91. Init();
  92. SetFile(fname);
  93. }
  94. ~InPlaceParser(void);
  95. void Init(void)
  96. {
  97. mQuoteChar = 34;
  98. mData = 0;
  99. mLen = 0;
  100. mMyAlloc = false;
  101. for (NxI32 i=0; i<256; i++)
  102. {
  103. mHard[i] = ST_DATA;
  104. mHardString[i*2] = i;
  105. mHardString[i*2+1] = 0;
  106. }
  107. mHard[0] = ST_EOS;
  108. mHard[32] = ST_SOFT;
  109. mHard[9] = ST_SOFT;
  110. mHard[13] = ST_SOFT;
  111. mHard[10] = ST_SOFT;
  112. }
  113. void SetFile(const char *fname); // use this file as source data to parse.
  114. void SetSourceData(char *data,NxI32 len)
  115. {
  116. mData = data;
  117. mLen = len;
  118. mMyAlloc = false;
  119. };
  120. NxI32 Parse(InPlaceParserInterface *callback); // returns true if entire file was parsed, false if it aborted for some reason
  121. NxI32 ProcessLine(NxI32 lineno,char *line,InPlaceParserInterface *callback);
  122. const char ** GetArglist(char *source,NxI32 &count); // convert source string into an arg list, this is a destructive parse.
  123. void SetHardSeparator(char c) // add a hard separator
  124. {
  125. mHard[c] = ST_HARD;
  126. }
  127. void SetHard(char c) // add a hard separator
  128. {
  129. mHard[c] = ST_HARD;
  130. }
  131. void SetCommentSymbol(char c) // comment character, treated as 'end of string'
  132. {
  133. mHard[c] = ST_EOS;
  134. }
  135. void ClearHardSeparator(char c)
  136. {
  137. mHard[c] = ST_DATA;
  138. }
  139. void DefaultSymbols(void); // set up default symbols for hard seperator and comment symbol of the '#' character.
  140. bool EOS(char c)
  141. {
  142. if ( mHard[c] == ST_EOS )
  143. {
  144. return true;
  145. }
  146. return false;
  147. }
  148. void SetQuoteChar(char c)
  149. {
  150. mQuoteChar = c;
  151. }
  152. private:
  153. inline char * AddHard(NxI32 &argc,const char **argv,char *foo);
  154. inline bool IsHard(char c);
  155. inline char * SkipSpaces(char *foo);
  156. inline bool IsWhiteSpace(char c);
  157. inline bool IsNonSeparator(char c); // non seperator,neither hard nor soft
  158. bool mMyAlloc; // whether or not *I* allocated the buffer and am responsible for deleting it.
  159. char *mData; // ascii data to parse.
  160. NxI32 mLen; // length of data
  161. SeparatorType mHard[256];
  162. char mHardString[256*2];
  163. char mQuoteChar;
  164. };
  165. /*******************************************************************/
  166. /******************** InParser.cpp ********************************/
  167. /*******************************************************************/
  168. void InPlaceParser::SetFile(const char *fname)
  169. {
  170. if ( mMyAlloc )
  171. {
  172. free(mData);
  173. }
  174. mData = 0;
  175. mLen = 0;
  176. mMyAlloc = false;
  177. FILE *fph = fopen(fname,"rb");
  178. if ( fph )
  179. {
  180. fseek(fph,0L,SEEK_END);
  181. mLen = ftell(fph);
  182. fseek(fph,0L,SEEK_SET);
  183. if ( mLen )
  184. {
  185. mData = (char *) malloc(sizeof(char)*(mLen+1));
  186. size_t ok = fread(mData, mLen, 1, fph);
  187. if ( !ok )
  188. {
  189. free(mData);
  190. mData = 0;
  191. }
  192. else
  193. {
  194. mData[mLen] = 0; // zero byte terminate end of file marker.
  195. mMyAlloc = true;
  196. }
  197. }
  198. fclose(fph);
  199. }
  200. }
  201. InPlaceParser::~InPlaceParser(void)
  202. {
  203. if ( mMyAlloc )
  204. {
  205. free(mData);
  206. }
  207. }
  208. #define MAXARGS 512
  209. bool InPlaceParser::IsHard(char c)
  210. {
  211. return mHard[c] == ST_HARD;
  212. }
  213. char * InPlaceParser::AddHard(NxI32 &argc,const char **argv,char *foo)
  214. {
  215. while ( IsHard(*foo) )
  216. {
  217. const char *hard = &mHardString[*foo*2];
  218. if ( argc < MAXARGS )
  219. {
  220. argv[argc++] = hard;
  221. }
  222. foo++;
  223. }
  224. return foo;
  225. }
  226. bool InPlaceParser::IsWhiteSpace(char c)
  227. {
  228. return mHard[c] == ST_SOFT;
  229. }
  230. char * InPlaceParser::SkipSpaces(char *foo)
  231. {
  232. while ( !EOS(*foo) && IsWhiteSpace(*foo) ) foo++;
  233. return foo;
  234. }
  235. bool InPlaceParser::IsNonSeparator(char c)
  236. {
  237. if ( !IsHard(c) && !IsWhiteSpace(c) && c != 0 ) return true;
  238. return false;
  239. }
  240. NxI32 InPlaceParser::ProcessLine(NxI32 lineno,char *line,InPlaceParserInterface *callback)
  241. {
  242. NxI32 ret = 0;
  243. const char *argv[MAXARGS];
  244. NxI32 argc = 0;
  245. char *foo = line;
  246. while ( !EOS(*foo) && argc < MAXARGS )
  247. {
  248. foo = SkipSpaces(foo); // skip any leading spaces
  249. if ( EOS(*foo) ) break;
  250. if ( *foo == mQuoteChar ) // if it is an open quote
  251. {
  252. foo++;
  253. if ( argc < MAXARGS )
  254. {
  255. argv[argc++] = foo;
  256. }
  257. while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
  258. if ( !EOS(*foo) )
  259. {
  260. *foo = 0; // replace close quote with zero byte EOS
  261. foo++;
  262. }
  263. }
  264. else
  265. {
  266. foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
  267. if ( IsNonSeparator(*foo) ) // add non-hard argument.
  268. {
  269. bool quote = false;
  270. if ( *foo == mQuoteChar )
  271. {
  272. foo++;
  273. quote = true;
  274. }
  275. if ( argc < MAXARGS )
  276. {
  277. argv[argc++] = foo;
  278. }
  279. if ( quote )
  280. {
  281. while (*foo && *foo != mQuoteChar ) foo++;
  282. if ( *foo ) *foo = 32;
  283. }
  284. // continue..until we hit an eos ..
  285. while ( !EOS(*foo) ) // until we hit EOS
  286. {
  287. if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
  288. {
  289. *foo = 0;
  290. foo++;
  291. break;
  292. }
  293. else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
  294. {
  295. const char *hard = &mHardString[*foo*2];
  296. *foo = 0;
  297. if ( argc < MAXARGS )
  298. {
  299. argv[argc++] = hard;
  300. }
  301. foo++;
  302. break;
  303. }
  304. foo++;
  305. } // end of while loop...
  306. }
  307. }
  308. }
  309. if ( argc )
  310. {
  311. ret = callback->ParseLine(lineno, argc, argv );
  312. }
  313. return ret;
  314. }
  315. NxI32 InPlaceParser::Parse(InPlaceParserInterface *callback) // returns true if entire file was parsed, false if it aborted for some reason
  316. {
  317. assert( callback );
  318. if ( !mData ) return 0;
  319. NxI32 ret = 0;
  320. NxI32 lineno = 0;
  321. char *foo = mData;
  322. char *begin = foo;
  323. while ( *foo )
  324. {
  325. if ( *foo == 10 || *foo == 13 )
  326. {
  327. lineno++;
  328. *foo = 0;
  329. if ( *begin ) // if there is any data to parse at all...
  330. {
  331. NxI32 v = ProcessLine(lineno,begin,callback);
  332. if ( v ) ret = v;
  333. }
  334. foo++;
  335. if ( *foo == 10 ) foo++; // skip line feed, if it is in the carraige-return line-feed format...
  336. begin = foo;
  337. }
  338. else
  339. {
  340. foo++;
  341. }
  342. }
  343. lineno++; // lasst line.
  344. NxI32 v = ProcessLine(lineno,begin,callback);
  345. if ( v ) ret = v;
  346. return ret;
  347. }
  348. void InPlaceParser::DefaultSymbols(void)
  349. {
  350. SetHardSeparator(',');
  351. SetHardSeparator('(');
  352. SetHardSeparator(')');
  353. SetHardSeparator('=');
  354. SetHardSeparator('[');
  355. SetHardSeparator(']');
  356. SetHardSeparator('{');
  357. SetHardSeparator('}');
  358. SetCommentSymbol('#');
  359. }
  360. const char ** InPlaceParser::GetArglist(char *line,NxI32 &count) // convert source string into an arg list, this is a destructive parse.
  361. {
  362. const char **ret = 0;
  363. static const char *argv[MAXARGS];
  364. NxI32 argc = 0;
  365. char *foo = line;
  366. while ( !EOS(*foo) && argc < MAXARGS )
  367. {
  368. foo = SkipSpaces(foo); // skip any leading spaces
  369. if ( EOS(*foo) ) break;
  370. if ( *foo == mQuoteChar ) // if it is an open quote
  371. {
  372. foo++;
  373. if ( argc < MAXARGS )
  374. {
  375. argv[argc++] = foo;
  376. }
  377. while ( !EOS(*foo) && *foo != mQuoteChar ) foo++;
  378. if ( !EOS(*foo) )
  379. {
  380. *foo = 0; // replace close quote with zero byte EOS
  381. foo++;
  382. }
  383. }
  384. else
  385. {
  386. foo = AddHard(argc,argv,foo); // add any hard separators, skip any spaces
  387. if ( IsNonSeparator(*foo) ) // add non-hard argument.
  388. {
  389. bool quote = false;
  390. if ( *foo == mQuoteChar )
  391. {
  392. foo++;
  393. quote = true;
  394. }
  395. if ( argc < MAXARGS )
  396. {
  397. argv[argc++] = foo;
  398. }
  399. if ( quote )
  400. {
  401. while (*foo && *foo != mQuoteChar ) foo++;
  402. if ( *foo ) *foo = 32;
  403. }
  404. // continue..until we hit an eos ..
  405. while ( !EOS(*foo) ) // until we hit EOS
  406. {
  407. if ( IsWhiteSpace(*foo) ) // if we hit a space, stomp a zero byte, and exit
  408. {
  409. *foo = 0;
  410. foo++;
  411. break;
  412. }
  413. else if ( IsHard(*foo) ) // if we hit a hard separator, stomp a zero byte and store the hard separator argument
  414. {
  415. const char *hard = &mHardString[*foo*2];
  416. *foo = 0;
  417. if ( argc < MAXARGS )
  418. {
  419. argv[argc++] = hard;
  420. }
  421. foo++;
  422. break;
  423. }
  424. foo++;
  425. } // end of while loop...
  426. }
  427. }
  428. }
  429. count = argc;
  430. if ( argc )
  431. {
  432. ret = argv;
  433. }
  434. return ret;
  435. }
  436. /*******************************************************************/
  437. /******************** Geometry.h ********************************/
  438. /*******************************************************************/
  439. class GeometryVertex
  440. {
  441. public:
  442. NxF32 mPos[3];
  443. NxF32 mNormal[3];
  444. NxF32 mTexel[2];
  445. };
  446. class GeometryInterface
  447. {
  448. public:
  449. virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured)
  450. {
  451. }
  452. };
  453. /*******************************************************************/
  454. /******************** Obj.h ********************************/
  455. /*******************************************************************/
  456. class OBJ : public InPlaceParserInterface
  457. {
  458. public:
  459. NxI32 LoadMesh(const char *fname,GeometryInterface *callback, bool textured);
  460. NxI32 ParseLine(NxI32 lineno,NxI32 argc,const char **argv); // return TRUE to continue parsing, return FALSE to abort parsing process
  461. private:
  462. void GetVertex(GeometryVertex &v,const char *face) const;
  463. FloatVector mVerts;
  464. FloatVector mTexels;
  465. FloatVector mNormals;
  466. bool mTextured;
  467. GeometryInterface *mCallback;
  468. };
  469. /*******************************************************************/
  470. /******************** Obj.cpp ********************************/
  471. /*******************************************************************/
  472. NxI32 OBJ::LoadMesh(const char *fname,GeometryInterface *iface, bool textured)
  473. {
  474. mTextured = textured;
  475. NxI32 ret = 0;
  476. mVerts.clear();
  477. mTexels.clear();
  478. mNormals.clear();
  479. mCallback = iface;
  480. InPlaceParser ipp(fname);
  481. ipp.Parse(this);
  482. return ret;
  483. }
  484. static const char * GetArg(const char **argv,NxI32 i,NxI32 argc)
  485. {
  486. const char * ret = 0;
  487. if ( i < argc ) ret = argv[i];
  488. return ret;
  489. }
  490. void OBJ::GetVertex(GeometryVertex &v,const char *face) const
  491. {
  492. v.mPos[0] = 0;
  493. v.mPos[1] = 0;
  494. v.mPos[2] = 0;
  495. v.mTexel[0] = 0;
  496. v.mTexel[1] = 0;
  497. v.mNormal[0] = 0;
  498. v.mNormal[1] = 1;
  499. v.mNormal[2] = 0;
  500. NxI32 index = atoi( face )-1;
  501. const char *texel = strstr(face,"/");
  502. if ( texel )
  503. {
  504. NxI32 tindex = atoi( texel+1) - 1;
  505. if ( tindex >=0 && tindex < (NxI32)(mTexels.size()/2) )
  506. {
  507. const NxF32 *t = &mTexels[tindex*2];
  508. v.mTexel[0] = t[0];
  509. v.mTexel[1] = t[1];
  510. }
  511. const char *normal = strstr(texel+1,"/");
  512. if ( normal )
  513. {
  514. NxI32 nindex = atoi( normal+1 ) - 1;
  515. if (nindex >= 0 && nindex < (NxI32)(mNormals.size()/3) )
  516. {
  517. const NxF32 *n = &mNormals[nindex*3];
  518. v.mNormal[0] = n[0];
  519. v.mNormal[1] = n[1];
  520. v.mNormal[2] = n[2];
  521. }
  522. }
  523. }
  524. if ( index >= 0 && index < (NxI32)(mVerts.size()/3) )
  525. {
  526. const NxF32 *p = &mVerts[index*3];
  527. v.mPos[0] = p[0];
  528. v.mPos[1] = p[1];
  529. v.mPos[2] = p[2];
  530. }
  531. }
  532. NxI32 OBJ::ParseLine(NxI32 lineno,NxI32 argc,const char **argv) // return TRUE to continue parsing, return FALSE to abort parsing process
  533. {
  534. NxI32 ret = 0;
  535. if ( argc >= 1 )
  536. {
  537. const char *foo = argv[0];
  538. if ( *foo != '#' )
  539. {
  540. if ( _stricmp(argv[0],"v") == 0 && argc == 4 )
  541. {
  542. NxF32 vx = (NxF32) atof( argv[1] );
  543. NxF32 vy = (NxF32) atof( argv[2] );
  544. NxF32 vz = (NxF32) atof( argv[3] );
  545. mVerts.push_back(vx);
  546. mVerts.push_back(vy);
  547. mVerts.push_back(vz);
  548. }
  549. else if ( _stricmp(argv[0],"vt") == 0 && (argc == 3 || argc == 4))
  550. {
  551. // ignore 4rd component if present
  552. NxF32 tx = (NxF32) atof( argv[1] );
  553. NxF32 ty = (NxF32) atof( argv[2] );
  554. mTexels.push_back(tx);
  555. mTexels.push_back(ty);
  556. }
  557. else if ( _stricmp(argv[0],"vn") == 0 && argc == 4 )
  558. {
  559. NxF32 normalx = (NxF32) atof(argv[1]);
  560. NxF32 normaly = (NxF32) atof(argv[2]);
  561. NxF32 normalz = (NxF32) atof(argv[3]);
  562. mNormals.push_back(normalx);
  563. mNormals.push_back(normaly);
  564. mNormals.push_back(normalz);
  565. }
  566. else if ( _stricmp(argv[0],"f") == 0 && argc >= 4 )
  567. {
  568. GeometryVertex v[32];
  569. NxI32 vcount = argc-1;
  570. for (NxI32 i=1; i<argc; i++)
  571. {
  572. GetVertex(v[i-1],argv[i] );
  573. }
  574. mCallback->NodeTriangle(&v[0],&v[1],&v[2], mTextured);
  575. if ( vcount >=3 ) // do the fan
  576. {
  577. for (NxI32 i=2; i<(vcount-1); i++)
  578. {
  579. mCallback->NodeTriangle(&v[0],&v[i],&v[i+1], mTextured);
  580. }
  581. }
  582. }
  583. }
  584. }
  585. return ret;
  586. }
  587. class BuildMesh : public GeometryInterface
  588. {
  589. public:
  590. NxI32 GetIndex(const NxF32 *p, const NxF32 *texCoord)
  591. {
  592. NxI32 vcount = (NxI32)mVertices.size()/3;
  593. if(vcount>0)
  594. {
  595. //New MS STL library checks indices in debug build, so zero causes an assert if it is empty.
  596. const NxF32 *v = &mVertices[0];
  597. const NxF32 *t = texCoord != NULL ? &mTexCoords[0] : NULL;
  598. for (NxI32 i=0; i<vcount; i++)
  599. {
  600. if ( v[0] == p[0] && v[1] == p[1] && v[2] == p[2] )
  601. {
  602. if (texCoord == NULL || (t[0] == texCoord[0] && t[1] == texCoord[1]))
  603. {
  604. return i;
  605. }
  606. }
  607. v+=3;
  608. if (t != NULL)
  609. t += 2;
  610. }
  611. }
  612. mVertices.push_back( p[0] );
  613. mVertices.push_back( p[1] );
  614. mVertices.push_back( p[2] );
  615. if (texCoord != NULL)
  616. {
  617. mTexCoords.push_back( texCoord[0] );
  618. mTexCoords.push_back( texCoord[1] );
  619. }
  620. return vcount;
  621. }
  622. virtual void NodeTriangle(const GeometryVertex *v1,const GeometryVertex *v2,const GeometryVertex *v3, bool textured)
  623. {
  624. mIndices.push_back( GetIndex(v1->mPos, textured ? v1->mTexel : NULL) );
  625. mIndices.push_back( GetIndex(v2->mPos, textured ? v2->mTexel : NULL) );
  626. mIndices.push_back( GetIndex(v3->mPos, textured ? v3->mTexel : NULL) );
  627. }
  628. const FloatVector& GetVertices(void) const { return mVertices; };
  629. const FloatVector& GetTexCoords(void) const { return mTexCoords; };
  630. const IntVector& GetIndices(void) const { return mIndices; };
  631. private:
  632. FloatVector mVertices;
  633. FloatVector mTexCoords;
  634. IntVector mIndices;
  635. };
  636. };
  637. using namespace WAVEFRONT;
  638. WavefrontObj::WavefrontObj(void)
  639. {
  640. mVertexCount = 0;
  641. mTriCount = 0;
  642. mIndices = 0;
  643. mVertices = NULL;
  644. mTexCoords = NULL;
  645. }
  646. WavefrontObj::~WavefrontObj(void)
  647. {
  648. delete mIndices;
  649. delete mVertices;
  650. }
  651. NxU32 WavefrontObj::loadObj(const char *fname, bool textured) // load a wavefront obj returns number of triangles that were loaded. Data is persists until the class is destructed.
  652. {
  653. NxU32 ret = 0;
  654. delete mVertices;
  655. mVertices = 0;
  656. delete mIndices;
  657. mIndices = 0;
  658. mVertexCount = 0;
  659. mTriCount = 0;
  660. BuildMesh bm;
  661. OBJ obj;
  662. obj.LoadMesh(fname,&bm, textured);
  663. const FloatVector &vlist = bm.GetVertices();
  664. const IntVector &indices = bm.GetIndices();
  665. if ( vlist.size() )
  666. {
  667. mVertexCount = (NxI32)vlist.size()/3;
  668. mVertices = new NxF32[mVertexCount*3];
  669. memcpy( mVertices, &vlist[0], sizeof(NxF32)*mVertexCount*3 );
  670. if (textured)
  671. {
  672. mTexCoords = new NxF32[mVertexCount * 2];
  673. const FloatVector& tList = bm.GetTexCoords();
  674. memcpy( mTexCoords, &tList[0], sizeof(NxF32) * mVertexCount * 2);
  675. }
  676. mTriCount = (NxI32)indices.size()/3;
  677. mIndices = new NxU32[mTriCount*3*sizeof(NxU32)];
  678. memcpy(mIndices, &indices[0], sizeof(NxU32)*mTriCount*3);
  679. ret = mTriCount;
  680. }
  681. return ret;
  682. }
  683. #endif