38f8e1ef97d9cacd00775d54bc87ac8c59d49aa1
[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-definition-factory.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 UtcDaliGltfLoaderFailedToLoad(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 UtcDaliGltfLoaderFailedToParse(void)
124 {
125   Context ctx;
126
127   ShaderDefinitionFactory sdf;
128   sdf.SetResources(ctx.resources);
129
130   DALI_TEST_EQUAL(ctx.loader.LoadModel(TEST_RESOURCE_DIR "/invalid.gltf", ctx.loadResult), false);
131
132   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
133   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
134
135   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
136   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
137   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
138   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
139   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
140
141   DALI_TEST_EQUAL(0, ctx.cameras.size());
142   DALI_TEST_EQUAL(0, ctx.lights.size());
143   DALI_TEST_EQUAL(0, ctx.animations.size());
144   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
145
146   END_TEST;
147 }
148
149 int UtcDaliGltfLoaderSuccess1(void)
150 {
151   Context ctx;
152
153   LoadSceneMetadata(TEST_RESOURCE_DIR "/AnimatedCube.metadata", ctx.metaData);
154
155   std::unordered_map<std::string, ImageMetadata> imageMetadataGroundTruth;
156   imageMetadataGroundTruth["AnimatedCube_BaseColor.png"]         = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::BOX_THEN_NEAREST};
157   imageMetadataGroundTruth["AnimatedCube_MetallicRoughness.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::NEAREST};
158
159   auto metaData = ctx.metaData.mImageMetadata.begin();
160   for(auto& groundTruth : imageMetadataGroundTruth)
161   {
162     DALI_TEST_EQUAL(groundTruth.first, metaData->first);
163     DALI_TEST_EQUAL(groundTruth.second.mMinSize, metaData->second.mMinSize);
164     DALI_TEST_EQUAL(groundTruth.second.mSamplingMode, metaData->second.mSamplingMode);
165     ++metaData;
166   }
167
168   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCube.gltf", ctx.loadResult);
169
170   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
171   DALI_TEST_EQUAL(9u, ctx.scene.GetNodeCount());
172
173   // Default envmap is used
174   DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size());
175
176   TestApplication app;
177
178   Customization::Choices choices;
179   for(auto iRoot : ctx.scene.GetRoots())
180   {
181     auto resourceRefs = ctx.resources.CreateRefCounter();
182     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
183     ctx.resources.mReferenceCounts = std::move(resourceRefs);
184     ctx.resources.CountEnvironmentReferences();
185     ctx.resources.LoadResources(ctx.pathProvider);
186   }
187
188   auto& materials = ctx.resources.mMaterials;
189   DALI_TEST_EQUAL(2u, materials.size());
190   const MaterialDefinition materialGroundTruth[]{
191     {
192       nullptr,
193       MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
194         MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
195         (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
196       0,
197       Color::WHITE,
198       1.f,
199       0.f,
200       Vector4(1.000, 0.766, 0.336, 1.0),
201       1.f,
202       1.f,
203       Vector3(0.2, 0.1, 0.0),
204       0.0f,
205       0.5f,
206       Vector3(0, 0, 1),
207       true,
208       false,
209       true,
210       false,
211       true,
212       true,
213       {
214         {
215           MaterialDefinition::ALBEDO,
216           {
217             "AnimatedCube_BaseColor.png",
218             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
219             ImageDimensions(256, 256),
220             SamplingMode::BOX_THEN_NEAREST,
221           },
222         },
223         {
224           MaterialDefinition::NORMAL,
225           {
226             "AnimatedCube_BaseColor.png",
227             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
228             ImageDimensions(256, 256),
229             SamplingMode::BOX_THEN_NEAREST,
230           },
231         },
232         {
233           MaterialDefinition::OCCLUSION,
234           {
235             "AnimatedCube_BaseColor.png",
236             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
237             ImageDimensions(256, 256),
238             SamplingMode::BOX_THEN_NEAREST,
239           },
240         },
241         {
242           MaterialDefinition::EMISSIVE,
243           {
244             "AnimatedCube_BaseColor.png",
245             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
246             ImageDimensions(256, 256),
247             SamplingMode::BOX_THEN_NEAREST,
248           },
249         },
250         {
251           MaterialDefinition::SPECULAR,
252           {
253             "AnimatedCube_BaseColor.png",
254             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
255             ImageDimensions(256, 256),
256             SamplingMode::BOX_THEN_NEAREST,
257           },
258         },
259         {
260           MaterialDefinition::SPECULAR_COLOR,
261           {
262             "AnimatedCube_BaseColor.png",
263             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
264             ImageDimensions(256, 256),
265             SamplingMode::BOX_THEN_NEAREST,
266           },
267         },
268       },
269     },
270     {
271       nullptr,
272       MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
273         MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION | MaterialDefinition::NORMAL |
274         MaterialDefinition::GLTF_CHANNELS,
275       0,
276       Color::WHITE,
277       1.f,
278       0.f,
279       Vector4(1.000, 0.766, 0.336, 1.0),
280       1.f,
281       1.f,
282       Vector3(0.2, 0.1, 0.0),
283       0.04f,
284       1.0f,
285       Vector3::ONE,
286       true,
287       true,
288       true,
289       false,
290       true,
291       false,
292       {
293         {
294           MaterialDefinition::ALBEDO,
295           {
296             "AnimatedCube_BaseColor.png",
297             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
298             ImageDimensions(256, 256),
299             SamplingMode::BOX_THEN_NEAREST,
300           },
301         },
302         {
303           MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
304           {
305             "AnimatedCube_MetallicRoughness.png",
306             SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
307             ImageDimensions(256, 256),
308             SamplingMode::NEAREST,
309           },
310         },
311         {
312           MaterialDefinition::NORMAL,
313           {
314             "AnimatedCube_BaseColor.png",
315             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
316             ImageDimensions(256, 256),
317             SamplingMode::BOX_THEN_NEAREST,
318           },
319         },
320         {
321           MaterialDefinition::OCCLUSION,
322           {
323             "AnimatedCube_BaseColor.png",
324             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
325             ImageDimensions(256, 256),
326             SamplingMode::BOX_THEN_NEAREST,
327           },
328         },
329         {
330           MaterialDefinition::EMISSIVE,
331           {
332             "AnimatedCube_BaseColor.png",
333             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
334             ImageDimensions(256, 256),
335             SamplingMode::BOX_THEN_NEAREST,
336           },
337         },
338       },
339     },
340   };
341
342   auto iMaterial = materials.begin();
343   auto iMetadata = ctx.metaData.mImageMetadata.begin();
344   for(auto& m : materialGroundTruth)
345   {
346     printf("material %ld\n", iMaterial - materials.begin());
347     auto& md = iMaterial->first;
348     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
349     DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
350     DALI_TEST_EQUAL(md.mColor, m.mColor);
351     DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
352     DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
353     DALI_TEST_EQUAL(md.mBaseColorFactor, m.mBaseColorFactor);
354     DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale);
355     DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength);
356     DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor);
357     DALI_TEST_EQUAL(md.mDielectricSpecular, m.mDielectricSpecular);
358     DALI_TEST_EQUAL(md.mSpecularFactor, m.mSpecularFactor);
359     DALI_TEST_EQUAL(md.mSpecularColorFactor, m.mSpecularColorFactor);
360     DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture);
361     DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture);
362     DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture);
363     DALI_TEST_EQUAL(md.mIsOpaque, m.mIsOpaque);
364     DALI_TEST_EQUAL(md.mIsMask, m.mIsMask);
365
366     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
367     auto iTexture = md.mTextureStages.begin();
368     for(auto& ts : m.mTextureStages)
369     {
370       printf("texture %ld\n", iTexture - md.mTextureStages.begin());
371       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
372       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
373       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
374       DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions);
375       DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode);
376
377       ++iTexture;
378     }
379     ++iMaterial;
380     ++iMetadata;
381   }
382
383   auto& meshes = ctx.resources.mMeshes;
384   DALI_TEST_EQUAL(2u, meshes.size());
385
386   using Blob     = MeshDefinition::Blob;
387   using Accessor = MeshDefinition::Accessor;
388   const MeshDefinition meshGroundTruth[]{
389     {
390       nullptr,
391       0,
392       Geometry::TRIANGLES,
393       "AnimatedCube.bin",
394       Accessor{Blob{0, 0}, {}},
395       Accessor{Blob{0, 0}, {}},
396       Accessor{Blob{0, 0}, {}},
397       Accessor{Blob{0, 0}, {}},
398       Accessor{Blob{0, 0}, {}},
399       Accessor{Blob{0, 0}, {}},
400     },
401     {
402       nullptr,
403       0,
404       Geometry::TRIANGLES,
405       "AnimatedCube.bin",
406       Accessor{Blob{0, 0}, {}},
407       Accessor{Blob{0, 0}, {}},
408       Accessor{Blob{0, 0}, {}},
409       Accessor{Blob{0, 0}, {}},
410       Accessor{Blob{0, 0}, {}},
411       Accessor{Blob{0, 0}, {}},
412     },
413   };
414
415   auto iMesh = meshes.begin();
416   for(auto& m : meshGroundTruth)
417   {
418     printf("mesh %ld\n", iMesh - meshes.begin());
419
420     auto& md = iMesh->first;
421     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
422     DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
423     for(auto mp : {
424           &MeshDefinition::mIndices,
425           &MeshDefinition::mPositions,
426           &MeshDefinition::mNormals,
427           &MeshDefinition::mTexCoords,
428           &MeshDefinition::mColors,
429           &MeshDefinition::mTangents,
430           &MeshDefinition::mJoints0,
431           &MeshDefinition::mWeights0})
432     {
433       DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
434       DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
435     }
436
437     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
438
439     ++iMesh;
440   }
441
442   DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
443   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
444
445   DALI_TEST_EQUAL(6u, ctx.cameras.size());
446   DALI_TEST_EQUAL(0u, ctx.lights.size());
447   DALI_TEST_EQUAL(1u, ctx.animations.size());
448   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
449
450   END_TEST;
451 }
452
453 int UtcDaliGltfLoaderSuccess2(void)
454 {
455   Context                 ctx;
456   ShaderDefinitionFactory sdf;
457   sdf.SetResources(ctx.resources);
458
459   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", ctx.loadResult);
460
461   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
462   DALI_TEST_EQUAL(1u, ctx.scene.GetNodeCount());
463
464   TestApplication app;
465
466   Customization::Choices choices;
467   for(auto iRoot : ctx.scene.GetRoots())
468   {
469     auto resourceRefs = ctx.resources.CreateRefCounter();
470     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
471     ctx.resources.mReferenceCounts = std::move(resourceRefs);
472     ctx.resources.LoadResources(ctx.pathProvider);
473   }
474
475   DALI_TEST_EQUAL(true, ctx.resources.mMeshes[0u].first.mPositions.IsDefined());
476   DALI_TEST_EQUAL(432, ctx.resources.mMeshes[0u].first.mPositions.mBlob.mLength);
477
478   END_TEST;
479 }
480
481 int UtcDaliGltfLoaderSuccessShort(void)
482 {
483   TestApplication app;
484
485   const std::string resourcePath = TEST_RESOURCE_DIR "/";
486   auto              pathProvider = [resourcePath](ResourceType::Value) {
487     return resourcePath;
488   };
489
490   Customization::Choices choices;
491   for(auto modelName : {
492         "2CylinderEngine",
493         "AnimatedMorphCube",
494         "AnimatedMorphCubeAnimateNonZeroFrame",
495         "AnimatedMorphSphere",
496         "AnimatedTriangle",
497         "BoxAnimated",
498         "CesiumMan",
499         "CesiumMilkTruck",
500         "EnvironmentTest",
501         "MetalRoughSpheres",
502         "MorphPrimitivesTest",
503         "MRendererTest",
504         "SimpleSparseAccessor",
505         "AnimatedCube",
506       })
507   {
508     Context ctx;
509
510     auto& resources = ctx.resources;
511     resources.mEnvironmentMaps.push_back({});
512
513     printf("%s\n", modelName);
514     ctx.loader.LoadModel(resourcePath + modelName + ".gltf", ctx.loadResult);
515     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
516
517     auto& scene = ctx.scene;
518     for(auto iRoot : scene.GetRoots())
519     {
520       struct Visitor : NodeDefinition::IVisitor
521       {
522         struct ResourceReceiver : IResourceReceiver
523         {
524           std::vector<bool> mCounts;
525
526           void Register(ResourceType::Value type, Index id) override
527           {
528             if(type == ResourceType::Mesh)
529             {
530               mCounts[id] = true;
531             }
532           }
533         } receiver;
534
535         void Start(NodeDefinition& n) override
536         {
537           for(auto& renderable : n.mRenderables)
538           {
539             renderable->RegisterResources(receiver);
540           }
541         }
542
543         void Finish(NodeDefinition& n) override
544         {
545         }
546       } visitor;
547       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
548
549       scene.Visit(iRoot, choices, visitor);
550       for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
551       {
552         if(visitor.receiver.mCounts[i0])
553         {
554           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath, resources.mBuffers);
555           DALI_TEST_CHECK(!raw.mAttribs.empty());
556
557           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
558           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
559         }
560       }
561     }
562   }
563
564   END_TEST;
565 }
566
567 int UtcDaliGltfLoaderMRendererTest(void)
568 {
569   Context ctx;
570
571   ShaderDefinitionFactory sdf;
572   sdf.SetResources(ctx.resources);
573   auto& resources = ctx.resources;
574
575   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/MRendererTest.gltf", ctx.loadResult);
576
577   auto& scene = ctx.scene;
578   auto& roots = scene.GetRoots();
579   DALI_TEST_EQUAL(roots.size(), 1u);
580   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
581   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
582
583   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
584
585   ViewProjection viewProjection;
586   Transforms     xforms{
587     MatrixStack{},
588     viewProjection};
589   NodeDefinition::CreateParams nodeParams{
590     resources,
591     xforms,
592   };
593
594   Customization::Choices choices;
595
596   TestApplication app;
597
598   Actor root = Actor::New();
599   SetActorCentered(root);
600   for(auto iRoot : roots)
601   {
602     auto resourceRefs = resources.CreateRefCounter();
603     scene.CountResourceRefs(iRoot, choices, resourceRefs);
604     ctx.resources.mReferenceCounts = std::move(resourceRefs);
605     ctx.resources.CountEnvironmentReferences();
606     ctx.resources.LoadResources(ctx.pathProvider);
607     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
608     {
609       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
610       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
611       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
612       root.Add(actor);
613     }
614   }
615
616   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
617   Actor child = root.GetChildAt(0);
618
619   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
620   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
621   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
622   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
623
624   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
625   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
626
627   END_TEST;
628 }
629
630 int UtcDaliGltfLoaderAnimationLoadingTest(void)
631 {
632   Context ctx;
633
634   auto& resources = ctx.resources;
635
636   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/CesiumMan_e.gltf", ctx.loadResult);
637
638   auto& scene = ctx.scene;
639   auto& roots = scene.GetRoots();
640   DALI_TEST_EQUAL(roots.size(), 1u);
641
642   ViewProjection viewProjection;
643   Transforms     xforms{
644     MatrixStack{},
645     viewProjection};
646   NodeDefinition::CreateParams nodeParams{
647     resources,
648     xforms,
649   };
650
651   Customization::Choices choices;
652
653   TestApplication app;
654
655   Actor root = Actor::New();
656   SetActorCentered(root);
657   for(auto iRoot : roots)
658   {
659     auto resourceRefs = resources.CreateRefCounter();
660     scene.CountResourceRefs(iRoot, choices, resourceRefs);
661     resources.mReferenceCounts = std::move(resourceRefs);
662     resources.CountEnvironmentReferences();
663     resources.LoadResources(ctx.pathProvider);
664     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
665     {
666       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
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(ctx.loadResult.mAnimationDefinitions.size(), 1u);
674   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].mProperties.size(), 57u);
675
676   uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[0].mNodeIndex)->mNodeId;
677   DALI_TEST_EQUAL(id, root.FindChildByName("Skeleton_torso_joint_1").GetProperty<int32_t>(Dali::Actor::Property::ID));
678
679   END_TEST;
680 }
681
682 int UtcDaliGltfLoaderImageFromBufferView(void)
683 {
684   Context ctx;
685
686   ShaderDefinitionFactory sdf;
687   sdf.SetResources(ctx.resources);
688   auto& resources = ctx.resources;
689
690   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", ctx.loadResult);
691
692   auto& scene = ctx.scene;
693   auto& roots = scene.GetRoots();
694   DALI_TEST_EQUAL(roots.size(), 1u);
695
696   ViewProjection viewProjection;
697   Transforms     xforms{
698     MatrixStack{},
699     viewProjection};
700   NodeDefinition::CreateParams nodeParams{
701     resources,
702     xforms,
703   };
704
705   Customization::Choices choices;
706
707   TestApplication app;
708
709   Actor root = Actor::New();
710   SetActorCentered(root);
711   for(auto iRoot : roots)
712   {
713     auto resourceRefs = resources.CreateRefCounter();
714     scene.CountResourceRefs(iRoot, choices, resourceRefs);
715     resources.mReferenceCounts = std::move(resourceRefs);
716     resources.CountEnvironmentReferences();
717     resources.LoadResources(ctx.pathProvider);
718     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
719     {
720       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
721       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
722       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
723       root.Add(actor);
724     }
725   }
726
727   DALI_TEST_CHECK(resources.mMaterials[0].second.GetTextureCount() > 1);
728   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetWidth(), 256);
729   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetHeight(), 256);
730
731   END_TEST;
732 }
733
734 int UtcDaliGltfLoaderUint8Indices(void)
735 {
736   Context ctx;
737
738   auto& resources = ctx.resources;
739
740   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AlphaBlendModeTest.gltf", ctx.loadResult);
741
742   auto& scene = ctx.scene;
743   auto& roots = scene.GetRoots();
744   DALI_TEST_EQUAL(roots.size(), 1u);
745
746   ViewProjection viewProjection;
747   Transforms     xforms{
748     MatrixStack{},
749     viewProjection};
750   NodeDefinition::CreateParams nodeParams{
751     resources,
752     xforms,
753   };
754
755   Customization::Choices choices;
756
757   TestApplication app;
758
759   Actor root = Actor::New();
760   SetActorCentered(root);
761   for(auto iRoot : roots)
762   {
763     auto resourceRefs = resources.CreateRefCounter();
764     scene.CountResourceRefs(iRoot, choices, resourceRefs);
765     resources.mReferenceCounts = std::move(resourceRefs);
766     resources.CountEnvironmentReferences();
767     resources.LoadResources(ctx.pathProvider);
768     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
769     {
770       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
771       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
772       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
773       root.Add(actor);
774     }
775   }
776
777   DALI_TEST_CHECK(root.FindChildByName("Bed"));
778   DALI_TEST_CHECK(root.FindChildByName("DecalBlend"));
779   DALI_TEST_CHECK(root.FindChildByName("DecalOpaque"));
780
781   END_TEST;
782 }