commit cf43b267d0bd0104c38c1008e725ffc6d428f99b
parent 6be9c358b64f45604a9875c25d56df66e30cd0e0
Author: vaplv <vaplv@free.fr>
Date: Sun, 6 Jul 2014 14:21:15 +0200
Change the `obj' project prefix by `aw'
AW means for Alias/Wavefront
Diffstat:
| M | cmake/CMakeLists.txt | | | 32 | ++++++++++++++++---------------- |
| A | src/aw.h | | | 150 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/aw_mtl.c | | | 77 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | src/aw_obj.c | | | 743 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/obj.c | | | 741 | ------------------------------------------------------------------------------- |
| D | src/obj.h | | | 130 | ------------------------------------------------------------------------------- |
| A | src/test_aw_obj.c | | | 345 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| D | src/test_obj.c | | | 345 | ------------------------------------------------------------------------------- |
8 files changed, 1331 insertions(+), 1232 deletions(-)
diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt
@@ -1,9 +1,9 @@
cmake_minimum_required(VERSION 2.6)
-project(loader_obj C)
+project(loader_aw C)
cmake_policy(SET CMP0011 NEW)
enable_testing()
-set(OBJ_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
+set(AW_SOURCE_DIR ${PROJECT_SOURCE_DIR}/../src)
################################################################################
# Dependencies
@@ -17,38 +17,38 @@ include(rcmake)
################################################################################
# Define targets
################################################################################
-set(OBJ_FILES_SRC obj.c)
-set(OBJ_FILES_INC obj.h)
-rcmake_prepend_path(OBJ_FILES_SRC ${OBJ_SOURCE_DIR})
-rcmake_prepend_path(OBJ_FILES_INC ${OBJ_SOURCE_DIR})
+set(AW_FILES_SRC aw_obj.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})
-add_library(loader-obj SHARED ${OBJ_FILES_SRC} ${OBJ_FILES_INC})
-target_link_libraries(loader-obj RSys)
+add_library(loader-aw SHARED ${AW_FILES_SRC} ${AW_FILES_INC})
+target_link_libraries(loader-aw RSys)
set(VERSION_MAJOR 0)
set(VERSION_MINOR 0)
set(VERSION_PATCH 0)
set(VERSION ${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH})
-set_target_properties(loader-obj PROPERTIES
- DEFINE_SYMBOL OBJ_SHARED_BUILD
+set_target_properties(loader-aw PROPERTIES
+ DEFINE_SYMBOL AW_SHARED_BUILD
VERSION ${VERSION}
SOVERSION ${VERSION_MAJOR})
-rcmake_setup_devel(LoaderObj loader-obj ${VERSION} obj/obj_version.h)
+rcmake_setup_devel(LoaderAW loader-aw ${VERSION} aw/aw_version.h)
################################################################################
# Define tests
################################################################################
-add_executable(test_obj ${OBJ_SOURCE_DIR}/test_obj.c)
-target_link_libraries(test_obj loader-obj)
-add_test(test_obj test_obj)
+add_executable(test_aw_obj ${AW_SOURCE_DIR}/test_aw_obj.c)
+target_link_libraries(test_aw_obj loader-aw)
+add_test(test_aw_obj test_aw_obj)
################################################################################
# Install directories
################################################################################
-install(TARGETS loader-obj
+install(TARGETS loader-aw
ARCHIVE DESTINATION lib
LIBRARY DESTINATION lib
RUNTIME DESTINATION bin)
-install(FILES ${OBJ_FILES_INC} DESTINATION include/obj)
+install(FILES ${AW_FILES_INC} DESTINATION include/aw)
diff --git a/src/aw.h b/src/aw.h
@@ -0,0 +1,150 @@
+#ifndef AW_H
+#define AW_H
+
+#include <rsys/rsys.h>
+
+#ifdef AW_SHARED_BUILD
+ #define AW_API extern EXPORT_SYM
+#elif defined(AW_STATIC_BUILD)
+ #define AW_API extern LOCAL_SYM
+#else
+ #define AW_API extern IMPORT_SYM
+#endif
+
+#ifndef NDEBUG
+ #define AW(Func) ASSERT(aw_##Func == AW_OK)
+#else
+ #define AW(Func) aw_##Func
+#endif
+
+#define AW_ID_NONE ((size_t)(-1))
+
+enum aw_result {
+ AW_BAD_ARGUMENT,
+ AW_IO_ERROR,
+ AW_MEMORY_ERROR,
+ AW_OK
+};
+
+struct aw_obj_desc {
+ size_t faces_count;
+ size_t groups_count;
+ size_t smooth_groups_count;
+ size_t usemtls_count;
+ size_t mtllibs_count;
+};
+
+struct aw_obj_face {
+ size_t vertex_id; /* Index of the first face vertex */
+ size_t vertices_count;
+ size_t group_id; /* Index of the face group */
+ size_t smooth_group_id; /* Index of the face smooth group */
+ size_t mtl_id; /* Index of the face material */
+};
+
+struct aw_obj_group {
+ const char* name;
+ size_t face_id; /* Index of the first group face */
+ size_t faces_count;
+};
+
+struct aw_obj_smooth_group {
+ char is_smoothed;
+ size_t face_id; /* Index of the first smooth group face */
+ size_t faces_count;
+};
+
+struct aw_obj_mtl {
+ const char* name;
+ size_t face_id;
+ size_t faces_count;
+};
+
+struct aw_obj_vertex {
+ float position[4];
+ float normal[3];
+ float texcoord[3];
+};
+
+struct aw_obj;
+struct aw_mtl;
+struct mem_allocator;
+
+BEGIN_DECLS
+
+/*******************************************************************************
+ * Obj functions
+ ******************************************************************************/
+AW_API enum aw_result
+aw_obj_create
+ (struct mem_allocator* allocator, /* NULL <=> use default allocator */
+ struct aw_obj** obj);
+
+AW_API enum aw_result
+aw_obj_ref_get
+ (struct aw_obj* obj);
+
+AW_API enum aw_result
+aw_obj_ref_put
+ (struct aw_obj* obj);
+
+AW_API enum aw_result
+aw_obj_load
+ (struct aw_obj* obj,
+ const char* filename);
+
+AW_API enum aw_result
+aw_obj_desc_get
+ (struct aw_obj* obj,
+ struct aw_obj_desc* desc);
+
+AW_API enum aw_result
+aw_obj_face_get
+ (const struct aw_obj* obj,
+ const size_t face_id,
+ struct aw_obj_face* face);
+
+AW_API enum aw_result
+aw_obj_group_get
+ (const struct aw_obj* obj,
+ const size_t group_id,
+ struct aw_obj_group* group);
+
+AW_API enum aw_result
+aw_obj_smooth_group_get
+ (const struct aw_obj* obj,
+ const size_t smooth_group_id,
+ struct aw_obj_smooth_group* smooth_group);
+
+AW_API enum aw_result
+aw_obj_mtl_get
+ (const struct aw_obj* obj,
+ const size_t mtl_id,
+ struct aw_obj_mtl* mtl);
+
+AW_API enum aw_result
+aw_obj_vertex_get
+ (const struct aw_obj* obj,
+ const size_t vertex_id,
+ struct aw_obj_vertex* vertex);
+
+/*******************************************************************************
+ * Mtl functions
+ ******************************************************************************/
+AW_API enum aw_result
+aw_mtl_create
+ (struct mem_allocator* allocator, /* NULL <=> use default allocator */
+ struct aw_mtl* mtl);
+
+AW_API enum aw_result
+aw_mtl_ref_get
+ (struct aw_mtl* mtl);
+
+AW_API enum aw_result
+aw_mtl_ref_put
+ (struct aw_mtl* mtl);
+
+END_DECLS
+
+#endif /* AW_H */
+
diff --git a/src/aw_mtl.c b/src/aw_mtl.c
@@ -0,0 +1,77 @@
+#define _POSIX_C_SOURCE 200112L /* strtok_r support */
+
+#include "obj.h"
+
+#include <rsys/mem_allocator.h>
+#include <rsys/ref_count.h>
+
+struct mtl {
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
+
+/*******************************************************************************
+ * Helper functions
+ ******************************************************************************/
+static void
+obj_mtl_release(ref_T* ref)
+{
+ struct obj_mtl* mtl = CONTAINER_OF(ref, struct obj_mtl, ref);
+ ASSERT(ref);
+ MEM_FREE(mtl->allocator, mtl);
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+enum obj_result
+obj_mtl_create
+ (struct mem_allocator* mem_allocator,
+ struct obj_mtl** mtl_out)
+{
+ struct mem_allocator* allocator;
+ struct obj_mtl* mtl = NULL;
+ enum obj_result res = OBJ_OK;
+
+ if(!mtl_out) {
+ res = OBJ_BAD_ARGUMENT;
+ goto error;
+ }
+ allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ mtl = MEM_CALLOC(allocator, 1, sizeof(struct obj_mtl));
+ if(!mtl) {
+ res = OBJ_MEMORY_ERROR;
+ goto error;
+ }
+ obj->allocator = allocator;
+ ref_init(&mtl->ref);
+
+exit:
+ if(mtl_out)
+ *mtl_out = mtl;
+ return res;
+error:
+ if(mtl) {
+ OBJ(mtl_ref_put(mtl));
+ mtl = NULL;
+ }
+ goto exit;
+}
+
+enum obj_result
+obj_mtl_ref_get(struct obj_mtl* mtl)
+{
+ if(!mtl)
+ return OBJ_BAD_ARGUMENT;
+ ref_get(&mtl->ref);
+ return OBJ_OK;
+}
+
+enum obj_result
+obj_mtl_ref_put(struct obj_mtl* mtl)
+{
+ if(!mtl)
+ return OBJ_BAD_ARGUMENT;
+ ref_put(&mtl->ref, obj_mtl_release);
+ return OBJ_OK;
+}
diff --git a/src/aw_obj.c b/src/aw_obj.c
@@ -0,0 +1,743 @@
+#define _POSIX_C_SOURCE 200112L /* strtok_r support */
+
+#include "aw.h"
+
+#include <rsys/dynamic_array_float.h>
+#include <rsys/float3.h>
+#include <rsys/float4.h>
+#include <rsys/mem_allocator.h>
+#include <rsys/ref_count.h>
+#include <rsys/str.h>
+
+#include <float.h>
+
+struct vertex {
+ size_t iposition;
+ size_t inormal;
+ size_t itexcoord;
+};
+static const struct vertex VERTEX_NULL = { AW_ID_NONE, AW_ID_NONE, AW_ID_NONE };
+
+struct named_group {
+ struct str name;
+ size_t iface; /* Index toward the first face */
+ size_t nfaces; /* Faces count in the group */
+};
+
+static INLINE void
+named_group_init(struct mem_allocator* allocator, struct named_group* grp)
+{
+ ASSERT(grp);
+ str_init(allocator, &grp->name);
+ grp->iface = 0;
+ grp->nfaces = 0;
+}
+
+static INLINE void
+named_group_release(struct named_group* grp)
+{
+ ASSERT(grp);
+ str_release(&grp->name);
+}
+
+static INLINE int
+named_group_copy(struct named_group* dst, const struct named_group* src)
+{
+ ASSERT(dst && src);
+ dst->iface = src->iface;
+ dst->nfaces = src->nfaces;
+ return str_copy(&dst->name, &src->name);
+}
+
+static INLINE int
+named_group_copy_and_release(struct named_group* dst, struct named_group* src)
+{
+ ASSERT(dst && src);
+ dst->iface = src->iface;
+ dst->nfaces = src->nfaces;
+ return str_copy_and_release(&dst->name, &src->name);
+}
+
+/* Generate the darray_vertex data structure */
+#define DARRAY_NAME vertex
+#define DARRAY_DATA struct vertex
+#include <rsys/dynamic_array.h>
+
+/* Generate the darray_face data structure */
+#define DARRAY_NAME face
+#define DARRAY_DATA struct aw_obj_face
+#include <rsys/dynamic_array.h>
+
+/* Generate the darray_named_group data structure */
+#define DARRAY_NAME named_group
+#define DARRAY_DATA struct named_group
+#define DARRAY_FUNCTOR_INIT named_group_init
+#define DARRAY_FUNCTOR_RELEASE named_group_release
+#define DARRAY_FUNCTOR_COPY named_group_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE named_group_copy_and_release
+#include <rsys/dynamic_array.h>
+
+/* Generate the darray_smooth_group data structure */
+#define DARRAY_NAME smooth_group
+#define DARRAY_DATA struct aw_obj_smooth_group
+#include <rsys/dynamic_array.h>
+
+/* Generate the darray_mtllib data structure */
+#define DARRAY_NAME mtllib
+#define DARRAY_DATA struct str
+#define DARRAY_FUNCTOR_INIT str_init
+#define DARRAY_FUNCTOR_RELEASE str_release
+#define DARRAY_FUNCTOR_COPY str_copy
+#define DARRAY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release
+#include <rsys/dynamic_array.h>
+
+struct aw_obj {
+ struct darray_float positions; /* float4 */
+ struct darray_float normals; /* float3 */
+ struct darray_float texcoords; /* float3 */
+ struct darray_vertex vertices;
+ struct darray_face faces;
+ struct darray_named_group groups;
+ struct darray_smooth_group smooth_groups;
+ struct darray_named_group usemtls;
+ struct darray_mtllib mtllibs;
+
+ size_t igroups_active; /* Index toward the first active group */
+
+ ref_T ref;
+ struct mem_allocator* allocator;
+};
+
+/*******************************************************************************
+ * 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)
+{
+ size_t nfaces, ngrps;
+ ASSERT(obj);
+ if(0 == (nfaces = darray_face_size_get(&obj->faces)))
+ return;
+ if(0 == (ngrps = darray_named_group_size_get(&obj->groups)))
+ return;
+ if(obj->igroups_active >= ngrps)
+ return;
+ FOR_EACH(obj->igroups_active, obj->igroups_active, ngrps) {
+ struct named_group* grp;
+ grp = darray_named_group_data_get(&obj->groups) + obj->igroups_active;
+ ASSERT(grp->iface <= nfaces);
+ grp->nfaces = nfaces - grp->iface;
+ }
+}
+
+static FINLINE void
+flush_usemtl(struct aw_obj* obj)
+{
+ struct named_group* mtl;
+ size_t nfaces, ngrps;
+ ASSERT(obj);
+ if(0 == (nfaces = darray_face_size_get(&obj->faces)))
+ return;
+ if(0 == (ngrps = darray_named_group_size_get(&obj->usemtls)))
+ return;
+ mtl = darray_named_group_data_get(&obj->usemtls) + (ngrps - 1);
+ ASSERT(mtl->iface <= nfaces);
+ mtl->nfaces = nfaces - mtl->iface;
+}
+
+static FINLINE void
+flush_smooth_group(struct aw_obj* obj)
+{
+ struct aw_obj_smooth_group* grp;
+ size_t nfaces, ngrps;
+ ASSERT(obj);
+ if(0 == (nfaces = darray_face_size_get(&obj->faces)))
+ return;
+ if(0 == (ngrps = darray_smooth_group_size_get(&obj->smooth_groups)))
+ return;
+ grp = darray_smooth_group_data_get(&obj->smooth_groups) + (ngrps - 1);
+ ASSERT(grp->face_id <= nfaces);
+ grp->faces_count = nfaces - grp->face_id;
+}
+
+static enum aw_result
+parse_floatX
+ (char** word_tk,
+ const unsigned count_min,
+ const unsigned count_max,
+ const float default_value,
+ struct darray_float* dst)
+{
+ unsigned i;
+ enum aw_result res = AW_OK;
+ ASSERT(word_tk && dst && count_min <= count_max);
+
+ FOR_EACH(i, 0, count_max) {
+ char* real;
+ float f;
+ if(NULL == (real = strtok_r(NULL, " ", word_tk)))
+ break;
+ res = string_to_float(real, &f);
+ if(res != AW_OK)
+ goto error;
+ if(darray_float_push_back(dst, &f)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ }
+ if(i < count_min) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+
+ FOR_EACH(i, i, count_max) {
+ if(darray_float_push_back(dst, &default_value)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ }
+
+exit:
+ return res;
+error:
+ FOR_EACH_REVERSE(i, i, 0)
+ darray_float_pop_back(dst);
+ goto exit;
+}
+
+static enum aw_result
+parse_face(struct aw_obj* obj, char** word_tk)
+{
+ struct aw_obj_face face;
+ char* word;
+ enum aw_result res = AW_OK;
+ ASSERT(obj && word_tk);
+
+ face.vertex_id = darray_vertex_size_get(&obj->vertices);
+ face.vertices_count = 0;
+ face.group_id = darray_named_group_size_get(&obj->groups) - 1;
+ face.smooth_group_id = darray_smooth_group_size_get(&obj->smooth_groups) - 1;
+ face.mtl_id = darray_named_group_size_get(&obj->usemtls) - 1;
+
+ /* Note that the obj indexation starts at 1 rather than 0. We thus subtract 1
+ * to the vertex attribute indices in order to match the C memory layout */
+ while((word = strtok_r(NULL, " ", word_tk))) {
+ char* id, *id_tk, *id_pos;
+ struct vertex vert = VERTEX_NULL;
+
+ /* position index */
+ id_pos = strtok_r(word, "/", &id_tk);
+ res = string_to_size_t(id_pos, &vert.iposition);
+ if(res != AW_OK)
+ goto error;
+ --vert.iposition; /* Match C memory layout */
+ if((id = strtok_r(NULL, "/", &id_tk))) {
+ id_pos += strlen(id_pos);
+ if( id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */
+ goto error;
+ if(id == id_pos + 2) { /* `//' separator => No tex */
+ /* normal index */
+ if(AW_OK != (res = string_to_size_t(id, &vert.inormal)))
+ goto error;
+ --vert.inormal; /* Match C memory layout */
+ } else {
+ /* texcoord index */
+ if(AW_OK != (res = string_to_size_t(id, &vert.itexcoord)))
+ goto error;
+ --vert.itexcoord; /* Match C memory latout */
+ /* normal index */
+ if((id = strtok_r(NULL, "/", &id_tk))) {
+ if(AW_OK != (res = string_to_size_t(id, &vert.inormal)))
+ goto error;
+ --vert.inormal; /* Match C memory layout */
+ }
+ }
+ }
+ if(darray_vertex_push_back(&obj->vertices, &vert)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ ++face.vertices_count;
+ }
+ if(darray_face_push_back(&obj->faces, &face)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+
+exit:
+ return res;
+error:
+ FOR_EACH_REVERSE(face.vertices_count, face.vertices_count, 0)
+ darray_vertex_pop_back(&obj->vertices);
+ goto exit;
+}
+
+static enum aw_result
+parse_group(struct aw_obj* obj, char** word_tk)
+{
+ char* word;
+ size_t ngrps = 0, igrp = 0;
+ enum aw_result res = AW_OK;
+ ASSERT(obj && word_tk);
+
+ flush_groups(obj);
+
+ word = strtok_r(NULL, " ", word_tk);
+ if(!word) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+ #define CALL(Func) { if(Func) { res = AW_MEMORY_ERROR; goto error; } }(void)0
+ ngrps = igrp = darray_named_group_size_get(&obj->groups);
+ obj->igroups_active = ngrps;
+ do {
+ struct named_group* grp = NULL;
+ if(darray_named_group_resize(&obj->groups, igrp + 1)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ grp = darray_named_group_data_get(&obj->groups) + ngrps;
+ ++igrp;
+ if(str_set(&grp->name, word)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ grp->iface = darray_face_size_get(&obj->faces);
+ grp->nfaces = 0;
+ } while((word = strtok_r(NULL, " ", word_tk)));
+
+exit:
+ return res;
+error:
+ if(igrp != ngrps)
+ CHECK(darray_named_group_resize(&obj->groups, ngrps), 0);
+ goto exit;
+}
+
+static enum aw_result
+parse_smooth_group(struct aw_obj* obj, char** word_tk)
+{
+ char* word;
+ struct aw_obj_smooth_group grp;
+ enum aw_result res;
+ size_t i;
+ ASSERT(obj && word_tk);
+
+ flush_smooth_group(obj);
+
+ word = strtok_r(NULL, " ", word_tk);
+ if(!strcmp(word, "off")) {
+ grp.is_smoothed = 0;
+ } else if(!strcmp(word, "on")) {
+ grp.is_smoothed = 1;
+ } else {
+ res = string_to_size_t(word, &i);
+ if(res != AW_OK)
+ return res;
+ grp.is_smoothed = i != 0;
+ }
+ grp.face_id = darray_face_size_get(&obj->faces);
+ grp.faces_count = 0;
+
+ if(darray_smooth_group_push_back(&obj->smooth_groups, &grp))
+ return AW_MEMORY_ERROR;
+
+ return AW_OK;
+}
+
+static enum aw_result
+parse_mtllib(struct aw_obj* obj, char** word_tk)
+{
+ char* word;
+ size_t imtllib = 0;
+ size_t nmtllibs = 0;
+ enum aw_result res = AW_OK;
+ ASSERT(obj && word_tk);
+
+ word = strtok_r(NULL, " ", word_tk);
+ if(!word) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+ nmtllibs = imtllib = darray_mtllib_size_get(&obj->mtllibs);
+ do {
+ struct str* str;
+ if(darray_mtllib_resize(&obj->mtllibs, imtllib + 1)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ str = darray_mtllib_data_get(&obj->mtllibs) + imtllib;
+ ++imtllib;
+ if(str_set(str, word)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ } while((word = strtok_r(NULL, " ", word_tk)));
+
+exit:
+ return res;
+error:
+ if(imtllib != nmtllibs)
+ CHECK(darray_mtllib_resize(&obj->mtllibs, nmtllibs), 0);
+ goto exit;
+}
+
+static enum aw_result
+parse_usemtl(struct aw_obj* obj, char** word_tk)
+{
+ char* word;
+ struct named_group* mtl = NULL;
+ size_t nmtls;
+ enum aw_result res = AW_OK;
+ ASSERT(obj && word_tk);
+
+ flush_usemtl(obj);
+
+ word= strtok_r(NULL, " ", word_tk);
+ if(!word_tk) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+
+ nmtls = darray_named_group_size_get(&obj->usemtls);
+ if(darray_named_group_resize(&obj->usemtls, nmtls + 1)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ mtl = darray_named_group_data_get(&obj->usemtls) + nmtls;
+ if(str_set(&mtl->name, word)) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ mtl->iface = darray_face_size_get(&obj->faces);
+ mtl->nfaces = 0;
+
+exit:
+ return res;
+error:
+ if(mtl)
+ darray_named_group_pop_back(&obj->usemtls);
+ goto exit;
+}
+
+static enum aw_result
+parse_file(struct aw_obj* obj, const char* path, char* content)
+{
+ char* line, *line_tk;
+ unsigned long iline;
+ 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(&word_tk, 3, 4, 1.f, &obj->positions);
+ } else if(!strcmp(word, "vn")) { /* Vertex normal */
+ res = parse_floatX(&word_tk, 3, 3, 0.f, &obj->normals);
+ } else if(!strcmp(word, "vt")) { /* Vertex texture coordinates */
+ res = parse_floatX(&word_tk, 1, 3, 0.f, &obj->texcoords);
+ } 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_BAD_ARGUMENT;
+ }
+ if(res != AW_OK)
+ goto error;
+ word = strtok_r(NULL, " ", &word_tk);
+ }
+ line = strtok_r(NULL, "\n", &line_tk);
+ ++iline;
+ }
+ flush_groups(obj);
+ flush_smooth_group(obj);
+ flush_usemtl(obj);
+exit:
+ return res;
+error:
+ fprintf(stderr, "%s:%lu: error: parsing failed\n", path, iline);
+ goto exit;
+}
+
+static void
+aw_clear(struct aw_obj* obj)
+{
+ ASSERT(obj);
+ darray_float_clear(&obj->positions);
+ darray_float_clear(&obj->normals);
+ darray_float_clear(&obj->texcoords);
+ darray_vertex_clear(&obj->vertices);
+ darray_face_clear(&obj->faces);
+ darray_named_group_clear(&obj->groups);
+ darray_named_group_clear(&obj->usemtls);
+ darray_smooth_group_clear(&obj->smooth_groups);
+ darray_mtllib_clear(&obj->mtllibs);
+ obj->igroups_active = 0;
+}
+
+static void
+aw_release(ref_T* ref)
+{
+ struct aw_obj* obj = CONTAINER_OF(ref, struct aw_obj, ref);
+ ASSERT(ref);
+ darray_float_release(&obj->positions);
+ darray_float_release(&obj->normals);
+ darray_float_release(&obj->texcoords);
+ darray_vertex_release(&obj->vertices);
+ darray_face_release(&obj->faces);
+ darray_named_group_release(&obj->groups);
+ darray_named_group_release(&obj->usemtls);
+ darray_smooth_group_release(&obj->smooth_groups);
+ darray_mtllib_release(&obj->mtllibs);
+ MEM_FREE(obj->allocator, obj);
+}
+
+/*******************************************************************************
+ * Exported functions
+ ******************************************************************************/
+enum aw_result
+aw_obj_create
+ (struct mem_allocator* mem_allocator,
+ struct aw_obj** aw_out)
+{
+ struct mem_allocator* allocator;
+ struct aw_obj* obj = NULL;
+ enum aw_result res = AW_OK;
+
+ if(!aw_out) {
+ res = AW_BAD_ARGUMENT;
+ goto error;
+ }
+ allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
+ obj = MEM_CALLOC(allocator, 1, sizeof(struct aw_obj));
+ if(!obj) {
+ res = AW_MEMORY_ERROR;
+ goto error;
+ }
+ obj->allocator = allocator;
+ ref_init(&obj->ref);
+ darray_float_init(mem_allocator, &obj->positions);
+ darray_float_init(mem_allocator, &obj->normals);
+ darray_float_init(mem_allocator, &obj->texcoords);
+ darray_vertex_init(mem_allocator, &obj->vertices);
+ darray_face_init(mem_allocator, &obj->faces);
+ darray_named_group_init(mem_allocator, &obj->groups);
+ darray_named_group_init(mem_allocator, &obj->usemtls);
+ darray_smooth_group_init(mem_allocator, &obj->smooth_groups);
+ darray_mtllib_init(mem_allocator, &obj->mtllibs);
+
+exit:
+ if(aw_out)
+ *aw_out = obj;
+ return res;
+error:
+ if(obj) {
+ AW(obj_ref_put(obj));
+ obj = NULL;
+ }
+ goto exit;
+}
+
+enum aw_result
+aw_obj_ref_get(struct aw_obj* obj)
+{
+ if(!obj)
+ return AW_BAD_ARGUMENT;
+ ref_get(&obj->ref);
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_ref_put(struct aw_obj* obj)
+{
+ if(!obj)
+ return AW_BAD_ARGUMENT;
+ ref_put(&obj->ref, aw_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;
+ 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)))
+ goto error;
+
+exit:
+ if(file)
+ fclose(file);
+ if(file_content)
+ MEM_FREE(obj->allocator, file_content);
+ return res;
+error:
+ goto exit;
+}
+
+enum aw_result
+aw_obj_desc_get(struct aw_obj* obj, struct aw_obj_desc* desc)
+{
+ if(!obj || !desc)
+ return AW_BAD_ARGUMENT;
+ desc->faces_count = darray_face_size_get(&obj->faces);
+ desc->groups_count = darray_named_group_size_get(&obj->groups);
+ desc->smooth_groups_count = darray_smooth_group_size_get(&obj->smooth_groups);
+ desc->usemtls_count = darray_named_group_size_get(&obj->usemtls);
+ desc->mtllibs_count = darray_mtllib_size_get(&obj->mtllibs);
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_face_get
+ (const struct aw_obj* obj, const size_t iface, struct aw_obj_face* face)
+{
+ if(!obj || !face || iface >= darray_face_size_get(&obj->faces))
+ return AW_BAD_ARGUMENT;
+ *face = darray_face_cdata_get(&obj->faces)[iface];
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_group_get
+ (const struct aw_obj* obj, const size_t igroup, struct aw_obj_group* grp)
+{
+ const struct named_group* group;
+ if(!obj || !grp || igroup >= darray_named_group_size_get(&obj->groups))
+ return AW_BAD_ARGUMENT;
+ group = darray_named_group_cdata_get(&obj->groups) + igroup;
+ grp->name = str_cget(&group->name);
+ grp->face_id = group->iface;
+ grp->faces_count = group->nfaces;
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_smooth_group_get
+ (const struct aw_obj* obj,
+ const size_t ismooth_group,
+ struct aw_obj_smooth_group* group)
+{
+ if(!obj || !group
+ || ismooth_group >= darray_smooth_group_size_get(&obj->smooth_groups))
+ return AW_BAD_ARGUMENT;
+ *group = darray_smooth_group_cdata_get(&obj->smooth_groups)[ismooth_group];
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_mtl_get
+ (const struct aw_obj* obj, const size_t imtl, struct aw_obj_mtl* mtl)
+{
+ const struct named_group* group;
+ if(!obj || !mtl || imtl >= darray_named_group_size_get(&obj->usemtls))
+ return AW_BAD_ARGUMENT;
+ group = darray_named_group_cdata_get(&obj->usemtls) + imtl;
+ mtl->name = str_cget(&group->name);
+ mtl->face_id = group->iface;
+ mtl->faces_count = group->nfaces;
+ return AW_OK;
+}
+
+enum aw_result
+aw_obj_vertex_get
+ (const struct aw_obj* obj, const size_t ivertex, struct aw_obj_vertex* vertex)
+{
+ const struct vertex* vert;
+ const float* data;
+ if(!obj || !vertex || ivertex >= darray_vertex_size_get(&obj->vertices))
+ return AW_BAD_ARGUMENT;
+ vert = darray_vertex_cdata_get(&obj->vertices) + ivertex;
+
+ /* Fetch vertex position */
+ ASSERT(vert->iposition != VERTEX_NULL.iposition);
+ data = darray_float_cdata_get(&obj->positions) + vert->iposition * 4;
+ f4_set(vertex->position, data);
+ /* Setup vertex texcoord */
+ if(vert->itexcoord == VERTEX_NULL.itexcoord) {
+ f3_splat(vertex->texcoord, 0.f);
+ } else {
+ data = darray_float_cdata_get(&obj->texcoords) + vert->itexcoord * 3;
+ f3_set(vertex->texcoord, data);
+ }
+ /* Setup vertex normal */
+ if(vert->inormal == VERTEX_NULL.inormal) {
+ f3_splat(vertex->normal, 0.f);
+ } else {
+ data = darray_float_cdata_get(&obj->normals) + vert->inormal * 3;
+ f3_set(vertex->normal, data);
+ }
+ return AW_OK;
+}
+
diff --git a/src/obj.c b/src/obj.c
@@ -1,741 +0,0 @@
-#define _POSIX_C_SOURCE 200112L /* strtok_r support */
-
-#include "obj.h"
-
-#include <rsys/dynamic_array_float.h>
-#include <rsys/float3.h>
-#include <rsys/float4.h>
-#include <rsys/mem_allocator.h>
-#include <rsys/ref_count.h>
-#include <rsys/str.h>
-
-#include <float.h>
-
-struct vertex {
- size_t iposition;
- size_t inormal;
- size_t itexcoord;
-};
-static const struct vertex VERTEX_NULL =
- { OBJ_ID_NONE, OBJ_ID_NONE, OBJ_ID_NONE };
-
-struct named_group {
- struct str name;
- size_t iface; /* Index toward the first face */
- size_t nfaces; /* Faces count in the group */
-};
-
-static INLINE void
-named_group_init(struct mem_allocator* allocator, struct named_group* grp)
-{
- ASSERT(grp);
- str_init(allocator, &grp->name);
- grp->iface = 0;
- grp->nfaces = 0;
-}
-
-static INLINE void
-named_group_release(struct named_group* grp)
-{
- ASSERT(grp);
- str_release(&grp->name);
-}
-
-static INLINE int
-named_group_copy(struct named_group* dst, const struct named_group* src)
-{
- ASSERT(dst && src);
- dst->iface = src->iface;
- dst->nfaces = src->nfaces;
- return str_copy(&dst->name, &src->name);
-}
-
-static INLINE int
-named_group_copy_and_release(struct named_group* dst, struct named_group* src)
-{
- ASSERT(dst && src);
- dst->iface = src->iface;
- dst->nfaces = src->nfaces;
- return str_copy_and_release(&dst->name, &src->name);
-}
-
-/* Generate the darray_vertex data structure */
-#define DARRAY_NAME vertex
-#define DARRAY_DATA struct vertex
-#include <rsys/dynamic_array.h>
-
-/* Generate the darray_face data structure */
-#define DARRAY_NAME face
-#define DARRAY_DATA struct obj_face
-#include <rsys/dynamic_array.h>
-
-/* Generate the darray_named_group data structure */
-#define DARRAY_NAME named_group
-#define DARRAY_DATA struct named_group
-#define DARRAY_FUNCTOR_INIT named_group_init
-#define DARRAY_FUNCTOR_RELEASE named_group_release
-#define DARRAY_FUNCTOR_COPY named_group_copy
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE named_group_copy_and_release
-#include <rsys/dynamic_array.h>
-
-/* Generate the darray_smooth_group data structure */
-#define DARRAY_NAME smooth_group
-#define DARRAY_DATA struct obj_smooth_group
-#include <rsys/dynamic_array.h>
-
-/* Generate the darray_mtllib data structure */
-#define DARRAY_NAME mtllib
-#define DARRAY_DATA struct str
-#define DARRAY_FUNCTOR_INIT str_init
-#define DARRAY_FUNCTOR_RELEASE str_release
-#define DARRAY_FUNCTOR_COPY str_copy
-#define DARRAY_FUNCTOR_COPY_AND_RELEASE str_copy_and_release
-#include <rsys/dynamic_array.h>
-
-struct obj {
- struct darray_float positions; /* float4 */
- struct darray_float normals; /* float3 */
- struct darray_float texcoords; /* float3 */
- struct darray_vertex vertices;
- struct darray_face faces;
- struct darray_named_group groups;
- struct darray_smooth_group smooth_groups;
- struct darray_named_group usemtls;
- struct darray_mtllib mtllibs;
-
- size_t igroups_active; /* Index toward the first active group */
-
- ref_T ref;
- struct mem_allocator* allocator;
-};
-
-/*******************************************************************************
- * Helper functions
- ******************************************************************************/
-static FINLINE enum obj_result
-string_to_float(const char* str, float* f)
-{
- char* ptr = NULL;
- ASSERT(f);
- if(!str)
- return OBJ_BAD_ARGUMENT;
- *f = (float)strtod(str, &ptr);
- if(ptr == str || *ptr != '\0')
- return OBJ_BAD_ARGUMENT;
- return OBJ_OK;
-}
-
-static FINLINE enum obj_result
-string_to_size_t(const char* str, size_t* i)
-{
- char* ptr = NULL;
- ASSERT(i);
- if(!str)
- return OBJ_BAD_ARGUMENT;
- *i = (size_t)strtol(str, &ptr, 10);
- if(ptr == str || *ptr != '\0')
- return OBJ_BAD_ARGUMENT;
- return OBJ_OK;
-}
-
-static FINLINE void
-flush_groups(struct obj* obj)
-{
- size_t nfaces, ngrps;
- ASSERT(obj);
- if(0 == (nfaces = darray_face_size_get(&obj->faces)))
- return;
- if(0 == (ngrps = darray_named_group_size_get(&obj->groups)))
- return;
- if(obj->igroups_active >= ngrps)
- return;
- FOR_EACH(obj->igroups_active, obj->igroups_active, ngrps) {
- struct named_group* grp;
- grp = darray_named_group_data_get(&obj->groups) + obj->igroups_active;
- ASSERT(grp->iface <= nfaces);
- grp->nfaces = nfaces - grp->iface;
- }
-}
-
-static FINLINE void
-flush_usemtl(struct obj* obj)
-{
- struct named_group* mtl;
- size_t nfaces, ngrps;
- ASSERT(obj);
- if(0 == (nfaces = darray_face_size_get(&obj->faces)))
- return;
- if(0 == (ngrps = darray_named_group_size_get(&obj->usemtls)))
- return;
- mtl = darray_named_group_data_get(&obj->usemtls) + (ngrps - 1);
- ASSERT(mtl->iface <= nfaces);
- mtl->nfaces = nfaces - mtl->iface;
-}
-
-static FINLINE void
-flush_smooth_group(struct obj* obj)
-{
- struct obj_smooth_group* grp;
- size_t nfaces, ngrps;
- ASSERT(obj);
- if(0 == (nfaces = darray_face_size_get(&obj->faces)))
- return;
- if(0 == (ngrps = darray_smooth_group_size_get(&obj->smooth_groups)))
- return;
- grp = darray_smooth_group_data_get(&obj->smooth_groups) + (ngrps - 1);
- ASSERT(grp->face_id <= nfaces);
- grp->faces_count = nfaces - grp->face_id;
-}
-
-static enum obj_result
-parse_floatX
- (char** word_tk,
- const unsigned count_min,
- const unsigned count_max,
- const float default_value,
- struct darray_float* dst)
-{
- unsigned i;
- enum obj_result res = OBJ_OK;
- ASSERT(word_tk && dst && count_min <= count_max);
-
- FOR_EACH(i, 0, count_max) {
- char* real;
- float f;
- if(NULL == (real = strtok_r(NULL, " ", word_tk)))
- break;
- res = string_to_float(real, &f);
- if(res != OBJ_OK)
- goto error;
- if(darray_float_push_back(dst, &f)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- }
- if(i < count_min) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
-
- FOR_EACH(i, i, count_max) {
- if(darray_float_push_back(dst, &default_value)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- }
-
-exit:
- return res;
-error:
- FOR_EACH_REVERSE(i, i, 0)
- darray_float_pop_back(dst);
- goto exit;
-}
-
-static enum obj_result
-parse_face(struct obj* obj, char** word_tk)
-{
- struct obj_face face;
- char* word;
- enum obj_result res = OBJ_OK;
- ASSERT(obj && word_tk);
-
- face.vertex_id = darray_vertex_size_get(&obj->vertices);
- face.vertices_count = 0;
- face.group_id = darray_named_group_size_get(&obj->groups) - 1;
- face.smooth_group_id = darray_smooth_group_size_get(&obj->smooth_groups) - 1;
- face.mtl_id = darray_named_group_size_get(&obj->usemtls) - 1;
-
- /* Note that the obj indexation starts at 1 rather than 0. We thus subtract 1
- * to the vertex attribute indices in order to match the C memory layout */
- while((word = strtok_r(NULL, " ", word_tk))) {
- char* id, *id_tk, *id_pos;
- struct vertex vert = VERTEX_NULL;
-
- /* position index */
- id_pos = strtok_r(word, "/", &id_tk);
- res = string_to_size_t(id_pos, &vert.iposition);
- if(res != OBJ_OK)
- goto error;
- --vert.iposition; /* Match C memory layout */
- if((id = strtok_r(NULL, "/", &id_tk))) {
- id_pos += strlen(id_pos);
- if( id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */
- goto error;
- if(id == id_pos + 2) { /* `//' separator => No tex */
- /* normal index */
- if(OBJ_OK != (res = string_to_size_t(id, &vert.inormal)))
- goto error;
- --vert.inormal; /* Match C memory layout */
- } else {
- /* texcoord index */
- if(OBJ_OK != (res = string_to_size_t(id, &vert.itexcoord)))
- goto error;
- --vert.itexcoord; /* Match C memory latout */
- /* normal index */
- if((id = strtok_r(NULL, "/", &id_tk))) {
- if(OBJ_OK != (res = string_to_size_t(id, &vert.inormal)))
- goto error;
- --vert.inormal; /* Match C memory layout */
- }
- }
- }
- if(darray_vertex_push_back(&obj->vertices, &vert)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- ++face.vertices_count;
- }
- if(darray_face_push_back(&obj->faces, &face)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
-
-exit:
- return res;
-error:
- FOR_EACH_REVERSE(face.vertices_count, face.vertices_count, 0)
- darray_vertex_pop_back(&obj->vertices);
- goto exit;
-}
-
-static enum obj_result
-parse_group(struct obj* obj, char** word_tk)
-{
- char* word;
- size_t ngrps = 0, igrp = 0;
- enum obj_result res = OBJ_OK;
- ASSERT(obj && word_tk);
-
- flush_groups(obj);
-
- word = strtok_r(NULL, " ", word_tk);
- if(!word) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
- #define CALL(Func) { if(Func) { res = OBJ_MEMORY_ERROR; goto error; } }(void)0
- ngrps = igrp = darray_named_group_size_get(&obj->groups);
- obj->igroups_active = ngrps;
- do {
- struct named_group* grp = NULL;
- if(darray_named_group_resize(&obj->groups, igrp + 1)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- grp = darray_named_group_data_get(&obj->groups) + ngrps;
- ++igrp;
- if(str_set(&grp->name, word)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- grp->iface = darray_face_size_get(&obj->faces);
- grp->nfaces = 0;
- } while((word = strtok_r(NULL, " ", word_tk)));
-
-exit:
- return res;
-error:
- if(igrp != ngrps)
- CHECK(darray_named_group_resize(&obj->groups, ngrps), 0);
- goto exit;
-}
-
-static enum obj_result
-parse_smooth_group(struct obj* obj, char** word_tk)
-{
- char* word;
- struct obj_smooth_group grp;
- enum obj_result res;
- size_t i;
- ASSERT(obj && word_tk);
-
- flush_smooth_group(obj);
-
- word = strtok_r(NULL, " ", word_tk);
- if(!strcmp(word, "off")) {
- grp.is_smoothed = 0;
- } else if(!strcmp(word, "on")) {
- grp.is_smoothed = 1;
- } else {
- res = string_to_size_t(word, &i);
- if(res != OBJ_OK)
- return res;
- grp.is_smoothed = i != 0;
- }
- grp.face_id = darray_face_size_get(&obj->faces);
- grp.faces_count = 0;
-
- if(darray_smooth_group_push_back(&obj->smooth_groups, &grp))
- return OBJ_MEMORY_ERROR;
-
- return OBJ_OK;
-}
-
-static enum obj_result
-parse_mtllib(struct obj* obj, char** word_tk)
-{
- char* word;
- size_t imtllib = 0;
- size_t nmtllibs = 0;
- enum obj_result res = OBJ_OK;
- ASSERT(obj && word_tk);
-
- word = strtok_r(NULL, " ", word_tk);
- if(!word) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
- nmtllibs = imtllib = darray_mtllib_size_get(&obj->mtllibs);
- do {
- struct str* str;
- if(darray_mtllib_resize(&obj->mtllibs, imtllib + 1)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- str = darray_mtllib_data_get(&obj->mtllibs) + imtllib;
- ++imtllib;
- if(str_set(str, word)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- } while((word = strtok_r(NULL, " ", word_tk)));
-
-exit:
- return res;
-error:
- if(imtllib != nmtllibs)
- CHECK(darray_mtllib_resize(&obj->mtllibs, nmtllibs), 0);
- goto exit;
-}
-
-static enum obj_result
-parse_usemtl(struct obj* obj, char** word_tk)
-{
- char* word;
- struct named_group* mtl = NULL;
- size_t nmtls;
- enum obj_result res = OBJ_OK;
- ASSERT(obj && word_tk);
-
- flush_usemtl(obj);
-
- word= strtok_r(NULL, " ", word_tk);
- if(!word_tk) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
-
- nmtls = darray_named_group_size_get(&obj->usemtls);
- if(darray_named_group_resize(&obj->usemtls, nmtls + 1)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- mtl = darray_named_group_data_get(&obj->usemtls) + nmtls;
- if(str_set(&mtl->name, word)) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- mtl->iface = darray_face_size_get(&obj->faces);
- mtl->nfaces = 0;
-
-exit:
- return res;
-error:
- if(mtl)
- darray_named_group_pop_back(&obj->usemtls);
- goto exit;
-}
-
-static enum obj_result
-parse_file(struct obj* obj, const char* path, char* content)
-{
- char* line, *line_tk;
- unsigned long iline;
- enum obj_result res = OBJ_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(&word_tk, 3, 4, 1.f, &obj->positions);
- } else if(!strcmp(word, "vn")) { /* Vertex normal */
- res = parse_floatX(&word_tk, 3, 3, 0.f, &obj->normals);
- } else if(!strcmp(word, "vt")) { /* Vertex texture coordinates */
- res = parse_floatX(&word_tk, 1, 3, 0.f, &obj->texcoords);
- } 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 = OBJ_BAD_ARGUMENT;
- }
- if(res != OBJ_OK)
- goto error;
- word = strtok_r(NULL, " ", &word_tk);
- }
- line = strtok_r(NULL, "\n", &line_tk);
- ++iline;
- }
- flush_groups(obj);
- flush_smooth_group(obj);
- flush_usemtl(obj);
-exit:
- return res;
-error:
- fprintf(stderr, "%s:%lu: error: parsing failed\n", path, iline);
- goto exit;
-}
-
-static void
-obj_clear(struct obj* obj)
-{
- ASSERT(obj);
- darray_float_clear(&obj->positions);
- darray_float_clear(&obj->normals);
- darray_float_clear(&obj->texcoords);
- darray_vertex_clear(&obj->vertices);
- darray_face_clear(&obj->faces);
- darray_named_group_clear(&obj->groups);
- darray_named_group_clear(&obj->usemtls);
- darray_smooth_group_clear(&obj->smooth_groups);
- darray_mtllib_clear(&obj->mtllibs);
- obj->igroups_active = 0;
-}
-
-static void
-obj_release(ref_T* ref)
-{
- struct obj* obj = CONTAINER_OF(ref, struct obj, ref);
- ASSERT(ref);
- darray_float_release(&obj->positions);
- darray_float_release(&obj->normals);
- darray_float_release(&obj->texcoords);
- darray_vertex_release(&obj->vertices);
- darray_face_release(&obj->faces);
- darray_named_group_release(&obj->groups);
- darray_named_group_release(&obj->usemtls);
- darray_smooth_group_release(&obj->smooth_groups);
- darray_mtllib_release(&obj->mtllibs);
- MEM_FREE(obj->allocator, obj);
-}
-
-/*******************************************************************************
- * Exported functions
- ******************************************************************************/
-enum obj_result
-obj_create
- (struct mem_allocator* mem_allocator,
- struct obj** obj_out)
-{
- struct mem_allocator* allocator;
- struct obj* obj = NULL;
- enum obj_result res = OBJ_OK;
-
- if(!obj_out) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
- allocator = mem_allocator ? mem_allocator : &mem_default_allocator;
- obj = MEM_CALLOC(allocator, 1, sizeof(struct obj));
- if(!obj) {
- res = OBJ_MEMORY_ERROR;
- goto error;
- }
- obj->allocator = allocator;
- ref_init(&obj->ref);
- darray_float_init(mem_allocator, &obj->positions);
- darray_float_init(mem_allocator, &obj->normals);
- darray_float_init(mem_allocator, &obj->texcoords);
- darray_vertex_init(mem_allocator, &obj->vertices);
- darray_face_init(mem_allocator, &obj->faces);
- darray_named_group_init(mem_allocator, &obj->groups);
- darray_named_group_init(mem_allocator, &obj->usemtls);
- darray_smooth_group_init(mem_allocator, &obj->smooth_groups);
- darray_mtllib_init(mem_allocator, &obj->mtllibs);
-
-exit:
- if(obj_out)
- *obj_out = obj;
- return res;
-error:
- if(obj) {
- OBJ(ref_put(obj));
- obj = NULL;
- }
- goto exit;
-}
-
-enum obj_result
-obj_ref_get(struct obj* obj)
-{
- if(!obj)
- return OBJ_BAD_ARGUMENT;
- ref_get(&obj->ref);
- return OBJ_OK;
-}
-
-enum obj_result
-obj_ref_put(struct obj* obj)
-{
- if(!obj)
- return OBJ_BAD_ARGUMENT;
- ref_put(&obj->ref, obj_release);
- return OBJ_OK;
-}
-
-enum obj_result
-obj_load(struct obj* obj, const char* filename)
-{
- FILE* file = NULL;
- char* file_content = NULL;
- long file_size = 0;
- size_t len = 0;
- enum obj_result res = OBJ_OK;
- (void)len;
-
- if(!obj || !filename) {
- res = OBJ_BAD_ARGUMENT;
- goto error;
- }
-
- file = fopen(filename, "r");
- if(!file) {
- res = OBJ_IO_ERROR;
- 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 = OBJ_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;
-
- obj_clear(obj);
- if(OBJ_OK != (res = parse_file(obj, filename, file_content)))
- goto error;
-
-exit:
- if(file)
- fclose(file);
- if(file_content)
- MEM_FREE(obj->allocator, file_content);
- return res;
-error:
- goto exit;
-}
-
-enum obj_result
-obj_desc_get(struct obj* obj, struct obj_desc* desc)
-{
- if(!obj || !desc)
- return OBJ_BAD_ARGUMENT;
- desc->faces_count = darray_face_size_get(&obj->faces);
- desc->groups_count = darray_named_group_size_get(&obj->groups);
- desc->smooth_groups_count = darray_smooth_group_size_get(&obj->smooth_groups);
- desc->usemtls_count = darray_named_group_size_get(&obj->usemtls);
- desc->mtllibs_count = darray_mtllib_size_get(&obj->mtllibs);
- return OBJ_OK;
-}
-
-enum obj_result
-obj_face_get(const struct obj* obj, const size_t iface, struct obj_face* face)
-{
- if(!obj || !face || iface >= darray_face_size_get(&obj->faces))
- return OBJ_BAD_ARGUMENT;
- *face = darray_face_cdata_get(&obj->faces)[iface];
- return OBJ_OK;
-}
-
-enum obj_result
-obj_group_get(const struct obj* obj, const size_t igroup, struct obj_group* grp)
-{
- const struct named_group* group;
- if(!obj || !grp || igroup >= darray_named_group_size_get(&obj->groups))
- return OBJ_BAD_ARGUMENT;
- group = darray_named_group_cdata_get(&obj->groups) + igroup;
- grp->name = str_cget(&group->name);
- grp->face_id = group->iface;
- grp->faces_count = group->nfaces;
- return OBJ_OK;
-}
-
-enum obj_result
-obj_smooth_group_get
- (const struct obj* obj,
- const size_t ismooth_group,
- struct obj_smooth_group* group)
-{
- if(!obj || !group
- || ismooth_group >= darray_smooth_group_size_get(&obj->smooth_groups))
- return OBJ_BAD_ARGUMENT;
- *group = darray_smooth_group_cdata_get(&obj->smooth_groups)[ismooth_group];
- return OBJ_OK;
-}
-
-enum obj_result
-obj_mtl_get(const struct obj* obj, const size_t imtl, struct obj_mtl* mtl)
-{
- const struct named_group* group;
- if(!obj || !mtl || imtl >= darray_named_group_size_get(&obj->usemtls))
- return OBJ_BAD_ARGUMENT;
- group = darray_named_group_cdata_get(&obj->usemtls) + imtl;
- mtl->name = str_cget(&group->name);
- mtl->face_id = group->iface;
- mtl->faces_count = group->nfaces;
- return OBJ_OK;
-}
-
-enum obj_result
-obj_vertex_get
- (const struct obj* obj, const size_t ivertex, struct obj_vertex* vertex)
-{
- const struct vertex* vert;
- const float* data;
- if(!obj || !vertex || ivertex >= darray_vertex_size_get(&obj->vertices))
- return OBJ_BAD_ARGUMENT;
- vert = darray_vertex_cdata_get(&obj->vertices) + ivertex;
-
- /* Fetch vertex position */
- ASSERT(vert->iposition != VERTEX_NULL.iposition);
- data = darray_float_cdata_get(&obj->positions) + vert->iposition * 4;
- f4_set(vertex->position, data);
- /* Setup vertex texcoord */
- if(vert->itexcoord == VERTEX_NULL.itexcoord) {
- f3_splat(vertex->texcoord, 0.f);
- } else {
- data = darray_float_cdata_get(&obj->texcoords) + vert->itexcoord * 3;
- f3_set(vertex->texcoord, data);
- }
- /* Setup vertex normal */
- if(vert->inormal == VERTEX_NULL.inormal) {
- f3_splat(vertex->normal, 0.f);
- } else {
- data = darray_float_cdata_get(&obj->normals) + vert->inormal * 3;
- f3_set(vertex->normal, data);
- }
- return OBJ_OK;
-}
-
diff --git a/src/obj.h b/src/obj.h
@@ -1,130 +0,0 @@
-#ifndef OBJ_H
-#define OBJ_H
-
-#include <rsys/rsys.h>
-
-#ifdef OBJ_SHARED_BUILD
- #define OBJ_API extern EXPORT_SYM
-#elif defined(OBJ_STATIC_BUILD)
- #define OBJ_API extern LOCAL_SYM
-#else
- #define OBJ_API extern IMPORT_SYM
-#endif
-
-#ifndef NDEBUG
- #define OBJ(Func) ASSERT(obj_##Func == OBJ_OK)
-#else
- #define OBJ(Func) obj_##Func
-#endif
-
-#define OBJ_ID_NONE ((size_t)(-1))
-
-enum obj_result {
- OBJ_BAD_ARGUMENT,
- OBJ_IO_ERROR,
- OBJ_MEMORY_ERROR,
- OBJ_OK
-};
-
-struct obj_desc {
- size_t faces_count;
- size_t groups_count;
- size_t smooth_groups_count;
- size_t usemtls_count;
- size_t mtllibs_count;
-};
-
-struct obj_face {
- size_t vertex_id; /* Index of the first face vertex */
- size_t vertices_count;
- size_t group_id; /* Index of the face group */
- size_t smooth_group_id; /* Index of the face smooth group */
- size_t mtl_id; /* Index of the face material */
-};
-
-struct obj_group {
- const char* name;
- size_t face_id; /* Index of the first group face */
- size_t faces_count;
-};
-
-struct obj_smooth_group {
- char is_smoothed;
- size_t face_id; /* Index of the first smooth group face */
- size_t faces_count;
-};
-
-struct obj_mtl {
- const char* name;
- size_t face_id;
- size_t faces_count;
-};
-
-struct obj_vertex {
- float position[4];
- float normal[3];
- float texcoord[3];
-};
-
-struct obj;
-struct mem_allocator;
-
-BEGIN_DECLS
-
-OBJ_API enum obj_result
-obj_create
- (struct mem_allocator* allocator, /* NULL <=> use default allocator */
- struct obj** obj);
-
-OBJ_API enum obj_result
-obj_ref_get
- (struct obj* obj);
-
-OBJ_API enum obj_result
-obj_ref_put
- (struct obj* obj);
-
-OBJ_API enum obj_result
-obj_load
- (struct obj* obj,
- const char* filename);
-
-OBJ_API enum obj_result
-obj_desc_get
- (struct obj* obj,
- struct obj_desc* desc);
-
-OBJ_API enum obj_result
-obj_face_get
- (const struct obj* obj,
- const size_t face_id,
- struct obj_face* face);
-
-OBJ_API enum obj_result
-obj_group_get
- (const struct obj* obj,
- const size_t group_id,
- struct obj_group* group);
-
-OBJ_API enum obj_result
-obj_smooth_group_get
- (const struct obj* obj,
- const size_t smooth_group_id,
- struct obj_smooth_group* smooth_group);
-
-OBJ_API enum obj_result
-obj_mtl_get
- (const struct obj* obj,
- const size_t mtl_id,
- struct obj_mtl* mtl);
-
-OBJ_API enum obj_result
-obj_vertex_get
- (const struct obj* obj,
- const size_t vertex_id,
- struct obj_vertex* vertex);
-
-END_DECLS
-
-#endif /* OBJ_H */
-
diff --git a/src/test_aw_obj.c b/src/test_aw_obj.c
@@ -0,0 +1,345 @@
+#include "aw.h"
+
+#include <rsys/float3.h>
+#include <rsys/float4.h>
+#include <rsys/mem_allocator.h>
+
+#include <string.h>
+
+static void
+test_plane(struct aw_obj* obj)
+{
+ static const char* plane_obj =
+ "mtllib master.mtl"
+ "\n"
+ "v 0.0000 2.0000 0.0000\n"
+ "v 0.0000 0.0000 0.0000\n"
+ "v 2.0000 0.0000 0.0000\n"
+ "v 2.0000 2.0000 0.0000\n"
+ "vt 0.0000 1.0000 0.0000\n"
+ "vt 0.0000 0.0000 0.0000\n"
+ "vt 1.0000 0.0000 0.0000\n"
+ "vt 1.0000 1.0000 0.0000\n"
+ "# 4 vertices\n"
+ "\n"
+ "usemtl wood\n"
+ "f 1/1 2/2 3/3 4/4\n"
+ "# 1 element\n";
+ float v4[4];
+ struct aw_obj_desc desc;
+ struct aw_obj_face face;
+ struct aw_obj_mtl mtl;
+ struct aw_obj_vertex vertex;
+ FILE* file;
+
+ NCHECK(obj, NULL);
+
+ file = fopen("test_obj_plane.obj", "w");
+ NCHECK(file, NULL);
+ fwrite(plane_obj, sizeof(char), strlen(plane_obj), file);
+ fclose(file);
+
+ 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, "test_obj_plane.obj"), AW_OK);
+
+ CHECK(aw_obj_desc_get(NULL, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_desc_get(obj, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_desc_get(NULL, &desc), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_desc_get(obj, &desc), AW_OK);
+ CHECK(desc.faces_count, 1);
+ CHECK(desc.groups_count, 0);
+ CHECK(desc.smooth_groups_count, 0);
+ CHECK(desc.usemtls_count, 1);
+ CHECK(desc.mtllibs_count, 1);
+
+ CHECK(aw_obj_face_get(NULL, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(obj, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(NULL, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(obj, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(NULL, AW_ID_NONE, &face), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(obj, AW_ID_NONE, &face), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(NULL, 0, &face), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_face_get(obj, 0, &face), AW_OK);
+ CHECK(face.vertex_id, 0);
+ CHECK(face.vertices_count, 4);
+ CHECK(face.group_id, AW_ID_NONE);
+ CHECK(face.smooth_group_id, AW_ID_NONE);
+ CHECK(face.mtl_id, 0);
+
+ CHECK(aw_obj_mtl_get(NULL, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(obj, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(NULL, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(obj, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(NULL, AW_ID_NONE, &mtl), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(obj, AW_ID_NONE, &mtl), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(NULL, 0, &mtl), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_mtl_get(obj, 0, &mtl), AW_OK);
+ CHECK(strcmp(mtl.name, "wood"), 0);
+ CHECK(mtl.face_id, 0);
+ CHECK(mtl.faces_count, 1);
+
+ CHECK(aw_obj_vertex_get(NULL, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(obj, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(NULL, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(obj, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(NULL, AW_ID_NONE, &vertex), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(obj, AW_ID_NONE, &vertex), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_vertex_get(NULL, 0, &vertex), AW_BAD_ARGUMENT);
+
+ CHECK(aw_obj_vertex_get(obj, 0, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.texcoord, f3(v4, 0.f, 1.f, 0.f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 1, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.texcoord, f3(v4, 0.f, 0.f, 0.f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 2, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.texcoord, f3(v4, 1.f, 0.f, 0.f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 3, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.texcoord, f3(v4, 1.f, 1.f, 0.f)), 1);
+}
+
+static void
+test_squares(struct aw_obj* obj)
+{
+ static const char* squares_obj =
+ "v 0.000000 2.000000 0.000000\n"
+ "v 0.000000 0.000000 0.000000\n"
+ "v 2.000000 0.000000 0.000000\n"
+ "v 2.000000 2.000000 0.000000\n"
+ "v 4.000000 0.000000 -1.255298\n"
+ "v 4.000000 2.000000 -1.255298\n"
+ "vn 0.000000 0.000000 1.000000\n"
+ "vn 0.000000 0.000000 1.000000\n"
+ "vn 0.276597 0.000000 0.960986\n"
+ "vn 0.276597 0.000000 0.960986\n"
+ "vn 0.531611 0.000000 0.846988\n"
+ "vn 0.531611 0.000000 0.846988\n"
+ "# 6 vertices\n"
+ "\n"
+ "# 6 normals\n"
+ "\n"
+ "g all\n"
+ "s 1\n"
+ "f 1//1 2//2 3//3 4//4\n"
+ "f 4//4 3//3 5//5 6//6\n"
+ "# 2 elements\n";
+ float v4[4];
+ struct aw_obj_desc desc;
+ struct aw_obj_face face;
+ struct aw_obj_group group;
+ struct aw_obj_smooth_group sgroup;
+ struct aw_obj_mtl mtl;
+ struct aw_obj_vertex vertex;
+ FILE* file;
+
+ NCHECK(obj, NULL);
+
+ file = fopen("test_obj_squares.obj", "w");
+ NCHECK(file, NULL);
+ fwrite(squares_obj, sizeof(char), strlen(squares_obj), file);
+ fclose(file);
+ CHECK(aw_obj_load(obj, "test_obj_squares.obj"), AW_OK);
+
+ CHECK(aw_obj_desc_get(obj, &desc), AW_OK);
+ CHECK(desc.faces_count, 2);
+ CHECK(desc.groups_count, 1);
+ CHECK(desc.smooth_groups_count, 1);
+ CHECK(desc.usemtls_count, 0);
+ CHECK(desc.mtllibs_count, 0);
+
+ CHECK(aw_obj_face_get(obj, 0, &face), AW_OK);
+ CHECK(face.vertex_id, 0);
+ CHECK(face.vertices_count, 4);
+ CHECK(face.group_id, 0);
+ CHECK(face.smooth_group_id, 0);
+ CHECK(face.mtl_id, AW_ID_NONE);
+
+ CHECK(aw_obj_vertex_get(obj, 0, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 1, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 2, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 3, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
+
+ CHECK(aw_obj_face_get(obj, 1, &face), AW_OK);
+ CHECK(face.vertex_id, 4);
+ CHECK(face.vertices_count, 4);
+ CHECK(face.group_id, 0);
+ CHECK(face.smooth_group_id, 0);
+ CHECK(face.mtl_id, AW_ID_NONE);
+
+ CHECK(aw_obj_vertex_get(obj, 4, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 5, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 6, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 4.f, 0.f, -1.255298f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)), 1);
+ CHECK(aw_obj_vertex_get(obj, 7, &vertex), AW_OK);
+ CHECK(f4_eq(vertex.position, f4(v4, 4.f, 2.f, -1.255298f, 1.f)), 1);
+ CHECK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)), 1);
+
+ CHECK(aw_obj_group_get(NULL, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(obj, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(NULL, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(obj, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(NULL, AW_ID_NONE, &group), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(obj, AW_ID_NONE, &group), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(NULL, 0, &group), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_group_get(obj, 0, &group), AW_OK);
+ CHECK(strcmp(group.name, "all"), 0);
+ CHECK(group.face_id, 0);
+ CHECK(group.faces_count, 2);
+
+ CHECK(aw_obj_smooth_group_get(NULL, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(obj, AW_ID_NONE, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(NULL, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(obj, 0, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(NULL, AW_ID_NONE, &sgroup), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(obj, AW_ID_NONE, &sgroup), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(NULL, 0, &sgroup), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_smooth_group_get(obj, 0, &sgroup), AW_OK);
+ CHECK(sgroup.is_smoothed, 1);
+ CHECK(sgroup.face_id, 0);
+ CHECK(sgroup.faces_count, 2);
+
+ CHECK(aw_obj_mtl_get(obj, 0, &mtl), AW_BAD_ARGUMENT);
+}
+
+static void
+test_cube(struct aw_obj* obj)
+{
+ static const char* cube_obj =
+ "# Cube with a different material applied to each of its faces\n"
+ "mtllib master.mtl\n"
+ "v 0.0000 2.0000 2.0000\n"
+ "v 0.0000 0.0000 2.0000\n"
+ "v 2.0000 0.0000 2.0000\n"
+ "v 2.0000 2.0000 2.0000\n"
+ "v 0.0000 2.0000 0.0000\n"
+ "v 0.0000 0.0000 0.0000\n"
+ "v 2.0000 0.0000 0.0000\n"
+ "v 2.0000 2.0000 0.0000\n"
+ "# 8 vertices\n"
+ "g front\n"
+ "usemtl red\n"
+ "f 1 2 3 4\n"
+ "g back\n"
+ "usemtl blue\n"
+ "f 8 7 6 5\n"
+ "g right\n"
+ "usemtl green\n"
+ "f 4 3 7 8\n"
+ "g top\n"
+ "usemtl gold\n"
+ "f 5 1 4 8\n"
+ "g left\n"
+ "usemtl orange\n"
+ "f 5 6 2 1\n"
+ "g bottom\n"
+ "usemtl purple\n"
+ "f 2 6 7 3\n"
+ "# 6 elements\n";
+ const char* group_names[6] =
+ { "front", "back", "right", "top", "left", "bottom" };
+ const char* mtl_names[6] =
+ { "red", "blue", "green", "gold", "orange", "purple" };
+ struct aw_obj_desc desc;
+ FILE* file;
+ size_t i;
+
+ NCHECK(obj, NULL);
+
+ file = fopen("test_obj_cube.obj", "w");
+ NCHECK(file, NULL);
+ fwrite(cube_obj, sizeof(char), strlen(cube_obj), file);
+ fclose(file);
+ CHECK(aw_obj_load(obj, "test_obj_cube.obj"), AW_OK);
+
+ CHECK(aw_obj_desc_get(obj, &desc), AW_OK);
+ CHECK(desc.faces_count, 6);
+ CHECK(desc.groups_count, 6);
+ CHECK(desc.smooth_groups_count, 0);
+ CHECK(desc.usemtls_count, 6);
+ CHECK(desc.mtllibs_count, 1);
+
+ FOR_EACH(i, 0, 6) {
+ struct aw_obj_face face;
+ CHECK(aw_obj_face_get(obj, i, &face), AW_OK);
+ CHECK(face.vertex_id, i*4);
+ CHECK(face.vertices_count, 4);
+ CHECK(face.group_id, i);
+ CHECK(face.smooth_group_id, AW_ID_NONE);
+ CHECK(face.mtl_id, i);
+ }
+
+ FOR_EACH(i, 0, 6) {
+ struct aw_obj_group group;
+ CHECK(aw_obj_group_get(obj, i, &group), AW_OK);
+ CHECK(strcmp(group.name, group_names[i]), 0);
+ CHECK(group.face_id, i);
+ CHECK(group.faces_count, 1);
+ }
+
+ FOR_EACH(i, 0, 6) {
+ struct aw_obj_mtl mtl;
+ CHECK(aw_obj_mtl_get(obj, i, &mtl), AW_OK);
+ CHECK(strcmp(mtl.name, mtl_names[i]), 0);
+ CHECK(mtl.face_id, i);
+ CHECK(mtl.faces_count, 1);
+ }
+}
+
+int
+main(int argc, char** argv)
+{
+ struct mem_allocator allocator;
+ struct aw_obj* obj;
+ int i;
+
+ mem_init_proxy_allocator(&allocator, &mem_default_allocator);
+
+ CHECK(aw_obj_create(NULL, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_create(&allocator, NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_create(NULL, &obj), AW_OK);
+
+ CHECK(aw_obj_ref_get(NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_ref_get(obj), AW_OK);
+ CHECK(aw_obj_ref_put(NULL), AW_BAD_ARGUMENT);
+ CHECK(aw_obj_ref_put(obj), AW_OK);
+ CHECK(aw_obj_ref_put(obj), AW_OK);
+
+ CHECK(aw_obj_create(&allocator, &obj), AW_OK);
+
+ test_plane(obj);
+ test_squares(obj);
+ test_cube(obj);
+ FOR_EACH(i, 1, argc)
+ CHECK(aw_obj_load(obj, argv[i]), AW_OK);
+
+ CHECK(aw_obj_ref_put(obj), AW_OK);
+
+ if(MEM_ALLOCATED_SIZE(&allocator)) {
+ char dump[512];
+ MEM_DUMP(&allocator, dump, sizeof(dump)/sizeof(char));
+ fprintf(stderr, "%s\n", dump);
+ FATAL("Memory leaks\n");
+ }
+ mem_shutdown_proxy_allocator(&allocator);
+ CHECK(mem_allocated_size(), 0);
+ return 0;
+}
+
diff --git a/src/test_obj.c b/src/test_obj.c
@@ -1,345 +0,0 @@
-#include "obj.h"
-
-#include <rsys/float3.h>
-#include <rsys/float4.h>
-#include <rsys/mem_allocator.h>
-
-#include <string.h>
-
-static void
-test_plane(struct obj* obj)
-{
- static const char* plane_obj =
- "mtllib master.mtl"
- "\n"
- "v 0.0000 2.0000 0.0000\n"
- "v 0.0000 0.0000 0.0000\n"
- "v 2.0000 0.0000 0.0000\n"
- "v 2.0000 2.0000 0.0000\n"
- "vt 0.0000 1.0000 0.0000\n"
- "vt 0.0000 0.0000 0.0000\n"
- "vt 1.0000 0.0000 0.0000\n"
- "vt 1.0000 1.0000 0.0000\n"
- "# 4 vertices\n"
- "\n"
- "usemtl wood\n"
- "f 1/1 2/2 3/3 4/4\n"
- "# 1 element\n";
- float v4[4];
- struct obj_desc desc;
- struct obj_face face;
- struct obj_mtl mtl;
- struct obj_vertex vertex;
- FILE* file;
-
- NCHECK(obj, NULL);
-
- file = fopen("test_obj_plane.obj", "w");
- NCHECK(file, NULL);
- fwrite(plane_obj, sizeof(char), strlen(plane_obj), file);
- fclose(file);
-
- CHECK(obj_load(NULL, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_load(obj, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_load(NULL, "test_obj_plane.obj"), OBJ_BAD_ARGUMENT);
- CHECK(obj_load(obj, "none.obj"), OBJ_IO_ERROR);
- CHECK(obj_load(obj, "test_obj_plane.obj"), OBJ_OK);
-
- CHECK(obj_desc_get(NULL, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_desc_get(obj, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_desc_get(NULL, &desc), OBJ_BAD_ARGUMENT);
- CHECK(obj_desc_get(obj, &desc), OBJ_OK);
- CHECK(desc.faces_count, 1);
- CHECK(desc.groups_count, 0);
- CHECK(desc.smooth_groups_count, 0);
- CHECK(desc.usemtls_count, 1);
- CHECK(desc.mtllibs_count, 1);
-
- CHECK(obj_face_get(NULL, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(obj, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(NULL, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(obj, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(NULL, OBJ_ID_NONE, &face), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(obj, OBJ_ID_NONE, &face), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(NULL, 0, &face), OBJ_BAD_ARGUMENT);
- CHECK(obj_face_get(obj, 0, &face), OBJ_OK);
- CHECK(face.vertex_id, 0);
- CHECK(face.vertices_count, 4);
- CHECK(face.group_id, OBJ_ID_NONE);
- CHECK(face.smooth_group_id, OBJ_ID_NONE);
- CHECK(face.mtl_id, 0);
-
- CHECK(obj_mtl_get(NULL, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(obj, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(NULL, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(obj, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(NULL, OBJ_ID_NONE, &mtl), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(obj, OBJ_ID_NONE, &mtl), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(NULL, 0, &mtl), OBJ_BAD_ARGUMENT);
- CHECK(obj_mtl_get(obj, 0, &mtl), OBJ_OK);
- CHECK(strcmp(mtl.name, "wood"), 0);
- CHECK(mtl.face_id, 0);
- CHECK(mtl.faces_count, 1);
-
- CHECK(obj_vertex_get(NULL, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(obj, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(NULL, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(obj, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(NULL, OBJ_ID_NONE, &vertex), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(obj, OBJ_ID_NONE, &vertex), OBJ_BAD_ARGUMENT);
- CHECK(obj_vertex_get(NULL, 0, &vertex), OBJ_BAD_ARGUMENT);
-
- CHECK(obj_vertex_get(obj, 0, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.texcoord, f3(v4, 0.f, 1.f, 0.f)), 1);
- CHECK(obj_vertex_get(obj, 1, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.texcoord, f3(v4, 0.f, 0.f, 0.f)), 1);
- CHECK(obj_vertex_get(obj, 2, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.texcoord, f3(v4, 1.f, 0.f, 0.f)), 1);
- CHECK(obj_vertex_get(obj, 3, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.texcoord, f3(v4, 1.f, 1.f, 0.f)), 1);
-}
-
-static void
-test_squares(struct obj* obj)
-{
- static const char* squares_obj =
- "v 0.000000 2.000000 0.000000\n"
- "v 0.000000 0.000000 0.000000\n"
- "v 2.000000 0.000000 0.000000\n"
- "v 2.000000 2.000000 0.000000\n"
- "v 4.000000 0.000000 -1.255298\n"
- "v 4.000000 2.000000 -1.255298\n"
- "vn 0.000000 0.000000 1.000000\n"
- "vn 0.000000 0.000000 1.000000\n"
- "vn 0.276597 0.000000 0.960986\n"
- "vn 0.276597 0.000000 0.960986\n"
- "vn 0.531611 0.000000 0.846988\n"
- "vn 0.531611 0.000000 0.846988\n"
- "# 6 vertices\n"
- "\n"
- "# 6 normals\n"
- "\n"
- "g all\n"
- "s 1\n"
- "f 1//1 2//2 3//3 4//4\n"
- "f 4//4 3//3 5//5 6//6\n"
- "# 2 elements\n";
- float v4[4];
- struct obj_desc desc;
- struct obj_face face;
- struct obj_group group;
- struct obj_smooth_group sgroup;
- struct obj_mtl mtl;
- struct obj_vertex vertex;
- FILE* file;
-
- NCHECK(obj, NULL);
-
- file = fopen("test_obj_squares.obj", "w");
- NCHECK(file, NULL);
- fwrite(squares_obj, sizeof(char), strlen(squares_obj), file);
- fclose(file);
- CHECK(obj_load(obj, "test_obj_squares.obj"), OBJ_OK);
-
- CHECK(obj_desc_get(obj, &desc), OBJ_OK);
- CHECK(desc.faces_count, 2);
- CHECK(desc.groups_count, 1);
- CHECK(desc.smooth_groups_count, 1);
- CHECK(desc.usemtls_count, 0);
- CHECK(desc.mtllibs_count, 0);
-
- CHECK(obj_face_get(obj, 0, &face), OBJ_OK);
- CHECK(face.vertex_id, 0);
- CHECK(face.vertices_count, 4);
- CHECK(face.group_id, 0);
- CHECK(face.smooth_group_id, 0);
- CHECK(face.mtl_id, OBJ_ID_NONE);
-
- CHECK(obj_vertex_get(obj, 0, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 0.f, 2.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)), 1);
- CHECK(obj_vertex_get(obj, 1, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 0.f, 0.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.f, 0.f, 1.f)), 1);
- CHECK(obj_vertex_get(obj, 2, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
- CHECK(obj_vertex_get(obj, 3, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
-
- CHECK(obj_face_get(obj, 1, &face), OBJ_OK);
- CHECK(face.vertex_id, 4);
- CHECK(face.vertices_count, 4);
- CHECK(face.group_id, 0);
- CHECK(face.smooth_group_id, 0);
- CHECK(face.mtl_id, OBJ_ID_NONE);
-
- CHECK(obj_vertex_get(obj, 4, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 2.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
- CHECK(obj_vertex_get(obj, 5, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 2.f, 0.f, 0.f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.276597f, 0.f, 0.960986f)), 1);
- CHECK(obj_vertex_get(obj, 6, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 4.f, 0.f, -1.255298f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)), 1);
- CHECK(obj_vertex_get(obj, 7, &vertex), OBJ_OK);
- CHECK(f4_eq(vertex.position, f4(v4, 4.f, 2.f, -1.255298f, 1.f)), 1);
- CHECK(f3_eq(vertex.normal, f3(v4, 0.531611f, 0.f, 0.846988f)), 1);
-
- CHECK(obj_group_get(NULL, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(obj, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(NULL, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(obj, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(NULL, OBJ_ID_NONE, &group), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(obj, OBJ_ID_NONE, &group), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(NULL, 0, &group), OBJ_BAD_ARGUMENT);
- CHECK(obj_group_get(obj, 0, &group), OBJ_OK);
- CHECK(strcmp(group.name, "all"), 0);
- CHECK(group.face_id, 0);
- CHECK(group.faces_count, 2);
-
- CHECK(obj_smooth_group_get(NULL, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(obj, OBJ_ID_NONE, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(NULL, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(obj, 0, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(NULL, OBJ_ID_NONE, &sgroup), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(obj, OBJ_ID_NONE, &sgroup), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(NULL, 0, &sgroup), OBJ_BAD_ARGUMENT);
- CHECK(obj_smooth_group_get(obj, 0, &sgroup), OBJ_OK);
- CHECK(sgroup.is_smoothed, 1);
- CHECK(sgroup.face_id, 0);
- CHECK(sgroup.faces_count, 2);
-
- CHECK(obj_mtl_get(obj, 0, &mtl), OBJ_BAD_ARGUMENT);
-}
-
-static void
-test_cube(struct obj* obj)
-{
- static const char* cube_obj =
- "# Cube with a different material applied to each of its faces\n"
- "mtllib master.mtl\n"
- "v 0.0000 2.0000 2.0000\n"
- "v 0.0000 0.0000 2.0000\n"
- "v 2.0000 0.0000 2.0000\n"
- "v 2.0000 2.0000 2.0000\n"
- "v 0.0000 2.0000 0.0000\n"
- "v 0.0000 0.0000 0.0000\n"
- "v 2.0000 0.0000 0.0000\n"
- "v 2.0000 2.0000 0.0000\n"
- "# 8 vertices\n"
- "g front\n"
- "usemtl red\n"
- "f 1 2 3 4\n"
- "g back\n"
- "usemtl blue\n"
- "f 8 7 6 5\n"
- "g right\n"
- "usemtl green\n"
- "f 4 3 7 8\n"
- "g top\n"
- "usemtl gold\n"
- "f 5 1 4 8\n"
- "g left\n"
- "usemtl orange\n"
- "f 5 6 2 1\n"
- "g bottom\n"
- "usemtl purple\n"
- "f 2 6 7 3\n"
- "# 6 elements\n";
- const char* group_names[6] =
- { "front", "back", "right", "top", "left", "bottom" };
- const char* mtl_names[6] =
- { "red", "blue", "green", "gold", "orange", "purple" };
- struct obj_desc desc;
- FILE* file;
- size_t i;
-
- NCHECK(obj, NULL);
-
- file = fopen("test_obj_cube.obj", "w");
- NCHECK(file, NULL);
- fwrite(cube_obj, sizeof(char), strlen(cube_obj), file);
- fclose(file);
- CHECK(obj_load(obj, "test_obj_cube.obj"), OBJ_OK);
-
- CHECK(obj_desc_get(obj, &desc), OBJ_OK);
- CHECK(desc.faces_count, 6);
- CHECK(desc.groups_count, 6);
- CHECK(desc.smooth_groups_count, 0);
- CHECK(desc.usemtls_count, 6);
- CHECK(desc.mtllibs_count, 1);
-
- FOR_EACH(i, 0, 6) {
- struct obj_face face;
- CHECK(obj_face_get(obj, i, &face), OBJ_OK);
- CHECK(face.vertex_id, i*4);
- CHECK(face.vertices_count, 4);
- CHECK(face.group_id, i);
- CHECK(face.smooth_group_id, OBJ_ID_NONE);
- CHECK(face.mtl_id, i);
- }
-
- FOR_EACH(i, 0, 6) {
- struct obj_group group;
- CHECK(obj_group_get(obj, i, &group), OBJ_OK);
- CHECK(strcmp(group.name, group_names[i]), 0);
- CHECK(group.face_id, i);
- CHECK(group.faces_count, 1);
- }
-
- FOR_EACH(i, 0, 6) {
- struct obj_mtl mtl;
- CHECK(obj_mtl_get(obj, i, &mtl), OBJ_OK);
- CHECK(strcmp(mtl.name, mtl_names[i]), 0);
- CHECK(mtl.face_id, i);
- CHECK(mtl.faces_count, 1);
- }
-}
-
-int
-main(int argc, char** argv)
-{
- struct mem_allocator allocator;
- struct obj* obj;
- int i;
-
- mem_init_proxy_allocator(&allocator, &mem_default_allocator);
-
- CHECK(obj_create(NULL, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_create(&allocator, NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_create(NULL, &obj), OBJ_OK);
-
- CHECK(obj_ref_get(NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_ref_get(obj), OBJ_OK);
- CHECK(obj_ref_put(NULL), OBJ_BAD_ARGUMENT);
- CHECK(obj_ref_put(obj), OBJ_OK);
- CHECK(obj_ref_put(obj), OBJ_OK);
-
- CHECK(obj_create(&allocator, &obj), OBJ_OK);
-
- test_plane(obj);
- test_squares(obj);
- test_cube(obj);
- FOR_EACH(i, 1, argc)
- CHECK(obj_load(obj, argv[i]), OBJ_OK);
-
- CHECK(obj_ref_put(obj), OBJ_OK);
-
- if(MEM_ALLOCATED_SIZE(&allocator)) {
- char dump[512];
- MEM_DUMP(&allocator, dump, sizeof(dump)/sizeof(char));
- fprintf(stderr, "%s\n", dump);
- FATAL("Memory leaks\n");
- }
- mem_shutdown_proxy_allocator(&allocator);
- CHECK(mem_allocated_size(), 0);
- return 0;
-}
-