loader_aw

Load OBJ/MTL file formats
git clone git://git.meso-star.fr/loader_aw.git
Log | Files | Refs | README | LICENSE

commit 69abdcb05bd5928413c218e10fc22c0aafe8eb2c
parent 344df434102b61a8ecc831bd5ef31d7a17bab105
Author: vaplv <vaplv@free.fr>
Date:   Sun, 20 Jul 2014 16:32:58 +0200

Add the loading of an obj from a C stream

Diffstat:
Msrc/aw.c | 42------------------------------------------
Msrc/aw.h | 6+++++-
Msrc/aw_c.h | 9---------
Msrc/aw_mtl.c | 11+++++------
Msrc/aw_obj.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Msrc/test_aw_obj.c | 2+-
6 files changed, 106 insertions(+), 110 deletions(-)

diff --git a/src/aw.c b/src/aw.c @@ -8,48 +8,6 @@ * Local functions ******************************************************************************/ enum aw_result -read_file(struct mem_allocator* allocator, const char* filename, char** out) -{ - FILE* file = NULL; - char* content = NULL; - long size = 0; - size_t len = 0; - enum aw_result res = AW_OK; - ASSERT(allocator && filename && out); - (void)len; - - file = fopen(filename, "r"); - if(!file) { - res = AW_IO_ERROR; - goto error; - } - fseek(file, 0, SEEK_END); - size = ftell(file); - fseek(file, 0, SEEK_SET); - - content = MEM_ALLOC(allocator, (size_t)size + 1 /* Null char */); - if(!content) { - res = AW_MEMORY_ERROR; - goto error; - } - len = fread(content, 1, (size_t)size, file); - content[size] = '\0'; - ASSERT(len == (size_t)size); - -exit: - if(file) - fclose(file); - *out = content; - return res; -error: - if(content) { - MEM_FREE(allocator, content); - content = NULL; - } - goto exit; -} - -enum aw_result parse_floatX (float* f, const unsigned int count_min, diff --git a/src/aw.h b/src/aw.h @@ -21,7 +21,6 @@ enum aw_result { AW_BAD_ARGUMENT, - AW_IO_ERROR, AW_MEMORY_ERROR, AW_OK }; @@ -149,6 +148,11 @@ aw_obj_load const char* filename); AW_API enum aw_result +aw_obj_load_stream + (struct aw_obj* obj, + FILE* stream); + +AW_API enum aw_result aw_obj_desc_get (struct aw_obj* obj, struct aw_obj_desc* desc); diff --git a/src/aw_c.h b/src/aw_c.h @@ -29,15 +29,6 @@ string_to_size_t(const char* str, size_t* i) return AW_OK; } -/* Read `filename' and store its content in `file'. `file' is internally - * allocated by the provided allocator and consequently the callee should - * deallocate it with the same allocator */ -extern LOCAL_SYM enum aw_result -read_file - (struct mem_allocator* allocator, - const char* filename, - char** file); - extern LOCAL_SYM enum aw_result parse_floatX (float* f, diff --git a/src/aw_mtl.c b/src/aw_mtl.c @@ -162,9 +162,8 @@ struct aw_mtl { struct darray_material materials; struct aw_material* newmtl; /* Pointer toward the current material */ - /* The following variables are used in error messages */ - const char* filename; /* Currently parsed file */ - size_t iline; /* Currently parsed line index */ + const char* filename; /* Currently parsed file. Use in error messages */ + size_t iline; /* Currently parsed line index. Use in error messages */ ref_T ref; struct mem_allocator* allocator; @@ -537,8 +536,8 @@ aw_mtl_ref_put(struct aw_mtl* mtl) enum aw_result aw_mtl_load(struct aw_mtl* mtl, const char* filename) { - enum aw_result res = AW_OK; FILE* file; + enum aw_result res = AW_OK; if(!mtl || !filename) return AW_BAD_ARGUMENT; @@ -546,8 +545,8 @@ aw_mtl_load(struct aw_mtl* mtl, const char* filename) mtl->filename = filename; file = fopen(filename, "r"); if(!file) { - fprintf(stderr, "Error opening the file `%s'\n", filename); - return AW_IO_ERROR; + fprintf(stderr, "Error opening `%s'\n", filename); + return AW_BAD_ARGUMENT; } res = aw_mtl_load_stream(mtl, file); diff --git a/src/aw_obj.c b/src/aw_obj.c @@ -2,6 +2,7 @@ #include "aw_c.h" +#include <rsys/dynamic_array_char.h> #include <rsys/dynamic_array_float.h> #include <rsys/float3.h> #include <rsys/float4.h> @@ -104,6 +105,9 @@ struct aw_obj { size_t igroups_active; /* Index toward the first active group */ + const char* filename; /* Currently parsed file. Use in error messages */ + size_t iline; /* Currently parsed line index. Use in error messages */ + ref_T ref; struct mem_allocator* allocator; }; @@ -400,57 +404,45 @@ error: } static enum aw_result -parse_obj_file(struct aw_obj* obj, const char* path, char* content) +parse_obj_line(struct aw_obj* obj, char* line) { - char* line, *line_tk; - unsigned long iline; + char* word, *word_tk; enum aw_result res = AW_OK; - ASSERT(obj && path && content); - - line = strtok_r(content, "\n", &line_tk); - iline = 1; - while(line) { - char* word, *word_tk; - - word = strtok_r(line, " ", &word_tk); - while(word) { - if(word[0] == '#') { /* Comment */ - break; - } else if(!strcmp(word, "v")) { /* Vertex position */ - res = parse_floatX_in_darray(&obj->positions, 3, 4, 1.f, &word_tk); - } else if(!strcmp(word, "vn")) { /* Vertex normal */ - res = parse_floatX_in_darray(&obj->normals, 3, 3, 0.f, &word_tk); - } else if(!strcmp(word, "vt")) { /* Vertex texture coordinates */ - res = parse_floatX_in_darray(&obj->texcoords, 1, 3, 0.f, &word_tk); - } else if(!strcmp(word, "f") || !strcmp(word, "fo")) { /* face element */ - res = parse_face(obj, &word_tk); - } else if(!strcmp(word, "g")) { /* Grouping */ - res = parse_group(obj, &word_tk); - } else if(!strcmp(word, "s")) { /* Smooth group */ - res = parse_smooth_group(obj, &word_tk); - } else if(!strcmp(word, "mtllib")) { /* Mtl library */ - res = parse_mtllib(obj, &word_tk); - } else if(!strcmp(word, "usemtl")) { /* Use the mtl library */ - res = parse_usemtl(obj, &word_tk); - } else { - res = AW_OK; - fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s", - path, iline, word); - } - if(res != AW_OK) - goto error; - word = strtok_r(NULL, " ", &word_tk); + ASSERT(obj && line); + + word = strtok_r(line, " ", &word_tk); + while(word) { + if(word[0] == '#') { /* Comment */ + break; + } else if(!strcmp(word, "v")) { /* Vertex position */ + res = parse_floatX_in_darray(&obj->positions, 3, 4, 1.f, &word_tk); + } else if(!strcmp(word, "vn")) { /* Vertex normal */ + res = parse_floatX_in_darray(&obj->normals, 3, 3, 0.f, &word_tk); + } else if(!strcmp(word, "vt")) { /* Vertex texture coordinates */ + res = parse_floatX_in_darray(&obj->texcoords, 1, 3, 0.f, &word_tk); + } else if(!strcmp(word, "f") || !strcmp(word, "fo")) { /* face element */ + res = parse_face(obj, &word_tk); + } else if(!strcmp(word, "g")) { /* Grouping */ + res = parse_group(obj, &word_tk); + } else if(!strcmp(word, "s")) { /* Smooth group */ + res = parse_smooth_group(obj, &word_tk); + } else if(!strcmp(word, "mtllib")) { /* Mtl library */ + res = parse_mtllib(obj, &word_tk); + } else if(!strcmp(word, "usemtl")) { /* Use the mtl library */ + res = parse_usemtl(obj, &word_tk); + } else { + res = AW_OK; + fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s", + obj->filename, obj->iline, word); } - line = strtok_r(NULL, "\n", &line_tk); - ++iline; + if(res != AW_OK) + goto error; + word = strtok_r(NULL, " ", &word_tk); } - flush_groups(obj); - flush_smooth_group(obj); - flush_usemtl(obj); exit: return res; error: - fprintf(stderr, "%s:%lu: error: parsing failed\n", path, iline); + fprintf(stderr, "%s:%lu: error: parsing failed\n", obj->filename, obj->iline); goto exit; } @@ -554,29 +546,81 @@ aw_obj_ref_put(struct aw_obj* obj) enum aw_result aw_obj_load(struct aw_obj* obj, const char* filename) { - char* file_content = NULL; + FILE* file; enum aw_result res = AW_OK; - if(!obj || !filename) { + if(!obj || !filename) + return AW_BAD_ARGUMENT; + + obj->filename = filename; + file = fopen(filename, "r"); + if(!file) { + fprintf(stderr, "Error opening `%s'\n", filename); + return AW_BAD_ARGUMENT; + } + + res = aw_obj_load_stream(obj, file); + obj->filename = NULL; + fclose(file); + return res; +} + +enum aw_result +aw_obj_load_stream(struct aw_obj* obj, FILE* stream) +{ + char* line; + struct darray_char buf; + const unsigned buf_chunk = 256; + enum aw_result res = AW_OK; + + if(!obj || !stream) { res = AW_BAD_ARGUMENT; goto error; } + darray_char_init(obj->allocator, &buf); - if(AW_OK != (res = read_file(obj->allocator, filename, &file_content))) + if(darray_char_resize(&buf, buf_chunk)) { + res = AW_MEMORY_ERROR; goto error; + } + if(!obj->filename) + obj->filename = "stream"; + obj->iline = 1; obj_clear(obj); - if(AW_OK != (res = parse_obj_file(obj, filename, file_content))) - goto error; + while((line = fgets + (darray_char_data_get(&buf), (int)darray_char_size_get(&buf), stream))) { + + while(!strrchr(line,'\n')) { /* Ensure that the whole line was read */ + if(darray_char_resize(&buf, darray_char_size_get(&buf) + buf_chunk)) { + res = AW_MEMORY_ERROR; + goto error; + } + line = darray_char_data_get(&buf); + if(!fgets(line + strlen(line), (int)buf_chunk, stream)) /* EOF */ + break; + } + line[strlen(line) - 1] = '\0'; /* Remove the newline character */ + + if(AW_OK != (res = parse_obj_line(obj, line))) + goto error; + ++obj->iline; + } + flush_groups(obj); + flush_smooth_group(obj); + flush_usemtl(obj); exit: - if(file_content) - MEM_FREE(obj->allocator, file_content); + if(obj && stream) + darray_char_release(&buf); return res; error: + if(obj) + obj_clear(obj); goto exit; } + enum aw_result aw_obj_desc_get(struct aw_obj* obj, struct aw_obj_desc* desc) { diff --git a/src/test_aw_obj.c b/src/test_aw_obj.c @@ -42,7 +42,7 @@ test_plane(struct aw_obj* obj) CHECK(aw_obj_load(NULL, NULL), AW_BAD_ARGUMENT); CHECK(aw_obj_load(obj, NULL), AW_BAD_ARGUMENT); CHECK(aw_obj_load(NULL, "test_obj_plane.obj"), AW_BAD_ARGUMENT); - CHECK(aw_obj_load(obj, "none.obj"), AW_IO_ERROR); + CHECK(aw_obj_load(obj, "none.obj"), AW_BAD_ARGUMENT); CHECK(aw_obj_load(obj, "test_obj_plane.obj"), AW_OK); CHECK(aw_obj_desc_get(NULL, NULL), AW_BAD_ARGUMENT);