Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/io/wavefront_obj/tests/obj_importer_tests.cc')
-rw-r--r--source/blender/io/wavefront_obj/tests/obj_importer_tests.cc491
1 files changed, 491 insertions, 0 deletions
diff --git a/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
new file mode 100644
index 00000000000..ddcfd6176f0
--- /dev/null
+++ b/source/blender/io/wavefront_obj/tests/obj_importer_tests.cc
@@ -0,0 +1,491 @@
+/* SPDX-License-Identifier: Apache-2.0 */
+
+#include <gtest/gtest.h>
+
+#include "testing/testing.h"
+#include "tests/blendfile_loading_base_test.h"
+
+#include "BKE_curve.h"
+#include "BKE_customdata.h"
+#include "BKE_main.h"
+#include "BKE_object.h"
+#include "BKE_scene.h"
+
+#include "BLI_listbase.h"
+#include "BLI_math_base.h"
+#include "BLI_math_vec_types.hh"
+
+#include "BLO_readfile.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_query.h"
+
+#include "DNA_curve_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_scene_types.h"
+
+#include "MEM_guardedalloc.h"
+
+#include "obj_importer.hh"
+
+namespace blender::io::obj {
+
+struct Expectation {
+ std::string name;
+ short type; /* OB_MESH, ... */
+ int totvert, mesh_totedge_or_curve_endp, mesh_totpoly_or_curve_order,
+ mesh_totloop_or_curve_cyclic;
+ float3 vert_first, vert_last;
+ float3 normal_first;
+ float2 uv_first;
+};
+
+class obj_importer_test : public BlendfileLoadingBaseTest {
+ public:
+ void import_and_check(const char *path,
+ const Expectation *expect,
+ size_t expect_count,
+ int expect_mat_count)
+ {
+ if (!blendfile_load("io_tests/blend_geometry/all_quads.blend")) {
+ ADD_FAILURE();
+ return;
+ }
+
+ OBJImportParams params;
+ params.clamp_size = 0;
+ params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD;
+ params.up_axis = OBJ_AXIS_Y_UP;
+
+ std::string obj_path = blender::tests::flags_test_asset_dir() + "/io_tests/obj/" + path;
+ strncpy(params.filepath, obj_path.c_str(), FILE_MAX - 1);
+ importer_main(bfile->main, bfile->curscene, bfile->cur_view_layer, params);
+
+ depsgraph_create(DAG_EVAL_VIEWPORT);
+
+ const int deg_objects_visibility_flags = DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY |
+ DEG_ITER_OBJECT_FLAG_LINKED_VIA_SET |
+ DEG_ITER_OBJECT_FLAG_VISIBLE |
+ DEG_ITER_OBJECT_FLAG_DUPLI;
+ size_t object_index = 0;
+ DEG_OBJECT_ITER_BEGIN (depsgraph, object, deg_objects_visibility_flags) {
+ if (object_index >= expect_count) {
+ ADD_FAILURE();
+ break;
+ }
+ const Expectation &exp = expect[object_index];
+ ASSERT_STREQ(object->id.name, exp.name.c_str());
+ EXPECT_EQ(object->type, exp.type);
+ EXPECT_V3_NEAR(object->loc, float3(0, 0, 0), 0.0001f);
+ if (strcmp(object->id.name, "OBCube") != 0) {
+ EXPECT_V3_NEAR(object->rot, float3(M_PI_2, 0, 0), 0.0001f);
+ }
+ EXPECT_V3_NEAR(object->scale, float3(1, 1, 1), 0.0001f);
+ if (object->type == OB_MESH || object->type == OB_SURF) {
+ Mesh *mesh = BKE_object_get_evaluated_mesh(object);
+ EXPECT_EQ(mesh->totvert, exp.totvert);
+ EXPECT_EQ(mesh->totedge, exp.mesh_totedge_or_curve_endp);
+ EXPECT_EQ(mesh->totpoly, exp.mesh_totpoly_or_curve_order);
+ EXPECT_EQ(mesh->totloop, exp.mesh_totloop_or_curve_cyclic);
+ EXPECT_V3_NEAR(mesh->mvert[0].co, exp.vert_first, 0.0001f);
+ EXPECT_V3_NEAR(mesh->mvert[mesh->totvert - 1].co, exp.vert_last, 0.0001f);
+ const float3 *lnors = (const float3 *)(CustomData_get_layer(&mesh->ldata, CD_NORMAL));
+ float3 normal_first = lnors != nullptr ? lnors[0] : float3(0, 0, 0);
+ EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f);
+ const MLoopUV *mloopuv = static_cast<const MLoopUV *>(
+ CustomData_get_layer(&mesh->ldata, CD_MLOOPUV));
+ float2 uv_first = mloopuv ? float2(mloopuv->uv) : float2(0, 0);
+ EXPECT_V2_NEAR(uv_first, exp.uv_first, 0.0001f);
+ }
+ if (object->type == OB_CURVES_LEGACY) {
+ Curve *curve = static_cast<Curve *>(DEG_get_evaluated_object(depsgraph, object)->data);
+ int numVerts;
+ float(*vertexCos)[3] = BKE_curve_nurbs_vert_coords_alloc(&curve->nurb, &numVerts);
+ EXPECT_EQ(numVerts, exp.totvert);
+ EXPECT_V3_NEAR(vertexCos[0], exp.vert_first, 0.0001f);
+ EXPECT_V3_NEAR(vertexCos[numVerts - 1], exp.vert_last, 0.0001f);
+ MEM_freeN(vertexCos);
+ const Nurb *nurb = static_cast<const Nurb *>(BLI_findlink(&curve->nurb, 0));
+ int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0;
+ EXPECT_EQ(nurb->orderu, exp.mesh_totpoly_or_curve_order);
+ EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp);
+ // Cyclic flag is not set by the importer yet
+ // int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
+ // EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
+ }
+ ++object_index;
+ }
+ DEG_OBJECT_ITER_END;
+ EXPECT_EQ(object_index, expect_count);
+
+ /* Count number of materials. */
+ int mat_count = 0;
+ LISTBASE_FOREACH (ID *, id, &bfile->main->materials) {
+ ++mat_count;
+ }
+ EXPECT_EQ(mat_count, expect_mat_count);
+ }
+};
+
+TEST_F(obj_importer_test, import_cube)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBNew object",
+ OB_MESH,
+ 8,
+ 12,
+ 6,
+ 24,
+ float3(-1, -1, 1),
+ float3(1, -1, -1),
+ float3(-0.57735f, 0.57735f, -0.57735f)},
+ };
+ import_and_check("cube.obj", expect, std::size(expect), 1);
+}
+
+TEST_F(obj_importer_test, import_suzanne_all_data)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBMonkey",
+ OB_MESH,
+ 505,
+ 1005,
+ 500,
+ 1968,
+ float3(-0.4375f, 0.164062f, 0.765625f),
+ float3(0.4375f, 0.164062f, 0.765625f),
+ float3(-0.6040f, -0.5102f, 0.6122f),
+ float2(0.692094f, 0.40191f)},
+ };
+ import_and_check("suzanne_all_data.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_nurbs)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBNew object",
+ OB_CURVES_LEGACY,
+ 12,
+ 0,
+ 4,
+ 1,
+ float3(0.260472f, -1.477212f, -0.866025f),
+ float3(-1.5f, 2.598076f, 0)},
+ };
+ import_and_check("nurbs.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_nurbs_curves)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBNew object", OB_CURVES_LEGACY, 4, 0, 4, 0, float3(2, -2, 0), float3(-2, -2, 0)},
+ {"OBNurbsCurveDiffWeights",
+ OB_CURVES_LEGACY,
+ 4,
+ 0,
+ 4,
+ 0,
+ float3(6, -2, 0),
+ float3(2, -2, 0)},
+ {"OBNurbsCurveCyclic", OB_CURVES_LEGACY, 7, 0, 4, 1, float3(-2, -2, 0), float3(-6, 2, 0)},
+ {"OBNurbsCurveEndpoint",
+ OB_CURVES_LEGACY,
+ 4,
+ 1,
+ 4,
+ 0,
+ float3(-6, -2, 0),
+ float3(-10, -2, 0)},
+ {"OBCurveDeg3", OB_CURVES_LEGACY, 4, 0, 3, 0, float3(10, -2, 0), float3(6, -2, 0)},
+ };
+ import_and_check("nurbs_curves.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_nurbs_cyclic)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBNew object",
+ OB_CURVES_LEGACY,
+ 31,
+ 0,
+ 4,
+ 1,
+ float3(2.591002f, 0, -0.794829f),
+ float3(3.280729f, 0, 3.043217f)},
+ };
+ import_and_check("nurbs_cyclic.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_nurbs_manual)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBCurve_Uniform_Parm", OB_CURVES_LEGACY, 5, 0, 4, 0, float3(-2, 0, 2), float3(-2, 0, 2)},
+ {"OBCurve_NonUniform_Parm",
+ OB_CURVES_LEGACY,
+ 5,
+ 0,
+ 4,
+ 0,
+ float3(-2, 0, 2),
+ float3(-2, 0, 2)},
+ {"OBCurve_Endpoints", OB_CURVES_LEGACY, 5, 1, 4, 0, float3(-2, 0, 2), float3(-2, 0, 2)},
+ {"OBCurve_Cyclic", OB_CURVES_LEGACY, 7, 0, 4, 1, float3(-2, 0, 2), float3(2, 0, -2)},
+ };
+ import_and_check("nurbs_manual.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_nurbs_mesh)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBTorus Knot",
+ OB_MESH,
+ 108,
+ 108,
+ 0,
+ 0,
+ float3(0.438725f, 1.070313f, 0.433013f),
+ float3(0.625557f, 1.040691f, 0.460328f)},
+ };
+ import_and_check("nurbs_mesh.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_materials)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBNew object", OB_MESH, 8, 12, 6, 24, float3(-1, -1, 1), float3(1, -1, -1)},
+ };
+ import_and_check("materials.obj", expect, std::size(expect), 4);
+}
+
+TEST_F(obj_importer_test, import_faces_invalid_or_with_holes)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBFaceWithHole_BecomesTwoFacesFormingAHole",
+ OB_MESH,
+ 8,
+ 10,
+ 2,
+ 12,
+ float3(-2, 0, -2),
+ float3(1, 0, -1)},
+ {"OBFaceQuadDupSomeVerts_BecomesOneQuadUsing4Verts",
+ OB_MESH,
+ 8,
+ 4,
+ 1,
+ 4,
+ float3(3, 0, -2),
+ float3(6, 0, -1)},
+ {"OBFaceTriDupVert_Becomes1Tri", OB_MESH, 8, 3, 1, 3, float3(-2, 0, 3), float3(1, 0, 4)},
+ {"OBFaceAllVertsDup_BecomesOneOverlappingFaceUsingAllVerts",
+ OB_MESH,
+ 8,
+ 8,
+ 1,
+ 8,
+ float3(3, 0, 3),
+ float3(6, 0, 4)},
+ {"OBFaceAllVerts_BecomesOneOverlappingFaceUsingAllVerts",
+ OB_MESH,
+ 8,
+ 8,
+ 1,
+ 8,
+ float3(8, 0, -2),
+ float3(11, 0, -1)},
+ {"OBFaceJustTwoVerts_IsSkipped", OB_MESH, 8, 0, 0, 0, float3(8, 0, 3), float3(11, 0, 4)},
+ };
+ import_and_check("faces_invalid_or_with_holes.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_invalid_indices)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBQuad",
+ OB_MESH,
+ 4,
+ 3,
+ 1,
+ 3,
+ float3(-2, 0, -2),
+ float3(2, 0, -2),
+ float3(0, 1, 0),
+ float2(0.5f, 0.25f)},
+ };
+ import_and_check("invalid_indices.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_invalid_syntax)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ {"OBObjectWithAReallyLongNameToCheckHowImportHandlesNamesThatAreLon",
+ OB_MESH,
+ 10, /* Note: right now parses some invalid obj syntax as valid vertices. */
+ 3,
+ 1,
+ 3,
+ float3(1, 2, 3),
+ float3(10, 11, 12),
+ float3(0.4082f, -0.8165f, 0.4082f),
+ float2(0, 0)},
+ };
+ import_and_check("invalid_syntax.obj", expect, std::size(expect), 0);
+}
+
+TEST_F(obj_importer_test, import_all_objects)
+{
+ Expectation expect[] = {
+ {"OBCube", OB_MESH, 8, 12, 6, 24, float3(1, 1, -1), float3(-1, 1, 1)},
+ /* .obj file has empty EmptyText and EmptyMesh objects; these are ignored and skipped */
+ {"OBSurfPatch",
+ OB_MESH,
+ 256,
+ 480,
+ 225,
+ 900,
+ float3(12.5f, -2.5f, 0.694444f),
+ float3(13.5f, -1.5f, 0.694444f),
+ float3(-0.3246f, -0.3531f, 0.8775f),
+ float2(0, 0.066667f)},
+ {"OBSurfSphere",
+ OB_MESH,
+ 640,
+ 1248,
+ 608,
+ 2432,
+ float3(11, -2, -1),
+ float3(11, -2, 1),
+ float3(-0.0541f, -0.0541f, -0.9971f),
+ float2(0, 1)},
+ {"OBSmoothCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(4, 1, -1),
+ float3(2, 1, 1),
+ float3(0.5774f, 0.5773f, 0.5774f)},
+ {"OBMaterialCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(28, 1, -1),
+ float3(26, 1, 1),
+ float3(-1, 0, 0)},
+ {"OBSubSurfCube",
+ OB_MESH,
+ 106,
+ 208,
+ 104,
+ 416,
+ float3(24.444445f, 0.444444f, -0.666667f),
+ float3(23.790743f, 0.490725f, -0.816819f),
+ float3(0.1697f, 0.1697f, 0.9708f)},
+ {"OBParticleCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(22, 1, -1),
+ float3(20, 1, 1),
+ float3(0, 0, 1)},
+ {"OBShapeKeyCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(19, 1, -1),
+ float3(17, 1, 1),
+ float3(-0.4082f, -0.4082f, 0.8165f)},
+ {"OBUVImageCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(10, 1, -1),
+ float3(8, 1, 1),
+ float3(0, 0, 1),
+ float2(0.654526f, 0.579873f)},
+ {"OBVGroupCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(16, 1, -1),
+ float3(14, 1, 1),
+ float3(0, 0, 1)},
+ {"OBVColCube", OB_MESH, 8, 13, 7, 26, float3(13, 1, -1), float3(11, 1, 1), float3(0, 0, 1)},
+ {"OBUVCube",
+ OB_MESH,
+ 8,
+ 13,
+ 7,
+ 26,
+ float3(7, 1, -1),
+ float3(5, 1, 1),
+ float3(0, 0, 1),
+ float2(0.654526f, 0.579873f)},
+ {"OBSurface",
+ OB_MESH,
+ 256,
+ 480,
+ 224,
+ 896,
+ float3(7.292893f, -2.707107f, -1),
+ float3(7.525872f, -2.883338f, 1),
+ float3(-0.7071f, -0.7071f, 0),
+ float2(0, 0.142857f)},
+ {"OBText",
+ OB_MESH,
+ 177,
+ 345,
+ 171,
+ 513,
+ float3(1.75f, -9.458f, 0),
+ float3(0.587f, -9.406f, 0),
+ float3(0, 0, 1),
+ float2(0.017544f, 0)},
+ {"OBSurfTorus.001",
+ OB_MESH,
+ 1024,
+ 2048,
+ 1024,
+ 4096,
+ float3(5.34467f, -2.65533f, -0.176777f),
+ float3(5.232792f, -2.411795f, -0.220835f),
+ float3(-0.5042f, -0.5042f, -0.7011f),
+ float2(0, 1)},
+ {"OBNurbsCircle",
+ OB_MESH,
+ 96,
+ 96,
+ 0,
+ 0,
+ float3(3.292893f, -2.707107f, 0),
+ float3(3.369084f, -2.77607f, 0)},
+ {"OBBezierCurve", OB_MESH, 13, 12, 0, 0, float3(-1, -2, 0), float3(1, -2, 0)},
+ {"OBBlankCube", OB_MESH, 8, 13, 7, 26, float3(1, 1, -1), float3(-1, 1, 1), float3(0, 0, 1)},
+ };
+ import_and_check("all_objects.obj", expect, std::size(expect), 7);
+}
+
+} // namespace blender::io::obj