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 #include "AbstractImportExportBase.h"
42 #include "UnitTestPCH.h"
43
44 #include <assimp/commonMetaData.h>
45 #include <assimp/postprocess.h>
46 #include <assimp/scene.h>
47 #include <assimp/Exporter.hpp>
48 #include <assimp/Importer.hpp>
49 #include <assimp/LogStream.hpp>
50 #include <assimp/DefaultLogger.hpp>
51
52 #include <rapidjson/schema.h>
53
54 #include <array>
55
56 #include <assimp/material.h>
57 #include <assimp/GltfMaterial.h>
58
59 using namespace Assimp;
60
61 class utglTF2ImportExport : public AbstractImportExportBase {
62 public:
importerMatTest(const char * file,bool spec_gloss,std::array<aiTextureMapMode,2> exp_modes={ aiTextureMapMode_Wrap, aiTextureMapMode_Wrap })63 virtual bool importerMatTest(const char *file, bool spec_gloss, std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap }) {
64 Assimp::Importer importer;
65 const aiScene *scene = importer.ReadFile(file, aiProcess_ValidateDataStructure);
66 EXPECT_NE(scene, nullptr);
67 if (!scene) {
68 return false;
69 }
70
71 EXPECT_TRUE(scene->HasMaterials());
72 if (!scene->HasMaterials()) {
73 return false;
74 }
75 const aiMaterial *material = scene->mMaterials[0];
76
77 // This Material should be a PBR
78 aiShadingMode shadingMode;
79 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_SHADING_MODEL, shadingMode));
80 EXPECT_EQ(aiShadingMode_PBR_BRDF, shadingMode);
81
82 // Should import the texture as diffuse and as base color
83 aiString path;
84 std::array<aiTextureMapMode,2> modes;
85 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(aiTextureType_DIFFUSE, 0, &path, nullptr, nullptr,
86 nullptr, nullptr, modes.data()));
87 EXPECT_STREQ(path.C_Str(), "CesiumLogoFlat.png");
88 EXPECT_EQ(exp_modes, modes);
89
90 // Also as Base Color
91 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(aiTextureType_BASE_COLOR, 0, &path, nullptr, nullptr,
92 nullptr, nullptr, modes.data()));
93 EXPECT_STREQ(path.C_Str(), "CesiumLogoFlat.png");
94 EXPECT_EQ(exp_modes, modes);
95
96 // Should have a MetallicFactor (default is 1.0)
97 ai_real metal_factor = ai_real(0.5);
98 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_METALLIC_FACTOR, metal_factor));
99 EXPECT_EQ(ai_real(0.0), metal_factor);
100
101 // And a roughness factor (default is 1.0)
102 ai_real roughness_factor = ai_real(0.5);
103 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_ROUGHNESS_FACTOR, roughness_factor));
104 EXPECT_EQ(ai_real(1.0), roughness_factor);
105
106 aiColor3D spec_color = { 0, 0, 0 };
107 ai_real glossiness = ai_real(0.5);
108 if (spec_gloss) {
109 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
110 constexpr ai_real spec_val(0.20000000298023225); // From the file
111 EXPECT_EQ(spec_val, spec_color.r);
112 EXPECT_EQ(spec_val, spec_color.g);
113 EXPECT_EQ(spec_val, spec_color.b);
114 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
115 EXPECT_EQ(ai_real(1.0), glossiness);
116 } else {
117 EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_COLOR_SPECULAR, spec_color));
118 EXPECT_EQ(aiReturn_FAILURE, material->Get(AI_MATKEY_GLOSSINESS_FACTOR, glossiness));
119 }
120
121 return true;
122 }
123
binaryImporterTest()124 virtual bool binaryImporterTest() {
125 Assimp::Importer importer;
126 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/2CylinderEngine-glTF-Binary/2CylinderEngine.glb",
127 aiProcess_ValidateDataStructure);
128 return nullptr != scene;
129 }
130
131 #ifndef ASSIMP_BUILD_NO_EXPORT
exporterTest()132 virtual bool exporterTest() {
133 Assimp::Importer importer;
134 Assimp::Exporter exporter;
135 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
136 aiProcess_ValidateDataStructure);
137 EXPECT_NE(nullptr, scene);
138 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.gltf"));
139
140 return true;
141 }
142 #endif // ASSIMP_BUILD_NO_EXPORT
143 };
144
TEST_F(utglTF2ImportExport,importglTF2FromFileTest)145 TEST_F(utglTF2ImportExport, importglTF2FromFileTest) {
146 EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", false, {aiTextureMapMode_Mirror, aiTextureMapMode_Clamp}));
147 }
148
TEST_F(utglTF2ImportExport,importBinaryglTF2FromFileTest)149 TEST_F(utglTF2ImportExport, importBinaryglTF2FromFileTest) {
150 EXPECT_TRUE(binaryImporterTest());
151 }
152
TEST_F(utglTF2ImportExport,importglTF2_KHR_materials_pbrSpecularGlossiness)153 TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_pbrSpecularGlossiness) {
154 EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf", true));
155 }
156
VerifyClearCoatScene(const aiScene * scene)157 void VerifyClearCoatScene(const aiScene *scene) {
158 ASSERT_NE(nullptr, scene);
159
160 ASSERT_TRUE(scene->HasMaterials());
161
162 // Find a specific Clearcoat material and check the values
163 const aiString partial_coated("Partial_Coated");
164 bool found_partial_coat = false;
165 for (size_t i = 0; i < scene->mNumMaterials; ++i) {
166 const aiMaterial *material = scene->mMaterials[i];
167 ASSERT_NE(nullptr, material);
168 if (material->GetName() == partial_coated) {
169 found_partial_coat = true;
170
171 ai_real clearcoat_factor(0.0f);
172 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_CLEARCOAT_FACTOR, clearcoat_factor));
173 EXPECT_EQ(ai_real(1.0f), clearcoat_factor);
174
175 ai_real clearcoat_rough_factor(0.0f);
176 EXPECT_EQ(aiReturn_SUCCESS, material->Get(AI_MATKEY_CLEARCOAT_ROUGHNESS_FACTOR, clearcoat_rough_factor));
177 EXPECT_EQ(ai_real(0.03f), clearcoat_rough_factor);
178
179 // Should import the texture as diffuse and as base color
180 aiString path;
181 std::array<aiTextureMapMode, 2> modes;
182 static const std::array<aiTextureMapMode, 2> exp_modes = { aiTextureMapMode_Wrap, aiTextureMapMode_Wrap };
183 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(AI_MATKEY_CLEARCOAT_TEXTURE, &path, nullptr, nullptr,
184 nullptr, nullptr, modes.data()));
185 EXPECT_STREQ(path.C_Str(), "PartialCoating.png");
186 EXPECT_EQ(exp_modes, modes);
187 }
188 }
189 EXPECT_TRUE(found_partial_coat);
190 }
191
TEST_F(utglTF2ImportExport,importglTF2_KHR_materials_clearcoat)192 TEST_F(utglTF2ImportExport, importglTF2_KHR_materials_clearcoat) {
193 Assimp::Importer importer;
194 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/ClearCoat-glTF/ClearCoatTest.gltf", aiProcess_ValidateDataStructure);
195 VerifyClearCoatScene(scene);
196 }
197
198 #ifndef ASSIMP_BUILD_NO_EXPORT
199
TEST_F(utglTF2ImportExport,importglTF2AndExport_KHR_materials_clearcoat)200 TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_clearcoat) {
201 {
202 Assimp::Importer importer;
203 Assimp::Exporter exporter;
204 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/ClearCoat-glTF/ClearCoatTest.gltf", aiProcess_ValidateDataStructure);
205 ASSERT_NE(nullptr, scene);
206 // Export
207 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/ClearCoat-glTF/ClearCoatTest_out.glb"));
208 }
209
210 // And re-import
211 Assimp::Importer importer;
212 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/ClearCoat-glTF/ClearCoatTest_out.glb", aiProcess_ValidateDataStructure);
213 VerifyClearCoatScene(scene);
214 }
215
TEST_F(utglTF2ImportExport,importglTF2AndExport_KHR_materials_pbrSpecularGlossiness)216 TEST_F(utglTF2ImportExport, importglTF2AndExport_KHR_materials_pbrSpecularGlossiness) {
217 Assimp::Importer importer;
218 Assimp::Exporter exporter;
219 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured.gltf",
220 aiProcess_ValidateDataStructure);
221 EXPECT_NE(nullptr, scene);
222 // Export
223 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb"));
224
225 // And re-import
226 EXPECT_TRUE(importerMatTest(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-pbrSpecularGlossiness/BoxTextured_out.glb", true));
227 }
228
TEST_F(utglTF2ImportExport,importglTF2AndExportToOBJ)229 TEST_F(utglTF2ImportExport, importglTF2AndExportToOBJ) {
230 Assimp::Importer importer;
231 Assimp::Exporter exporter;
232 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
233 aiProcess_ValidateDataStructure);
234 EXPECT_NE(nullptr, scene);
235 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured_out.obj"));
236 }
237
TEST_F(utglTF2ImportExport,importglTF2EmbeddedAndExportToOBJ)238 TEST_F(utglTF2ImportExport, importglTF2EmbeddedAndExportToOBJ) {
239 Assimp::Importer importer;
240 Assimp::Exporter exporter;
241 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured.gltf",
242 aiProcess_ValidateDataStructure);
243 EXPECT_NE(nullptr, scene);
244 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "obj", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF-Embedded/BoxTextured_out.obj"));
245 }
246
247 #endif // ASSIMP_BUILD_NO_EXPORT
248
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModePointsWithoutIndices)249 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePointsWithoutIndices) {
250 Assimp::Importer importer;
251 //Points without indices
252 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_00.gltf", aiProcess_ValidateDataStructure);
253 EXPECT_NE(nullptr, scene);
254 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u);
255 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
256 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u);
257 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
258 }
259 }
260
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLinesWithoutIndices)261 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesWithoutIndices) {
262 Assimp::Importer importer;
263 //Lines without indices
264 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_01.gltf", aiProcess_ValidateDataStructure);
265 EXPECT_NE(nullptr, scene);
266 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 8u);
267 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
268 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
269 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i * 2u);
270 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i * 2u + 1u);
271 }
272 }
273
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLinesLoopWithoutIndices)274 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesLoopWithoutIndices) {
275 Assimp::Importer importer;
276 //Lines loop without indices
277 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_02.gltf", aiProcess_ValidateDataStructure);
278 EXPECT_NE(nullptr, scene);
279 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
280
281 std::array<unsigned int, 5> l1 = { { 0u, 1u, 2u, 3u, 0u } };
282 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
283 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
284 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
285 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
286 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1u]);
287 }
288 }
289
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLinesStripWithoutIndices)290 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLinesStripWithoutIndices) {
291 Assimp::Importer importer;
292 //Lines strip without indices
293 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_03.gltf", aiProcess_ValidateDataStructure);
294 EXPECT_NE(nullptr, scene);
295 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 5u);
296
297 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
298 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
299 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 2u);
300 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
301 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], i + 1u);
302 }
303 }
304
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeTrianglesStripWithoutIndices)305 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStripWithoutIndices) {
306 Assimp::Importer importer;
307 //Triangles strip without indices
308 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_04.gltf", aiProcess_ValidateDataStructure);
309 EXPECT_NE(nullptr, scene);
310 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
311 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
312 std::array<unsigned int, 3> f1 = { { 0u, 1u, 2u } };
313 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
314 for (unsigned int i = 0; i < 3; ++i) {
315 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
316 }
317
318 std::array<unsigned int, 3> f2 = { { 2u, 1u, 3u } };
319 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
320 for (size_t i = 0; i < 3; ++i) {
321 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
322 }
323 }
324
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeTrianglesFanWithoutIndices)325 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFanWithoutIndices) {
326 Assimp::Importer importer;
327 //Triangles fan without indices
328 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_05.gltf", aiProcess_ValidateDataStructure);
329 EXPECT_NE(nullptr, scene);
330 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
331 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
332 std::array<unsigned int, 3> f1 = { { 0u, 1u, 2u } };
333 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
334 for (size_t i = 0; i < 3; ++i) {
335 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
336 }
337
338 std::array<unsigned int, 3> f2 = { { 0u, 2u, 3u } };
339 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
340 for (size_t i = 0; i < 3; ++i) {
341 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
342 }
343 }
344
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeTrianglesWithoutIndices)345 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesWithoutIndices) {
346 Assimp::Importer importer;
347 //Triangles without indices
348 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_06.gltf", aiProcess_ValidateDataStructure);
349 EXPECT_NE(nullptr, scene);
350 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
351 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 6u);
352 std::array<unsigned int, 3> f1 = { { 0u, 1u, 2u } };
353 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
354 for (size_t i = 0; i < 3; ++i) {
355 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
356 }
357
358 std::array<unsigned int, 3> f2 = { { 3u, 4u, 5u } };
359 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
360 for (size_t i = 0; i < 3; ++i) {
361 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
362 }
363 }
364
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModePoints)365 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModePoints) {
366 Assimp::Importer importer;
367 //Line loop
368 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_07.gltf", aiProcess_ValidateDataStructure);
369 EXPECT_NE(nullptr, scene);
370 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 1024u);
371 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
372 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mNumIndices, 1u);
373 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], i);
374 }
375 }
376
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLines)377 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLines) {
378 Assimp::Importer importer;
379 //Lines
380 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_08.gltf", aiProcess_ValidateDataStructure);
381 EXPECT_NE(nullptr, scene);
382 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
383 std::array<unsigned int, 5> l1 = { { 0u, 3u, 2u, 1u, 0u } };
384 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
385 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
386 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
387 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]);
388 }
389 }
390
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLineLoop)391 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineLoop) {
392 Assimp::Importer importer;
393 //Line loop
394 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_09.gltf", aiProcess_ValidateDataStructure);
395 EXPECT_NE(nullptr, scene);
396 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
397 std::array<unsigned int, 5> l1 = { { 0, 3u, 2u, 1u, 0u } };
398 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
399 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
400 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
401 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]);
402 }
403 }
404
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeLineStrip)405 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeLineStrip) {
406 Assimp::Importer importer;
407 //Lines Strip
408 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_10.gltf", aiProcess_ValidateDataStructure);
409 EXPECT_NE(nullptr, scene);
410 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
411 std::array<unsigned int, 5> l1 = { { 0u, 3u, 2u, 1u, 0u } };
412 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 2u);
413 for (unsigned int i = 0; i < scene->mMeshes[0]->mNumFaces; ++i) {
414 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[0], l1[i]);
415 EXPECT_EQ(scene->mMeshes[0]->mFaces[i].mIndices[1], l1[i + 1]);
416 }
417 }
418
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeTrianglesStrip)419 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesStrip) {
420 Assimp::Importer importer;
421 //Triangles strip
422 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_11.gltf", aiProcess_ValidateDataStructure);
423 EXPECT_NE(nullptr, scene);
424 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
425 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
426 std::array<unsigned int, 3> f1 = { { 0u, 3u, 1u } };
427 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
428 for (size_t i = 0; i < 3; ++i) {
429 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
430 }
431
432 std::array<unsigned int, 3> f2 = { { 1u, 3u, 2u } };
433 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
434 for (size_t i = 0; i < 3; ++i) {
435 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
436 }
437 }
438
TEST_F(utglTF2ImportExport,importglTF2PrimitiveModeTrianglesFan)439 TEST_F(utglTF2ImportExport, importglTF2PrimitiveModeTrianglesFan) {
440 Assimp::Importer importer;
441 //Triangles fan
442 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Asset-Generator/Mesh_PrimitiveMode/Mesh_PrimitiveMode_12.gltf", aiProcess_ValidateDataStructure);
443 EXPECT_NE(nullptr, scene);
444 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 4u);
445 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 2u);
446 std::array<unsigned int, 3> f1 = { { 0u, 3u, 2u } };
447 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mNumIndices, 3u);
448 for (size_t i = 0; i < 3; ++i) {
449 EXPECT_EQ(scene->mMeshes[0]->mFaces[0].mIndices[i], f1[i]);
450 }
451
452 std::array<unsigned int, 3> f2 = { { 0u, 2u, 1u } };
453 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mNumIndices, 3u);
454 for (size_t i = 0; i < 3; ++i) {
455 EXPECT_EQ(scene->mMeshes[0]->mFaces[1].mIndices[i], f2[i]);
456 }
457 }
458
ReadFile(const char * name)459 std::vector<char> ReadFile(const char *name) {
460 std::vector<char> ret;
461
462 FILE *p = ::fopen(name, "r");
463 if (nullptr == p) {
464 return ret;
465 }
466
467 ::fseek(p, 0, SEEK_END);
468 const size_t size = ::ftell(p);
469 ::fseek(p, 0, SEEK_SET);
470
471 ret.resize(size);
472 const size_t readSize = ::fread(&ret[0], 1, size, p);
473 EXPECT_EQ(readSize, size);
474 ::fclose(p);
475
476 return ret;
477 }
478
TEST_F(utglTF2ImportExport,importglTF2FromMemory)479 TEST_F(utglTF2ImportExport, importglTF2FromMemory) {
480 /*const auto flags = aiProcess_CalcTangentSpace | aiProcess_Triangulate | aiProcess_RemoveComponent |
481 aiProcess_GenSmoothNormals | aiProcess_PreTransformVertices | aiProcess_FixInfacingNormals |
482 aiProcess_FindDegenerates | aiProcess_GenUVCoords | aiProcess_SortByPType;
483 const auto& buff = ReadFile("C:\\Users\\kimkulling\\Downloads\\camel\\camel\\scene.gltf");*/
484 /*const aiScene* Scene = ::aiImportFileFromMemory(&buff[0], buff.size(), flags, ".gltf");
485 EXPECT_EQ( nullptr, Scene );*/
486 }
487
TEST_F(utglTF2ImportExport,bug_import_simple_skin)488 TEST_F(utglTF2ImportExport, bug_import_simple_skin) {
489 Assimp::Importer importer;
490 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/simple_skin/simple_skin.gltf",
491 aiProcess_ValidateDataStructure);
492 EXPECT_NE(nullptr, scene);
493 }
494
TEST_F(utglTF2ImportExport,import_cameras)495 TEST_F(utglTF2ImportExport, import_cameras) {
496 Assimp::Importer importer;
497 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/cameras/Cameras.gltf",
498 aiProcess_ValidateDataStructure);
499 EXPECT_NE(nullptr, scene);
500 }
501
TEST_F(utglTF2ImportExport,incorrect_vertex_arrays)502 TEST_F(utglTF2ImportExport, incorrect_vertex_arrays) {
503 Assimp::Importer importer;
504 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/IncorrectVertexArrays/Cube.gltf",
505 aiProcess_ValidateDataStructure);
506 EXPECT_NE(nullptr, scene);
507 EXPECT_EQ(scene->mMeshes[0]->mNumVertices, 36u);
508 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 12u);
509 EXPECT_EQ(scene->mMeshes[1]->mNumVertices, 35u);
510 EXPECT_EQ(scene->mMeshes[1]->mNumFaces, 11u);
511 EXPECT_EQ(scene->mMeshes[2]->mNumVertices, 36u);
512 EXPECT_EQ(scene->mMeshes[2]->mNumFaces, 18u);
513 EXPECT_EQ(scene->mMeshes[3]->mNumVertices, 35u);
514 EXPECT_EQ(scene->mMeshes[3]->mNumFaces, 17u);
515 EXPECT_EQ(scene->mMeshes[4]->mNumVertices, 36u);
516 EXPECT_EQ(scene->mMeshes[4]->mNumFaces, 12u);
517 EXPECT_EQ(scene->mMeshes[5]->mNumVertices, 35u);
518 EXPECT_EQ(scene->mMeshes[5]->mNumFaces, 11u);
519 EXPECT_EQ(scene->mMeshes[6]->mNumVertices, 36u);
520 EXPECT_EQ(scene->mMeshes[6]->mNumFaces, 18u);
521 EXPECT_EQ(scene->mMeshes[7]->mNumVertices, 35u);
522 EXPECT_EQ(scene->mMeshes[7]->mNumFaces, 17u);
523 }
524
TEST_F(utglTF2ImportExport,texture_transform_test)525 TEST_F(utglTF2ImportExport, texture_transform_test) {
526 Assimp::Importer importer;
527 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/textureTransform/TextureTransformTest.gltf",
528 aiProcess_ValidateDataStructure);
529 EXPECT_NE(nullptr, scene);
530 }
531
532 #ifndef ASSIMP_BUILD_NO_EXPORT
TEST_F(utglTF2ImportExport,exportglTF2FromFileTest)533 TEST_F(utglTF2ImportExport, exportglTF2FromFileTest) {
534 EXPECT_TRUE(exporterTest());
535 }
536
TEST_F(utglTF2ImportExport,crash_in_anim_mesh_destructor)537 TEST_F(utglTF2ImportExport, crash_in_anim_mesh_destructor) {
538 Assimp::Importer importer;
539 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube.gltf",
540 aiProcess_ValidateDataStructure);
541 ASSERT_NE(nullptr, scene);
542 Assimp::Exporter exporter;
543 ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/glTF-Sample-Models/AnimatedMorphCube-glTF/AnimatedMorphCube_out.glTF"));
544 }
545
TEST_F(utglTF2ImportExport,error_string_preserved)546 TEST_F(utglTF2ImportExport, error_string_preserved) {
547 Assimp::Importer importer;
548 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/MissingBin/BoxTextured.gltf",
549 aiProcess_ValidateDataStructure);
550 ASSERT_EQ(nullptr, scene);
551 std::string error = importer.GetErrorString();
552 ASSERT_NE(error.find("BoxTextured0.bin"), std::string::npos) << "Error string should contain an error about missing .bin file";
553 }
554
TEST_F(utglTF2ImportExport,export_bad_accessor_bounds)555 TEST_F(utglTF2ImportExport, export_bad_accessor_bounds) {
556 Assimp::Importer importer;
557 Assimp::Exporter exporter;
558 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites.glb", aiProcess_ValidateDataStructure);
559 ASSERT_NE(scene, nullptr);
560
561 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.glb"));
562 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "gltf2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxWithInfinites-glTF-Binary/BoxWithInfinites_out.gltf"));
563 }
564
TEST_F(utglTF2ImportExport,export_normalized_normals)565 TEST_F(utglTF2ImportExport, export_normalized_normals) {
566 Assimp::Importer importer;
567 Assimp::Exporter exporter;
568 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals.glb", aiProcess_ValidateDataStructure);
569 ASSERT_NE(scene, nullptr);
570 EXPECT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb"));
571
572 // load in again and ensure normal-length normals but no Nan's or Inf's introduced
573 scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxBadNormals-glTF-Binary/BoxBadNormals_out.glb", aiProcess_ValidateDataStructure);
574 for ( auto i = 0u; i < scene->mMeshes[0]->mNumVertices; ++i ) {
575 const auto length = scene->mMeshes[0]->mNormals[i].Length();
576 EXPECT_TRUE(abs(length) < 1e-6 || abs(length - 1) < 1e-6);
577 }
578 }
579
580 #endif // ASSIMP_BUILD_NO_EXPORT
581
TEST_F(utglTF2ImportExport,sceneMetadata)582 TEST_F(utglTF2ImportExport, sceneMetadata) {
583 Assimp::Importer importer;
584 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf",
585 aiProcess_ValidateDataStructure);
586 ASSERT_NE(scene, nullptr);
587 ASSERT_NE(scene->mMetaData, nullptr);
588 {
589 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
590 aiString format;
591 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
592 ASSERT_EQ(strcmp(format.C_Str(), "glTF2 Importer"), 0);
593 }
594 {
595 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
596 aiString version;
597 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
598 ASSERT_EQ(strcmp(version.C_Str(), "2.0"), 0);
599 }
600 {
601 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
602 aiString generator;
603 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
604 ASSERT_EQ(strcmp(generator.C_Str(), "COLLADA2GLTF"), 0);
605 }
606 }
607
TEST_F(utglTF2ImportExport,texcoords)608 TEST_F(utglTF2ImportExport, texcoords) {
609
610 Assimp::Importer importer;
611 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf", aiProcess_ValidateDataStructure);
612 ASSERT_NE(scene, nullptr);
613 ASSERT_TRUE(scene->HasMaterials());
614 const aiMaterial *material = scene->mMaterials[0];
615
616 aiString path;
617 unsigned int uvIndex = 255;
618 aiTextureMapMode modes[2];
619 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(AI_MATKEY_BASE_COLOR_TEXTURE, &path, nullptr, &uvIndex, nullptr, nullptr, modes));
620 EXPECT_STREQ(path.C_Str(), "texture.png");
621 EXPECT_EQ(uvIndex, 0u);
622
623 uvIndex = 255;
624 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &path, nullptr, &uvIndex, nullptr, nullptr, modes));
625 EXPECT_STREQ(path.C_Str(), "texture.png");
626 EXPECT_EQ(uvIndex, 1u);
627 }
628
629 #ifndef ASSIMP_BUILD_NO_EXPORT
630
TEST_F(utglTF2ImportExport,texcoords_export)631 TEST_F(utglTF2ImportExport, texcoords_export) {
632 {
633 Assimp::Importer importer;
634 Assimp::Exporter exporter;
635 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf", aiProcess_ValidateDataStructure);
636 ASSERT_NE(scene, nullptr);
637 ASSERT_EQ(aiReturn_SUCCESS, exporter.Export(scene, "glb2", ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf_out.glb"));
638 }
639
640 Assimp::Importer importer;
641 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTexcoords-glTF/boxTexcoords.gltf", aiProcess_ValidateDataStructure);
642 ASSERT_NE(scene, nullptr);
643
644 ASSERT_TRUE(scene->HasMaterials());
645 const aiMaterial *material = scene->mMaterials[0];
646
647 aiString path;
648 unsigned int uvIndex = 255;
649 aiTextureMapMode modes[2];
650 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(AI_MATKEY_BASE_COLOR_TEXTURE, &path, nullptr, &uvIndex, nullptr, nullptr, modes));
651 EXPECT_STREQ(path.C_Str(), "texture.png");
652 EXPECT_EQ(uvIndex, 0u);
653
654 uvIndex = 255;
655 EXPECT_EQ(aiReturn_SUCCESS, material->GetTexture(AI_MATKEY_GLTF_PBRMETALLICROUGHNESS_METALLICROUGHNESS_TEXTURE, &path, nullptr, &uvIndex, nullptr, nullptr, modes));
656 EXPECT_STREQ(path.C_Str(), "texture.png");
657 EXPECT_EQ(uvIndex, 1u);
658 }
659
660 #endif // ASSIMP_BUILD_NO_EXPORT
TEST_F(utglTF2ImportExport,recursive_nodes)661 TEST_F(utglTF2ImportExport, recursive_nodes) {
662 Assimp::Importer importer;
663 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/RecursiveNodes/RecursiveNodes.gltf", aiProcess_ValidateDataStructure);
664 EXPECT_EQ(nullptr, scene);
665 }
666
TEST_F(utglTF2ImportExport,norootnode_noscene)667 TEST_F(utglTF2ImportExport, norootnode_noscene) {
668 Assimp::Importer importer;
669 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/TestNoRootNode/NoScene.gltf", aiProcess_ValidateDataStructure);
670 ASSERT_EQ(scene, nullptr);
671 }
672
TEST_F(utglTF2ImportExport,norootnode_scenewithoutnodes)673 TEST_F(utglTF2ImportExport, norootnode_scenewithoutnodes) {
674 Assimp::Importer importer;
675 const aiScene* scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/TestNoRootNode/SceneWithoutNodes.gltf", aiProcess_ValidateDataStructure);
676 ASSERT_NE(scene, nullptr);
677 ASSERT_NE(scene->mRootNode, nullptr);
678 }
679
680 // Shall not crash!
TEST_F(utglTF2ImportExport,norootnode_issue_3269)681 TEST_F(utglTF2ImportExport, norootnode_issue_3269) {
682 Assimp::Importer importer;
683 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/issue_3269/texcoord_crash.gltf", aiProcess_ValidateDataStructure);
684 ASSERT_EQ(scene, nullptr);
685 }
686
TEST_F(utglTF2ImportExport,indexOutOfRange)687 TEST_F(utglTF2ImportExport, indexOutOfRange) {
688 // The contents of an asset should not lead to an assert.
689 Assimp::Importer importer;
690
691 struct LogObserver : Assimp::LogStream {
692 bool m_observedWarning = false;
693 void write(const char *message) override {
694 m_observedWarning = m_observedWarning || std::strstr(message, "faces were dropped");
695 }
696 };
697 LogObserver logObserver;
698
699 DefaultLogger::get()->attachStream(&logObserver);
700 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/IndexOutOfRange/IndexOutOfRange.gltf", aiProcess_ValidateDataStructure);
701 ASSERT_NE(scene, nullptr);
702 ASSERT_NE(scene->mRootNode, nullptr);
703 ASSERT_EQ(scene->mNumMeshes, 1u);
704 EXPECT_EQ(scene->mMeshes[0]->mNumFaces, 11u);
705 DefaultLogger::get()->detachStream(&logObserver);
706 EXPECT_TRUE(logObserver.m_observedWarning);
707 }
708
TEST_F(utglTF2ImportExport,allIndicesOutOfRange)709 TEST_F(utglTF2ImportExport, allIndicesOutOfRange) {
710 // The contents of an asset should not lead to an assert.
711 Assimp::Importer importer;
712 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/IndexOutOfRange/AllIndicesOutOfRange.gltf", aiProcess_ValidateDataStructure);
713 ASSERT_EQ(scene, nullptr);
714 std::string error = importer.GetErrorString();
715 ASSERT_NE(error.find("Mesh \"Mesh\" has no faces"), std::string::npos);
716 }
717
718 /////////////////////////////////
719 // Draco decoding
720
TEST_F(utglTF2ImportExport,import_dracoEncoded)721 TEST_F(utglTF2ImportExport, import_dracoEncoded) {
722 Assimp::Importer importer;
723 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/draco/2CylinderEngine.gltf",
724 aiProcess_ValidateDataStructure);
725 #ifndef ASSIMP_ENABLE_DRACO
726 // No draco support, scene should not load
727 ASSERT_EQ(scene, nullptr);
728 #else
729 ASSERT_NE(scene, nullptr);
730 ASSERT_NE(scene->mMetaData, nullptr);
731 {
732 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT));
733 aiString format;
734 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT, format));
735 ASSERT_EQ(strcmp(format.C_Str(), "glTF2 Importer"), 0);
736 }
737 {
738 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_FORMAT_VERSION));
739 aiString version;
740 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_FORMAT_VERSION, version));
741 ASSERT_EQ(strcmp(version.C_Str(), "2.0"), 0);
742 }
743 {
744 ASSERT_TRUE(scene->mMetaData->HasKey(AI_METADATA_SOURCE_GENERATOR));
745 aiString generator;
746 ASSERT_TRUE(scene->mMetaData->Get(AI_METADATA_SOURCE_GENERATOR, generator));
747 ASSERT_EQ(strcmp(generator.C_Str(), "COLLADA2GLTF"), 0);
748 }
749 #endif
750 }
751
TEST_F(utglTF2ImportExport,wrongTypes)752 TEST_F(utglTF2ImportExport, wrongTypes) {
753 // Deliberately broken version of the BoxTextured.gltf asset.
754 using tup_T = std::tuple<std::string, std::string, std::string, std::string>;
755 std::vector<tup_T> wrongTypes = {
756 { "/glTF2/wrongTypes/badArray.gltf", "array", "primitives", "meshes[0]" },
757 { "/glTF2/wrongTypes/badString.gltf", "string", "name", "scenes[0]" },
758 { "/glTF2/wrongTypes/badUint.gltf", "uint", "index", "materials[0]" },
759 { "/glTF2/wrongTypes/badNumber.gltf", "number", "scale", "materials[0]" },
760 { "/glTF2/wrongTypes/badObject.gltf", "object", "pbrMetallicRoughness", "materials[0]" },
761 { "/glTF2/wrongTypes/badExtension.gltf", "object", "KHR_texture_transform", "materials[0]" }
762 };
763 for (const auto& tuple : wrongTypes)
764 {
765 const auto& file = std::get<0>(tuple);
766 const auto& type = std::get<1>(tuple);
767 const auto& member = std::get<2>(tuple);
768 const auto& context = std::get<3>(tuple);
769 Assimp::Importer importer;
770 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR + file , aiProcess_ValidateDataStructure);
771 ASSERT_EQ(scene, nullptr);
772 const std::string error = importer.GetErrorString();
773 EXPECT_FALSE(error.empty());
774 EXPECT_NE(error.find(member + "\" was not of type \"" + type + "\" when reading " + context), std::string::npos);
775 }
776 }
777
778 namespace {
779 /// This class provides a fake schema to the GLTF importer.
780 /// It just checks that the file has a top-level "scene" property which is an integer.
781 class FakeSchemaProvider : public rapidjson::IRemoteSchemaDocumentProvider
782 {
783 public:
FakeSchemaProvider(const char * schemaName)784 FakeSchemaProvider(const char* schemaName) :
785 m_schemaName(schemaName)
786 {
787 rapidjson::Document schemaDoc;
788 schemaDoc.Parse(R"==({"properties":{"scene" : { "type" : "integer" }}, "required": [ "scene" ]})==");
789 EXPECT_FALSE(schemaDoc.HasParseError());
790 m_schema.reset(new rapidjson::SchemaDocument(schemaDoc, m_schemaName.c_str(), static_cast<rapidjson::SizeType>(m_schemaName.size()), this));
791 }
792
GetRemoteDocument(const char * uri,rapidjson::SizeType)793 const rapidjson::SchemaDocument* GetRemoteDocument(const char* uri, rapidjson::SizeType) override {
794 if (m_schemaName == uri) {
795 return m_schema.get();
796 }
797 return nullptr;
798 }
799
800 private:
801 std::string m_schemaName;
802 std::unique_ptr<const rapidjson::SchemaDocument> m_schema;
803 };
804 }
805
TEST_F(utglTF2ImportExport,schemaCheckPass)806 TEST_F(utglTF2ImportExport, schemaCheckPass) {
807 FakeSchemaProvider schemaProvider("glTF.schema.json");
808 Assimp::Importer importer;
809 importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
810 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
811 EXPECT_NE(scene, nullptr);
812 EXPECT_STREQ(importer.GetErrorString(), "");
813 }
814
TEST_F(utglTF2ImportExport,schemaCheckFail)815 TEST_F(utglTF2ImportExport, schemaCheckFail) {
816 FakeSchemaProvider schemaProvider("glTF.schema.json");
817 Assimp::Importer importer;
818 importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
819 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/SchemaFailures/sceneWrongType.gltf", aiProcess_ValidateDataStructure);
820 EXPECT_EQ(scene, nullptr);
821 const std::string errorString = importer.GetErrorString();
822 EXPECT_NE(errorString.find("The JSON document did not satisfy the glTF2 schema"), std::string::npos);
823 }
824
TEST_F(utglTF2ImportExport,noSchemaFound)825 TEST_F(utglTF2ImportExport, noSchemaFound) {
826 // More than one importer might make use the provider, but not all schemas might be present.
827 // Check that the glTF importer handles the case when an non-null provider returns null when asked for schemas.
828 FakeSchemaProvider schemaProvider("missingSchema.json");
829 Assimp::Importer importer;
830 importer.SetPropertyPointer(AI_CONFIG_IMPORT_SCHEMA_DOCUMENT_PROVIDER, &schemaProvider);
831 const aiScene *scene = importer.ReadFile(ASSIMP_TEST_MODELS_DIR "/glTF2/BoxTextured-glTF/BoxTextured.gltf", aiProcess_ValidateDataStructure);
832 EXPECT_NE(scene, nullptr);
833 EXPECT_STREQ(importer.GetErrorString(), "");
834 }
835