loader_aw

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

commit ba93a862a2fc5d24d4f338b8bab778b96c1f167b
parent 95e7507b0916f2f766e1440940075cad220b7e6a
Author: vaplv <vaplv@free.fr>
Date:   Thu, 25 Sep 2014 15:50:52 +0200

Add support of negative vertex indexation

Diffstat:
Msrc/aw_c.h | 20++++++++++++++++++--
Msrc/aw_obj.c | 61+++++++++++++++++++++++++++++++++++++++----------------------
Msrc/test_aw_obj.c | 145+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 202 insertions(+), 24 deletions(-)

diff --git a/src/aw_c.h b/src/aw_c.h @@ -32,18 +32,34 @@ string_to_float(const char* str, float* f) } static FINLINE res_T -string_to_size_t(const char* str, size_t* i) +string_to_long(const char* str, long* i) { char* ptr = NULL; ASSERT(i); if(!str) return R_BAD_ARG; - *i = (size_t)strtol(str, &ptr, 10); + *i = strtol(str, &ptr, 10); if(ptr == str || *ptr != '\0') return R_BAD_ARG; return R_OK; } +static FINLINE res_T +string_to_size_t(const char* str, size_t* i) +{ + long l; + res_T res; + ASSERT(i); + + res = string_to_long(str, &l); + if(res != R_OK) + return res; + if(l < 0) + return R_BAD_ARG; + *i = (size_t)l; + return R_OK; +} + extern LOCAL_SYM res_T parse_floatX (float* f, diff --git a/src/aw_obj.c b/src/aw_obj.c @@ -207,12 +207,40 @@ parse_floatX_in_darray } static res_T +string_to_vertex_id + (const char* str, /* Input string */ + const size_t vertices_count, /* Current vertices count for a given attrib */ + size_t* id) /* Computed id */ +{ + long id_long; + res_T res; + + res = string_to_long(str, &id_long); + if(res != R_OK) return res; + + if(id_long > 0) { + /* The obj indexation starts at 1 rather than 0 => subtract 1 to the vertex + * attribute indices in order to match the C memory layout */ + *id = (size_t)(id_long - 1); + } else if(id_long < 0) { + /* One can count vertices back up the list from an element's position in + * the file. In this case the index is negative. For instance, a reference + * number of -1 indicates the vertex immediately above the element */ + *id = vertices_count - (size_t)labs(id_long); + } + if(*id >= vertices_count) + return R_BAD_ARG; + return R_OK; +} + +static res_T parse_face(struct aw_obj* obj, char** word_tk) { struct aw_obj_face face; char* word; res_T res = R_OK; ASSERT(obj && word_tk); + #define CALL(Func) if(R_OK != (res = Func)) goto error face.vertex_id = darray_vertex_size_get(&obj->vertices); face.vertices_count = 0; @@ -220,49 +248,38 @@ parse_face(struct aw_obj* obj, char** word_tk) 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, " \t", word_tk))) { char* id, *id_tk, *id_pos; struct vertex vert = VERTEX_NULL; + const size_t positions_count = darray_float_size_get(&obj->positions) / 4; + const size_t normals_count = darray_float_size_get(&obj->normals) / 3; + const size_t texcoords_count = darray_float_size_get(&obj->texcoords) / 3; /* position index */ id_pos = strtok_r(word, "/", &id_tk); - res = string_to_size_t(id_pos, &vert.iposition); - if(res != R_OK) - goto error; - --vert.iposition; /* Match C memory layout */ + CALL(string_to_vertex_id(id_pos, positions_count, &vert.iposition)); if((id = strtok_r(NULL, "/", &id_tk))) { id_pos += strlen(id_pos); - if( id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */ + if(id > id_pos + 3) /* Unexpected N `/' separators with N > 2 */ goto error; if(id == id_pos + 2) { /* `//' separator => No tex */ /* normal index */ - if(R_OK != (res = string_to_size_t(id, &vert.inormal))) - goto error; - --vert.inormal; /* Match C memory layout */ + CALL(string_to_vertex_id(id, normals_count, &vert.inormal)); } else { /* texcoord index */ - if(R_OK != (res = string_to_size_t(id, &vert.itexcoord))) - goto error; - --vert.itexcoord; /* Match C memory latout */ + CALL(string_to_vertex_id(id, texcoords_count, &vert.itexcoord)); /* normal index */ if((id = strtok_r(NULL, "/", &id_tk))) { - if(R_OK != (res = string_to_size_t(id, &vert.inormal))) - goto error; - --vert.inormal; /* Match C memory layout */ + CALL(string_to_vertex_id(id, normals_count, &vert.inormal)); } } } - res = darray_vertex_push_back(&obj->vertices, &vert); - if(res != R_OK) - goto error; + CALL(darray_vertex_push_back(&obj->vertices, &vert)); ++face.vertices_count; } - res = darray_face_push_back(&obj->faces, &face); - if(res != R_OK) - goto error; + CALL(darray_face_push_back(&obj->faces, &face)); + #undef CALL exit: return res; error: diff --git a/src/test_aw_obj.c b/src/test_aw_obj.c @@ -346,6 +346,150 @@ test_cube(struct aw_obj* obj) fclose(file); } +static void +test_cbox(struct aw_obj* obj) +{ + static const char* cbox_obj = + "mtllib cbox.mtl\n" + "v -1.01 0 0.99\n" + "v 1 0 0.99\n" + "v 1 0 -1.04\n" + "v -0.99 0 -1.04\n" + "g floor\n" + "usemtl floor\n" + "f -4 -3 -2 -1\n" + + "v -1.02 1.99 0.99\n" + "v -1.02 1.99 -1.04\n" + "v 1 1.99 -1.04\n" + "v 1 1.99 0.99\n" + "g ceiling\n" + "usemtl ceiling\n" + "f -4 -3 -2 -1\n" + + "v -0.99 0 -1.04\n" + "v 1 0 -1.04\n" + "v 1 1.99 -1.04\n" + "v -1.02 1.99 -1.04\n" + "g back\n" + "usemtl back\n" + "f -4 -3 -2 -1\n" + + "v 1 0 -1.04\n" + "v 1 0 0.99\n" + "v 1 1.99 0.99\n" + "v 1 1.99 -1.04\n" + "g right\n" + "usemtl right\n" + "f -4 -3 -2 -1\n" + + "v -1.01 0 0.99\n" + "v -0.99 0 -1.04\n" + "v -1.02 1.99 -1.04\n" + "v -1.02 1.99 0.99\n" + "g left\n" + "usemtl left\n" + "f -4 -3 -2 -1\n"; + struct aw_obj_desc desc; + struct aw_obj_face face; + struct aw_obj_vertex vertex; + struct aw_obj_group group; + struct aw_obj_mtl mtl; + float tmp[3]; + FILE* file; + + NCHECK(obj, NULL); + + file = fopen("test_cbox.obj", "w+"); + NCHECK(file, NULL); + fwrite(cbox_obj, sizeof(char), strlen(cbox_obj), file); + CHECK(fseek(file, 0, SEEK_SET), 0); + CHECK(aw_obj_load_stream(obj, file), R_OK); + fclose(file); + + CHECK(aw_obj_desc_get(obj, &desc), R_OK); + CHECK(desc.faces_count, 5); + CHECK(desc.groups_count, 5); + CHECK(desc.smooth_groups_count, 0); + CHECK(desc.usemtls_count, 5); + CHECK(desc.mtllibs_count, 1); + + CHECK(aw_obj_face_get(obj, 0, &face), R_OK); + CHECK(face.vertex_id, 0); + CHECK(face.vertices_count, 4); + CHECK(face.group_id, 0); + CHECK(face.mtl_id, 0); + + CHECK(aw_obj_group_get(obj, 0, &group), R_OK); + CHECK(strcmp(group.name, "floor"), 0); + CHECK(group.face_id, 0); + CHECK(group.faces_count, 1); + + CHECK(aw_obj_mtl_get(obj, 0, &mtl), R_OK); + CHECK(strcmp(mtl.name, "floor"), 0); + CHECK(mtl.face_id, 0); + CHECK(mtl.faces_count, 1); + + CHECK(aw_obj_vertex_get(obj, 0, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.01f, 0.f, 0.99f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 1, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 0.f, 0.99f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 2, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 0.f, -1.04f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 3, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -0.99f, 0.f, -1.04f), 1.e-6f), 1); + + CHECK(aw_obj_face_get(obj, 1, &face), R_OK); + CHECK(face.vertex_id, 4); + CHECK(face.vertices_count, 4); + CHECK(face.group_id, 1); + CHECK(face.mtl_id, 1); + + CHECK(aw_obj_group_get(obj, 1, &group), R_OK); + CHECK(strcmp(group.name, "ceiling"), 0); + CHECK(group.face_id, 1); + CHECK(group.faces_count, 1); + + CHECK(aw_obj_mtl_get(obj, 1, &mtl), R_OK); + CHECK(strcmp(mtl.name, "ceiling"), 0); + CHECK(mtl.face_id, 1); + CHECK(mtl.faces_count, 1); + + CHECK(aw_obj_vertex_get(obj, 4, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, 0.99f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 5, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, -1.04f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 6, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 1.99f, -1.04f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 7, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, 1.f, 1.99f, 0.99f), 1.e-6f), 1); + + CHECK(aw_obj_face_get(obj, 4, &face), R_OK); + CHECK(face.vertex_id, 16); + CHECK(face.vertices_count, 4); + CHECK(face.group_id, 4); + CHECK(face.mtl_id, 4); + + CHECK(aw_obj_group_get(obj, 4, &group), R_OK); + CHECK(strcmp(group.name, "left"), 0); + CHECK(group.face_id, 4); + CHECK(group.faces_count, 1); + + CHECK(aw_obj_mtl_get(obj, 4, &mtl), R_OK); + CHECK(strcmp(mtl.name, "left"), 0); + CHECK(mtl.face_id, 4); + CHECK(mtl.faces_count, 1); + + CHECK(aw_obj_vertex_get(obj, 16, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.01f, 0.f, 0.99f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 17, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -0.99f, 0.f, -1.04f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 18, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, -1.04f), 1.e-6f), 1); + CHECK(aw_obj_vertex_get(obj, 19, &vertex), R_OK); + CHECK(f3_eq_eps(vertex.position, f3(tmp, -1.02f, 1.99f, 0.99f), 1.e-6f), 1); +} + int main(int argc, char** argv) { @@ -370,6 +514,7 @@ main(int argc, char** argv) test_plane(obj); test_squares(obj); test_cube(obj); + test_cbox(obj); FOR_EACH(i, 1, argc) CHECK(aw_obj_load(obj, argv[i]), R_OK);