]> git.sesse.net Git - pistorm/blob - raylib_pi4_test/external/tinyobj_loader_c.h
[MEGA-WIP] Raylib-based RTG output
[pistorm] / raylib_pi4_test / external / tinyobj_loader_c.h
1 /*
2    The MIT License (MIT)
3
4    Copyright (c) 2016 - 2019 Syoyo Fujita and many contributors.
5
6    Permission is hereby granted, free of charge, to any person obtaining a copy
7    of this software and associated documentation files (the "Software"), to deal
8    in the Software without restriction, including without limitation the rights
9    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10    copies of the Software, and to permit persons to whom the Software is
11    furnished to do so, subject to the following conditions:
12
13    The above copyright notice and this permission notice shall be included in
14    all copies or substantial portions of the Software.
15
16    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22    THE SOFTWARE.
23    */
24 #ifndef TINOBJ_LOADER_C_H_
25 #define TINOBJ_LOADER_C_H_
26
27 /* @todo { Remove stddef dependency. unsigned int? } ---> RAY: DONE. */
28 //#include <stddef.h>
29
30 typedef struct {
31   char *name;
32
33   float ambient[3];
34   float diffuse[3];
35   float specular[3];
36   float transmittance[3];
37   float emission[3];
38   float shininess;
39   float ior;      /* index of refraction */
40   float dissolve; /* 1 == opaque; 0 == fully transparent */
41   /* illumination model (see http://www.fileformat.info/format/material/) */
42   int illum;
43
44   int pad0;
45
46   char *ambient_texname;            /* map_Ka */
47   char *diffuse_texname;            /* map_Kd */
48   char *specular_texname;           /* map_Ks */
49   char *specular_highlight_texname; /* map_Ns */
50   char *bump_texname;               /* map_bump, bump */
51   char *displacement_texname;       /* disp */
52   char *alpha_texname;              /* map_d */
53 } tinyobj_material_t;
54
55 typedef struct {
56   char *name; /* group name or object name. */
57   unsigned int face_offset;
58   unsigned int length;
59 } tinyobj_shape_t;
60
61 typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t;
62
63 typedef struct {
64   unsigned int num_vertices;
65   unsigned int num_normals;
66   unsigned int num_texcoords;
67   unsigned int num_faces;
68   unsigned int num_face_num_verts;
69
70   int pad0;
71
72   float *vertices;
73   float *normals;
74   float *texcoords;
75   tinyobj_vertex_index_t *faces;
76   int *face_num_verts;
77   int *material_ids;
78 } tinyobj_attrib_t;
79
80
81 #define TINYOBJ_FLAG_TRIANGULATE (1 << 0)
82
83 #define TINYOBJ_INVALID_INDEX (0x80000000)
84
85 #define TINYOBJ_SUCCESS (0)
86 #define TINYOBJ_ERROR_EMPTY (-1)
87 #define TINYOBJ_ERROR_INVALID_PARAMETER (-2)
88 #define TINYOBJ_ERROR_FILE_OPERATION (-3)
89
90 /* Parse wavefront .obj(.obj string data is expanded to linear char array `buf')
91  * flags are combination of TINYOBJ_FLAG_***
92  * Returns TINYOBJ_SUCCESS if things goes well.
93  * Returns TINYOBJ_ERR_*** when there is an error.
94  */
95 extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
96                              unsigned int *num_shapes, tinyobj_material_t **materials,
97                              unsigned int *num_materials, const char *buf, unsigned int len,
98                              unsigned int flags);
99 extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out,
100                                   unsigned int *num_materials_out,
101                                   const char *filename);
102
103 extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib);
104 extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib);
105 extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes);
106 extern void tinyobj_materials_free(tinyobj_material_t *materials,
107                                    unsigned int num_materials);
108
109 #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION
110 #include <stdio.h>
111 #include <assert.h>
112 #include <string.h>
113 #include <errno.h>
114
115 #if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE)
116 /* ok */
117 #elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE)
118 /* ok */
119 #else
120 #error "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE."
121 #endif
122
123 #ifndef TINYOBJ_MALLOC
124 #include <stdlib.h>
125 #define TINYOBJ_MALLOC malloc
126 #define TINYOBJ_REALLOC realloc
127 #define TINYOBJ_CALLOC calloc
128 #define TINYOBJ_FREE free
129 #endif
130
131 #define TINYOBJ_MAX_FACES_PER_F_LINE (16)
132
133 #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
134 #define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10))
135 #define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0'))
136
137 static void skip_space(const char **token) {
138   while ((*token)[0] == ' ' || (*token)[0] == '\t') {
139     (*token)++;
140   }
141 }
142
143 static void skip_space_and_cr(const char **token) {
144   while ((*token)[0] == ' ' || (*token)[0] == '\t' || (*token)[0] == '\r') {
145     (*token)++;
146   }
147 }
148
149 static int until_space(const char *token) {
150   const char *p = token;
151   while (p[0] != '\0' && p[0] != ' ' && p[0] != '\t' && p[0] != '\r') {
152     p++;
153   }
154
155   return (int)(p - token);
156 }
157
158 static unsigned int length_until_newline(const char *token, unsigned int n) {
159   unsigned int len = 0;
160
161   /* Assume token[n-1] = '\0' */
162   for (len = 0; len < n - 1; len++) {
163     if (token[len] == '\n') {
164       break;
165     }
166     if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) {
167       break;
168     }
169   }
170
171   return len;
172 }
173
174 static unsigned int length_until_line_feed(const char *token, unsigned int n) {
175   unsigned int len = 0;
176
177   /* Assume token[n-1] = '\0' */
178   for (len = 0; len < n; len++) {
179     if ((token[len] == '\n') || (token[len] == '\r')) {
180       break;
181     }
182   }
183
184   return len;
185 }
186
187 /* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work
188 */
189 static int my_atoi(const char *c) {
190   int value = 0;
191   int sign = 1;
192   if (*c == '+' || *c == '-') {
193     if (*c == '-') sign = -1;
194     c++;
195   }
196   while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */
197     value *= 10;
198     value += (int)(*c - '0');
199     c++;
200   }
201   return value * sign;
202 }
203
204 /* Make index zero-base, and also support relative index. */
205 static int fixIndex(int idx, unsigned int n) {
206   if (idx > 0) return idx - 1;
207   if (idx == 0) return 0;
208   return (int)n + idx; /* negative value = relative */
209 }
210
211 /* Parse raw triples: i, i/j/k, i//k, i/j */
212 static tinyobj_vertex_index_t parseRawTriple(const char **token) {
213   tinyobj_vertex_index_t vi;
214   /* 0x80000000 = -2147483648 = invalid */
215   vi.v_idx = (int)(0x80000000);
216   vi.vn_idx = (int)(0x80000000);
217   vi.vt_idx = (int)(0x80000000);
218
219   vi.v_idx = my_atoi((*token));
220   while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
221          (*token)[0] != '\t' && (*token)[0] != '\r') {
222     (*token)++;
223   }
224   if ((*token)[0] != '/') {
225     return vi;
226   }
227   (*token)++;
228
229   /* i//k */
230   if ((*token)[0] == '/') {
231     (*token)++;
232     vi.vn_idx = my_atoi((*token));
233     while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
234            (*token)[0] != '\t' && (*token)[0] != '\r') {
235       (*token)++;
236     }
237     return vi;
238   }
239
240   /* i/j/k or i/j */
241   vi.vt_idx = my_atoi((*token));
242   while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
243          (*token)[0] != '\t' && (*token)[0] != '\r') {
244     (*token)++;
245   }
246   if ((*token)[0] != '/') {
247     return vi;
248   }
249
250   /* i/j/k */
251   (*token)++; /* skip '/' */
252   vi.vn_idx = my_atoi((*token));
253   while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' &&
254          (*token)[0] != '\t' && (*token)[0] != '\r') {
255     (*token)++;
256   }
257   return vi;
258 }
259
260 static int parseInt(const char **token) {
261   int i = 0;
262   skip_space(token);
263   i = my_atoi((*token));
264   (*token) += until_space((*token));
265   return i;
266 }
267
268 /*
269  * Tries to parse a floating point number located at s.
270  *
271  * s_end should be a location in the string where reading should absolutely
272  * stop. For example at the end of the string, to prevent buffer overflows.
273  *
274  * Parses the following EBNF grammar:
275  *   sign    = "+" | "-" ;
276  *   END     = ? anything not in digit ?
277  *   digit   = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
278  *   integer = [sign] , digit , {digit} ;
279  *   decimal = integer , ["." , integer] ;
280  *   float   = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ;
281  *
282  *  Valid strings are for example:
283  *   -0  +3.1417e+2  -0.0E-3  1.0324  -1.41   11e2
284  *
285  * If the parsing is a success, result is set to the parsed value and true
286  * is returned.
287  *
288  * The function is greedy and will parse until any of the following happens:
289  *  - a non-conforming character is encountered.
290  *  - s_end is reached.
291  *
292  * The following situations triggers a failure:
293  *  - s >= s_end.
294  *  - parse failure.
295  */
296 static int tryParseDouble(const char *s, const char *s_end, double *result) {
297   double mantissa = 0.0;
298   /* This exponent is base 2 rather than 10.
299    * However the exponent we parse is supposed to be one of ten,
300    * thus we must take care to convert the exponent/and or the
301    * mantissa to a * 2^E, where a is the mantissa and E is the
302    * exponent.
303    * To get the final double we will use ldexp, it requires the
304    * exponent to be in base 2.
305    */
306   int exponent = 0;
307
308   /* NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED
309    * TO JUMP OVER DEFINITIONS.
310    */
311   char sign = '+';
312   char exp_sign = '+';
313   char const *curr = s;
314
315   /* How many characters were read in a loop. */
316   int read = 0;
317   /* Tells whether a loop terminated due to reaching s_end. */
318   int end_not_reached = 0;
319
320   /*
321      BEGIN PARSING.
322      */
323
324   if (s >= s_end) {
325     return 0; /* fail */
326   }
327
328   /* Find out what sign we've got. */
329   if (*curr == '+' || *curr == '-') {
330     sign = *curr;
331     curr++;
332   } else if (IS_DIGIT(*curr)) { /* Pass through. */
333   } else {
334     goto fail;
335   }
336
337   /* Read the integer part. */
338   end_not_reached = (curr != s_end);
339   while (end_not_reached && IS_DIGIT(*curr)) {
340     mantissa *= 10;
341     mantissa += (int)(*curr - 0x30);
342     curr++;
343     read++;
344     end_not_reached = (curr != s_end);
345   }
346
347   /* We must make sure we actually got something. */
348   if (read == 0) goto fail;
349   /* We allow numbers of form "#", "###" etc. */
350   if (!end_not_reached) goto assemble;
351
352   /* Read the decimal part. */
353   if (*curr == '.') {
354     curr++;
355     read = 1;
356     end_not_reached = (curr != s_end);
357     while (end_not_reached && IS_DIGIT(*curr)) {
358       /* pow(10.0, -read) */
359       double frac_value = 1.0;
360       int f;
361       for (f = 0; f < read; f++) {
362         frac_value *= 0.1;
363       }
364       mantissa += (int)(*curr - 0x30) * frac_value;
365       read++;
366       curr++;
367       end_not_reached = (curr != s_end);
368     }
369   } else if (*curr == 'e' || *curr == 'E') {
370   } else {
371     goto assemble;
372   }
373
374   if (!end_not_reached) goto assemble;
375
376   /* Read the exponent part. */
377   if (*curr == 'e' || *curr == 'E') {
378     curr++;
379     /* Figure out if a sign is present and if it is. */
380     end_not_reached = (curr != s_end);
381     if (end_not_reached && (*curr == '+' || *curr == '-')) {
382       exp_sign = *curr;
383       curr++;
384     } else if (IS_DIGIT(*curr)) { /* Pass through. */
385     } else {
386       /* Empty E is not allowed. */
387       goto fail;
388     }
389
390     read = 0;
391     end_not_reached = (curr != s_end);
392     while (end_not_reached && IS_DIGIT(*curr)) {
393       exponent *= 10;
394       exponent += (int)(*curr - 0x30);
395       curr++;
396       read++;
397       end_not_reached = (curr != s_end);
398     }
399     if (read == 0) goto fail;
400   }
401
402 assemble :
403
404   {
405     double a = 1.0; /* = pow(5.0, exponent); */
406     double b  = 1.0; /* = 2.0^exponent */
407     int i;
408     for (i = 0; i < exponent; i++) {
409       a = a * 5.0;
410     }
411
412     for (i = 0; i < exponent; i++) {
413       b = b * 2.0;
414     }
415
416     if (exp_sign == '-') {
417       a = 1.0 / a;
418       b = 1.0 / b;
419     }
420
421     *result =
422       /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent),
423          exponent); */
424       (sign == '+' ? 1 : -1) * (mantissa * a * b);
425   }
426
427   return 1;
428 fail:
429   return 0;
430 }
431
432 static float parseFloat(const char **token) {
433   const char *end;
434   double val = 0.0;
435   float f = 0.0f;
436   skip_space(token);
437   end = (*token) + until_space((*token));
438   val = 0.0;
439   tryParseDouble((*token), end, &val);
440   f = (float)(val);
441   (*token) = end;
442   return f;
443 }
444
445 static void parseFloat2(float *x, float *y, const char **token) {
446   (*x) = parseFloat(token);
447   (*y) = parseFloat(token);
448 }
449
450 static void parseFloat3(float *x, float *y, float *z, const char **token) {
451   (*x) = parseFloat(token);
452   (*y) = parseFloat(token);
453   (*z) = parseFloat(token);
454 }
455
456 static unsigned int my_strnlen(const char *s, unsigned int n) {
457     const char *p = memchr(s, 0, n);
458     return p ? (unsigned int)(p - s) : n;
459 }
460
461 static char *my_strdup(const char *s, unsigned int max_length) {
462   char *d;
463   unsigned int len;
464
465   if (s == NULL) return NULL;
466
467   /* Do not consider CRLF line ending(#19) */
468   len = length_until_line_feed(s, max_length);
469   /* len = strlen(s); */
470
471   /* trim line ending and append '\0' */
472   d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */
473   memcpy(d, s, (unsigned int)(len));
474   d[len] = '\0';
475
476   return d;
477 }
478
479 static char *my_strndup(const char *s, unsigned int len) {
480   char *d;
481   unsigned int slen;
482
483   if (s == NULL) return NULL;
484   if (len == 0) return NULL;
485
486   slen = my_strnlen(s, len);
487   d = (char *)TINYOBJ_MALLOC(slen + 1); /* + '\0' */
488   if (!d) {
489     return NULL;
490   }
491   memcpy(d, s, slen);
492   d[slen] = '\0';
493
494   return d;
495 }
496
497 char *dynamic_fgets(char **buf, unsigned int *size, FILE *file) {
498   char *offset;
499   char *ret;
500   unsigned int old_size;
501
502   if (!(ret = fgets(*buf, (int)*size, file))) {
503     return ret;
504   }
505
506   if (NULL != strchr(*buf, '\n')) {
507     return ret;
508   }
509
510   do {
511     old_size = *size;
512     *size *= 2;
513     *buf = (char*)TINYOBJ_REALLOC(*buf, *size);
514     offset = &((*buf)[old_size - 1]);
515
516     ret = fgets(offset, (int)(old_size + 1), file);
517   } while(ret && (NULL == strchr(*buf, '\n')));
518
519   return ret;
520 }
521
522 static void initMaterial(tinyobj_material_t *material) {
523   int i;
524   material->name = NULL;
525   material->ambient_texname = NULL;
526   material->diffuse_texname = NULL;
527   material->specular_texname = NULL;
528   material->specular_highlight_texname = NULL;
529   material->bump_texname = NULL;
530   material->displacement_texname = NULL;
531   material->alpha_texname = NULL;
532   for (i = 0; i < 3; i++) {
533     material->ambient[i] = 0.f;
534     material->diffuse[i] = 0.f;
535     material->specular[i] = 0.f;
536     material->transmittance[i] = 0.f;
537     material->emission[i] = 0.f;
538   }
539   material->illum = 0;
540   material->dissolve = 1.f;
541   material->shininess = 1.f;
542   material->ior = 1.f;
543 }
544
545 /* Implementation of string to int hashtable */
546
547 #define HASH_TABLE_ERROR 1 
548 #define HASH_TABLE_SUCCESS 0
549
550 #define HASH_TABLE_DEFAULT_SIZE 10
551
552 typedef struct hash_table_entry_t
553 {
554   unsigned long hash;
555   int filled;
556   int pad0;
557   long value;
558
559   struct hash_table_entry_t* next;
560 } hash_table_entry_t;
561
562 typedef struct
563 {
564   unsigned long* hashes;
565   hash_table_entry_t* entries;
566   unsigned int capacity;
567   unsigned int n;
568 } hash_table_t;
569
570 static unsigned long hash_djb2(const unsigned char* str)
571 {
572   unsigned long hash = 5381;
573   int c;
574
575   while ((c = *str++)) {
576     hash = ((hash << 5) + hash) + (unsigned long)(c);
577   }
578
579   return hash;
580 }
581
582 static void create_hash_table(unsigned int start_capacity, hash_table_t* hash_table)
583 {
584   if (start_capacity < 1)
585     start_capacity = HASH_TABLE_DEFAULT_SIZE;
586   hash_table->hashes = (unsigned long*) TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long));
587   hash_table->entries = (hash_table_entry_t*) TINYOBJ_CALLOC(start_capacity, sizeof(hash_table_entry_t));
588   hash_table->capacity = start_capacity;
589   hash_table->n = 0;
590 }
591
592 static void destroy_hash_table(hash_table_t* hash_table)
593 {
594   TINYOBJ_FREE(hash_table->entries);
595   TINYOBJ_FREE(hash_table->hashes);
596 }
597
598 /* Insert with quadratic probing */
599 static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table)
600 {
601   /* Insert value */
602   unsigned int start_index = hash % hash_table->capacity;
603   unsigned int index = start_index;
604   hash_table_entry_t* start_entry = hash_table->entries + start_index;
605   unsigned int i;
606   hash_table_entry_t* entry;
607
608   for (i = 1; hash_table->entries[index].filled; i++)
609   {
610     if (i >= hash_table->capacity)
611       return HASH_TABLE_ERROR;
612     index = (start_index + (i * i)) % hash_table->capacity; 
613   }
614
615   entry = hash_table->entries + index;
616   entry->hash = hash;
617   entry->filled = 1;
618   entry->value = value;
619
620   if (index != start_index) {
621     /* This is a new entry, but not the start entry, hence we need to add a next pointer to our entry */
622     entry->next = start_entry->next;
623     start_entry->next = entry;
624   }
625
626   return HASH_TABLE_SUCCESS;
627 }
628
629 static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table)
630 {
631   int ret = hash_table_insert_value(hash, value, hash_table);
632   if (ret == HASH_TABLE_SUCCESS)
633   {
634     hash_table->hashes[hash_table->n] = hash;
635     hash_table->n++;
636   }
637   return ret;
638 }
639
640 static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table)
641 {
642   hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity);
643   while (entry)
644   {
645     if (entry->hash == hash && entry->filled)
646     {
647       return entry;
648     }
649     entry = entry->next;
650   }
651   return NULL;
652 }
653
654 static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table)
655 {
656   unsigned int new_capacity;
657   hash_table_t new_hash_table;
658   unsigned int i;
659
660   if (new_n <= hash_table->capacity) {
661     return;
662   }
663   new_capacity = 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n);
664   /* Create a new hash table. We're not calling create_hash_table because we want to realloc the hash array */
665   new_hash_table.hashes = hash_table->hashes = (unsigned long*) TINYOBJ_REALLOC((void*) hash_table->hashes, sizeof(unsigned long) * new_capacity);
666   new_hash_table.entries = (hash_table_entry_t*) TINYOBJ_CALLOC(new_capacity, sizeof(hash_table_entry_t));
667   new_hash_table.capacity = new_capacity;
668   new_hash_table.n = hash_table->n;
669
670   /* Rehash */
671   for (i = 0; i < hash_table->capacity; i++)
672   {
673     hash_table_entry_t* entry = hash_table_find(hash_table->hashes[i], hash_table);
674     hash_table_insert_value(hash_table->hashes[i], entry->value, &new_hash_table);
675   }
676
677   TINYOBJ_FREE(hash_table->entries);
678   (*hash_table) = new_hash_table;
679 }
680
681 static int hash_table_exists(const char* name, hash_table_t* hash_table)
682 {
683   return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL;
684 }
685
686 static void hash_table_set(const char* name, unsigned int val, hash_table_t* hash_table)
687 {
688   /* Hash name */
689   unsigned long hash = hash_djb2((const unsigned char *)name);
690
691   hash_table_entry_t* entry = hash_table_find(hash, hash_table);
692   if (entry)
693   {
694     entry->value = (long)val;
695     return;
696   }
697
698   /* Expand if necessary
699    * Grow until the element has been added
700    */
701   do
702   {
703     hash_table_maybe_grow(hash_table->n + 1, hash_table);
704   }
705   while (hash_table_insert(hash, (long)val, hash_table) != HASH_TABLE_SUCCESS);
706 }
707
708 static long hash_table_get(const char* name, hash_table_t* hash_table)
709 {
710   hash_table_entry_t* ret = hash_table_find(hash_djb2((const unsigned char*)(name)), hash_table);
711   return ret->value;
712 }
713
714 static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev,
715                                                 unsigned int num_materials,
716                                                 tinyobj_material_t *new_mat) {
717   tinyobj_material_t *dst;
718   dst = (tinyobj_material_t *)TINYOBJ_REALLOC(
719                                       prev, sizeof(tinyobj_material_t) * (num_materials + 1));
720
721   dst[num_materials] = (*new_mat); /* Just copy pointer for char* members */
722   return dst;
723 }
724
725 static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
726                                             unsigned int *num_materials_out,
727                                             const char *filename,
728                                             hash_table_t* material_table) {
729   tinyobj_material_t material;
730   unsigned int buffer_size = 128;
731   char *linebuf;
732   FILE *fp;
733   unsigned int num_materials = 0;
734   tinyobj_material_t *materials = NULL;
735   int has_previous_material = 0;
736   const char *line_end = NULL;
737
738   if (materials_out == NULL) {
739     return TINYOBJ_ERROR_INVALID_PARAMETER;
740   }
741
742   if (num_materials_out == NULL) {
743     return TINYOBJ_ERROR_INVALID_PARAMETER;
744   }
745
746   (*materials_out) = NULL;
747   (*num_materials_out) = 0;
748
749   fp = fopen(filename, "r");
750   if (!fp) {
751     fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno);
752     return TINYOBJ_ERROR_FILE_OPERATION;
753   }
754
755   /* Create a default material */
756   initMaterial(&material);
757
758   linebuf = (char*)TINYOBJ_MALLOC(buffer_size);
759   while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) {
760     const char *token = linebuf;
761
762     line_end = token + strlen(token);
763
764     /* Skip leading space. */
765     token += strspn(token, " \t");
766
767     assert(token);
768     if (token[0] == '\0') continue; /* empty line */
769
770     if (token[0] == '#') continue; /* comment line */
771
772     /* new mtl */
773     if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) {
774       char namebuf[4096];
775
776       /* flush previous material. */
777       if (has_previous_material) {
778         materials = tinyobj_material_add(materials, num_materials, &material);
779         num_materials++;
780       } else {
781         has_previous_material = 1;
782       }
783
784       /* initial temporary material */
785       initMaterial(&material);
786
787       /* set new mtl name */
788       token += 7;
789 #ifdef _MSC_VER
790       sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf));
791 #else
792       sscanf(token, "%s", namebuf);
793 #endif
794       material.name = my_strdup(namebuf, (unsigned int) (line_end - token));
795
796       /* Add material to material table */
797       if (material_table)
798         hash_table_set(material.name, num_materials, material_table);
799
800       continue;
801     }
802
803     /* ambient */
804     if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) {
805       float r, g, b;
806       token += 2;
807       parseFloat3(&r, &g, &b, &token);
808       material.ambient[0] = r;
809       material.ambient[1] = g;
810       material.ambient[2] = b;
811       continue;
812     }
813
814     /* diffuse */
815     if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) {
816       float r, g, b;
817       token += 2;
818       parseFloat3(&r, &g, &b, &token);
819       material.diffuse[0] = r;
820       material.diffuse[1] = g;
821       material.diffuse[2] = b;
822       continue;
823     }
824
825     /* specular */
826     if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) {
827       float r, g, b;
828       token += 2;
829       parseFloat3(&r, &g, &b, &token);
830       material.specular[0] = r;
831       material.specular[1] = g;
832       material.specular[2] = b;
833       continue;
834     }
835
836     /* transmittance */
837     if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) {
838       float r, g, b;
839       token += 2;
840       parseFloat3(&r, &g, &b, &token);
841       material.transmittance[0] = r;
842       material.transmittance[1] = g;
843       material.transmittance[2] = b;
844       continue;
845     }
846
847     /* ior(index of refraction) */
848     if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) {
849       token += 2;
850       material.ior = parseFloat(&token);
851       continue;
852     }
853
854     /* emission */
855     if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) {
856       float r, g, b;
857       token += 2;
858       parseFloat3(&r, &g, &b, &token);
859       material.emission[0] = r;
860       material.emission[1] = g;
861       material.emission[2] = b;
862       continue;
863     }
864
865     /* shininess */
866     if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) {
867       token += 2;
868       material.shininess = parseFloat(&token);
869       continue;
870     }
871
872     /* illum model */
873     if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) {
874       token += 6;
875       material.illum = parseInt(&token);
876       continue;
877     }
878
879     /* dissolve */
880     if ((token[0] == 'd' && IS_SPACE(token[1]))) {
881       token += 1;
882       material.dissolve = parseFloat(&token);
883       continue;
884     }
885     if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) {
886       token += 2;
887       /* Invert value of Tr(assume Tr is in range [0, 1]) */
888       material.dissolve = 1.0f - parseFloat(&token);
889       continue;
890     }
891
892     /* ambient texture */
893     if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
894       token += 7;
895       material.ambient_texname = my_strdup(token, (unsigned int) (line_end - token));
896       continue;
897     }
898
899     /* diffuse texture */
900     if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
901       token += 7;
902       material.diffuse_texname = my_strdup(token, (unsigned int) (line_end - token));
903       continue;
904     }
905
906     /* specular texture */
907     if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
908       token += 7;
909       material.specular_texname = my_strdup(token, (unsigned int) (line_end - token));
910       continue;
911     }
912
913     /* specular highlight texture */
914     if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
915       token += 7;
916       material.specular_highlight_texname = my_strdup(token, (unsigned int) (line_end - token));
917       continue;
918     }
919
920     /* bump texture */
921     if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) {
922       token += 9;
923       material.bump_texname = my_strdup(token, (unsigned int) (line_end - token));
924       continue;
925     }
926
927     /* alpha texture */
928     if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) {
929       token += 6;
930       material.alpha_texname = my_strdup(token, (unsigned int) (line_end - token));
931       continue;
932     }
933
934     /* bump texture */
935     if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
936       token += 5;
937       material.bump_texname = my_strdup(token, (unsigned int) (line_end - token));
938       continue;
939     }
940
941     /* displacement texture */
942     if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
943       token += 5;
944       material.displacement_texname = my_strdup(token, (unsigned int) (line_end - token));
945       continue;
946     }
947
948     /* @todo { unknown parameter } */
949   }
950
951   if (material.name) {
952     /* Flush last material element */
953     materials = tinyobj_material_add(materials, num_materials, &material);
954     num_materials++;
955   }
956
957   (*num_materials_out) = num_materials;
958   (*materials_out) = materials;
959
960   if (linebuf) {
961     TINYOBJ_FREE(linebuf);
962   }
963
964   return TINYOBJ_SUCCESS;
965 }
966
967 int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out,
968                            unsigned int *num_materials_out,
969                            const char *filename) {
970   return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL);
971
972
973
974 typedef enum {
975   COMMAND_EMPTY,
976   COMMAND_V,
977   COMMAND_VN,
978   COMMAND_VT,
979   COMMAND_F,
980   COMMAND_G,
981   COMMAND_O,
982   COMMAND_USEMTL,
983   COMMAND_MTLLIB
984
985 } CommandType;
986
987 typedef struct {
988   float vx, vy, vz;
989   float nx, ny, nz;
990   float tx, ty;
991
992   /* @todo { Use dynamic array } */
993   tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
994   unsigned int num_f;
995
996   int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE];
997   unsigned int num_f_num_verts;
998
999   const char *group_name;
1000   unsigned int group_name_len;
1001   int pad0;
1002
1003   const char *object_name;
1004   unsigned int object_name_len;
1005   int pad1;
1006
1007   const char *material_name;
1008   unsigned int material_name_len;
1009   int pad2;
1010
1011   const char *mtllib_name;
1012   unsigned int mtllib_name_len;
1013
1014   CommandType type;
1015 } Command;
1016
1017 static int parseLine(Command *command, const char *p, unsigned int p_len,
1018                      int triangulate) {
1019   char linebuf[4096];
1020   const char *token;
1021   assert(p_len < 4095);
1022
1023   memcpy(linebuf, p, p_len);
1024   linebuf[p_len] = '\0';
1025
1026   token = linebuf;
1027
1028   command->type = COMMAND_EMPTY;
1029
1030   /* Skip leading space. */
1031   skip_space(&token);
1032
1033   assert(token);
1034   if (token[0] == '\0') { /* empty line */
1035     return 0;
1036   }
1037
1038   if (token[0] == '#') { /* comment line */
1039     return 0;
1040   }
1041
1042   /* vertex */
1043   if (token[0] == 'v' && IS_SPACE((token[1]))) {
1044     float x, y, z;
1045     token += 2;
1046     parseFloat3(&x, &y, &z, &token);
1047     command->vx = x;
1048     command->vy = y;
1049     command->vz = z;
1050     command->type = COMMAND_V;
1051     return 1;
1052   }
1053
1054   /* normal */
1055   if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
1056     float x, y, z;
1057     token += 3;
1058     parseFloat3(&x, &y, &z, &token);
1059     command->nx = x;
1060     command->ny = y;
1061     command->nz = z;
1062     command->type = COMMAND_VN;
1063     return 1;
1064   }
1065
1066   /* texcoord */
1067   if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
1068     float x, y;
1069     token += 3;
1070     parseFloat2(&x, &y, &token);
1071     command->tx = x;
1072     command->ty = y;
1073     command->type = COMMAND_VT;
1074     return 1;
1075   }
1076
1077   /* face */
1078   if (token[0] == 'f' && IS_SPACE((token[1]))) {
1079     unsigned int num_f = 0;
1080
1081     tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
1082     token += 2;
1083     skip_space(&token);
1084
1085     while (!IS_NEW_LINE(token[0])) {
1086       tinyobj_vertex_index_t vi = parseRawTriple(&token);
1087       skip_space_and_cr(&token);
1088
1089       f[num_f] = vi;
1090       num_f++;
1091     }
1092
1093     command->type = COMMAND_F;
1094
1095     if (triangulate) {
1096       unsigned int k;
1097       unsigned int n = 0;
1098
1099       tinyobj_vertex_index_t i0 = f[0];
1100       tinyobj_vertex_index_t i1;
1101       tinyobj_vertex_index_t i2 = f[1];
1102
1103       assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
1104
1105       for (k = 2; k < num_f; k++) {
1106         i1 = i2;
1107         i2 = f[k];
1108         command->f[3 * n + 0] = i0;
1109         command->f[3 * n + 1] = i1;
1110         command->f[3 * n + 2] = i2;
1111
1112         command->f_num_verts[n] = 3;
1113         n++;
1114       }
1115       command->num_f = 3 * n;
1116       command->num_f_num_verts = n;
1117
1118     } else {
1119       unsigned int k = 0;
1120       assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
1121       for (k = 0; k < num_f; k++) {
1122         command->f[k] = f[k];
1123       }
1124
1125       command->num_f = num_f;
1126       command->f_num_verts[0] = (int)num_f;
1127       command->num_f_num_verts = 1;
1128     }
1129
1130     return 1;
1131   }
1132
1133   /* use mtl */
1134   if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) {
1135     token += 7;
1136
1137     skip_space(&token);
1138     command->material_name = p + (token - linebuf);
1139     command->material_name_len = (unsigned int)length_until_newline(
1140                                                                     token, (p_len - (unsigned int)(token - linebuf)) + 1);
1141     command->type = COMMAND_USEMTL;
1142
1143     return 1;
1144   }
1145
1146   /* load mtl */
1147   if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
1148     /* By specification, `mtllib` should be appear only once in .obj */
1149     token += 7;
1150
1151     skip_space(&token);
1152     command->mtllib_name = p + (token - linebuf);
1153     command->mtllib_name_len = (unsigned int)length_until_newline(
1154                                                                   token, p_len - (unsigned int)(token - linebuf)) +
1155       1;
1156     command->type = COMMAND_MTLLIB;
1157
1158     return 1;
1159   }
1160
1161   /* group name */
1162   if (token[0] == 'g' && IS_SPACE((token[1]))) {
1163     /* @todo { multiple group name. } */
1164     token += 2;
1165
1166     command->group_name = p + (token - linebuf);
1167     command->group_name_len = (unsigned int)length_until_newline(
1168                                                                  token, p_len - (unsigned int)(token - linebuf)) +
1169       1;
1170     command->type = COMMAND_G;
1171
1172     return 1;
1173   }
1174
1175   /* object name */
1176   if (token[0] == 'o' && IS_SPACE((token[1]))) {
1177     /* @todo { multiple object name? } */
1178     token += 2;
1179
1180     command->object_name = p + (token - linebuf);
1181     command->object_name_len = (unsigned int)length_until_newline(
1182                                                                   token, p_len - (unsigned int)(token - linebuf)) +
1183       1;
1184     command->type = COMMAND_O;
1185
1186     return 1;
1187   }
1188
1189   return 0;
1190 }
1191
1192 typedef struct {
1193   unsigned int pos;
1194   unsigned int len;
1195 } LineInfo;
1196
1197 static int is_line_ending(const char *p, unsigned int i, unsigned int end_i) {
1198   if (p[i] == '\0') return 1;
1199   if (p[i] == '\n') return 1; /* this includes \r\n */
1200   if (p[i] == '\r') {
1201     if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */
1202       return 1;
1203     }
1204   }
1205   return 0;
1206 }
1207
1208 int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
1209                       unsigned int *num_shapes, tinyobj_material_t **materials_out,
1210                       unsigned int *num_materials_out, const char *buf, unsigned int len,
1211                       unsigned int flags) {
1212   LineInfo *line_infos = NULL;
1213   Command *commands = NULL;
1214   unsigned int num_lines = 0;
1215
1216   unsigned int num_v = 0;
1217   unsigned int num_vn = 0;
1218   unsigned int num_vt = 0;
1219   unsigned int num_f = 0;
1220   unsigned int num_faces = 0;
1221
1222   int mtllib_line_index = -1;
1223
1224   tinyobj_material_t *materials = NULL;
1225   unsigned int num_materials = 0;
1226
1227   hash_table_t material_table;
1228
1229   if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER;
1230   if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1231   if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1232   if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1233   if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1234   if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1235   if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
1236
1237   tinyobj_attrib_init(attrib);
1238    /* 1. Find '\n' and create line data. */
1239   {
1240     unsigned int i;
1241     unsigned int end_idx = len;
1242     unsigned int prev_pos = 0;
1243     unsigned int line_no = 0;
1244     unsigned int last_line_ending = 0;
1245
1246     /* Count # of lines. */
1247     for (i = 0; i < end_idx; i++) {
1248       if (is_line_ending(buf, i, end_idx)) {
1249         num_lines++;
1250         last_line_ending = i;
1251       }
1252     }
1253     /* The last char from the input may not be a line
1254      * ending character so add an extra line if there
1255      * are more characters after the last line ending
1256      * that was found. */
1257     if (end_idx - last_line_ending > 0) {
1258         num_lines++;
1259     }
1260
1261     if (num_lines == 0) return TINYOBJ_ERROR_EMPTY;
1262
1263     line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines);
1264
1265     /* Fill line infos. */
1266     for (i = 0; i < end_idx; i++) {
1267       if (is_line_ending(buf, i, end_idx)) {
1268         line_infos[line_no].pos = prev_pos;
1269         line_infos[line_no].len = i - prev_pos;
1270         prev_pos = i + 1;
1271         line_no++;
1272       }
1273     }
1274     if (end_idx - last_line_ending > 0) {
1275       line_infos[line_no].pos = prev_pos;
1276       line_infos[line_no].len = end_idx - 1 - last_line_ending;
1277     }
1278   }
1279
1280   commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); 
1281
1282   create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table);
1283
1284   /* 2. parse each line */
1285   {
1286     unsigned int i = 0;
1287     for (i = 0; i < num_lines; i++) {
1288       int ret = parseLine(&commands[i], &buf[line_infos[i].pos],
1289                           line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE);
1290       if (ret) {
1291         if (commands[i].type == COMMAND_V) {
1292           num_v++;
1293         } else if (commands[i].type == COMMAND_VN) {
1294           num_vn++;
1295         } else if (commands[i].type == COMMAND_VT) {
1296           num_vt++;
1297         } else if (commands[i].type == COMMAND_F) {
1298           num_f += commands[i].num_f;
1299           num_faces += commands[i].num_f_num_verts;
1300         }
1301
1302         if (commands[i].type == COMMAND_MTLLIB) {
1303           mtllib_line_index = (int)i;
1304         }
1305       }
1306     }
1307   }
1308
1309   /* line_infos are not used anymore. Release memory. */
1310   if (line_infos) {
1311     TINYOBJ_FREE(line_infos);
1312   }
1313
1314   /* Load material(if exits) */
1315   if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name &&
1316       commands[mtllib_line_index].mtllib_name_len > 0) {
1317     char *filename = my_strndup(commands[mtllib_line_index].mtllib_name,
1318                                 commands[mtllib_line_index].mtllib_name_len);
1319
1320     int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table);
1321
1322     if (ret != TINYOBJ_SUCCESS) {
1323       /* warning. */
1324       fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret);
1325     }
1326
1327     TINYOBJ_FREE(filename);
1328
1329   }
1330
1331   /* Construct attributes */
1332
1333   {
1334     unsigned int v_count = 0;
1335     unsigned int n_count = 0;
1336     unsigned int t_count = 0;
1337     unsigned int f_count = 0;
1338     unsigned int face_count = 0;
1339     int material_id = -1; /* -1 = default unknown material. */
1340     unsigned int i = 0;
1341
1342     attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3);
1343     attrib->num_vertices = (unsigned int)num_v;
1344     attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3);
1345     attrib->num_normals = (unsigned int)num_vn;
1346     attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2);
1347     attrib->num_texcoords = (unsigned int)num_vt;
1348     attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f);
1349     attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
1350     
1351     attrib->num_faces = (unsigned int)num_faces;
1352     attrib->num_face_num_verts = (unsigned int)num_f;
1353     
1354     attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
1355
1356     for (i = 0; i < num_lines; i++) {
1357       if (commands[i].type == COMMAND_EMPTY) {
1358         continue;
1359       } else if (commands[i].type == COMMAND_USEMTL) {
1360         /* @todo
1361            if (commands[t][i].material_name &&
1362            commands[t][i].material_name_len > 0) {
1363            std::string material_name(commands[t][i].material_name,
1364            commands[t][i].material_name_len);
1365
1366            if (material_map.find(material_name) != material_map.end()) {
1367            material_id = material_map[material_name];
1368            } else {
1369         // Assign invalid material ID
1370         material_id = -1;
1371         }
1372         }
1373         */
1374         if (commands[i].material_name &&
1375            commands[i].material_name_len >0) 
1376         {
1377           /* Create a null terminated string */
1378           char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1);
1379           memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len);
1380           material_name_null_term[commands[i].material_name_len] = 0;
1381
1382           if (hash_table_exists(material_name_null_term, &material_table))
1383             material_id = (int)hash_table_get(material_name_null_term, &material_table);
1384           else
1385             material_id = -1;
1386
1387           TINYOBJ_FREE(material_name_null_term);
1388         }
1389       } else if (commands[i].type == COMMAND_V) {
1390         attrib->vertices[3 * v_count + 0] = commands[i].vx;
1391         attrib->vertices[3 * v_count + 1] = commands[i].vy;
1392         attrib->vertices[3 * v_count + 2] = commands[i].vz;
1393         v_count++;
1394       } else if (commands[i].type == COMMAND_VN) {
1395         attrib->normals[3 * n_count + 0] = commands[i].nx;
1396         attrib->normals[3 * n_count + 1] = commands[i].ny;
1397         attrib->normals[3 * n_count + 2] = commands[i].nz;
1398         n_count++;
1399       } else if (commands[i].type == COMMAND_VT) {
1400         attrib->texcoords[2 * t_count + 0] = commands[i].tx;
1401         attrib->texcoords[2 * t_count + 1] = commands[i].ty;
1402         t_count++;
1403       } else if (commands[i].type == COMMAND_F) {
1404         unsigned int k = 0;
1405         for (k = 0; k < commands[i].num_f; k++) {
1406           tinyobj_vertex_index_t vi = commands[i].f[k];
1407           int v_idx = fixIndex(vi.v_idx, v_count);
1408           int vn_idx = fixIndex(vi.vn_idx, n_count);
1409           int vt_idx = fixIndex(vi.vt_idx, t_count);
1410           attrib->faces[f_count + k].v_idx = v_idx;
1411           attrib->faces[f_count + k].vn_idx = vn_idx;
1412           attrib->faces[f_count + k].vt_idx = vt_idx;
1413         }
1414
1415         for (k = 0; k < commands[i].num_f_num_verts; k++) {
1416           attrib->material_ids[face_count + k] = material_id;
1417           attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k];
1418         }
1419
1420         f_count += commands[i].num_f;
1421         face_count += commands[i].num_f_num_verts;
1422       }
1423     }
1424   }
1425
1426   /* 5. Construct shape information. */
1427   {
1428     unsigned int face_count = 0;
1429     unsigned int i = 0;
1430     unsigned int n = 0;
1431     unsigned int shape_idx = 0;
1432
1433     const char *shape_name = NULL;
1434     unsigned int shape_name_len = 0;
1435     const char *prev_shape_name = NULL;
1436     unsigned int prev_shape_name_len = 0;
1437     unsigned int prev_shape_face_offset = 0;
1438     unsigned int prev_face_offset = 0;
1439     tinyobj_shape_t prev_shape = {NULL, 0, 0};
1440
1441     /* Find the number of shapes in .obj */
1442     for (i = 0; i < num_lines; i++) {
1443       if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) {
1444         n++;
1445       }
1446     }
1447
1448     /* Allocate array of shapes with maximum possible size(+1 for unnamed
1449      * group/object).
1450      * Actual # of shapes found in .obj is determined in the later */
1451     (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1));
1452
1453     for (i = 0; i < num_lines; i++) {
1454       if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) {
1455         if (commands[i].type == COMMAND_O) {
1456           shape_name = commands[i].object_name;
1457           shape_name_len = commands[i].object_name_len;
1458         } else {
1459           shape_name = commands[i].group_name;
1460           shape_name_len = commands[i].group_name_len;
1461         }
1462
1463         if (face_count == 0) {
1464           /* 'o' or 'g' appears before any 'f' */
1465           prev_shape_name = shape_name;
1466           prev_shape_name_len = shape_name_len;
1467           prev_shape_face_offset = face_count;
1468           prev_face_offset = face_count;
1469         } else {
1470           if (shape_idx == 0) {
1471             /* 'o' or 'g' after some 'v' lines. */
1472             (*shapes)[shape_idx].name = my_strndup(
1473                                                    prev_shape_name, prev_shape_name_len); /* may be NULL */
1474             (*shapes)[shape_idx].face_offset = prev_shape.face_offset;
1475             (*shapes)[shape_idx].length = face_count - prev_face_offset;
1476             shape_idx++;
1477
1478             prev_face_offset = face_count;
1479
1480           } else {
1481             if ((face_count - prev_face_offset) > 0) {
1482               (*shapes)[shape_idx].name =
1483                 my_strndup(prev_shape_name, prev_shape_name_len);
1484               (*shapes)[shape_idx].face_offset = prev_face_offset;
1485               (*shapes)[shape_idx].length = face_count - prev_face_offset;
1486               shape_idx++;
1487               prev_face_offset = face_count;
1488             }
1489           }
1490
1491           /* Record shape info for succeeding 'o' or 'g' command. */
1492           prev_shape_name = shape_name;
1493           prev_shape_name_len = shape_name_len;
1494           prev_shape_face_offset = face_count;
1495         }
1496       }
1497       if (commands[i].type == COMMAND_F) {
1498         face_count++;
1499       }
1500     }
1501
1502     if ((face_count - prev_face_offset) > 0) {
1503       unsigned int length = face_count - prev_shape_face_offset;
1504       if (length > 0) {
1505         (*shapes)[shape_idx].name =
1506           my_strndup(prev_shape_name, prev_shape_name_len);
1507         (*shapes)[shape_idx].face_offset = prev_face_offset;
1508         (*shapes)[shape_idx].length = face_count - prev_face_offset;
1509         shape_idx++;
1510       }
1511     } else {
1512       /* Guess no 'v' line occurrence after 'o' or 'g', so discards current
1513        * shape information. */
1514     }
1515
1516     (*num_shapes) = shape_idx;
1517   }
1518
1519   if (commands) {
1520     TINYOBJ_FREE(commands);
1521   }
1522
1523   destroy_hash_table(&material_table);
1524   
1525   (*materials_out) = materials;
1526   (*num_materials_out) = num_materials;
1527
1528   return TINYOBJ_SUCCESS;
1529 }
1530
1531 void tinyobj_attrib_init(tinyobj_attrib_t *attrib) {
1532   attrib->vertices = NULL;
1533   attrib->num_vertices = 0;
1534   attrib->normals = NULL;
1535   attrib->num_normals = 0;
1536   attrib->texcoords = NULL;
1537   attrib->num_texcoords = 0;
1538   attrib->faces = NULL;
1539   attrib->num_faces = 0;
1540   attrib->face_num_verts = NULL;
1541   attrib->num_face_num_verts = 0;
1542   attrib->material_ids = NULL;
1543 }
1544
1545 void tinyobj_attrib_free(tinyobj_attrib_t *attrib) {
1546   if (attrib->vertices) TINYOBJ_FREE(attrib->vertices);
1547   if (attrib->normals) TINYOBJ_FREE(attrib->normals);
1548   if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords);
1549   if (attrib->faces) TINYOBJ_FREE(attrib->faces);
1550   if (attrib->face_num_verts) TINYOBJ_FREE(attrib->face_num_verts);
1551   if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids);
1552 }
1553
1554 void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes) {
1555   unsigned int i;
1556   if (shapes == NULL) return;
1557
1558   for (i = 0; i < num_shapes; i++) {
1559     if (shapes[i].name) TINYOBJ_FREE(shapes[i].name);
1560   }
1561
1562   TINYOBJ_FREE(shapes);
1563 }
1564
1565 void tinyobj_materials_free(tinyobj_material_t *materials,
1566                             unsigned int num_materials) {
1567   unsigned int i;
1568   if (materials == NULL) return;
1569
1570   for (i = 0; i < num_materials; i++) {
1571     if (materials[i].name) TINYOBJ_FREE(materials[i].name);
1572     if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname);
1573     if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname);
1574     if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname);
1575     if (materials[i].specular_highlight_texname)
1576       TINYOBJ_FREE(materials[i].specular_highlight_texname);
1577     if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname);
1578     if (materials[i].displacement_texname)
1579       TINYOBJ_FREE(materials[i].displacement_texname);
1580     if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname);
1581   }
1582
1583   TINYOBJ_FREE(materials);
1584 }
1585 #endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */
1586
1587 #endif /* TINOBJ_LOADER_C_H_ */