github.com/Konstantin8105/c4go@v0.0.0-20240505174241-768bb1c65a51/tests/raylib/external/tinyobj_loader_c.h (about)

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