Texture size reduction on the fly for 3D model using metadata
[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      {
217        {MaterialDefinition::ALBEDO,
218         {"AnimatedCube_BaseColor.png",
219          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
220          ImageDimensions(256, 256),
221          SamplingMode::BOX_THEN_NEAREST}},
222        {MaterialDefinition::NORMAL,
223         {"AnimatedCube_BaseColor.png",
224          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
225          ImageDimensions(256, 256),
226          SamplingMode::BOX_THEN_NEAREST}},
227        {MaterialDefinition::OCCLUSION,
228         {"AnimatedCube_BaseColor.png",
229          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
230          ImageDimensions(256, 256),
231          SamplingMode::BOX_THEN_NEAREST}},
232        {MaterialDefinition::EMISSIVE,
233         {"AnimatedCube_BaseColor.png",
234          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
235          ImageDimensions(256, 256),
236          SamplingMode::BOX_THEN_NEAREST}},
237        {MaterialDefinition::SPECULAR,
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        {MaterialDefinition::SPECULAR_COLOR,
243         {"AnimatedCube_BaseColor.png",
244          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
245          ImageDimensions(256, 256),
246          SamplingMode::BOX_THEN_NEAREST}},
247      }},
248     {MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
249        MaterialDefinition::EMISSIVE | MaterialDefinition::OCCLUSION |
250        MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
251      0,
252      Color::WHITE,
253      1.f,
254      0.f,
255      Vector4(1.000, 0.766, 0.336, 1.0),
256      1.f,
257      1.f,
258      Vector3(0.2, 0.1, 0.0),
259      0.04f,
260      1.0f,
261      Vector3::ONE,
262      true,
263      true,
264      true,
265      false,
266      {
267        {MaterialDefinition::ALBEDO,
268         {"AnimatedCube_BaseColor.png",
269          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
270          ImageDimensions(256, 256),
271          SamplingMode::BOX_THEN_NEAREST}},
272        {MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
273         {"AnimatedCube_MetallicRoughness.png",
274          SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT),
275          ImageDimensions(256, 256),
276          SamplingMode::NEAREST}},
277        {MaterialDefinition::NORMAL,
278         {"AnimatedCube_BaseColor.png",
279          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
280          ImageDimensions(256, 256),
281          SamplingMode::BOX_THEN_NEAREST}},
282        {MaterialDefinition::OCCLUSION,
283         {"AnimatedCube_BaseColor.png",
284          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
285          ImageDimensions(256, 256),
286          SamplingMode::BOX_THEN_NEAREST}},
287        {MaterialDefinition::EMISSIVE,
288         {"AnimatedCube_BaseColor.png",
289          SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT),
290          ImageDimensions(256, 256),
291          SamplingMode::BOX_THEN_NEAREST}},
292      }},
293   };
294
295   auto iMaterial = materials.begin();
296   auto iMetadata = ctx.metaData.mImageMetadata.begin();
297   for(auto& m : materialGroundTruth)
298   {
299     printf("material %ld\n", iMaterial - materials.begin());
300     auto& md = iMaterial->first;
301     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
302     DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
303     DALI_TEST_EQUAL(md.mColor, m.mColor);
304     DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
305     DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
306     DALI_TEST_EQUAL(md.mBaseColorFactor, m.mBaseColorFactor);
307     DALI_TEST_EQUAL(md.mNormalScale, m.mNormalScale);
308     DALI_TEST_EQUAL(md.mOcclusionStrength, m.mOcclusionStrength);
309     DALI_TEST_EQUAL(md.mEmissiveFactor, m.mEmissiveFactor);
310     DALI_TEST_EQUAL(md.mDielectricSpecular, m.mDielectricSpecular);
311     DALI_TEST_EQUAL(md.mSpecularFactor, m.mSpecularFactor);
312     DALI_TEST_EQUAL(md.mSpecularColorFactor, m.mSpecularColorFactor);
313     DALI_TEST_EQUAL(md.mNeedAlbedoTexture, m.mNeedAlbedoTexture);
314     DALI_TEST_EQUAL(md.mNeedMetallicRoughnessTexture, m.mNeedMetallicRoughnessTexture);
315     DALI_TEST_EQUAL(md.mNeedNormalTexture, m.mNeedNormalTexture);
316
317     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
318     auto iTexture = md.mTextureStages.begin();
319     for(auto& ts : m.mTextureStages)
320     {
321       printf("texture %ld\n", iTexture - md.mTextureStages.begin());
322       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
323       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
324       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
325       DALI_TEST_EQUAL(iTexture->mTexture.mMinImageDimensions, ts.mTexture.mMinImageDimensions);
326       DALI_TEST_EQUAL(iTexture->mTexture.mSamplingMode, ts.mTexture.mSamplingMode);
327
328       ++iTexture;
329     }
330     ++iMaterial;
331     ++iMetadata;
332   }
333
334   auto& meshes = ctx.resources.mMeshes;
335   DALI_TEST_EQUAL(2u, meshes.size());
336
337   using Blob     = MeshDefinition::Blob;
338   using Accessor = MeshDefinition::Accessor;
339   const MeshDefinition meshGroundTruth[]{
340     {
341       0,
342       Geometry::TRIANGLES,
343       "AnimatedCube.bin",
344       Accessor{Blob{0, 0}, {}},
345       Accessor{Blob{0, 0}, {}},
346       Accessor{Blob{0, 0}, {}},
347       Accessor{Blob{0, 0}, {}},
348       Accessor{Blob{0, 0}, {}},
349       Accessor{Blob{0, 0}, {}},
350     },
351     {
352       0,
353       Geometry::TRIANGLES,
354       "AnimatedCube.bin",
355       Accessor{Blob{0, 0}, {}},
356       Accessor{Blob{0, 0}, {}},
357       Accessor{Blob{0, 0}, {}},
358       Accessor{Blob{0, 0}, {}},
359       Accessor{Blob{0, 0}, {}},
360       Accessor{Blob{0, 0}, {}},
361     },
362   };
363
364   auto iMesh = meshes.begin();
365   for(auto& m : meshGroundTruth)
366   {
367     printf("mesh %ld\n", iMesh - meshes.begin());
368
369     auto& md = iMesh->first;
370     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
371     DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
372     for(auto mp : {
373           &MeshDefinition::mIndices,
374           &MeshDefinition::mPositions,
375           &MeshDefinition::mNormals,
376           &MeshDefinition::mTexCoords,
377           &MeshDefinition::mColors,
378           &MeshDefinition::mTangents,
379           &MeshDefinition::mJoints0,
380           &MeshDefinition::mWeights0})
381     {
382       DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
383       DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
384     }
385
386     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
387
388     ++iMesh;
389   }
390
391   DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
392   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
393
394   DALI_TEST_EQUAL(3u, ctx.cameras.size());
395   DALI_TEST_EQUAL(0u, ctx.lights.size());
396   DALI_TEST_EQUAL(1u, ctx.animations.size());
397   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
398
399   END_TEST;
400 }
401
402 int UtcDaliGltfLoaderSuccessShort(void)
403 {
404   TestApplication app;
405
406   const std::string resourcePath = TEST_RESOURCE_DIR "/";
407   auto              pathProvider = [resourcePath](ResourceType::Value) {
408     return resourcePath;
409   };
410
411   Customization::Choices choices;
412   for(auto modelName : {
413         "2CylinderEngine",
414         "AnimatedMorphCube",
415         "AnimatedMorphSphere",
416         "AnimatedTriangle",
417         "BoxAnimated",
418         "CesiumMan",
419         "CesiumMilkTruck",
420         "EnvironmentTest",
421         "MetalRoughSpheres",
422         "MorphPrimitivesTest",
423         "MRendererTest",
424         "SimpleSparseAccessor",
425         "AnimatedCube",
426       })
427   {
428     Context ctx;
429
430     ShaderDefinitionFactory sdf;
431
432     auto& resources = ctx.resources;
433     resources.mEnvironmentMaps.push_back({});
434
435     sdf.SetResources(resources);
436
437     printf("%s\n", modelName);
438     LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
439     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
440
441     auto& scene = ctx.scene;
442     for(auto iRoot : scene.GetRoots())
443     {
444       struct Visitor : NodeDefinition::IVisitor
445       {
446         struct ResourceReceiver : IResourceReceiver
447         {
448           std::vector<bool> mCounts;
449
450           void Register(ResourceType::Value type, Index id) override
451           {
452             if(type == ResourceType::Mesh)
453             {
454               mCounts[id] = true;
455             }
456           }
457         } receiver;
458
459         void Start(NodeDefinition& n) override
460         {
461           for(auto& renderable : n.mRenderables)
462           {
463             renderable->RegisterResources(receiver);
464           }
465         }
466
467         void Finish(NodeDefinition& n) override
468         {
469         }
470       } visitor;
471       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
472
473       scene.Visit(iRoot, choices, visitor);
474       for(uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
475       {
476         if(visitor.receiver.mCounts[i0])
477         {
478           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
479           DALI_TEST_CHECK(!raw.mAttribs.empty());
480
481           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
482           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
483         }
484       }
485     }
486   }
487
488   END_TEST;
489 }
490
491 int UtcDaliGltfLoaderMRendererTest(void)
492 {
493   Context ctx;
494
495   ShaderDefinitionFactory sdf;
496   sdf.SetResources(ctx.resources);
497   auto& resources = ctx.resources;
498
499   LoadGltfScene(TEST_RESOURCE_DIR "/MRendererTest.gltf", sdf, ctx.loadResult);
500
501   auto& scene = ctx.scene;
502   auto& roots = scene.GetRoots();
503   DALI_TEST_EQUAL(roots.size(), 1u);
504   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mName, "RootNode");
505   DALI_TEST_EQUAL(scene.GetNode(roots[0])->mScale, Vector3(1.0f, 1.0f, 1.0f));
506
507   DALI_TEST_EQUAL(scene.GetNodeCount(), 1u);
508
509   ViewProjection viewProjection;
510   Transforms     xforms{
511     MatrixStack{},
512     viewProjection};
513   NodeDefinition::CreateParams nodeParams{
514     resources,
515     xforms,
516   };
517
518   Customization::Choices choices;
519
520   TestApplication app;
521
522   Actor root = Actor::New();
523   SetActorCentered(root);
524   for(auto iRoot : roots)
525   {
526     auto resourceRefs = resources.CreateRefCounter();
527     scene.CountResourceRefs(iRoot, choices, resourceRefs);
528     resources.CountEnvironmentReferences(resourceRefs);
529     resources.LoadResources(resourceRefs, ctx.pathProvider);
530     if(auto actor = scene.CreateNodes(iRoot, choices, nodeParams))
531     {
532       scene.ConfigureSkeletonJoints(iRoot, resources.mSkeletons, actor);
533       scene.ConfigureSkinningShaders(resources, actor, std::move(nodeParams.mSkinnables));
534       scene.ApplyConstraints(actor, std::move(nodeParams.mConstrainables));
535       root.Add(actor);
536     }
537   }
538
539   DALI_TEST_EQUAL(root.GetChildCount(), 1u);
540   Actor child = root.GetChildAt(0);
541
542   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::NAME).Get<std::string>(), "RootNode");
543   DALI_TEST_EQUAL(child.GetProperty(Actor::Property::SCALE).Get<Vector3>(), Vector3(1.0f, 1.0f, 1.0f));
544   DALI_TEST_EQUAL(child.GetRendererCount(), 1u);
545   DALI_TEST_EQUAL(child.GetRendererAt(0).GetTextures().GetTextureCount(), 4u);
546
547   END_TEST;
548 }