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