Reverted to previous working version #1434

This commit is contained in:
Ray 2020-11-21 14:14:25 +01:00
parent 9bb4d84577
commit 36dc302c25
2 changed files with 171 additions and 306 deletions

View file

@ -24,8 +24,8 @@
#ifndef TINOBJ_LOADER_C_H_ #ifndef TINOBJ_LOADER_C_H_
#define TINOBJ_LOADER_C_H_ #define TINOBJ_LOADER_C_H_
/* @todo { Remove stddef dependency. size_t? } */ /* @todo { Remove stddef dependency. unsigned int? } ---> RAY: DONE. */
#include <stddef.h> //#include <stddef.h>
typedef struct { typedef struct {
char *name; char *name;
@ -87,57 +87,24 @@ typedef struct {
#define TINYOBJ_ERROR_INVALID_PARAMETER (-2) #define TINYOBJ_ERROR_INVALID_PARAMETER (-2)
#define TINYOBJ_ERROR_FILE_OPERATION (-3) #define TINYOBJ_ERROR_FILE_OPERATION (-3)
/* Provide a callback that can read text file without any parsing or modification. /* Parse wavefront .obj(.obj string data is expanded to linear char array `buf')
* The obj and mtl parser is going to read all the necessary data: * flags are combination of TINYOBJ_FLAG_***
* tinyobj_parse_obj
* tinyobj_parse_mtl_file
*
* @param[in] filename Filename to be loaded.
* @param[in] is_mtl 1 when the callback is invoked for loading .mtl. 0 for .obj
* @param[in] obj_filename .obj filename. Useful when you load .mtl from same location of .obj. When the callback is called to load .obj, `filename` and `obj_filename` are same.
* @param[out] buf Content of loaded file
* @param[out] len Size of content(file)
*/
typedef void (*file_reader_callback)(const char *filename, int is_mtl, const char *obj_filename, char **buf, size_t *len);
/* Parse wavefront .obj
* @param[out] attrib Attibutes
* @param[out] shapes Array of parsed shapes
* @param[out] num_shapes Array length of `shapes`
* @param[out] materials Array of parsed materials
* @param[out] num_materials Array length of `materials`
* @param[in] file_name File name of .obj
* @param[in] file_reader File reader callback function(to read .obj and .mtl).
* @param[in] flags combination of TINYOBJ_FLAG_***
*
* Returns TINYOBJ_SUCCESS if things goes well. * Returns TINYOBJ_SUCCESS if things goes well.
* Returns TINYOBJ_ERR_*** when there is an error. * Returns TINYOBJ_ERR_*** when there is an error.
*/ */
extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, extern int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
size_t *num_shapes, tinyobj_material_t **materials, unsigned int *num_shapes, tinyobj_material_t **materials,
size_t *num_materials, const char *file_name, file_reader_callback file_reader, unsigned int *num_materials, const char *buf, unsigned int len,
unsigned int flags); unsigned int flags);
/* Parse wavefront .mtl
*
* @param[out] materials_out
* @param[out] num_materials_out
* @param[in] filename .mtl filename
* @param[in] filename of .obj filename. could be NULL if you just want to parse .mtl file.
* @param[in] file_reader File reader callback
* Returns TINYOBJ_SUCCESS if things goes well.
* Returns TINYOBJ_ERR_*** when there is an error.
*/
extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, extern int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out,
size_t *num_materials_out, unsigned int *num_materials_out,
const char *filename, const char *obj_filename, file_reader_callback file_reader); const char *filename);
extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib); extern void tinyobj_attrib_init(tinyobj_attrib_t *attrib);
extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib); extern void tinyobj_attrib_free(tinyobj_attrib_t *attrib);
extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes); extern void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes);
extern void tinyobj_materials_free(tinyobj_material_t *materials, extern void tinyobj_materials_free(tinyobj_material_t *materials,
size_t num_materials); unsigned int num_materials);
#ifdef TINYOBJ_LOADER_C_IMPLEMENTATION #ifdef TINYOBJ_LOADER_C_IMPLEMENTATION
#include <stdio.h> #include <stdio.h>
@ -162,7 +129,6 @@ extern void tinyobj_materials_free(tinyobj_material_t *materials,
#endif #endif
#define TINYOBJ_MAX_FACES_PER_F_LINE (16) #define TINYOBJ_MAX_FACES_PER_F_LINE (16)
#define TINYOBJ_MAX_FILEPATH (8192)
#define IS_SPACE(x) (((x) == ' ') || ((x) == '\t')) #define IS_SPACE(x) (((x) == ' ') || ((x) == '\t'))
#define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10)) #define IS_DIGIT(x) ((unsigned int)((x) - '0') < (unsigned int)(10))
@ -189,8 +155,8 @@ static int until_space(const char *token) {
return (int)(p - token); return (int)(p - token);
} }
static size_t length_until_newline(const char *token, size_t n) { static unsigned int length_until_newline(const char *token, unsigned int n) {
size_t len = 0; unsigned int len = 0;
/* Assume token[n-1] = '\0' */ /* Assume token[n-1] = '\0' */
for (len = 0; len < n - 1; len++) { for (len = 0; len < n - 1; len++) {
@ -205,8 +171,8 @@ static size_t length_until_newline(const char *token, size_t n) {
return len; return len;
} }
static size_t length_until_line_feed(const char *token, size_t n) { static unsigned int length_until_line_feed(const char *token, unsigned int n) {
size_t len = 0; unsigned int len = 0;
/* Assume token[n-1] = '\0' */ /* Assume token[n-1] = '\0' */
for (len = 0; len < n; len++) { for (len = 0; len < n; len++) {
@ -236,7 +202,7 @@ static int my_atoi(const char *c) {
} }
/* Make index zero-base, and also support relative index. */ /* Make index zero-base, and also support relative index. */
static int fixIndex(int idx, size_t n) { static int fixIndex(int idx, unsigned int n) {
if (idx > 0) return idx - 1; if (idx > 0) return idx - 1;
if (idx == 0) return 0; if (idx == 0) return 0;
return (int)n + idx; /* negative value = relative */ return (int)n + idx; /* negative value = relative */
@ -487,14 +453,14 @@ static void parseFloat3(float *x, float *y, float *z, const char **token) {
(*z) = parseFloat(token); (*z) = parseFloat(token);
} }
static size_t my_strnlen(const char *s, size_t n) { static unsigned int my_strnlen(const char *s, unsigned int n) {
const char *p = memchr(s, 0, n); const char *p = memchr(s, 0, n);
return p ? (size_t)(p - s) : n; return p ? (unsigned int)(p - s) : n;
} }
static char *my_strdup(const char *s, size_t max_length) { static char *my_strdup(const char *s, unsigned int max_length) {
char *d; char *d;
size_t len; unsigned int len;
if (s == NULL) return NULL; if (s == NULL) return NULL;
@ -504,15 +470,15 @@ static char *my_strdup(const char *s, size_t max_length) {
/* trim line ending and append '\0' */ /* trim line ending and append '\0' */
d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */ d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */
memcpy(d, s, (size_t)(len)); memcpy(d, s, (unsigned int)(len));
d[len] = '\0'; d[len] = '\0';
return d; return d;
} }
static char *my_strndup(const char *s, size_t len) { static char *my_strndup(const char *s, unsigned int len) {
char *d; char *d;
size_t slen; unsigned int slen;
if (s == NULL) return NULL; if (s == NULL) return NULL;
if (len == 0) return NULL; if (len == 0) return NULL;
@ -528,36 +494,10 @@ static char *my_strndup(const char *s, size_t len) {
return d; return d;
} }
static char *my_joinpath(const char *s, const char *t, const char delim, size_t max_len) { char *dynamic_fgets(char **buf, unsigned int *size, FILE *file) {
char *d;
size_t slen;
size_t tlen;
size_t len;
if ((s == NULL) && (t == NULL)) return NULL;
if (max_len == 0) return NULL;
slen = my_strnlen(s, max_len);
tlen = my_strnlen(t, max_len);
len = slen + tlen + 1; /* +1 for delimiter */
d = (char *)TINYOBJ_MALLOC(len + 1); /* + '\0' */
if (!d) {
return NULL;
}
memcpy(d, s, slen);
d[slen] = delim;
memcpy(d + slen +1, t, tlen);
d[len] = '\0';
return d;
}
char *dynamic_fgets(char **buf, size_t *size, FILE *file) {
char *offset; char *offset;
char *ret; char *ret;
size_t old_size; unsigned int old_size;
if (!(ret = fgets(*buf, (int)*size, file))) { if (!(ret = fgets(*buf, (int)*size, file))) {
return ret; return ret;
@ -623,8 +563,8 @@ typedef struct
{ {
unsigned long* hashes; unsigned long* hashes;
hash_table_entry_t* entries; hash_table_entry_t* entries;
size_t capacity; unsigned int capacity;
size_t n; unsigned int n;
} hash_table_t; } hash_table_t;
static unsigned long hash_djb2(const unsigned char* str) static unsigned long hash_djb2(const unsigned char* str)
@ -639,7 +579,7 @@ static unsigned long hash_djb2(const unsigned char* str)
return hash; return hash;
} }
static void create_hash_table(size_t start_capacity, hash_table_t* hash_table) static void create_hash_table(unsigned int start_capacity, hash_table_t* hash_table)
{ {
if (start_capacity < 1) if (start_capacity < 1)
start_capacity = HASH_TABLE_DEFAULT_SIZE; start_capacity = HASH_TABLE_DEFAULT_SIZE;
@ -659,10 +599,10 @@ static void destroy_hash_table(hash_table_t* hash_table)
static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table) static int hash_table_insert_value(unsigned long hash, long value, hash_table_t* hash_table)
{ {
/* Insert value */ /* Insert value */
size_t start_index = hash % hash_table->capacity; unsigned int start_index = hash % hash_table->capacity;
size_t index = start_index; unsigned int index = start_index;
hash_table_entry_t* start_entry = hash_table->entries + start_index; hash_table_entry_t* start_entry = hash_table->entries + start_index;
size_t i; unsigned int i;
hash_table_entry_t* entry; hash_table_entry_t* entry;
for (i = 1; hash_table->entries[index].filled; i++) for (i = 1; hash_table->entries[index].filled; i++)
@ -711,11 +651,11 @@ static hash_table_entry_t* hash_table_find(unsigned long hash, hash_table_t* has
return NULL; return NULL;
} }
static void hash_table_maybe_grow(size_t new_n, hash_table_t* hash_table) static void hash_table_maybe_grow(unsigned int new_n, hash_table_t* hash_table)
{ {
size_t new_capacity; unsigned int new_capacity;
hash_table_t new_hash_table; hash_table_t new_hash_table;
size_t i; unsigned int i;
if (new_n <= hash_table->capacity) { if (new_n <= hash_table->capacity) {
return; return;
@ -743,7 +683,7 @@ 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; return hash_table_find(hash_djb2((const unsigned char*)name), hash_table) != NULL;
} }
static void hash_table_set(const char* name, size_t val, hash_table_t* hash_table) static void hash_table_set(const char* name, unsigned int val, hash_table_t* hash_table)
{ {
/* Hash name */ /* Hash name */
unsigned long hash = hash_djb2((const unsigned char *)name); unsigned long hash = hash_djb2((const unsigned char *)name);
@ -772,7 +712,7 @@ static long hash_table_get(const char* name, hash_table_t* hash_table)
} }
static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev, static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev,
size_t num_materials, unsigned int num_materials,
tinyobj_material_t *new_mat) { tinyobj_material_t *new_mat) {
tinyobj_material_t *dst; tinyobj_material_t *dst;
dst = (tinyobj_material_t *)TINYOBJ_REALLOC( dst = (tinyobj_material_t *)TINYOBJ_REALLOC(
@ -782,81 +722,18 @@ static tinyobj_material_t *tinyobj_material_add(tinyobj_material_t *prev,
return dst; return dst;
} }
static int is_line_ending(const char *p, size_t i, size_t 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;
}
typedef struct {
size_t pos;
size_t len;
} LineInfo;
/* Find '\n' and create line data. */
static int get_line_infos(const char *buf, size_t buf_len, LineInfo **line_infos, size_t *num_lines)
{
size_t i = 0;
size_t end_idx = buf_len;
size_t prev_pos = 0;
size_t line_no = 0;
size_t 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;
}
return 0;
}
static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out, static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
size_t *num_materials_out, unsigned int *num_materials_out,
const char *mtl_filename, const char *obj_filename, file_reader_callback file_reader, const char *filename,
hash_table_t* material_table) { hash_table_t* material_table) {
tinyobj_material_t material; tinyobj_material_t material;
size_t num_materials = 0; unsigned int buffer_size = 128;
char *linebuf;
FILE *fp;
unsigned int num_materials = 0;
tinyobj_material_t *materials = NULL; tinyobj_material_t *materials = NULL;
int has_previous_material = 0; int has_previous_material = 0;
const char *line_end = NULL; const char *line_end = NULL;
size_t num_lines = 0;
LineInfo *line_infos = NULL;
size_t i = 0;
char *buf = NULL;
size_t len = 0;
if (materials_out == NULL) { if (materials_out == NULL) {
return TINYOBJ_ERROR_INVALID_PARAMETER; return TINYOBJ_ERROR_INVALID_PARAMETER;
@ -869,30 +746,20 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
(*materials_out) = NULL; (*materials_out) = NULL;
(*num_materials_out) = 0; (*num_materials_out) = 0;
file_reader(mtl_filename, 1, obj_filename, &buf, &len); fp = fopen(filename, "r");
if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; if (!fp) {
if (buf == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; fprintf(stderr, "TINYOBJ: Error reading file '%s': %s (%d)\n", filename, strerror(errno), errno);
return TINYOBJ_ERROR_FILE_OPERATION;
if (get_line_infos(buf, len, &line_infos, &num_lines) != 0) {
return TINYOBJ_ERROR_EMPTY;
} }
/* Create a default material */ /* Create a default material */
initMaterial(&material); initMaterial(&material);
for (i = 0; i < num_lines; i++) { linebuf = (char*)TINYOBJ_MALLOC(buffer_size);
const char *p = &buf[line_infos[i].pos]; while (NULL != dynamic_fgets(&linebuf, &buffer_size, fp)) {
size_t p_len = line_infos[i].len; const char *token = linebuf;
char linebuf[4096]; line_end = token + strlen(token);
const char *token;
assert(p_len < 4095);
memcpy(linebuf, p, p_len);
linebuf[p_len] = '\0';
token = linebuf;
line_end = token + p_len;
/* Skip leading space. */ /* Skip leading space. */
token += strspn(token, " \t"); token += strspn(token, " \t");
@ -924,7 +791,7 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
#else #else
sscanf(token, "%s", namebuf); sscanf(token, "%s", namebuf);
#endif #endif
material.name = my_strdup(namebuf, (size_t) (line_end - token)); material.name = my_strdup(namebuf, (unsigned int) (line_end - token));
/* Add material to material table */ /* Add material to material table */
if (material_table) if (material_table)
@ -1025,56 +892,56 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
/* ambient texture */ /* ambient texture */
if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) { if ((0 == strncmp(token, "map_Ka", 6)) && IS_SPACE(token[6])) {
token += 7; token += 7;
material.ambient_texname = my_strdup(token, (size_t) (line_end - token)); material.ambient_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* diffuse texture */ /* diffuse texture */
if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) { if ((0 == strncmp(token, "map_Kd", 6)) && IS_SPACE(token[6])) {
token += 7; token += 7;
material.diffuse_texname = my_strdup(token, (size_t) (line_end - token)); material.diffuse_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* specular texture */ /* specular texture */
if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) { if ((0 == strncmp(token, "map_Ks", 6)) && IS_SPACE(token[6])) {
token += 7; token += 7;
material.specular_texname = my_strdup(token, (size_t) (line_end - token)); material.specular_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* specular highlight texture */ /* specular highlight texture */
if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) { if ((0 == strncmp(token, "map_Ns", 6)) && IS_SPACE(token[6])) {
token += 7; token += 7;
material.specular_highlight_texname = my_strdup(token, (size_t) (line_end - token)); material.specular_highlight_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* bump texture */ /* bump texture */
if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) { if ((0 == strncmp(token, "map_bump", 8)) && IS_SPACE(token[8])) {
token += 9; token += 9;
material.bump_texname = my_strdup(token, (size_t) (line_end - token)); material.bump_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* alpha texture */ /* alpha texture */
if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) { if ((0 == strncmp(token, "map_d", 5)) && IS_SPACE(token[5])) {
token += 6; token += 6;
material.alpha_texname = my_strdup(token, (size_t) (line_end - token)); material.alpha_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* bump texture */ /* bump texture */
if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) { if ((0 == strncmp(token, "bump", 4)) && IS_SPACE(token[4])) {
token += 5; token += 5;
material.bump_texname = my_strdup(token, (size_t) (line_end - token)); material.bump_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
/* displacement texture */ /* displacement texture */
if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) { if ((0 == strncmp(token, "disp", 4)) && IS_SPACE(token[4])) {
token += 5; token += 5;
material.displacement_texname = my_strdup(token, (size_t) (line_end - token)); material.displacement_texname = my_strdup(token, (unsigned int) (line_end - token));
continue; continue;
} }
@ -1090,13 +957,17 @@ static int tinyobj_parse_and_index_mtl_file(tinyobj_material_t **materials_out,
(*num_materials_out) = num_materials; (*num_materials_out) = num_materials;
(*materials_out) = materials; (*materials_out) = materials;
if (linebuf) {
TINYOBJ_FREE(linebuf);
}
return TINYOBJ_SUCCESS; return TINYOBJ_SUCCESS;
} }
int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out, int tinyobj_parse_mtl_file(tinyobj_material_t **materials_out,
size_t *num_materials_out, unsigned int *num_materials_out,
const char *mtl_filename, const char *obj_filename, file_reader_callback file_reader) { const char *filename) {
return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, mtl_filename, obj_filename, file_reader, NULL); return tinyobj_parse_and_index_mtl_file(materials_out, num_materials_out, filename, NULL);
} }
@ -1120,10 +991,10 @@ typedef struct {
/* @todo { Use dynamic array } */ /* @todo { Use dynamic array } */
tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
size_t num_f; unsigned int num_f;
int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE]; int f_num_verts[TINYOBJ_MAX_FACES_PER_F_LINE];
size_t num_f_num_verts; unsigned int num_f_num_verts;
const char *group_name; const char *group_name;
unsigned int group_name_len; unsigned int group_name_len;
@ -1143,7 +1014,7 @@ typedef struct {
CommandType type; CommandType type;
} Command; } Command;
static int parseLine(Command *command, const char *p, size_t p_len, static int parseLine(Command *command, const char *p, unsigned int p_len,
int triangulate) { int triangulate) {
char linebuf[4096]; char linebuf[4096];
const char *token; const char *token;
@ -1205,7 +1076,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
/* face */ /* face */
if (token[0] == 'f' && IS_SPACE((token[1]))) { if (token[0] == 'f' && IS_SPACE((token[1]))) {
size_t num_f = 0; unsigned int num_f = 0;
tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE]; tinyobj_vertex_index_t f[TINYOBJ_MAX_FACES_PER_F_LINE];
token += 2; token += 2;
@ -1222,8 +1093,8 @@ static int parseLine(Command *command, const char *p, size_t p_len,
command->type = COMMAND_F; command->type = COMMAND_F;
if (triangulate) { if (triangulate) {
size_t k; unsigned int k;
size_t n = 0; unsigned int n = 0;
tinyobj_vertex_index_t i0 = f[0]; tinyobj_vertex_index_t i0 = f[0];
tinyobj_vertex_index_t i1; tinyobj_vertex_index_t i1;
@ -1245,7 +1116,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
command->num_f_num_verts = n; command->num_f_num_verts = n;
} else { } else {
size_t k = 0; unsigned int k = 0;
assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE); assert(num_f < TINYOBJ_MAX_FACES_PER_F_LINE);
for (k = 0; k < num_f; k++) { for (k = 0; k < num_f; k++) {
command->f[k] = f[k]; command->f[k] = f[k];
@ -1266,7 +1137,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
skip_space(&token); skip_space(&token);
command->material_name = p + (token - linebuf); command->material_name = p + (token - linebuf);
command->material_name_len = (unsigned int)length_until_newline( command->material_name_len = (unsigned int)length_until_newline(
token, (p_len - (size_t)(token - linebuf)) + 1); token, (p_len - (unsigned int)(token - linebuf)) + 1);
command->type = COMMAND_USEMTL; command->type = COMMAND_USEMTL;
return 1; return 1;
@ -1280,7 +1151,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
skip_space(&token); skip_space(&token);
command->mtllib_name = p + (token - linebuf); command->mtllib_name = p + (token - linebuf);
command->mtllib_name_len = (unsigned int)length_until_newline( command->mtllib_name_len = (unsigned int)length_until_newline(
token, p_len - (size_t)(token - linebuf)) + token, p_len - (unsigned int)(token - linebuf)) +
1; 1;
command->type = COMMAND_MTLLIB; command->type = COMMAND_MTLLIB;
@ -1294,7 +1165,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
command->group_name = p + (token - linebuf); command->group_name = p + (token - linebuf);
command->group_name_len = (unsigned int)length_until_newline( command->group_name_len = (unsigned int)length_until_newline(
token, p_len - (size_t)(token - linebuf)) + token, p_len - (unsigned int)(token - linebuf)) +
1; 1;
command->type = COMMAND_G; command->type = COMMAND_G;
@ -1308,7 +1179,7 @@ static int parseLine(Command *command, const char *p, size_t p_len,
command->object_name = p + (token - linebuf); command->object_name = p + (token - linebuf);
command->object_name_len = (unsigned int)length_until_newline( command->object_name_len = (unsigned int)length_until_newline(
token, p_len - (size_t)(token - linebuf)) + token, p_len - (unsigned int)(token - linebuf)) +
1; 1;
command->type = COMMAND_O; command->type = COMMAND_O;
@ -1318,61 +1189,43 @@ static int parseLine(Command *command, const char *p, size_t p_len,
return 0; return 0;
} }
#if 0 typedef struct {
/* `path` content will be modified unsigned int pos;
*/ unsigned int len;
static char *get_dirname(char *path) } LineInfo;
{
char *last_delim = NULL;
if (path == NULL) { static int is_line_ending(const char *p, unsigned int i, unsigned int end_i) {
return path; 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;
#if defined(_WIN32)
last_delim = strrchr(path, '\\');
#else
last_delim = strrchr(path, '/');
#endif
if (last_delim == NULL) {
/* no delimiter in the string. */
return path;
}
/* remove '/' */
last_delim[0] = '\0';
return path;
} }
#endif
int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
size_t *num_shapes, tinyobj_material_t **materials_out, unsigned int *num_shapes, tinyobj_material_t **materials_out,
size_t *num_materials_out, const char *obj_filename, file_reader_callback file_reader, unsigned int *num_materials_out, const char *buf, unsigned int len,
unsigned int flags) { unsigned int flags) {
LineInfo *line_infos = NULL; LineInfo *line_infos = NULL;
Command *commands = NULL; Command *commands = NULL;
size_t num_lines = 0; unsigned int num_lines = 0;
size_t num_v = 0; unsigned int num_v = 0;
size_t num_vn = 0; unsigned int num_vn = 0;
size_t num_vt = 0; unsigned int num_vt = 0;
size_t num_f = 0; unsigned int num_f = 0;
size_t num_faces = 0; unsigned int num_faces = 0;
int mtllib_line_index = -1; int mtllib_line_index = -1;
tinyobj_material_t *materials = NULL; tinyobj_material_t *materials = NULL;
size_t num_materials = 0; unsigned int num_materials = 0;
hash_table_t material_table; hash_table_t material_table;
char *buf = NULL;
size_t len = 0;
file_reader(obj_filename, /* is_mtl */0, obj_filename, &buf, &len);
if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER; if (len < 1) return TINYOBJ_ERROR_INVALID_PARAMETER;
if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; if (attrib == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; if (shapes == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
@ -1382,10 +1235,46 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER; if (num_materials_out == NULL) return TINYOBJ_ERROR_INVALID_PARAMETER;
tinyobj_attrib_init(attrib); 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;
/* 1. create line data */ /* Count # of lines. */
if (get_line_infos(buf, len, &line_infos, &num_lines) != 0) { for (i = 0; i < end_idx; i++) {
return TINYOBJ_ERROR_EMPTY; 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); commands = (Command *)TINYOBJ_MALLOC(sizeof(Command) * num_lines);
@ -1394,7 +1283,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
/* 2. parse each line */ /* 2. parse each line */
{ {
size_t i = 0; unsigned int i = 0;
for (i = 0; i < num_lines; i++) { for (i = 0; i < num_lines; i++) {
int ret = parseLine(&commands[i], &buf[line_infos[i].pos], int ret = parseLine(&commands[i], &buf[line_infos[i].pos],
line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE); line_infos[i].len, flags & TINYOBJ_FLAG_TRIANGULATE);
@ -1425,26 +1314,10 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
/* Load material(if exits) */ /* Load material(if exits) */
if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name && if (mtllib_line_index >= 0 && commands[mtllib_line_index].mtllib_name &&
commands[mtllib_line_index].mtllib_name_len > 0) { commands[mtllib_line_index].mtllib_name_len > 0) {
char *filename = my_strndup(commands[mtllib_line_index].mtllib_name,
/* Extract .obj filepath. */
/*char *search_path = NULL; */
char *filename = NULL;
int ret;
#if 0
/* Simply find last delimiter `/`
* TODO(syoyo): Robust extraction of base directory of filename.
*/
if (obj_filename) {
char *basedir = my_strdup(file_name, my_strnlen(file_name, TINYOBJ_MAX_FILEPATH));
search_path = get_dirname(basedir);
}
#endif
filename = my_strndup(commands[mtllib_line_index].mtllib_name,
commands[mtllib_line_index].mtllib_name_len); commands[mtllib_line_index].mtllib_name_len);
ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, obj_filename, file_reader, &material_table); int ret = tinyobj_parse_and_index_mtl_file(&materials, &num_materials, filename, &material_table);
if (ret != TINYOBJ_SUCCESS) { if (ret != TINYOBJ_SUCCESS) {
/* warning. */ /* warning. */
@ -1452,24 +1325,19 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
} }
TINYOBJ_FREE(filename); TINYOBJ_FREE(filename);
#if 0
if (search_path) {
TINYOBJ_FREE(search_path);
}
#endif
} }
/* Construct attributes */ /* Construct attributes */
{ {
size_t v_count = 0; unsigned int v_count = 0;
size_t n_count = 0; unsigned int n_count = 0;
size_t t_count = 0; unsigned int t_count = 0;
size_t f_count = 0; unsigned int f_count = 0;
size_t face_count = 0; unsigned int face_count = 0;
int material_id = -1; /* -1 = default unknown material. */ int material_id = -1; /* -1 = default unknown material. */
size_t i = 0; unsigned int i = 0;
attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3); attrib->vertices = (float *)TINYOBJ_MALLOC(sizeof(float) * num_v * 3);
attrib->num_vertices = (unsigned int)num_v; attrib->num_vertices = (unsigned int)num_v;
@ -1477,12 +1345,13 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
attrib->num_normals = (unsigned int)num_vn; attrib->num_normals = (unsigned int)num_vn;
attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2); attrib->texcoords = (float *)TINYOBJ_MALLOC(sizeof(float) * num_vt * 2);
attrib->num_texcoords = (unsigned int)num_vt; attrib->num_texcoords = (unsigned int)num_vt;
attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC( attrib->faces = (tinyobj_vertex_index_t *)TINYOBJ_MALLOC(sizeof(tinyobj_vertex_index_t) * num_f);
sizeof(tinyobj_vertex_index_t) * num_f);
attrib->num_faces = (unsigned int)num_f;
attrib->face_num_verts = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces); 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); attrib->material_ids = (int *)TINYOBJ_MALLOC(sizeof(int) * num_faces);
attrib->num_face_num_verts = (unsigned int)num_faces;
for (i = 0; i < num_lines; i++) { for (i = 0; i < num_lines; i++) {
if (commands[i].type == COMMAND_EMPTY) { if (commands[i].type == COMMAND_EMPTY) {
@ -1508,7 +1377,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
/* Create a null terminated string */ /* Create a null terminated string */
char* material_name_null_term = (char*) TINYOBJ_MALLOC(commands[i].material_name_len + 1); 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); 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] = 0; material_name_null_term[commands[i].material_name_len - 1] = 0;
if (hash_table_exists(material_name_null_term, &material_table)) if (hash_table_exists(material_name_null_term, &material_table))
material_id = (int)hash_table_get(material_name_null_term, &material_table); material_id = (int)hash_table_get(material_name_null_term, &material_table);
@ -1532,7 +1401,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
attrib->texcoords[2 * t_count + 1] = commands[i].ty; attrib->texcoords[2 * t_count + 1] = commands[i].ty;
t_count++; t_count++;
} else if (commands[i].type == COMMAND_F) { } else if (commands[i].type == COMMAND_F) {
size_t k = 0; unsigned int k = 0;
for (k = 0; k < commands[i].num_f; k++) { for (k = 0; k < commands[i].num_f; k++) {
tinyobj_vertex_index_t vi = commands[i].f[k]; tinyobj_vertex_index_t vi = commands[i].f[k];
int v_idx = fixIndex(vi.v_idx, v_count); int v_idx = fixIndex(vi.v_idx, v_count);
@ -1557,9 +1426,9 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
/* 5. Construct shape information. */ /* 5. Construct shape information. */
{ {
unsigned int face_count = 0; unsigned int face_count = 0;
size_t i = 0; unsigned int i = 0;
size_t n = 0; unsigned int n = 0;
size_t shape_idx = 0; unsigned int shape_idx = 0;
const char *shape_name = NULL; const char *shape_name = NULL;
unsigned int shape_name_len = 0; unsigned int shape_name_len = 0;
@ -1631,7 +1500,7 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes,
} }
if ((face_count - prev_face_offset) > 0) { if ((face_count - prev_face_offset) > 0) {
size_t length = face_count - prev_shape_face_offset; unsigned int length = face_count - prev_shape_face_offset;
if (length > 0) { if (length > 0) {
(*shapes)[shape_idx].name = (*shapes)[shape_idx].name =
my_strndup(prev_shape_name, prev_shape_name_len); my_strndup(prev_shape_name, prev_shape_name_len);
@ -1682,8 +1551,8 @@ void tinyobj_attrib_free(tinyobj_attrib_t *attrib) {
if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids); if (attrib->material_ids) TINYOBJ_FREE(attrib->material_ids);
} }
void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes) { void tinyobj_shapes_free(tinyobj_shape_t *shapes, unsigned int num_shapes) {
size_t i; unsigned int i;
if (shapes == NULL) return; if (shapes == NULL) return;
for (i = 0; i < num_shapes; i++) { for (i = 0; i < num_shapes; i++) {
@ -1694,8 +1563,8 @@ void tinyobj_shapes_free(tinyobj_shape_t *shapes, size_t num_shapes) {
} }
void tinyobj_materials_free(tinyobj_material_t *materials, void tinyobj_materials_free(tinyobj_material_t *materials,
size_t num_materials) { unsigned int num_materials) {
size_t i; unsigned int i;
if (materials == NULL) return; if (materials == NULL) return;
for (i = 0; i < num_materials; i++) { for (i = 0; i < num_materials; i++) {

View file

@ -898,7 +898,7 @@ Material *LoadMaterials(const char *fileName, int *materialCount)
{ {
tinyobj_material_t *mats = NULL; tinyobj_material_t *mats = NULL;
int result = tinyobj_parse_mtl_file(&mats, &count, fileName, NULL, NULL); int result = tinyobj_parse_mtl_file(&mats, &count, fileName);
if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName); if (result != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MATERIAL: [%s] Failed to parse materials file", fileName);
// TODO: Process materials to return // TODO: Process materials to return
@ -2946,10 +2946,6 @@ RayHitInfo GetCollisionRayGround(Ray ray, float groundHeight)
#if defined(SUPPORT_FILEFORMAT_OBJ) #if defined(SUPPORT_FILEFORMAT_OBJ)
// Load OBJ mesh data // Load OBJ mesh data
// TODO used by loadOBJ, could change to a function that could handle
// data coming from a file, memory or archive...
static Model LoadOBJ(const char *fileName) static Model LoadOBJ(const char *fileName)
{ {
Model model = { 0 }; Model model = { 0 };
@ -2961,17 +2957,17 @@ static Model LoadOBJ(const char *fileName)
tinyobj_material_t *materials = NULL; tinyobj_material_t *materials = NULL;
unsigned int materialCount = 0; unsigned int materialCount = 0;
//char *fileData = LoadFileText(fileName); char *fileData = LoadFileText(fileName);
//if (fileData != NULL) if (fileData != NULL)
{ {
//unsigned int dataSize = (unsigned int)strlen(fileData); unsigned int dataSize = (unsigned int)strlen(fileData);
char currentDir[1024] = { 0 }; char currentDir[1024] = { 0 };
strcpy(currentDir, GetWorkingDirectory()); strcpy(currentDir, GetWorkingDirectory());
chdir(GetDirectoryPath(fileName)); chdir(GetDirectoryPath(fileName));
unsigned int flags = TINYOBJ_FLAG_TRIANGULATE; unsigned int flags = TINYOBJ_FLAG_TRIANGULATE;
int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileName, NULL, flags); int ret = tinyobj_parse_obj(&attrib, &meshes, &meshCount, &materials, &materialCount, fileData, dataSize, flags);
if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName); if (ret != TINYOBJ_SUCCESS) TRACELOG(LOG_WARNING, "MODEL: [%s] Failed to load OBJ data", fileName);
else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount); else TRACELOG(LOG_INFO, "MODEL: [%s] OBJ data loaded successfully: %i meshes / %i materials", fileName, meshCount, materialCount);