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:
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);