2 * Copyright (c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 // Enable debug log for test coverage
19 #define DEBUG_ENABLED 1
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>
30 using namespace Dali::SceneLoader;
32 #define DALI_TEST_THROW(expression, exception, predicate) \
34 bool daliTestThrowSuccess__ = false;\
37 do { expression; } while(0);\
38 printf("No exception was thrown.\n");\
40 catch (std::decay<exception>::type& ex)\
42 daliTestThrowSuccess__ = predicate(ex);\
46 printf("Wrong type of exception thrown.\n");\
48 DALI_TEST_CHECK(daliTestThrowSuccess__);\
55 ResourceBundle resources;
56 SceneDefinition scene;
58 std::vector<AnimationDefinition> animations;
59 std::vector<AnimationGroupDefinition> animationGroups;
60 std::vector<CameraParameters> cameras;
61 std::vector<LightParameters> lights;
63 LoadResult loadResult {
73 struct ExceptionMessageStartsWith
75 const std::string_view expected;
77 bool operator()(const std::runtime_error& e)
79 const bool success = (0 == strncmp(e.what(), expected.data(), expected.size()));
82 printf("Expected: %s, got: %s.\n", expected.data(), e.what());
90 int UtcDaliGltfLoaderFailedToLoad(void)
94 ShaderDefinitionFactory sdf;
95 sdf.SetResources(ctx.resources);
97 DALI_TEST_THROW(LoadGltfScene("non-existent.gltf", sdf, ctx.loadResult),
99 ExceptionMessageStartsWith{"Failed to load"});
101 DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
102 DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
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());
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());
118 int UtcDaliGltfLoaderFailedToParse(void)
122 ShaderDefinitionFactory sdf;
123 sdf.SetResources(ctx.resources);
125 DALI_TEST_THROW(LoadGltfScene(TEST_RESOURCE_DIR "/invalid.gltf", sdf, ctx.loadResult),
127 ExceptionMessageStartsWith{"Failed to parse"});
129 DALI_TEST_EQUAL(0, ctx.scene.GetRoots().size());
130 DALI_TEST_EQUAL(0, ctx.scene.GetNodeCount());
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());
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());
146 int UtcDaliGltfLoaderSuccess1(void)
150 ShaderDefinitionFactory sdf;
151 sdf.SetResources(ctx.resources);
153 LoadGltfScene(TEST_RESOURCE_DIR "/AnimatedCube.gltf", sdf, ctx.loadResult);
155 DALI_TEST_EQUAL(1u, ctx.scene.GetRoots().size());
156 DALI_TEST_EQUAL(6u, ctx.scene.GetNodeCount());
158 DALI_TEST_EQUAL(0u, ctx.resources.mEnvironmentMaps.size());
160 auto& materials = ctx.resources.mMaterials;
161 DALI_TEST_EQUAL(2u, materials.size());
162 const MaterialDefinition materialGroundTruth[] {
164 MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
165 MaterialDefinition::NORMAL | MaterialDefinition::TRANSPARENCY | MaterialDefinition::GLTF_CHANNELS |
166 (0x80 << MaterialDefinition::ALPHA_CUTOFF_SHIFT),
168 Vector4(1.f, .766f, .336f, 1.f),
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) } },
184 MaterialDefinition::ALBEDO | MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS |
185 MaterialDefinition::NORMAL | MaterialDefinition::GLTF_CHANNELS,
187 Vector4(1.f, .766f, .336f, 1.f),
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) } },
204 auto iMaterial = materials.begin();
205 for (auto& m : materialGroundTruth)
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);
215 DALI_TEST_EQUAL(md.mTextureStages.size(), m.mTextureStages.size());
216 auto iTexture = md.mTextureStages.begin();
217 for (auto& ts: m.mTextureStages)
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
228 auto& meshes = ctx.resources.mMeshes;
229 DALI_TEST_EQUAL(2u, meshes.size());
231 using Blob = MeshDefinition::Blob;
232 using Accessor = MeshDefinition::Accessor;
233 const MeshDefinition meshGroundTruth[] {
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 }, {} },
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 }, {} },
256 auto iMesh = meshes.begin();
257 for (auto& m : meshGroundTruth)
259 printf("mesh %ld\n", iMesh - meshes.begin());
261 auto& md = iMesh->first;
262 DALI_TEST_EQUAL(md.mFlags, m.mFlags);
263 DALI_TEST_EQUAL(md.mPrimitiveType, m.mPrimitiveType);
265 &MeshDefinition::mIndices,
266 &MeshDefinition::mPositions,
267 &MeshDefinition::mNormals,
268 &MeshDefinition::mTexCoords,
269 &MeshDefinition::mTangents,
270 &MeshDefinition::mJoints0,
271 &MeshDefinition::mWeights0
274 DALI_TEST_EQUAL((md.*mp).IsDefined(), (m.*mp).IsDefined());
275 DALI_TEST_EQUAL((md.*mp).mBlob.IsDefined(), (m.*mp).mBlob.IsDefined());
278 DALI_TEST_EQUAL(md.mBlendShapeHeader.IsDefined(), m.mBlendShapeHeader.IsDefined());
283 DALI_TEST_EQUAL(2u, ctx.resources.mShaders.size());
284 DALI_TEST_EQUAL(0u, ctx.resources.mSkeletons.size());
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());
294 int UtcDaliGltfLoaderSuccessShort(void)
298 const std::string resourcePath = TEST_RESOURCE_DIR "/";
299 auto pathProvider = [resourcePath](ResourceType::Value) {
303 Customization::Choices choices;
304 for (auto modelName : {
307 "AnimatedMorphSphere",
314 "MorphPrimitivesTest",
315 "SimpleSparseAccessor",
320 ShaderDefinitionFactory sdf;
322 auto& resources = ctx.resources;
323 resources.mEnvironmentMaps.push_back({});
325 sdf.SetResources(resources);
327 printf("%s\n", modelName);
328 LoadGltfScene(resourcePath + modelName + ".gltf", sdf, ctx.loadResult);
329 DALI_TEST_CHECK(ctx.scene.GetNodeCount() > 0);
331 auto& scene = ctx.scene;
332 for (auto iRoot : scene.GetRoots())
334 struct Visitor: NodeDefinition::IVisitor
336 struct ResourceReceiver: IResourceReceiver
338 std::vector<bool> mCounts;
340 void Register(ResourceType::Value type, Index id) override
342 if (type == ResourceType::Mesh)
349 void Start(NodeDefinition& n) override
353 n.mRenderable->RegisterResources(receiver);
357 void Finish(NodeDefinition& n) override
360 visitor.receiver.mCounts.resize(resources.mMeshes.size(), false);
362 scene.Visit(iRoot, choices, visitor);
363 for (uint32_t i0 = 0, i1 = resources.mMeshes.size(); i0 < i1; ++i0)
365 if (visitor.receiver.mCounts[i0])
367 auto raw = resources.mMeshes[i0].first.LoadRaw(resourcePath);
368 DALI_TEST_CHECK(!raw.mAttribs.empty());
370 resources.mMeshes[i0].second = resources.mMeshes[i0].first.Load(std::move(raw));
371 DALI_TEST_CHECK(resources.mMeshes[i0].second.geometry);