commit a4fde9c937876a4cd828173cacec08ac684901d7
parent 4731fce957c755f180bfe70136e66d15211a55e4
Author: vaplv <vaplv@free.fr>
Date: Sun, 6 Jul 2014 16:35:34 +0200
Parse the newmtl, Ka, Kd and Ks mtl directives
Diffstat:
| M | cmake/CMakeLists.txt | | | 2 | +- |
| A | src/aw.c | | | 47 | +++++++++++++++++++++++++++++++++++++++++++++++ |
| M | src/aw.h | | | 5 | +++++ |
| A | src/aw_c.h | | | 42 | ++++++++++++++++++++++++++++++++++++++++++ |
| M | src/aw_mtl.c | | | 226 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
| M | src/aw_obj.c | | | 78 | +++++++++++++++--------------------------------------------------------------- |
6 files changed, 333 insertions(+), 67 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -17,7 +17,7 @@ include(rcmake)
################################################################################
# Define targets
################################################################################
-set(AW_FILES_SRC aw_obj.c aw_mtl.c)
+set(AW_FILES_SRC aw_c.h aw.c aw_obj.c aw_mtl.c)
set(AW_FILES_INC aw.h)
rcmake_prepend_path(AW_FILES_SRC ${AW_SOURCE_DIR})
rcmake_prepend_path(AW_FILES_INC ${AW_SOURCE_DIR})
diff --git a/src/aw.c b/src/aw.c
@@ -0,0 +1,47 @@
+#include "aw_c.h"
+#include <rsys/mem_allocator.h>
+
+/*******************************************************************************
+ * 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;
+}
diff --git a/src/aw.h b/src/aw.h
@@ -144,6 +144,11 @@ AW_API enum aw_result
aw_mtl_ref_put
(struct aw_mtl* mtl);
+AW_API enum aw_result
+aw_mtl_load
+ (struct aw_mtl* mtl,
+ const char* filename);
+
END_DECLS
#endif /* AW_H */
diff --git a/src/aw_c.h b/src/aw_c.h
@@ -0,0 +1,42 @@
+#ifndef AW_C_H
+#define AW_C_H
+
+#include "aw.h"
+
+static FINLINE enum aw_result
+string_to_float(const char* str, float* f)
+{
+ char* ptr = NULL;
+ ASSERT(f);
+ if(!str)
+ return AW_BAD_ARGUMENT;
+ *f = (float)strtod(str, &ptr);
+ if(ptr == str || *ptr != '\0')
+ return AW_BAD_ARGUMENT;
+ return AW_OK;
+}
+
+static FINLINE enum aw_result
+string_to_size_t(const char* str, size_t* i)
+{
+ char* ptr = NULL;
+ ASSERT(i);
+ if(!str)
+ return AW_BAD_ARGUMENT;
+ *i = (size_t)strtol(str, &ptr, 10);
+ if(ptr == str || *ptr != '\0')
+ return AW_BAD_ARGUMENT;
+ return AW_OK;
+}
+
+/* Read `filename' and store its content in `file'. `file' is internally
+ * allocated by the provided allocator and consequentle the callee should
+ * deallocate it by using the same allocator */
+extern LOCAL_SYM enum aw_result
+read_file
+ (struct mem_allocator* allocator,
+ const char* filename,
+ char** file);
+
+#endif /* AW_C_H */
+
diff --git a/src/aw_mtl.c b/src/aw_mtl.c
@@ -1,11 +1,76 @@
#define _POSIX_C_SOURCE 200112L /* strtok_r support */
-#include "aw.h"
+#include "aw_c.h"
+#include <rsys/dynamic_array.h>
+#include <rsys/float3.h>
#include <rsys/mem_allocator.h>
#include <rsys/ref_count.h>
+#include <rsys/str.h>
+
+struct color {
+ float value[3];
+ char is_CIEXYZ;
+};
+
+static FINLINE void
+color_copy(struct color* dst, const struct color* src)
+{
+ ASSERT(dst && src);
+ f3_set(dst->value, src->value);
+ dst->is_CIEXYZ = src->is_CIEXYZ;
+}
+
+struct material {
+ struct str name;
+ struct color ambient;
+ struct color diffuse;
+ struct color specular;
+};
+
+static FINLINE void
+material_init(struct mem_allocator* allocator, struct material* mtl)
+{
+ ASSERT(mtl);
+ str_init(allocator, &mtl->name);
+}
+
+static FINLINE void
+material_release(struct material* mtl)
+{
+ ASSERT(mtl);
+ str_release(&mtl->name);
+}
+
+static FINLINE int
+material_copy(struct material* dst, const struct material* src)
+{
+ ASSERT(dst && src);
+ color_copy(&dst->ambient, &src->ambient);
+ return str_copy(&dst->name, &src->name);
+}
+
+static FINLINE int
+material_copy_and_release(struct material* dst, struct material* src)
+{
+ ASSERT(dst && src);
+ color_copy(&dst->ambient, &src->ambient);
+ return str_copy_and_release(&dst->name, &src->name);
+}
+
+/* Generate the darray_mtl data structure */
+#define DARRAY_NAME material
+#define DARRAY_DATA struct material
+#define DARRAY_FUNCTOR_INIT material_init
+#define DARRAY_FUNCTOR_RELEASE material_release
+#define DARRAY_FUNCTOR_COPY material_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE material_copy_and_release
+#include <rsys/dynamic_array.h>
struct aw_mtl {
+ struct darray_material materials;
+ struct material* newmtl; /* Pointer toward the current material */
+
ref_T ref;
struct mem_allocator* allocator;
};
@@ -13,11 +78,137 @@ struct aw_mtl {
/*******************************************************************************
* Helper functions
******************************************************************************/
+static enum aw_result
+parse_newmtl(struct aw_mtl* mtl, char** word_tk)
+{
+ char* word;
+ size_t nmtls;
+ ASSERT(mtl && word_tk);
+
+ word = strtok_r(NULL, "\n", word_tk);
+ if(!word)
+ return AW_BAD_ARGUMENT;
+
+ nmtls = darray_material_size_get(&mtl->materials);
+ if(darray_material_resize(&mtl->materials, nmtls + 1))
+ return AW_MEMORY_ERROR;
+
+ mtl->newmtl = darray_material_data_get(&mtl->materials) + nmtls;
+ if(str_set(&mtl->newmtl->name, word)) {
+ darray_material_pop_back(&mtl->materials);
+ mtl->newmtl = NULL;
+ return AW_MEMORY_ERROR;
+ }
+ return AW_OK;
+}
+
+static enum aw_result
+parse_color(struct color* col, char** word_tk)
+{
+ char* word;
+ enum aw_result res = AW_OK;
+ ASSERT(col && word_tk);
+
+ word = strtok_r(NULL, " ", word_tk);
+ if(!word)
+ return AW_BAD_ARGUMENT;
+
+ if(!strcmp(word, "spectral")) {
+ fprintf(stderr, "spectral colors are not supported\n");
+ return AW_BAD_ARGUMENT;
+ }
+
+ col->is_CIEXYZ = strcmp(word, "xyz") == 0;
+ if(col->is_CIEXYZ && !(word = strtok_r(NULL, " ", word_tk)))
+ return AW_BAD_ARGUMENT;
+
+ if(AW_OK != (res = string_to_float(word, &col->value[0])))
+ return res;
+
+ /* If only the first component is defined the second and third ones are
+ * assumed to be equal to the first one */
+ word = strtok_r(NULL, " ", word_tk);
+ if(!word) {
+ col->value[1] = col->value[2] = col->value[0];
+ } else {
+ if(AW_OK != (res = string_to_float(word, &col->value[1])))
+ return res;
+ word = strtok_r(NULL, " ", word_tk);
+ if(AW_OK != (res = string_to_float(word, &col->value[2])))
+ return res;
+ }
+ return AW_OK;
+}
+
+static enum aw_result
+parse_mtl_file(struct aw_mtl* mtl, const char* path, char* content)
+{
+ 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, " ", &word_tk);
+ while(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 */
+ } else if(!strcmp(word, "Ns")) { /* Specular exponent */
+ } else if(!strcmp(word, "Ni")) { /* Refraction index */
+ } else if(!strcmp(word, "illum")) { /* Illumination model */
+ } else if(!strcmp(word, "d")) { /* Dissolve factor */
+ } else if(!strcmp(word, "sharpness")) { /* Reflection sharpness */
+ } else if(!strcmp(word, "map_Ka")) { /* Ambient texture */
+ } else if(!strcmp(word, "map_Kd")) { /* Diffuse texture */
+ } else if(!strcmp(word, "map_Ks")) { /* Specular texture */
+ } else if(!strcmp(word, "map_Ns")) { /* Specular exponent texture */
+ } else if(!strcmp(word, "map_d")) { /* Dissolve texture */
+ } else if(!strcmp(word, "bump")) { /* Bump map */
+ } else {
+ res = AW_OK;
+ fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s\n",
+ path, iline, word);
+ }
+ if(res != AW_OK)
+ goto error;
+ word = strtok_r(NULL, " ", &word_tk);
+ }
+ line = strtok_r(NULL, "\n", &line_tk);
+ ++iline;
+ }
+exit:
+ return res;
+error:
+ fprintf(stderr, "%s:%lu: error: parsing failed\n", path, iline);
+ goto exit;
+}
+
+static void
+mtl_clear(struct aw_mtl* mtl)
+{
+ ASSERT(mtl);
+ darray_material_clear(&mtl->materials);
+ mtl->newmtl = NULL;
+}
+
static void
-aw_mtl_release(ref_T* ref)
+mtl_release(ref_T* ref)
{
struct aw_mtl* mtl = CONTAINER_OF(ref, struct aw_mtl, ref);
ASSERT(ref);
+ darray_material_release(&mtl->materials);
MEM_FREE(mtl->allocator, mtl);
}
@@ -45,6 +236,8 @@ aw_mtl_create
}
mtl->allocator = allocator;
ref_init(&mtl->ref);
+ darray_material_init(allocator, &mtl->materials);
+ mtl->newmtl = NULL;
exit:
if(mtl_out)
@@ -72,6 +265,33 @@ aw_mtl_ref_put(struct aw_mtl* mtl)
{
if(!mtl)
return AW_BAD_ARGUMENT;
- ref_put(&mtl->ref, aw_mtl_release);
+ ref_put(&mtl->ref, mtl_release);
return AW_OK;
}
+
+enum aw_result
+aw_mtl_load(struct aw_mtl* mtl, const char* filename)
+{
+ char* file_content = NULL;
+ enum aw_result res = AW_OK;
+
+ if(!mtl || !filename) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+
+ if(AW_OK != (res = read_file(mtl->allocator, filename, &file_content)))
+ goto error;
+
+ mtl_clear(mtl);
+ if(AW_OK != (res = parse_mtl_file(mtl, filename, file_content)))
+ goto error;
+
+exit:
+ if(file_content)
+ MEM_FREE(mtl->allocator, file_content);
+ return res;
+error:
+ goto exit;
+}
+
diff --git a/src/aw_obj.c b/src/aw_obj.c
@@ -1,6 +1,6 @@
#define _POSIX_C_SOURCE 200112L /* strtok_r support */
-#include "aw.h"
+#include "aw_c.h"
#include <rsys/dynamic_array_float.h>
#include <rsys/float3.h>
@@ -111,32 +111,6 @@ struct aw_obj {
/*******************************************************************************
* Helper functions
******************************************************************************/
-static FINLINE enum aw_result
-string_to_float(const char* str, float* f)
-{
- char* ptr = NULL;
- ASSERT(f);
- if(!str)
- return AW_BAD_ARGUMENT;
- *f = (float)strtod(str, &ptr);
- if(ptr == str || *ptr != '\0')
- return AW_BAD_ARGUMENT;
- return AW_OK;
-}
-
-static FINLINE enum aw_result
-string_to_size_t(const char* str, size_t* i)
-{
- char* ptr = NULL;
- ASSERT(i);
- if(!str)
- return AW_BAD_ARGUMENT;
- *i = (size_t)strtol(str, &ptr, 10);
- if(ptr == str || *ptr != '\0')
- return AW_BAD_ARGUMENT;
- return AW_OK;
-}
-
static FINLINE void
flush_groups(struct aw_obj* obj)
{
@@ -447,7 +421,7 @@ error:
}
static enum aw_result
-parse_file(struct aw_obj* obj, const char* path, char* content)
+parse_obj_file(struct aw_obj* obj, const char* path, char* content)
{
char* line, *line_tk;
unsigned long iline;
@@ -480,7 +454,9 @@ parse_file(struct aw_obj* obj, const char* path, char* content)
} else if(!strcmp(word, "usemtl")) { /* Use the mtl library */
res = parse_usemtl(obj, &word_tk);
} else {
- res = AW_BAD_ARGUMENT;
+ res = AW_OK;
+ fprintf(stderr, "%s:%lu: warning: ignored or malformed directive %s",
+ path, iline, word);
}
if(res != AW_OK)
goto error;
@@ -500,7 +476,7 @@ error:
}
static void
-aw_clear(struct aw_obj* obj)
+obj_clear(struct aw_obj* obj)
{
ASSERT(obj);
darray_float_clear(&obj->positions);
@@ -516,7 +492,7 @@ aw_clear(struct aw_obj* obj)
}
static void
-aw_release(ref_T* ref)
+obj_release(ref_T* ref)
{
struct aw_obj* obj = CONTAINER_OF(ref, struct aw_obj, ref);
ASSERT(ref);
@@ -538,13 +514,13 @@ aw_release(ref_T* ref)
enum aw_result
aw_obj_create
(struct mem_allocator* mem_allocator,
- struct aw_obj** aw_out)
+ struct aw_obj** obj_out)
{
struct mem_allocator* allocator;
struct aw_obj* obj = NULL;
enum aw_result res = AW_OK;
- if(!aw_out) {
+ if(!obj_out) {
res = AW_BAD_ARGUMENT;
goto error;
}
@@ -567,8 +543,8 @@ aw_obj_create
darray_mtllib_init(mem_allocator, &obj->mtllibs);
exit:
- if(aw_out)
- *aw_out = obj;
+ if(obj_out)
+ *obj_out = obj;
return res;
error:
if(obj) {
@@ -592,53 +568,29 @@ aw_obj_ref_put(struct aw_obj* obj)
{
if(!obj)
return AW_BAD_ARGUMENT;
- ref_put(&obj->ref, aw_release);
+ ref_put(&obj->ref, obj_release);
return AW_OK;
}
enum aw_result
aw_obj_load(struct aw_obj* obj, const char* filename)
{
- FILE* file = NULL;
char* file_content = NULL;
- long file_size = 0;
- size_t len = 0;
enum aw_result res = AW_OK;
- (void)len;
if(!obj || !filename) {
res = AW_BAD_ARGUMENT;
goto error;
}
- file = fopen(filename, "r");
- if(!file) {
- res = AW_IO_ERROR;
+ if(AW_OK != (res = read_file(obj->allocator, filename, &file_content)))
goto error;
- }
- fseek(file, 0, SEEK_END);
- file_size = ftell(file);
- fseek(file, 0, SEEK_SET);
-
- file_content = MEM_ALLOC(obj->allocator, (size_t)file_size + 1);
- if(!file_content) {
- res = AW_MEMORY_ERROR;
- goto error;
- }
- len = fread(file_content, 1, (size_t)file_size, file);
- file_content[file_size] = '\0';
- ASSERT(len == (size_t)file_size);
- fclose(file);
- file = NULL;
-
- aw_clear(obj);
- if(AW_OK != (res = parse_file(obj, filename, file_content)))
+ obj_clear(obj);
+ if(AW_OK != (res = parse_obj_file(obj, filename, file_content)))
goto error;
exit:
- if(file)
- fclose(file);
if(file_content)
MEM_FREE(obj->allocator, file_content);
return res;