minesweeper

A minewseeper implementation to play around with Hare and Raylib
git clone https://git.tronto.net/minesweeper
Download | Log | Files | Refs | README | LICENSE

tinyobj_loader_c.h (45666B)


      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, "rt");
    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   fclose(fp);
    952 
    953   if (material.name) {
    954     /* Flush last material element */
    955     materials = tinyobj_material_add(materials, num_materials, &material);
    956     num_materials++;
    957   }
    958 
    959   (*num_materials_out) = num_materials;
    960   (*materials_out) = materials;
    961 
    962   if (linebuf) {
    963     TINYOBJ_FREE(linebuf);
    964   }
    965 
    966   return TINYOBJ_SUCCESS;
    967 }
    968 
    969 int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out,
    970                            unsigned int *num_materials_out,
    971                            const char *filename) {
    972   return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL);
    973 } 
    974 
    975 
    976 typedef enum {
    977   COMMAND_EMPTY,
    978   COMMAND_V,
    979   COMMAND_VN,
    980   COMMAND_VT,
    981   COMMAND_F,
    982   COMMAND_G,
    983   COMMAND_O,
    984   COMMAND_USEMTL,
    985   COMMAND_MTLLIB
    986 
    987 } CommandType;
    988 
    989 typedef struct {
    990   float vx, vy, vz;
    991   float nx, ny, nz;
    992   float tx, ty;
    993 
    994   /* @todo { Use dynamic array } */
    995   tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
    996   unsigned int num_f;
    997 
    998   int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE];
    999   unsigned int num_f_num_verts;
   1000 
   1001   const char *group_name;
   1002   unsigned int group_name_len;
   1003   int pad0;
   1004 
   1005   const char *object_name;
   1006   unsigned int object_name_len;
   1007   int pad1;
   1008 
   1009   const char *material_name;
   1010   unsigned int material_name_len;
   1011   int pad2;
   1012 
   1013   const char *mtllib_name;
   1014   unsigned int mtllib_name_len;
   1015 
   1016   CommandType type;
   1017 } Command;
   1018 
   1019 static int parseLine(Command *command, const char *p, unsigned int p_len,
   1020                      int triangulate) {
   1021   char linebuf[4096];
   1022   const char *token;
   1023   assert(p_len < 4095);
   1024 
   1025   memcpy(linebuf, p, p_len);
   1026   linebuf[p_len] = '\0';
   1027 
   1028   token = linebuf;
   1029 
   1030   command->type = COMMAND_EMPTY;
   1031 
   1032   /* Skip leading space. */
   1033   skip_space(&token);
   1034 
   1035   assert(token);
   1036   if (token[0] == '\0') { /* empty line */
   1037     return 0;
   1038   }
   1039 
   1040   if (token[0] == '#') { /* comment line */
   1041     return 0;
   1042   }
   1043 
   1044   /* vertex */
   1045   if (token[0] == 'v' && IS_SPACE((token[1]))) {
   1046     float x, y, z;
   1047     token += 2;
   1048     parseFloat3(&x, &y, &z, &token);
   1049     command->vx = x;
   1050     command->vy = y;
   1051     command->vz = z;
   1052     command->type = COMMAND_V;
   1053     return 1;
   1054   }
   1055 
   1056   /* normal */
   1057   if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) {
   1058     float x, y, z;
   1059     token += 3;
   1060     parseFloat3(&x, &y, &z, &token);
   1061     command->nx = x;
   1062     command->ny = y;
   1063     command->nz = z;
   1064     command->type = COMMAND_VN;
   1065     return 1;
   1066   }
   1067 
   1068   /* texcoord */
   1069   if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) {
   1070     float x, y;
   1071     token += 3;
   1072     parseFloat2(&x, &y, &token);
   1073     command->tx = x;
   1074     command->ty = y;
   1075     command->type = COMMAND_VT;
   1076     return 1;
   1077   }
   1078 
   1079   /* face */
   1080   if (token[0] == 'f' && IS_SPACE((token[1]))) {
   1081     unsigned int num_f = 0;
   1082 
   1083     tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
   1084     token += 2;
   1085     skip_space(&token);
   1086 
   1087     while (!IS_NEW_LINE(token[0])) {
   1088       tinyobj_vertex_index_t vi = parseRawTriple(&token);
   1089       skip_space_and_cr(&token);
   1090 
   1091       f[num_f] = vi;
   1092       num_f++;
   1093     }
   1094 
   1095     command->type = COMMAND_F;
   1096 
   1097     if (triangulate) {
   1098       unsigned int k;
   1099       unsigned int n = 0;
   1100 
   1101       tinyobj_vertex_index_t i0 = f[0];
   1102       tinyobj_vertex_index_t i1;
   1103       tinyobj_vertex_index_t i2 = f[1];
   1104 
   1105       assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
   1106 
   1107       for (k = 2; k < num_f; k++) {
   1108         i1 = i2;
   1109         i2 = f[k];
   1110         command->f[3 * n + 0] = i0;
   1111         command->f[3 * n + 1] = i1;
   1112         command->f[3 * n + 2] = i2;
   1113 
   1114         command->f_num_verts[n] = 3;
   1115         n++;
   1116       }
   1117       command->num_f = 3 * n;
   1118       command->num_f_num_verts = n;
   1119 
   1120     } else {
   1121       unsigned int k = 0;
   1122       assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
   1123       for (k = 0; k < num_f; k++) {
   1124         command->f[k] = f[k];
   1125       }
   1126 
   1127       command->num_f = num_f;
   1128       command->f_num_verts[0] = (int)num_f;
   1129       command->num_f_num_verts = 1;
   1130     }
   1131 
   1132     return 1;
   1133   }
   1134 
   1135   /* use mtl */
   1136   if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) {
   1137     token += 7;
   1138 
   1139     skip_space(&token);
   1140     command->material_name = p + (token - linebuf);
   1141     command->material_name_len = (unsigned int)length_until_newline(
   1142                                                                     token, (p_len - (unsigned int)(token - linebuf)) + 1);
   1143     command->type = COMMAND_USEMTL;
   1144 
   1145     return 1;
   1146   }
   1147 
   1148   /* load mtl */
   1149   if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) {
   1150     /* By specification, `mtllib` should be appear only once in .obj */
   1151     token += 7;
   1152 
   1153     skip_space(&token);
   1154     command->mtllib_name = p + (token - linebuf);
   1155     command->mtllib_name_len = (unsigned int)length_until_newline(
   1156                                                                   token, p_len - (unsigned int)(token - linebuf)) +
   1157       1;
   1158     command->type = COMMAND_MTLLIB;
   1159 
   1160     return 1;
   1161   }
   1162 
   1163   /* group name */
   1164   if (token[0] == 'g' && IS_SPACE((token[1]))) {
   1165     /* @todo { multiple group name. } */
   1166     token += 2;
   1167 
   1168     command->group_name = p + (token - linebuf);
   1169     command->group_name_len = (unsigned int)length_until_newline(
   1170                                                                  token, p_len - (unsigned int)(token - linebuf)) +
   1171       1;
   1172     command->type = COMMAND_G;
   1173 
   1174     return 1;
   1175   }
   1176 
   1177   /* object name */
   1178   if (token[0] == 'o' && IS_SPACE((token[1]))) {
   1179     /* @todo { multiple object name? } */
   1180     token += 2;
   1181 
   1182     command->object_name = p + (token - linebuf);
   1183     command->object_name_len = (unsigned int)length_until_newline(
   1184                                                                   token, p_len - (unsigned int)(token - linebuf)) +
   1185       1;
   1186     command->type = COMMAND_O;
   1187 
   1188     return 1;
   1189   }
   1190 
   1191   return 0;
   1192 }
   1193 
   1194 typedef struct {
   1195   unsigned int pos;
   1196   unsigned int len;
   1197 } LineInfo;
   1198 
   1199 static int is_line_ending(const char *p, unsigned int i, unsigned int end_i) {
   1200   if (p[i] == '\0') return 1;
   1201   if (p[i] == '\n') return 1; /* this includes \r\n */
   1202   if (p[i] == '\r') {
   1203     if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */
   1204       return 1;
   1205     }
   1206   }
   1207   return 0;
   1208 }
   1209 
   1210 int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
   1211                       unsigned int *num_shapes, tinyobj_material_t **materials_out,
   1212                       unsigned int *num_materials_out, const char *buf, unsigned int len,
   1213                       unsigned int flags) {
   1214   LineInfo *line_infos = NULL;
   1215   Command *commands = NULL;
   1216   unsigned int num_lines = 0;
   1217 
   1218   unsigned int num_v = 0;
   1219   unsigned int num_vn = 0;
   1220   unsigned int num_vt = 0;
   1221   unsigned int num_f = 0;
   1222   unsigned int num_faces = 0;
   1223 
   1224   int mtllib_line_index = -1;
   1225 
   1226   tinyobj_material_t *materials = NULL;
   1227   unsigned int num_materials = 0;
   1228 
   1229   hash_table_t material_table;
   1230 
   1231   if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1232   if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1233   if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1234   if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1235   if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1236   if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1237   if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
   1238 
   1239   tinyobj_attrib_init(attrib);
   1240    /* 1. Find '\n' and create line data. */
   1241   {
   1242     unsigned int i;
   1243     unsigned int end_idx = len;
   1244     unsigned int prev_pos = 0;
   1245     unsigned int line_no = 0;
   1246     unsigned int last_line_ending = 0;
   1247 
   1248     /* Count # of lines. */
   1249     for (i = 0; i < end_idx; i++) {
   1250       if (is_line_ending(buf, i, end_idx)) {
   1251         num_lines++;
   1252         last_line_ending = i;
   1253       }
   1254     }
   1255     /* The last char from the input may not be a line
   1256      * ending character so add an extra line if there
   1257      * are more characters after the last line ending
   1258      * that was found. */
   1259     if (end_idx - last_line_ending > 0) {
   1260         num_lines++;
   1261     }
   1262 
   1263     if (num_lines == 0) return TINYOBJ_ERROR_EMPTY;
   1264 
   1265     line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines);
   1266 
   1267     /* Fill line infos. */
   1268     for (i = 0; i < end_idx; i++) {
   1269       if (is_line_ending(buf, i, end_idx)) {
   1270         line_infos[line_no].pos = prev_pos;
   1271         line_infos[line_no].len = i - prev_pos;
   1272          
   1273 // ---- QUICK BUG FIX : https://github.com/raysan5/raylib/issues/3473
   1274         if ( i > 0 && buf[i-1] == '\r' ) line_infos[line_no].len--;
   1275 // --------
   1276 
   1277         prev_pos = i + 1;
   1278         line_no++;
   1279       }
   1280     }
   1281     if (end_idx - last_line_ending > 0) {
   1282       line_infos[line_no].pos = prev_pos;
   1283       line_infos[line_no].len = end_idx - 1 - last_line_ending;
   1284     }
   1285   }
   1286 
   1287   commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); 
   1288 
   1289   create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table);
   1290 
   1291   /* 2. parse each line */
   1292   {
   1293     unsigned int i = 0;
   1294     for (i = 0; i < num_lines; i++) {
   1295       int ret = parseLine(&commands[i], &buf[line_infos[i].pos],
   1296                           line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE);
   1297       if (ret) {
   1298         if (commands[i].type == COMMAND_V) {
   1299           num_v++;
   1300         } else if (commands[i].type == COMMAND_VN) {
   1301           num_vn++;
   1302         } else if (commands[i].type == COMMAND_VT) {
   1303           num_vt++;
   1304         } else if (commands[i].type == COMMAND_F) {
   1305           num_f += commands[i].num_f;
   1306           num_faces += commands[i].num_f_num_verts;
   1307         }
   1308 
   1309         if (commands[i].type == COMMAND_MTLLIB) {
   1310           mtllib_line_index = (int)i;
   1311         }
   1312       }
   1313     }
   1314   }
   1315 
   1316   /* line_infos are not used anymore. Release memory. */
   1317   if (line_infos) {
   1318     TINYOBJ_FREE(line_infos);
   1319   }
   1320 
   1321   /* Load material(if exits) */
   1322   if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name &&
   1323       commands[mtllib_line_index].mtllib_name_len > 0) {
   1324     char *filename = my_strndup(commands[mtllib_line_index].mtllib_name,
   1325                                 commands[mtllib_line_index].mtllib_name_len);
   1326 
   1327     int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table);
   1328 
   1329     if (ret != TINYOBJ_SUCCESS) {
   1330       /* warning. */
   1331       fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret);
   1332     }
   1333 
   1334     TINYOBJ_FREE(filename);
   1335 
   1336   }
   1337 
   1338   /* Construct attributes */
   1339 
   1340   {
   1341     unsigned int v_count = 0;
   1342     unsigned int n_count = 0;
   1343     unsigned int t_count = 0;
   1344     unsigned int f_count = 0;
   1345     unsigned int face_count = 0;
   1346     int material_id = -1; /* -1 = default unknown material. */
   1347     unsigned int i = 0;
   1348 
   1349     attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3);
   1350     attrib->num_vertices = (unsigned int)num_v;
   1351     attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3);
   1352     attrib->num_normals = (unsigned int)num_vn;
   1353     attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2);
   1354     attrib->num_texcoords = (unsigned int)num_vt;
   1355     attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f);
   1356     attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
   1357     
   1358     attrib->num_faces = (unsigned int)num_faces;
   1359     attrib->num_face_num_verts = (unsigned int)num_f;
   1360     
   1361     attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
   1362 
   1363     for (i = 0; i < num_lines; i++) {
   1364       if (commands[i].type == COMMAND_EMPTY) {
   1365         continue;
   1366       } else if (commands[i].type == COMMAND_USEMTL) {
   1367         /* @todo
   1368            if (commands[t][i].material_name &&
   1369            commands[t][i].material_name_len > 0) {
   1370            std::string material_name(commands[t][i].material_name,
   1371            commands[t][i].material_name_len);
   1372 
   1373            if (material_map.find(material_name) != material_map.end()) {
   1374            material_id = material_map[material_name];
   1375            } else {
   1376         // Assign invalid material ID
   1377         material_id = -1;
   1378         }
   1379         }
   1380         */
   1381         if (commands[i].material_name &&
   1382            commands[i].material_name_len >0) 
   1383         {
   1384           /* Create a null terminated string */
   1385           char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1);
   1386           memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len);
   1387           material_name_null_term[commands[i].material_name_len] = 0;
   1388 
   1389           if (hash_table_exists(material_name_null_term, &material_table))
   1390             material_id = (int)hash_table_get(material_name_null_term, &material_table);
   1391           else
   1392             material_id = -1;
   1393 
   1394           TINYOBJ_FREE(material_name_null_term);
   1395         }
   1396       } else if (commands[i].type == COMMAND_V) {
   1397         attrib->vertices[3 * v_count + 0] = commands[i].vx;
   1398         attrib->vertices[3 * v_count + 1] = commands[i].vy;
   1399         attrib->vertices[3 * v_count + 2] = commands[i].vz;
   1400         v_count++;
   1401       } else if (commands[i].type == COMMAND_VN) {
   1402         attrib->normals[3 * n_count + 0] = commands[i].nx;
   1403         attrib->normals[3 * n_count + 1] = commands[i].ny;
   1404         attrib->normals[3 * n_count + 2] = commands[i].nz;
   1405         n_count++;
   1406       } else if (commands[i].type == COMMAND_VT) {
   1407         attrib->texcoords[2 * t_count + 0] = commands[i].tx;
   1408         attrib->texcoords[2 * t_count + 1] = commands[i].ty;
   1409         t_count++;
   1410       } else if (commands[i].type == COMMAND_F) {
   1411         unsigned int k = 0;
   1412         for (k = 0; k < commands[i].num_f; k++) {
   1413           tinyobj_vertex_index_t vi = commands[i].f[k];
   1414           int v_idx = fixIndex(vi.v_idx, v_count);
   1415           int vn_idx = fixIndex(vi.vn_idx, n_count);
   1416           int vt_idx = fixIndex(vi.vt_idx, t_count);
   1417           attrib->faces[f_count + k].v_idx = v_idx;
   1418           attrib->faces[f_count + k].vn_idx = vn_idx;
   1419           attrib->faces[f_count + k].vt_idx = vt_idx;
   1420         }
   1421 
   1422         for (k = 0; k < commands[i].num_f_num_verts; k++) {
   1423           attrib->material_ids[face_count + k] = material_id;
   1424           attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k];
   1425         }
   1426 
   1427         f_count += commands[i].num_f;
   1428         face_count += commands[i].num_f_num_verts;
   1429       }
   1430     }
   1431   }
   1432 
   1433   /* 5. Construct shape information. */
   1434   {
   1435     unsigned int face_count = 0;
   1436     unsigned int i = 0;
   1437     unsigned int n = 0;
   1438     unsigned int shape_idx = 0;
   1439 
   1440     const char *shape_name = NULL;
   1441     unsigned int shape_name_len = 0;
   1442     const char *prev_shape_name = NULL;
   1443     unsigned int prev_shape_name_len = 0;
   1444     unsigned int prev_shape_face_offset = 0;
   1445     unsigned int prev_face_offset = 0;
   1446     tinyobj_shape_t prev_shape = {NULL, 0, 0};
   1447 
   1448     /* Find the number of shapes in .obj */
   1449     for (i = 0; i < num_lines; i++) {
   1450       if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) {
   1451         n++;
   1452       }
   1453     }
   1454 
   1455     /* Allocate array of shapes with maximum possible size(+1 for unnamed
   1456      * group/object).
   1457      * Actual # of shapes found in .obj is determined in the later */
   1458     (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1));
   1459 
   1460     for (i = 0; i < num_lines; i++) {
   1461       if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) {
   1462         if (commands[i].type == COMMAND_O) {
   1463           shape_name = commands[i].object_name;
   1464           shape_name_len = commands[i].object_name_len;
   1465         } else {
   1466           shape_name = commands[i].group_name;
   1467           shape_name_len = commands[i].group_name_len;
   1468         }
   1469 
   1470         if (face_count == 0) {
   1471           /* 'o' or 'g' appears before any 'f' */
   1472           prev_shape_name = shape_name;
   1473           prev_shape_name_len = shape_name_len;
   1474           prev_shape_face_offset = face_count;
   1475           prev_face_offset = face_count;
   1476         } else {
   1477           if (shape_idx == 0) {
   1478             /* 'o' or 'g' after some 'v' lines. */
   1479             (*shapes)[shape_idx].name = my_strndup(
   1480                                                    prev_shape_name, prev_shape_name_len); /* may be NULL */
   1481             (*shapes)[shape_idx].face_offset = prev_shape.face_offset;
   1482             (*shapes)[shape_idx].length = face_count - prev_face_offset;
   1483             shape_idx++;
   1484 
   1485             prev_face_offset = face_count;
   1486 
   1487           } else {
   1488             if ((face_count - prev_face_offset) > 0) {
   1489               (*shapes)[shape_idx].name =
   1490                 my_strndup(prev_shape_name, prev_shape_name_len);
   1491               (*shapes)[shape_idx].face_offset = prev_face_offset;
   1492               (*shapes)[shape_idx].length = face_count - prev_face_offset;
   1493               shape_idx++;
   1494               prev_face_offset = face_count;
   1495             }
   1496           }
   1497 
   1498           /* Record shape info for succeeding 'o' or 'g' command. */
   1499           prev_shape_name = shape_name;
   1500           prev_shape_name_len = shape_name_len;
   1501           prev_shape_face_offset = face_count;
   1502         }
   1503       }
   1504       if (commands[i].type == COMMAND_F) {
   1505         face_count++;
   1506       }
   1507     }
   1508 
   1509     if ((face_count - prev_face_offset) > 0) {
   1510       unsigned int length = face_count - prev_shape_face_offset;
   1511       if (length > 0) {
   1512         (*shapes)[shape_idx].name =
   1513           my_strndup(prev_shape_name, prev_shape_name_len);
   1514         (*shapes)[shape_idx].face_offset = prev_face_offset;
   1515         (*shapes)[shape_idx].length = face_count - prev_face_offset;
   1516         shape_idx++;
   1517       }
   1518     } else {
   1519       /* Guess no 'v' line occurrence after 'o' or 'g', so discards current
   1520        * shape information. */
   1521     }
   1522 
   1523     (*num_shapes) = shape_idx;
   1524   }
   1525 
   1526   if (commands) {
   1527     TINYOBJ_FREE(commands);
   1528   }
   1529 
   1530   destroy_hash_table(&material_table);
   1531   
   1532   (*materials_out) = materials;
   1533   (*num_materials_out) = num_materials;
   1534 
   1535   return TINYOBJ_SUCCESS;
   1536 }
   1537 
   1538 void tinyobj_attrib_init(tinyobj_attrib_t *attrib) {
   1539   attrib->vertices = NULL;
   1540   attrib->num_vertices = 0;
   1541   attrib->normals = NULL;
   1542   attrib->num_normals = 0;
   1543   attrib->texcoords = NULL;
   1544   attrib->num_texcoords = 0;
   1545   attrib->faces = NULL;
   1546   attrib->num_faces = 0;
   1547   attrib->face_num_verts = NULL;
   1548   attrib->num_face_num_verts = 0;
   1549   attrib->material_ids = NULL;
   1550 }
   1551 
   1552 void tinyobj_attrib_free(tinyobj_attrib_t *attrib) {
   1553   if (attrib->vertices) TINYOBJ_FREE(attrib->vertices);
   1554   if (attrib->normals) TINYOBJ_FREE(attrib->normals);
   1555   if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords);
   1556   if (attrib->faces) TINYOBJ_FREE(attrib->faces);
   1557   if (attrib->face_num_verts) TINYOBJ_FREE(attrib->face_num_verts);
   1558   if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids);
   1559 }
   1560 
   1561 void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes) {
   1562   unsigned int i;
   1563   if (shapes == NULL) return;
   1564 
   1565   for (i = 0; i < num_shapes; i++) {
   1566     if (shapes[i].name) TINYOBJ_FREE(shapes[i].name);
   1567   }
   1568 
   1569   TINYOBJ_FREE(shapes);
   1570 }
   1571 
   1572 void tinyobj_materials_free(tinyobj_material_t *materials,
   1573                             unsigned int num_materials) {
   1574   unsigned int i;
   1575   if (materials == NULL) return;
   1576 
   1577   for (i = 0; i < num_materials; i++) {
   1578     if (materials[i].name) TINYOBJ_FREE(materials[i].name);
   1579     if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname);
   1580     if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname);
   1581     if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname);
   1582     if (materials[i].specular_highlight_texname)
   1583       TINYOBJ_FREE(materials[i].specular_highlight_texname);
   1584     if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname);
   1585     if (materials[i].displacement_texname)
   1586       TINYOBJ_FREE(materials[i].displacement_texname);
   1587     if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname);
   1588   }
   1589 
   1590   TINYOBJ_FREE(materials);
   1591 }
   1592 #endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */
   1593 
   1594 #endif /* TINOBJ_LOADER_C_H_ */