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