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