Limited joint/weight attributes to 4 sets
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / loader / gltf2-util.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 // CLASS HEADER
19 #include <dali-scene3d/internal/loader/gltf2-util.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali-scene3d/public-api/loader/utils.h>
23 #include <dali/devel-api/scripting/scripting.h>
24 #include <dali/devel-api/threading/mutex.h>
25 #include <dali/integration-api/debug.h>
26 #include <limits> ///< for std::numeric_limits
27
28 using namespace Dali::Scene3D::Loader;
29
30 namespace Dali::Scene3D::Loader::Internal
31 {
32 namespace Gltf2Util
33 {
34 static constexpr std::string_view MRENDERER_MODEL_IDENTIFICATION = "M-Renderer";
35 static constexpr std::string_view POSITION_PROPERTY              = "position";
36 static constexpr std::string_view ORIENTATION_PROPERTY           = "orientation";
37 static constexpr std::string_view SCALE_PROPERTY                 = "scale";
38 static constexpr std::string_view BLEND_SHAPE_WEIGHTS_UNIFORM    = "uBlendShapeWeight";
39 static constexpr std::string_view ROOT_NODE_NAME                 = "RootNode";
40 static const Vector3              SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
41
42 static const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
43   Geometry::POINTS,
44   Geometry::LINES,
45   Geometry::LINE_LOOP,
46   Geometry::LINE_STRIP,
47   Geometry::TRIANGLES,
48   Geometry::TRIANGLE_STRIP,
49   Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
50
51 static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] =
52 {
53   {"NONE", gltf2::ExtensionFlags::NONE},
54   {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
55   {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
56   {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
57   {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
58 };
59 static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
60
61 std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
62 {
63   auto results = json::Read::Array<gltf2::Animation, json::ObjectReader<gltf2::Animation>::Read>(j);
64
65   for(auto& animation : results)
66   {
67     for(auto& channel : animation.mChannels)
68     {
69       channel.mSampler.UpdateVector(animation.mSamplers);
70     }
71   }
72
73   return results;
74 }
75
76 void ApplyAccessorMinMax(const gltf2::Accessor& accessor, float* values)
77 {
78   DALI_ASSERT_ALWAYS(accessor.mMax.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMax.size());
79   DALI_ASSERT_ALWAYS(accessor.mMin.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMin.size());
80   MeshDefinition::Blob::ApplyMinMax(accessor.mMin, accessor.mMax, accessor.mCount, values);
81 }
82
83 const json::Reader<gltf2::Buffer>& GetBufferReader()
84 {
85   static const auto BUFFER_READER = std::move(json::Reader<gltf2::Buffer>()
86                                                 .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::Buffer::mByteLength))
87                                                 .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Buffer::mUri)));
88   return BUFFER_READER;
89 }
90
91 const json::Reader<gltf2::BufferView>& GetBufferViewReader()
92 {
93   static const auto BUFFER_VIEW_READER = std::move(json::Reader<gltf2::BufferView>()
94                                                      .Register(*json::MakeProperty("buffer", gltf2::RefReader<gltf2::Document>::Read<gltf2::Buffer, &gltf2::Document::mBuffers>, &gltf2::BufferView::mBuffer))
95                                                      .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteOffset))
96                                                      .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteLength))
97                                                      .Register(*json::MakeProperty("byteStride", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteStride))
98                                                      .Register(*json::MakeProperty("target", json::Read::Number<uint32_t>, &gltf2::BufferView::mTarget)));
99   return BUFFER_VIEW_READER;
100 }
101
102 const json::Reader<gltf2::BufferViewClient>& GetBufferViewClientReader()
103 {
104   static const auto BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::BufferViewClient>()
105                                                             .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::BufferViewClient::mBufferView))
106                                                             .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferViewClient::mByteOffset)));
107   return BUFFER_VIEW_CLIENT_READER;
108 }
109
110 const json::Reader<gltf2::ComponentTypedBufferViewClient>& GetComponentTypedBufferViewClientReader()
111 {
112   static const auto COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::ComponentTypedBufferViewClient>()
113                                                                             .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, gltf2::Ref<gltf2::BufferView>>("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::ComponentTypedBufferViewClient::mBufferView))
114                                                                             .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::ComponentTypedBufferViewClient::mByteOffset))
115                                                                             .Register(*json::MakeProperty("componentType", json::Read::Enum<gltf2::Component::Type>, &gltf2::ComponentTypedBufferViewClient::mComponentType)));
116   return COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER;
117 }
118
119 const json::Reader<gltf2::Accessor::Sparse>& GetAccessorSparseReader()
120 {
121   static const auto ACCESSOR_SPARSE_READER = std::move(json::Reader<gltf2::Accessor::Sparse>()
122                                                          .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::Sparse::mCount))
123                                                          .Register(*json::MakeProperty("indices", json::ObjectReader<gltf2::ComponentTypedBufferViewClient>::Read, &gltf2::Accessor::Sparse::mIndices))
124                                                          .Register(*json::MakeProperty("values", json::ObjectReader<gltf2::BufferViewClient>::Read, &gltf2::Accessor::Sparse::mValues)));
125   return ACCESSOR_SPARSE_READER;
126 }
127
128 const json::Reader<gltf2::Accessor>& GetAccessorReader()
129 {
130   static const auto ACCESSOR_READER = std::move(json::Reader<gltf2::Accessor>()
131                                                   .Register(*new json::Property<gltf2::Accessor, gltf2::Ref<gltf2::BufferView>>("bufferView",
132                                                                                                                                 gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>,
133                                                                                                                                 &gltf2::Accessor::mBufferView))
134                                                   .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::Accessor::mByteOffset))
135                                                   .Register(*new json::Property<gltf2::Accessor, gltf2::Component::Type>("componentType",
136                                                                                                                          json::Read::Enum<gltf2::Component::Type>,
137                                                                                                                          &gltf2::Accessor::mComponentType))
138                                                   .Register(*new json::Property<gltf2::Accessor, std::string_view>("name", json::Read::StringView, &gltf2::Accessor::mName))
139                                                   .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::mCount))
140                                                   .Register(*json::MakeProperty("normalized", json::Read::Boolean, &gltf2::Accessor::mNormalized))
141                                                   .Register(*json::MakeProperty("type", gltf2::ReadStringEnum<gltf2::AccessorType>, &gltf2::Accessor::mType))
142                                                   .Register(*json::MakeProperty("min", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMin))
143                                                   .Register(*json::MakeProperty("max", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMax))
144                                                   .Register(*new json::Property<gltf2::Accessor, gltf2::Accessor::Sparse>("sparse", json::ObjectReader<gltf2::Accessor::Sparse>::Read, &gltf2::Accessor::SetSparse)));
145   return ACCESSOR_READER;
146 }
147
148 const json::Reader<gltf2::Image>& GetImageReader()
149 {
150   static const auto IMAGE_READER = std::move(json::Reader<gltf2::Image>()
151                                                .Register(*new json::Property<gltf2::Image, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
152                                                .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Image::mUri))
153                                                .Register(*json::MakeProperty("mimeType", json::Read::StringView, &gltf2::Image::mMimeType))
154                                                .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::Image::mBufferView)));
155   return IMAGE_READER;
156 }
157
158 const json::Reader<gltf2::Sampler>& GetSamplerReader()
159 {
160   static const auto SAMPLER_READER = std::move(json::Reader<gltf2::Sampler>()
161                                                  .Register(*json::MakeProperty("minFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMinFilter))
162                                                  .Register(*json::MakeProperty("magFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMagFilter))
163                                                  .Register(*json::MakeProperty("wrapS", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapS))
164                                                  .Register(*json::MakeProperty("wrapT", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapT)));
165   return SAMPLER_READER;
166 }
167
168 const json::Reader<gltf2::Texture>& GetTextureReader()
169 {
170   static const auto TEXURE_READER = std::move(json::Reader<gltf2::Texture>()
171                                                 .Register(*json::MakeProperty("source", gltf2::RefReader<gltf2::Document>::Read<gltf2::Image, &gltf2::Document::mImages>, &gltf2::Texture::mSource))
172                                                 .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Document>::Read<gltf2::Sampler, &gltf2::Document::mSamplers>, &gltf2::Texture::mSampler)));
173   return TEXURE_READER;
174 }
175
176 const json::Reader<gltf2::TextureInfo>& GetTextureInfoReader()
177 {
178   static const auto TEXURE_INFO_READER = std::move(json::Reader<gltf2::TextureInfo>()
179                                                      .Register(*json::MakeProperty("index", gltf2::RefReader<gltf2::Document>::Read<gltf2::Texture, &gltf2::Document::mTextures>, &gltf2::TextureInfo::mTexture))
180                                                      .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureInfo::mTexCoord))
181                                                      .Register(*json::MakeProperty("scale", json::Read::Number<float>, &gltf2::TextureInfo::mScale))
182                                                      .Register(*json::MakeProperty("strength", json::Read::Number<float>, &gltf2::TextureInfo::mStrength)));
183   return TEXURE_INFO_READER;
184 }
185
186 const json::Reader<gltf2::Material::Pbr>& GetMaterialPbrReader()
187 {
188   static const auto MATERIAL_PBR_READER = std::move(json::Reader<gltf2::Material::Pbr>()
189                                                       .Register(*json::MakeProperty("baseColorFactor", gltf2::ReadDaliVector<Vector4>, &gltf2::Material::Pbr::mBaseColorFactor))
190                                                       .Register(*json::MakeProperty("baseColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mBaseColorTexture))
191                                                       .Register(*json::MakeProperty("metallicFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mMetallicFactor))
192                                                       .Register(*json::MakeProperty("roughnessFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mRoughnessFactor))
193                                                       .Register(*json::MakeProperty("metallicRoughnessTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mMetallicRoughnessTexture)));
194   return MATERIAL_PBR_READER;
195 }
196
197 const json::Reader<gltf2::MaterialSpecular>& GetMaterialSpecularReader()
198 {
199   static const auto MATERIAL_SPECULAR_READER = std::move(json::Reader<gltf2::MaterialSpecular>()
200                                                            .Register(*json::MakeProperty("specularFactor", json::Read::Number<float>, &gltf2::MaterialSpecular::mSpecularFactor))
201                                                            .Register(*json::MakeProperty("specularTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularTexture))
202                                                            .Register(*json::MakeProperty("specularColorFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::MaterialSpecular::mSpecularColorFactor))
203                                                            .Register(*json::MakeProperty("specularColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularColorTexture)));
204   return MATERIAL_SPECULAR_READER;
205 }
206
207 const json::Reader<gltf2::MaterialIor>& GetMaterialIorReader()
208 {
209   static const auto MATERIAL_IOR_READER = std::move(json::Reader<gltf2::MaterialIor>()
210                                                       .Register(*json::MakeProperty("ior", json::Read::Number<float>, &gltf2::MaterialIor::mIor)));
211   return MATERIAL_IOR_READER;
212 }
213
214 const json::Reader<gltf2::MaterialExtensions>& GetMaterialExtensionsReader()
215 {
216   static const auto MATERIAL_EXTENSION_READER = std::move(json::Reader<gltf2::MaterialExtensions>()
217                                                             .Register(*json::MakeProperty("KHR_materials_ior", json::ObjectReader<gltf2::MaterialIor>::Read, &gltf2::MaterialExtensions::mMaterialIor))
218                                                             .Register(*json::MakeProperty("KHR_materials_specular", json::ObjectReader<gltf2::MaterialSpecular>::Read, &gltf2::MaterialExtensions::mMaterialSpecular)));
219   return MATERIAL_EXTENSION_READER;
220 }
221
222 const json::Reader<gltf2::Material>& GetMaterialReader()
223 {
224   static const auto MATERIAL_READER = std::move(json::Reader<gltf2::Material>()
225                                                   .Register(*new json::Property<gltf2::Material, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
226                                                   .Register(*json::MakeProperty("pbrMetallicRoughness", json::ObjectReader<gltf2::Material::Pbr>::Read, &gltf2::Material::mPbrMetallicRoughness))
227                                                   .Register(*json::MakeProperty("normalTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mNormalTexture))
228                                                   .Register(*json::MakeProperty("occlusionTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mOcclusionTexture))
229                                                   .Register(*json::MakeProperty("emissiveTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mEmissiveTexture))
230                                                   .Register(*json::MakeProperty("emissiveFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::Material::mEmissiveFactor))
231                                                   .Register(*json::MakeProperty("alphaMode", gltf2::ReadStringEnum<gltf2::AlphaMode>, &gltf2::Material::mAlphaMode))
232                                                   .Register(*json::MakeProperty("alphaCutoff", json::Read::Number<float>, &gltf2::Material::mAlphaCutoff))
233                                                   .Register(*json::MakeProperty("doubleSided", json::Read::Boolean, &gltf2::Material::mDoubleSided))
234                                                   .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::MaterialExtensions>::Read, &gltf2::Material::mMaterialExtensions)));
235   return MATERIAL_READER;
236 }
237
238 std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
239 {
240   auto&                                                             jsonObject = json::Cast<json_object_s>(j);
241   std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> result;
242
243   auto element = jsonObject.start;
244   while(element)
245   {
246     auto jsonString = *element->name;
247
248     gltf2::Attribute::HashType hash = gltf2::Attribute::HashFromString(jsonString.string, jsonString.string_size);
249
250     result[hash] =
251       gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
252     element = element->next;
253   }
254   return result;
255 }
256
257 std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes2(const json_value_s& j)
258 {
259   auto&                                                         jsonObject = json::Cast<json_object_s>(j);
260   std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> result;
261
262   auto element = jsonObject.start;
263   while(element)
264   {
265     auto jsonString = *element->name;
266
267     result[gltf2::Attribute::TargetFromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
268
269     element = element->next;
270   }
271   return result;
272 }
273
274 std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> ReadMeshPrimitiveTargets(const json_value_s& j)
275 {
276   auto&                                                                      jsonObject = json::Cast<json_array_s>(j);
277   std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> result;
278
279   result.reserve(jsonObject.length);
280
281   auto element = jsonObject.start;
282   while(element)
283   {
284     result.push_back(std::move(ReadMeshPrimitiveAttributes2(*element->value)));
285     element = element->next;
286   }
287
288   return result;
289 }
290
291 const json::Reader<gltf2::Mesh::Primitive>& GetMeshPrimitiveReader()
292 {
293   static const auto MESH_PRIMITIVE_READER = std::move(json::Reader<gltf2::Mesh::Primitive>()
294                                                         .Register(*json::MakeProperty("attributes", ReadMeshPrimitiveAttributes, &gltf2::Mesh::Primitive::mAttributes))
295                                                         .Register(*json::MakeProperty("indices", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Mesh::Primitive::mIndices))
296                                                         .Register(*json::MakeProperty("material", gltf2::RefReader<gltf2::Document>::Read<gltf2::Material, &gltf2::Document::mMaterials>, &gltf2::Mesh::Primitive::mMaterial))
297                                                         .Register(*json::MakeProperty("mode", json::Read::Enum<gltf2::Mesh::Primitive::Mode>, &gltf2::Mesh::Primitive::mMode))
298                                                         .Register(*json::MakeProperty("targets", ReadMeshPrimitiveTargets, &gltf2::Mesh::Primitive::mTargets)));
299   return MESH_PRIMITIVE_READER;
300 }
301
302 const json::Reader<gltf2::Mesh::Extras>& GetMeshExtrasReader()
303 {
304   static const auto MESH_EXTRAS_READER = std::move(json::Reader<gltf2::Mesh::Extras>()
305                                                      .Register(*json::MakeProperty("targetNames", json::Read::Array<std::string_view, json::Read::StringView>, &gltf2::Mesh::Extras::mTargetNames)));
306   return MESH_EXTRAS_READER;
307 }
308
309 std::vector<std::string_view> ReadMeshExtensionsTargetsName(const json_value_s& j)
310 {
311   auto&                         jsonObject = json::Cast<json_object_s>(j);
312   std::vector<std::string_view> result;
313
314   auto element = jsonObject.start;
315   while(element)
316   {
317     auto     jsonString = *element->name;
318     uint32_t index      = json::Read::Number<uint32_t>(*element->value);
319
320     if(result.size() <= index)
321     {
322       DALI_ASSERT_ALWAYS(index < std::numeric_limits<uint32_t>::max());
323       result.resize(index + 1u);
324     }
325
326     result[index] = json::Read::StringView(jsonString);
327
328     element = element->next;
329   }
330   return result;
331 }
332
333 const json::Reader<gltf2::Mesh::Extensions>& GetMeshExtensionsReader()
334 {
335   static const auto MESH_EXTENSIONS_READER = std::move(json::Reader<gltf2::Mesh::Extensions>()
336                                                          .Register(*json::MakeProperty("SXR_targets_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mSXRTargetsNames))
337                                                          .Register(*json::MakeProperty("avatar_shape_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mAvatarShapeNames)));
338   return MESH_EXTENSIONS_READER;
339 }
340
341 const json::Reader<gltf2::Mesh>& GetMeshReader()
342 {
343   static const auto MESH_READER = std::move(json::Reader<gltf2::Mesh>()
344                                               .Register(*new json::Property<gltf2::Mesh, std::string_view>("name", json::Read::StringView, &gltf2::Mesh::mName))
345                                               .Register(*json::MakeProperty("primitives",
346                                                                             json::Read::Array<gltf2::Mesh::Primitive, json::ObjectReader<gltf2::Mesh::Primitive>::Read>,
347                                                                             &gltf2::Mesh::mPrimitives))
348                                               .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights))
349                                               .Register(*json::MakeProperty("extras", json::ObjectReader<gltf2::Mesh::Extras>::Read, &gltf2::Mesh::mExtras))
350                                               .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::Mesh::Extensions>::Read, &gltf2::Mesh::mExtensions)));
351   return MESH_READER;
352 }
353
354 const json::Reader<gltf2::Skin>& GetSkinReader()
355 {
356   static const auto SKIN_READER = std::move(json::Reader<gltf2::Skin>()
357                                               .Register(*new json::Property<gltf2::Skin, std::string_view>("name", json::Read::StringView, &gltf2::Skin::mName))
358                                               .Register(*json::MakeProperty("inverseBindMatrices",
359                                                                             gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>,
360                                                                             &gltf2::Skin::mInverseBindMatrices))
361                                               .Register(*json::MakeProperty("skeleton",
362                                                                             gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>,
363                                                                             &gltf2::Skin::mSkeleton))
364                                               .Register(*json::MakeProperty("joints",
365                                                                             json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
366                                                                             &gltf2::Skin::mJoints)));
367   return SKIN_READER;
368 }
369
370 const json::Reader<gltf2::Camera::Perspective>& GetCameraPerspectiveReader()
371 {
372   static const auto CAMERA_PERSPECTIVE_READER = std::move(json::Reader<gltf2::Camera::Perspective>()
373                                                             .Register(*json::MakeProperty("aspectRatio", json::Read::Number<float>, &gltf2::Camera::Perspective::mAspectRatio))
374                                                             .Register(*json::MakeProperty("yfov", json::Read::Number<float>, &gltf2::Camera::Perspective::mYFov))
375                                                             .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Perspective::mZFar))
376                                                             .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Perspective::mZNear))); // TODO: infinite perspective projection, where znear is omitted
377   return CAMERA_PERSPECTIVE_READER;
378 }
379
380 const json::Reader<gltf2::Camera::Orthographic>& GetCameraOrthographicReader()
381 {
382   static const auto CAMERA_ORTHOGRAPHIC_READER = std::move(json::Reader<gltf2::Camera::Orthographic>()
383                                                              .Register(*json::MakeProperty("xmag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mXMag))
384                                                              .Register(*json::MakeProperty("ymag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mYMag))
385                                                              .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZFar))
386                                                              .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZNear)));
387   return CAMERA_ORTHOGRAPHIC_READER;
388 }
389
390 const json::Reader<gltf2::Camera>& GetCameraReader()
391 {
392   static const auto CAMERA_READER = std::move(json::Reader<gltf2::Camera>()
393                                                 .Register(*new json::Property<gltf2::Camera, std::string_view>("name", json::Read::StringView, &gltf2::Camera::mName))
394                                                 .Register(*json::MakeProperty("type", json::Read::StringView, &gltf2::Camera::mType))
395                                                 .Register(*json::MakeProperty("perspective", json::ObjectReader<gltf2::Camera::Perspective>::Read, &gltf2::Camera::mPerspective))
396                                                 .Register(*json::MakeProperty("orthographic", json::ObjectReader<gltf2::Camera::Orthographic>::Read, &gltf2::Camera::mOrthographic)));
397   return CAMERA_READER;
398 }
399
400 const json::Reader<gltf2::Node>& GetNodeReader()
401 {
402   static const auto NODE_READER = std::move(json::Reader<gltf2::Node>()
403                                               .Register(*new json::Property<gltf2::Node, std::string_view>("name", json::Read::StringView, &gltf2::Node::mName))
404                                               .Register(*json::MakeProperty("translation", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mTranslation))
405                                               .Register(*json::MakeProperty("rotation", gltf2::ReadQuaternion, &gltf2::Node::mRotation))
406                                               .Register(*json::MakeProperty("scale", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mScale))
407                                               .Register(*new json::Property<gltf2::Node, Matrix>("matrix", gltf2::ReadDaliVector<Matrix>, &gltf2::Node::SetMatrix))
408                                               .Register(*json::MakeProperty("camera", gltf2::RefReader<gltf2::Document>::Read<gltf2::Camera, &gltf2::Document::mCameras>, &gltf2::Node::mCamera))
409                                               .Register(*json::MakeProperty("children", json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>, &gltf2::Node::mChildren))
410                                               .Register(*json::MakeProperty("mesh", gltf2::RefReader<gltf2::Document>::Read<gltf2::Mesh, &gltf2::Document::mMeshes>, &gltf2::Node::mMesh))
411                                               .Register(*json::MakeProperty("skin", gltf2::RefReader<gltf2::Document>::Read<gltf2::Skin, &gltf2::Document::mSkins>, &gltf2::Node::mSkin)));
412   return NODE_READER;
413 }
414
415 const json::Reader<gltf2::Animation::Sampler>& GetAnimationSamplerReader()
416 {
417   static const auto ANIMATION_SAMPLER_READER = std::move(json::Reader<gltf2::Animation::Sampler>()
418                                                            .Register(*json::MakeProperty("input", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mInput))
419                                                            .Register(*json::MakeProperty("output", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mOutput))
420                                                            .Register(*json::MakeProperty("interpolation", gltf2::ReadStringEnum<gltf2::Animation::Sampler::Interpolation>, &gltf2::Animation::Sampler::mInterpolation)));
421   return ANIMATION_SAMPLER_READER;
422 }
423
424 const json::Reader<gltf2::Animation::Channel::Target>& GetAnimationChannelTargetReader()
425 {
426   static const auto ANIMATION_TARGET_READER = std::move(json::Reader<gltf2::Animation::Channel::Target>()
427                                                           .Register(*json::MakeProperty("node", gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>, &gltf2::Animation::Channel::Target::mNode))
428                                                           .Register(*json::MakeProperty("path", gltf2::ReadStringEnum<gltf2::Animation::Channel::Target>, &gltf2::Animation::Channel::Target::mPath)));
429   return ANIMATION_TARGET_READER;
430 }
431
432 const json::Reader<gltf2::Animation::Channel>& GetAnimationChannelReader()
433 {
434   static const auto ANIMATION_CHANNEL_READER = std::move(json::Reader<gltf2::Animation::Channel>()
435                                                            .Register(*json::MakeProperty("target", json::ObjectReader<gltf2::Animation::Channel::Target>::Read, &gltf2::Animation::Channel::mTarget))
436                                                            .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Animation>::Read<gltf2::Animation::Sampler, &gltf2::Animation::mSamplers>, &gltf2::Animation::Channel::mSampler)));
437   return ANIMATION_CHANNEL_READER;
438 }
439
440 const json::Reader<gltf2::Animation>& GetAnimationReader()
441 {
442   static const auto ANIMATION_READER = std::move(json::Reader<gltf2::Animation>()
443                                                    .Register(*new json::Property<gltf2::Animation, std::string_view>("name", json::Read::StringView, &gltf2::Animation::mName))
444                                                    .Register(*json::MakeProperty("samplers",
445                                                                                  json::Read::Array<gltf2::Animation::Sampler, json::ObjectReader<gltf2::Animation::Sampler>::Read>,
446                                                                                  &gltf2::Animation::mSamplers))
447                                                    .Register(*json::MakeProperty("channels",
448                                                                                  json::Read::Array<gltf2::Animation::Channel, json::ObjectReader<gltf2::Animation::Channel>::Read>,
449                                                                                  &gltf2::Animation::mChannels)));
450   return ANIMATION_READER;
451 }
452
453 const json::Reader<gltf2::Scene>& GetSceneReader()
454 {
455   static const auto SCENE_READER = std::move(json::Reader<gltf2::Scene>()
456                                                .Register(*new json::Property<gltf2::Scene, std::string_view>("name", json::Read::StringView, &gltf2::Scene::mName))
457                                                .Register(*json::MakeProperty("nodes",
458                                                                              json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
459                                                                              &gltf2::Scene::mNodes)));
460   return SCENE_READER;
461 }
462
463 const json::Reader<gltf2::Document>& GetDocumentReader()
464 {
465   static const auto DOCUMENT_READER = std::move(json::Reader<gltf2::Document>()
466                                                   .Register(*json::MakeProperty("buffers",
467                                                                                 json::Read::Array<gltf2::Buffer, json::ObjectReader<gltf2::Buffer>::Read>,
468                                                                                 &gltf2::Document::mBuffers))
469                                                   .Register(*json::MakeProperty("bufferViews",
470                                                                                 json::Read::Array<gltf2::BufferView, json::ObjectReader<gltf2::BufferView>::Read>,
471                                                                                 &gltf2::Document::mBufferViews))
472                                                   .Register(*json::MakeProperty("accessors",
473                                                                                 json::Read::Array<gltf2::Accessor, json::ObjectReader<gltf2::Accessor>::Read>,
474                                                                                 &gltf2::Document::mAccessors))
475                                                   .Register(*json::MakeProperty("images",
476                                                                                 json::Read::Array<gltf2::Image, json::ObjectReader<gltf2::Image>::Read>,
477                                                                                 &gltf2::Document::mImages))
478                                                   .Register(*json::MakeProperty("samplers",
479                                                                                 json::Read::Array<gltf2::Sampler, json::ObjectReader<gltf2::Sampler>::Read>,
480                                                                                 &gltf2::Document::mSamplers))
481                                                   .Register(*json::MakeProperty("textures",
482                                                                                 json::Read::Array<gltf2::Texture, json::ObjectReader<gltf2::Texture>::Read>,
483                                                                                 &gltf2::Document::mTextures))
484                                                   .Register(*json::MakeProperty("materials",
485                                                                                 json::Read::Array<gltf2::Material, json::ObjectReader<gltf2::Material>::Read>,
486                                                                                 &gltf2::Document::mMaterials))
487                                                   .Register(*json::MakeProperty("meshes",
488                                                                                 json::Read::Array<gltf2::Mesh, json::ObjectReader<gltf2::Mesh>::Read>,
489                                                                                 &gltf2::Document::mMeshes))
490                                                   .Register(*json::MakeProperty("skins",
491                                                                                 json::Read::Array<gltf2::Skin, json::ObjectReader<gltf2::Skin>::Read>,
492                                                                                 &gltf2::Document::mSkins))
493                                                   .Register(*json::MakeProperty("cameras",
494                                                                                 json::Read::Array<gltf2::Camera, json::ObjectReader<gltf2::Camera>::Read>,
495                                                                                 &gltf2::Document::mCameras))
496                                                   .Register(*json::MakeProperty("nodes",
497                                                                                 json::Read::Array<gltf2::Node, json::ObjectReader<gltf2::Node>::Read>,
498                                                                                 &gltf2::Document::mNodes))
499                                                   .Register(*json::MakeProperty("animations",
500                                                                                 ReadAnimationArray,
501                                                                                 &gltf2::Document::mAnimations))
502                                                   .Register(*json::MakeProperty("extensionsRequired",
503                                                                                 json::Read::Array<std::string_view, json::Read::StringView>,
504                                                                                 &gltf2::Document::mExtensionsRequired))
505                                                   .Register(*json::MakeProperty("extensionsUsed",
506                                                                                 json::Read::Array<std::string_view, json::Read::StringView>,
507                                                                                 &gltf2::Document::mExtensionsUsed))
508                                                   .Register(*json::MakeProperty("scenes",
509                                                                                 json::Read::Array<gltf2::Scene, json::ObjectReader<gltf2::Scene>::Read>,
510                                                                                 &gltf2::Document::mScenes))
511                                                   .Register(*json::MakeProperty("scene", gltf2::RefReader<gltf2::Document>::Read<gltf2::Scene, &gltf2::Document::mScenes>, &gltf2::Document::mScene)));
512   return DOCUMENT_READER;
513 }
514
515 void ConvertBuffer(const gltf2::Buffer& buffer, decltype(ResourceBundle::mBuffers)& outBuffers, const std::string& resourcePath)
516 {
517   BufferDefinition bufferDefinition;
518
519   bufferDefinition.mResourcePath = resourcePath;
520   bufferDefinition.mUri          = buffer.mUri;
521   bufferDefinition.mByteLength   = buffer.mByteLength;
522
523   outBuffers.emplace_back(std::move(bufferDefinition));
524 }
525
526 void ConvertBuffers(const gltf2::Document& document, ConversionContext& context)
527 {
528   auto& outBuffers = context.mOutput.mResources.mBuffers;
529   outBuffers.reserve(document.mBuffers.size());
530
531   for(auto& buffer : document.mBuffers)
532   {
533     if(buffer.mUri.empty())
534     {
535       continue;
536     }
537     ConvertBuffer(buffer, outBuffers, context.mPath);
538   }
539 }
540
541 SamplerFlags::Type ConvertWrapMode(gltf2::Wrap::Type wrapMode)
542 {
543   switch(wrapMode)
544   {
545     case gltf2::Wrap::REPEAT:
546       return SamplerFlags::WRAP_REPEAT;
547     case gltf2::Wrap::CLAMP_TO_EDGE:
548       return SamplerFlags::WRAP_CLAMP;
549     case gltf2::Wrap::MIRRORED_REPEAT:
550       return SamplerFlags::WRAP_MIRROR;
551     default:
552       throw std::runtime_error("Invalid wrap type.");
553   }
554 }
555
556 SamplerFlags::Type ConvertSampler(const gltf2::Ref<gltf2::Sampler>& sampler)
557 {
558   if(sampler)
559   {
560     return ((sampler->mMinFilter < gltf2::Filter::NEAREST_MIPMAP_NEAREST) ? (sampler->mMinFilter - gltf2::Filter::NEAREST) : ((sampler->mMinFilter - gltf2::Filter::NEAREST_MIPMAP_NEAREST) + 2)) |
561            ((sampler->mMagFilter - gltf2::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) |
562            (ConvertWrapMode(sampler->mWrapS) << SamplerFlags::WRAP_S_SHIFT) |
563            (ConvertWrapMode(sampler->mWrapT) << SamplerFlags::WRAP_T_SHIFT);
564   }
565   else
566   {
567     // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#texturesampler
568     // "The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used."
569     // "What is an auto filtering", I hear you ask. Since there's nothing else to determine mipmapping from - including glTF image
570     // properties, if not in some extension -, we will simply assume linear filtering.
571     return SamplerFlags::FILTER_LINEAR | (SamplerFlags::FILTER_LINEAR << SamplerFlags::FILTER_MAG_SHIFT) |
572            (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_S_SHIFT) | (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_T_SHIFT);
573   }
574 }
575
576 TextureDefinition ConvertTextureInfo(const gltf2::TextureInfo& textureInfo, ConversionContext& context, const ImageMetadata& metaData = ImageMetadata())
577 {
578   TextureDefinition textureDefinition;
579   std::string       uri = std::string(textureInfo.mTexture->mSource->mUri);
580   if(uri.empty())
581   {
582     uint32_t bufferIndex = textureInfo.mTexture->mSource->mBufferView->mBuffer.GetIndex();
583     if(bufferIndex != INVALID_INDEX && context.mOutput.mResources.mBuffers[bufferIndex].IsAvailable())
584     {
585       auto& stream = context.mOutput.mResources.mBuffers[bufferIndex].GetBufferStream();
586       stream.clear();
587       stream.seekg(textureInfo.mTexture->mSource->mBufferView->mByteOffset, stream.beg);
588       std::vector<uint8_t> dataBuffer;
589       dataBuffer.resize(textureInfo.mTexture->mSource->mBufferView->mByteLength);
590       stream.read(reinterpret_cast<char*>(dataBuffer.data()), static_cast<std::streamsize>(static_cast<size_t>(textureInfo.mTexture->mSource->mBufferView->mByteLength)));
591       return TextureDefinition{std::move(dataBuffer), ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
592     }
593     return TextureDefinition();
594   }
595   else
596   {
597     return TextureDefinition{uri, ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode};
598   }
599 }
600
601 void AddTextureStage(uint32_t semantic, MaterialDefinition& materialDefinition, gltf2::TextureInfo textureInfo, const Dali::Scene3D::Loader::ImageMetadata& metaData, ConversionContext& context)
602 {
603   materialDefinition.mTextureStages.push_back({semantic, ConvertTextureInfo(textureInfo, context, metaData)});
604   materialDefinition.mFlags |= semantic;
605 }
606
607 void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<std::string, ImageMetadata>& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context)
608 {
609   auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info) {
610     if(!info.mTexture->mSource->mUri.empty())
611     {
612       if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end())
613       {
614         return search->second;
615       }
616     }
617     return ImageMetadata();
618   };
619
620   MaterialDefinition materialDefinition;
621
622   materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
623   materialDefinition.mShadowAvailable = true;
624
625   auto& pbr = material.mPbrMetallicRoughness;
626   if(material.mAlphaMode == gltf2::AlphaMode::BLEND)
627   {
628     materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::BLEND;
629     materialDefinition.mIsOpaque      = false;
630     materialDefinition.mFlags |= MaterialDefinition::TRANSPARENCY;
631   }
632   else if(material.mAlphaMode == gltf2::AlphaMode::MASK)
633   {
634     materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::MASK;
635     materialDefinition.mIsMask        = true;
636     materialDefinition.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff)));
637   }
638
639   materialDefinition.mBaseColorFactor = pbr.mBaseColorFactor;
640
641   materialDefinition.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!material.mNormalTexture + !!material.mOcclusionTexture + !!material.mEmissiveTexture);
642   if(pbr.mBaseColorTexture)
643   {
644     AddTextureStage(MaterialDefinition::ALBEDO, materialDefinition, pbr.mBaseColorTexture, getTextureMetaData(imageMetaData, pbr.mBaseColorTexture), context);
645   }
646   else
647   {
648     materialDefinition.mNeedAlbedoTexture = false;
649   }
650
651   materialDefinition.mMetallic  = pbr.mMetallicFactor;
652   materialDefinition.mRoughness = pbr.mRoughnessFactor;
653
654   if(pbr.mMetallicRoughnessTexture)
655   {
656     AddTextureStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS,
657                     materialDefinition,
658                     pbr.mMetallicRoughnessTexture,
659                     getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture),
660                     context);
661   }
662   else
663   {
664     materialDefinition.mNeedMetallicRoughnessTexture = false;
665   }
666
667   materialDefinition.mNormalScale = material.mNormalTexture.mScale;
668   if(material.mNormalTexture)
669   {
670     AddTextureStage(MaterialDefinition::NORMAL, materialDefinition, material.mNormalTexture, getTextureMetaData(imageMetaData, material.mNormalTexture), context);
671   }
672   else
673   {
674     materialDefinition.mNeedNormalTexture = false;
675   }
676
677   if(material.mOcclusionTexture)
678   {
679     AddTextureStage(MaterialDefinition::OCCLUSION, materialDefinition, material.mOcclusionTexture, getTextureMetaData(imageMetaData, material.mOcclusionTexture), context);
680     materialDefinition.mOcclusionStrength = material.mOcclusionTexture.mStrength;
681   }
682
683   materialDefinition.mEmissiveFactor = material.mEmissiveFactor;
684   if(material.mEmissiveTexture)
685   {
686     AddTextureStage(MaterialDefinition::EMISSIVE, materialDefinition, material.mEmissiveTexture, getTextureMetaData(imageMetaData, material.mEmissiveTexture), context);
687   }
688
689   if(!Dali::Equals(material.mMaterialExtensions.mMaterialIor.mIor, gltf2::UNDEFINED_FLOAT_VALUE))
690   {
691     materialDefinition.mIor                = material.mMaterialExtensions.mMaterialIor.mIor;
692     materialDefinition.mDielectricSpecular = powf((materialDefinition.mIor - 1.0f) / (materialDefinition.mIor + 1.0f), 2.0f);
693   }
694   materialDefinition.mSpecularFactor      = material.mMaterialExtensions.mMaterialSpecular.mSpecularFactor;
695   materialDefinition.mSpecularColorFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularColorFactor;
696
697   if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)
698   {
699     AddTextureStage(MaterialDefinition::SPECULAR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture), context);
700   }
701
702   if(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)
703   {
704     AddTextureStage(MaterialDefinition::SPECULAR_COLOR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture), context);
705   }
706
707   materialDefinition.mDoubleSided = material.mDoubleSided;
708
709   outMaterials.emplace_back(std::move(materialDefinition), TextureSet());
710 }
711
712 void ConvertMaterials(const gltf2::Document& document, ConversionContext& context)
713 {
714   auto& imageMetaData = context.mOutput.mSceneMetadata.mImageMetadata;
715
716   auto& outMaterials = context.mOutput.mResources.mMaterials;
717   outMaterials.reserve(document.mMaterials.size());
718
719   for(auto& material : document.mMaterials)
720   {
721     ConvertMaterial(material, imageMetaData, outMaterials, context);
722   }
723 }
724
725 MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gltf2::Accessor& accessor)
726 {
727   DALI_ASSERT_ALWAYS((accessor.mBufferView &&
728                       (accessor.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) ||
729                      (accessor.mSparse && !accessor.mBufferView));
730
731   DALI_ASSERT_ALWAYS(!accessor.mSparse ||
732                      ((accessor.mSparse->mIndices.mBufferView && (accessor.mSparse->mIndices.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) &&
733                       (accessor.mSparse->mValues.mBufferView && (accessor.mSparse->mValues.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max()))));
734
735   MeshDefinition::SparseBlob sparseBlob;
736   if(accessor.mSparse)
737   {
738     const gltf2::Accessor::Sparse&               sparse  = *accessor.mSparse;
739     const gltf2::ComponentTypedBufferViewClient& indices = sparse.mIndices;
740     const gltf2::BufferViewClient&               values  = sparse.mValues;
741
742     MeshDefinition::Blob indicesBlob(
743       indices.mBufferView->mByteOffset + indices.mByteOffset,
744       sparse.mCount * indices.GetBytesPerComponent(),
745       static_cast<uint16_t>(indices.mBufferView->mByteStride),
746       static_cast<uint16_t>(indices.GetBytesPerComponent()),
747       {},
748       {});
749     MeshDefinition::Blob valuesBlob(
750       values.mBufferView->mByteOffset + values.mByteOffset,
751       sparse.mCount * accessor.GetElementSizeBytes(),
752       static_cast<uint16_t>(values.mBufferView->mByteStride),
753       static_cast<uint16_t>(accessor.GetElementSizeBytes()),
754       {},
755       {});
756
757     sparseBlob = std::move(MeshDefinition::SparseBlob(std::move(indicesBlob), std::move(valuesBlob), accessor.mSparse->mCount));
758   }
759
760   uint32_t bufferViewOffset = 0u;
761   uint32_t bufferViewStride = 0u;
762   if(accessor.mBufferView)
763   {
764     bufferViewOffset = accessor.mBufferView->mByteOffset;
765     bufferViewStride = accessor.mBufferView->mByteStride;
766   }
767
768   return MeshDefinition::Accessor{
769     std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset,
770           accessor.GetBytesLength(),
771           static_cast<uint16_t>(bufferViewStride),
772           static_cast<uint16_t>(accessor.GetElementSizeBytes()),
773           accessor.mMin,
774           accessor.mMax}),
775       std::move(sparseBlob),
776       accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0,
777       accessor.mNormalized};
778 }
779
780 MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType attributeHash,
781                                                    MeshDefinition& meshDefinition,
782                                                    bool& needNormals, bool& needTangents)
783 {
784   MeshDefinition::Accessor* accessorDest{nullptr};
785
786   switch(gltf2::Attribute::TypeFromHash(attributeHash))
787   {
788     case gltf2::Attribute::POSITION:
789     {
790       accessorDest = &meshDefinition.mPositions;
791       break;
792     }
793     case gltf2::Attribute::NORMAL:
794     {
795       accessorDest = &meshDefinition.mNormals;
796       needNormals  = false;
797       break;
798     }
799     case gltf2::Attribute::TANGENT:
800     {
801       accessorDest = &meshDefinition.mTangents;
802       needTangents = false;
803       break;
804     }
805     case gltf2::Attribute::TEXCOORD_N:
806     {
807       meshDefinition.mTexCoords.emplace_back(MeshDefinition::Accessor{});
808       accessorDest = &meshDefinition.mTexCoords.back();
809       break;
810     }
811     case gltf2::Attribute::COLOR_N:
812     {
813       meshDefinition.mColors.emplace_back(MeshDefinition::Accessor{});
814       accessorDest = &meshDefinition.mColors.back();
815       break;
816     }
817     case gltf2::Attribute::JOINTS_N:
818     {
819       if(meshDefinition.mJoints.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
820       {
821         meshDefinition.mJoints.emplace_back(MeshDefinition::Accessor{});
822         accessorDest = &meshDefinition.mJoints.back();
823       }
824       break;
825     }
826     case gltf2::Attribute::WEIGHTS_N:
827     {
828       if(meshDefinition.mWeights.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
829       {
830         meshDefinition.mWeights.emplace_back(MeshDefinition::Accessor{});
831         accessorDest = &meshDefinition.mWeights.back();
832       }
833       break;
834     }
835     case gltf2::Attribute::INVALID:
836     {
837       accessorDest = nullptr;
838       break;
839     }
840   }
841   return accessorDest;
842 }
843
844 void SetFlagsFromComponentType(const gltf2::Accessor& accessor,
845                                gltf2::Attribute::HashType attributeHash,
846                                MeshDefinition& meshDefinition,
847                                bool isQuantized)
848 {
849   switch(gltf2::Attribute::TypeFromHash(attributeHash))
850   {
851     case gltf2::Attribute::POSITION:
852     {
853       if(isQuantized)
854       {
855         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
856         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
857         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
858         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
859       }
860       DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accessor.mComponentType == gltf2::Component::FLOAT);
861       break;
862     }
863     case gltf2::Attribute::NORMAL:
864     {
865       if(isQuantized)
866       {
867         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
868         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
869       }
870
871       DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || accessor.mComponentType == gltf2::Component::FLOAT);
872       break;
873     }
874     case gltf2::Attribute::TANGENT:
875     {
876       if(isQuantized)
877       {
878         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
879         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
880       }
881
882       DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || accessor.mComponentType == gltf2::Component::FLOAT);
883       break;
884     }
885     case gltf2::Attribute::TEXCOORD_N:
886     {
887       if(isQuantized)
888       {
889         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
890         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
891         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
892         meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
893       }
894       DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || accessor.mComponentType == gltf2::Component::FLOAT);
895       break;
896     }
897     case gltf2::Attribute::COLOR_N:
898     {
899       break;
900     }
901     case gltf2::Attribute::JOINTS_N:
902     {
903       meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
904       meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
905       DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) ||
906                         MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) ||
907                         accessor.mComponentType == gltf2::Component::FLOAT);
908       break;
909     }
910     case gltf2::Attribute::WEIGHTS_N:
911     {
912       meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
913       meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
914       DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) ||
915                         MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) ||
916                         accessor.mComponentType == gltf2::Component::FLOAT);
917
918       break;
919     }
920     case gltf2::Attribute::INVALID:
921     {
922       break;
923     }
924   }
925 }
926
927 void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
928 {
929   bool isQuantized = MaskMatch(document.mExtensionFlags, gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION);
930
931   uint32_t meshCount = 0;
932   context.mMeshIds.reserve(document.mMeshes.size());
933   for(auto& mesh : document.mMeshes)
934   {
935     context.mMeshIds.push_back(meshCount);
936     meshCount += mesh.mPrimitives.size();
937   }
938
939   auto& outMeshes = context.mOutput.mResources.mMeshes;
940   outMeshes.reserve(meshCount);
941   for(auto& mesh : document.mMeshes)
942   {
943     for(auto& primitive : mesh.mPrimitives)
944     {
945       MeshDefinition meshDefinition;
946
947       auto& attribs                 = primitive.mAttributes;
948       meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
949
950       auto positionIter = attribs.find(gltf2::Attribute::ToHash(gltf2::Attribute::POSITION, false, 0));
951       if(positionIter == attribs.end())
952       {
953         DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!");
954         continue;
955       }
956
957       auto& positionsAccessor = *positionIter->second;
958
959       // glTF2 support vector4 tangent for mesh.
960       // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
961       meshDefinition.mTangentType = Property::VECTOR4;
962
963       bool needNormals  = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
964       bool needTangents = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
965
966       for(const auto& [attributeHash, accessor] : attribs)
967       {
968         MeshDefinition::Accessor* accessorDest = GetAccessorFromAttribute(attributeHash, meshDefinition, needNormals, needTangents);
969         if(accessorDest == nullptr)
970         {
971           continue;
972         }
973         *accessorDest = ConvertMeshPrimitiveAccessor(*accessor);
974         SetFlagsFromComponentType(*accessor, attributeHash, meshDefinition, isQuantized);
975       }
976
977       if(needNormals)
978       {
979         meshDefinition.RequestNormals();
980       }
981       if(needTangents)
982       {
983         meshDefinition.RequestTangents();
984       }
985
986       if(primitive.mIndices)
987       {
988         meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices);
989         meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
990         meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_INDICES;
991         DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_INDICES) || primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_SHORT);
992       }
993
994       if(!primitive.mTargets.empty())
995       {
996         meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
997         meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
998         uint32_t blendShapeIndex          = 0u;
999         for(const auto& target : primitive.mTargets)
1000         {
1001           MeshDefinition::BlendShape blendShape;
1002
1003           auto endIt = target.end();
1004           auto it    = target.find(gltf2::Attribute::POSITION);
1005           if(it != endIt)
1006           {
1007             blendShape.deltas             = ConvertMeshPrimitiveAccessor(*it->second);
1008             blendShape.deltas.mNormalized = it->second->mNormalized;
1009
1010             if(isQuantized)
1011             {
1012               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
1013               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
1014             }
1015
1016             DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U16_POSITION))) || it->second->mComponentType == gltf2::Component::FLOAT);
1017           }
1018           it = target.find(gltf2::Attribute::NORMAL);
1019           if(it != endIt)
1020           {
1021             blendShape.normals             = ConvertMeshPrimitiveAccessor(*it->second);
1022             blendShape.normals.mNormalized = it->second->mNormalized;
1023
1024             if(isQuantized)
1025             {
1026               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
1027               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
1028             }
1029
1030             DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))) || it->second->mComponentType == gltf2::Component::FLOAT);
1031           }
1032           it = target.find(gltf2::Attribute::TANGENT);
1033           if(it != endIt)
1034           {
1035             blendShape.tangents             = ConvertMeshPrimitiveAccessor(*it->second);
1036             blendShape.tangents.mNormalized = it->second->mNormalized;
1037
1038             if(isQuantized)
1039             {
1040               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
1041               blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
1042             }
1043
1044             DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))) || it->second->mComponentType == gltf2::Component::FLOAT);
1045           }
1046
1047           if(!mesh.mWeights.empty())
1048           {
1049             blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
1050           }
1051
1052           // Get blendshape name from extras / SXR_targets_names / avatar_shape_names.
1053           if(blendShapeIndex < mesh.mExtras.mTargetNames.size())
1054           {
1055             blendShape.name = mesh.mExtras.mTargetNames[blendShapeIndex];
1056           }
1057           else if(blendShapeIndex < mesh.mExtensions.mSXRTargetsNames.size())
1058           {
1059             blendShape.name = mesh.mExtensions.mSXRTargetsNames[blendShapeIndex];
1060           }
1061           else if(blendShapeIndex < mesh.mExtensions.mAvatarShapeNames.size())
1062           {
1063             blendShape.name = mesh.mExtensions.mAvatarShapeNames[blendShapeIndex];
1064           }
1065
1066           meshDefinition.mBlendShapes.push_back(std::move(blendShape));
1067           ++blendShapeIndex;
1068         }
1069       }
1070
1071       outMeshes.push_back({std::move(meshDefinition), MeshGeometry{}});
1072     }
1073   }
1074 }
1075
1076 ModelRenderable* MakeModelRenderable(const gltf2::Mesh::Primitive& primitive, ConversionContext& context)
1077 {
1078   auto modelRenderable = new ModelRenderable();
1079
1080   auto materialIdx = primitive.mMaterial.GetIndex();
1081   if(INVALID_INDEX == materialIdx)
1082   {
1083     // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material
1084     if(INVALID_INDEX == context.mDefaultMaterial)
1085     {
1086       auto& outMaterials       = context.mOutput.mResources.mMaterials;
1087       context.mDefaultMaterial = outMaterials.size();
1088
1089       ConvertMaterial(gltf2::Material{}, context.mOutput.mSceneMetadata.mImageMetadata, outMaterials, context);
1090     }
1091
1092     materialIdx = context.mDefaultMaterial;
1093   }
1094
1095   modelRenderable->mMaterialIdx = materialIdx;
1096
1097   return modelRenderable;
1098 }
1099
1100 void ConvertCamera(const gltf2::Camera& camera, CameraParameters& cameraParameters)
1101 {
1102   cameraParameters.isPerspective = camera.mType.compare("perspective") == 0;
1103   if(cameraParameters.isPerspective)
1104   {
1105     auto& perspective = camera.mPerspective;
1106     if(!Dali::Equals(perspective.mYFov, gltf2::UNDEFINED_FLOAT_VALUE))
1107     {
1108       cameraParameters.yFovDegree = Degree(Radian(perspective.mYFov));
1109     }
1110     else
1111     {
1112       cameraParameters.yFovDegree = Degree(gltf2::UNDEFINED_FLOAT_VALUE);
1113     }
1114     cameraParameters.zNear = perspective.mZNear;
1115     cameraParameters.zFar  = perspective.mZFar;
1116     // TODO: yes, we seem to ignore aspectRatio in CameraParameters.
1117   }
1118   else
1119   {
1120     auto& ortho = camera.mOrthographic;
1121     if(!Dali::Equals(ortho.mYMag, gltf2::UNDEFINED_FLOAT_VALUE) && !Dali::Equals(ortho.mXMag, gltf2::UNDEFINED_FLOAT_VALUE))
1122     {
1123       cameraParameters.orthographicSize = ortho.mYMag * .5f;
1124       cameraParameters.aspectRatio      = ortho.mXMag / ortho.mYMag;
1125     }
1126     else
1127     {
1128       cameraParameters.orthographicSize = gltf2::UNDEFINED_FLOAT_VALUE;
1129       cameraParameters.aspectRatio      = gltf2::UNDEFINED_FLOAT_VALUE;
1130     }
1131     cameraParameters.zNear = ortho.mZNear;
1132     cameraParameters.zFar  = ortho.mZFar;
1133   }
1134
1135   cameraParameters.name = std::string(camera.mName);
1136 }
1137
1138 void ConvertNode(gltf2::Node const& node, const Index gltfIndex, Index parentIndex, ConversionContext& context, bool isMRendererModel)
1139 {
1140   auto& output    = context.mOutput;
1141   auto& scene     = output.mScene;
1142   auto& resources = output.mResources;
1143
1144   const auto index    = scene.GetNodeCount();
1145   auto       weakNode = scene.AddNode([&]() {
1146     std::unique_ptr<NodeDefinition> nodeDefinition{new NodeDefinition()};
1147
1148     nodeDefinition->mParentIdx = parentIndex;
1149     nodeDefinition->mName      = node.mName;
1150     if(nodeDefinition->mName.empty())
1151     {
1152       // TODO: Production quality generation of unique names.
1153       nodeDefinition->mName = std::to_string(reinterpret_cast<uintptr_t>(nodeDefinition.get()));
1154     }
1155
1156     if(!node.mSkin) // Nodes with skinned meshes are not supposed to have local transforms.
1157     {
1158       nodeDefinition->mPosition    = node.mTranslation;
1159       nodeDefinition->mOrientation = node.mRotation;
1160       nodeDefinition->mScale       = node.mScale;
1161
1162       if(isMRendererModel && node.mName == ROOT_NODE_NAME && node.mScale == SCALE_TO_ADJUST)
1163       {
1164         nodeDefinition->mScale *= 0.01f;
1165       }
1166     }
1167
1168     return nodeDefinition; }());
1169   if(!weakNode)
1170   {
1171     ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid.";
1172   }
1173
1174   context.mNodeIndices.RegisterMapping(gltfIndex, index);
1175
1176   Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX;
1177   if(node.mMesh)
1178   {
1179     auto&    mesh           = *node.mMesh;
1180     uint32_t primitiveCount = mesh.mPrimitives.size();
1181     auto     meshIndex      = context.mMeshIds[node.mMesh.GetIndex()];
1182     weakNode->mRenderables.reserve(primitiveCount);
1183     for(uint32_t i = 0; i < primitiveCount; ++i)
1184     {
1185       std::unique_ptr<NodeDefinition::Renderable> renderable;
1186       auto                                        modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context);
1187       modelRenderable->mMeshIdx                                   = meshIndex + i;
1188
1189       DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX ||
1190                         resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx);
1191       resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx = skeletonIdx;
1192
1193       renderable.reset(modelRenderable);
1194       weakNode->mRenderables.push_back(std::move(renderable));
1195     }
1196   }
1197
1198   if(node.mCamera)
1199   {
1200     CameraParameters cameraParameters;
1201     ConvertCamera(*node.mCamera, cameraParameters);
1202
1203     cameraParameters.matrix.SetTransformComponents(node.mScale, node.mRotation, node.mTranslation);
1204     output.mCameraParameters.push_back(cameraParameters);
1205   }
1206
1207   for(auto& child : node.mChildren)
1208   {
1209     ConvertNode(*child, child.GetIndex(), index, context, isMRendererModel);
1210   }
1211 }
1212
1213 void ConvertSceneNodes(const gltf2::Scene& scene, ConversionContext& context, bool isMRendererModel)
1214 {
1215   auto& outScene  = context.mOutput.mScene;
1216   Index rootIndex = outScene.GetNodeCount();
1217   switch(scene.mNodes.size())
1218   {
1219     case 0:
1220       break;
1221
1222     case 1:
1223       ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, context, isMRendererModel);
1224       outScene.AddRootNode(rootIndex);
1225       break;
1226
1227     default:
1228     {
1229       std::unique_ptr<NodeDefinition> sceneRoot{new NodeDefinition()};
1230       sceneRoot->mName = "GLTF_LOADER_SCENE_ROOT_" + std::to_string(outScene.GetRoots().size());
1231
1232       outScene.AddNode(std::move(sceneRoot));
1233       outScene.AddRootNode(rootIndex);
1234
1235       for(auto& node : scene.mNodes)
1236       {
1237         ConvertNode(*node, node.GetIndex(), rootIndex, context, isMRendererModel);
1238       }
1239       break;
1240     }
1241   }
1242 }
1243
1244 void ConvertNodes(const gltf2::Document& document, ConversionContext& context, bool isMRendererModel)
1245 {
1246   if(!document.mScenes.empty())
1247   {
1248     uint32_t rootSceneIndex = 0u;
1249     if(document.mScene)
1250     {
1251       rootSceneIndex = document.mScene.GetIndex();
1252     }
1253     ConvertSceneNodes(document.mScenes[rootSceneIndex], context, isMRendererModel);
1254
1255     for(uint32_t i = 0; i < rootSceneIndex; ++i)
1256     {
1257       ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1258     }
1259
1260     for(uint32_t i = rootSceneIndex + 1; i < document.mScenes.size(); ++i)
1261     {
1262       ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1263     }
1264   }
1265 }
1266
1267 template<typename T>
1268 void LoadDataFromAccessor(ConversionContext& context, uint32_t bufferIndex, Vector<T>& dataBuffer, uint32_t offset, uint32_t size)
1269 {
1270   if(bufferIndex >= context.mOutput.mResources.mBuffers.size())
1271   {
1272     DALI_LOG_ERROR("Invailid buffer index\n");
1273     return;
1274   }
1275
1276   auto& buffer = context.mOutput.mResources.mBuffers[bufferIndex];
1277   if(!buffer.IsAvailable())
1278   {
1279     DALI_LOG_ERROR("Failed to load from buffer stream.\n");
1280   }
1281   auto& stream = buffer.GetBufferStream();
1282   stream.clear();
1283   stream.seekg(offset, stream.beg);
1284   stream.read(reinterpret_cast<char*>(dataBuffer.Begin()), static_cast<std::streamsize>(static_cast<size_t>(size)));
1285 }
1286
1287 template<typename T>
1288 float LoadDataFromAccessors(ConversionContext& context, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector<float>& inputDataBuffer, Vector<T>& outputDataBuffer)
1289 {
1290   inputDataBuffer.Resize(input.mCount);
1291   outputDataBuffer.Resize(output.mCount);
1292
1293   const uint32_t inputDataBufferSize  = input.GetBytesLength();
1294   const uint32_t outputDataBufferSize = output.GetBytesLength();
1295
1296   LoadDataFromAccessor<float>(context, output.mBufferView->mBuffer.GetIndex(), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize);
1297   LoadDataFromAccessor<T>(context, output.mBufferView->mBuffer.GetIndex(), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize);
1298   ApplyAccessorMinMax(input, reinterpret_cast<float*>(inputDataBuffer.begin()));
1299   ApplyAccessorMinMax(output, reinterpret_cast<float*>(outputDataBuffer.begin()));
1300
1301   return inputDataBuffer[input.mCount - 1u];
1302 }
1303
1304 bool IsFirstFrameValueEmpty(const uint32_t inputCount, const Vector<float>& inputBuffer)
1305 {
1306   return (inputCount > 0 && !Dali::EqualsZero(inputBuffer[0]));
1307 }
1308
1309 template<typename T>
1310 float LoadKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, KeyFrames& keyFrames, gltf2::Animation::Channel::Target::Type type)
1311 {
1312   const gltf2::Accessor& input  = *channel.mSampler->mInput;
1313   const gltf2::Accessor& output = *channel.mSampler->mOutput;
1314
1315   Vector<float> inputDataBuffer;
1316   Vector<T>     outputDataBuffer;
1317
1318   const float duration = std::max(LoadDataFromAccessors<T>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1319
1320   if(IsFirstFrameValueEmpty(input.mCount, inputDataBuffer))
1321   {
1322     keyFrames.Add(0.0f, outputDataBuffer[0]);
1323   }
1324
1325   for(uint32_t i = 0; i < input.mCount; ++i)
1326   {
1327     keyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i]);
1328   }
1329
1330   return duration;
1331 }
1332
1333 float LoadBlendShapeKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, Index nodeIndex, uint32_t& propertyIndex, AnimationDefinition& animationDefinition)
1334 {
1335   const gltf2::Accessor& input  = *channel.mSampler->mInput;
1336   const gltf2::Accessor& output = *channel.mSampler->mOutput;
1337
1338   Vector<float> inputDataBuffer;
1339   Vector<float> outputDataBuffer;
1340
1341   const float duration = std::max(LoadDataFromAccessors<float>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1342
1343   char        weightNameBuffer[32];
1344   auto        prefixSize    = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.data());
1345   char* const pWeightName   = weightNameBuffer + prefixSize;
1346   const auto  remainingSize = sizeof(weightNameBuffer) - prefixSize;
1347   for(uint32_t weightIndex = 0u, endWeightIndex = channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount; weightIndex < endWeightIndex; ++weightIndex)
1348   {
1349     AnimatedProperty animatedProperty;
1350
1351     animatedProperty.mNodeIndex = nodeIndex;
1352     snprintf(pWeightName, remainingSize, "%d]", weightIndex);
1353     animatedProperty.mPropertyName = std::string(weightNameBuffer);
1354
1355     animatedProperty.mKeyFrames = KeyFrames::New();
1356
1357     if(IsFirstFrameValueEmpty(input.mCount, inputDataBuffer))
1358     {
1359       animatedProperty.mKeyFrames.Add(0.0f, outputDataBuffer[weightIndex]);
1360     }
1361
1362     for(uint32_t i = 0; i < input.mCount; ++i)
1363     {
1364       animatedProperty.mKeyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i * endWeightIndex + weightIndex]);
1365     }
1366
1367     animatedProperty.mTimePeriod = {0.f, duration};
1368
1369     animationDefinition.SetProperty(propertyIndex++, std::move(animatedProperty));
1370   }
1371
1372   return duration;
1373 }
1374
1375 template<typename T>
1376 float LoadAnimation(AnimationDefinition& animationDefinition, Index nodeIndex, Index propertyIndex, const std::string& propertyName, const gltf2::Animation::Channel& channel, ConversionContext& context)
1377 {
1378   AnimatedProperty animatedProperty;
1379   animatedProperty.mNodeIndex    = nodeIndex;
1380   animatedProperty.mPropertyName = propertyName;
1381
1382   animatedProperty.mKeyFrames  = KeyFrames::New();
1383   float duration               = LoadKeyFrames<T>(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
1384   animatedProperty.mTimePeriod = {0.f, duration};
1385
1386   animationDefinition.SetProperty(propertyIndex, std::move(animatedProperty));
1387   return duration;
1388 }
1389
1390 void ConvertAnimations(const gltf2::Document& document, ConversionContext& context)
1391 {
1392   auto& output = context.mOutput;
1393
1394   output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + document.mAnimations.size());
1395
1396   for(const auto& animation : document.mAnimations)
1397   {
1398     AnimationDefinition animationDefinition;
1399
1400     if(!animation.mName.empty())
1401     {
1402       animationDefinition.SetName(animation.mName.data());
1403     }
1404
1405     uint32_t numberOfProperties = 0u;
1406     for(const auto& channel : animation.mChannels)
1407     {
1408       if(channel.mTarget.mPath == gltf2::Animation::Channel::Target::WEIGHTS)
1409       {
1410         numberOfProperties += channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount;
1411       }
1412       else
1413       {
1414         numberOfProperties++;
1415       }
1416     }
1417     animationDefinition.ReserveSize(numberOfProperties);
1418
1419     Index propertyIndex = 0u;
1420     for(const auto& channel : animation.mChannels)
1421     {
1422       Index nodeIndex = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
1423       float duration  = 0.f;
1424
1425       switch(channel.mTarget.mPath)
1426       {
1427         case gltf2::Animation::Channel::Target::TRANSLATION:
1428         {
1429           duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, POSITION_PROPERTY.data(), channel, context);
1430           break;
1431         }
1432         case gltf2::Animation::Channel::Target::ROTATION:
1433         {
1434           duration = LoadAnimation<Quaternion>(animationDefinition, nodeIndex, propertyIndex, ORIENTATION_PROPERTY.data(), channel, context);
1435           break;
1436         }
1437         case gltf2::Animation::Channel::Target::SCALE:
1438         {
1439           duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, SCALE_PROPERTY.data(), channel, context);
1440           break;
1441         }
1442         case gltf2::Animation::Channel::Target::WEIGHTS:
1443         {
1444           duration = LoadBlendShapeKeyFrames(context, channel, nodeIndex, propertyIndex, animationDefinition);
1445
1446           break;
1447         }
1448         default:
1449         {
1450           // nothing to animate.
1451           break;
1452         }
1453       }
1454
1455       animationDefinition.SetDuration(std::max(duration, animationDefinition.GetDuration()));
1456
1457       ++propertyIndex;
1458     }
1459
1460     output.mAnimationDefinitions.push_back(std::move(animationDefinition));
1461   }
1462 }
1463
1464 void ProcessSkins(const gltf2::Document& document, ConversionContext& context)
1465 {
1466   // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices
1467   // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer,
1468   // otherwise we'll set identity matrices for inverse bind pose.
1469   struct IInverseBindMatrixProvider
1470   {
1471     virtual ~IInverseBindMatrixProvider()
1472     {
1473     }
1474     virtual void Provide(Matrix& inverseBindMatrix) = 0;
1475   };
1476
1477   struct InverseBindMatrixAccessor : public IInverseBindMatrixProvider
1478   {
1479     std::istream&  mStream;
1480     const uint32_t mElementSizeBytes;
1481
1482     InverseBindMatrixAccessor(const gltf2::Accessor& accessor, ConversionContext& context)
1483     : mStream(context.mOutput.mResources.mBuffers[accessor.mBufferView->mBuffer.GetIndex()].GetBufferStream()),
1484       mElementSizeBytes(accessor.GetElementSizeBytes())
1485     {
1486       DALI_ASSERT_DEBUG(accessor.mType == gltf2::AccessorType::MAT4 && accessor.mComponentType == gltf2::Component::FLOAT);
1487
1488       if(!mStream.rdbuf()->in_avail())
1489       {
1490         DALI_LOG_ERROR("Failed to load from stream\n");
1491       }
1492       mStream.clear();
1493       mStream.seekg(accessor.mBufferView->mByteOffset + accessor.mByteOffset, mStream.beg);
1494     }
1495
1496     virtual void Provide(Matrix& inverseBindMatrix) override
1497     {
1498       DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast<char*>(inverseBindMatrix.AsFloat()), static_cast<std::streamsize>(static_cast<size_t>(mElementSizeBytes))));
1499     }
1500   };
1501
1502   struct DefaultInverseBindMatrixProvider : public IInverseBindMatrixProvider
1503   {
1504     virtual void Provide(Matrix& inverseBindMatrix) override
1505     {
1506       inverseBindMatrix = Matrix::IDENTITY;
1507     }
1508   };
1509
1510   auto& resources = context.mOutput.mResources;
1511   resources.mSkeletons.reserve(document.mSkins.size());
1512
1513   for(auto& skin : document.mSkins)
1514   {
1515     std::unique_ptr<IInverseBindMatrixProvider> inverseBindMatrixProvider;
1516     if(skin.mInverseBindMatrices)
1517     {
1518       inverseBindMatrixProvider.reset(new InverseBindMatrixAccessor(*skin.mInverseBindMatrices, context));
1519     }
1520     else
1521     {
1522       inverseBindMatrixProvider.reset(new DefaultInverseBindMatrixProvider());
1523     }
1524
1525     SkeletonDefinition skeleton;
1526     if(skin.mSkeleton.GetIndex() != INVALID_INDEX)
1527     {
1528       skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(skin.mSkeleton.GetIndex());
1529     }
1530
1531     skeleton.mJoints.resize(skin.mJoints.size());
1532     auto iJoint = skeleton.mJoints.begin();
1533     for(auto& joint : skin.mJoints)
1534     {
1535       iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(joint.GetIndex());
1536
1537       inverseBindMatrixProvider->Provide(iJoint->mInverseBindMatrix);
1538
1539       ++iJoint;
1540     }
1541
1542     resources.mSkeletons.push_back(std::move(skeleton));
1543   }
1544 }
1545
1546 void SetObjectReaders()
1547 {
1548   json::SetObjectReader(GetBufferReader());
1549   json::SetObjectReader(GetBufferViewReader());
1550   json::SetObjectReader(GetBufferViewClientReader());
1551   json::SetObjectReader(GetComponentTypedBufferViewClientReader());
1552   json::SetObjectReader(GetAccessorSparseReader());
1553   json::SetObjectReader(GetAccessorReader());
1554   json::SetObjectReader(GetImageReader());
1555   json::SetObjectReader(GetSamplerReader());
1556   json::SetObjectReader(GetTextureReader());
1557   json::SetObjectReader(GetTextureInfoReader());
1558   json::SetObjectReader(GetMaterialPbrReader());
1559   json::SetObjectReader(GetMaterialSpecularReader());
1560   json::SetObjectReader(GetMaterialIorReader());
1561   json::SetObjectReader(GetMaterialExtensionsReader());
1562   json::SetObjectReader(GetMaterialReader());
1563   json::SetObjectReader(GetMeshPrimitiveReader());
1564   json::SetObjectReader(GetMeshExtrasReader());
1565   json::SetObjectReader(GetMeshExtensionsReader());
1566   json::SetObjectReader(GetMeshReader());
1567   json::SetObjectReader(GetSkinReader());
1568   json::SetObjectReader(GetCameraPerspectiveReader());
1569   json::SetObjectReader(GetCameraOrthographicReader());
1570   json::SetObjectReader(GetCameraReader());
1571   json::SetObjectReader(GetNodeReader());
1572   json::SetObjectReader(GetAnimationSamplerReader());
1573   json::SetObjectReader(GetAnimationChannelTargetReader());
1574   json::SetObjectReader(GetAnimationChannelReader());
1575   json::SetObjectReader(GetAnimationReader());
1576   json::SetObjectReader(GetSceneReader());
1577 }
1578
1579 void SetDefaultEnvironmentMap(const gltf2::Document& document, ConversionContext& context)
1580 {
1581   EnvironmentDefinition environmentDefinition;
1582   environmentDefinition.mUseBrdfTexture = true;
1583   environmentDefinition.mIblIntensity   = Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
1584   context.mOutput.mResources.mEnvironmentMaps.push_back({std::move(environmentDefinition), EnvironmentDefinition::Textures()});
1585 }
1586
1587 void InitializeGltfLoader()
1588 {
1589   static Dali::Mutex initializeMutex;
1590   // Set ObjectReader only once (for all gltf loading).
1591   static bool setObjectReadersRequired = true;
1592   {
1593     Mutex::ScopedLock lock(initializeMutex);
1594     if(setObjectReadersRequired)
1595     {
1596       // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.
1597       SetObjectReaders();
1598       setObjectReadersRequired = false;
1599     }
1600   }
1601 }
1602
1603 const std::string_view GetRendererModelIdentification()
1604 {
1605   return MRENDERER_MODEL_IDENTIFICATION;
1606 }
1607
1608 void ReadDocument(const json_object_s& jsonObject, gltf2::Document& document)
1609 {
1610   GetDocumentReader().Read(jsonObject, document);
1611 }
1612
1613 void ReadDocumentFromParsedData(const json_object_s& jsonObject, gltf2::Document& document)
1614 {
1615   static Dali::Mutex readMutex;
1616   Mutex::ScopedLock  lock(readMutex);
1617   gt::SetRefReaderObject(document);
1618   Gltf2Util::ReadDocument(jsonObject, document);
1619 }
1620
1621 bool GenerateDocument(json::unique_ptr& root, gt::Document& document, bool& isMRendererModel)
1622 {
1623   auto& rootObject = js::Cast<json_object_s>(*root);
1624   auto  jsonAsset  = js::FindObjectChild("asset", rootObject);
1625
1626   auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsonAsset));
1627   if(jsAssetVersion)
1628   {
1629     document.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
1630   }
1631
1632   auto jsAssetGenerator = js::FindObjectChild("generator", js::Cast<json_object_s>(*jsonAsset));
1633   if(jsAssetGenerator)
1634   {
1635     document.mAsset.mGenerator = js::Read::StringView(*jsAssetGenerator);
1636     isMRendererModel           = (document.mAsset.mGenerator.find(Gltf2Util::GetRendererModelIdentification().data()) != std::string_view::npos);
1637   }
1638
1639   Gltf2Util::InitializeGltfLoader();
1640   Gltf2Util::ReadDocumentFromParsedData(rootObject, document);
1641
1642   return true;
1643 }
1644
1645 void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
1646 {
1647   for(auto& extension : document.mExtensionsRequired)
1648   {
1649     gltf2::ExtensionFlags flag;
1650     if(Dali::Scripting::GetEnumeration<gltf2::ExtensionFlags>(extension.data(), EXTENSION_STRING_TABLE, EXTENSION_STRING_TABLE_COUNT, flag))
1651     {
1652       document.mExtensionFlags |= flag;
1653     }
1654     else
1655     {
1656       DALI_LOG_ERROR("Unsupported glTF extension required: %s\n", extension.data());
1657       DALI_ASSERT_DEBUG(false && "Unsupported glTF extension required");
1658     }
1659   }
1660
1661   Gltf2Util::ConvertBuffers(document, context);
1662   Gltf2Util::ConvertMaterials(document, context);
1663   Gltf2Util::ConvertMeshes(document, context);
1664   Gltf2Util::ConvertNodes(document, context, isMRendererModel);
1665   Gltf2Util::ConvertAnimations(document, context);
1666   Gltf2Util::ProcessSkins(document, context);
1667
1668   // Set Default Environment map
1669   Gltf2Util::SetDefaultEnvironmentMap(document, context);
1670 }
1671
1672 } // namespace Gltf2Util
1673
1674 } // namespace Dali::Scene3D::Loader::Internal