loader_aw

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

commit 76efa9c8e2723d16201ef21298e1c87974e3d142
parent 35fa61731b78a04536d6783526198eb9ae485a93
Author: vaplv <vaplv@free.fr>
Date:   Sat,  5 Jul 2014 19:27:25 +0200

Add and test the vertex getter

Diffstat:
Msrc/obj.c | 71++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Msrc/obj.h | 12++++++++++++
Msrc/test_obj.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 129 insertions(+), 9 deletions(-)

diff --git a/src/obj.c b/src/obj.c @@ -3,15 +3,21 @@ #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; @@ -239,22 +245,39 @@ parse_face(struct obj* obj, char** word_tk) 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; - struct vertex vert; + char* id, *id_tk, *id_pos; + struct vertex vert = VERTEX_NULL; + /* position index */ - id = strtok_r(word, "/", &id_tk); - res = string_to_size_t(id, &vert.iposition); + id_pos = strtok_r(word, "/", &id_tk); + res = string_to_size_t(id_pos, &vert.iposition); if(res != OBJ_OK) goto error; - /* texcoord index */ + --vert.iposition; /* Match C memory layout */ if((id = strtok_r(NULL, "/", &id_tk))) { - if(*id != '\0' && OBJ_OK != (res = string_to_size_t(id, &vert.itexcoord))) + id_pos += strlen(id_pos); + if( id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */ goto error; - /* normal index */ - if((id = strtok_r(NULL, "/", &id_tk))) { + 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)) { @@ -263,7 +286,6 @@ parse_face(struct obj* obj, char** word_tk) } ++face.vertices_count; } - if(darray_face_push_back(&obj->faces, &face)) { res = OBJ_MEMORY_ERROR; goto error; @@ -686,3 +708,34 @@ obj_mtl_get(const struct obj* obj, const size_t imtl, struct obj_mtl* mtl) 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 @@ -60,6 +60,12 @@ struct obj_mtl { size_t faces_count; }; +struct obj_vertex { + float position[4]; + float normal[3]; + float texcoord[3]; +}; + struct obj; struct mem_allocator; @@ -112,6 +118,12 @@ obj_mtl_get 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_obj.c b/src/test_obj.c @@ -1,5 +1,9 @@ #include "obj.h" + +#include <rsys/float3.h> +#include <rsys/float4.h> #include <rsys/mem_allocator.h> + #include <string.h> static void @@ -21,9 +25,11 @@ test_plane(struct obj* obj) "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); @@ -74,6 +80,27 @@ test_plane(struct obj* obj) 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 @@ -101,11 +128,13 @@ test_squares(struct obj* obj) "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); @@ -130,6 +159,19 @@ test_squares(struct obj* obj) 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); @@ -137,6 +179,19 @@ test_squares(struct obj* obj) 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);