diff options
Diffstat (limited to 'libs/raylib/src/external/tinyobj_loader_c.h')
-rw-r--r-- | libs/raylib/src/external/tinyobj_loader_c.h | 1587 |
1 files changed, 0 insertions, 1587 deletions
diff --git a/libs/raylib/src/external/tinyobj_loader_c.h b/libs/raylib/src/external/tinyobj_loader_c.h deleted file mode 100644 index 7ef55ff..0000000 --- a/libs/raylib/src/external/tinyobj_loader_c.h +++ /dev/null @@ -1,1587 +0,0 @@ -/* - The MIT License (MIT) - - Copyright (c) 2016 - 2019 Syoyo Fujita and many contributors. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. - */ -#ifndef TINOBJ_LOADER_C_H_ -#define TINOBJ_LOADER_C_H_ - -/* @todo { Remove stddef dependency. unsigned int? } ---> RAY: DONE. */ -//#include <stddef.h> - -typedef struct { - char *name; - - float ambient[3]; - float diffuse[3]; - float specular[3]; - float transmittance[3]; - float emission[3]; - float shininess; - float ior; /* index of refraction */ - float dissolve; /* 1 == opaque; 0 == fully transparent */ - /* illumination model (see http://www.fileformat.info/format/material/) */ - int illum; - - int pad0; - - char *ambient_texname; /* map_Ka */ - char *diffuse_texname; /* map_Kd */ - char *specular_texname; /* map_Ks */ - char *specular_highlight_texname; /* map_Ns */ - char *bump_texname; /* map_bump, bump */ - char *displacement_texname; /* disp */ - char *alpha_texname; /* map_d */ -} tinyobj_material_t; - -typedef struct { - char *name; /* group name or object name. */ - unsigned int face_offset; - unsigned int length; -} tinyobj_shape_t; - -typedef struct { int v_idx, vt_idx, vn_idx; } tinyobj_vertex_index_t; - -typedef struct { - unsigned int num_vertices; - unsigned int num_normals; - unsigned int num_texcoords; - unsigned int num_faces; - unsigned int num_face_num_verts; - - int pad0; - - float *vertices; - float *normals; - float *texcoords; - tinyobj_vertex_index_t *faces; - int *face_num_verts; - int *material_ids; -} tinyobj_attrib_t; - - -#define TINYOBJ_FLAG_TRIANGULATE (1 << 0) - -#define TINYOBJ_INVALID_INDEX (0x80000000) - -#define TINYOBJ_SUCCESS (0) -#define TINYOBJ_ERROR_EMPTY (-1) -#define TINYOBJ_ERROR_INVALID_PARAMETER (-2) -#define TINYOBJ_ERROR_FILE_OPERATION (-3) - -/* Parse wavefront .obj(.obj string data is expanded to linear char array `buf') - * flags are combination of TINYOBJ_FLAG_*** - * Returns TINYOBJ_SUCCESS if things goes well. - * Returns TINYOBJ_ERR_*** when there is an error. - */ -extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, - unsigned int *num_shapes, tinyobj_material_t **materials, - unsigned int *num_materials, const char *buf, unsigned int len, - unsigned int flags); -extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, - unsigned int *num_materials_out, - const char *filename); - -extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); -extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); -extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes); -extern void tinyobj_materials_free(tinyobj_material_t *materials, - unsigned int num_materials); - -#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION -#include <stdio.h> -#include <assert.h> -#include <string.h> -#include <errno.h> - -#if defined(TINYOBJ_MALLOC) && defined(TINYOBJ_REALLOC) && defined(TINYOBJ_CALLOC) && defined(TINYOBJ_FREE) -/* ok */ -#elif !defined(TINYOBJ_MALLOC) && !defined(TINYOBJ_REALLOC) && !defined(TINYOBJ_CALLOC) && !defined(TINYOBJ_FREE) -/* ok */ -#else -#error "Must define all or none of TINYOBJ_MALLOC, TINYOBJ_REALLOC, TINYOBJ_CALLOC and TINYOBJ_FREE." -#endif - -#ifndef TINYOBJ_MALLOC -#include <stdlib.h> -#define TINYOBJ_MALLOC malloc -#define TINYOBJ_REALLOC realloc -#define TINYOBJ_CALLOC calloc -#define TINYOBJ_FREE free -#endif - -#define TINYOBJ_MAX_FACES_PER_F_LINE (16) - -#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) -#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) -#define IS_NEW_LINE(x) (((x) == '\r') || ((x) == '\n') || ((x) == '\0')) - -static void skip_space(const char **token) { - while ((*token)[0] == ' ' || (*token)[0] == '\t') { - (*token)++; - } -} - -static void skip_space_and_cr(const char **token) { - while ((*token)[0] == ' ' || (*token)[0] == '\t' || (*token)[0] == '\r') { - (*token)++; - } -} - -static int until_space(const char *token) { - const char *p = token; - while (p[0] != '\0' && p[0] != ' ' && p[0] != '\t' && p[0] != '\r') { - p++; - } - - return (int)(p - token); -} - -static unsigned int length_until_newline(const char *token, unsigned int n) { - unsigned int len = 0; - - /* Assume token[n-1] = '\0' */ - for (len = 0; len < n - 1; len++) { - if (token[len] == '\n') { - break; - } - if ((token[len] == '\r') && ((len < (n - 2)) && (token[len + 1] != '\n'))) { - break; - } - } - - return len; -} - -static unsigned int length_until_line_feed(const char *token, unsigned int n) { - unsigned int len = 0; - - /* Assume token[n-1] = '\0' */ - for (len = 0; len < n; len++) { - if ((token[len] == '\n') || (token[len] == '\r')) { - break; - } - } - - return len; -} - -/* http://stackoverflow.com/questions/5710091/how-does-atoi-function-in-c-work -*/ -static int my_atoi(const char *c) { - int value = 0; - int sign = 1; - if (*c == '+' || *c == '-') { - if (*c == '-') sign = -1; - c++; - } - while (((*c) >= '0') && ((*c) <= '9')) { /* isdigit(*c) */ - value *= 10; - value += (int)(*c - '0'); - c++; - } - return value * sign; -} - -/* Make index zero-base, and also support relative index. */ -static int fixIndex(int idx, unsigned int n) { - if (idx > 0) return idx - 1; - if (idx == 0) return 0; - return (int)n + idx; /* negative value = relative */ -} - -/* Parse raw triples: i, i/j/k, i//k, i/j */ -static tinyobj_vertex_index_t parseRawTriple(const char **token) { - tinyobj_vertex_index_t vi; - /* 0x80000000 = -2147483648 = invalid */ - vi.v_idx = (int)(0x80000000); - vi.vn_idx = (int)(0x80000000); - vi.vt_idx = (int)(0x80000000); - - vi.v_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - if ((*token)[0] != '/') { - return vi; - } - (*token)++; - - /* i//k */ - if ((*token)[0] == '/') { - (*token)++; - vi.vn_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - return vi; - } - - /* i/j/k or i/j */ - vi.vt_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - if ((*token)[0] != '/') { - return vi; - } - - /* i/j/k */ - (*token)++; /* skip '/' */ - vi.vn_idx = my_atoi((*token)); - while ((*token)[0] != '\0' && (*token)[0] != '/' && (*token)[0] != ' ' && - (*token)[0] != '\t' && (*token)[0] != '\r') { - (*token)++; - } - return vi; -} - -static int parseInt(const char **token) { - int i = 0; - skip_space(token); - i = my_atoi((*token)); - (*token) += until_space((*token)); - return i; -} - -/* - * Tries to parse a floating point number located at s. - * - * s_end should be a location in the string where reading should absolutely - * stop. For example at the end of the string, to prevent buffer overflows. - * - * Parses the following EBNF grammar: - * sign = "+" | "-" ; - * END = ? anything not in digit ? - * digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ; - * integer = [sign] , digit , {digit} ; - * decimal = integer , ["." , integer] ; - * float = ( decimal , END ) | ( decimal , ("E" | "e") , integer , END ) ; - * - * Valid strings are for example: - * -0 +3.1417e+2 -0.0E-3 1.0324 -1.41 11e2 - * - * If the parsing is a success, result is set to the parsed value and true - * is returned. - * - * The function is greedy and will parse until any of the following happens: - * - a non-conforming character is encountered. - * - s_end is reached. - * - * The following situations triggers a failure: - * - s >= s_end. - * - parse failure. - */ -static int tryParseDouble(const char *s, const char *s_end, double *result) { - double mantissa = 0.0; - /* This exponent is base 2 rather than 10. - * However the exponent we parse is supposed to be one of ten, - * thus we must take care to convert the exponent/and or the - * mantissa to a * 2^E, where a is the mantissa and E is the - * exponent. - * To get the final double we will use ldexp, it requires the - * exponent to be in base 2. - */ - int exponent = 0; - - /* NOTE: THESE MUST BE DECLARED HERE SINCE WE ARE NOT ALLOWED - * TO JUMP OVER DEFINITIONS. - */ - char sign = '+'; - char exp_sign = '+'; - char const *curr = s; - - /* How many characters were read in a loop. */ - int read = 0; - /* Tells whether a loop terminated due to reaching s_end. */ - int end_not_reached = 0; - - /* - BEGIN PARSING. - */ - - if (s >= s_end) { - return 0; /* fail */ - } - - /* Find out what sign we've got. */ - if (*curr == '+' || *curr == '-') { - sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - goto fail; - } - - /* Read the integer part. */ - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - mantissa *= 10; - mantissa += (int)(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - - /* We must make sure we actually got something. */ - if (read == 0) goto fail; - /* We allow numbers of form "#", "###" etc. */ - if (!end_not_reached) goto assemble; - - /* Read the decimal part. */ - if (*curr == '.') { - curr++; - read = 1; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - /* pow(10.0, -read) */ - double frac_value = 1.0; - int f; - for (f = 0; f < read; f++) { - frac_value *= 0.1; - } - mantissa += (int)(*curr - 0x30) * frac_value; - read++; - curr++; - end_not_reached = (curr != s_end); - } - } else if (*curr == 'e' || *curr == 'E') { - } else { - goto assemble; - } - - if (!end_not_reached) goto assemble; - - /* Read the exponent part. */ - if (*curr == 'e' || *curr == 'E') { - curr++; - /* Figure out if a sign is present and if it is. */ - end_not_reached = (curr != s_end); - if (end_not_reached && (*curr == '+' || *curr == '-')) { - exp_sign = *curr; - curr++; - } else if (IS_DIGIT(*curr)) { /* Pass through. */ - } else { - /* Empty E is not allowed. */ - goto fail; - } - - read = 0; - end_not_reached = (curr != s_end); - while (end_not_reached && IS_DIGIT(*curr)) { - exponent *= 10; - exponent += (int)(*curr - 0x30); - curr++; - read++; - end_not_reached = (curr != s_end); - } - if (read == 0) goto fail; - } - -assemble : - - { - double a = 1.0; /* = pow(5.0, exponent); */ - double b = 1.0; /* = 2.0^exponent */ - int i; - for (i = 0; i < exponent; i++) { - a = a * 5.0; - } - - for (i = 0; i < exponent; i++) { - b = b * 2.0; - } - - if (exp_sign == '-') { - a = 1.0 / a; - b = 1.0 / b; - } - - *result = - /* (sign == '+' ? 1 : -1) * ldexp(mantissa * pow(5.0, exponent), - exponent); */ - (sign == '+' ? 1 : -1) * (mantissa * a * b); - } - - return 1; -fail: - return 0; -} - -static float parseFloat(const char **token) { - const char *end; - double val = 0.0; - float f = 0.0f; - skip_space(token); - end = (*token) + until_space((*token)); - val = 0.0; - tryParseDouble((*token), end, &val); - f = (float)(val); - (*token) = end; - return f; -} - -static void parseFloat2(float *x, float *y, const char **token) { - (*x) = parseFloat(token); - (*y) = parseFloat(token); -} - -static void parseFloat3(float *x, float *y, float *z, const char **token) { - (*x) = parseFloat(token); - (*y) = parseFloat(token); - (*z) = parseFloat(token); -} - -static unsigned int my_strnlen(const char *s, unsigned int n) { - const char *p = memchr(s, 0, n); - return p ? (unsigned int)(p - s) : n; -} - -static char *my_strdup(const char *s, unsigned int max_length) { - char *d; - unsigned int len; - - if (s == NULL) return NULL; - - /* Do not consider CRLF line ending(#19) */ - len = length_until_line_feed(s, max_length); - /* len = strlen(s); */ - - /* trim line ending and append '\0' */ - d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ - memcpy(d, s, (unsigned int)(len)); - d[len] = '\0'; - - return d; -} - -static char *my_strndup(const char *s, unsigned int len) { - char *d; - unsigned int slen; - - if (s == NULL) return NULL; - if (len == 0) return NULL; - - slen = my_strnlen(s, len); - d = (char *)TINYOBJ_MALLOC(slen + 1); /* + '\0' */ - if (!d) { - return NULL; - } - memcpy(d, s, slen); - d[slen] = '\0'; - - return d; -} - -char *dynamic_fgets(char **buf, unsigned int *size, FILE *file) { - char *offset; - char *ret; - unsigned int old_size; - - if (!(ret = fgets(*buf, (int)*size, file))) { - return ret; - } - - if (NULL != strchr(*buf, '\n')) { - return ret; - } - - do { - old_size = *size; - *size *= 2; - *buf = (char*)TINYOBJ_REALLOC(*buf, *size); - offset = &((*buf)[old_size - 1]); - - ret = fgets(offset, (int)(old_size + 1), file); - } while(ret && (NULL == strchr(*buf, '\n'))); - - return ret; -} - -static void initMaterial(tinyobj_material_t *material) { - int i; - material->name = NULL; - material->ambient_texname = NULL; - material->diffuse_texname = NULL; - material->specular_texname = NULL; - material->specular_highlight_texname = NULL; - material->bump_texname = NULL; - material->displacement_texname = NULL; - material->alpha_texname = NULL; - for (i = 0; i < 3; i++) { - material->ambient[i] = 0.f; - material->diffuse[i] = 0.f; - material->specular[i] = 0.f; - material->transmittance[i] = 0.f; - material->emission[i] = 0.f; - } - material->illum = 0; - material->dissolve = 1.f; - material->shininess = 1.f; - material->ior = 1.f; -} - -/* Implementation of string to int hashtable */ - -#define HASH_TABLE_ERROR 1 -#define HASH_TABLE_SUCCESS 0 - -#define HASH_TABLE_DEFAULT_SIZE 10 - -typedef struct hash_table_entry_t -{ - unsigned long hash; - int filled; - int pad0; - long value; - - struct hash_table_entry_t* next; -} hash_table_entry_t; - -typedef struct -{ - unsigned long* hashes; - hash_table_entry_t* entries; - unsigned int capacity; - unsigned int n; -} hash_table_t; - -static unsigned long hash_djb2(const unsigned char* str) -{ - unsigned long hash = 5381; - int c; - - while ((c = *str++)) { - hash = ((hash << 5) + hash) + (unsigned long)(c); - } - - return hash; -} - -static void create_hash_table(unsigned int start_capacity, hash_table_t* hash_table) -{ - if (start_capacity < 1) - start_capacity = HASH_TABLE_DEFAULT_SIZE; - hash_table->hashes = (unsigned long*) TINYOBJ_MALLOC(start_capacity * sizeof(unsigned long)); - hash_table->entries = (hash_table_entry_t*) TINYOBJ_CALLOC(start_capacity, sizeof(hash_table_entry_t)); - hash_table->capacity = start_capacity; - hash_table->n = 0; -} - -static void destroy_hash_table(hash_table_t* hash_table) -{ - TINYOBJ_FREE(hash_table->entries); - TINYOBJ_FREE(hash_table->hashes); -} - -/* Insert with quadratic probing */ -static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table) -{ - /* Insert value */ - unsigned int start_index = hash % hash_table->capacity; - unsigned int index = start_index; - hash_table_entry_t* start_entry = hash_table->entries + start_index; - unsigned int i; - hash_table_entry_t* entry; - - for (i = 1; hash_table->entries[index].filled; i++) - { - if (i >= hash_table->capacity) - return HASH_TABLE_ERROR; - index = (start_index + (i * i)) % hash_table->capacity; - } - - entry = hash_table->entries + index; - entry->hash = hash; - entry->filled = 1; - entry->value = value; - - if (index != start_index) { - /* This is a new entry, but not the start entry, hence we need to add a next pointer to our entry */ - entry->next = start_entry->next; - start_entry->next = entry; - } - - return HASH_TABLE_SUCCESS; -} - -static int hash_table_insert(unsigned long hash, long value, hash_table_t* hash_table) -{ - int ret = hash_table_insert_value(hash, value, hash_table); - if (ret == HASH_TABLE_SUCCESS) - { - hash_table->hashes[hash_table->n] = hash; - hash_table->n++; - } - return ret; -} - -static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* hash_table) -{ - hash_table_entry_t* entry = hash_table->entries + (hash % hash_table->capacity); - while (entry) - { - if (entry->hash == hash && entry->filled) - { - return entry; - } - entry = entry->next; - } - return NULL; -} - -static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table) -{ - unsigned int new_capacity; - hash_table_t new_hash_table; - unsigned int i; - - if (new_n <= hash_table->capacity) { - return; - } - new_capacity = 2 * ((2 * hash_table->capacity) > new_n ? hash_table->capacity : new_n); - /* Create a new hash table. We're not calling create_hash_table because we want to realloc the hash array */ - new_hash_table.hashes = hash_table->hashes = (unsigned long*) TINYOBJ_REALLOC((void*) hash_table->hashes, sizeof(unsigned long) * new_capacity); - new_hash_table.entries = (hash_table_entry_t*) TINYOBJ_CALLOC(new_capacity, sizeof(hash_table_entry_t)); - new_hash_table.capacity = new_capacity; - new_hash_table.n = hash_table->n; - - /* Rehash */ - for (i = 0; i < hash_table->capacity; i++) - { - hash_table_entry_t* entry = hash_table_find(hash_table->hashes[i], hash_table); - hash_table_insert_value(hash_table->hashes[i], entry->value, &new_hash_table); - } - - TINYOBJ_FREE(hash_table->entries); - (*hash_table) = new_hash_table; -} - -static int hash_table_exists(const char* name, hash_table_t* hash_table) -{ - return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL; -} - -static void hash_table_set(const char* name, unsigned int val, hash_table_t* hash_table) -{ - /* Hash name */ - unsigned long hash = hash_djb2((const unsigned char *)name); - - hash_table_entry_t* entry = hash_table_find(hash, hash_table); - if (entry) - { - entry->value = (long)val; - return; - } - - /* Expand if necessary - * Grow until the element has been added - */ - do - { - hash_table_maybe_grow(hash_table->n + 1, hash_table); - } - while (hash_table_insert(hash, (long)val, hash_table) != HASH_TABLE_SUCCESS); -} - -static long hash_table_get(const char* name, hash_table_t* hash_table) -{ - hash_table_entry_t* ret = hash_table_find(hash_djb2((const unsigned char*)(name)), hash_table); - return ret->value; -} - -static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, - unsigned int num_materials, - tinyobj_material_t *new_mat) { - tinyobj_material_t *dst; - dst = (tinyobj_material_t *)TINYOBJ_REALLOC( - prev, sizeof(tinyobj_material_t) * (num_materials + 1)); - - dst[num_materials] = (*new_mat); /* Just copy pointer for char* members */ - return dst; -} - -static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, - unsigned int *num_materials_out, - const char *filename, - hash_table_t* material_table) { - tinyobj_material_t material; - unsigned int buffer_size = 128; - char *linebuf; - FILE *fp; - unsigned int num_materials = 0; - tinyobj_material_t *materials = NULL; - int has_previous_material = 0; - const char *line_end = NULL; - - if (materials_out == NULL) { - return TINYOBJ_ERROR_INVALID_PARAMETER; - } - - if (num_materials_out == NULL) { - return TINYOBJ_ERROR_INVALID_PARAMETER; - } - - (*materials_out) = NULL; - (*num_materials_out) = 0; - - fp = fopen(filename, "r"); - if (!fp) { - //fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno); // @raysan5: commented - return TINYOBJ_ERROR_FILE_OPERATION; - } - - /* Create a default material */ - initMaterial(&material); - - linebuf = (char*)TINYOBJ_MALLOC(buffer_size); - while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) { - const char *token = linebuf; - - line_end = token + strlen(token); - - /* Skip leading space. */ - token += strspn(token, " \t"); - - assert(token); - if (token[0] == '\0') continue; /* empty line */ - - if (token[0] == '#') continue; /* comment line */ - - /* new mtl */ - if ((0 == strncmp(token, "newmtl", 6)) && IS_SPACE((token[6]))) { - char namebuf[4096]; - - /* flush previous material. */ - if (has_previous_material) { - materials = tinyobj_material_add(materials, num_materials, &material); - num_materials++; - } else { - has_previous_material = 1; - } - - /* initial temporary material */ - initMaterial(&material); - - /* set new mtl name */ - token += 7; -#ifdef _MSC_VER - sscanf_s(token, "%s", namebuf, (unsigned)_countof(namebuf)); -#else - sscanf(token, "%s", namebuf); -#endif - material.name = my_strdup(namebuf, (unsigned int) (line_end - token)); - - /* Add material to material table */ - if (material_table) - hash_table_set(material.name, num_materials, material_table); - - continue; - } - - /* ambient */ - if (token[0] == 'K' && token[1] == 'a' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.ambient[0] = r; - material.ambient[1] = g; - material.ambient[2] = b; - continue; - } - - /* diffuse */ - if (token[0] == 'K' && token[1] == 'd' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.diffuse[0] = r; - material.diffuse[1] = g; - material.diffuse[2] = b; - continue; - } - - /* specular */ - if (token[0] == 'K' && token[1] == 's' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.specular[0] = r; - material.specular[1] = g; - material.specular[2] = b; - continue; - } - - /* transmittance */ - if (token[0] == 'K' && token[1] == 't' && IS_SPACE((token[2]))) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.transmittance[0] = r; - material.transmittance[1] = g; - material.transmittance[2] = b; - continue; - } - - /* ior(index of refraction) */ - if (token[0] == 'N' && token[1] == 'i' && IS_SPACE((token[2]))) { - token += 2; - material.ior = parseFloat(&token); - continue; - } - - /* emission */ - if (token[0] == 'K' && token[1] == 'e' && IS_SPACE(token[2])) { - float r, g, b; - token += 2; - parseFloat3(&r, &g, &b, &token); - material.emission[0] = r; - material.emission[1] = g; - material.emission[2] = b; - continue; - } - - /* shininess */ - if (token[0] == 'N' && token[1] == 's' && IS_SPACE(token[2])) { - token += 2; - material.shininess = parseFloat(&token); - continue; - } - - /* illum model */ - if (0 == strncmp(token, "illum", 5) && IS_SPACE(token[5])) { - token += 6; - material.illum = parseInt(&token); - continue; - } - - /* dissolve */ - if ((token[0] == 'd' && IS_SPACE(token[1]))) { - token += 1; - material.dissolve = parseFloat(&token); - continue; - } - if (token[0] == 'T' && token[1] == 'r' && IS_SPACE(token[2])) { - token += 2; - /* Invert value of Tr(assume Tr is in range [0, 1]) */ - material.dissolve = 1.0f - parseFloat(&token); - continue; - } - - /* ambient texture */ - if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { - token += 7; - material.ambient_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* diffuse texture */ - if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { - token += 7; - material.diffuse_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* specular texture */ - if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { - token += 7; - material.specular_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* specular highlight texture */ - if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { - token += 7; - material.specular_highlight_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* bump texture */ - if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { - token += 9; - material.bump_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* alpha texture */ - if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { - token += 6; - material.alpha_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* bump texture */ - if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { - token += 5; - material.bump_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* displacement texture */ - if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { - token += 5; - material.displacement_texname = my_strdup(token, (unsigned int) (line_end - token)); - continue; - } - - /* @todo { unknown parameter } */ - } - - if (material.name) { - /* Flush last material element */ - materials = tinyobj_material_add(materials, num_materials, &material); - num_materials++; - } - - (*num_materials_out) = num_materials; - (*materials_out) = materials; - - if (linebuf) { - TINYOBJ_FREE(linebuf); - } - - return TINYOBJ_SUCCESS; -} - -int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, - unsigned int *num_materials_out, - const char *filename) { - return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL); -} - - -typedef enum { - COMMAND_EMPTY, - COMMAND_V, - COMMAND_VN, - COMMAND_VT, - COMMAND_F, - COMMAND_G, - COMMAND_O, - COMMAND_USEMTL, - COMMAND_MTLLIB - -} CommandType; - -typedef struct { - float vx, vy, vz; - float nx, ny, nz; - float tx, ty; - - /* @todo { Use dynamic array } */ - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; - unsigned int num_f; - - int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; - unsigned int num_f_num_verts; - - const char *group_name; - unsigned int group_name_len; - int pad0; - - const char *object_name; - unsigned int object_name_len; - int pad1; - - const char *material_name; - unsigned int material_name_len; - int pad2; - - const char *mtllib_name; - unsigned int mtllib_name_len; - - CommandType type; -} Command; - -static int parseLine(Command *command, const char *p, unsigned int p_len, - int triangulate) { - char linebuf[4096]; - const char *token; - assert(p_len < 4095); - - memcpy(linebuf, p, p_len); - linebuf[p_len] = '\0'; - - token = linebuf; - - command->type = COMMAND_EMPTY; - - /* Skip leading space. */ - skip_space(&token); - - assert(token); - if (token[0] == '\0') { /* empty line */ - return 0; - } - - if (token[0] == '#') { /* comment line */ - return 0; - } - - /* vertex */ - if (token[0] == 'v' && IS_SPACE((token[1]))) { - float x, y, z; - token += 2; - parseFloat3(&x, &y, &z, &token); - command->vx = x; - command->vy = y; - command->vz = z; - command->type = COMMAND_V; - return 1; - } - - /* normal */ - if (token[0] == 'v' && token[1] == 'n' && IS_SPACE((token[2]))) { - float x, y, z; - token += 3; - parseFloat3(&x, &y, &z, &token); - command->nx = x; - command->ny = y; - command->nz = z; - command->type = COMMAND_VN; - return 1; - } - - /* texcoord */ - if (token[0] == 'v' && token[1] == 't' && IS_SPACE((token[2]))) { - float x, y; - token += 3; - parseFloat2(&x, &y, &token); - command->tx = x; - command->ty = y; - command->type = COMMAND_VT; - return 1; - } - - /* face */ - if (token[0] == 'f' && IS_SPACE((token[1]))) { - unsigned int num_f = 0; - - tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; - token += 2; - skip_space(&token); - - while (!IS_NEW_LINE(token[0])) { - tinyobj_vertex_index_t vi = parseRawTriple(&token); - skip_space_and_cr(&token); - - f[num_f] = vi; - num_f++; - } - - command->type = COMMAND_F; - - if (triangulate) { - unsigned int k; - unsigned int n = 0; - - tinyobj_vertex_index_t i0 = f[0]; - tinyobj_vertex_index_t i1; - tinyobj_vertex_index_t i2 = f[1]; - - assert(3 * num_f < TINYOBJ_MAX_FACES_PER_F_LINE); - - for (k = 2; k < num_f; k++) { - i1 = i2; - i2 = f[k]; - command->f[3 * n + 0] = i0; - command->f[3 * n + 1] = i1; - command->f[3 * n + 2] = i2; - - command->f_num_verts[n] = 3; - n++; - } - command->num_f = 3 * n; - command->num_f_num_verts = n; - - } else { - unsigned int k = 0; - assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); - for (k = 0; k < num_f; k++) { - command->f[k] = f[k]; - } - - command->num_f = num_f; - command->f_num_verts[0] = (int)num_f; - command->num_f_num_verts = 1; - } - - return 1; - } - - /* use mtl */ - if ((0 == strncmp(token, "usemtl", 6)) && IS_SPACE((token[6]))) { - token += 7; - - skip_space(&token); - command->material_name = p + (token - linebuf); - command->material_name_len = (unsigned int)length_until_newline( - token, (p_len - (unsigned int)(token - linebuf)) + 1); - command->type = COMMAND_USEMTL; - - return 1; - } - - /* load mtl */ - if ((0 == strncmp(token, "mtllib", 6)) && IS_SPACE((token[6]))) { - /* By specification, `mtllib` should be appear only once in .obj */ - token += 7; - - skip_space(&token); - command->mtllib_name = p + (token - linebuf); - command->mtllib_name_len = (unsigned int)length_until_newline( - token, p_len - (unsigned int)(token - linebuf)) + - 1; - command->type = COMMAND_MTLLIB; - - return 1; - } - - /* group name */ - if (token[0] == 'g' && IS_SPACE((token[1]))) { - /* @todo { multiple group name. } */ - token += 2; - - command->group_name = p + (token - linebuf); - command->group_name_len = (unsigned int)length_until_newline( - token, p_len - (unsigned int)(token - linebuf)) + - 1; - command->type = COMMAND_G; - - return 1; - } - - /* object name */ - if (token[0] == 'o' && IS_SPACE((token[1]))) { - /* @todo { multiple object name? } */ - token += 2; - - command->object_name = p + (token - linebuf); - command->object_name_len = (unsigned int)length_until_newline( - token, p_len - (unsigned int)(token - linebuf)) + - 1; - command->type = COMMAND_O; - - return 1; - } - - return 0; -} - -typedef struct { - unsigned int pos; - unsigned int len; -} LineInfo; - -static int is_line_ending(const char *p, unsigned int i, unsigned int end_i) { - if (p[i] == '\0') return 1; - if (p[i] == '\n') return 1; /* this includes \r\n */ - if (p[i] == '\r') { - if (((i + 1) < end_i) && (p[i + 1] != '\n')) { /* detect only \r case */ - return 1; - } - } - return 0; -} - -int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, - unsigned int *num_shapes, tinyobj_material_t **materials_out, - unsigned int *num_materials_out, const char *buf, unsigned int len, - unsigned int flags) { - LineInfo *line_infos = NULL; - Command *commands = NULL; - unsigned int num_lines = 0; - - unsigned int num_v = 0; - unsigned int num_vn = 0; - unsigned int num_vt = 0; - unsigned int num_f = 0; - unsigned int num_faces = 0; - - int mtllib_line_index = -1; - - tinyobj_material_t *materials = NULL; - unsigned int num_materials = 0; - - hash_table_t material_table; - - if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (num_shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; - - tinyobj_attrib_init(attrib); - /* 1. Find '\n' and create line data. */ - { - unsigned int i; - unsigned int end_idx = len; - unsigned int prev_pos = 0; - unsigned int line_no = 0; - unsigned int last_line_ending = 0; - - /* Count # of lines. */ - for (i = 0; i < end_idx; i++) { - if (is_line_ending(buf, i, end_idx)) { - num_lines++; - last_line_ending = i; - } - } - /* The last char from the input may not be a line - * ending character so add an extra line if there - * are more characters after the last line ending - * that was found. */ - if (end_idx - last_line_ending > 0) { - num_lines++; - } - - if (num_lines == 0) return TINYOBJ_ERROR_EMPTY; - - line_infos = (LineInfo *)TINYOBJ_MALLOC(sizeof(LineInfo) * num_lines); - - /* Fill line infos. */ - for (i = 0; i < end_idx; i++) { - if (is_line_ending(buf, i, end_idx)) { - line_infos[line_no].pos = prev_pos; - line_infos[line_no].len = i - prev_pos; - prev_pos = i + 1; - line_no++; - } - } - if (end_idx - last_line_ending > 0) { - line_infos[line_no].pos = prev_pos; - line_infos[line_no].len = end_idx - 1 - last_line_ending; - } - } - - commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines); - - create_hash_table(HASH_TABLE_DEFAULT_SIZE, &material_table); - - /* 2. parse each line */ - { - unsigned int i = 0; - for (i = 0; i < num_lines; i++) { - int ret = parseLine(&commands[i], &buf[line_infos[i].pos], - line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); - if (ret) { - if (commands[i].type == COMMAND_V) { - num_v++; - } else if (commands[i].type == COMMAND_VN) { - num_vn++; - } else if (commands[i].type == COMMAND_VT) { - num_vt++; - } else if (commands[i].type == COMMAND_F) { - num_f += commands[i].num_f; - num_faces += commands[i].num_f_num_verts; - } - - if (commands[i].type == COMMAND_MTLLIB) { - mtllib_line_index = (int)i; - } - } - } - } - - /* line_infos are not used anymore. Release memory. */ - if (line_infos) { - TINYOBJ_FREE(line_infos); - } - - /* Load material(if exits) */ - if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name && - commands[mtllib_line_index].mtllib_name_len > 0) { - char *filename = my_strndup(commands[mtllib_line_index].mtllib_name, - commands[mtllib_line_index].mtllib_name_len); - - int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table); - - if (ret != TINYOBJ_SUCCESS) { - /* warning. */ - //fprintf(stderr, "TINYOBJ: Failed to parse material file '%s': %d\n", filename, ret); // @raysan5: commented - } - - TINYOBJ_FREE(filename); - - } - - /* Construct attributes */ - - { - unsigned int v_count = 0; - unsigned int n_count = 0; - unsigned int t_count = 0; - unsigned int f_count = 0; - unsigned int face_count = 0; - int material_id = -1; /* -1 = default unknown material. */ - unsigned int i = 0; - - attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3); - attrib->num_vertices = (unsigned int)num_v; - attrib->normals = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vn * 3); - attrib->num_normals = (unsigned int)num_vn; - attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2); - attrib->num_texcoords = (unsigned int)num_vt; - attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f); - attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); - - attrib->num_faces = (unsigned int)num_faces; - attrib->num_face_num_verts = (unsigned int)num_f; - - attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); - - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_EMPTY) { - continue; - } else if (commands[i].type == COMMAND_USEMTL) { - /* @todo - if (commands[t][i].material_name && - commands[t][i].material_name_len > 0) { - std::string material_name(commands[t][i].material_name, - commands[t][i].material_name_len); - - if (material_map.find(material_name) != material_map.end()) { - material_id = material_map[material_name]; - } else { - // Assign invalid material ID - material_id = -1; - } - } - */ - if (commands[i].material_name && - commands[i].material_name_len >0) - { - /* Create a null terminated string */ - char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1); - memcpy((void*) material_name_null_term, (const void*) commands[i].material_name, commands[i].material_name_len); - material_name_null_term[commands[i].material_name_len - 1] = 0; - - if (hash_table_exists(material_name_null_term, &material_table)) - material_id = (int)hash_table_get(material_name_null_term, &material_table); - else - material_id = -1; - - TINYOBJ_FREE(material_name_null_term); - } - } else if (commands[i].type == COMMAND_V) { - attrib->vertices[3 * v_count + 0] = commands[i].vx; - attrib->vertices[3 * v_count + 1] = commands[i].vy; - attrib->vertices[3 * v_count + 2] = commands[i].vz; - v_count++; - } else if (commands[i].type == COMMAND_VN) { - attrib->normals[3 * n_count + 0] = commands[i].nx; - attrib->normals[3 * n_count + 1] = commands[i].ny; - attrib->normals[3 * n_count + 2] = commands[i].nz; - n_count++; - } else if (commands[i].type == COMMAND_VT) { - attrib->texcoords[2 * t_count + 0] = commands[i].tx; - attrib->texcoords[2 * t_count + 1] = commands[i].ty; - t_count++; - } else if (commands[i].type == COMMAND_F) { - unsigned int k = 0; - for (k = 0; k < commands[i].num_f; k++) { - tinyobj_vertex_index_t vi = commands[i].f[k]; - int v_idx = fixIndex(vi.v_idx, v_count); - int vn_idx = fixIndex(vi.vn_idx, n_count); - int vt_idx = fixIndex(vi.vt_idx, t_count); - attrib->faces[f_count + k].v_idx = v_idx; - attrib->faces[f_count + k].vn_idx = vn_idx; - attrib->faces[f_count + k].vt_idx = vt_idx; - } - - for (k = 0; k < commands[i].num_f_num_verts; k++) { - attrib->material_ids[face_count + k] = material_id; - attrib->face_num_verts[face_count + k] = commands[i].f_num_verts[k]; - } - - f_count += commands[i].num_f; - face_count += commands[i].num_f_num_verts; - } - } - } - - /* 5. Construct shape information. */ - { - unsigned int face_count = 0; - unsigned int i = 0; - unsigned int n = 0; - unsigned int shape_idx = 0; - - const char *shape_name = NULL; - unsigned int shape_name_len = 0; - const char *prev_shape_name = NULL; - unsigned int prev_shape_name_len = 0; - unsigned int prev_shape_face_offset = 0; - unsigned int prev_face_offset = 0; - tinyobj_shape_t prev_shape = {NULL, 0, 0}; - - /* Find the number of shapes in .obj */ - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { - n++; - } - } - - /* Allocate array of shapes with maximum possible size(+1 for unnamed - * group/object). - * Actual # of shapes found in .obj is determined in the later */ - (*shapes) = (tinyobj_shape_t*)TINYOBJ_MALLOC(sizeof(tinyobj_shape_t) * (n + 1)); - - for (i = 0; i < num_lines; i++) { - if (commands[i].type == COMMAND_O || commands[i].type == COMMAND_G) { - if (commands[i].type == COMMAND_O) { - shape_name = commands[i].object_name; - shape_name_len = commands[i].object_name_len; - } else { - shape_name = commands[i].group_name; - shape_name_len = commands[i].group_name_len; - } - - if (face_count == 0) { - /* 'o' or 'g' appears before any 'f' */ - prev_shape_name = shape_name; - prev_shape_name_len = shape_name_len; - prev_shape_face_offset = face_count; - prev_face_offset = face_count; - } else { - if (shape_idx == 0) { - /* 'o' or 'g' after some 'v' lines. */ - (*shapes)[shape_idx].name = my_strndup( - prev_shape_name, prev_shape_name_len); /* may be NULL */ - (*shapes)[shape_idx].face_offset = prev_shape.face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - - prev_face_offset = face_count; - - } else { - if ((face_count - prev_face_offset) > 0) { - (*shapes)[shape_idx].name = - my_strndup(prev_shape_name, prev_shape_name_len); - (*shapes)[shape_idx].face_offset = prev_face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - prev_face_offset = face_count; - } - } - - /* Record shape info for succeeding 'o' or 'g' command. */ - prev_shape_name = shape_name; - prev_shape_name_len = shape_name_len; - prev_shape_face_offset = face_count; - } - } - if (commands[i].type == COMMAND_F) { - face_count++; - } - } - - if ((face_count - prev_face_offset) > 0) { - unsigned int length = face_count - prev_shape_face_offset; - if (length > 0) { - (*shapes)[shape_idx].name = - my_strndup(prev_shape_name, prev_shape_name_len); - (*shapes)[shape_idx].face_offset = prev_face_offset; - (*shapes)[shape_idx].length = face_count - prev_face_offset; - shape_idx++; - } - } else { - /* Guess no 'v' line occurrence after 'o' or 'g', so discards current - * shape information. */ - } - - (*num_shapes) = shape_idx; - } - - if (commands) { - TINYOBJ_FREE(commands); - } - - destroy_hash_table(&material_table); - - (*materials_out) = materials; - (*num_materials_out) = num_materials; - - return TINYOBJ_SUCCESS; -} - -void tinyobj_attrib_init(tinyobj_attrib_t *attrib) { - attrib->vertices = NULL; - attrib->num_vertices = 0; - attrib->normals = NULL; - attrib->num_normals = 0; - attrib->texcoords = NULL; - attrib->num_texcoords = 0; - attrib->faces = NULL; - attrib->num_faces = 0; - attrib->face_num_verts = NULL; - attrib->num_face_num_verts = 0; - attrib->material_ids = NULL; -} - -void tinyobj_attrib_free(tinyobj_attrib_t *attrib) { - if (attrib->vertices) TINYOBJ_FREE(attrib->vertices); - if (attrib->normals) TINYOBJ_FREE(attrib->normals); - if (attrib->texcoords) TINYOBJ_FREE(attrib->texcoords); - if (attrib->faces) TINYOBJ_FREE(attrib->faces); - if (attrib->face_num_verts) TINYOBJ_FREE(attrib->face_num_verts); - if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids); -} - -void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes) { - unsigned int i; - if (shapes == NULL) return; - - for (i = 0; i < num_shapes; i++) { - if (shapes[i].name) TINYOBJ_FREE(shapes[i].name); - } - - TINYOBJ_FREE(shapes); -} - -void tinyobj_materials_free(tinyobj_material_t *materials, - unsigned int num_materials) { - unsigned int i; - if (materials == NULL) return; - - for (i = 0; i < num_materials; i++) { - if (materials[i].name) TINYOBJ_FREE(materials[i].name); - if (materials[i].ambient_texname) TINYOBJ_FREE(materials[i].ambient_texname); - if (materials[i].diffuse_texname) TINYOBJ_FREE(materials[i].diffuse_texname); - if (materials[i].specular_texname) TINYOBJ_FREE(materials[i].specular_texname); - if (materials[i].specular_highlight_texname) - TINYOBJ_FREE(materials[i].specular_highlight_texname); - if (materials[i].bump_texname) TINYOBJ_FREE(materials[i].bump_texname); - if (materials[i].displacement_texname) - TINYOBJ_FREE(materials[i].displacement_texname); - if (materials[i].alpha_texname) TINYOBJ_FREE(materials[i].alpha_texname); - } - - TINYOBJ_FREE(materials); -} -#endif /* TINYOBJ_LOADER_C_IMPLEMENTATION */ - -#endif /* TINOBJ_LOADER_C_H_ */ |