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:
| M | src/aw_c.h | | | 20 | ++++++++++++++++++-- |
| M | src/aw_obj.c | | | 61 | +++++++++++++++++++++++++++++++++++++++---------------------- |
| M | src/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);