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