2 * Copyright (c) 2024 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 #include <dali-scene3d/internal/loader/gltf2-util.h>
22 #include <dali-scene3d/public-api/loader/utils.h>
23 #include <dali/devel-api/scripting/scripting.h>
24 #include <dali/devel-api/threading/mutex.h>
25 #include <dali/integration-api/debug.h>
26 #include <limits> ///< for std::numeric_limits
28 using namespace Dali::Scene3D::Loader;
30 namespace Dali::Scene3D::Loader::Internal
34 static constexpr std::string_view MRENDERER_MODEL_IDENTIFICATION = "M-Renderer";
35 static constexpr std::string_view POSITION_PROPERTY = "position";
36 static constexpr std::string_view ORIENTATION_PROPERTY = "orientation";
37 static constexpr std::string_view SCALE_PROPERTY = "scale";
38 static constexpr std::string_view BLEND_SHAPE_WEIGHTS_UNIFORM = "uBlendShapeWeight";
39 static constexpr std::string_view ROOT_NODE_NAME = "RootNode";
40 static const Vector3 SCALE_TO_ADJUST(100.0f, 100.0f, 100.0f);
42 static const Geometry::Type GLTF2_TO_DALI_PRIMITIVES[]{
48 Geometry::TRIANGLE_STRIP,
49 Geometry::TRIANGLE_FAN}; //...because Dali swaps the last two.
51 static const Dali::Scripting::StringEnum EXTENSION_STRING_TABLE[] =
53 {"NONE", gltf2::ExtensionFlags::NONE},
54 {"KHR_mesh_quantization", gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION},
55 {"KHR_texture_transform", gltf2::ExtensionFlags::KHR_TEXTURE_TRANSFORM},
56 {"KHR_materials_ior", gltf2::ExtensionFlags::KHR_MATERIALS_IOR},
57 {"KHR_materials_specular", gltf2::ExtensionFlags::KHR_MATERIALS_SPECULAR},
59 static const unsigned int EXTENSION_STRING_TABLE_COUNT = sizeof(EXTENSION_STRING_TABLE) / sizeof(EXTENSION_STRING_TABLE[0]);
61 std::vector<gltf2::Animation> ReadAnimationArray(const json_value_s& j)
63 auto results = json::Read::Array<gltf2::Animation, json::ObjectReader<gltf2::Animation>::Read>(j);
65 for(auto& animation : results)
67 for(auto& channel : animation.mChannels)
69 channel.mSampler.UpdateVector(animation.mSamplers);
76 void ApplyAccessorMinMax(const gltf2::Accessor& accessor, float* values)
78 DALI_ASSERT_ALWAYS(accessor.mMax.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMax.size());
79 DALI_ASSERT_ALWAYS(accessor.mMin.empty() || gltf2::AccessorType::ElementCount(accessor.mType) == accessor.mMin.size());
80 MeshDefinition::Blob::ApplyMinMax(accessor.mMin, accessor.mMax, accessor.mCount, values);
83 const json::Reader<gltf2::Buffer>& GetBufferReader()
85 static const auto BUFFER_READER = std::move(json::Reader<gltf2::Buffer>()
86 .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::Buffer::mByteLength))
87 .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Buffer::mUri)));
91 const json::Reader<gltf2::BufferView>& GetBufferViewReader()
93 static const auto BUFFER_VIEW_READER = std::move(json::Reader<gltf2::BufferView>()
94 .Register(*json::MakeProperty("buffer", gltf2::RefReader<gltf2::Document>::Read<gltf2::Buffer, &gltf2::Document::mBuffers>, &gltf2::BufferView::mBuffer))
95 .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteOffset))
96 .Register(*json::MakeProperty("byteLength", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteLength))
97 .Register(*json::MakeProperty("byteStride", json::Read::Number<uint32_t>, &gltf2::BufferView::mByteStride))
98 .Register(*json::MakeProperty("target", json::Read::Number<uint32_t>, &gltf2::BufferView::mTarget)));
99 return BUFFER_VIEW_READER;
102 const json::Reader<gltf2::BufferViewClient>& GetBufferViewClientReader()
104 static const auto BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::BufferViewClient>()
105 .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::BufferViewClient::mBufferView))
106 .Register(*json::MakeProperty("byteOffset", json::Read::Number<uint32_t>, &gltf2::BufferViewClient::mByteOffset)));
107 return BUFFER_VIEW_CLIENT_READER;
110 const json::Reader<gltf2::ComponentTypedBufferViewClient>& GetComponentTypedBufferViewClientReader()
112 static const auto COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER = std::move(json::Reader<gltf2::ComponentTypedBufferViewClient>()
113 .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, gltf2::Ref<gltf2::BufferView>>("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::ComponentTypedBufferViewClient::mBufferView))
114 .Register(*new json::Property<gltf2::ComponentTypedBufferViewClient, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::ComponentTypedBufferViewClient::mByteOffset))
115 .Register(*json::MakeProperty("componentType", json::Read::Enum<gltf2::Component::Type>, &gltf2::ComponentTypedBufferViewClient::mComponentType)));
116 return COMPONENT_TYPED_BUFFER_VIEW_CLIENT_READER;
119 const json::Reader<gltf2::Accessor::Sparse>& GetAccessorSparseReader()
121 static const auto ACCESSOR_SPARSE_READER = std::move(json::Reader<gltf2::Accessor::Sparse>()
122 .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::Sparse::mCount))
123 .Register(*json::MakeProperty("indices", json::ObjectReader<gltf2::ComponentTypedBufferViewClient>::Read, &gltf2::Accessor::Sparse::mIndices))
124 .Register(*json::MakeProperty("values", json::ObjectReader<gltf2::BufferViewClient>::Read, &gltf2::Accessor::Sparse::mValues)));
125 return ACCESSOR_SPARSE_READER;
128 const json::Reader<gltf2::Accessor>& GetAccessorReader()
130 static const auto ACCESSOR_READER = std::move(json::Reader<gltf2::Accessor>()
131 .Register(*new json::Property<gltf2::Accessor, gltf2::Ref<gltf2::BufferView>>("bufferView",
132 gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>,
133 &gltf2::Accessor::mBufferView))
134 .Register(*new json::Property<gltf2::Accessor, uint32_t>("byteOffset", json::Read::Number<uint32_t>, &gltf2::Accessor::mByteOffset))
135 .Register(*new json::Property<gltf2::Accessor, gltf2::Component::Type>("componentType",
136 json::Read::Enum<gltf2::Component::Type>,
137 &gltf2::Accessor::mComponentType))
138 .Register(*new json::Property<gltf2::Accessor, std::string_view>("name", json::Read::StringView, &gltf2::Accessor::mName))
139 .Register(*json::MakeProperty("count", json::Read::Number<uint32_t>, &gltf2::Accessor::mCount))
140 .Register(*json::MakeProperty("normalized", json::Read::Boolean, &gltf2::Accessor::mNormalized))
141 .Register(*json::MakeProperty("type", gltf2::ReadStringEnum<gltf2::AccessorType>, &gltf2::Accessor::mType))
142 .Register(*json::MakeProperty("min", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMin))
143 .Register(*json::MakeProperty("max", json::Read::Array<float, json::Read::Number>, &gltf2::Accessor::mMax))
144 .Register(*new json::Property<gltf2::Accessor, gltf2::Accessor::Sparse>("sparse", json::ObjectReader<gltf2::Accessor::Sparse>::Read, &gltf2::Accessor::SetSparse)));
145 return ACCESSOR_READER;
148 const json::Reader<gltf2::Image>& GetImageReader()
150 static const auto IMAGE_READER = std::move(json::Reader<gltf2::Image>()
151 .Register(*new json::Property<gltf2::Image, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
152 .Register(*json::MakeProperty("uri", json::Read::StringView, &gltf2::Image::mUri))
153 .Register(*json::MakeProperty("mimeType", json::Read::StringView, &gltf2::Image::mMimeType))
154 .Register(*json::MakeProperty("bufferView", gltf2::RefReader<gltf2::Document>::Read<gltf2::BufferView, &gltf2::Document::mBufferViews>, &gltf2::Image::mBufferView)));
158 const json::Reader<gltf2::Sampler>& GetSamplerReader()
160 static const auto SAMPLER_READER = std::move(json::Reader<gltf2::Sampler>()
161 .Register(*json::MakeProperty("minFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMinFilter))
162 .Register(*json::MakeProperty("magFilter", json::Read::Enum<gltf2::Filter::Type>, &gltf2::Sampler::mMagFilter))
163 .Register(*json::MakeProperty("wrapS", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapS))
164 .Register(*json::MakeProperty("wrapT", json::Read::Enum<gltf2::Wrap::Type>, &gltf2::Sampler::mWrapT)));
165 return SAMPLER_READER;
168 const json::Reader<gltf2::Texture>& GetTextureReader()
170 static const auto TEXURE_READER = std::move(json::Reader<gltf2::Texture>()
171 .Register(*json::MakeProperty("source", gltf2::RefReader<gltf2::Document>::Read<gltf2::Image, &gltf2::Document::mImages>, &gltf2::Texture::mSource))
172 .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Document>::Read<gltf2::Sampler, &gltf2::Document::mSamplers>, &gltf2::Texture::mSampler)));
173 return TEXURE_READER;
176 const json::Reader<gltf2::TextureTransform>& GetTextureTransformReader()
178 static const auto TEXURE_TRANSFORM_READER = std::move(json::Reader<gltf2::TextureTransform>()
179 .Register(*json::MakeProperty("rotation", json::Read::Number<float>, &gltf2::TextureTransform::mRotation))
180 .Register(*json::MakeProperty("offset", gltf2::ReadDaliVector<Vector2>, &gltf2::TextureTransform::mUvOffset))
181 .Register(*json::MakeProperty("scale", gltf2::ReadDaliVector<Vector2>, &gltf2::TextureTransform::mUvScale))
182 .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureTransform::mTexCoord)));
183 return TEXURE_TRANSFORM_READER;
186 const json::Reader<gltf2::TextureExtensions>& GetTextureExtensionsReader()
188 static const auto TEXTURE_EXTENSION_READER = std::move(json::Reader<gltf2::TextureExtensions>()
189 .Register(*json::MakeProperty("KHR_texture_transform", json::ObjectReader<gltf2::TextureTransform>::Read, &gltf2::TextureExtensions::mTextureTransform)));
190 return TEXTURE_EXTENSION_READER;
193 const json::Reader<gltf2::TextureInfo>& GetTextureInfoReader()
195 static const auto TEXURE_INFO_READER = std::move(json::Reader<gltf2::TextureInfo>()
196 .Register(*json::MakeProperty("index", gltf2::RefReader<gltf2::Document>::Read<gltf2::Texture, &gltf2::Document::mTextures>, &gltf2::TextureInfo::mTexture))
197 .Register(*json::MakeProperty("texCoord", json::Read::Number<uint32_t>, &gltf2::TextureInfo::mTexCoord))
198 .Register(*json::MakeProperty("scale", json::Read::Number<float>, &gltf2::TextureInfo::mScale))
199 .Register(*json::MakeProperty("strength", json::Read::Number<float>, &gltf2::TextureInfo::mStrength))
200 .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::TextureExtensions>::Read, &gltf2::TextureInfo::mTextureExtensions)));
201 return TEXURE_INFO_READER;
204 const json::Reader<gltf2::Material::Pbr>& GetMaterialPbrReader()
206 static const auto MATERIAL_PBR_READER = std::move(json::Reader<gltf2::Material::Pbr>()
207 .Register(*json::MakeProperty("baseColorFactor", gltf2::ReadDaliVector<Vector4>, &gltf2::Material::Pbr::mBaseColorFactor))
208 .Register(*json::MakeProperty("baseColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mBaseColorTexture))
209 .Register(*json::MakeProperty("metallicFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mMetallicFactor))
210 .Register(*json::MakeProperty("roughnessFactor", json::Read::Number<float>, &gltf2::Material::Pbr::mRoughnessFactor))
211 .Register(*json::MakeProperty("metallicRoughnessTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::Pbr::mMetallicRoughnessTexture)));
212 return MATERIAL_PBR_READER;
215 const json::Reader<gltf2::MaterialSpecular>& GetMaterialSpecularReader()
217 static const auto MATERIAL_SPECULAR_READER = std::move(json::Reader<gltf2::MaterialSpecular>()
218 .Register(*json::MakeProperty("specularFactor", json::Read::Number<float>, &gltf2::MaterialSpecular::mSpecularFactor))
219 .Register(*json::MakeProperty("specularTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularTexture))
220 .Register(*json::MakeProperty("specularColorFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::MaterialSpecular::mSpecularColorFactor))
221 .Register(*json::MakeProperty("specularColorTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::MaterialSpecular::mSpecularColorTexture)));
222 return MATERIAL_SPECULAR_READER;
225 const json::Reader<gltf2::MaterialIor>& GetMaterialIorReader()
227 static const auto MATERIAL_IOR_READER = std::move(json::Reader<gltf2::MaterialIor>()
228 .Register(*json::MakeProperty("ior", json::Read::Number<float>, &gltf2::MaterialIor::mIor)));
229 return MATERIAL_IOR_READER;
232 const json::Reader<gltf2::MaterialExtensions>& GetMaterialExtensionsReader()
234 static const auto MATERIAL_EXTENSION_READER = std::move(json::Reader<gltf2::MaterialExtensions>()
235 .Register(*json::MakeProperty("KHR_materials_ior", json::ObjectReader<gltf2::MaterialIor>::Read, &gltf2::MaterialExtensions::mMaterialIor))
236 .Register(*json::MakeProperty("KHR_materials_specular", json::ObjectReader<gltf2::MaterialSpecular>::Read, &gltf2::MaterialExtensions::mMaterialSpecular)));
237 return MATERIAL_EXTENSION_READER;
240 const json::Reader<gltf2::Material>& GetMaterialReader()
242 static const auto MATERIAL_READER = std::move(json::Reader<gltf2::Material>()
243 .Register(*new json::Property<gltf2::Material, std::string_view>("name", json::Read::StringView, &gltf2::Material::mName))
244 .Register(*json::MakeProperty("pbrMetallicRoughness", json::ObjectReader<gltf2::Material::Pbr>::Read, &gltf2::Material::mPbrMetallicRoughness))
245 .Register(*json::MakeProperty("normalTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mNormalTexture))
246 .Register(*json::MakeProperty("occlusionTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mOcclusionTexture))
247 .Register(*json::MakeProperty("emissiveTexture", json::ObjectReader<gltf2::TextureInfo>::Read, &gltf2::Material::mEmissiveTexture))
248 .Register(*json::MakeProperty("emissiveFactor", gltf2::ReadDaliVector<Vector3>, &gltf2::Material::mEmissiveFactor))
249 .Register(*json::MakeProperty("alphaMode", gltf2::ReadStringEnum<gltf2::AlphaMode>, &gltf2::Material::mAlphaMode))
250 .Register(*json::MakeProperty("alphaCutoff", json::Read::Number<float>, &gltf2::Material::mAlphaCutoff))
251 .Register(*json::MakeProperty("doubleSided", json::Read::Boolean, &gltf2::Material::mDoubleSided))
252 .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::MaterialExtensions>::Read, &gltf2::Material::mMaterialExtensions)));
253 return MATERIAL_READER;
256 std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes(const json_value_s& j)
258 auto& jsonObject = json::Cast<json_object_s>(j);
259 std::map<gltf2::Attribute::HashType, gltf2::Ref<gltf2::Accessor>> result;
261 auto element = jsonObject.start;
264 auto jsonString = *element->name;
266 gltf2::Attribute::HashType hash = gltf2::Attribute::HashFromString(jsonString.string, jsonString.string_size);
269 gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
270 element = element->next;
275 std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> ReadMeshPrimitiveAttributes2(const json_value_s& j)
277 auto& jsonObject = json::Cast<json_object_s>(j);
278 std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>> result;
280 auto element = jsonObject.start;
283 auto jsonString = *element->name;
285 result[gltf2::Attribute::TargetFromString(jsonString.string, jsonString.string_size)] = gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>(*element->value);
287 element = element->next;
292 std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> ReadMeshPrimitiveTargets(const json_value_s& j)
294 auto& jsonObject = json::Cast<json_array_s>(j);
295 std::vector<std::map<gltf2::Attribute::Type, gltf2::Ref<gltf2::Accessor>>> result;
297 result.reserve(jsonObject.length);
299 auto element = jsonObject.start;
302 result.push_back(std::move(ReadMeshPrimitiveAttributes2(*element->value)));
303 element = element->next;
309 const json::Reader<gltf2::Mesh::Primitive>& GetMeshPrimitiveReader()
311 static const auto MESH_PRIMITIVE_READER = std::move(json::Reader<gltf2::Mesh::Primitive>()
312 .Register(*json::MakeProperty("attributes", ReadMeshPrimitiveAttributes, &gltf2::Mesh::Primitive::mAttributes))
313 .Register(*json::MakeProperty("indices", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Mesh::Primitive::mIndices))
314 .Register(*json::MakeProperty("material", gltf2::RefReader<gltf2::Document>::Read<gltf2::Material, &gltf2::Document::mMaterials>, &gltf2::Mesh::Primitive::mMaterial))
315 .Register(*json::MakeProperty("mode", json::Read::Enum<gltf2::Mesh::Primitive::Mode>, &gltf2::Mesh::Primitive::mMode))
316 .Register(*json::MakeProperty("targets", ReadMeshPrimitiveTargets, &gltf2::Mesh::Primitive::mTargets)));
317 return MESH_PRIMITIVE_READER;
320 const json::Reader<gltf2::Mesh::Extras>& GetMeshExtrasReader()
322 static const auto MESH_EXTRAS_READER = std::move(json::Reader<gltf2::Mesh::Extras>()
323 .Register(*json::MakeProperty("targetNames", json::Read::Array<std::string_view, json::Read::StringView>, &gltf2::Mesh::Extras::mTargetNames)));
324 return MESH_EXTRAS_READER;
327 std::vector<std::string_view> ReadMeshExtensionsTargetsName(const json_value_s& j)
329 auto& jsonObject = json::Cast<json_object_s>(j);
330 std::vector<std::string_view> result;
332 auto element = jsonObject.start;
335 auto jsonString = *element->name;
336 uint32_t index = json::Read::Number<uint32_t>(*element->value);
338 if(result.size() <= index)
340 DALI_ASSERT_ALWAYS(index < std::numeric_limits<uint32_t>::max());
341 result.resize(index + 1u);
344 result[index] = json::Read::StringView(jsonString);
346 element = element->next;
351 const json::Reader<gltf2::Mesh::Extensions>& GetMeshExtensionsReader()
353 static const auto MESH_EXTENSIONS_READER = std::move(json::Reader<gltf2::Mesh::Extensions>()
354 .Register(*json::MakeProperty("SXR_targets_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mSXRTargetsNames))
355 .Register(*json::MakeProperty("avatar_shape_names", ReadMeshExtensionsTargetsName, &gltf2::Mesh::Extensions::mAvatarShapeNames)));
356 return MESH_EXTENSIONS_READER;
359 const json::Reader<gltf2::Mesh>& GetMeshReader()
361 static const auto MESH_READER = std::move(json::Reader<gltf2::Mesh>()
362 .Register(*new json::Property<gltf2::Mesh, std::string_view>("name", json::Read::StringView, &gltf2::Mesh::mName))
363 .Register(*json::MakeProperty("primitives",
364 json::Read::Array<gltf2::Mesh::Primitive, json::ObjectReader<gltf2::Mesh::Primitive>::Read>,
365 &gltf2::Mesh::mPrimitives))
366 .Register(*json::MakeProperty("weights", json::Read::Array<float, json::Read::Number>, &gltf2::Mesh::mWeights))
367 .Register(*json::MakeProperty("extras", json::ObjectReader<gltf2::Mesh::Extras>::Read, &gltf2::Mesh::mExtras))
368 .Register(*json::MakeProperty("extensions", json::ObjectReader<gltf2::Mesh::Extensions>::Read, &gltf2::Mesh::mExtensions)));
372 const json::Reader<gltf2::Skin>& GetSkinReader()
374 static const auto SKIN_READER = std::move(json::Reader<gltf2::Skin>()
375 .Register(*new json::Property<gltf2::Skin, std::string_view>("name", json::Read::StringView, &gltf2::Skin::mName))
376 .Register(*json::MakeProperty("inverseBindMatrices",
377 gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>,
378 &gltf2::Skin::mInverseBindMatrices))
379 .Register(*json::MakeProperty("skeleton",
380 gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>,
381 &gltf2::Skin::mSkeleton))
382 .Register(*json::MakeProperty("joints",
383 json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
384 &gltf2::Skin::mJoints)));
388 const json::Reader<gltf2::Camera::Perspective>& GetCameraPerspectiveReader()
390 static const auto CAMERA_PERSPECTIVE_READER = std::move(json::Reader<gltf2::Camera::Perspective>()
391 .Register(*json::MakeProperty("aspectRatio", json::Read::Number<float>, &gltf2::Camera::Perspective::mAspectRatio))
392 .Register(*json::MakeProperty("yfov", json::Read::Number<float>, &gltf2::Camera::Perspective::mYFov))
393 .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Perspective::mZFar))
394 .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Perspective::mZNear))); // TODO: infinite perspective projection, where znear is omitted
395 return CAMERA_PERSPECTIVE_READER;
398 const json::Reader<gltf2::Camera::Orthographic>& GetCameraOrthographicReader()
400 static const auto CAMERA_ORTHOGRAPHIC_READER = std::move(json::Reader<gltf2::Camera::Orthographic>()
401 .Register(*json::MakeProperty("xmag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mXMag))
402 .Register(*json::MakeProperty("ymag", json::Read::Number<float>, &gltf2::Camera::Orthographic::mYMag))
403 .Register(*json::MakeProperty("zfar", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZFar))
404 .Register(*json::MakeProperty("znear", json::Read::Number<float>, &gltf2::Camera::Orthographic::mZNear)));
405 return CAMERA_ORTHOGRAPHIC_READER;
408 const json::Reader<gltf2::Camera>& GetCameraReader()
410 static const auto CAMERA_READER = std::move(json::Reader<gltf2::Camera>()
411 .Register(*new json::Property<gltf2::Camera, std::string_view>("name", json::Read::StringView, &gltf2::Camera::mName))
412 .Register(*json::MakeProperty("type", json::Read::StringView, &gltf2::Camera::mType))
413 .Register(*json::MakeProperty("perspective", json::ObjectReader<gltf2::Camera::Perspective>::Read, &gltf2::Camera::mPerspective))
414 .Register(*json::MakeProperty("orthographic", json::ObjectReader<gltf2::Camera::Orthographic>::Read, &gltf2::Camera::mOrthographic)));
415 return CAMERA_READER;
418 const json::Reader<gltf2::Node>& GetNodeReader()
420 static const auto NODE_READER = std::move(json::Reader<gltf2::Node>()
421 .Register(*new json::Property<gltf2::Node, std::string_view>("name", json::Read::StringView, &gltf2::Node::mName))
422 .Register(*json::MakeProperty("translation", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mTranslation))
423 .Register(*json::MakeProperty("rotation", gltf2::ReadQuaternion, &gltf2::Node::mRotation))
424 .Register(*json::MakeProperty("scale", gltf2::ReadDaliVector<Vector3>, &gltf2::Node::mScale))
425 .Register(*new json::Property<gltf2::Node, Matrix>("matrix", gltf2::ReadDaliVector<Matrix>, &gltf2::Node::SetMatrix))
426 .Register(*json::MakeProperty("camera", gltf2::RefReader<gltf2::Document>::Read<gltf2::Camera, &gltf2::Document::mCameras>, &gltf2::Node::mCamera))
427 .Register(*json::MakeProperty("children", json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>, &gltf2::Node::mChildren))
428 .Register(*json::MakeProperty("mesh", gltf2::RefReader<gltf2::Document>::Read<gltf2::Mesh, &gltf2::Document::mMeshes>, &gltf2::Node::mMesh))
429 .Register(*json::MakeProperty("skin", gltf2::RefReader<gltf2::Document>::Read<gltf2::Skin, &gltf2::Document::mSkins>, &gltf2::Node::mSkin)));
433 const json::Reader<gltf2::Animation::Sampler>& GetAnimationSamplerReader()
435 static const auto ANIMATION_SAMPLER_READER = std::move(json::Reader<gltf2::Animation::Sampler>()
436 .Register(*json::MakeProperty("input", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mInput))
437 .Register(*json::MakeProperty("output", gltf2::RefReader<gltf2::Document>::Read<gltf2::Accessor, &gltf2::Document::mAccessors>, &gltf2::Animation::Sampler::mOutput))
438 .Register(*json::MakeProperty("interpolation", gltf2::ReadStringEnum<gltf2::Animation::Sampler::Interpolation>, &gltf2::Animation::Sampler::mInterpolation)));
439 return ANIMATION_SAMPLER_READER;
442 const json::Reader<gltf2::Animation::Channel::Target>& GetAnimationChannelTargetReader()
444 static const auto ANIMATION_TARGET_READER = std::move(json::Reader<gltf2::Animation::Channel::Target>()
445 .Register(*json::MakeProperty("node", gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>, &gltf2::Animation::Channel::Target::mNode))
446 .Register(*json::MakeProperty("path", gltf2::ReadStringEnum<gltf2::Animation::Channel::Target>, &gltf2::Animation::Channel::Target::mPath)));
447 return ANIMATION_TARGET_READER;
450 const json::Reader<gltf2::Animation::Channel>& GetAnimationChannelReader()
452 static const auto ANIMATION_CHANNEL_READER = std::move(json::Reader<gltf2::Animation::Channel>()
453 .Register(*json::MakeProperty("target", json::ObjectReader<gltf2::Animation::Channel::Target>::Read, &gltf2::Animation::Channel::mTarget))
454 .Register(*json::MakeProperty("sampler", gltf2::RefReader<gltf2::Animation>::Read<gltf2::Animation::Sampler, &gltf2::Animation::mSamplers>, &gltf2::Animation::Channel::mSampler)));
455 return ANIMATION_CHANNEL_READER;
458 const json::Reader<gltf2::Animation>& GetAnimationReader()
460 static const auto ANIMATION_READER = std::move(json::Reader<gltf2::Animation>()
461 .Register(*new json::Property<gltf2::Animation, std::string_view>("name", json::Read::StringView, &gltf2::Animation::mName))
462 .Register(*json::MakeProperty("samplers",
463 json::Read::Array<gltf2::Animation::Sampler, json::ObjectReader<gltf2::Animation::Sampler>::Read>,
464 &gltf2::Animation::mSamplers))
465 .Register(*json::MakeProperty("channels",
466 json::Read::Array<gltf2::Animation::Channel, json::ObjectReader<gltf2::Animation::Channel>::Read>,
467 &gltf2::Animation::mChannels)));
468 return ANIMATION_READER;
471 const json::Reader<gltf2::Scene>& GetSceneReader()
473 static const auto SCENE_READER = std::move(json::Reader<gltf2::Scene>()
474 .Register(*new json::Property<gltf2::Scene, std::string_view>("name", json::Read::StringView, &gltf2::Scene::mName))
475 .Register(*json::MakeProperty("nodes",
476 json::Read::Array<gltf2::Ref<gltf2::Node>, gltf2::RefReader<gltf2::Document>::Read<gltf2::Node, &gltf2::Document::mNodes>>,
477 &gltf2::Scene::mNodes)));
481 const json::Reader<gltf2::Document>& GetDocumentReader()
483 static const auto DOCUMENT_READER = std::move(json::Reader<gltf2::Document>()
484 .Register(*json::MakeProperty("buffers",
485 json::Read::Array<gltf2::Buffer, json::ObjectReader<gltf2::Buffer>::Read>,
486 &gltf2::Document::mBuffers))
487 .Register(*json::MakeProperty("bufferViews",
488 json::Read::Array<gltf2::BufferView, json::ObjectReader<gltf2::BufferView>::Read>,
489 &gltf2::Document::mBufferViews))
490 .Register(*json::MakeProperty("accessors",
491 json::Read::Array<gltf2::Accessor, json::ObjectReader<gltf2::Accessor>::Read>,
492 &gltf2::Document::mAccessors))
493 .Register(*json::MakeProperty("images",
494 json::Read::Array<gltf2::Image, json::ObjectReader<gltf2::Image>::Read>,
495 &gltf2::Document::mImages))
496 .Register(*json::MakeProperty("samplers",
497 json::Read::Array<gltf2::Sampler, json::ObjectReader<gltf2::Sampler>::Read>,
498 &gltf2::Document::mSamplers))
499 .Register(*json::MakeProperty("textures",
500 json::Read::Array<gltf2::Texture, json::ObjectReader<gltf2::Texture>::Read>,
501 &gltf2::Document::mTextures))
502 .Register(*json::MakeProperty("materials",
503 json::Read::Array<gltf2::Material, json::ObjectReader<gltf2::Material>::Read>,
504 &gltf2::Document::mMaterials))
505 .Register(*json::MakeProperty("meshes",
506 json::Read::Array<gltf2::Mesh, json::ObjectReader<gltf2::Mesh>::Read>,
507 &gltf2::Document::mMeshes))
508 .Register(*json::MakeProperty("skins",
509 json::Read::Array<gltf2::Skin, json::ObjectReader<gltf2::Skin>::Read>,
510 &gltf2::Document::mSkins))
511 .Register(*json::MakeProperty("cameras",
512 json::Read::Array<gltf2::Camera, json::ObjectReader<gltf2::Camera>::Read>,
513 &gltf2::Document::mCameras))
514 .Register(*json::MakeProperty("nodes",
515 json::Read::Array<gltf2::Node, json::ObjectReader<gltf2::Node>::Read>,
516 &gltf2::Document::mNodes))
517 .Register(*json::MakeProperty("animations",
519 &gltf2::Document::mAnimations))
520 .Register(*json::MakeProperty("extensionsRequired",
521 json::Read::Array<std::string_view, json::Read::StringView>,
522 &gltf2::Document::mExtensionsRequired))
523 .Register(*json::MakeProperty("extensionsUsed",
524 json::Read::Array<std::string_view, json::Read::StringView>,
525 &gltf2::Document::mExtensionsUsed))
526 .Register(*json::MakeProperty("scenes",
527 json::Read::Array<gltf2::Scene, json::ObjectReader<gltf2::Scene>::Read>,
528 &gltf2::Document::mScenes))
529 .Register(*json::MakeProperty("scene", gltf2::RefReader<gltf2::Document>::Read<gltf2::Scene, &gltf2::Document::mScenes>, &gltf2::Document::mScene)));
530 return DOCUMENT_READER;
533 void ConvertBuffer(const gltf2::Buffer& buffer, decltype(ResourceBundle::mBuffers)& outBuffers, const std::string& resourcePath)
535 BufferDefinition bufferDefinition;
537 bufferDefinition.mResourcePath = resourcePath;
538 bufferDefinition.mUri = buffer.mUri;
539 bufferDefinition.mByteLength = buffer.mByteLength;
541 outBuffers.emplace_back(std::move(bufferDefinition));
544 void ConvertBuffers(const gltf2::Document& document, ConversionContext& context)
546 auto& outBuffers = context.mOutput.mResources.mBuffers;
547 outBuffers.reserve(document.mBuffers.size());
549 for(auto& buffer : document.mBuffers)
551 if(buffer.mUri.empty())
555 ConvertBuffer(buffer, outBuffers, context.mPath);
559 SamplerFlags::Type ConvertWrapMode(gltf2::Wrap::Type wrapMode)
563 case gltf2::Wrap::REPEAT:
564 return SamplerFlags::WRAP_REPEAT;
565 case gltf2::Wrap::CLAMP_TO_EDGE:
566 return SamplerFlags::WRAP_CLAMP;
567 case gltf2::Wrap::MIRRORED_REPEAT:
568 return SamplerFlags::WRAP_MIRROR;
570 throw std::runtime_error("Invalid wrap type.");
574 SamplerFlags::Type ConvertSampler(const gltf2::Ref<gltf2::Sampler>& sampler)
578 return ((sampler->mMinFilter < gltf2::Filter::NEAREST_MIPMAP_NEAREST) ? (sampler->mMinFilter - gltf2::Filter::NEAREST) : ((sampler->mMinFilter - gltf2::Filter::NEAREST_MIPMAP_NEAREST) + 2)) |
579 ((sampler->mMagFilter - gltf2::Filter::NEAREST) << SamplerFlags::FILTER_MAG_SHIFT) |
580 (ConvertWrapMode(sampler->mWrapS) << SamplerFlags::WRAP_S_SHIFT) |
581 (ConvertWrapMode(sampler->mWrapT) << SamplerFlags::WRAP_T_SHIFT);
585 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#texturesampler
586 // "The index of the sampler used by this texture. When undefined, a sampler with repeat wrapping and auto filtering should be used."
587 // "What is an auto filtering", I hear you ask. Since there's nothing else to determine mipmapping from - including glTF image
588 // properties, if not in some extension -, we will simply assume linear filtering.
589 return SamplerFlags::FILTER_LINEAR | (SamplerFlags::FILTER_LINEAR << SamplerFlags::FILTER_MAG_SHIFT) |
590 (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_S_SHIFT) | (SamplerFlags::WRAP_REPEAT << SamplerFlags::WRAP_T_SHIFT);
594 TextureDefinition ConvertTextureInfo(const gltf2::TextureInfo& textureInfo, ConversionContext& context, const ImageMetadata& metaData = ImageMetadata())
596 TextureDefinition textureDefinition;
597 std::string uri = std::string(textureInfo.mTexture->mSource->mUri);
600 uint32_t bufferIndex = textureInfo.mTexture->mSource->mBufferView->mBuffer.GetIndex();
601 if(bufferIndex != INVALID_INDEX && context.mOutput.mResources.mBuffers[bufferIndex].IsAvailable())
603 auto& stream = context.mOutput.mResources.mBuffers[bufferIndex].GetBufferStream();
605 stream.seekg(static_cast<std::streamoff>(static_cast<std::size_t>(textureInfo.mTexture->mSource->mBufferView->mByteOffset)), stream.beg);
606 std::vector<uint8_t> dataBuffer;
607 dataBuffer.resize(textureInfo.mTexture->mSource->mBufferView->mByteLength);
608 stream.read(reinterpret_cast<char*>(dataBuffer.data()), static_cast<std::streamsize>(static_cast<size_t>(textureInfo.mTexture->mSource->mBufferView->mByteLength)));
609 return TextureDefinition{std::move(dataBuffer), ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode, textureInfo.mTextureExtensions.mTextureTransform.GetTransform()};
611 return TextureDefinition();
615 return TextureDefinition{uri, ConvertSampler(textureInfo.mTexture->mSampler), metaData.mMinSize, metaData.mSamplingMode, textureInfo.mTextureExtensions.mTextureTransform.GetTransform()};
619 void AddTextureStage(uint32_t semantic, MaterialDefinition& materialDefinition, gltf2::TextureInfo textureInfo, const Dali::Scene3D::Loader::ImageMetadata& metaData, ConversionContext& context)
621 // Overrides the textureInfo texCoord value if KHR_texture_transform extension is supported and texCoord value is supplied.
622 if(textureInfo.mTextureExtensions && textureInfo.mTexCoord != textureInfo.mTextureExtensions.mTextureTransform.mTexCoord && textureInfo.mTextureExtensions.mTextureTransform.mTexCoord != 0u)
624 textureInfo.mTexCoord = textureInfo.mTextureExtensions.mTextureTransform.mTexCoord;
626 materialDefinition.mTextureStages.push_back({semantic, ConvertTextureInfo(textureInfo, context, metaData)});
627 materialDefinition.mFlags |= semantic;
630 void ConvertMaterial(const gltf2::Material& material, const std::unordered_map<std::string, ImageMetadata>& imageMetaData, decltype(ResourceBundle::mMaterials)& outMaterials, ConversionContext& context)
632 auto getTextureMetaData = [](const std::unordered_map<std::string, ImageMetadata>& metaData, const gltf2::TextureInfo& info) {
633 if(!info.mTexture->mSource->mUri.empty())
635 if(auto search = metaData.find(info.mTexture->mSource->mUri.data()); search != metaData.end())
637 return search->second;
640 return ImageMetadata();
643 MaterialDefinition materialDefinition;
645 materialDefinition.mFlags |= MaterialDefinition::GLTF_CHANNELS;
646 materialDefinition.mShadowAvailable = true;
648 auto& pbr = material.mPbrMetallicRoughness;
649 if(material.mAlphaMode == gltf2::AlphaMode::BLEND)
651 materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::BLEND;
652 materialDefinition.mIsOpaque = false;
653 materialDefinition.mFlags |= MaterialDefinition::TRANSPARENCY;
655 else if(material.mAlphaMode == gltf2::AlphaMode::MASK)
657 materialDefinition.mAlphaModeType = Scene3D::Material::AlphaModeType::MASK;
658 materialDefinition.mIsMask = true;
659 materialDefinition.SetAlphaCutoff(std::min(1.f, std::max(0.f, material.mAlphaCutoff)));
662 materialDefinition.mBaseColorFactor = pbr.mBaseColorFactor;
664 materialDefinition.mTextureStages.reserve(!!pbr.mBaseColorTexture + !!pbr.mMetallicRoughnessTexture + !!material.mNormalTexture + !!material.mOcclusionTexture + !!material.mEmissiveTexture);
665 if(pbr.mBaseColorTexture)
667 AddTextureStage(MaterialDefinition::ALBEDO, materialDefinition, pbr.mBaseColorTexture, getTextureMetaData(imageMetaData, pbr.mBaseColorTexture), context);
671 materialDefinition.mNeedAlbedoTexture = false;
674 materialDefinition.mMetallic = pbr.mMetallicFactor;
675 materialDefinition.mRoughness = pbr.mRoughnessFactor;
677 if(pbr.mMetallicRoughnessTexture)
679 AddTextureStage(MaterialDefinition::METALLIC | MaterialDefinition::ROUGHNESS,
681 pbr.mMetallicRoughnessTexture,
682 getTextureMetaData(imageMetaData, pbr.mMetallicRoughnessTexture),
687 materialDefinition.mNeedMetallicRoughnessTexture = false;
690 materialDefinition.mNormalScale = material.mNormalTexture.mScale;
691 if(material.mNormalTexture)
693 AddTextureStage(MaterialDefinition::NORMAL, materialDefinition, material.mNormalTexture, getTextureMetaData(imageMetaData, material.mNormalTexture), context);
697 materialDefinition.mNeedNormalTexture = false;
700 if(material.mOcclusionTexture)
702 AddTextureStage(MaterialDefinition::OCCLUSION, materialDefinition, material.mOcclusionTexture, getTextureMetaData(imageMetaData, material.mOcclusionTexture), context);
703 materialDefinition.mOcclusionStrength = material.mOcclusionTexture.mStrength;
706 materialDefinition.mEmissiveFactor = material.mEmissiveFactor;
707 if(material.mEmissiveTexture)
709 AddTextureStage(MaterialDefinition::EMISSIVE, materialDefinition, material.mEmissiveTexture, getTextureMetaData(imageMetaData, material.mEmissiveTexture), context);
712 if(!Dali::Equals(material.mMaterialExtensions.mMaterialIor.mIor, gltf2::UNDEFINED_FLOAT_VALUE))
714 materialDefinition.mIor = material.mMaterialExtensions.mMaterialIor.mIor;
715 materialDefinition.mDielectricSpecular = powf((materialDefinition.mIor - 1.0f) / (materialDefinition.mIor + 1.0f), 2.0f);
717 materialDefinition.mSpecularFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularFactor;
718 materialDefinition.mSpecularColorFactor = material.mMaterialExtensions.mMaterialSpecular.mSpecularColorFactor;
720 if(material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture)
722 AddTextureStage(MaterialDefinition::SPECULAR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularTexture), context);
725 if(material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture)
727 AddTextureStage(MaterialDefinition::SPECULAR_COLOR, materialDefinition, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture, getTextureMetaData(imageMetaData, material.mMaterialExtensions.mMaterialSpecular.mSpecularColorTexture), context);
730 materialDefinition.mDoubleSided = material.mDoubleSided;
732 outMaterials.emplace_back(std::move(materialDefinition), TextureSet());
735 void ConvertMaterials(const gltf2::Document& document, ConversionContext& context)
737 auto& imageMetaData = context.mOutput.mSceneMetadata.mImageMetadata;
739 auto& outMaterials = context.mOutput.mResources.mMaterials;
740 outMaterials.reserve(document.mMaterials.size());
742 for(auto& material : document.mMaterials)
744 ConvertMaterial(material, imageMetaData, outMaterials, context);
748 MeshDefinition::Accessor ConvertMeshPrimitiveAccessor(const gltf2::Accessor& accessor)
750 DALI_ASSERT_ALWAYS((accessor.mBufferView &&
751 (accessor.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) ||
752 (accessor.mSparse && !accessor.mBufferView));
754 DALI_ASSERT_ALWAYS(!accessor.mSparse ||
755 ((accessor.mSparse->mIndices.mBufferView && (accessor.mSparse->mIndices.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max())) &&
756 (accessor.mSparse->mValues.mBufferView && (accessor.mSparse->mValues.mBufferView->mByteStride < std::numeric_limits<uint16_t>::max()))));
758 MeshDefinition::SparseBlob sparseBlob;
761 const gltf2::Accessor::Sparse& sparse = *accessor.mSparse;
762 const gltf2::ComponentTypedBufferViewClient& indices = sparse.mIndices;
763 const gltf2::BufferViewClient& values = sparse.mValues;
765 MeshDefinition::Blob indicesBlob(
766 indices.mBufferView->mByteOffset + indices.mByteOffset,
767 sparse.mCount * indices.GetBytesPerComponent(),
768 static_cast<uint16_t>(indices.mBufferView->mByteStride),
769 static_cast<uint16_t>(indices.GetBytesPerComponent()),
772 MeshDefinition::Blob valuesBlob(
773 values.mBufferView->mByteOffset + values.mByteOffset,
774 sparse.mCount * accessor.GetElementSizeBytes(),
775 static_cast<uint16_t>(values.mBufferView->mByteStride),
776 static_cast<uint16_t>(accessor.GetElementSizeBytes()),
780 sparseBlob = std::move(MeshDefinition::SparseBlob(std::move(indicesBlob), std::move(valuesBlob), accessor.mSparse->mCount));
783 uint32_t bufferViewOffset = 0u;
784 uint32_t bufferViewStride = 0u;
785 if(accessor.mBufferView)
787 bufferViewOffset = accessor.mBufferView->mByteOffset;
788 bufferViewStride = accessor.mBufferView->mByteStride;
791 return MeshDefinition::Accessor{
792 std::move(MeshDefinition::Blob{bufferViewOffset + accessor.mByteOffset,
793 accessor.GetBytesLength(),
794 static_cast<uint16_t>(bufferViewStride),
795 static_cast<uint16_t>(accessor.GetElementSizeBytes()),
798 std::move(sparseBlob),
799 accessor.mBufferView ? accessor.mBufferView->mBuffer.GetIndex() : 0,
800 accessor.mNormalized};
803 MeshDefinition::Accessor* GetAccessorFromAttribute(gltf2::Attribute::HashType attributeHash,
804 MeshDefinition& meshDefinition,
808 MeshDefinition::Accessor* accessorDest{nullptr};
810 switch(gltf2::Attribute::TypeFromHash(attributeHash))
812 case gltf2::Attribute::POSITION:
814 accessorDest = &meshDefinition.mPositions;
817 case gltf2::Attribute::NORMAL:
819 accessorDest = &meshDefinition.mNormals;
823 case gltf2::Attribute::TANGENT:
825 accessorDest = &meshDefinition.mTangents;
826 needTangents = false;
829 case gltf2::Attribute::TEXCOORD_N:
831 meshDefinition.mTexCoords.emplace_back(MeshDefinition::Accessor{});
832 accessorDest = &meshDefinition.mTexCoords.back();
835 case gltf2::Attribute::COLOR_N:
837 meshDefinition.mColors.emplace_back(MeshDefinition::Accessor{});
838 accessorDest = &meshDefinition.mColors.back();
841 case gltf2::Attribute::JOINTS_N:
843 if(meshDefinition.mJoints.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
845 meshDefinition.mJoints.emplace_back(MeshDefinition::Accessor{});
846 accessorDest = &meshDefinition.mJoints.back();
850 case gltf2::Attribute::WEIGHTS_N:
852 if(meshDefinition.mWeights.size() < MeshDefinition::MAX_NUMBER_OF_JOINT_SETS)
854 meshDefinition.mWeights.emplace_back(MeshDefinition::Accessor{});
855 accessorDest = &meshDefinition.mWeights.back();
859 case gltf2::Attribute::INVALID:
861 accessorDest = nullptr;
868 void SetFlagsFromComponentType(const gltf2::Accessor& accessor,
869 gltf2::Attribute::HashType attributeHash,
870 MeshDefinition& meshDefinition,
873 switch(gltf2::Attribute::TypeFromHash(attributeHash))
875 case gltf2::Attribute::POSITION:
879 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
880 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_POSITION;
881 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
882 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_POSITION;
884 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_POSITION))) || accessor.mComponentType == gltf2::Component::FLOAT);
887 case gltf2::Attribute::NORMAL:
891 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
892 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
895 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_NORMAL))) || accessor.mComponentType == gltf2::Component::FLOAT);
898 case gltf2::Attribute::TANGENT:
902 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
903 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
906 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TANGENT))) || accessor.mComponentType == gltf2::Component::FLOAT);
909 case gltf2::Attribute::TEXCOORD_N:
913 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TEXCOORD;
914 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_TEXCOORD;
915 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TEXCOORD;
916 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_TEXCOORD;
918 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(meshDefinition.mFlags, MeshDefinition::S8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::S16_TEXCOORD) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_TEXCOORD))) || accessor.mComponentType == gltf2::Component::FLOAT);
921 case gltf2::Attribute::COLOR_N:
925 case gltf2::Attribute::JOINTS_N:
927 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_JOINT_IDS;
928 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_JOINT_IDS;
929 DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_JOINT_IDS) ||
930 MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_JOINT_IDS) ||
931 accessor.mComponentType == gltf2::Component::FLOAT);
934 case gltf2::Attribute::WEIGHTS_N:
936 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_SHORT) * MeshDefinition::U16_WEIGHT;
937 meshDefinition.mFlags |= (accessor.mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_WEIGHT;
938 DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U16_WEIGHT) ||
939 MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_WEIGHT) ||
940 accessor.mComponentType == gltf2::Component::FLOAT);
944 case gltf2::Attribute::INVALID:
951 void ConvertMeshes(const gltf2::Document& document, ConversionContext& context)
953 bool isQuantized = MaskMatch(document.mExtensionFlags, gltf2::ExtensionFlags::KHR_MESH_QUANTIZATION);
955 uint32_t meshCount = 0;
956 context.mMeshIds.reserve(document.mMeshes.size());
957 for(auto& mesh : document.mMeshes)
959 context.mMeshIds.push_back(meshCount);
960 meshCount += mesh.mPrimitives.size();
963 auto& outMeshes = context.mOutput.mResources.mMeshes;
964 outMeshes.reserve(meshCount);
965 for(auto& mesh : document.mMeshes)
967 for(auto& primitive : mesh.mPrimitives)
969 MeshDefinition meshDefinition;
971 auto& attribs = primitive.mAttributes;
972 meshDefinition.mPrimitiveType = GLTF2_TO_DALI_PRIMITIVES[primitive.mMode];
974 auto positionIter = attribs.find(gltf2::Attribute::ToHash(gltf2::Attribute::POSITION, false, 0));
975 if(positionIter == attribs.end())
977 DALI_LOG_ERROR("Primitive mesh dosn't have POSITION atrributes!");
981 auto& positionsAccessor = *positionIter->second;
983 // glTF2 support vector4 tangent for mesh.
984 // https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#meshes-overview
985 meshDefinition.mTangentType = Property::VECTOR4;
987 bool needNormals = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
988 bool needTangents = (positionsAccessor.mType == gltf2::AccessorType::VEC3);
990 for(const auto& [attributeHash, accessor] : attribs)
992 MeshDefinition::Accessor* accessorDest = GetAccessorFromAttribute(attributeHash, meshDefinition, needNormals, needTangents);
993 if(accessorDest == nullptr)
997 *accessorDest = ConvertMeshPrimitiveAccessor(*accessor);
998 SetFlagsFromComponentType(*accessor, attributeHash, meshDefinition, isQuantized);
1003 meshDefinition.RequestNormals();
1007 meshDefinition.RequestTangents();
1010 if(primitive.mIndices)
1012 meshDefinition.mIndices = ConvertMeshPrimitiveAccessor(*primitive.mIndices);
1013 meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_INT) * MeshDefinition::U32_INDICES;
1014 meshDefinition.mFlags |= (primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_BYTE) * MeshDefinition::U8_INDICES;
1015 DALI_ASSERT_DEBUG(MaskMatch(meshDefinition.mFlags, MeshDefinition::U32_INDICES) || MaskMatch(meshDefinition.mFlags, MeshDefinition::U8_INDICES) || primitive.mIndices->mComponentType == gltf2::Component::UNSIGNED_SHORT);
1018 if(!primitive.mTargets.empty())
1020 meshDefinition.mBlendShapes.reserve(primitive.mTargets.size());
1021 meshDefinition.mBlendShapeVersion = BlendShapes::Version::VERSION_2_0;
1022 uint32_t blendShapeIndex = 0u;
1023 for(const auto& target : primitive.mTargets)
1025 MeshDefinition::BlendShape blendShape;
1027 auto endIt = target.end();
1028 auto it = target.find(gltf2::Attribute::POSITION);
1031 blendShape.deltas = ConvertMeshPrimitiveAccessor(*it->second);
1032 blendShape.deltas.mNormalized = it->second->mNormalized;
1036 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_POSITION;
1037 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_POSITION;
1040 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U8_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION) || MaskMatch(blendShape.mFlags, MeshDefinition::U16_POSITION))) || it->second->mComponentType == gltf2::Component::FLOAT);
1042 it = target.find(gltf2::Attribute::NORMAL);
1045 blendShape.normals = ConvertMeshPrimitiveAccessor(*it->second);
1046 blendShape.normals.mNormalized = it->second->mNormalized;
1050 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_NORMAL;
1051 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_NORMAL;
1054 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))) || it->second->mComponentType == gltf2::Component::FLOAT);
1056 it = target.find(gltf2::Attribute::TANGENT);
1059 blendShape.tangents = ConvertMeshPrimitiveAccessor(*it->second);
1060 blendShape.tangents.mNormalized = it->second->mNormalized;
1064 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::BYTE) * MeshDefinition::S8_TANGENT;
1065 blendShape.mFlags |= (it->second->mComponentType == gltf2::Component::SHORT) * MeshDefinition::S16_TANGENT;
1068 DALI_ASSERT_DEBUG((isQuantized && (MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT) || MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))) || it->second->mComponentType == gltf2::Component::FLOAT);
1071 if(!mesh.mWeights.empty())
1073 blendShape.weight = mesh.mWeights[meshDefinition.mBlendShapes.size()];
1076 // Get blendshape name from extras / SXR_targets_names / avatar_shape_names.
1077 if(blendShapeIndex < mesh.mExtras.mTargetNames.size())
1079 blendShape.name = mesh.mExtras.mTargetNames[blendShapeIndex];
1081 else if(blendShapeIndex < mesh.mExtensions.mSXRTargetsNames.size())
1083 blendShape.name = mesh.mExtensions.mSXRTargetsNames[blendShapeIndex];
1085 else if(blendShapeIndex < mesh.mExtensions.mAvatarShapeNames.size())
1087 blendShape.name = mesh.mExtensions.mAvatarShapeNames[blendShapeIndex];
1090 meshDefinition.mBlendShapes.push_back(std::move(blendShape));
1095 outMeshes.push_back({std::move(meshDefinition), MeshGeometry{}});
1100 ModelRenderable* MakeModelRenderable(const gltf2::Mesh::Primitive& primitive, ConversionContext& context)
1102 auto modelRenderable = new ModelRenderable();
1104 auto materialIdx = primitive.mMaterial.GetIndex();
1105 if(INVALID_INDEX == materialIdx)
1107 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#default-material
1108 if(INVALID_INDEX == context.mDefaultMaterial)
1110 auto& outMaterials = context.mOutput.mResources.mMaterials;
1111 context.mDefaultMaterial = outMaterials.size();
1113 ConvertMaterial(gltf2::Material{}, context.mOutput.mSceneMetadata.mImageMetadata, outMaterials, context);
1116 materialIdx = context.mDefaultMaterial;
1119 modelRenderable->mMaterialIdx = materialIdx;
1121 return modelRenderable;
1124 void ConvertCamera(const gltf2::Camera& camera, CameraParameters& cameraParameters)
1126 cameraParameters.isPerspective = camera.mType.compare("perspective") == 0;
1127 if(cameraParameters.isPerspective)
1129 auto& perspective = camera.mPerspective;
1130 if(!Dali::Equals(perspective.mYFov, gltf2::UNDEFINED_FLOAT_VALUE))
1132 cameraParameters.yFovDegree = Degree(Radian(perspective.mYFov));
1136 cameraParameters.yFovDegree = Degree(gltf2::UNDEFINED_FLOAT_VALUE);
1138 cameraParameters.zNear = perspective.mZNear;
1139 cameraParameters.zFar = perspective.mZFar;
1140 // TODO: yes, we seem to ignore aspectRatio in CameraParameters.
1144 auto& ortho = camera.mOrthographic;
1145 if(!Dali::Equals(ortho.mYMag, gltf2::UNDEFINED_FLOAT_VALUE) && !Dali::Equals(ortho.mXMag, gltf2::UNDEFINED_FLOAT_VALUE))
1147 cameraParameters.orthographicSize = ortho.mYMag * .5f;
1148 cameraParameters.aspectRatio = ortho.mXMag / ortho.mYMag;
1152 cameraParameters.orthographicSize = gltf2::UNDEFINED_FLOAT_VALUE;
1153 cameraParameters.aspectRatio = gltf2::UNDEFINED_FLOAT_VALUE;
1155 cameraParameters.zNear = ortho.mZNear;
1156 cameraParameters.zFar = ortho.mZFar;
1159 cameraParameters.name = std::string(camera.mName);
1162 void ConvertNode(gltf2::Node const& node, const Index gltfIndex, Index parentIndex, ConversionContext& context, bool isMRendererModel)
1164 auto& output = context.mOutput;
1165 auto& scene = output.mScene;
1166 auto& resources = output.mResources;
1168 const auto index = scene.GetNodeCount();
1169 auto weakNode = scene.AddNode([&]() {
1170 std::unique_ptr<NodeDefinition> nodeDefinition{new NodeDefinition()};
1172 nodeDefinition->mParentIdx = parentIndex;
1173 nodeDefinition->mName = node.mName;
1174 if(nodeDefinition->mName.empty())
1176 // TODO: Production quality generation of unique names.
1177 nodeDefinition->mName = std::to_string(reinterpret_cast<uintptr_t>(nodeDefinition.get()));
1180 if(!node.mSkin) // Nodes with skinned meshes are not supposed to have local transforms.
1182 nodeDefinition->mPosition = node.mTranslation;
1183 nodeDefinition->mOrientation = node.mRotation;
1184 nodeDefinition->mScale = node.mScale;
1186 if(isMRendererModel && node.mName == ROOT_NODE_NAME && node.mScale == SCALE_TO_ADJUST)
1188 nodeDefinition->mScale *= 0.01f;
1192 return nodeDefinition; }());
1195 ExceptionFlinger(ASSERT_LOCATION) << "Node name '" << node.mName << "' is not unique; scene is invalid.";
1198 context.mNodeIndices.RegisterMapping(gltfIndex, index);
1200 Index skeletonIdx = node.mSkin ? node.mSkin.GetIndex() : INVALID_INDEX;
1203 auto& mesh = *node.mMesh;
1204 uint32_t primitiveCount = mesh.mPrimitives.size();
1205 auto meshIndex = context.mMeshIds[node.mMesh.GetIndex()];
1206 weakNode->mRenderables.reserve(primitiveCount);
1207 for(uint32_t i = 0; i < primitiveCount; ++i)
1209 std::unique_ptr<NodeDefinition::Renderable> renderable;
1210 auto modelRenderable = MakeModelRenderable(mesh.mPrimitives[i], context);
1211 modelRenderable->mMeshIdx = meshIndex + i;
1213 DALI_ASSERT_DEBUG(resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == INVALID_INDEX ||
1214 resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx == skeletonIdx);
1215 resources.mMeshes[modelRenderable->mMeshIdx].first.mSkeletonIdx = skeletonIdx;
1217 renderable.reset(modelRenderable);
1218 weakNode->mRenderables.push_back(std::move(renderable));
1224 CameraParameters cameraParameters;
1225 ConvertCamera(*node.mCamera, cameraParameters);
1227 cameraParameters.matrix.SetTransformComponents(node.mScale, node.mRotation, node.mTranslation);
1228 output.mCameraParameters.push_back(cameraParameters);
1231 for(auto& child : node.mChildren)
1233 ConvertNode(*child, child.GetIndex(), index, context, isMRendererModel);
1237 void ConvertSceneNodes(const gltf2::Scene& scene, ConversionContext& context, bool isMRendererModel)
1239 auto& outScene = context.mOutput.mScene;
1240 Index rootIndex = outScene.GetNodeCount();
1241 switch(scene.mNodes.size())
1247 ConvertNode(*scene.mNodes[0], scene.mNodes[0].GetIndex(), INVALID_INDEX, context, isMRendererModel);
1248 outScene.AddRootNode(rootIndex);
1253 std::unique_ptr<NodeDefinition> sceneRoot{new NodeDefinition()};
1254 sceneRoot->mName = "GLTF_LOADER_SCENE_ROOT_" + std::to_string(outScene.GetRoots().size());
1256 outScene.AddNode(std::move(sceneRoot));
1257 outScene.AddRootNode(rootIndex);
1259 for(auto& node : scene.mNodes)
1261 ConvertNode(*node, node.GetIndex(), rootIndex, context, isMRendererModel);
1268 void ConvertNodes(const gltf2::Document& document, ConversionContext& context, bool isMRendererModel)
1270 if(!document.mScenes.empty())
1272 uint32_t rootSceneIndex = 0u;
1275 rootSceneIndex = document.mScene.GetIndex();
1277 ConvertSceneNodes(document.mScenes[rootSceneIndex], context, isMRendererModel);
1279 for(uint32_t i = 0; i < rootSceneIndex; ++i)
1281 ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1284 for(uint32_t i = rootSceneIndex + 1; i < document.mScenes.size(); ++i)
1286 ConvertSceneNodes(document.mScenes[i], context, isMRendererModel);
1291 template<typename T>
1292 void LoadDataFromAccessor(ConversionContext& context, uint32_t bufferIndex, Vector<T>& dataBuffer, uint32_t offset, uint32_t size)
1294 if(bufferIndex >= context.mOutput.mResources.mBuffers.size())
1296 DALI_LOG_ERROR("Invailid buffer index\n");
1300 auto& buffer = context.mOutput.mResources.mBuffers[bufferIndex];
1301 if(!buffer.IsAvailable())
1303 DALI_LOG_ERROR("Failed to load from buffer stream.\n");
1305 auto& stream = buffer.GetBufferStream();
1307 stream.seekg(static_cast<std::streamoff>(static_cast<std::size_t>(offset)), stream.beg);
1308 stream.read(reinterpret_cast<char*>(dataBuffer.Begin()), static_cast<std::streamsize>(static_cast<size_t>(size)));
1311 template<typename T>
1312 float LoadDataFromAccessors(ConversionContext& context, const gltf2::Accessor& input, const gltf2::Accessor& output, Vector<float>& inputDataBuffer, Vector<T>& outputDataBuffer)
1314 inputDataBuffer.Resize(input.mCount);
1315 outputDataBuffer.Resize(output.mCount);
1317 const uint32_t inputDataBufferSize = input.GetBytesLength();
1318 const uint32_t outputDataBufferSize = output.GetBytesLength();
1320 LoadDataFromAccessor<float>(context, output.mBufferView->mBuffer.GetIndex(), inputDataBuffer, input.mBufferView->mByteOffset + input.mByteOffset, inputDataBufferSize);
1321 LoadDataFromAccessor<T>(context, output.mBufferView->mBuffer.GetIndex(), outputDataBuffer, output.mBufferView->mByteOffset + output.mByteOffset, outputDataBufferSize);
1322 ApplyAccessorMinMax(input, reinterpret_cast<float*>(inputDataBuffer.begin()));
1323 ApplyAccessorMinMax(output, reinterpret_cast<float*>(outputDataBuffer.begin()));
1325 return inputDataBuffer[input.mCount - 1u];
1328 bool IsFirstFrameValueEmpty(const uint32_t inputCount, const Vector<float>& inputBuffer)
1330 return (inputCount > 0 && !Dali::EqualsZero(inputBuffer[0]));
1333 template<typename T>
1334 float LoadKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, KeyFrames& keyFrames, gltf2::Animation::Channel::Target::Type type)
1336 const gltf2::Accessor& input = *channel.mSampler->mInput;
1337 const gltf2::Accessor& output = *channel.mSampler->mOutput;
1339 Vector<float> inputDataBuffer;
1340 Vector<T> outputDataBuffer;
1342 const float duration = std::max(LoadDataFromAccessors<T>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1344 if(IsFirstFrameValueEmpty(input.mCount, inputDataBuffer))
1346 keyFrames.Add(0.0f, outputDataBuffer[0]);
1349 for(uint32_t i = 0; i < input.mCount; ++i)
1351 keyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i]);
1357 float LoadBlendShapeKeyFrames(ConversionContext& context, const gltf2::Animation::Channel& channel, Index nodeIndex, uint32_t& propertyIndex, AnimationDefinition& animationDefinition)
1359 const gltf2::Accessor& input = *channel.mSampler->mInput;
1360 const gltf2::Accessor& output = *channel.mSampler->mOutput;
1362 Vector<float> inputDataBuffer;
1363 Vector<float> outputDataBuffer;
1365 const float duration = std::max(LoadDataFromAccessors<float>(context, input, output, inputDataBuffer, outputDataBuffer), AnimationDefinition::MIN_DURATION_SECONDS);
1367 char weightNameBuffer[32];
1368 auto prefixSize = snprintf(weightNameBuffer, sizeof(weightNameBuffer), "%s[", BLEND_SHAPE_WEIGHTS_UNIFORM.data());
1369 char* const pWeightName = weightNameBuffer + prefixSize;
1370 const auto remainingSize = sizeof(weightNameBuffer) - prefixSize;
1371 for(uint32_t weightIndex = 0u, endWeightIndex = channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount; weightIndex < endWeightIndex; ++weightIndex)
1373 AnimatedProperty animatedProperty;
1375 animatedProperty.mNodeIndex = nodeIndex;
1376 snprintf(pWeightName, remainingSize, "%d]", weightIndex);
1377 animatedProperty.mPropertyName = std::string(weightNameBuffer);
1379 animatedProperty.mKeyFrames = KeyFrames::New();
1381 if(IsFirstFrameValueEmpty(input.mCount, inputDataBuffer))
1383 animatedProperty.mKeyFrames.Add(0.0f, outputDataBuffer[weightIndex]);
1386 for(uint32_t i = 0; i < input.mCount; ++i)
1388 animatedProperty.mKeyFrames.Add(inputDataBuffer[i] / duration, outputDataBuffer[i * endWeightIndex + weightIndex]);
1391 animatedProperty.mTimePeriod = {0.f, duration};
1393 animationDefinition.SetProperty(propertyIndex++, std::move(animatedProperty));
1399 template<typename T>
1400 float LoadAnimation(AnimationDefinition& animationDefinition, Index nodeIndex, Index propertyIndex, const std::string& propertyName, const gltf2::Animation::Channel& channel, ConversionContext& context)
1402 AnimatedProperty animatedProperty;
1403 animatedProperty.mNodeIndex = nodeIndex;
1404 animatedProperty.mPropertyName = propertyName;
1406 animatedProperty.mKeyFrames = KeyFrames::New();
1407 float duration = LoadKeyFrames<T>(context, channel, animatedProperty.mKeyFrames, channel.mTarget.mPath);
1408 animatedProperty.mTimePeriod = {0.f, duration};
1410 animationDefinition.SetProperty(propertyIndex, std::move(animatedProperty));
1414 void ConvertAnimations(const gltf2::Document& document, ConversionContext& context)
1416 auto& output = context.mOutput;
1418 output.mAnimationDefinitions.reserve(output.mAnimationDefinitions.size() + document.mAnimations.size());
1420 for(const auto& animation : document.mAnimations)
1422 AnimationDefinition animationDefinition;
1424 if(!animation.mName.empty())
1426 animationDefinition.SetName(animation.mName.data());
1429 uint32_t numberOfProperties = 0u;
1430 for(const auto& channel : animation.mChannels)
1432 if(channel.mTarget.mPath == gltf2::Animation::Channel::Target::WEIGHTS)
1434 numberOfProperties += channel.mSampler->mOutput->mCount / channel.mSampler->mInput->mCount;
1438 numberOfProperties++;
1441 animationDefinition.ReserveSize(numberOfProperties);
1443 Index propertyIndex = 0u;
1444 for(const auto& channel : animation.mChannels)
1446 Index nodeIndex = context.mNodeIndices.GetRuntimeId(channel.mTarget.mNode.GetIndex());
1447 float duration = 0.f;
1449 switch(channel.mTarget.mPath)
1451 case gltf2::Animation::Channel::Target::TRANSLATION:
1453 duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, POSITION_PROPERTY.data(), channel, context);
1456 case gltf2::Animation::Channel::Target::ROTATION:
1458 duration = LoadAnimation<Quaternion>(animationDefinition, nodeIndex, propertyIndex, ORIENTATION_PROPERTY.data(), channel, context);
1461 case gltf2::Animation::Channel::Target::SCALE:
1463 duration = LoadAnimation<Vector3>(animationDefinition, nodeIndex, propertyIndex, SCALE_PROPERTY.data(), channel, context);
1466 case gltf2::Animation::Channel::Target::WEIGHTS:
1468 duration = LoadBlendShapeKeyFrames(context, channel, nodeIndex, propertyIndex, animationDefinition);
1474 // nothing to animate.
1479 animationDefinition.SetDuration(std::max(duration, animationDefinition.GetDuration()));
1484 output.mAnimationDefinitions.push_back(std::move(animationDefinition));
1488 void ProcessSkins(const gltf2::Document& document, ConversionContext& context)
1490 // https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#skininversebindmatrices
1491 // If an inverseBindMatrices accessor was provided, we'll load the joint data from the buffer,
1492 // otherwise we'll set identity matrices for inverse bind pose.
1493 struct IInverseBindMatrixProvider
1495 virtual ~IInverseBindMatrixProvider()
1498 virtual void Provide(Matrix& inverseBindMatrix) = 0;
1501 struct InverseBindMatrixAccessor : public IInverseBindMatrixProvider
1503 std::istream& mStream;
1504 const uint32_t mElementSizeBytes;
1506 InverseBindMatrixAccessor(const gltf2::Accessor& accessor, ConversionContext& context)
1507 : mStream(context.mOutput.mResources.mBuffers[accessor.mBufferView->mBuffer.GetIndex()].GetBufferStream()),
1508 mElementSizeBytes(accessor.GetElementSizeBytes())
1510 DALI_ASSERT_DEBUG(accessor.mType == gltf2::AccessorType::MAT4 && accessor.mComponentType == gltf2::Component::FLOAT);
1512 if(!mStream.rdbuf()->in_avail())
1514 DALI_LOG_ERROR("Failed to load from stream\n");
1517 mStream.seekg(static_cast<std::streamoff>(static_cast<std::size_t>(accessor.mBufferView->mByteOffset + accessor.mByteOffset)), mStream.beg);
1520 virtual void Provide(Matrix& inverseBindMatrix) override
1522 DALI_ASSERT_ALWAYS(mStream.read(reinterpret_cast<char*>(inverseBindMatrix.AsFloat()), static_cast<std::streamsize>(static_cast<size_t>(mElementSizeBytes))));
1526 struct DefaultInverseBindMatrixProvider : public IInverseBindMatrixProvider
1528 virtual void Provide(Matrix& inverseBindMatrix) override
1530 inverseBindMatrix = Matrix::IDENTITY;
1534 auto& resources = context.mOutput.mResources;
1535 resources.mSkeletons.reserve(document.mSkins.size());
1537 for(auto& skin : document.mSkins)
1539 std::unique_ptr<IInverseBindMatrixProvider> inverseBindMatrixProvider;
1540 if(skin.mInverseBindMatrices)
1542 inverseBindMatrixProvider.reset(new InverseBindMatrixAccessor(*skin.mInverseBindMatrices, context));
1546 inverseBindMatrixProvider.reset(new DefaultInverseBindMatrixProvider());
1549 SkeletonDefinition skeleton;
1550 if(skin.mSkeleton.GetIndex() != INVALID_INDEX)
1552 skeleton.mRootNodeIdx = context.mNodeIndices.GetRuntimeId(skin.mSkeleton.GetIndex());
1555 skeleton.mJoints.resize(skin.mJoints.size());
1556 auto iJoint = skeleton.mJoints.begin();
1557 for(auto& joint : skin.mJoints)
1559 iJoint->mNodeIdx = context.mNodeIndices.GetRuntimeId(joint.GetIndex());
1561 inverseBindMatrixProvider->Provide(iJoint->mInverseBindMatrix);
1566 resources.mSkeletons.push_back(std::move(skeleton));
1570 void SetObjectReaders()
1572 json::SetObjectReader(GetBufferReader());
1573 json::SetObjectReader(GetBufferViewReader());
1574 json::SetObjectReader(GetBufferViewClientReader());
1575 json::SetObjectReader(GetComponentTypedBufferViewClientReader());
1576 json::SetObjectReader(GetAccessorSparseReader());
1577 json::SetObjectReader(GetAccessorReader());
1578 json::SetObjectReader(GetImageReader());
1579 json::SetObjectReader(GetSamplerReader());
1580 json::SetObjectReader(GetTextureReader());
1581 json::SetObjectReader(GetTextureTransformReader());
1582 json::SetObjectReader(GetTextureExtensionsReader());
1583 json::SetObjectReader(GetTextureInfoReader());
1584 json::SetObjectReader(GetMaterialPbrReader());
1585 json::SetObjectReader(GetMaterialSpecularReader());
1586 json::SetObjectReader(GetMaterialIorReader());
1587 json::SetObjectReader(GetMaterialExtensionsReader());
1588 json::SetObjectReader(GetMaterialReader());
1589 json::SetObjectReader(GetMeshPrimitiveReader());
1590 json::SetObjectReader(GetMeshExtrasReader());
1591 json::SetObjectReader(GetMeshExtensionsReader());
1592 json::SetObjectReader(GetMeshReader());
1593 json::SetObjectReader(GetSkinReader());
1594 json::SetObjectReader(GetCameraPerspectiveReader());
1595 json::SetObjectReader(GetCameraOrthographicReader());
1596 json::SetObjectReader(GetCameraReader());
1597 json::SetObjectReader(GetNodeReader());
1598 json::SetObjectReader(GetAnimationSamplerReader());
1599 json::SetObjectReader(GetAnimationChannelTargetReader());
1600 json::SetObjectReader(GetAnimationChannelReader());
1601 json::SetObjectReader(GetAnimationReader());
1602 json::SetObjectReader(GetSceneReader());
1605 void SetDefaultEnvironmentMap(const gltf2::Document& document, ConversionContext& context)
1607 EnvironmentDefinition environmentDefinition;
1608 environmentDefinition.mUseBrdfTexture = true;
1609 environmentDefinition.mIblIntensity = Scene3D::Loader::EnvironmentDefinition::GetDefaultIntensity();
1610 context.mOutput.mResources.mEnvironmentMaps.push_back({std::move(environmentDefinition), EnvironmentDefinition::Textures()});
1613 void InitializeGltfLoader()
1615 static Dali::Mutex initializeMutex;
1616 // Set ObjectReader only once (for all gltf loading).
1617 static bool setObjectReadersRequired = true;
1619 Mutex::ScopedLock lock(initializeMutex);
1620 if(setObjectReadersRequired)
1622 // NOTE: only referencing own, anonymous namespace, const objects; the pointers will never need to change.
1624 setObjectReadersRequired = false;
1629 const std::string_view GetRendererModelIdentification()
1631 return MRENDERER_MODEL_IDENTIFICATION;
1634 void ReadDocument(const json_object_s& jsonObject, gltf2::Document& document)
1636 GetDocumentReader().Read(jsonObject, document);
1639 void ReadDocumentFromParsedData(const json_object_s& jsonObject, gltf2::Document& document)
1641 static Dali::Mutex readMutex;
1642 Mutex::ScopedLock lock(readMutex);
1643 gt::SetRefReaderObject(document);
1644 Gltf2Util::ReadDocument(jsonObject, document);
1647 bool GenerateDocument(json::unique_ptr& root, gt::Document& document, bool& isMRendererModel)
1649 auto& rootObject = js::Cast<json_object_s>(*root);
1650 auto jsonAsset = js::FindObjectChild("asset", rootObject);
1652 auto jsAssetVersion = js::FindObjectChild("version", js::Cast<json_object_s>(*jsonAsset));
1655 document.mAsset.mVersion = js::Read::StringView(*jsAssetVersion);
1658 auto jsAssetGenerator = js::FindObjectChild("generator", js::Cast<json_object_s>(*jsonAsset));
1659 if(jsAssetGenerator)
1661 document.mAsset.mGenerator = js::Read::StringView(*jsAssetGenerator);
1662 isMRendererModel = (document.mAsset.mGenerator.find(Gltf2Util::GetRendererModelIdentification().data()) != std::string_view::npos);
1665 Gltf2Util::InitializeGltfLoader();
1666 Gltf2Util::ReadDocumentFromParsedData(rootObject, document);
1671 void ConvertGltfToContext(gt::Document& document, Gltf2Util::ConversionContext& context, bool isMRendererModel)
1673 for(auto& extension : document.mExtensionsRequired)
1675 gltf2::ExtensionFlags flag;
1676 if(Dali::Scripting::GetEnumeration<gltf2::ExtensionFlags>(extension.data(), EXTENSION_STRING_TABLE, EXTENSION_STRING_TABLE_COUNT, flag))
1678 document.mExtensionFlags |= flag;
1682 DALI_LOG_ERROR("Unsupported glTF extension required: %s\n", extension.data());
1683 DALI_ASSERT_DEBUG(false && "Unsupported glTF extension required");
1687 Gltf2Util::ConvertBuffers(document, context);
1688 Gltf2Util::ConvertMaterials(document, context);
1689 Gltf2Util::ConvertMeshes(document, context);
1690 Gltf2Util::ConvertNodes(document, context, isMRendererModel);
1691 Gltf2Util::ConvertAnimations(document, context);
1692 Gltf2Util::ProcessSkins(document, context);
1694 // Set Default Environment map
1695 Gltf2Util::SetDefaultEnvironmentMap(document, context);
1698 } // namespace Gltf2Util
1700 } // namespace Dali::Scene3D::Loader::Internal