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