4b93f7f599f060b39fef830a0dc4beeb6b56df44
[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   const 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       Accessor{Blob{0, 0}, {}},
433       Accessor{Blob{0, 0}, {}},
434     },
435     {
436       nullptr,
437       0,
438       Geometry::TRIANGLES,
439       "AnimatedCube.bin",
440       Accessor{Blob{0, 0}, {}},
441       Accessor{Blob{0, 0}, {}},
442       Accessor{Blob{0, 0}, {}},
443       Accessor{Blob{0, 0}, {}},
444       Accessor{Blob{0, 0}, {}},
445       Accessor{Blob{0, 0}, {}},
446     },
447   };
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     for(auto mp : {
458           &MeshDefinition::mIndices,
459           &MeshDefinition::mPositions,
460           &MeshDefinition::mNormals,
461           &MeshDefinition::mTexCoords,
462           &MeshDefinition::mColors,
463           &MeshDefinition::mTangents,
464           &MeshDefinition::mJoints0,
465           &MeshDefinition::mWeights0})
466     {
467       DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
468       DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
469     }
470
471     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
472
473     ++iMesh;
474   }
475
476   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
477
478   DALI_TEST_EQUAL(6u, ctx.cameras.size());
479   DALI_TEST_EQUAL(0u, ctx.lights.size());
480   DALI_TEST_EQUAL(1u, ctx.animations.size());
481   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
482
483   END_TEST;
484 }
485
486 int UtcDaliGltfLoaderSuccess2(void)
487 {
488   Context ctx;
489
490   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
491
492   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
493   DALI_TEST_EQUAL(1u, ctx.scene.GetNodeCount());
494
495   TestApplication app;
496
497   Customization::Choices choices;
498   for(auto iRoot : ctx.scene.GetRoots())
499   {
500     auto resourceRefs = ctx.resources.CreateRefCounter();
501     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
502     ctx.resources.mReferenceCounts = std::move(resourceRefs);
503     ctx.resources.LoadResources(ctx.pathProvider);
504   }
505
506   DALI_TEST_EQUAL(true, ctx.resources.mMeshes[0u].first.mPositions.IsDefined());
507   DALI_TEST_EQUAL(432, ctx.resources.mMeshes[0u].first.mPositions.mBlob.mLength);
508
509   END_TEST;
510 }
511
512 int UtcDaliGltfLoaderSuccessShort(void)
513 {
514   TestApplication app;
515
516   const std::string resourcePath = TEST_RESOURCE_DIR "/";
517   auto              pathProvider = [resourcePath](ResourceType::Value) {
518     return resourcePath;
519   };
520
521   Customization::Choices choices;
522   for(auto modelName : {
523         "2CylinderEngine",
524         "AnimatedMorphCube",
525         "AnimatedMorphCubeAnimateNonZeroFrame",
526         "AnimatedMorphSphere",
527         "AnimatedTriangle",
528         "BoxAnimated",
529         "CesiumMan",
530         "CesiumMilkTruck",
531         "EnvironmentTest",
532         "MetalRoughSpheres",
533         "MorphPrimitivesTest",
534         "MRendererTest",
535         "SimpleSparseAccessor",
536         "AnimatedCube",
537         /**
538          * For the Avocado glTF file and its Assets
539          * Donated by Microsoft for glTF testing
540          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
541          */
542         "AvocadoQuantized",
543         /**
544          * For the AnimatedMorphCube 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/AnimatedMorphCube/glTF-Quantized
547          */
548         "AnimatedMorphCubeQuantized",
549         /**
550          * For the MorphPrimitivesTest glTF file and its Assets
551          * Created by @ft-lab
552          * Licensed under the terms of the CC BY 4.0 license: https://creativecommons.org/licenses/by/4.0/
553          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/MorphPrimitivesTest/glTF
554          * Modified using gltfpack 0.18.
555          */
556         "MorphPrimitivesTestQuantized",
557         /**
558          * For the CesiumMilkTruck glTF file and its Assets
559          * Donated by Cesium for glTF testing
560          * Licensed under the terms of the CC BY 4.0 license: http://creativecommons.org/licenses/by/4.0/
561          * Take from https://github.com/KhronosGroup/glTF-Sample-Models/tree/master/2.0/CesiumMilkTruck/glTF
562          * Modified using gltfpack 0.18.
563          */
564         "CesiumMilkTruckQuantized",
565       })
566   {
567     Context ctx;
568
569     auto& resources = ctx.resources;
570     resources.mEnvironmentMaps.push_back({});
571
572     printf("%s\n", modelName);
573     ctx.loader.LoadModel(resourcePath + modelName + ".gltf", ctx.loadResult);
574     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
575
576     auto& scene = ctx.scene;
577     for(auto iRoot : scene.GetRoots())
578     {
579       struct Visitor : NodeDefinition::IVisitor
580       {
581         struct ResourceReceiver : IResourceReceiver
582         {
583           std::vector<bool> mCounts;
584
585           void Register(ResourceType::Value type, Index id) override
586           {
587             if(type == ResourceType::Mesh)
588             {
589               mCounts[id] = true;
590             }
591           }
592         } receiver;
593
594         void Start(NodeDefinition& n) override
595         {
596           for(auto& renderable : n.mRenderables)
597           {
598             renderable->RegisterResources(receiver);
599           }
600         }
601
602         void Finish(NodeDefinition& n) override
603         {
604         }
605       } visitor;
606       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
607
608       scene.Visit(iRoot, choices, visitor);
609       for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
610       {
611         if(visitor.receiver.mCounts[i0])
612         {
613           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath, resources.mBuffers);
614           DALI_TEST_CHECK(!raw.mAttribs.empty());
615
616           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
617           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
618         }
619       }
620     }
621   }
622
623   END_TEST;
624 }
625
626 int UtcDaliGltfLoaderMRendererTest(void)
627 {
628   Context ctx;
629   auto&   resources = ctx.resources;
630
631   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
632
633   auto& scene = ctx.scene;
634   auto& roots = scene.GetRoots();
635   DALI_TEST_EQUAL(roots.size(), 1u);
636   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
637   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
638
639   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
640
641   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
642   ViewProjection                    viewProjection;
643   Transforms                        xforms{
644     MatrixStack{},
645     viewProjection};
646   NodeDefinition::CreateParams nodeParams{
647     resources,
648     xforms,
649     shaderManager,
650   };
651
652   Customization::Choices choices;
653
654   TestApplication app;
655
656   Actor root = Actor::New();
657   SetActorCentered(root);
658   for(auto iRoot : roots)
659   {
660     auto resourceRefs = resources.CreateRefCounter();
661     scene.CountResourceRefs(iRoot, choices, resourceRefs);
662     ctx.resources.mReferenceCounts = std::move(resourceRefs);
663     ctx.resources.CountEnvironmentReferences();
664     ctx.resources.LoadResources(ctx.pathProvider);
665     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
666     {
667       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
668       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
669       root.Add(actor);
670     }
671   }
672
673   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
674   Actor child = root.GetChildAt(0);
675
676   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
677   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
678   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
679   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 5u);
680
681   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
682   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
683
684   END_TEST;
685 }
686
687 int UtcDaliGltfLoaderAnimationLoadingTest(void)
688 {
689   TestApplication app;
690   Context         ctx;
691
692   auto& resources = ctx.resources;
693
694   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/CesiumMan_e.gltf", ctx.loadResult);
695
696   auto& scene = ctx.scene;
697   auto& roots = scene.GetRoots();
698   DALI_TEST_EQUAL(roots.size(), 1u);
699
700   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
701   ViewProjection                    viewProjection;
702   Transforms                        xforms{
703     MatrixStack{},
704     viewProjection};
705   NodeDefinition::CreateParams nodeParams{
706     resources,
707     xforms,
708     shaderManager,
709   };
710
711   Customization::Choices choices;
712
713   Actor root = Actor::New();
714   SetActorCentered(root);
715   for(auto iRoot : roots)
716   {
717     auto resourceRefs = resources.CreateRefCounter();
718     scene.CountResourceRefs(iRoot, choices, resourceRefs);
719     resources.mReferenceCounts = std::move(resourceRefs);
720     resources.CountEnvironmentReferences();
721     resources.LoadResources(ctx.pathProvider);
722     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
723     {
724       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
725       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
726       root.Add(actor);
727     }
728   }
729
730   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
731   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].GetPropertyCount(), 57u);
732
733   uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].GetPropertyAt(0).mNodeIndex)->mNodeId;
734   DALI_TEST_EQUAL(id, root.FindChildByName("Skeleton_torso_joint_1").GetProperty<int32_t>(Dali::Actor::Property::ID));
735
736   END_TEST;
737 }
738
739 int UtcDaliGltfLoaderImageFromBufferView(void)
740 {
741   Context ctx;
742
743   auto& resources = ctx.resources;
744
745   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", ctx.loadResult);
746
747   auto& scene = ctx.scene;
748   auto& roots = scene.GetRoots();
749   DALI_TEST_EQUAL(roots.size(), 1u);
750
751   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
752   ViewProjection                    viewProjection;
753   Transforms                        xforms{
754     MatrixStack{},
755     viewProjection};
756   NodeDefinition::CreateParams nodeParams{
757     resources,
758     xforms,
759     shaderManager,
760   };
761
762   Customization::Choices choices;
763
764   TestApplication app;
765
766   Actor root = Actor::New();
767   SetActorCentered(root);
768   for(auto iRoot : roots)
769   {
770     auto resourceRefs = resources.CreateRefCounter();
771     scene.CountResourceRefs(iRoot, choices, resourceRefs);
772     resources.mReferenceCounts = std::move(resourceRefs);
773     resources.CountEnvironmentReferences();
774     resources.LoadResources(ctx.pathProvider);
775     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
776     {
777       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
778       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
779       root.Add(actor);
780     }
781   }
782
783   DALI_TEST_CHECK(resources.mMaterials[0].second.GetTextureCount() > 1);
784   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetWidth(), 256);
785   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetHeight(), 256);
786
787   END_TEST;
788 }
789
790 int UtcDaliGltfLoaderUint8Indices(void)
791 {
792   Context ctx;
793
794   auto& resources = ctx.resources;
795
796   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AlphaBlendModeTest.gltf", ctx.loadResult);
797
798   auto& scene = ctx.scene;
799   auto& roots = scene.GetRoots();
800   DALI_TEST_EQUAL(roots.size(), 1u);
801
802   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
803   ViewProjection                    viewProjection;
804   Transforms                        xforms{
805     MatrixStack{},
806     viewProjection};
807   NodeDefinition::CreateParams nodeParams{
808     resources,
809     xforms,
810     shaderManager,
811   };
812
813   Customization::Choices choices;
814
815   TestApplication app;
816
817   Actor root = Actor::New();
818   SetActorCentered(root);
819   for(auto iRoot : roots)
820   {
821     auto resourceRefs = resources.CreateRefCounter();
822     scene.CountResourceRefs(iRoot, choices, resourceRefs);
823     resources.mReferenceCounts = std::move(resourceRefs);
824     resources.CountEnvironmentReferences();
825     resources.LoadResources(ctx.pathProvider);
826     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
827     {
828       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
829       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
830       root.Add(actor);
831     }
832   }
833
834   DALI_TEST_CHECK(root.FindChildByName("Bed"));
835   DALI_TEST_CHECK(root.FindChildByName("DecalBlend"));
836   DALI_TEST_CHECK(root.FindChildByName("DecalOpaque"));
837
838   END_TEST;
839 }
840
841 int UtcDaliGltfLoaderQuantizedMesh(void)
842 {
843   Context ctx;
844
845   auto& resources = ctx.resources;
846
847   /**
848    * For the Avocado glTF file and its Assets
849    * Donated by Microsoft for glTF testing
850    * Take from https://github.com/KhronosGroup/glTF-Sample-Models/blob/master/2.0/Avocado/glTF-Quantized
851    */
852   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AvocadoQuantized.gltf", ctx.loadResult);
853
854   auto& scene = ctx.scene;
855   DALI_TEST_EQUAL(1u, scene.GetRoots().size());
856   DALI_TEST_EQUAL(1u, scene.GetNodeCount());
857
858   auto& roots = scene.GetRoots();
859   DALI_TEST_EQUAL(roots.size(), 1u);
860
861   Scene3D::Loader::ShaderManagerPtr shaderManager = new Scene3D::Loader::ShaderManager();
862   ViewProjection                    viewProjection;
863   Transforms                        xforms{
864     MatrixStack{},
865     viewProjection};
866   NodeDefinition::CreateParams nodeParams{
867     resources,
868     xforms,
869     shaderManager,
870   };
871
872   Customization::Choices choices;
873
874   TestApplication app;
875
876   Actor root = Actor::New();
877   SetActorCentered(root);
878   for(auto iRoot : roots)
879   {
880     auto resourceRefs = resources.CreateRefCounter();
881     scene.CountResourceRefs(iRoot, choices, resourceRefs);
882     resources.mReferenceCounts = std::move(resourceRefs);
883     resources.CountEnvironmentReferences();
884     resources.LoadResources(ctx.pathProvider);
885     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
886     {
887       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
888       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
889       root.Add(actor);
890     }
891   }
892
893   auto& meshes = ctx.resources.mMeshes;
894   DALI_TEST_EQUAL(1u, meshes.size());
895
896   auto& md = meshes[0u].first;
897
898   DALI_TEST_EQUAL(MeshDefinition::Flags::U16_POSITION | MeshDefinition::Flags::S8_NORMAL | MeshDefinition::Flags::S8_TANGENT | MeshDefinition::Flags::U16_TEXCOORD, md.mFlags);
899
900   DALI_TEST_EQUAL(true, md.mPositions.IsDefined());
901   DALI_TEST_EQUAL(false, md.mPositions.mNormalized);
902   DALI_TEST_EQUAL(sizeof(uint16_t) * 3, md.mPositions.mBlob.mElementSizeHint);
903   DALI_TEST_EQUAL(true, md.mPositions.mBlob.IsDefined());
904   DALI_TEST_EQUAL(2436, md.mPositions.mBlob.mLength);
905   DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMin.size());
906   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[0]);
907   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[1]);
908   DALI_TEST_EQUAL(0.0f, md.mPositions.mBlob.mMin[2]);
909   DALI_TEST_EQUAL(3u, md.mPositions.mBlob.mMax.size());
910   DALI_TEST_EQUAL(11086.0f, md.mPositions.mBlob.mMax[0]);
911   DALI_TEST_EQUAL(16383.0f, md.mPositions.mBlob.mMax[1]);
912   DALI_TEST_EQUAL(7194.0f, md.mPositions.mBlob.mMax[2]);
913
914   DALI_TEST_EQUAL(true, md.mNormals.IsDefined());
915   DALI_TEST_EQUAL(true, md.mNormals.mNormalized);
916   DALI_TEST_EQUAL(sizeof(int8_t) * 3, md.mNormals.mBlob.mElementSizeHint);
917   DALI_TEST_EQUAL(true, md.mNormals.mBlob.IsDefined());
918   DALI_TEST_EQUAL(1218, md.mNormals.mBlob.mLength);
919   DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMin.size());
920   DALI_TEST_EQUAL(0u, md.mNormals.mBlob.mMax.size());
921
922   DALI_TEST_EQUAL(true, md.mTangents.IsDefined());
923   DALI_TEST_EQUAL(true, md.mTangents.mNormalized);
924   DALI_TEST_EQUAL(Property::VECTOR4, md.mTangentType);
925   DALI_TEST_EQUAL(sizeof(int8_t) * 4, md.mTangents.mBlob.mElementSizeHint);
926   DALI_TEST_EQUAL(true, md.mTangents.mBlob.IsDefined());
927   DALI_TEST_EQUAL(1624, md.mTangents.mBlob.mLength);
928   DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMin.size());
929   DALI_TEST_EQUAL(0u, md.mTangents.mBlob.mMax.size());
930
931   DALI_TEST_EQUAL(true, md.mTexCoords.IsDefined());
932   DALI_TEST_EQUAL(false, md.mTexCoords.mNormalized);
933   DALI_TEST_EQUAL(sizeof(uint16_t) * 2, md.mTexCoords.mBlob.mElementSizeHint);
934   DALI_TEST_EQUAL(true, md.mTexCoords.mBlob.IsDefined());
935   DALI_TEST_EQUAL(1624, md.mTexCoords.mBlob.mLength);
936   DALI_TEST_EQUAL(0u, md.mTexCoords.mBlob.mMin.size());
937   DALI_TEST_EQUAL(0u, md.mTexCoords.mBlob.mMax.size());
938
939   END_TEST;
940 }