loader_aw

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

commit 344df434102b61a8ecc831bd5ef31d7a17bab105
parent 54588b198b8a19b3674271190485496726b72bc7
Author: vaplv <vaplv@free.fr>
Date:   Sun, 20 Jul 2014 16:16:01 +0200

Add the loading of a mtl from a C stream

Diffstat:
Msrc/aw.h | 5+++++
Msrc/aw_mtl.c | 178+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Msrc/test_aw_mtl.c | 11+++++++----
3 files changed, 122 insertions(+), 72 deletions(-)

diff --git a/src/aw.h b/src/aw.h @@ -205,6 +205,11 @@ aw_mtl_load const char* filename); AW_API enum aw_result +aw_mtl_load_stream + (struct aw_mtl* mtl, + FILE* stream); + +AW_API enum aw_result aw_mtl_materials_count_get (struct aw_mtl* mtl, size_t* materials_count); diff --git a/src/aw_mtl.c b/src/aw_mtl.c @@ -2,7 +2,7 @@ #include "aw_c.h" -#include <rsys/dynamic_array.h> +#include <rsys/dynamic_array_char.h> #include <rsys/float3.h> #include <rsys/mem_allocator.h> #include <rsys/ref_count.h> @@ -162,6 +162,10 @@ 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 */ + ref_T ref; struct mem_allocator* allocator; }; @@ -396,71 +400,64 @@ parse_map } static enum aw_result -parse_mtl_file(struct aw_mtl* mtl, const char* path, char* content) +parse_mtl_line(struct aw_mtl* mtl, char* line) { - char* line, *line_tk; - unsigned long iline; enum aw_result res = AW_OK; - ASSERT(mtl && path && content); - - line = strtok_r(content, "\n", &line_tk); - iline = 1; - while(line) { - char* word, *word_tk; - word = strtok_r(line, " \t", &word_tk); - if(word) { - if(!strcmp(word, "newmtl")) { /* Material name declaration */ - res = parse_newmtl(mtl, &word_tk); - } else if(mtl->newmtl == NULL) { - res = AW_BAD_ARGUMENT; - } else if(!strcmp(word, "Ka")) { /* Ambient reflectivity */ - res = parse_color(&mtl->newmtl->ambient, &word_tk); - } else if(!strcmp(word, "Kd")) { /* Diffuse reflectivity */ - res = parse_color(&mtl->newmtl->diffuse, &word_tk); - } else if(!strcmp(word, "Ks")) { /* Specular reflectivity */ - res = parse_color(&mtl->newmtl->specular, &word_tk); - } else if(!strcmp(word, "Tf")) { /* Transimission filter */ - res = parse_color(&mtl->newmtl->transmission, &word_tk); - } else if(!strcmp(word, "Ns")) { /* Specular exponent */ - res = parse_floatX - (&mtl->newmtl->specular_exponent, 1, 1, 0.f, FLT_MAX, 0.f, &word_tk); - } else if(!strcmp(word, "Ni")) { /* Refraction index */ - res = parse_floatX - (&mtl->newmtl->refraction_index, 1, 1, 0.001f, 10.f, 0.001f,&word_tk); - } else if(!strcmp(word, "illum")) { /* Illumination model */ - res = parse_size_t(&mtl->newmtl->illumination_model, 0, 10, &word_tk); - } else if(!strcmp(word, "map_Ka")) { /* Ambient texture */ - res = parse_map(&mtl->newmtl->ambient_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Kd")) { /* Diffuse texture */ - res = parse_map(&mtl->newmtl->diffuse_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Ks")) { /* Specular texture */ - res = parse_map(&mtl->newmtl->specular_map, MAP_COMMON, &word_tk); - } else if(!strcmp(word, "map_Ns")) { /* Specular exponent texture */ - res = parse_map - (&mtl->newmtl->specular_exponent_map, MAP_SCALAR, &word_tk); - } else if(!strcmp(word, "bump")) { /* Bump map */ - res = parse_map(&mtl->newmtl->bump_map, MAP_BUMP, &word_tk); - } else { - res = AW_OK; - fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s\n", - path, iline, word); - while((word = strtok_r(NULL, " \t", &word_tk))); - } - if(res != AW_OK) - goto error; - if((word = strtok_r(NULL, " ", &word_tk))) { - fprintf(stderr, "%s:%lu: unexpected directive %s\n", path, iline, word); - res = AW_BAD_ARGUMENT; - goto error; - } + char* word, *word_tk; + ASSERT(mtl && line); + + word = strtok_r(line, " \t", &word_tk); + if(word) { + if(!strcmp(word, "newmtl")) { /* Material name declaration */ + res = parse_newmtl(mtl, &word_tk); + } else if(mtl->newmtl == NULL) { + res = AW_BAD_ARGUMENT; + } else if(!strcmp(word, "Ka")) { /* Ambient reflectivity */ + res = parse_color(&mtl->newmtl->ambient, &word_tk); + } else if(!strcmp(word, "Kd")) { /* Diffuse reflectivity */ + res = parse_color(&mtl->newmtl->diffuse, &word_tk); + } else if(!strcmp(word, "Ks")) { /* Specular reflectivity */ + res = parse_color(&mtl->newmtl->specular, &word_tk); + } else if(!strcmp(word, "Tf")) { /* Transimission filter */ + res = parse_color(&mtl->newmtl->transmission, &word_tk); + } else if(!strcmp(word, "Ns")) { /* Specular exponent */ + res = parse_floatX + (&mtl->newmtl->specular_exponent, 1, 1, 0.f, FLT_MAX, 0.f, &word_tk); + } else if(!strcmp(word, "Ni")) { /* Refraction index */ + res = parse_floatX + (&mtl->newmtl->refraction_index, 1, 1, 0.001f, 10.f, 0.001f,&word_tk); + } else if(!strcmp(word, "illum")) { /* Illumination model */ + res = parse_size_t(&mtl->newmtl->illumination_model, 0, 10, &word_tk); + } else if(!strcmp(word, "map_Ka")) { /* Ambient texture */ + res = parse_map(&mtl->newmtl->ambient_map, MAP_COMMON, &word_tk); + } else if(!strcmp(word, "map_Kd")) { /* Diffuse texture */ + res = parse_map(&mtl->newmtl->diffuse_map, MAP_COMMON, &word_tk); + } else if(!strcmp(word, "map_Ks")) { /* Specular texture */ + res = parse_map(&mtl->newmtl->specular_map, MAP_COMMON, &word_tk); + } else if(!strcmp(word, "map_Ns")) { /* Specular exponent texture */ + res = parse_map + (&mtl->newmtl->specular_exponent_map, MAP_SCALAR, &word_tk); + } else if(!strcmp(word, "bump")) { /* Bump map */ + res = parse_map(&mtl->newmtl->bump_map, MAP_BUMP, &word_tk); + } else { + res = AW_OK; + fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s\n", + mtl->filename, mtl->iline, word); + while((word = strtok_r(NULL, " \t", &word_tk))); + } + if(res != AW_OK) + goto error; + if((word = strtok_r(NULL, " ", &word_tk))) { + fprintf(stderr, "%s:%lu: unexpected directive %s\n", + mtl->filename, mtl->iline, word); + res = AW_BAD_ARGUMENT; + goto error; } - line = strtok_r(NULL, "\n", &line_tk); - ++iline; } exit: return res; error: - fprintf(stderr, "%s:%lu: error: parsing failed\n", path, iline); + fprintf(stderr, "%s:%lu: error: parsing failed\n", mtl->filename, mtl->iline); goto exit; } @@ -506,7 +503,6 @@ aw_mtl_create mtl->allocator = allocator; ref_init(&mtl->ref); darray_material_init(allocator, &mtl->materials); - mtl->newmtl = NULL; exit: if(mtl_out) @@ -541,24 +537,70 @@ aw_mtl_ref_put(struct aw_mtl* mtl) enum aw_result aw_mtl_load(struct aw_mtl* mtl, const char* filename) { - char* file_content = NULL; enum aw_result res = AW_OK; + FILE* file; - if(!mtl || !filename) { + if(!mtl || !filename) + return AW_BAD_ARGUMENT; + + mtl->filename = filename; + file = fopen(filename, "r"); + if(!file) { + fprintf(stderr, "Error opening the file `%s'\n", filename); + return AW_IO_ERROR; + } + + res = aw_mtl_load_stream(mtl, file); + mtl->filename = NULL; + fclose(file); + return res; +} + +enum aw_result +aw_mtl_load_stream(struct aw_mtl* mtl, FILE* stream) +{ + char* line; + struct darray_char buf; + const unsigned buf_chunk = 256; + enum aw_result res = AW_OK; + + if(!mtl || !stream) { res = AW_BAD_ARGUMENT; goto error; } - mtl_clear(mtl); + darray_char_init(mtl->allocator, &buf); - if(AW_OK != (res = read_file(mtl->allocator, filename, &file_content))) + if(darray_char_resize(&buf, buf_chunk)) { + res = AW_MEMORY_ERROR; goto error; + } - if(AW_OK != (res = parse_mtl_file(mtl, filename, file_content))) - goto error; + if(!mtl->filename) + mtl->filename = "stream"; + mtl->iline = 1; + mtl_clear(mtl); + 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_mtl_line(mtl, line))) + goto error; + ++mtl->iline; + } exit: - if(file_content) - MEM_FREE(mtl->allocator, file_content); + if(mtl && stream) + darray_char_release(&buf); return res; error: if(mtl) diff --git a/src/test_aw_mtl.c b/src/test_aw_mtl.c @@ -30,7 +30,7 @@ test_common(struct aw_mtl* mtl) "decal -s 1 1 1 -o 0 0 0 -mm 0 1 sand.mps\n" "bump -s 1 1 1 -o 0 0 0 -bm 1 sand.mpb\n" "\n" - "refl -type sphere -mm 0 1 clouds.mpc\n"; + "refl -type sphere -mm 0 1 clouds.mpc"; FILE* file; size_t nmtls; float tmp[3]; @@ -175,12 +175,15 @@ test_multiple_materials(struct aw_mtl* mtl) NCHECK(mtl, NULL); - file = fopen("test_mtl_multi.mtl", "w"); + file = fopen("test_mtl_multi.mtl", "rw"); NCHECK(file, NULL); fwrite(mtl_multi, sizeof(char), strlen(mtl_multi), file); - fclose(file); + CHECK(fseek(file, 0, SEEK_SET), 0); - CHECK(aw_mtl_load(mtl, "test_mtl_multi.mtl"), AW_OK); + CHECK(aw_mtl_load_stream(NULL, NULL), AW_BAD_ARGUMENT); + CHECK(aw_mtl_load_stream(mtl, NULL), AW_BAD_ARGUMENT); + CHECK(aw_mtl_load_stream(NULL, file), AW_BAD_ARGUMENT); + CHECK(aw_mtl_load_stream(mtl, file), AW_OK); CHECK(aw_mtl_materials_count_get(mtl, &nmtls), AW_OK); CHECK(nmtls, 3);