From 0feb2e0b26c521cd6328f89ef8636eb9b94df6a1 Mon Sep 17 00:00:00 2001 From: "Vaclav [WENDYN] Nemec" Date: Mon, 29 Jan 2024 04:28:42 +0100 Subject: [PATCH 1/7] "Triangulate" flag was breaking shape face offsets. --- tinyobj_loader_c.h | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tinyobj_loader_c.h b/tinyobj_loader_c.h index 0cfc6f8..c1625fe 100644 --- a/tinyobj_loader_c.h +++ b/tinyobj_loader_c.h @@ -1647,7 +1647,11 @@ int tinyobj_parse_obj(tinyobj_attrib_t *attrib, tinyobj_shape_t **shapes, } } if (commands[i].type == COMMAND_F) { - face_count++; + if (flags & TINYOBJ_FLAG_TRIANGULATE) { + face_count += commands[i].num_f_num_verts; + } else { + face_count++; + } } } From dc137fde714b22755d0329e65e17154fbf01d2a9 Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sat, 3 Feb 2024 01:52:23 +0100 Subject: [PATCH 2/7] I added test for checking shape offsets after triangulation. --- test/fixtures/shapes-triangulation.obj | 56 ++++++++++++++++++++++++++ test/tinyobj_regression_tests.c | 41 +++++++++++++++++++ test/tinyobj_regression_tests.h | 1 + test/tinyobj_tests.c | 1 + 4 files changed, 99 insertions(+) create mode 100644 test/fixtures/shapes-triangulation.obj diff --git a/test/fixtures/shapes-triangulation.obj b/test/fixtures/shapes-triangulation.obj new file mode 100644 index 0000000..383f193 --- /dev/null +++ b/test/fixtures/shapes-triangulation.obj @@ -0,0 +1,56 @@ +# OBJ File: 'house' +# by WENDYN + +o house +v -1.0000 0.0000 -1.0000 +v 1.0000 0.0000 -1.0000 +v 1.0000 0.0000 1.0000 +v -1.0000 0.0000 1.0000 +v -1.0000 1.0000 -1.0000 +v 1.0000 1.0000 -1.0000 +v 1.0000 1.0000 1.0000 +v -1.0000 1.0000 1.0000 +v 0.0000 2.0000 -1.0000 +v 0.0000 2.0000 1.0000 + +vn 0.0000 -1.0000 0.0000 +vn 0.0000 0.0000 -1.0000 +vn -1.0000 0.0000 0.0000 +vn 0.0000 0.0000 1.0000 +vn 1.0000 0.0000 0.0000 +vn 0.0000 1.0000 0.0000 +vn -0.7071 0.7071 0.0000 +vn 0.7071 0.7071 0.0000 + +s off +g base +f 1//1 2//1 3//1 4//1 + +g facade +f 1//2 2//2 6//2 5//2 +f 5//2 6//2 9//2 + +g left_wall +f 4//3 1//3 5//3 8//3 + +g back_wall +f 3//4 4//4 8//4 7//4 + +g back_roof_wall +f 7//4 8//4 10//4 + +g right_wall +f 2//5 3//5 7//5 6//5 + +g floor +f 5//6 6//6 7//6 +f 5//6 7//6 8//6 + +g left_roof +f 8//7 5//7 9//7 10//7 + +g right_roof +f 6//8 7//8 10//8 9//8 + +# TODO: Remove extra content at the end of the file when +# https://github.com/syoyo/tinyobjloader-c/issues/12 is fixed diff --git a/test/tinyobj_regression_tests.c b/test/tinyobj_regression_tests.c index ba0b985..53591a6 100644 --- a/test/tinyobj_regression_tests.c +++ b/test/tinyobj_regression_tests.c @@ -83,3 +83,44 @@ void test_tinyobj_negative_exponent(void) TEST_CHECK(float_equals(attrib.vertices[2], 2.0e-0f)); } } + +void test_tinyobj_shapes_triangulation(void) +{ + { + const char * filename = "fixtures/shapes-triangulation.obj"; + + tinyobj_shape_t * shape = NULL; + tinyobj_material_t * material = NULL; + tinyobj_attrib_t attrib; + + unsigned long num_shapes; + unsigned long num_materials; + + tinyobj_attrib_init(&attrib); + + int result = tinyobj_parse_obj(&attrib, &shape, &num_shapes, &material, &num_materials, filename, loadFile, NULL, TINYOBJ_FLAG_TRIANGULATE); + + TEST_CHECK(result == TINYOBJ_SUCCESS); + + TEST_CHECK(num_shapes == 9); + + TEST_CHECK(shape[0].face_offset == 0); + TEST_CHECK(shape[0].length == 2); + TEST_CHECK(shape[1].face_offset == 2); + TEST_CHECK(shape[1].length == 3); + TEST_CHECK(shape[2].face_offset == 5); + TEST_CHECK(shape[2].length == 2); + TEST_CHECK(shape[3].face_offset == 7); + TEST_CHECK(shape[3].length == 2); + TEST_CHECK(shape[4].face_offset == 9); + TEST_CHECK(shape[4].length == 1); + TEST_CHECK(shape[5].face_offset == 10); + TEST_CHECK(shape[5].length == 2); + TEST_CHECK(shape[6].face_offset == 12); + TEST_CHECK(shape[6].length == 2); + TEST_CHECK(shape[7].face_offset == 14); + TEST_CHECK(shape[7].length == 2); + TEST_CHECK(shape[8].face_offset == 16); + TEST_CHECK(shape[8].length == 2); + } +} \ No newline at end of file diff --git a/test/tinyobj_regression_tests.h b/test/tinyobj_regression_tests.h index 3861fa3..607574c 100644 --- a/test/tinyobj_regression_tests.h +++ b/test/tinyobj_regression_tests.h @@ -3,5 +3,6 @@ void test_tinyobj_crlf_string(void); void test_tinyobj_negative_exponent(void); +void test_tinyobj_shapes_triangulation(void); #endif diff --git a/test/tinyobj_tests.c b/test/tinyobj_tests.c index 0137ed1..645dae0 100644 --- a/test/tinyobj_tests.c +++ b/test/tinyobj_tests.c @@ -34,6 +34,7 @@ TEST_LIST = { { "crlf_string", test_tinyobj_crlf_string }, { "negative_exponent_issue26", test_tinyobj_negative_exponent }, + { "shapes_triangulation", test_tinyobj_shapes_triangulation }, { 0 } // required by acutest }; From 0e837104494d15c7e99b8cd0322795fc4af334f3 Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sat, 3 Feb 2024 04:21:52 +0100 Subject: [PATCH 3/7] I added an example of working with shapes. --- examples/viewer/viewer.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/examples/viewer/viewer.c b/examples/viewer/viewer.c index e4b7d0e..06170a6 100644 --- a/examples/viewer/viewer.c +++ b/examples/viewer/viewer.c @@ -41,12 +41,13 @@ static DrawObject gDrawObject; static int width = 768; static int height = 768; -static bool use_colors = false; +static enum { COLOR_FROM_NORMALS, COLOR_FROM_MATERIAL, COLOR_FROM_SHAPE, __COLOR_FROM_LAST } color_source = COLOR_FROM_NORMALS; static bool draw_wireframe = true; static const size_t OBJ_SIZE = sizeof(float) * 3 // pos + sizeof(float) * 3 // normal + sizeof(float) * 3 // color (based on normal) + + sizeof(float) * 3 // color (based on shape) + sizeof(float) * 3; // color from material file. static float prevMouseX, prevMouseY; @@ -364,6 +365,26 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], face_offset += (size_t)attrib.face_num_verts[i]; } + for (i = 0; i < num_shapes; i++) + { + /* Get unique color based on shape index */ + float r = (cosf(6.283185f * ((float)i / num_shapes + 0.0f / 3.0f)) + 1.0f) / 2.0f; + float g = (cosf(6.283185f * ((float)i / num_shapes + 2.0f / 3.0f)) + 1.0f) / 2.0f; + float b = (cosf(6.283185f * ((float)i / num_shapes + 1.0f / 3.0f)) + 1.0f) / 2.0f; + unsigned int s; + for (s = 0; s < shapes[i].length; s++) + { + unsigned int f = shapes[i].face_offset + s; + int k; + for(k = 0; k < 3; k++) + { + vb[(3 * f + k) * stride + 12] = r; + vb[(3 * f + k) * stride + 13] = g; + vb[(3 * f + k) * stride + 14] = b; + } + } + } + o.vb = 0; o.numTriangles = 0; if (num_triangles > 0) { @@ -431,7 +452,8 @@ static void keyboardFunc(GLFWwindow* window, int key, int scancode, int action, if (key == GLFW_KEY_Q || key == GLFW_KEY_ESCAPE) glfwSetWindowShouldClose(window, GL_TRUE); - if (key == GLFW_KEY_C) use_colors = !use_colors; + if (key == GLFW_KEY_C && ++color_source >= __COLOR_FROM_LAST) + color_source = COLOR_FROM_NORMALS; if (key == GLFW_KEY_W) draw_wireframe = !draw_wireframe; } } @@ -504,10 +526,10 @@ static void Draw(const DrawObject* draw_object) { glEnableClientState(GL_COLOR_ARRAY); glVertexPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)0); glNormalPointer(GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 3)); - if (use_colors) { - glColorPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 9)); - } else { - glColorPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 6)); + switch (color_source) { + case COLOR_FROM_NORMALS: glColorPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 6)); break; + case COLOR_FROM_MATERIAL: glColorPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 9)); break; + case COLOR_FROM_SHAPE: glColorPointer(3, GL_FLOAT, OBJ_SIZE, (const void*)(sizeof(float) * 12)); break; } glDrawArrays(GL_TRIANGLES, 0, 3 * draw_object->numTriangles); CheckErrors("drawarrays"); From 765967bee89647a484060397c7e0072201103074 Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sat, 3 Feb 2024 04:52:34 +0100 Subject: [PATCH 4/7] I removed extra spaces. --- test/fixtures/shapes-triangulation.obj | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/test/fixtures/shapes-triangulation.obj b/test/fixtures/shapes-triangulation.obj index 383f193..e7a8031 100644 --- a/test/fixtures/shapes-triangulation.obj +++ b/test/fixtures/shapes-triangulation.obj @@ -1,5 +1,5 @@ # OBJ File: 'house' -# by WENDYN +# for tinyobjloader-c project o house v -1.0000 0.0000 -1.0000 @@ -12,7 +12,6 @@ v 1.0000 1.0000 1.0000 v -1.0000 1.0000 1.0000 v 0.0000 2.0000 -1.0000 v 0.0000 2.0000 1.0000 - vn 0.0000 -1.0000 0.0000 vn 0.0000 0.0000 -1.0000 vn -1.0000 0.0000 0.0000 @@ -25,30 +24,22 @@ vn 0.7071 0.7071 0.0000 s off g base f 1//1 2//1 3//1 4//1 - g facade f 1//2 2//2 6//2 5//2 f 5//2 6//2 9//2 - g left_wall f 4//3 1//3 5//3 8//3 - g back_wall f 3//4 4//4 8//4 7//4 - g back_roof_wall f 7//4 8//4 10//4 - g right_wall f 2//5 3//5 7//5 6//5 - g floor f 5//6 6//6 7//6 f 5//6 7//6 8//6 - g left_roof f 8//7 5//7 9//7 10//7 - g right_roof f 6//8 7//8 10//8 9//8 From be2d186f545ed4fddb8444ce1b13d47f562385db Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sun, 4 Feb 2024 02:51:44 +0100 Subject: [PATCH 5/7] I replaced hardcoded Nb of vertices of a face to make it clear where it came from. --- examples/viewer/viewer.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/viewer/viewer.c b/examples/viewer/viewer.c index 06170a6..7d0e6eb 100644 --- a/examples/viewer/viewer.c +++ b/examples/viewer/viewer.c @@ -376,7 +376,7 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], { unsigned int f = shapes[i].face_offset + s; int k; - for(k = 0; k < 3; k++) + for(k = 0; k < attrib.face_num_verts[f]; k++) { vb[(3 * f + k) * stride + 12] = r; vb[(3 * f + k) * stride + 13] = g; From 2ff846a882f19f2fb585efaa818ab67bc3be2399 Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sun, 4 Feb 2024 10:54:52 +0100 Subject: [PATCH 6/7] I switched to `size_t` for indexes since rest of the code is also using `size_t`. --- examples/viewer/viewer.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/examples/viewer/viewer.c b/examples/viewer/viewer.c index 7d0e6eb..5720733 100644 --- a/examples/viewer/viewer.c +++ b/examples/viewer/viewer.c @@ -371,12 +371,12 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], float r = (cosf(6.283185f * ((float)i / num_shapes + 0.0f / 3.0f)) + 1.0f) / 2.0f; float g = (cosf(6.283185f * ((float)i / num_shapes + 2.0f / 3.0f)) + 1.0f) / 2.0f; float b = (cosf(6.283185f * ((float)i / num_shapes + 1.0f / 3.0f)) + 1.0f) / 2.0f; - unsigned int s; - for (s = 0; s < shapes[i].length; s++) + size_t s; + for (s = 0; s < (size_t)shapes[i].length; s++) { - unsigned int f = shapes[i].face_offset + s; - int k; - for(k = 0; k < attrib.face_num_verts[f]; k++) + size_t f = (size_t)shapes[i].face_offset + s; + size_t k; + for(k = 0; k < (size_t)attrib.face_num_verts[f]; k++) { vb[(3 * f + k) * stride + 12] = r; vb[(3 * f + k) * stride + 13] = g; From 805796c38e47cb56886db0602fcc4a3e8829a091 Mon Sep 17 00:00:00 2001 From: wendyn-projects Date: Sun, 4 Feb 2024 11:10:43 +0100 Subject: [PATCH 7/7] Keeping Track of `face_offset` This way it shows how it would be calculated even when not knowing we are working with triangles. --- examples/viewer/viewer.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/examples/viewer/viewer.c b/examples/viewer/viewer.c index 5720733..22b8f04 100644 --- a/examples/viewer/viewer.c +++ b/examples/viewer/viewer.c @@ -365,6 +365,7 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], face_offset += (size_t)attrib.face_num_verts[i]; } + face_offset = 0; for (i = 0; i < num_shapes; i++) { /* Get unique color based on shape index */ @@ -378,10 +379,11 @@ static int LoadObjAndConvert(float bmin[3], float bmax[3], size_t k; for(k = 0; k < (size_t)attrib.face_num_verts[f]; k++) { - vb[(3 * f + k) * stride + 12] = r; - vb[(3 * f + k) * stride + 13] = g; - vb[(3 * f + k) * stride + 14] = b; + vb[(face_offset + k) * stride + 12] = r; + vb[(face_offset + k) * stride + 13] = g; + vb[(face_offset + k) * stride + 14] = b; } + face_offset += k; } }