1 /*
2 ---------------------------------------------------------------------------
3 Open Asset Import Library (assimp)
4 ---------------------------------------------------------------------------
5 
6 Copyright (c) 2006-2021, assimp team
7 
8 All rights reserved.
9 
10 Redistribution and use of this software in source and binary forms,
11 with or without modification, are permitted provided that the following
12 conditions are met:
13 
14 * Redistributions of source code must retain the above
15 copyright notice, this list of conditions and the
16 following disclaimer.
17 
18 * Redistributions in binary form must reproduce the above
19 copyright notice, this list of conditions and the
20 following disclaimer in the documentation and/or other
21 materials provided with the distribution.
22 
23 * Neither the name of the assimp team, nor the names of its
24 contributors may be used to endorse or promote products
25 derived from this software without specific prior
26 written permission of the assimp team.
27 
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 ---------------------------------------------------------------------------
40 */
41 
42 #include "AbstractImportExportBase.h"
43 #include "SceneDiffer.h"
44 #include "UnitTestPCH.h"
45 #include <assimp/postprocess.h>
46 #include <assimp/scene.h>
47 #include <assimp/Exporter.hpp>
48 #include <assimp/Importer.hpp>
49 
50 using namespace Assimp;
51 
52 static const float VertComponents[24 * 3] = {
53     -0.500000, 0.500000, 0.500000,
54     -0.500000, 0.500000, -0.500000,
55     -0.500000, -0.500000, -0.500000,
56     -0.500000, -0.500000, 0.500000,
57     -0.500000, -0.500000, -0.500000,
58     0.500000, -0.500000, -0.500000,
59     0.500000, -0.500000, 0.500000,
60     -0.500000, -0.500000, 0.500000,
61     -0.500000, 0.500000, -0.500000,
62     0.500000, 0.500000, -0.500000,
63     0.500000, -0.500000, -0.500000,
64     -0.500000, -0.500000, -0.500000,
65     0.500000, 0.500000, 0.500000,
66     0.500000, 0.500000, -0.500000,
67     -0.500000, 0.500000, -0.500000,
68     -0.500000, 0.500000, 0.500000,
69     0.500000, -0.500000, 0.500000,
70     0.500000, 0.500000, 0.500000,
71     -0.500000, 0.500000, 0.500000,
72     -0.500000, -0.500000, 0.500000,
73     0.500000, -0.500000, -0.500000,
74     0.500000, 0.500000, -0.500000,
75     0.500000, 0.500000, 0.500000f,
76     0.500000, -0.500000, 0.500000f
77 };
78 
79 static const char *ObjModel =
80         "o 1\n"
81         "\n"
82         "# Vertex list\n"
83         "\n"
84         "v -0.5 -0.5  0.5\n"
85         "v -0.5 -0.5 -0.5\n"
86         "v -0.5  0.5 -0.5\n"
87         "v -0.5  0.5  0.5\n"
88         "v  0.5 -0.5  0.5\n"
89         "v  0.5 -0.5 -0.5\n"
90         "v  0.5  0.5 -0.5\n"
91         "v  0.5  0.5  0.5\n"
92         "\n"
93         "# Point / Line / Face list\n"
94         "\n"
95         "g Box01\n"
96         "usemtl Default\n"
97         "f 4 3 2 1\n"
98         "f 2 6 5 1\n"
99         "f 3 7 6 2\n"
100         "f 8 7 3 4\n"
101         "f 5 8 4 1\n"
102         "f 6 7 8 5\n"
103         "\n"
104         "# End of file\n";
105 
106 static const char *ObjModel_Issue1111 =
107         "o 1\n"
108         "\n"
109         "# Vertex list\n"
110         "\n"
111         "v -0.5 -0.5  0.5\n"
112         "v -0.5 -0.5 -0.5\n"
113         "v -0.5  0.5 -0.5\n"
114         "\n"
115         "usemtl\n"
116         "f 1 2 3\n"
117         "\n"
118         "# End of file\n";
119 
120 class utObjImportExport : public AbstractImportExportBase {
121 protected:
SetUp()122     void SetUp() override {
123         m_im = new Assimp::Importer;
124     }
125 
TearDown()126     void TearDown() override {
127         delete m_im;
128         m_im = nullptr;
129     }
130 
createScene()131     aiScene *createScene() {
132         aiScene *expScene = new aiScene;
133         expScene->mNumMeshes = 1;
134         expScene->mMeshes = new aiMesh *[1];
135         aiMesh *mesh = new aiMesh;
136         mesh->mName.Set("Box01");
137         mesh->mNumVertices = 24;
138         mesh->mVertices = new aiVector3D[24];
139         ::memcpy(&mesh->mVertices->x, &VertComponents[0], sizeof(float) * 24 * 3);
140         mesh->mNumFaces = 6;
141         mesh->mFaces = new aiFace[mesh->mNumFaces];
142 
143         mesh->mFaces[0].mNumIndices = 4;
144         mesh->mFaces[0].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
145         mesh->mFaces[0].mIndices[0] = 0;
146         mesh->mFaces[0].mIndices[1] = 1;
147         mesh->mFaces[0].mIndices[2] = 2;
148         mesh->mFaces[0].mIndices[3] = 3;
149 
150         mesh->mFaces[1].mNumIndices = 4;
151         mesh->mFaces[1].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
152         mesh->mFaces[1].mIndices[0] = 4;
153         mesh->mFaces[1].mIndices[1] = 5;
154         mesh->mFaces[1].mIndices[2] = 6;
155         mesh->mFaces[1].mIndices[3] = 7;
156 
157         mesh->mFaces[2].mNumIndices = 4;
158         mesh->mFaces[2].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
159         mesh->mFaces[2].mIndices[0] = 8;
160         mesh->mFaces[2].mIndices[1] = 9;
161         mesh->mFaces[2].mIndices[2] = 10;
162         mesh->mFaces[2].mIndices[3] = 11;
163 
164         mesh->mFaces[3].mNumIndices = 4;
165         mesh->mFaces[3].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
166         mesh->mFaces[3].mIndices[0] = 12;
167         mesh->mFaces[3].mIndices[1] = 13;
168         mesh->mFaces[3].mIndices[2] = 14;
169         mesh->mFaces[3].mIndices[3] = 15;
170 
171         mesh->mFaces[4].mNumIndices = 4;
172         mesh->mFaces[4].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
173         mesh->mFaces[4].mIndices[0] = 16;
174         mesh->mFaces[4].mIndices[1] = 17;
175         mesh->mFaces[4].mIndices[2] = 18;
176         mesh->mFaces[4].mIndices[3] = 19;
177 
178         mesh->mFaces[5].mNumIndices = 4;
179         mesh->mFaces[5].mIndices = new unsigned int[mesh->mFaces[0].mNumIndices];
180         mesh->mFaces[5].mIndices[0] = 20;
181         mesh->mFaces[5].mIndices[1] = 21;
182         mesh->mFaces[5].mIndices[2] = 22;
183         mesh->mFaces[5].mIndices[3] = 23;
184 
185         expScene->mMeshes[0] = mesh;
186 
187         expScene->mNumMaterials = 1;
188         expScene->mMaterials = new aiMaterial *[expScene->mNumMaterials];
189 
190         return expScene;
191     }
192 
importerTest()193     bool importerTest() override {
194         ::Assimp::Importer importer;
195         const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure);
196         return nullptr != scene;
197     }
198 
199 #ifndef ASSIMP_BUILD_NO_EXPORT
200 
exporterTest()201     bool exporterTest() override {
202         ::Assimp::Importer importer;
203         ::Assimp::Exporter exporter;
204         const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/spider.obj", aiProcess_ValidateDataStructure);
205         EXPECT_NE(nullptr, scene);
206         EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_out.obj"));
207         EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "objnomtl", ASSIMP_TEST_MODELS_DIR "/OBJ/spider_nomtl_out.obj"));
208 
209         return true;
210     }
211 
212 #endif // ASSIMP_BUILD_NO_EXPORT
213 
214 protected:
215     ::Assimp::Importer *m_im;
216     aiScene *m_expectedScene;
217 };
218 
TEST_F(utObjImportExport,importObjFromFileTest)219 TEST_F(utObjImportExport, importObjFromFileTest) {
220     EXPECT_TRUE(importerTest());
221 }
222 
223 #ifndef ASSIMP_BUILD_NO_EXPORT
224 
TEST_F(utObjImportExport,exportObjFromFileTest)225 TEST_F(utObjImportExport, exportObjFromFileTest) {
226     EXPECT_TRUE(exporterTest());
227 }
228 
229 #endif // ASSIMP_BUILD_NO_EXPORT
230 
TEST_F(utObjImportExport,obj_import_test)231 TEST_F(utObjImportExport, obj_import_test) {
232     const aiScene *scene = m_im->ReadFileFromMemory((void *)ObjModel, strlen(ObjModel), 0);
233     aiScene *expected = createScene();
234     EXPECT_NE(nullptr, scene);
235 
236     SceneDiffer differ;
237     EXPECT_TRUE(differ.isEqual(expected, scene));
238     differ.showReport();
239 
240     m_im->FreeScene();
241     for (unsigned int i = 0; i < expected->mNumMeshes; ++i) {
242         delete expected->mMeshes[i];
243     }
244     delete[] expected->mMeshes;
245     expected->mMeshes = nullptr;
246     delete[] expected->mMaterials;
247     expected->mMaterials = nullptr;
248     delete expected;
249 }
250 
TEST_F(utObjImportExport,issue1111_no_mat_name_Test)251 TEST_F(utObjImportExport, issue1111_no_mat_name_Test) {
252     const aiScene *scene = m_im->ReadFileFromMemory((void *)ObjModel_Issue1111, strlen(ObjModel_Issue1111), 0);
253     EXPECT_NE(nullptr, scene);
254 }
255 
TEST_F(utObjImportExport,issue809_vertex_color_Test)256 TEST_F(utObjImportExport, issue809_vertex_color_Test) {
257     ::Assimp::Importer importer;
258     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/cube_with_vertexcolors.obj", aiProcess_ValidateDataStructure);
259     EXPECT_NE(nullptr, scene);
260 
261 #ifndef ASSIMP_BUILD_NO_EXPORT
262     ::Assimp::Exporter exporter;
263     EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/OBJ/test_out.obj"));
264 #endif // ASSIMP_BUILD_NO_EXPORT
265 }
266 
TEST_F(utObjImportExport,issue1923_vertex_color_Test)267 TEST_F(utObjImportExport, issue1923_vertex_color_Test) {
268     ::Assimp::Importer importer;
269     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/cube_with_vertexcolors_uni.obj", aiProcess_ValidateDataStructure);
270     EXPECT_NE(nullptr, scene);
271 
272     scene = importer.GetOrphanedScene();
273 
274 #ifndef ASSIMP_BUILD_NO_EXPORT
275     ::Assimp::Exporter exporter;
276     const aiExportDataBlob *blob = exporter.ExportToBlob(scene, "obj");
277     EXPECT_NE(nullptr, blob);
278 
279     const aiScene *sceneReImport = importer.ReadFileFromMemory(blob->data, blob->size, aiProcess_ValidateDataStructure);
280     EXPECT_NE(nullptr, scene);
281 
282     SceneDiffer differ;
283     EXPECT_TRUE(differ.isEqual(scene, sceneReImport));
284 #endif // ASSIMP_BUILD_NO_EXPORT
285 
286     delete scene;
287 }
288 
TEST_F(utObjImportExport,issue1453_segfault)289 TEST_F(utObjImportExport, issue1453_segfault) {
290     static const char *curObjModel =
291             "v  0.0  0.0  0.0\n"
292             "v  0.0  0.0  1.0\n"
293             "v  0.0  1.0  0.0\n"
294             "v  0.0  1.0  1.0\n"
295             "v  1.0  0.0  0.0\n"
296             "v  1.0  0.0  1.0\n"
297             "v  1.0  1.0  0.0\n"
298             "v  1.0  1.0  1.0\nB";
299 
300     Assimp::Importer myimporter;
301     const aiScene *scene = myimporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), aiProcess_ValidateDataStructure);
302     EXPECT_EQ(nullptr, scene);
303 }
304 
TEST_F(utObjImportExport,relative_indices_Test)305 TEST_F(utObjImportExport, relative_indices_Test) {
306     static const char *curObjModel =
307             "v -0.500000 0.000000 0.400000\n"
308             "v -0.500000 0.000000 -0.800000\n"
309             "v -0.500000 1.000000 -0.800000\n"
310             "v -0.500000 1.000000 0.400000\n"
311             "f -4 -3 -2 -1\nB";
312 
313     Assimp::Importer myimporter;
314     const aiScene *scene = myimporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), aiProcess_ValidateDataStructure);
315     EXPECT_NE(nullptr, scene);
316 
317     EXPECT_EQ(scene->mNumMeshes, 1U);
318     const aiMesh *mesh = scene->mMeshes[0];
319     EXPECT_EQ(mesh->mNumVertices, 4U);
320     EXPECT_EQ(mesh->mNumFaces, 1U);
321     const aiFace face = mesh->mFaces[0];
322     EXPECT_EQ(face.mNumIndices, 4U);
323     for (unsigned int i = 0; i < face.mNumIndices; ++i) {
324         EXPECT_EQ(face.mIndices[i], i);
325     }
326 }
327 
TEST_F(utObjImportExport,homogeneous_coordinates_Test)328 TEST_F(utObjImportExport, homogeneous_coordinates_Test) {
329     static const char *curObjModel =
330             "v -0.500000 0.000000 0.400000 0.50000\n"
331             "v -0.500000 0.000000 -0.800000 1.00000\n"
332             "v 0.500000 1.000000 -0.800000 0.5000\n"
333             "f 1 2 3\nB";
334 
335     Assimp::Importer myimporter;
336     const aiScene *scene = myimporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), aiProcess_ValidateDataStructure);
337     EXPECT_NE(nullptr, scene);
338 
339     EXPECT_EQ(scene->mNumMeshes, 1U);
340     const aiMesh *mesh = scene->mMeshes[0];
341     EXPECT_EQ(mesh->mNumVertices, 3U);
342     EXPECT_EQ(mesh->mNumFaces, 1U);
343     const aiFace face = mesh->mFaces[0];
344     EXPECT_EQ(face.mNumIndices, 3U);
345     const aiVector3D vertice = mesh->mVertices[0];
346     EXPECT_EQ(vertice.x, -1.0f);
347     EXPECT_EQ(vertice.y, 0.0f);
348     EXPECT_EQ(vertice.z, 0.8f);
349 }
350 
TEST_F(utObjImportExport,homogeneous_coordinates_divide_by_zero_Test)351 TEST_F(utObjImportExport, homogeneous_coordinates_divide_by_zero_Test) {
352     static const char *curObjModel =
353             "v -0.500000 0.000000 0.400000 0.\n"
354             "v -0.500000 0.000000 -0.800000 1.00000\n"
355             "v 0.500000 1.000000 -0.800000 0.5000\n"
356             "f 1 2 3\nB";
357 
358     Assimp::Importer myimporter;
359     const aiScene *scene = myimporter.ReadFileFromMemory(curObjModel, std::strlen(curObjModel), aiProcess_ValidateDataStructure);
360     EXPECT_EQ(nullptr, scene);
361 }
362 
363 TEST_F(utObjImportExport, 0based_array_Test) {
364     static const char *curObjModel =
365             "v -0.500000 0.000000 0.400000\n"
366             "v -0.500000 0.000000 -0.800000\n"
367             "v -0.500000 1.000000 -0.800000\n"
368             "f 0 1 2\nB";
369 
370     Assimp::Importer myImporter;
371     const aiScene *scene = myImporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), 0);
372     EXPECT_EQ(nullptr, scene);
373 }
374 
TEST_F(utObjImportExport,invalid_normals_uvs)375 TEST_F(utObjImportExport, invalid_normals_uvs) {
376     static const char *curObjModel =
377             "v -0.500000 0.000000 0.400000\n"
378             "v -0.500000 0.000000 -0.800000\n"
379             "v -0.500000 1.000000 -0.800000\n"
380             "vt 0 0\n"
381             "vn 0 1 0\n"
382             "f 1/1/1 1/1/1 2/2/2\nB";
383 
384     Assimp::Importer myImporter;
385     const aiScene *scene = myImporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), 0);
386     EXPECT_NE(nullptr, scene);
387 }
388 
TEST_F(utObjImportExport,no_vt_just_vns)389 TEST_F(utObjImportExport, no_vt_just_vns) {
390     static const char *curObjModel =
391             "v 0 0 0\n"
392             "v 0 0 0\n"
393             "v 0 0 0\n"
394             "v 0 0 0\n"
395             "v 0 0 0\n"
396             "v 0 0 0\n"
397             "v 0 0 0\n"
398             "v 0 0 0\n"
399             "v 0 0 0\n"
400             "v 0 0 0\n"
401             "v 10 0 0\n"
402             "v 0 10 0\n"
403             "vn 0 0 1\n"
404             "vn 0 0 1\n"
405             "vn 0 0 1\n"
406             "vn 0 0 1\n"
407             "vn 0 0 1\n"
408             "vn 0 0 1\n"
409             "vn 0 0 1\n"
410             "vn 0 0 1\n"
411             "vn 0 0 1\n"
412             "vn 0 0 1\n"
413             "vn 0 0 1\n"
414             "vn 0 0 1\n"
415             "f 10/10 11/11 12/12\n";
416 
417     Assimp::Importer myImporter;
418     const aiScene *scene = myImporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), 0);
419     EXPECT_NE(nullptr, scene);
420 }
421 
TEST_F(utObjImportExport,mtllib_after_g)422 TEST_F(utObjImportExport, mtllib_after_g) {
423     ::Assimp::Importer importer;
424     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/cube_mtllib_after_g.obj", aiProcess_ValidateDataStructure);
425     ASSERT_NE(nullptr, scene);
426 
427     EXPECT_EQ(scene->mNumMeshes, 1U);
428     const aiMesh *mesh = scene->mMeshes[0];
429     const aiMaterial *mat = scene->mMaterials[mesh->mMaterialIndex];
430     aiString name;
431     ASSERT_EQ(aiReturn_SUCCESS, mat->Get(AI_MATKEY_NAME, name));
432     EXPECT_STREQ("MyMaterial", name.C_Str());
433 }
434 
TEST_F(utObjImportExport,import_point_cloud)435 TEST_F(utObjImportExport, import_point_cloud) {
436     ::Assimp::Importer importer;
437     const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/point_cloud.obj", 0);
438     ASSERT_NE(nullptr, scene);
439 }
440 
TEST_F(utObjImportExport,import_without_linend)441 TEST_F(utObjImportExport, import_without_linend) {
442     Assimp::Importer myImporter;
443     const aiScene *scene = myImporter.ReadFile(ASSIMP_TEST_MODELS_DIR "/OBJ/box_without_lineending.obj", 0);
444     ASSERT_NE(nullptr, scene);
445 }
446 
TEST_F(utObjImportExport,import_with_line_continuations)447 TEST_F(utObjImportExport, import_with_line_continuations) {
448     static const char *curObjModel =
449             "v -0.5 -0.5 0.5\n"
450             "v -0.5 \\\n"
451             "  -0.5 -0.5\n"
452             "v -0.5 \\\n"
453             "   0.5 \\\n"
454             "   -0.5\n"
455             "f 1 2 3\n";
456 
457     Assimp::Importer myImporter;
458     const aiScene *scene = myImporter.ReadFileFromMemory(curObjModel, strlen(curObjModel), 0);
459     EXPECT_NE(nullptr, scene);
460 
461     EXPECT_EQ(scene->mNumMeshes, 1U);
462     EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 3U);
463     EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 1U);
464 
465     auto vertices = scene->mMeshes[0]->mVertices;
466     const float threshold = 0.0001f;
467 
468     EXPECT_NEAR(vertices[0].x, -0.5f, threshold);
469     EXPECT_NEAR(vertices[0].y, -0.5f, threshold);
470     EXPECT_NEAR(vertices[0].z, 0.5f, threshold);
471 
472     EXPECT_NEAR(vertices[1].x, -0.5f, threshold);
473     EXPECT_NEAR(vertices[1].y, -0.5f, threshold);
474     EXPECT_NEAR(vertices[1].z, -0.5f, threshold);
475 
476     EXPECT_NEAR(vertices[2].x, -0.5f, threshold);
477     EXPECT_NEAR(vertices[2].y, 0.5f, threshold);
478     EXPECT_NEAR(vertices[2].z, -0.5f, threshold);
479 }
480