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