a40ccaca98df3b64f28fbb89e985e83adddeac1a
[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.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
620       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
621       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
622       root.Add(actor);
623     }
624   }
625
626   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
627   Actor child = root.GetChildAt(0);
628
629   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
630   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
631   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
632   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
633
634   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
635   DALI_TEST_EQUAL(child.GetRendererAt(0u).GetProperty<decltype(BlendMode::ON)>(Renderer::Property::BLEND_MODE), BlendMode::ON);
636
637   END_TEST;
638 }
639
640 int UtcDaliGltfLoaderAnimationLoadingTest(void)
641 {
642   TestApplication app;
643   Context ctx;
644
645   auto& resources = ctx.resources;
646
647   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/CesiumMan_e.gltf", ctx.loadResult);
648
649   auto& scene = ctx.scene;
650   auto& roots = scene.GetRoots();
651   DALI_TEST_EQUAL(roots.size(), 1u);
652
653   ViewProjection viewProjection;
654   Transforms     xforms{
655     MatrixStack{},
656     viewProjection};
657   NodeDefinition::CreateParams nodeParams{
658     resources,
659     xforms,
660   };
661
662   Customization::Choices choices;
663
664   Actor root = Actor::New();
665   SetActorCentered(root);
666   for(auto iRoot : roots)
667   {
668     auto resourceRefs = resources.CreateRefCounter();
669     scene.CountResourceRefs(iRoot, choices, resourceRefs);
670     resources.mReferenceCounts = std::move(resourceRefs);
671     resources.CountEnvironmentReferences();
672     resources.LoadResources(ctx.pathProvider);
673     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
674     {
675       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
676       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
677       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
678       root.Add(actor);
679     }
680   }
681
682   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions.size(), 1u);
683   DALI_TEST_EQUAL(ctx.loadResult.mAnimationDefinitions[0].GetPropertyCount(), 57u);
684
685   uint32_t id = ctx.loadResult.mScene.GetNode(ctx.loadResult.mAnimationDefinitions[0].GetPropertyAt(0).mNodeIndex)->mNodeId;
686   DALI_TEST_EQUAL(id, root.FindChildByName("Skeleton_torso_joint_1").GetProperty<int32_t>(Dali::Actor::Property::ID));
687
688   END_TEST;
689 }
690
691 int UtcDaliGltfLoaderImageFromBufferView(void)
692 {
693   Context ctx;
694
695   ShaderDefinitionFactory sdf;
696   sdf.SetResources(ctx.resources);
697   auto& resources = ctx.resources;
698
699   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/EnvironmentTest_b.gltf", ctx.loadResult);
700
701   auto& scene = ctx.scene;
702   auto& roots = scene.GetRoots();
703   DALI_TEST_EQUAL(roots.size(), 1u);
704
705   ViewProjection viewProjection;
706   Transforms     xforms{
707     MatrixStack{},
708     viewProjection};
709   NodeDefinition::CreateParams nodeParams{
710     resources,
711     xforms,
712   };
713
714   Customization::Choices choices;
715
716   TestApplication app;
717
718   Actor root = Actor::New();
719   SetActorCentered(root);
720   for(auto iRoot : roots)
721   {
722     auto resourceRefs = resources.CreateRefCounter();
723     scene.CountResourceRefs(iRoot, choices, resourceRefs);
724     resources.mReferenceCounts = std::move(resourceRefs);
725     resources.CountEnvironmentReferences();
726     resources.LoadResources(ctx.pathProvider);
727     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
728     {
729       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
730       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
731       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
732       root.Add(actor);
733     }
734   }
735
736   DALI_TEST_CHECK(resources.mMaterials[0].second.GetTextureCount() > 1);
737   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetWidth(), 256);
738   DALI_TEST_EQUAL(resources.mMaterials[0].second.GetTexture(0).GetHeight(), 256);
739
740   END_TEST;
741 }
742
743 int UtcDaliGltfLoaderUint8Indices(void)
744 {
745   Context ctx;
746
747   auto& resources = ctx.resources;
748
749   ctx.loader.LoadModel(TEST_RESOURCE_DIR "/AlphaBlendModeTest.gltf", ctx.loadResult);
750
751   auto& scene = ctx.scene;
752   auto& roots = scene.GetRoots();
753   DALI_TEST_EQUAL(roots.size(), 1u);
754
755   ViewProjection viewProjection;
756   Transforms     xforms{
757     MatrixStack{},
758     viewProjection};
759   NodeDefinition::CreateParams nodeParams{
760     resources,
761     xforms,
762   };
763
764   Customization::Choices choices;
765
766   TestApplication app;
767
768   Actor root = Actor::New();
769   SetActorCentered(root);
770   for(auto iRoot : roots)
771   {
772     auto resourceRefs = resources.CreateRefCounter();
773     scene.CountResourceRefs(iRoot, choices, resourceRefs);
774     resources.mReferenceCounts = std::move(resourceRefs);
775     resources.CountEnvironmentReferences();
776     resources.LoadResources(ctx.pathProvider);
777     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
778     {
779       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
780       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
781       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
782       root.Add(actor);
783     }
784   }
785
786   DALI_TEST_CHECK(root.FindChildByName("Bed"));
787   DALI_TEST_CHECK(root.FindChildByName("DecalBlend"));
788   DALI_TEST_CHECK(root.FindChildByName("DecalOpaque"));
789
790   END_TEST;
791 }