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