medfall

A super great game engine
Log | Files | Refs

tinyobjloader.h (43089B)


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