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