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