fast_obj.h 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397
  1. /*
  2. *
  3. * MIT License
  4. *
  5. * Copyright (c) 2018 Richard Knight
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to deal
  9. * in the Software without restriction, including without limitation the rights
  10. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  11. * copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in all
  15. * copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  22. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  23. * SOFTWARE.
  24. *
  25. */
  26. #ifndef FAST_OBJ_HDR
  27. #define FAST_OBJ_HDR
  28. typedef struct
  29. {
  30. /* Texture name from .mtl file */
  31. char* name;
  32. /* Resolved path to texture */
  33. char* path;
  34. } fastObjTexture;
  35. typedef struct
  36. {
  37. /* Material name */
  38. char* name;
  39. /* Parameters */
  40. float Ka[3]; /* Ambient */
  41. float Kd[3]; /* Diffuse */
  42. float Ks[3]; /* Specular */
  43. float Ke[3]; /* Emission */
  44. float Kt[3]; /* Transmittance */
  45. float Ns; /* Shininess */
  46. float Ni; /* Index of refraction */
  47. float Tf[3]; /* Transmission filter */
  48. float d; /* Disolve (alpha) */
  49. int illum; /* Illumination model */
  50. /* Texture maps */
  51. fastObjTexture map_Ka;
  52. fastObjTexture map_Kd;
  53. fastObjTexture map_Ks;
  54. fastObjTexture map_Ke;
  55. fastObjTexture map_Kt;
  56. fastObjTexture map_Ns;
  57. fastObjTexture map_Ni;
  58. fastObjTexture map_d;
  59. fastObjTexture map_bump;
  60. } fastObjMaterial;
  61. typedef struct
  62. {
  63. unsigned int p;
  64. unsigned int t;
  65. unsigned int n;
  66. } fastObjIndex;
  67. typedef struct
  68. {
  69. /* Group name */
  70. char* name;
  71. /* Number of faces */
  72. unsigned int face_count;
  73. /* First face in fastObjMesh face_* arrays */
  74. unsigned int face_offset;
  75. /* First index in fastObjMesh indices array */
  76. unsigned int index_offset;
  77. } fastObjGroup;
  78. typedef struct
  79. {
  80. /* Vertex data */
  81. unsigned int position_count;
  82. float* positions;
  83. unsigned int texcoord_count;
  84. float* texcoords;
  85. unsigned int normal_count;
  86. float* normals;
  87. /* Face data: one element for each face */
  88. unsigned int face_count;
  89. unsigned int* face_vertices;
  90. unsigned int* face_materials;
  91. /* Index data: one element for each face vertex */
  92. fastObjIndex* indices;
  93. /* Materials */
  94. unsigned int material_count;
  95. fastObjMaterial* materials;
  96. /* Mesh groups */
  97. unsigned int group_count;
  98. fastObjGroup* groups;
  99. } fastObjMesh;
  100. fastObjMesh* fast_obj_read(const char* path);
  101. void fast_obj_destroy(fastObjMesh* mesh);
  102. #endif
  103. #ifdef FAST_OBJ_IMPLEMENTATION
  104. #include <stdio.h>
  105. #include <stdlib.h>
  106. #include <string.h>
  107. #ifndef FAST_OBJ_REALLOC
  108. #define FAST_OBJ_REALLOC realloc
  109. #endif
  110. #ifndef FAST_OBJ_FREE
  111. #define FAST_OBJ_FREE free
  112. #endif
  113. #ifdef _WIN32
  114. #define FAST_OBJ_SEPARATOR '\\'
  115. #define FAST_OBJ_OTHER_SEP '/'
  116. #else
  117. #define FAST_OBJ_SEPARATOR '/'
  118. #define FAST_OBJ_OTHER_SEP '\\'
  119. #endif
  120. /* Size of buffer to read into */
  121. #define BUFFER_SIZE 65536
  122. /* Max supported power when parsing float */
  123. #define MAX_POWER 20
  124. typedef struct
  125. {
  126. /* Final mesh */
  127. fastObjMesh* mesh;
  128. /* Current group */
  129. fastObjGroup group;
  130. /* Current material index */
  131. unsigned int material;
  132. /* Current line in file */
  133. unsigned int line;
  134. /* Base path for materials/textures */
  135. char* base;
  136. } fastObjData;
  137. static const
  138. double POWER_10_POS[MAX_POWER] =
  139. {
  140. 1.0e0, 1.0e1, 1.0e2, 1.0e3, 1.0e4, 1.0e5, 1.0e6, 1.0e7, 1.0e8, 1.0e9,
  141. 1.0e10, 1.0e11, 1.0e12, 1.0e13, 1.0e14, 1.0e15, 1.0e16, 1.0e17, 1.0e18, 1.0e19,
  142. };
  143. static const
  144. double POWER_10_NEG[MAX_POWER] =
  145. {
  146. 1.0e0, 1.0e-1, 1.0e-2, 1.0e-3, 1.0e-4, 1.0e-5, 1.0e-6, 1.0e-7, 1.0e-8, 1.0e-9,
  147. 1.0e-10, 1.0e-11, 1.0e-12, 1.0e-13, 1.0e-14, 1.0e-15, 1.0e-16, 1.0e-17, 1.0e-18, 1.0e-19,
  148. };
  149. static
  150. void* memory_realloc(void* ptr, size_t bytes)
  151. {
  152. return FAST_OBJ_REALLOC(ptr, bytes);
  153. }
  154. static
  155. void memory_dealloc(void* ptr)
  156. {
  157. FAST_OBJ_FREE(ptr);
  158. }
  159. #define array_clean(_arr) ((_arr) ? memory_dealloc(_array_header(_arr)), 0 : 0)
  160. #define array_push(_arr, _val) (_array_mgrow(_arr, 1) ? ((_arr)[_array_size(_arr)++] = (_val), _array_size(_arr) - 1) : 0)
  161. #define array_size(_arr) ((_arr) ? _array_size(_arr) : 0)
  162. #define array_capacity(_arr) ((_arr) ? _array_capacity(_arr) : 0)
  163. #define array_empty(_arr) (array_size(_arr) == 0)
  164. #define _array_header(_arr) ((unsigned int*)(_arr) - 2)
  165. #define _array_size(_arr) (_array_header(_arr)[0])
  166. #define _array_capacity(_arr) (_array_header(_arr)[1])
  167. #define _array_ngrow(_arr, _n) ((_arr) == 0 || (_array_size(_arr) + (_n) >= _array_capacity(_arr)))
  168. #define _array_mgrow(_arr, _n) (_array_ngrow(_arr, _n) ? (_array_grow(_arr, _n) != 0) : 1)
  169. #define _array_grow(_arr, _n) (*((void**)&(_arr)) = array_realloc(_arr, _n, sizeof(*(_arr))))
  170. static
  171. void* array_realloc(void* ptr, unsigned int n, unsigned int b)
  172. {
  173. unsigned int sz = array_size(ptr);
  174. unsigned int nsz = sz + n;
  175. unsigned int cap = array_capacity(ptr);
  176. unsigned int ncap = 3 * cap / 2;
  177. unsigned int* r;
  178. if (ncap < nsz)
  179. ncap = nsz;
  180. ncap = (ncap + 15) & ~15u;
  181. r = (unsigned int*)(memory_realloc(ptr ? _array_header(ptr) : 0, b * ncap + 2 * sizeof(unsigned int)));
  182. if (!r)
  183. return 0;
  184. r[0] = sz;
  185. r[1] = ncap;
  186. return (r + 2);
  187. }
  188. static
  189. void* file_open(const char* path)
  190. {
  191. return fopen(path, "rb");
  192. }
  193. static
  194. void file_close(void* file)
  195. {
  196. FILE* f;
  197. f = (FILE*)(file);
  198. fclose(f);
  199. }
  200. static
  201. size_t file_read(void* file, void* dst, size_t bytes)
  202. {
  203. FILE* f;
  204. f = (FILE*)(file);
  205. return fread(dst, 1, bytes, f);
  206. }
  207. static
  208. unsigned long file_size(void* file)
  209. {
  210. FILE* f;
  211. long p;
  212. long n;
  213. f = (FILE*)(file);
  214. p = ftell(f);
  215. fseek(f, 0, SEEK_END);
  216. n = ftell(f);
  217. fseek(f, p, SEEK_SET);
  218. if (n > 0)
  219. return (unsigned long)(n);
  220. else
  221. return 0;
  222. }
  223. static
  224. char* string_copy(const char* s, const char* e)
  225. {
  226. size_t n;
  227. char* p;
  228. n = (size_t)(e - s);
  229. p = (char*)(memory_realloc(0, n + 1));
  230. if (p)
  231. {
  232. memcpy(p, s, n);
  233. p[n] = '\0';
  234. }
  235. return p;
  236. }
  237. static
  238. char* string_substr(const char* s, size_t a, size_t b)
  239. {
  240. return string_copy(s + a, s + b);
  241. }
  242. static
  243. char* string_concat(const char* a, const char* s, const char* e)
  244. {
  245. size_t an;
  246. size_t sn;
  247. char* p;
  248. an = a ? strlen(a) : 0;
  249. sn = (size_t)(e - s);
  250. p = (char*)(memory_realloc(0, an + sn + 1));
  251. if (p)
  252. {
  253. if (a)
  254. memcpy(p, a, an);
  255. memcpy(p + an, s, sn);
  256. p[an + sn] = '\0';
  257. }
  258. return p;
  259. }
  260. static
  261. int string_equal(const char* a, const char* s, const char* e)
  262. {
  263. while (*a++ == *s++ && s != e)
  264. ;
  265. return (*a == '\0' && s == e);
  266. }
  267. static
  268. int string_find_last(const char* s, char c, size_t* p)
  269. {
  270. const char* e;
  271. e = s + strlen(s);
  272. while (e > s)
  273. {
  274. e--;
  275. if (*e == c)
  276. {
  277. *p = (size_t)(e - s);
  278. return 1;
  279. }
  280. }
  281. return 0;
  282. }
  283. static
  284. void string_fix_separators(char* s)
  285. {
  286. while (*s)
  287. {
  288. if (*s == FAST_OBJ_OTHER_SEP)
  289. *s = FAST_OBJ_SEPARATOR;
  290. s++;
  291. }
  292. }
  293. static
  294. int is_whitespace(char c)
  295. {
  296. return (c == ' ' || c == '\t' || c == '\r');
  297. }
  298. static
  299. int is_newline(char c)
  300. {
  301. return (c == '\n');
  302. }
  303. static
  304. int is_digit(char c)
  305. {
  306. return (c >= '0' && c <= '9');
  307. }
  308. static
  309. int is_exponent(char c)
  310. {
  311. return (c == 'e' || c == 'E');
  312. }
  313. static
  314. const char* skip_whitespace(const char* ptr)
  315. {
  316. while (is_whitespace(*ptr))
  317. ptr++;
  318. return ptr;
  319. }
  320. static
  321. const char* skip_line(const char* ptr)
  322. {
  323. while (!is_newline(*ptr++))
  324. ;
  325. return ptr;
  326. }
  327. static
  328. fastObjGroup group_default(void)
  329. {
  330. fastObjGroup group;
  331. group.name = 0;
  332. group.face_count = 0;
  333. group.face_offset = 0;
  334. group.index_offset = 0;
  335. return group;
  336. }
  337. static
  338. void group_clean(fastObjGroup* group)
  339. {
  340. memory_dealloc(group->name);
  341. }
  342. static
  343. void flush_output(fastObjData* data)
  344. {
  345. /* Add group if not empty */
  346. if (data->group.face_count > 0)
  347. array_push(data->mesh->groups, data->group);
  348. else
  349. group_clean(&data->group);
  350. /* Reset for more data */
  351. data->group = group_default();
  352. data->group.face_offset = array_size(data->mesh->face_vertices);
  353. data->group.index_offset = array_size(data->mesh->indices);
  354. }
  355. static
  356. const char* parse_int(const char* ptr, int* val)
  357. {
  358. int sign;
  359. int num;
  360. if (*ptr == '-')
  361. {
  362. sign = -1;
  363. ptr++;
  364. }
  365. else
  366. {
  367. sign = +1;
  368. }
  369. num = 0;
  370. while (is_digit(*ptr))
  371. num = 10 * num + (*ptr++ - '0');
  372. *val = sign * num;
  373. return ptr;
  374. }
  375. static
  376. const char* parse_float(const char* ptr, float* val)
  377. {
  378. double sign;
  379. double num;
  380. double fra;
  381. double div;
  382. int eval;
  383. const double* powers;
  384. ptr = skip_whitespace(ptr);
  385. switch (*ptr)
  386. {
  387. case '+':
  388. sign = 1.0;
  389. ptr++;
  390. break;
  391. case '-':
  392. sign = -1.0;
  393. ptr++;
  394. break;
  395. default:
  396. sign = 1.0;
  397. break;
  398. }
  399. num = 0.0;
  400. while (is_digit(*ptr))
  401. num = 10.0 * num + (double)(*ptr++ - '0');
  402. if (*ptr == '.')
  403. ptr++;
  404. fra = 0.0;
  405. div = 1.0;
  406. while (is_digit(*ptr))
  407. {
  408. fra = 10.0 * fra + (double)(*ptr++ - '0');
  409. div *= 10.0;
  410. }
  411. num += fra / div;
  412. if (is_exponent(*ptr))
  413. {
  414. ptr++;
  415. switch (*ptr)
  416. {
  417. case '+':
  418. powers = POWER_10_POS;
  419. ptr++;
  420. break;
  421. case '-':
  422. powers = POWER_10_NEG;
  423. ptr++;
  424. break;
  425. default:
  426. powers = POWER_10_POS;
  427. break;
  428. }
  429. eval = 0;
  430. while (is_digit(*ptr))
  431. eval = 10 * eval + (*ptr++ - '0');
  432. num *= (eval >= MAX_POWER) ? 0.0 : powers[eval];
  433. }
  434. *val = (float)(sign * num);
  435. return ptr;
  436. }
  437. static
  438. const char* parse_vertex(fastObjData* data, const char* ptr)
  439. {
  440. unsigned int ii;
  441. float v;
  442. for (ii = 0; ii < 3; ii++)
  443. {
  444. ptr = parse_float(ptr, &v);
  445. array_push(data->mesh->positions, v);
  446. }
  447. return ptr;
  448. }
  449. static
  450. const char* parse_texcoord(fastObjData* data, const char* ptr)
  451. {
  452. unsigned int ii;
  453. float v;
  454. for (ii = 0; ii < 2; ii++)
  455. {
  456. ptr = parse_float(ptr, &v);
  457. array_push(data->mesh->texcoords, v);
  458. }
  459. return ptr;
  460. }
  461. static
  462. const char* parse_normal(fastObjData* data, const char* ptr)
  463. {
  464. unsigned int ii;
  465. float v;
  466. for (ii = 0; ii < 3; ii++)
  467. {
  468. ptr = parse_float(ptr, &v);
  469. array_push(data->mesh->normals, v);
  470. }
  471. return ptr;
  472. }
  473. static
  474. const char* parse_face(fastObjData* data, const char* ptr)
  475. {
  476. unsigned int count;
  477. fastObjIndex vn;
  478. int v;
  479. int t;
  480. int n;
  481. ptr = skip_whitespace(ptr);
  482. count = 0;
  483. while (!is_newline(*ptr))
  484. {
  485. v = 0;
  486. t = 0;
  487. n = 0;
  488. ptr = parse_int(ptr, &v);
  489. if (*ptr == '/')
  490. {
  491. ptr++;
  492. if (*ptr != '/')
  493. ptr = parse_int(ptr, &t);
  494. if (*ptr == '/')
  495. {
  496. ptr++;
  497. ptr = parse_int(ptr, &n);
  498. }
  499. }
  500. if (v < 0)
  501. vn.p = (array_size(data->mesh->positions) / 3) - (unsigned int)(-v);
  502. else
  503. vn.p = (unsigned int)(v);
  504. if (t < 0)
  505. vn.t = (array_size(data->mesh->texcoords) / 2) - (unsigned int)(-t);
  506. else if (t > 0)
  507. vn.t = (unsigned int)(t);
  508. else
  509. vn.t = 0;
  510. if (n < 0)
  511. vn.n = (array_size(data->mesh->normals) / 3) - (unsigned int)(-n);
  512. else if (n > 0)
  513. vn.n = (unsigned int)(n);
  514. else
  515. vn.n = 0;
  516. array_push(data->mesh->indices, vn);
  517. count++;
  518. ptr = skip_whitespace(ptr);
  519. }
  520. array_push(data->mesh->face_vertices, count);
  521. array_push(data->mesh->face_materials, data->material);
  522. data->group.face_count++;
  523. return ptr;
  524. }
  525. static
  526. const char* parse_group(fastObjData* data, const char* ptr)
  527. {
  528. const char* s;
  529. const char* e;
  530. ptr = skip_whitespace(ptr);
  531. s = ptr;
  532. while (!is_whitespace(*ptr) && !is_newline(*ptr))
  533. ptr++;
  534. e = ptr;
  535. flush_output(data);
  536. data->group.name = string_copy(s, e);
  537. return ptr;
  538. }
  539. static
  540. fastObjTexture map_default(void)
  541. {
  542. fastObjTexture map;
  543. map.name = 0;
  544. map.path = 0;
  545. return map;
  546. }
  547. static
  548. fastObjMaterial mtl_default(void)
  549. {
  550. fastObjMaterial mtl;
  551. mtl.name = 0;
  552. mtl.Ka[0] = 0.0;
  553. mtl.Ka[1] = 0.0;
  554. mtl.Ka[2] = 0.0;
  555. mtl.Kd[0] = 1.0;
  556. mtl.Kd[1] = 1.0;
  557. mtl.Kd[2] = 1.0;
  558. mtl.Ks[0] = 0.0;
  559. mtl.Ks[1] = 0.0;
  560. mtl.Ks[2] = 0.0;
  561. mtl.Ke[0] = 0.0;
  562. mtl.Ke[1] = 0.0;
  563. mtl.Ke[2] = 0.0;
  564. mtl.Kt[0] = 0.0;
  565. mtl.Kt[1] = 0.0;
  566. mtl.Kt[2] = 0.0;
  567. mtl.Ns = 1.0;
  568. mtl.Ni = 1.0;
  569. mtl.Tf[0] = 1.0;
  570. mtl.Tf[1] = 1.0;
  571. mtl.Tf[2] = 1.0;
  572. mtl.d = 1.0;
  573. mtl.illum = 1;
  574. mtl.map_Ka = map_default();
  575. mtl.map_Kd = map_default();
  576. mtl.map_Ks = map_default();
  577. mtl.map_Ke = map_default();
  578. mtl.map_Kt = map_default();
  579. mtl.map_Ns = map_default();
  580. mtl.map_Ni = map_default();
  581. mtl.map_d = map_default();
  582. mtl.map_bump = map_default();
  583. return mtl;
  584. }
  585. static
  586. const char* parse_usemtl(fastObjData* data, const char* ptr)
  587. {
  588. const char* s;
  589. const char* e;
  590. unsigned int idx;
  591. fastObjMaterial* mtl;
  592. ptr = skip_whitespace(ptr);
  593. /* Parse the material name */
  594. s = ptr;
  595. while (!is_whitespace(*ptr) && !is_newline(*ptr))
  596. ptr++;
  597. e = ptr;
  598. /* If there are no materials yet, add a dummy invalid material at index 0 */
  599. if (array_empty(data->mesh->materials))
  600. array_push(data->mesh->materials, mtl_default());
  601. /* Find an existing material with the same name */
  602. idx = 0;
  603. while (idx < array_size(data->mesh->materials))
  604. {
  605. mtl = &data->mesh->materials[idx];
  606. if (mtl->name && string_equal(mtl->name, s, e))
  607. break;
  608. idx++;
  609. }
  610. if (idx == array_size(data->mesh->materials))
  611. idx = 0;
  612. data->material = idx;
  613. return ptr;
  614. }
  615. static
  616. void map_clean(fastObjTexture* map)
  617. {
  618. memory_dealloc(map->name);
  619. memory_dealloc(map->path);
  620. }
  621. static
  622. void mtl_clean(fastObjMaterial* mtl)
  623. {
  624. map_clean(&mtl->map_Ka);
  625. map_clean(&mtl->map_Kd);
  626. map_clean(&mtl->map_Ks);
  627. map_clean(&mtl->map_Ke);
  628. map_clean(&mtl->map_Kt);
  629. map_clean(&mtl->map_Ns);
  630. map_clean(&mtl->map_Ni);
  631. map_clean(&mtl->map_d);
  632. map_clean(&mtl->map_bump);
  633. memory_dealloc(mtl->name);
  634. }
  635. static
  636. const char* read_mtl_int(const char* p, int* v)
  637. {
  638. return parse_int(p, v);
  639. }
  640. static
  641. const char* read_mtl_single(const char* p, float* v)
  642. {
  643. return parse_float(p, v);
  644. }
  645. static
  646. const char* read_mtl_triple(const char* p, float v[3])
  647. {
  648. p = read_mtl_single(p, &v[0]);
  649. p = read_mtl_single(p, &v[1]);
  650. p = read_mtl_single(p, &v[2]);
  651. return p;
  652. }
  653. static
  654. const char* read_map(fastObjData* data, const char* ptr, fastObjTexture* map)
  655. {
  656. const char* s;
  657. const char* e;
  658. char* name;
  659. char* path;
  660. ptr = skip_whitespace(ptr);
  661. /* Don't support options at present */
  662. if (*ptr == '-')
  663. return ptr;
  664. /* Read name */
  665. s = ptr;
  666. while (!is_whitespace(*ptr) && !is_newline(*ptr))
  667. ptr++;
  668. e = ptr;
  669. name = string_copy(s, e);
  670. path = string_concat(data->base, s, e);
  671. string_fix_separators(path);
  672. map->name = name;
  673. map->path = path;
  674. return e;
  675. }
  676. static
  677. int read_mtllib(fastObjData* data, void* file)
  678. {
  679. unsigned long n;
  680. const char* s;
  681. char* contents;
  682. size_t l;
  683. const char* p;
  684. const char* e;
  685. int found_d;
  686. fastObjMaterial mtl;
  687. /* Read entire file */
  688. n = file_size(file);
  689. contents = (char*)(memory_realloc(0, n + 1));
  690. if (!contents)
  691. return 0;
  692. l = file_read(file, contents, n);
  693. contents[l] = '\n';
  694. mtl = mtl_default();
  695. found_d = 0;
  696. p = contents;
  697. e = contents + l;
  698. while (p < e)
  699. {
  700. p = skip_whitespace(p);
  701. switch (*p)
  702. {
  703. case 'n':
  704. p++;
  705. if (p[0] == 'e' &&
  706. p[1] == 'w' &&
  707. p[2] == 'm' &&
  708. p[3] == 't' &&
  709. p[4] == 'l' &&
  710. is_whitespace(p[5]))
  711. {
  712. /* Push previous material (if there is one) */
  713. if (mtl.name)
  714. {
  715. array_push(data->mesh->materials, mtl);
  716. mtl = mtl_default();
  717. }
  718. /* Read name */
  719. p += 5;
  720. while (is_whitespace(*p))
  721. p++;
  722. s = p;
  723. while (!is_whitespace(*p) && !is_newline(*p))
  724. p++;
  725. mtl.name = string_copy(s, p);
  726. }
  727. break;
  728. case 'K':
  729. if (p[1] == 'a')
  730. p = read_mtl_triple(p + 2, mtl.Ka);
  731. else if (p[1] == 'd')
  732. p = read_mtl_triple(p + 2, mtl.Kd);
  733. else if (p[1] == 's')
  734. p = read_mtl_triple(p + 2, mtl.Ks);
  735. else if (p[1] == 'e')
  736. p = read_mtl_triple(p + 2, mtl.Ke);
  737. else if (p[1] == 't')
  738. p = read_mtl_triple(p + 2, mtl.Kt);
  739. break;
  740. case 'N':
  741. if (p[1] == 's')
  742. p = read_mtl_single(p + 2, &mtl.Ns);
  743. else if (p[1] == 'i')
  744. p = read_mtl_single(p + 2, &mtl.Ni);
  745. break;
  746. case 'T':
  747. if (p[1] == 'r')
  748. {
  749. float Tr;
  750. p = read_mtl_single(p + 2, &Tr);
  751. if (!found_d)
  752. {
  753. /* Ignore Tr if we've already read d */
  754. mtl.d = 1.0f - Tr;
  755. }
  756. }
  757. else if (p[1] == 'f')
  758. p = read_mtl_triple(p + 2, mtl.Tf);
  759. break;
  760. case 'd':
  761. if (is_whitespace(p[1]))
  762. {
  763. p = read_mtl_single(p + 1, &mtl.d);
  764. found_d = 1;
  765. }
  766. break;
  767. case 'i':
  768. p++;
  769. if (p[0] == 'l' &&
  770. p[1] == 'l' &&
  771. p[2] == 'u' &&
  772. p[3] == 'm' &&
  773. is_whitespace(p[4]))
  774. {
  775. p = read_mtl_int(p + 4, &mtl.illum);
  776. }
  777. break;
  778. case 'm':
  779. p++;
  780. if (p[0] == 'a' &&
  781. p[1] == 'p' &&
  782. p[2] == '_')
  783. {
  784. p += 3;
  785. if (*p == 'K')
  786. {
  787. p++;
  788. if (is_whitespace(p[1]))
  789. {
  790. if (*p == 'a')
  791. p = read_map(data, p + 1, &mtl.map_Ka);
  792. else if (*p == 'd')
  793. p = read_map(data, p + 1, &mtl.map_Kd);
  794. else if (*p == 's')
  795. p = read_map(data, p + 1, &mtl.map_Ks);
  796. else if (*p == 'e')
  797. p = read_map(data, p + 1, &mtl.map_Ke);
  798. else if (*p == 't')
  799. p = read_map(data, p + 1, &mtl.map_Kt);
  800. }
  801. }
  802. else if (*p == 'N')
  803. {
  804. p++;
  805. if (is_whitespace(p[1]))
  806. {
  807. if (*p == 's')
  808. p = read_map(data, p + 1, &mtl.map_Ns);
  809. else if (*p == 'i')
  810. p = read_map(data, p + 1, &mtl.map_Ni);
  811. }
  812. }
  813. else if (*p == 'd')
  814. {
  815. p++;
  816. if (is_whitespace(*p))
  817. p = read_map(data, p, &mtl.map_d);
  818. }
  819. else if (p[0] == 'b' &&
  820. p[1] == 'u' &&
  821. p[2] == 'm' &&
  822. p[3] == 'p' &&
  823. is_whitespace(p[4]))
  824. {
  825. p = read_map(data, p + 4, &mtl.map_d);
  826. }
  827. }
  828. break;
  829. case '#':
  830. break;
  831. }
  832. p = skip_line(p);
  833. }
  834. /* Push final material */
  835. if (mtl.name)
  836. array_push(data->mesh->materials, mtl);
  837. memory_dealloc(contents);
  838. return 1;
  839. }
  840. static
  841. const char* parse_mtllib(fastObjData* data, const char* ptr)
  842. {
  843. const char* s;
  844. const char* e;
  845. char* lib;
  846. void* file;
  847. ptr = skip_whitespace(ptr);
  848. s = ptr;
  849. while (!is_whitespace(*ptr) && !is_newline(*ptr))
  850. ptr++;
  851. e = ptr;
  852. lib = string_concat(data->base, s, e);
  853. if (lib)
  854. {
  855. string_fix_separators(lib);
  856. file = file_open(lib);
  857. if (file)
  858. {
  859. read_mtllib(data, file);
  860. file_close(file);
  861. }
  862. memory_dealloc(lib);
  863. }
  864. return ptr;
  865. }
  866. static
  867. void parse_buffer(fastObjData* data, const char* ptr, const char* end)
  868. {
  869. const char* p;
  870. p = ptr;
  871. while (p != end)
  872. {
  873. p = skip_whitespace(p);
  874. switch (*p)
  875. {
  876. case 'v':
  877. p++;
  878. switch (*p++)
  879. {
  880. case ' ':
  881. case '\t':
  882. p = parse_vertex(data, p);
  883. break;
  884. case 't':
  885. p = parse_texcoord(data, p);
  886. break;
  887. case 'n':
  888. p = parse_normal(data, p);
  889. break;
  890. default:
  891. p--; /* roll p++ back in case *p was a newline */
  892. }
  893. break;
  894. case 'f':
  895. p++;
  896. switch (*p++)
  897. {
  898. case ' ':
  899. case '\t':
  900. p = parse_face(data, p);
  901. break;
  902. default:
  903. p--; /* roll p++ back in case *p was a newline */
  904. }
  905. break;
  906. case 'g':
  907. p++;
  908. switch (*p++)
  909. {
  910. case ' ':
  911. case '\t':
  912. p = parse_group(data, p);
  913. break;
  914. default:
  915. p--; /* roll p++ back in case *p was a newline */
  916. }
  917. break;
  918. case 'm':
  919. p++;
  920. if (p[0] == 't' &&
  921. p[1] == 'l' &&
  922. p[2] == 'l' &&
  923. p[3] == 'i' &&
  924. p[4] == 'b' &&
  925. is_whitespace(p[5]))
  926. p = parse_mtllib(data, p + 5);
  927. break;
  928. case 'u':
  929. p++;
  930. if (p[0] == 's' &&
  931. p[1] == 'e' &&
  932. p[2] == 'm' &&
  933. p[3] == 't' &&
  934. p[4] == 'l' &&
  935. is_whitespace(p[5]))
  936. p = parse_usemtl(data, p + 5);
  937. break;
  938. case '#':
  939. break;
  940. }
  941. p = skip_line(p);
  942. data->line++;
  943. }
  944. }
  945. void fast_obj_destroy(fastObjMesh* m)
  946. {
  947. unsigned int ii;
  948. for (ii = 0; ii < array_size(m->groups); ii++)
  949. group_clean(&m->groups[ii]);
  950. for (ii = 0; ii < array_size(m->materials); ii++)
  951. mtl_clean(&m->materials[ii]);
  952. array_clean(m->positions);
  953. array_clean(m->texcoords);
  954. array_clean(m->normals);
  955. array_clean(m->face_vertices);
  956. array_clean(m->face_materials);
  957. array_clean(m->indices);
  958. array_clean(m->groups);
  959. array_clean(m->materials);
  960. memory_dealloc(m);
  961. }
  962. fastObjMesh* fast_obj_read(const char* path)
  963. {
  964. fastObjData data;
  965. fastObjMesh* m;
  966. void* file;
  967. char* buffer;
  968. char* start;
  969. char* end;
  970. char* last;
  971. unsigned int read;
  972. size_t sep;
  973. unsigned int bytes;
  974. /* Open file */
  975. file = file_open(path);
  976. if (!file)
  977. return 0;
  978. /* Empty mesh */
  979. m = (fastObjMesh*)(memory_realloc(0, sizeof(fastObjMesh)));
  980. if (!m)
  981. return 0;
  982. m->positions = 0;
  983. m->texcoords = 0;
  984. m->normals = 0;
  985. m->face_vertices = 0;
  986. m->face_materials = 0;
  987. m->indices = 0;
  988. m->materials = 0;
  989. m->groups = 0;
  990. /* Add dummy position/texcoord/normal */
  991. array_push(m->positions, 0.0f);
  992. array_push(m->positions, 0.0f);
  993. array_push(m->positions, 0.0f);
  994. array_push(m->texcoords, 0.0f);
  995. array_push(m->texcoords, 0.0f);
  996. array_push(m->normals, 0.0f);
  997. array_push(m->normals, 0.0f);
  998. array_push(m->normals, 1.0f);
  999. /* Data needed during parsing */
  1000. data.mesh = m;
  1001. data.group = group_default();
  1002. data.material = 0;
  1003. data.line = 1;
  1004. data.base = 0;
  1005. /* Find base path for materials/textures */
  1006. if (string_find_last(path, FAST_OBJ_SEPARATOR, &sep))
  1007. data.base = string_substr(path, 0, sep + 1);
  1008. /* Create buffer for reading file */
  1009. buffer = (char*)(memory_realloc(0, 2 * BUFFER_SIZE * sizeof(char)));
  1010. if (!buffer)
  1011. return 0;
  1012. start = buffer;
  1013. for (;;)
  1014. {
  1015. /* Read another buffer's worth from file */
  1016. read = (unsigned int)(file_read(file, start, BUFFER_SIZE));
  1017. if (read == 0 && start == buffer)
  1018. break;
  1019. /* Ensure buffer ends in a newline */
  1020. if (read < BUFFER_SIZE)
  1021. {
  1022. if (read == 0 || start[read - 1] != '\n')
  1023. start[read++] = '\n';
  1024. }
  1025. end = start + read;
  1026. if (end == buffer)
  1027. break;
  1028. /* Find last new line */
  1029. last = end;
  1030. while (last > buffer)
  1031. {
  1032. last--;
  1033. if (*last == '\n')
  1034. break;
  1035. }
  1036. /* Check there actually is a new line */
  1037. if (*last != '\n')
  1038. break;
  1039. last++;
  1040. /* Process buffer */
  1041. parse_buffer(&data, buffer, last);
  1042. /* Copy overflow for next buffer */
  1043. bytes = (unsigned int)(end - last);
  1044. memcpy(buffer, last, bytes);
  1045. start = buffer + bytes;
  1046. }
  1047. /* Flush final group */
  1048. flush_output(&data);
  1049. group_clean(&data.group);
  1050. m->position_count = array_size(m->positions) / 3;
  1051. m->texcoord_count = array_size(m->texcoords) / 2;
  1052. m->normal_count = array_size(m->normals) / 3;
  1053. m->face_count = array_size(m->face_vertices);
  1054. m->material_count = array_size(m->materials);
  1055. m->group_count = array_size(m->groups);
  1056. /* Clean up */
  1057. memory_dealloc(buffer);
  1058. memory_dealloc(data.base);
  1059. file_close(file);
  1060. return m;
  1061. }
  1062. #endif