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