[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene3d-internal / utc-Dali-Gltf2LoaderImpl.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // Enable debug log for test coverage
19 #define DEBUG_ENABLED 1
20
21 #include <dali-scene3d/internal/loader/gltf2-loader-impl.h>
22 #include <dali-scene3d/public-api/loader/load-result.h>
23 #include <dali-scene3d/public-api/loader/resource-bundle.h>
24 #include <dali-scene3d/public-api/loader/scene-definition.h>
25 #include <dali-scene3d/public-api/loader/shader-manager.h>
26 #include <dali-test-suite-utils.h>
27 #include <string_view>
28
29 using namespace Dali;
30 using namespace Dali::Scene3D::Loader;
31
32 #define DALI_TEST_THROW(expression, exception, predicate) \
33   {                                                       \
34     bool daliTestThrowSuccess__ = false;                  \
35     try                                                   \
36     {                                                     \
37       do                                                  \
38       {                                                   \
39         expression;                                       \
40       } while(0);                                         \
41       printf("No exception was thrown.\n");               \
42     }                                                     \
43     catch(std::decay<exception>::type & ex)               \
44     {                                                     \
45       daliTestThrowSuccess__ = predicate(ex);             \
46     }                                                     \
47     catch(...)                                            \
48     {                                                     \
49       printf("Wrong type of exception thrown.\n");        \
50     }                                                     \
51     DALI_TEST_CHECK(daliTestThrowSuccess__);              \
52   }
53
54 namespace
55 {
56 struct Context
57 {
58   ResourceBundle::PathProvider pathProvider = [](ResourceType::Value type) {
59     return TEST_RESOURCE_DIR "/";
60   };
61
62   ResourceBundle  resources;
63   SceneDefinition scene;
64   SceneMetadata   metaData;
65
66   std::vector<AnimationDefinition>      animations;
67   std::vector<AnimationGroupDefinition> animationGroups;
68   std::vector<CameraParameters>         cameras;
69   std::vector<LightParameters>          lights;
70
71   LoadResult loadResult{
72     resources,
73     scene,
74     metaData,
75     animations,
76     animationGroups,
77     cameras,
78     lights};
79
80   Dali::Scene3D::Loader::Internal::Gltf2LoaderImpl loader;
81 };
82
83 struct ExceptionMessageStartsWith
84 {
85   const std::string_view expected;
86
87   bool operator()(const std::runtime_error& e)
88   {
89     const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
90     if(!success)
91     {
92       printf("Expected: %s, got: %s.\n", expected.data(), e.what());
93     }
94     return success;
95   }
96 };
97
98 } // namespace
99
100 int UtcDaliGltfLoaderFailedToLoad1(void)
101 {
102   Context ctx;
103
104   DALI_TEST_EQUAL(ctx.loader.LoadModel("non-existent.gltf", ctx.loadResult), false);
105
106   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
107   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
108
109   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
110   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
111   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
112   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
113   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
114
115   DALI_TEST_EQUAL(0, ctx.cameras.size());
116   DALI_TEST_EQUAL(0, ctx.lights.size());
117   DALI_TEST_EQUAL(0, ctx.animations.size());
118   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
119
120   END_TEST;
121 }
122
123 int UtcDaliGltfLoaderFailedToLoad2(void)
124 {
125   Context ctx;
126
127   try
128   {
129     DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/UnsupportedExtension.gltf", ctx.loadResult), false);
130   }
131   catch(...)
132   {
133     printf("Unsupported glTF extension required.\n");
134   }
135
136   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
137   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
138
139   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
140   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
141   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
142   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
143   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
144
145   DALI_TEST_EQUAL(0, ctx.cameras.size());
146   DALI_TEST_EQUAL(0, ctx.lights.size());
147   DALI_TEST_EQUAL(0, ctx.animations.size());
148   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
149
150   END_TEST;
151 }
152
153 int UtcDaliGltfLoaderFailedToParse(void)
154 {
155   Context ctx;
156
157   DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/invalid.gltf", ctx.loadResult), false);
158
159   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
160   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
161
162   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
163   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
164   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
165   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
166
167   DALI_TEST_EQUAL(0, ctx.cameras.size());
168   DALI_TEST_EQUAL(0, ctx.lights.size());
169   DALI_TEST_EQUAL(0, ctx.animations.size());
170   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
171
172   END_TEST;
173 }
174
175 int UtcDaliGltfLoaderSuccess1(void)
176 {
177   Context ctx;
178
179   LoadSceneMetadata(TEST_RESOURCE_DIR "/AnimatedCube.metadata", ctx.metaData);
180
181   std::unordered_map<std::string, ImageMetadata> imageMetadataGroundTruth;
182   imageMetadataGroundTruth["AnimatedCube_BaseColor.png"]         = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::BOX_THEN_NEAREST};
183   imageMetadataGroundTruth["AnimatedCube_MetallicRoughness.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::NEAREST};
184
185   auto metaData = ctx.metaData.mImageMetadata.begin();
186   for(auto& groundTruth : imageMetadataGroundTruth)
187   {
188     DALI_TEST_EQUAL(groundTruth.first, metaData->first);
189     DALI_TEST_EQUAL(groundTruth.second.mMinSize, metaData->second.mMinSize);
190     DALI_TEST_EQUAL(groundTruth.second.mSamplingMode, metaData->second.mSamplingMode);
191     ++metaData;
192   }
193
194   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCube.gltf", ctx.loadResult);
195
196   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
197   DALI_TEST_EQUAL(9u, ctx.scene.GetNodeCount());
198
199   // Default envmap is used
200   DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size());
201
202   TestApplication app;
203
204   Customization::Choices choices;
205   for(auto iRoot : ctx.scene.GetRoots())
206   {
207     auto resourceRefs = ctx.resources.CreateRefCounter();
208     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
209     ctx.resources.mReferenceCounts = std::move(resourceRefs);
210     ctx.resources.CountEnvironmentReferences();
211     ctx.resources.LoadResources(ctx.pathProvider);
212   }
213
214   auto& materials = ctx.resources.mMaterials;
215   DALI_TEST_EQUAL(2u, materials.size());
216   const MaterialDefinition materialGroundTruth[]{
217     {nullptr,
218      MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
219        MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
220        MaterialDefinition::GLTF_CHANNELS | (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
221      0,
222      Color::WHITE,
223      1.f,
224      0.f,
225      Vector4(1.000, 0.766, 0.336, 1.0),
226      1.f,
227      1.f,
228      Vector3(0.2, 0.1, 0.0),
229      1.0f,
230      0.0f,
231      0.5f,
232      Vector3(0, 0, 1),
233      true,
234      false,
235      true,
236      false,
237      Scene3D::Material::AlphaModeType::MASK,
238      true,
239      true,
240      true,
241      {
242        {
243          MaterialDefinition::ALBEDO,
244          {
245            "AnimatedCube_BaseColor.png",
246            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
247            ImageDimensions(256, 256),
248            SamplingMode::BOX_THEN_NEAREST,
249          },
250        },
251        {
252          MaterialDefinition::NORMAL,
253          {
254            "AnimatedCube_BaseColor.png",
255            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
256            ImageDimensions(256, 256),
257            SamplingMode::BOX_THEN_NEAREST,
258          },
259        },
260        {
261          MaterialDefinition::OCCLUSION,
262          {
263            "AnimatedCube_BaseColor.png",
264            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
265            ImageDimensions(256, 256),
266            SamplingMode::BOX_THEN_NEAREST,
267          },
268        },
269        {
270          MaterialDefinition::EMISSIVE,
271          {
272            "AnimatedCube_BaseColor.png",
273            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
274            ImageDimensions(256, 256),
275            SamplingMode::BOX_THEN_NEAREST,
276          },
277        },
278        {
279          MaterialDefinition::SPECULAR,
280          {
281            "AnimatedCube_BaseColor.png",
282            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
283            ImageDimensions(256, 256),
284            SamplingMode::BOX_THEN_NEAREST,
285          },
286        },
287        {
288          MaterialDefinition::SPECULAR_COLOR,
289          {
290            "AnimatedCube_BaseColor.png",
291            SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
292            ImageDimensions(256, 256),
293            SamplingMode::BOX_THEN_NEAREST,
294          },
295        },
296      },
297      nullptr},
298     {
299       nullptr,
300       MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
301         MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | MaterialDefinition::NORMAL |
302         MaterialDefinition::GLTF_CHANNELS,
303       0,
304       Color::WHITE,
305       1.f,
306       0.f,
307       Vector4(1.000, 0.766, 0.336, 1.0),
308       1.f,
309       1.f,
310       Vector3(0.2, 0.1, 0.0),
311       -1.0f,
312       0.04f,
313       1.0f,
314       Vector3::ONE,
315       true,
316       true,
317       true,
318       false,
319       Scene3D::Material::AlphaModeType::OPAQUE,
320       true,
321       false,
322       true,
323       {
324         {
325           MaterialDefinition::ALBEDO,
326           {
327             "AnimatedCube_BaseColor.png",
328             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
329             ImageDimensions(256, 256),
330             SamplingMode::BOX_THEN_NEAREST,
331           },
332         },
333         {
334           MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS,
335           {
336             "AnimatedCube_MetallicRoughness.png",
337             SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
338             ImageDimensions(256, 256),
339             SamplingMode::NEAREST,
340           },
341         },
342         {
343           MaterialDefinition::NORMAL,
344           {
345             "AnimatedCube_BaseColor.png",
346             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
347             ImageDimensions(256, 256),
348             SamplingMode::BOX_THEN_NEAREST,
349           },
350         },
351         {
352           MaterialDefinition::OCCLUSION,
353           {
354             "AnimatedCube_BaseColor.png",
355             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
356             ImageDimensions(256, 256),
357             SamplingMode::BOX_THEN_NEAREST,
358           },
359         },
360         {
361           MaterialDefinition::EMISSIVE,
362           {
363             "AnimatedCube_BaseColor.png",
364             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
365             ImageDimensions(256, 256),
366             SamplingMode::BOX_THEN_NEAREST,
367           },
368         },
369       },
370       nullptr,
371     },
372   };
373
374   auto iMaterial = materials.begin();
375   auto iMetadata = ctx.metaData.mImageMetadata.begin();
376   for(auto& m : materialGroundTruth)
377   {
378     printf("material %ld\n", iMaterial - materials.begin());
379     auto& md = iMaterial->first;
380     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
381     DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
382     DALI_TEST_EQUAL(md.mColor, m.mColor);
383     DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
384     DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
385     DALI_TEST_EQUAL(md.mBaseColorFactor, m.mBaseColorFactor);
386     DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale);
387     DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength);
388     DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor);
389     DALI_TEST_EQUAL(md.mIor, m.mIor);
390     DALI_TEST_EQUAL(md.mDielectricSpecular, m.mDielectricSpecular);
391     DALI_TEST_EQUAL(md.mSpecularFactor, m.mSpecularFactor);
392     DALI_TEST_EQUAL(md.mSpecularColorFactor, m.mSpecularColorFactor);
393     DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture);
394     DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture);
395     DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture);
396     DALI_TEST_EQUAL(md.mAlphaModeType, m.mAlphaModeType);
397     DALI_TEST_EQUAL(md.mIsOpaque, m.mIsOpaque);
398     DALI_TEST_EQUAL(md.mIsMask, m.mIsMask);
399
400     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
401     auto iTexture = md.mTextureStages.begin();
402     for(auto& ts : m.mTextureStages)
403     {
404       printf("texture %ld\n", iTexture - md.mTextureStages.begin());
405       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
406       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
407       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
408       DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions);
409       DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode);
410
411       ++iTexture;
412     }
413     ++iMaterial;
414     ++iMetadata;
415   }
416
417   auto& meshes = ctx.resources.mMeshes;
418   DALI_TEST_EQUAL(2u, meshes.size());
419
420   using Blob     = MeshDefinition::Blob;
421   using Accessor = MeshDefinition::Accessor;
422   MeshDefinition meshGroundTruth[]{
423     {
424       nullptr,
425       0,
426       Geometry::TRIANGLES,
427       "AnimatedCube.bin",
428       Accessor{Blob{0, 0}, {}},
429       Accessor{Blob{0, 0}, {}},
430       Accessor{Blob{0, 0}, {}},
431       Accessor{Blob{0, 0}, {}},
432     },
433     {
434       nullptr,
435       0,
436       Geometry::TRIANGLES,
437       "AnimatedCube.bin",
438       Accessor{Blob{0, 0}, {}},
439       Accessor{Blob{0, 0}, {}},
440       Accessor{Blob{0, 0}, {}},
441       Accessor{Blob{0, 0}, {}},
442     },
443   };
444   meshGroundTruth[0].mColors.push_back(Accessor{Blob{0, 0}, {}});
445   meshGroundTruth[0].mTexCoords.push_back(Accessor{Blob{0, 0}, {}});
446   meshGroundTruth[1].mColors.push_back(Accessor{Blob{0, 0}, {}});
447   meshGroundTruth[1].mTexCoords.push_back(Accessor{Blob{0, 0}, {}});
448
449   auto iMesh = meshes.begin();
450   for(auto& m : meshGroundTruth)
451   {
452     printf("mesh %ld\n", iMesh - meshes.begin());
453
454     auto& md = iMesh->first;
455     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
456     DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
457
458     DALI_TEST_EQUAL((md.mIndices).IsDefined(), (m.mIndices).IsDefined());
459     DALI_TEST_EQUAL((md.mIndices).mBlob.IsDefined(), (m.mIndices).mBlob.IsDefined());
460
461     DALI_TEST_EQUAL((md.mPositions).IsDefined(), (m.mPositions).IsDefined());
462     DALI_TEST_EQUAL((md.mPositions).mBlob.IsDefined(), (m.mPositions).mBlob.IsDefined());
463
464     DALI_TEST_EQUAL((md.mNormals).IsDefined(), (m.mNormals).IsDefined());
465     DALI_TEST_EQUAL((md.mNormals).mBlob.IsDefined(), (m.mNormals).mBlob.IsDefined());
466
467     DALI_TEST_EQUAL((md.mTangents).IsDefined(), (m.mTangents).IsDefined());
468     DALI_TEST_EQUAL((md.mTangents).mBlob.IsDefined(), (m.mTangents).mBlob.IsDefined());
469
470     DALI_TEST_EQUAL(md.mTexCoords.empty(), m.mTexCoords.empty());
471     DALI_TEST_EQUAL(md.mColors.empty(), m.mColors.empty());
472
473     DALI_TEST_EQUAL(md.mJoints.empty(), (m.mJoints.empty()));
474     DALI_TEST_EQUAL(md.mWeights.empty(), (m.mWeights.empty()));
475
476     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
477
478     ++iMesh;
479   }
480
481   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
482
483   DALI_TEST_EQUAL(6u, ctx.cameras.size());
484   DALI_TEST_EQUAL(0u, ctx.lights.size());
485   DALI_TEST_EQUAL(1u, ctx.animations.size());
486   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
487
488   END_TEST;
489 }
490
491 int UtcDaliGltfLoaderSuccess2(void)
492 {
493   Context ctx;
494
495   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
496
497   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
498   DALI_TEST_EQUAL(1u, ctx.scene.GetNodeCount());
499
500   TestApplication app;
501
502   Customization::Choices choices;
503   for(auto iRoot : ctx.scene.GetRoots())
504   {
505     auto resourceRefs = ctx.resources.CreateRefCounter();
506     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
507     ctx.resources.mReferenceCounts = std::move(resourceRefs);
508     ctx.resources.LoadResources(ctx.pathProvider);
509   }
510
511   DALI_TEST_EQUAL(true, ctx.resources.mMeshes[0u].first.mPositions.IsDefined());
512   DALI_TEST_EQUAL(432, ctx.resources.mMeshes[0u].first.mPositions.mBlob.mLength);
513
514   END_TEST;
515 }
516
517 int UtcDaliGltfLoaderSuccessShort(void)
518 {
519   TestApplication app;
520
521   const std::string resourcePath = TEST_RESOURCE_DIR "/";
522   auto              pathProvider = [resourcePath](ResourceType::Value) {
523     return resourcePath;
524   };
525
526   Customization::Choices choices;
527   for(auto modelName : {
528         "2CylinderEngine",
529         "AnimatedMorphCube",
530         "AnimatedMorphCubeAnimateNonZeroFrame",
531         "AnimatedMorphSphere",
532         "AnimatedTriangle",
533         "BoxAnimated",
534         "CesiumMan",
535         "CesiumMilkTruck",
536         "EnvironmentTest",
537         "MetalRoughSpheres",
538         "MorphPrimitivesTest",
539         "MRendererTest",
540         "SimpleSparseAccessor",
541         "TextureTransformMultiTest",
542         "AnimatedCube",
543         /**
544          * For the Avocado glTF file and its Assets
545          * Donated by Microsoft for glTF testing
546          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
547          */
548         "AvocadoQuantized",
549         /**
550          * For the AnimatedMorphCube glTF file and its Assets
551          * Donated by Microsoft for glTF testing
552          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/AnimatedMorphCube/glTF-Quantized
553          */
554         "AnimatedMorphCubeQuantized",
555         /**
556          * For the MorphPrimitivesTest glTF file and its Assets
557          * Created by @ft-lab
558          * Licensed under the terms of the CC BY 4.0 license: https://creativecommons.org/licenses/by/4.0/
559          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MorphPrimitivesTest/glTF
560          * Modified using gltfpack 0.18.
561          */
562         "MorphPrimitivesTestQuantized",
563         /**
564          * For the CesiumMilkTruck glTF file and its Assets
565          * Donated by Cesium for glTF testing
566          * Licensed under the terms of the CC BY 4.0 license: http://creativecommons.org/licenses/by/4.0/
567          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/CesiumMilkTruck/glTF
568          * Modified using gltfpack 0.18.
569          */
570         "CesiumMilkTruckQuantized",
571       })
572   {
573     Context ctx;
574
575     auto& resources = ctx.resources;
576     resources.mEnvironmentMaps.push_back({});
577
578     printf("%s\n", modelName);
579     ctx.loader.LoadModel(resourcePath + modelName + ".gltf", ctx.loadResult);
580     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
581
582     auto& scene = ctx.scene;
583     for(auto iRoot : scene.GetRoots())
584     {
585       struct Visitor : NodeDefinition::IVisitor
586       {
587         struct ResourceReceiver : IResourceReceiver
588         {
589           std::vector<bool> mCounts;
590
591           void Register(ResourceType::Value type, Index id) override
592           {
593             if(type == ResourceType::Mesh)
594             {
595               mCounts[id] = true;
596             }
597           }
598         } receiver;
599
600         void Start(NodeDefinition& n) override
601         {
602           for(auto& renderable : n.mRenderables)
603           {
604             renderable->RegisterResources(receiver);
605           }
606         }
607
608         void Finish(NodeDefinition& n) override
609         {
610         }
611       } visitor;
612       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
613
614       scene.Visit(iRoot, choices, visitor);
615       for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
616       {
617         if(visitor.receiver.mCounts[i0])
618         {
619           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath, resources.mBuffers);
620           DALI_TEST_CHECK(!raw.mAttribs.empty());
621
622           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
623           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
624         }
625       }
626     }
627   }
628
629   END_TEST;
630 }
631
632 int UtcDaliGltfLoaderMRendererTest(void)
633 {
634   Context ctx;
635   auto&   resources = ctx.resources;
636
637   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
638
639   auto& scene = ctx.scene;
640   auto& roots = scene.GetRoots();
641   DALI_TEST_EQUAL(roots.size(), 1u);
642   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
643   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
644
645   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
646
647   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
648   ViewProjection                    viewProjection;
649   Transforms                        xforms{
650     MatrixStack{},
651     viewProjection};
652   NodeDefinition::CreateParams nodeParams{
653     resources,
654     xforms,
655     shaderManager,
656   };
657
658   Customization::Choices choices;
659
660   TestApplication app;
661
662   Actor root = Actor::New();
663   SetActorCentered(root);
664   for(auto iRoot : roots)
665   {
666     auto resourceRefs = resources.CreateRefCounter();
667     scene.CountResourceRefs(iRoot, choices, resourceRefs);
668     ctx.resources.mReferenceCounts = std::move(resourceRefs);
669     ctx.resources.CountEnvironmentReferences();
670     ctx.resources.LoadResources(ctx.pathProvider);
671     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
672     {
673       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
674       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
675       root.Add(actor);
676     }
677   }
678
679   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
680   Actor child = root.GetChildAt(0);
681
682   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
683   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
684   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
685   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 5u);
686
687   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
688   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
689
690   END_TEST;
691 }
692
693 int UtcDaliGltfLoaderAnimationLoadingTest(void)
694 {
695   TestApplication app;
696   Context         ctx;
697
698   auto& resources = ctx.resources;
699
700   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/CesiumMan_e.gltf", ctx.loadResult);
701
702   auto& scene = ctx.scene;
703   auto& roots = scene.GetRoots();
704   DALI_TEST_EQUAL(roots.size(), 1u);
705
706   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
707   ViewProjection                    viewProjection;
708   Transforms                        xforms{
709     MatrixStack{},
710     viewProjection};
711   NodeDefinition::CreateParams nodeParams{
712     resources,
713     xforms,
714     shaderManager,
715   };
716
717   Customization::Choices choices;
718
719   Actor root = Actor::New();
720   SetActorCentered(root);
721   for(auto iRoot : roots)
722   {
723     auto resourceRefs = resources.CreateRefCounter();
724     scene.CountResourceRefs(iRoot, choices, resourceRefs);
725     resources.mReferenceCounts = std::move(resourceRefs);
726     resources.CountEnvironmentReferences();
727     resources.LoadResources(ctx.pathProvider);
728     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
729     {
730       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
731       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
732       root.Add(actor);
733     }
734   }
735
736   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
737   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].GetPropertyCount(), 57u);
738
739   uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].GetPropertyAt(0).mNodeIndex)->mNodeId;
740   DALI_TEST_EQUAL(id, root.FindChildByName("Skeleton_torso_joint_1").GetProperty<int32_t>(Dali::Actor::Property::ID));
741
742   END_TEST;
743 }
744
745 int UtcDaliGltfLoaderImageFromBufferView(void)
746 {
747   Context ctx;
748
749   auto& resources = ctx.resources;
750
751   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", ctx.loadResult);
752
753   auto& scene = ctx.scene;
754   auto& roots = scene.GetRoots();
755   DALI_TEST_EQUAL(roots.size(), 1u);
756
757   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
758   ViewProjection                    viewProjection;
759   Transforms                        xforms{
760     MatrixStack{},
761     viewProjection};
762   NodeDefinition::CreateParams nodeParams{
763     resources,
764     xforms,
765     shaderManager,
766   };
767
768   Customization::Choices choices;
769
770   TestApplication app;
771
772   Actor root = Actor::New();
773   SetActorCentered(root);
774   for(auto iRoot : roots)
775   {
776     auto resourceRefs = resources.CreateRefCounter();
777     scene.CountResourceRefs(iRoot, choices, resourceRefs);
778     resources.mReferenceCounts = std::move(resourceRefs);
779     resources.CountEnvironmentReferences();
780     resources.LoadResources(ctx.pathProvider);
781     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
782     {
783       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
784       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
785       root.Add(actor);
786     }
787   }
788
789   DALI_TEST_CHECK(resources.mMaterials[0].second.GetTextureCount() > 1);
790   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetWidth(), 256);
791   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetHeight(), 256);
792
793   END_TEST;
794 }
795
796 int UtcDaliGltfLoaderUint8Indices(void)
797 {
798   Context ctx;
799
800   auto& resources = ctx.resources;
801
802   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AlphaBlendModeTest.gltf", ctx.loadResult);
803
804   auto& scene = ctx.scene;
805   auto& roots = scene.GetRoots();
806   DALI_TEST_EQUAL(roots.size(), 1u);
807
808   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
809   ViewProjection                    viewProjection;
810   Transforms                        xforms{
811     MatrixStack{},
812     viewProjection};
813   NodeDefinition::CreateParams nodeParams{
814     resources,
815     xforms,
816     shaderManager,
817   };
818
819   Customization::Choices choices;
820
821   TestApplication app;
822
823   Actor root = Actor::New();
824   SetActorCentered(root);
825   for(auto iRoot : roots)
826   {
827     auto resourceRefs = resources.CreateRefCounter();
828     scene.CountResourceRefs(iRoot, choices, resourceRefs);
829     resources.mReferenceCounts = std::move(resourceRefs);
830     resources.CountEnvironmentReferences();
831     resources.LoadResources(ctx.pathProvider);
832     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
833     {
834       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
835       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
836       root.Add(actor);
837     }
838   }
839
840   DALI_TEST_CHECK(root.FindChildByName("Bed"));
841   DALI_TEST_CHECK(root.FindChildByName("DecalBlend"));
842   DALI_TEST_CHECK(root.FindChildByName("DecalOpaque"));
843
844   END_TEST;
845 }
846
847 int UtcDaliGltfLoaderQuantizedMesh(void)
848 {
849   Context ctx;
850
851   auto& resources = ctx.resources;
852
853   /**
854    * For the Avocado glTF file and its Assets
855    * Donated by Microsoft for glTF testing
856    * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
857    */
858   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AvocadoQuantized.gltf", ctx.loadResult);
859
860   auto& scene = ctx.scene;
861   DALI_TEST_EQUAL(1u, scene.GetRoots().size());
862   DALI_TEST_EQUAL(1u, scene.GetNodeCount());
863
864   auto& roots = scene.GetRoots();
865   DALI_TEST_EQUAL(roots.size(), 1u);
866
867   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
868   ViewProjection                    viewProjection;
869   Transforms                        xforms{
870     MatrixStack{},
871     viewProjection};
872   NodeDefinition::CreateParams nodeParams{
873     resources,
874     xforms,
875     shaderManager,
876   };
877
878   Customization::Choices choices;
879
880   TestApplication app;
881
882   Actor root = Actor::New();
883   SetActorCentered(root);
884   for(auto iRoot : roots)
885   {
886     auto resourceRefs = resources.CreateRefCounter();
887     scene.CountResourceRefs(iRoot, choices, resourceRefs);
888     resources.mReferenceCounts = std::move(resourceRefs);
889     resources.CountEnvironmentReferences();
890     resources.LoadResources(ctx.pathProvider);
891     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
892     {
893       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
894       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
895       root.Add(actor);
896     }
897   }
898
899   auto& meshes = ctx.resources.mMeshes;
900   DALI_TEST_EQUAL(1u, meshes.size());
901
902   auto& md = meshes[0u].first;
903
904   DALI_TEST_EQUAL(MeshDefinition::Flags::U16_POSITION | MeshDefinition::Flags::S8_NORMAL | MeshDefinition::Flags::S8_TANGENT | MeshDefinition::Flags::U16_TEXCOORD, md.mFlags);
905
906   DALI_TEST_EQUAL(true, md.mPositions.IsDefined());
907   DALI_TEST_EQUAL(false, md.mPositions.mNormalized);
908   DALI_TEST_EQUAL(sizeof(uint16_t) * 3, md.mPositions.mBlob.mElementSizeHint);
909   DALI_TEST_EQUAL(true, md.mPositions.mBlob.IsDefined());
910   DALI_TEST_EQUAL(2436, md.mPositions.mBlob.mLength);
911   DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMin.size());
912   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[0]);
913   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[1]);
914   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[2]);
915   DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMax.size());
916   DALI_TEST_EQUAL(11086.0f, md.mPositions.mBlob.mMax[0]);
917   DALI_TEST_EQUAL(16383.0f, md.mPositions.mBlob.mMax[1]);
918   DALI_TEST_EQUAL(7194.0f, md.mPositions.mBlob.mMax[2]);
919
920   DALI_TEST_EQUAL(true, md.mNormals.IsDefined());
921   DALI_TEST_EQUAL(true, md.mNormals.mNormalized);
922   DALI_TEST_EQUAL(sizeof(int8_t) * 3, md.mNormals.mBlob.mElementSizeHint);
923   DALI_TEST_EQUAL(true, md.mNormals.mBlob.IsDefined());
924   DALI_TEST_EQUAL(1218, md.mNormals.mBlob.mLength);
925   DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMin.size());
926   DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMax.size());
927
928   DALI_TEST_EQUAL(true, md.mTangents.IsDefined());
929   DALI_TEST_EQUAL(true, md.mTangents.mNormalized);
930   DALI_TEST_EQUAL(Property::VECTOR4, md.mTangentType);
931   DALI_TEST_EQUAL(sizeof(int8_t) * 4, md.mTangents.mBlob.mElementSizeHint);
932   DALI_TEST_EQUAL(true, md.mTangents.mBlob.IsDefined());
933   DALI_TEST_EQUAL(1624, md.mTangents.mBlob.mLength);
934   DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMin.size());
935   DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMax.size());
936
937   DALI_TEST_EQUAL(false, md.mTexCoords.empty());
938   DALI_TEST_EQUAL(true, md.mTexCoords[0].IsDefined());
939   DALI_TEST_EQUAL(false, md.mTexCoords[0].mNormalized);
940   DALI_TEST_EQUAL(sizeof(uint16_t) * 2, md.mTexCoords[0].mBlob.mElementSizeHint);
941   DALI_TEST_EQUAL(true, md.mTexCoords[0].mBlob.IsDefined());
942   DALI_TEST_EQUAL(1624, md.mTexCoords[0].mBlob.mLength);
943   DALI_TEST_EQUAL(0u, md.mTexCoords[0].mBlob.mMin.size());
944   DALI_TEST_EQUAL(0u, md.mTexCoords[0].mBlob.mMax.size());
945
946   END_TEST;
947 }
948
949 int UtcDaliGltfLoaderTextureTransform(void)
950 {
951   Context ctx;
952
953   auto& resources = ctx.resources;
954
955   /**
956    * For the Avocado glTF file and its Assets
957    * Donated by Microsoft for glTF testing
958    * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
959    */
960   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AvocadoQuantized.gltf", ctx.loadResult);
961
962   auto& scene = ctx.scene;
963   DALI_TEST_EQUAL(1u, scene.GetRoots().size());
964   DALI_TEST_EQUAL(1u, scene.GetNodeCount());
965
966   TestApplication app;
967
968   Customization::Choices choices;
969   for(auto iRoot : scene.GetRoots())
970   {
971     auto resourceRefs = resources.CreateRefCounter();
972     scene.CountResourceRefs(iRoot, choices, resourceRefs);
973     resources.mReferenceCounts = std::move(resourceRefs);
974     resources.CountEnvironmentReferences();
975     resources.LoadResources(ctx.pathProvider);
976   }
977
978   auto& materials = resources.mMaterials;
979   DALI_TEST_EQUAL(1u, materials.size());
980
981   auto  iMaterial = materials.begin();
982   auto& md        = iMaterial->first;
983
984   DALI_TEST_EQUAL(3u, md.mTextureStages.size());
985
986   Matrix3 textureTransformGroundTruth(0.000238f, 0.0f, 0.0f, 0.0f, 0.000242f, 0.0f, 0.00678f, 0.002982f, 1.0f);
987   DALI_TEST_EQUALS(md.mTextureStages[0].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
988   DALI_TEST_EQUALS(md.mTextureStages[1].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
989   DALI_TEST_EQUALS(md.mTextureStages[2].mTexture.mTransform, textureTransformGroundTruth, 0.01f, TEST_LOCATION);
990
991   END_TEST;
992 }