a6256f54b2e22e6779c29777544edc7cbd13c337
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene3d / utc-Dali-Gltf2Loader.cpp
1 /*
2  * Copyright (c) 2022 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/public-api/loader/gltf2-loader.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
81 struct ExceptionMessageStartsWith
82 {
83   const std::string_view expected;
84
85   bool operator()(const std::runtime_error& e)
86   {
87     const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
88     if(!success)
89     {
90       printf("Expected: %s, got: %s.\n", expected.data(), e.what());
91     }
92     return success;
93   }
94 };
95
96 } // namespace
97
98 int UtcDaliGltfLoaderFailedToLoad(void)
99 {
100   Context ctx;
101
102   ShaderDefinitionFactory sdf;
103   sdf.SetResources(ctx.resources);
104
105   DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
106                   std::runtime_error,
107                   ExceptionMessageStartsWith{"Failed to load"});
108
109   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
110   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
111
112   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
113   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
114   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
115   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
116   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
117
118   DALI_TEST_EQUAL(0, ctx.cameras.size());
119   DALI_TEST_EQUAL(0, ctx.lights.size());
120   DALI_TEST_EQUAL(0, ctx.animations.size());
121   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
122
123   END_TEST;
124 }
125
126 int UtcDaliGltfLoaderFailedToParse(void)
127 {
128   Context ctx;
129
130   ShaderDefinitionFactory sdf;
131   sdf.SetResources(ctx.resources);
132
133   DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
134                   std::runtime_error,
135                   ExceptionMessageStartsWith{"Failed to parse"});
136
137   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
138   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
139
140   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
141   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
142   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
143   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
144   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
145
146   DALI_TEST_EQUAL(0, ctx.cameras.size());
147   DALI_TEST_EQUAL(0, ctx.lights.size());
148   DALI_TEST_EQUAL(0, ctx.animations.size());
149   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
150
151   END_TEST;
152 }
153
154 int UtcDaliGltfLoaderSuccess1(void)
155 {
156   Context ctx;
157
158   LoadSceneMetadata(TEST_RESOURCE_DIR "/AnimatedCube.metadata", ctx.metaData);
159
160   std::unordered_map<std::string, ImageMetadata> imageMetadataGroundTruth;
161   imageMetadataGroundTruth["AnimatedCube_BaseColor.png"]         = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::BOX_THEN_NEAREST};
162   imageMetadataGroundTruth["AnimatedCube_MetallicRoughness.png"] = ImageMetadata{ImageDimensions(256, 256), Dali::SamplingMode::NEAREST};
163
164   auto metaData = ctx.metaData.mImageMetadata.begin();
165   for(auto& groundTruth : imageMetadataGroundTruth)
166   {
167     DALI_TEST_EQUAL(groundTruth.first, metaData->first);
168     DALI_TEST_EQUAL(groundTruth.second.mMinSize, metaData->second.mMinSize);
169     DALI_TEST_EQUAL(groundTruth.second.mSamplingMode, metaData->second.mSamplingMode);
170     ++metaData;
171   }
172
173   ShaderDefinitionFactory sdf;
174   sdf.SetResources(ctx.resources);
175
176   LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult);
177
178   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
179   DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount());
180
181   // Default envmap is used
182   DALI_TEST_EQUAL(1u, ctx.resources.mEnvironmentMaps.size());
183
184   TestApplication app;
185
186   Customization::Choices choices;
187   for(auto iRoot : ctx.scene.GetRoots())
188   {
189     auto resourceRefs = ctx.resources.CreateRefCounter();
190     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
191     ctx.resources.CountEnvironmentReferences(resourceRefs);
192     ctx.resources.LoadResources(resourceRefs, ctx.pathProvider);
193   }
194
195   auto& materials = ctx.resources.mMaterials;
196   DALI_TEST_EQUAL(2u, materials.size());
197   const MaterialDefinition materialGroundTruth[]{
198     {MaterialDefinition::ALBEDO | MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
199        MaterialDefinition::NORMAL | MaterialDefinition::SPECULAR | MaterialDefinition::SPECULAR_COLOR |
200        (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
201      0,
202      Color::WHITE,
203      1.f,
204      0.f,
205      Vector4(1.000, 0.766, 0.336, 1.0),
206      1.f,
207      1.f,
208      Vector3(0.2, 0.1, 0.0),
209      0.0f,
210      0.5f,
211      Vector3(0, 0, 1),
212      true,
213      false,
214      true,
215      false,
216      true,
217      true,
218      {
219        {MaterialDefinition::ALBEDO,
220         {"AnimatedCube_BaseColor.png",
221          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
222          ImageDimensions(256, 256),
223          SamplingMode::BOX_THEN_NEAREST}},
224        {MaterialDefinition::NORMAL,
225         {"AnimatedCube_BaseColor.png",
226          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
227          ImageDimensions(256, 256),
228          SamplingMode::BOX_THEN_NEAREST}},
229        {MaterialDefinition::OCCLUSION,
230         {"AnimatedCube_BaseColor.png",
231          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
232          ImageDimensions(256, 256),
233          SamplingMode::BOX_THEN_NEAREST}},
234        {MaterialDefinition::EMISSIVE,
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        {MaterialDefinition::SPECULAR,
240         {"AnimatedCube_BaseColor.png",
241          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
242          ImageDimensions(256, 256),
243          SamplingMode::BOX_THEN_NEAREST}},
244        {MaterialDefinition::SPECULAR_COLOR,
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     {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
251        MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
252        MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
253      0,
254      Color::WHITE,
255      1.f,
256      0.f,
257      Vector4(1.000, 0.766, 0.336, 1.0),
258      1.f,
259      1.f,
260      Vector3(0.2, 0.1, 0.0),
261      0.04f,
262      1.0f,
263      Vector3::ONE,
264      true,
265      true,
266      true,
267      false,
268      true,
269      false,
270      {
271        {MaterialDefinition::ALBEDO,
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        {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
277         {"AnimatedCube_MetallicRoughness.png",
278          SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
279          ImageDimensions(256, 256),
280          SamplingMode::NEAREST}},
281        {MaterialDefinition::NORMAL,
282         {"AnimatedCube_BaseColor.png",
283          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
284          ImageDimensions(256, 256),
285          SamplingMode::BOX_THEN_NEAREST}},
286        {MaterialDefinition::OCCLUSION,
287         {"AnimatedCube_BaseColor.png",
288          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
289          ImageDimensions(256, 256),
290          SamplingMode::BOX_THEN_NEAREST}},
291        {MaterialDefinition::EMISSIVE,
292         {"AnimatedCube_BaseColor.png",
293          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
294          ImageDimensions(256, 256),
295          SamplingMode::BOX_THEN_NEAREST}},
296      }},
297   };
298
299   auto iMaterial = materials.begin();
300   auto iMetadata = ctx.metaData.mImageMetadata.begin();
301   for(auto& m : materialGroundTruth)
302   {
303     printf("material %ld\n", iMaterial - materials.begin());
304     auto& md = iMaterial->first;
305     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
306     DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
307     DALI_TEST_EQUAL(md.mColor, m.mColor);
308     DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
309     DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
310     DALI_TEST_EQUAL(md.mBaseColorFactor, m.mBaseColorFactor);
311     DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale);
312     DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength);
313     DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor);
314     DALI_TEST_EQUAL(md.mDielectricSpecular, m.mDielectricSpecular);
315     DALI_TEST_EQUAL(md.mSpecularFactor, m.mSpecularFactor);
316     DALI_TEST_EQUAL(md.mSpecularColorFactor, m.mSpecularColorFactor);
317     DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture);
318     DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture);
319     DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture);
320     DALI_TEST_EQUAL(md.mIsOpaque, m.mIsOpaque);
321     DALI_TEST_EQUAL(md.mIsMask, m.mIsMask);
322
323     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
324     auto iTexture = md.mTextureStages.begin();
325     for(auto& ts : m.mTextureStages)
326     {
327       printf("texture %ld\n", iTexture - md.mTextureStages.begin());
328       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
329       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
330       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
331       DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions);
332       DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode);
333
334       ++iTexture;
335     }
336     ++iMaterial;
337     ++iMetadata;
338   }
339
340   auto& meshes = ctx.resources.mMeshes;
341   DALI_TEST_EQUAL(2u, meshes.size());
342
343   using Blob     = MeshDefinition::Blob;
344   using Accessor = MeshDefinition::Accessor;
345   const MeshDefinition meshGroundTruth[]{
346     {
347       0,
348       Geometry::TRIANGLES,
349       "AnimatedCube.bin",
350       Accessor{Blob{0, 0}, {}},
351       Accessor{Blob{0, 0}, {}},
352       Accessor{Blob{0, 0}, {}},
353       Accessor{Blob{0, 0}, {}},
354       Accessor{Blob{0, 0}, {}},
355       Accessor{Blob{0, 0}, {}},
356     },
357     {
358       0,
359       Geometry::TRIANGLES,
360       "AnimatedCube.bin",
361       Accessor{Blob{0, 0}, {}},
362       Accessor{Blob{0, 0}, {}},
363       Accessor{Blob{0, 0}, {}},
364       Accessor{Blob{0, 0}, {}},
365       Accessor{Blob{0, 0}, {}},
366       Accessor{Blob{0, 0}, {}},
367     },
368   };
369
370   auto iMesh = meshes.begin();
371   for(auto& m : meshGroundTruth)
372   {
373     printf("mesh %ld\n", iMesh - meshes.begin());
374
375     auto& md = iMesh->first;
376     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
377     DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
378     for(auto mp : {
379           &MeshDefinition::mIndices,
380           &MeshDefinition::mPositions,
381           &MeshDefinition::mNormals,
382           &MeshDefinition::mTexCoords,
383           &MeshDefinition::mColors,
384           &MeshDefinition::mTangents,
385           &MeshDefinition::mJoints0,
386           &MeshDefinition::mWeights0})
387     {
388       DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
389       DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
390     }
391
392     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
393
394     ++iMesh;
395   }
396
397   DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
398   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
399
400   DALI_TEST_EQUAL(3u, ctx.cameras.size());
401   DALI_TEST_EQUAL(0u, ctx.lights.size());
402   DALI_TEST_EQUAL(1u, ctx.animations.size());
403   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
404
405   END_TEST;
406 }
407
408 int UtcDaliGltfLoaderSuccess2(void)
409 {
410   Context ctx;
411   ShaderDefinitionFactory sdf;
412   sdf.SetResources(ctx.resources);
413
414   LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCubeStride.gltf", sdf, ctx.loadResult);
415
416   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
417   DALI_TEST_EQUAL(1u, ctx.scene.GetNodeCount());
418
419   TestApplication app;
420
421   Customization::Choices choices;
422   for(auto iRoot : ctx.scene.GetRoots())
423   {
424     auto resourceRefs = ctx.resources.CreateRefCounter();
425     ctx.scene.CountResourceRefs(iRoot, choices, resourceRefs);
426     ctx.resources.LoadResources(resourceRefs, ctx.pathProvider);
427   }
428
429   DALI_TEST_EQUAL(true, ctx.resources.mMeshes[0u].first.mPositions.IsDefined());
430   DALI_TEST_EQUAL(432, ctx.resources.mMeshes[0u].first.mPositions.mBlob.mLength);
431
432   END_TEST;
433 }
434
435 int UtcDaliGltfLoaderSuccessShort(void)
436 {
437   TestApplication app;
438
439   const std::string resourcePath = TEST_RESOURCE_DIR "/";
440   auto              pathProvider = [resourcePath](ResourceType::Value) {
441     return resourcePath;
442   };
443
444   Customization::Choices choices;
445   for(auto modelName : {
446         "2CylinderEngine",
447         "AnimatedMorphCube",
448         "AnimatedMorphSphere",
449         "AnimatedTriangle",
450         "BoxAnimated",
451         "CesiumMan",
452         "CesiumMilkTruck",
453         "EnvironmentTest",
454         "MetalRoughSpheres",
455         "MorphPrimitivesTest",
456         "MRendererTest",
457         "SimpleSparseAccessor",
458         "AnimatedCube",
459       })
460   {
461     Context ctx;
462
463     ShaderDefinitionFactory sdf;
464
465     auto& resources = ctx.resources;
466     resources.mEnvironmentMaps.push_back({});
467
468     sdf.SetResources(resources);
469
470     printf("%s\n", modelName);
471     LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
472     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
473
474     auto& scene = ctx.scene;
475     for(auto iRoot : scene.GetRoots())
476     {
477       struct Visitor : NodeDefinition::IVisitor
478       {
479         struct ResourceReceiver : IResourceReceiver
480         {
481           std::vector<bool> mCounts;
482
483           void Register(ResourceType::Value type, Index id) override
484           {
485             if(type == ResourceType::Mesh)
486             {
487               mCounts[id] = true;
488             }
489           }
490         } receiver;
491
492         void Start(NodeDefinition& n) override
493         {
494           for(auto& renderable : n.mRenderables)
495           {
496             renderable->RegisterResources(receiver);
497           }
498         }
499
500         void Finish(NodeDefinition& n) override
501         {
502         }
503       } visitor;
504       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
505
506       scene.Visit(iRoot, choices, visitor);
507       for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
508       {
509         if(visitor.receiver.mCounts[i0])
510         {
511           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
512           DALI_TEST_CHECK(!raw.mAttribs.empty());
513
514           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
515           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
516         }
517       }
518     }
519   }
520
521   END_TEST;
522 }
523
524 int UtcDaliGltfLoaderMRendererTest(void)
525 {
526   Context ctx;
527
528   ShaderDefinitionFactory sdf;
529   sdf.SetResources(ctx.resources);
530   auto& resources = ctx.resources;
531
532   LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult);
533
534   auto& scene = ctx.scene;
535   auto& roots = scene.GetRoots();
536   DALI_TEST_EQUAL(roots.size(), 1u);
537   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
538   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
539
540   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
541
542   ViewProjection viewProjection;
543   Transforms     xforms{
544     MatrixStack{},
545     viewProjection};
546   NodeDefinition::CreateParams nodeParams{
547     resources,
548     xforms,
549   };
550
551   Customization::Choices choices;
552
553   TestApplication app;
554
555   Actor root = Actor::New();
556   SetActorCentered(root);
557   for(auto iRoot : roots)
558   {
559     auto resourceRefs = resources.CreateRefCounter();
560     scene.CountResourceRefs(iRoot, choices, resourceRefs);
561     resources.CountEnvironmentReferences(resourceRefs);
562     resources.LoadResources(resourceRefs, ctx.pathProvider);
563     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
564     {
565       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
566       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
567       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
568       root.Add(actor);
569     }
570   }
571
572   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
573   Actor child = root.GetChildAt(0);
574
575   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
576   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
577   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
578   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
579
580   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
581   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
582
583   END_TEST;
584 }
585
586
587 int UtcDaliGltfLoaderAnimationLoadingTest(void)
588 {
589   Context ctx;
590
591   ShaderDefinitionFactory sdf;
592   sdf.SetResources(ctx.resources);
593   auto& resources = ctx.resources;
594
595   LoadGltfScene(TEST_RESOURCE_DIR "/BoxAnimated.gltf", sdf, ctx.loadResult);
596
597   auto& scene = ctx.scene;
598   auto& roots = scene.GetRoots();
599   DALI_TEST_EQUAL(roots.size(), 1u);
600
601   ViewProjection viewProjection;
602   Transforms     xforms{
603     MatrixStack{},
604     viewProjection};
605   NodeDefinition::CreateParams nodeParams{
606     resources,
607     xforms,
608   };
609
610   Customization::Choices choices;
611
612   TestApplication app;
613
614   Actor root = Actor::New();
615   SetActorCentered(root);
616   for(auto iRoot : roots)
617   {
618     auto resourceRefs = resources.CreateRefCounter();
619     scene.CountResourceRefs(iRoot, choices, resourceRefs);
620     resources.CountEnvironmentReferences(resourceRefs);
621     resources.LoadResources(resourceRefs, ctx.pathProvider);
622     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
623     {
624       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
625       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
626       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
627       root.Add(actor);
628     }
629   }
630
631   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
632   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].mProperties.size(), 2u);
633
634   uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[0].mNodeIndex)->mNodeId;
635   DALI_TEST_EQUAL(id, root.FindChildByName("node2").GetProperty<int32_t>(Dali::Actor::Property::ID));
636   uint32_t id2 = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].mProperties[1].mNodeIndex)->mNodeId;
637   DALI_TEST_EQUAL(id2, root.FindChildByName("node0").GetProperty<int32_t>(Dali::Actor::Property::ID));
638
639   END_TEST;
640 }