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