Refactoring ImageVisualShaderFactory::GetShader
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene-loader / utc-Dali-Gltf2Loader.cpp
1 /*
2  * Copyright (c) 2020 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-scene-loader/public-api/resource-bundle.h"
22 #include "dali-scene-loader/public-api/scene-definition.h"
23 #include "dali-scene-loader/public-api/load-result.h"
24 #include "dali-scene-loader/public-api/gltf2-loader.h"
25 #include "dali-scene-loader/public-api/shader-definition-factory.h"
26 #include <dali-test-suite-utils.h>
27 #include <string_view>
28
29 using namespace Dali;
30 using namespace Dali::SceneLoader;
31
32 #define DALI_TEST_THROW(expression, exception, predicate) \
33   {\
34     bool daliTestThrowSuccess__ = false;\
35     try\
36     {\
37       do { expression; } while(0);\
38       printf("No exception was thrown.\n");\
39     }\
40     catch (std::decay<exception>::type& ex)\
41     {\
42       daliTestThrowSuccess__ = predicate(ex);\
43     }\
44     catch (...)\
45     {\
46       printf("Wrong type of exception thrown.\n");\
47     }\
48     DALI_TEST_CHECK(daliTestThrowSuccess__);\
49   }
50
51 namespace
52 {
53 struct Context
54 {
55   ResourceBundle resources;
56   SceneDefinition scene;
57
58   std::vector<AnimationDefinition> animations;
59   std::vector<AnimationGroupDefinition> animationGroups;
60   std::vector<CameraParameters> cameras;
61   std::vector<LightParameters> lights;
62
63   LoadResult loadResult {
64     resources,
65     scene,
66     animations,
67     animationGroups,
68     cameras,
69     lights
70   };
71 };
72
73 struct ExceptionMessageStartsWith
74 {
75   const std::string_view expected;
76
77   bool operator()(const std::runtime_error& e)
78   {
79     const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
80     if (!success)
81     {
82       printf("Expected: %s, got: %s.\n", expected.data(), e.what());
83     }
84     return success;
85   }
86 };
87
88 }
89
90 int UtcDaliGltfLoaderFailedToLoad(void)
91 {
92   Context ctx;
93
94   ShaderDefinitionFactory sdf;
95   sdf.SetResources(ctx.resources);
96
97   DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
98     std::runtime_error,
99     ExceptionMessageStartsWith{"Failed to load"});
100
101   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
102   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
103
104   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
105   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
106   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
107   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
108   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
109
110   DALI_TEST_EQUAL(0, ctx.cameras.size());
111   DALI_TEST_EQUAL(0, ctx.lights.size());
112   DALI_TEST_EQUAL(0, ctx.animations.size());
113   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
114
115   END_TEST;
116 }
117
118 int UtcDaliGltfLoaderFailedToParse(void)
119 {
120   Context ctx;
121
122   ShaderDefinitionFactory sdf;
123   sdf.SetResources(ctx.resources);
124
125   DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
126     std::runtime_error,
127     ExceptionMessageStartsWith{"Failed to parse"});
128
129   DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
130   DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
131
132   DALI_TEST_EQUAL(0, ctx.resources.mEnvironmentMaps.size());
133   DALI_TEST_EQUAL(0, ctx.resources.mMaterials.size());
134   DALI_TEST_EQUAL(0, ctx.resources.mMeshes.size());
135   DALI_TEST_EQUAL(0, ctx.resources.mShaders.size());
136   DALI_TEST_EQUAL(0, ctx.resources.mSkeletons.size());
137
138   DALI_TEST_EQUAL(0, ctx.cameras.size());
139   DALI_TEST_EQUAL(0, ctx.lights.size());
140   DALI_TEST_EQUAL(0, ctx.animations.size());
141   DALI_TEST_EQUAL(0, ctx.animationGroups.size());
142
143   END_TEST;
144 }
145
146 int UtcDaliGltfLoaderSuccess1(void)
147 {
148   Context ctx;
149
150   ShaderDefinitionFactory sdf;
151   sdf.SetResources(ctx.resources);
152
153   LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult);
154
155   DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
156   DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount());
157
158   DALI_TEST_EQUAL(0u, ctx.resources.mEnvironmentMaps.size());
159
160   auto& materials = ctx.resources.mMaterials;
161   DALI_TEST_EQUAL(2u, materials.size());
162   const MaterialDefinition materialGroundTruth[] {
163     {
164       MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
165         MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
166         (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
167       0,
168       Vector4(1.f, .766f, .336f, 1.f),
169       1.f,
170       0.f,
171       {
172         { MaterialDefinition::ALBEDO,
173           { "AnimatedCube_BaseColor.png",
174             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
175         { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
176           { "AnimatedCube_MetallicRoughness.png",
177             SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
178         { MaterialDefinition::NORMAL,
179           { "AnimatedCube_BaseColor.png",
180             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
181       }
182     },
183     {
184       MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
185         MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
186       0,
187       Vector4(1.f, .766f, .336f, 1.f),
188       1.f,
189       0.f,
190       {
191         { MaterialDefinition::ALBEDO,
192           { "AnimatedCube_BaseColor.png",
193             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
194         { MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS | MaterialDefinition::GLTF_CHANNELS,
195           { "AnimatedCube_MetallicRoughness.png",
196             SamplerFlags::Encode(FilterMode::NEAREST_MIPMAP_LINEAR, FilterMode::NEAREST, WrapMode::CLAMP_TO_EDGE, WrapMode::MIRRORED_REPEAT) } },
197         { MaterialDefinition::NORMAL,
198           { "AnimatedCube_BaseColor.png",
199             SamplerFlags::Encode(FilterMode::LINEAR_MIPMAP_LINEAR, FilterMode::LINEAR, WrapMode::CLAMP_TO_EDGE, WrapMode::REPEAT) } },
200       }
201     },
202   };
203
204   auto iMaterial = materials.begin();
205   for (auto& m : materialGroundTruth)
206   {
207     printf("material %ld\n", iMaterial - materials.begin());
208     auto& md = iMaterial->first;
209     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
210     DALI_TEST_EQUAL(md.mEnvironmentIdx, m.mEnvironmentIdx);
211     DALI_TEST_EQUAL(md.mColor, m.mColor);
212     DALI_TEST_EQUAL(md.mMetallic, m.mMetallic);
213     DALI_TEST_EQUAL(md.mRoughness, m.mRoughness);
214
215     DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
216     auto iTexture = md.mTextureStages.begin();
217     for (auto& ts: m.mTextureStages)
218     {
219       printf("texture %ld\n", iTexture - md.mTextureStages.begin());
220       DALI_TEST_EQUAL(iTexture->mSemantic, ts.mSemantic);
221       DALI_TEST_EQUAL(iTexture->mTexture.mImageUri, ts.mTexture.mImageUri);
222       DALI_TEST_EQUAL(uint32_t(iTexture->mTexture.mSamplerFlags), uint32_t(ts.mTexture.mSamplerFlags)); // don't interpret it as a character
223       ++iTexture;
224     }
225     ++iMaterial;
226   }
227
228   auto& meshes = ctx.resources.mMeshes;
229   DALI_TEST_EQUAL(2u, meshes.size());
230
231   using Blob = MeshDefinition::Blob;
232   using Accessor = MeshDefinition::Accessor;
233   const MeshDefinition meshGroundTruth[] {
234     {
235       0,
236       Geometry::TRIANGLES,
237       "AnimatedCube.bin",
238       Accessor{ Blob{ 0, 0 }, {} },
239       Accessor{ Blob{ 0, 0 }, {} },
240       Accessor{ Blob{ 0, 0 }, {} },
241       Accessor{ Blob{ 0, 0 }, {} },
242       Accessor{ Blob{ 0, 0 }, {} },
243     },
244     {
245       0,
246       Geometry::TRIANGLES,
247       "AnimatedCube.bin",
248       Accessor{ Blob{ 0, 0 }, {} },
249       Accessor{ Blob{ 0, 0 }, {} },
250       Accessor{ Blob{ 0, 0 }, {} },
251       Accessor{ Blob{ 0, 0 }, {} },
252       Accessor{ Blob{ 0, 0 }, {} },
253     },
254   };
255
256   auto iMesh = meshes.begin();
257   for (auto& m : meshGroundTruth)
258   {
259     printf("mesh %ld\n", iMesh - meshes.begin());
260
261     auto& md = iMesh->first;
262     DALI_TEST_EQUAL(md.mFlags, m.mFlags);
263     DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
264     for (auto mp: {
265       &MeshDefinition::mIndices,
266       &MeshDefinition::mPositions,
267       &MeshDefinition::mNormals,
268       &MeshDefinition::mTexCoords,
269       &MeshDefinition::mTangents,
270       &MeshDefinition::mJoints0,
271       &MeshDefinition::mWeights0
272     })
273     {
274       DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
275       DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
276     }
277
278     DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
279
280     ++iMesh;
281   }
282
283   DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
284   DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
285
286   DALI_TEST_EQUAL(3u, ctx.cameras.size());
287   DALI_TEST_EQUAL(0u, ctx.lights.size());
288   DALI_TEST_EQUAL(1u, ctx.animations.size());
289   DALI_TEST_EQUAL(0u, ctx.animationGroups.size());
290
291   END_TEST;
292 }
293
294 int UtcDaliGltfLoaderSuccessShort(void)
295 {
296   TestApplication app;
297
298   const std::string resourcePath = TEST_RESOURCE_DIR "/";
299   auto pathProvider = [resourcePath](ResourceType::Value) {
300     return resourcePath;
301   };
302
303   Customization::Choices choices;
304   for (auto modelName : {
305     "2CylinderEngine",
306     "AnimatedMorphCube",
307     "AnimatedMorphSphere",
308     "AnimatedTriangle",
309     "BoxAnimated",
310     "CesiumMan",
311     "CesiumMilkTruck",
312     "EnvironmentTest",
313     "MetalRoughSpheres",
314     "MorphPrimitivesTest",
315     "SimpleSparseAccessor",
316   })
317   {
318     Context ctx;
319
320     ShaderDefinitionFactory sdf;
321
322     auto& resources = ctx.resources;
323     resources.mEnvironmentMaps.push_back({});
324
325     sdf.SetResources(resources);
326
327     printf("%s\n", modelName);
328     LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
329     DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
330
331     auto& scene = ctx.scene;
332     for (auto iRoot : scene.GetRoots())
333     {
334       struct Visitor: NodeDefinition::IVisitor
335       {
336         struct ResourceReceiver: IResourceReceiver
337         {
338           std::vector<bool> mCounts;
339
340           void Register(ResourceType::Value type, Index id) override
341           {
342             if (type == ResourceType::Mesh)
343             {
344               mCounts[id] = true;
345             }
346           }
347         } receiver;
348
349         void Start(NodeDefinition& n) override
350         {
351           if (n.mRenderable)
352           {
353             n.mRenderable->RegisterResources(receiver);
354           }
355         }
356
357         void Finish(NodeDefinition& n) override
358         {}
359       } visitor;
360       visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
361
362       scene.Visit(iRoot, choices, visitor);
363       for (uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
364       {
365         if (visitor.receiver.mCounts[i0])
366         {
367           auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
368           DALI_TEST_CHECK(!raw.mAttribs.empty());
369
370           resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
371           DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);
372         }
373       }
374     }
375   }
376
377   END_TEST;
378 }