Merge "Support glTF extention: KHR_mesh_quantization" into devel/master
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / public-api / loader / mesh-definition.cpp
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 // CLASS HEADER
19 #include <dali-scene3d/public-api/loader/mesh-definition.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/adaptor-framework/file-stream.h>
23 #include <dali/devel-api/adaptor-framework/pixel-buffer.h>
24 #include <dali/integration-api/debug.h>
25 #include <dali/public-api/math/compile-time-math.h>
26 #include <cstring>
27 #include <fstream>
28 #include <functional>
29 #include <type_traits>
30
31 namespace Dali::Scene3D::Loader
32 {
33 namespace
34 {
35 template<bool use32BitIndices>
36 class IndexProvider
37 {
38 public:
39   using IndexType = typename std::conditional_t<use32BitIndices, uint32_t, uint16_t>;
40   IndexProvider(const uint16_t* indices)
41   : mData(reinterpret_cast<uintptr_t>(indices)),
42     mFunc(indices ? IncrementPointer : Increment)
43   {
44   }
45
46   IndexType operator()()
47   {
48     return mFunc(mData);
49   }
50
51 private:
52   static IndexType Increment(uintptr_t& data)
53   {
54     // mData was 'zero' at construct time. Just simply return counter start with 0.
55     return static_cast<IndexType>(data++);
56   }
57
58   static IndexType IncrementPointer(uintptr_t& data)
59   {
60     auto iPtr   = reinterpret_cast<const IndexType*>(data);
61     auto result = *iPtr;
62     data        = reinterpret_cast<uintptr_t>(++iPtr);
63     return result;
64   }
65
66   uintptr_t mData;
67   IndexType (*mFunc)(uintptr_t&);
68 };
69
70 const char* QUAD("quad");
71
72 ///@brief Reads a blob from the given stream @a source into @a target, which must have
73 /// at least @a descriptor.length bytes.
74 bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint8_t* target)
75 {
76   source.clear();
77   if(!source.seekg(descriptor.mOffset, std::istream::beg))
78   {
79     return false;
80   }
81
82   if(descriptor.IsConsecutive())
83   {
84     return !!source.read(reinterpret_cast<char*>(target), static_cast<std::streamsize>(static_cast<size_t>(descriptor.mLength)));
85   }
86   else
87   {
88     if(descriptor.mStride > descriptor.mElementSizeHint)
89     {
90       const uint32_t diff      = descriptor.mStride - descriptor.mElementSizeHint;
91       uint32_t       readSize  = 0;
92       uint32_t       totalSize = (descriptor.mLength / descriptor.mElementSizeHint) * descriptor.mStride;
93       while(readSize < totalSize &&
94             source.read(reinterpret_cast<char*>(target), descriptor.mElementSizeHint))
95       {
96         readSize += descriptor.mStride;
97         target += descriptor.mElementSizeHint;
98         source.seekg(diff, std::istream::cur);
99       }
100       return readSize == totalSize;
101     }
102   }
103   return false;
104 }
105
106 template<typename T>
107 void ReadValues(const std::vector<uint8_t>& valuesBuffer, const std::vector<uint8_t>& indicesBuffer, uint8_t* target, uint32_t count, uint32_t elementSizeHint)
108 {
109   const T* const indicesPtr = reinterpret_cast<const T* const>(indicesBuffer.data());
110   for(uint32_t index = 0u; index < count; ++index)
111   {
112     uint32_t valuesIndex = indicesPtr[index] * elementSizeHint;
113     memcpy(target + valuesIndex, &valuesBuffer[index * elementSizeHint], elementSizeHint);
114   }
115 }
116
117 bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target, std::vector<uint32_t>* sparseIndices)
118 {
119   bool success = false;
120
121   if(accessor.mBlob.IsDefined())
122   {
123     success = ReadBlob(accessor.mBlob, source, target);
124     if(!success)
125     {
126       return false;
127     }
128   }
129
130   if(accessor.mSparse)
131   {
132     const MeshDefinition::Blob& indices = accessor.mSparse->mIndices;
133     const MeshDefinition::Blob& values  = accessor.mSparse->mValues;
134
135     if(!indices.IsDefined() || !values.IsDefined())
136     {
137       return false;
138     }
139
140     const auto           indicesBufferSize = indices.GetBufferSize();
141     std::vector<uint8_t> indicesBuffer(indicesBufferSize);
142     success = ReadBlob(indices, source, indicesBuffer.data());
143     if(!success)
144     {
145       return false;
146     }
147
148     const auto           valuesBufferSize = values.GetBufferSize();
149     std::vector<uint8_t> valuesBuffer(valuesBufferSize);
150     success = ReadBlob(values, source, valuesBuffer.data());
151     if(!success)
152     {
153       return false;
154     }
155
156     // If non-null sparse indices vector, prepare it for output
157     if(sparseIndices)
158     {
159       sparseIndices->resize(accessor.mSparse->mCount);
160     }
161
162     switch(indices.mElementSizeHint)
163     {
164       case 1u:
165       {
166         ReadValues<uint8_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
167         if(sparseIndices)
168         {
169           // convert 8-bit indices into 32-bit
170           std::transform(indicesBuffer.begin(), indicesBuffer.end(), sparseIndices->begin(), [](const uint8_t& value) { return uint32_t(value); });
171         }
172         break;
173       }
174       case 2u:
175       {
176         ReadValues<uint16_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
177         if(sparseIndices)
178         {
179           // convert 16-bit indices into 32-bit
180           std::transform(reinterpret_cast<uint16_t*>(indicesBuffer.data()),
181                          reinterpret_cast<uint16_t*>(indicesBuffer.data()) + accessor.mSparse->mCount,
182                          sparseIndices->begin(),
183                          [](const uint16_t& value) {
184                            return uint32_t(value);
185                          });
186         }
187         break;
188       }
189       case 4u:
190       {
191         ReadValues<uint32_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
192         if(sparseIndices)
193         {
194           std::copy(indicesBuffer.begin(), indicesBuffer.end(), reinterpret_cast<uint8_t*>(sparseIndices->data()));
195         }
196         break;
197       }
198       default:
199       {
200         DALI_ASSERT_DEBUG(!"Unsupported type for an index");
201       }
202     }
203   }
204
205   return success;
206 }
207
208 bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target)
209 {
210   return ReadAccessor(accessor, source, target, nullptr);
211 }
212
213 template<typename T>
214 void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
215 {
216   constexpr auto sizeofBlobUnit = sizeof(T) * 4;
217
218   DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
219                       accessor.mBlob.mStride >= sizeofBlobUnit) &&
220                      "Joints buffer length not a multiple of element size");
221   const auto inBufferSize  = accessor.mBlob.GetBufferSize();
222   const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
223
224   std::vector<uint8_t> buffer(outBufferSize);
225   auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
226   if(!ReadAccessor(accessor, source, inBuffer))
227   {
228     ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
229   }
230
231   if constexpr(sizeofBlobUnit != sizeof(Vector4))
232   {
233     auto       floats = reinterpret_cast<float*>(buffer.data());
234     const auto end    = inBuffer + inBufferSize;
235     while(inBuffer != end)
236     {
237       const auto value = *reinterpret_cast<T*>(inBuffer);
238       *floats          = static_cast<float>(value);
239
240       inBuffer += sizeof(T);
241       ++floats;
242     }
243   }
244   raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
245 }
246
247 template<typename T>
248 void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
249 {
250   constexpr auto sizeofBlobUnit = sizeof(T) * 4;
251
252   DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
253                       accessor.mBlob.mStride >= sizeofBlobUnit) &&
254                      "weights buffer length not a multiple of element size");
255   const auto inBufferSize  = accessor.mBlob.GetBufferSize();
256   const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
257
258   std::vector<uint8_t> buffer(outBufferSize);
259   auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
260   if(!ReadAccessor(accessor, source, inBuffer))
261   {
262     ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'.";
263   }
264
265   if constexpr(sizeofBlobUnit != sizeof(Vector4))
266   {
267     auto       floats = reinterpret_cast<float*>(buffer.data());
268     const auto end    = inBuffer + inBufferSize;
269     while(inBuffer != end)
270     {
271       const auto value = *reinterpret_cast<T*>(inBuffer);
272       // Normalize weight value. value /= 255 for uint8_t weight, and value /= 65535 for uint16_t weight.
273       *floats = static_cast<float>(value) / static_cast<float>((1 << (sizeof(T) * 8)) - 1);
274
275       inBuffer += sizeof(T);
276       ++floats;
277     }
278   }
279   raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
280 }
281
282 template<bool use32BitsIndices, typename IndexProviderType = IndexProvider<use32BitsIndices>>
283 bool GenerateNormals(MeshDefinition::RawData& raw)
284 {
285   using IndexType = typename IndexProviderType::IndexType;
286
287   // mIndicies size must be even if we use 32bit indices.
288   if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0)))
289   {
290     return false;
291   }
292
293   auto& attribs = raw.mAttribs;
294   DALI_ASSERT_DEBUG(attribs.size() > 0); // positions
295
296   IndexProviderType getIndex(raw.mIndices.data());
297
298   const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t)));
299
300   auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
301
302   std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
303   auto                 normals = reinterpret_cast<Vector3*>(buffer.data());
304
305   for(uint32_t i = 0; i < numIndices; i += 3)
306   {
307     IndexType indices[]{getIndex(), getIndex(), getIndex()};
308     Vector3   pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
309
310     Vector3 a = pos[1] - pos[0];
311     Vector3 b = pos[2] - pos[0];
312
313     Vector3 normal(a.Cross(b));
314     normals[indices[0]] += normal;
315     normals[indices[1]] += normal;
316     normals[indices[2]] += normal;
317   }
318
319   auto iEnd = normals + attribs[0].mNumElements;
320   while(normals != iEnd)
321   {
322     normals->Normalize();
323     ++normals;
324   }
325
326   attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)});
327
328   return true;
329 }
330
331 template<bool use32BitsIndices, bool useVec3, bool hasUvs, typename T = std::conditional_t<useVec3, Vector3, Vector4>, typename = std::enable_if_t<(std::is_same<T, Vector3>::value || std::is_same<T, Vector4>::value)>, typename IndexProviderType = IndexProvider<use32BitsIndices>>
332 bool GenerateTangents(MeshDefinition::RawData& raw)
333 {
334   using IndexType = typename IndexProviderType::IndexType;
335
336   // mIndicies size must be even if we use 32bit indices.
337   if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0)))
338   {
339     return false;
340   }
341
342   auto& attribs = raw.mAttribs;
343   // Required positions, normals, uvs (if we have). If not, skip generation
344   if(DALI_UNLIKELY(attribs.size() < (2 + static_cast<size_t>(hasUvs))))
345   {
346     return false;
347   }
348
349   std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(T));
350   auto                 tangents = reinterpret_cast<T*>(buffer.data());
351
352   if constexpr(hasUvs)
353   {
354     IndexProviderType getIndex(raw.mIndices.data());
355
356     const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t)));
357
358     auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
359     auto* uvs       = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
360
361     for(uint32_t i = 0; i < numIndices; i += 3)
362     {
363       IndexType indices[]{getIndex(), getIndex(), getIndex()};
364       Vector3   pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
365       Vector2   uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]};
366
367       float x0 = pos[1].x - pos[0].x;
368       float y0 = pos[1].y - pos[0].y;
369       float z0 = pos[1].z - pos[0].z;
370
371       float x1 = pos[2].x - pos[0].x;
372       float y1 = pos[2].y - pos[0].y;
373       float z1 = pos[2].z - pos[0].z;
374
375       float s0 = uv[1].x - uv[0].x;
376       float t0 = uv[1].y - uv[0].y;
377
378       float s1 = uv[2].x - uv[0].x;
379       float t1 = uv[2].y - uv[0].y;
380
381       float   det = (s0 * t1 - t0 * s1);
382       float   r   = 1.f / ((std::abs(det) < Dali::Epsilon<1000>::value) ? (Dali::Epsilon<1000>::value * (det > 0.0f ? 1.f : -1.f)) : det);
383       Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
384       tangents[indices[0]] += T(tangent);
385       tangents[indices[1]] += T(tangent);
386       tangents[indices[2]] += T(tangent);
387     }
388   }
389
390   auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
391   auto  iEnd    = normals + attribs[1].mNumElements;
392   while(normals != iEnd)
393   {
394     Vector3 tangentVec3;
395     if constexpr(hasUvs)
396     {
397       // Calculated by indexs
398       tangentVec3 = Vector3((*tangents).x, (*tangents).y, (*tangents).z);
399     }
400     else
401     {
402       // Only choiced by normal vector. by indexs
403       Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)};
404       tangentVec3 = t[t[1].LengthSquared() > t[0].LengthSquared()];
405     }
406
407     tangentVec3 -= *normals * normals->Dot(tangentVec3);
408     tangentVec3.Normalize();
409     if constexpr(useVec3)
410     {
411       *tangents = tangentVec3;
412     }
413     else
414     {
415       *tangents = Vector4(tangentVec3.x, tangentVec3.y, tangentVec3.z, 1.0f);
416     }
417
418     ++tangents;
419     ++normals;
420   }
421   attribs.push_back({"aTangent", useVec3 ? Property::VECTOR3 : Property::VECTOR4, attribs[0].mNumElements, std::move(buffer)});
422
423   return true;
424 }
425
426 void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight)
427 {
428   DALI_ASSERT_DEBUG(0u != totalTextureSize && "totalTextureSize is zero.")
429
430   // Calculate the dimensions of the texture.
431   // The total size of the texture is the length of the blend shapes blob.
432
433   textureWidth  = 0u;
434   textureHeight = 0u;
435
436   if(0u == totalTextureSize)
437   {
438     // nothing to do.
439     return;
440   }
441
442   const uint32_t pow2      = static_cast<uint32_t>(ceil(log2(totalTextureSize)));
443   const uint32_t powWidth  = pow2 >> 1u;
444   const uint32_t powHeight = pow2 - powWidth;
445
446   textureWidth  = 1u << powWidth;
447   textureHeight = 1u << powHeight;
448 }
449
450 template<typename T>
451 float GetNormalizedScale()
452 {
453   return 1.0f / (std::numeric_limits<T>::max());
454 }
455
456 template<typename T>
457 void DequantizeData(std::vector<uint8_t>& buffer, float* dequantizedValues, uint32_t numValues, bool normalized)
458 {
459   // see https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Khronos/KHR_mesh_quantization#encoding-quantized-data
460
461   T* values = reinterpret_cast<T*>(buffer.data());
462
463   for(uint32_t i = 0; i < numValues; ++i)
464   {
465     *dequantizedValues = normalized ? std::max((*values) * GetNormalizedScale<T>(), -1.0f) : *values;
466
467     values++;
468     dequantizedValues++;
469   }
470 }
471
472 void GetDequantizedData(std::vector<uint8_t>& buffer, uint32_t numComponents, uint32_t count, uint32_t flags, bool normalized)
473 {
474   bool dequantized = false;
475
476   std::vector<uint8_t> dequantizedBuffer(count * numComponents * sizeof(float));
477   float*               dequantizedValues = reinterpret_cast<float*>(dequantizedBuffer.data());
478
479   if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
480   {
481     DequantizeData<int8_t>(buffer, dequantizedValues, numComponents * count, normalized);
482     dequantized = true;
483   }
484   else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
485   {
486     DequantizeData<uint8_t>(buffer, dequantizedValues, numComponents * count, normalized);
487     dequantized = true;
488   }
489   else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
490   {
491     DequantizeData<int16_t>(buffer, dequantizedValues, numComponents * count, normalized);
492     dequantized = true;
493   }
494   else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
495   {
496     DequantizeData<uint16_t>(buffer, dequantizedValues, numComponents * count, normalized);
497     dequantized = true;
498   }
499
500   if(dequantized)
501   {
502     buffer = std::move(dequantizedBuffer);
503   }
504 }
505
506 void GetDequantizedMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t flags)
507 {
508   float scale = 1.0f;
509
510   if(MaskMatch(flags, MeshDefinition::Flags::S8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S8_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S8_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S8_TEXCOORD))
511   {
512     scale = GetNormalizedScale<int8_t>();
513   }
514   else if(MaskMatch(flags, MeshDefinition::Flags::U8_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U8_TEXCOORD))
515   {
516     scale = GetNormalizedScale<uint8_t>();
517   }
518   else if(MaskMatch(flags, MeshDefinition::Flags::S16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::S16_NORMAL) || MaskMatch(flags, MeshDefinition::Flags::S16_TANGENT) || MaskMatch(flags, MeshDefinition::Flags::S16_TEXCOORD))
519   {
520     scale = GetNormalizedScale<int16_t>();
521   }
522   else if(MaskMatch(flags, MeshDefinition::Flags::U16_POSITION) || MaskMatch(flags, MeshDefinition::Flags::U16_TEXCOORD))
523   {
524     scale = GetNormalizedScale<uint16_t>();
525   }
526
527   if(scale != 1.0f)
528   {
529     for(float& value : min)
530     {
531       value = std::max(value * scale, -1.0f);
532     }
533
534     for(float& value : max)
535     {
536       value = std::min(value * scale, 1.0f);
537     }
538   }
539 }
540
541 void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
542 {
543   uint32_t geometryBufferIndex = 0u;
544   float    maxDistanceSquared  = 0.f;
545   Vector3* geometryBufferV3    = reinterpret_cast<Vector3*>(geometryBuffer);
546   for(auto& blendShape : blendShapes)
547   {
548     if(blendShape.deltas.IsDefined())
549     {
550       const auto bufferSize = blendShape.deltas.mBlob.GetBufferSize();
551       uint32_t   numVector3;
552
553       if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_POSITION))
554       {
555         DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
556                             blendShape.deltas.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
557                            "Blend Shape position buffer length not a multiple of element size");
558         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
559       }
560       else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_POSITION))
561       {
562         DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
563                             blendShape.deltas.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
564                            "Blend Shape position buffer length not a multiple of element size");
565         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
566       }
567       else
568       {
569         DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0) ||
570                             blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
571                            "Blend Shape position buffer length not a multiple of element size");
572         numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
573       }
574
575       std::vector<uint8_t>  buffer(bufferSize);
576       std::vector<uint32_t> sparseIndices{};
577
578       if(ReadAccessor(blendShape.deltas, buffers[blendShape.deltas.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
579       {
580         GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::POSITIONS_MASK, blendShape.deltas.mNormalized);
581
582         if(blendShape.deltas.mNormalized)
583         {
584           GetDequantizedMinMax(blendShape.deltas.mBlob.mMin, blendShape.deltas.mBlob.mMax, blendShape.mFlags & MeshDefinition::POSITIONS_MASK);
585         }
586
587         blendShape.deltas.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
588
589         // Calculate the difference with the original mesh.
590         // Find the max distance to normalize the deltas.
591         const auto* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
592
593         auto ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
594           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
595           delta                                                  = deltasBuffer[deltaIndex];
596           return std::max(maxDistanceSquared, delta.LengthSquared());
597         };
598
599         if(sparseIndices.empty())
600         {
601           for(uint32_t index = 0u; index < numberOfVertices; ++index)
602           {
603             maxDistanceSquared = ProcessVertex(geometryBufferIndex++, index);
604           }
605         }
606         else
607         {
608           // initialize blendshape texture
609           // TODO: there may be a case when sparse accessor uses a base buffer view for initial values.
610           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3::ZERO);
611           for(auto index : sparseIndices)
612           {
613             maxDistanceSquared = ProcessVertex(geometryBufferIndex + index, index);
614           }
615           geometryBufferIndex += numberOfVertices;
616         }
617       }
618     }
619
620     if(blendShape.normals.IsDefined())
621     {
622       const auto bufferSize = blendShape.normals.mBlob.GetBufferSize();
623       uint32_t   numVector3;
624
625       if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_NORMAL))
626       {
627         DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
628                             blendShape.normals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
629                            "Blend Shape normals buffer length not a multiple of element size");
630         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
631       }
632       else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_NORMAL))
633       {
634         DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
635                             blendShape.normals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
636                            "Blend Shape normals buffer length not a multiple of element size");
637         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
638       }
639       else
640       {
641         DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0) ||
642                             blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
643                            "Blend Shape normals buffer length not a multiple of element size");
644         numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
645       }
646
647       std::vector<uint8_t>  buffer(bufferSize);
648       std::vector<uint32_t> sparseIndices;
649
650       if(ReadAccessor(blendShape.normals, buffers[blendShape.normals.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
651       {
652         GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::NORMALS_MASK, blendShape.normals.mNormalized);
653
654         if(blendShape.normals.mNormalized)
655         {
656           GetDequantizedMinMax(blendShape.normals.mBlob.mMin, blendShape.normals.mBlob.mMax, blendShape.mFlags & MeshDefinition::NORMALS_MASK);
657         }
658
659         blendShape.normals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
660
661         // Calculate the difference with the original mesh, and translate to make all values positive.
662         const Vector3* const deltasBuffer  = reinterpret_cast<const Vector3* const>(buffer.data());
663         auto                 ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
664           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
665           delta.x *= 0.5f;
666           delta.y *= 0.5f;
667           delta.z *= 0.5f;
668
669           delta.x += 0.5f;
670           delta.y += 0.5f;
671           delta.z += 0.5f;
672         };
673
674         if(sparseIndices.empty())
675         {
676           for(uint32_t index = 0u; index < numberOfVertices; ++index)
677           {
678             ProcessVertex(geometryBufferIndex++, index);
679           }
680         }
681         else
682         {
683           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3(0.5, 0.5, 0.5));
684           for(auto index : sparseIndices)
685           {
686             ProcessVertex(geometryBufferIndex + index, index);
687           }
688           geometryBufferIndex += numberOfVertices;
689         }
690       }
691     }
692
693     if(blendShape.tangents.IsDefined())
694     {
695       const auto bufferSize = blendShape.tangents.mBlob.GetBufferSize();
696
697       uint32_t numVector3;
698
699       if(MaskMatch(blendShape.mFlags, MeshDefinition::S8_TANGENT))
700       {
701         DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
702                             blendShape.tangents.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
703                            "Blend Shape tangents buffer length not a multiple of element size");
704         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
705       }
706       else if(MaskMatch(blendShape.mFlags, MeshDefinition::S16_TANGENT))
707       {
708         DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
709                             blendShape.tangents.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
710                            "Blend Shape tangents buffer length not a multiple of element size");
711         numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
712       }
713       else
714       {
715         DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0) ||
716                             blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
717                            "Blend Shape tangents buffer length not a multiple of element size");
718         numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
719       }
720
721       std::vector<uint8_t>  buffer(bufferSize);
722       std::vector<uint32_t> sparseIndices;
723
724       if(ReadAccessor(blendShape.tangents, buffers[blendShape.tangents.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
725       {
726         GetDequantizedData(buffer, 3u, numVector3, blendShape.mFlags & MeshDefinition::TANGENTS_MASK, blendShape.tangents.mNormalized);
727
728         if(blendShape.tangents.mNormalized)
729         {
730           GetDequantizedMinMax(blendShape.tangents.mBlob.mMin, blendShape.tangents.mBlob.mMax, blendShape.mFlags & MeshDefinition::TANGENTS_MASK);
731         }
732
733         blendShape.tangents.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()), &sparseIndices);
734
735         // Calculate the difference with the original mesh, and translate to make all values positive.
736         const Vector3* const deltasBuffer  = reinterpret_cast<const Vector3* const>(buffer.data());
737         auto                 ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
738           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
739           delta.x *= 0.5f;
740           delta.y *= 0.5f;
741           delta.z *= 0.5f;
742
743           delta.x += 0.5f;
744           delta.y += 0.5f;
745           delta.z += 0.5f;
746         };
747
748         if(sparseIndices.empty())
749         {
750           for(uint32_t index = 0u; index < numberOfVertices; ++index)
751           {
752             ProcessVertex(geometryBufferIndex++, index);
753           }
754         }
755         else
756         {
757           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3(0.5, 0.5, 0.5));
758           for(auto index : sparseIndices)
759           {
760             ProcessVertex(geometryBufferIndex + index, index);
761           }
762           geometryBufferIndex += numberOfVertices;
763         }
764       }
765     }
766   }
767
768   geometryBufferIndex = 0u;
769
770   const float maxDistance = sqrtf(maxDistanceSquared);
771
772   const float normalizeFactor = (maxDistanceSquared < Math::MACHINE_EPSILON_100) ? 1.f : (0.5f / maxDistance);
773
774   // Calculate and store the unnormalize factor.
775   blendShapeUnnormalizeFactor = maxDistance * 2.0f;
776
777   for(const auto& blendShape : blendShapes)
778   {
779     // Normalize all the deltas and translate to a possitive value.
780     // Deltas are going to be passed to the shader in a color texture
781     // whose values that are less than zero are clamped.
782     if(blendShape.deltas.IsDefined())
783     {
784       for(uint32_t index = 0u; index < numberOfVertices; ++index)
785       {
786         Vector3& delta = geometryBufferV3[geometryBufferIndex++];
787         delta.x        = Clamp(((delta.x * normalizeFactor) + 0.5f), 0.f, 1.f);
788         delta.y        = Clamp(((delta.y * normalizeFactor) + 0.5f), 0.f, 1.f);
789         delta.z        = Clamp(((delta.z * normalizeFactor) + 0.5f), 0.f, 1.f);
790       }
791     }
792
793     if(blendShape.normals.IsDefined())
794     {
795       geometryBufferIndex += numberOfVertices;
796     }
797
798     if(blendShape.tangents.IsDefined())
799     {
800       geometryBufferIndex += numberOfVertices;
801     }
802   }
803 }
804
805 std::iostream& GetAvailableData(std::fstream& meshStream, const std::string& meshPath, BufferDefinition& buffer, std::string& availablePath)
806 {
807   auto& stream  = (meshStream.is_open()) ? meshStream : buffer.GetBufferStream();
808   availablePath = (meshStream.is_open()) ? meshPath : buffer.GetUri();
809   return stream;
810 }
811
812 } // namespace
813
814 MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
815 : mIndices{indices},
816   mValues{values},
817   mCount{count}
818 {
819 }
820
821 MeshDefinition::SparseBlob::SparseBlob(Blob&& indices, Blob&& values, uint32_t count)
822 : mIndices(std::move(indices)),
823   mValues(std::move(values)),
824   mCount{count}
825 {
826 }
827
828 MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob&       blob,
829                                    const MeshDefinition::SparseBlob& sparse,
830                                    Index                             bufferIndex)
831 : mBlob{blob},
832   mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
833   mBufferIdx(bufferIndex)
834 {
835 }
836
837 MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&&       blob,
838                                    MeshDefinition::SparseBlob&& sparse,
839                                    Index                        bufferIndex)
840 : mBlob{std::move(blob)},
841   mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
842   mBufferIdx(bufferIndex)
843 {
844 }
845
846 void MeshDefinition::Blob::ComputeMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t numComponents, uint32_t count, const float* values)
847 {
848   min.assign(numComponents, MAXFLOAT);
849   max.assign(numComponents, -MAXFLOAT);
850   for(uint32_t i = 0; i < count; ++i)
851   {
852     for(uint32_t j = 0; j < numComponents; ++j)
853     {
854       min[j] = std::min(min[j], *values);
855       max[j] = std::max(max[j], *values);
856       values++;
857     }
858   }
859 }
860
861 void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values, std::vector<uint32_t>* sparseIndices)
862 {
863   DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
864   const auto numComponents = std::max(min.size(), max.size());
865
866   using ClampFn   = void (*)(const float*, const float*, uint32_t, float&);
867   ClampFn clampFn = min.empty() ? (max.empty() ? static_cast<ClampFn>(nullptr) : [](const float* min, const float* max, uint32_t i, float& value) { value = std::min(max[i], value); })
868                                 : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) { value = std::max(min[i], value); }
869                                                : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); }));
870
871   if(!clampFn)
872   {
873     return;
874   }
875
876   auto end = values + count * numComponents;
877   while(values != end)
878   {
879     auto     nextElement = values + numComponents;
880     uint32_t i           = 0;
881     while(values != nextElement)
882     {
883       clampFn(min.data(), max.data(), i, *values);
884       ++values;
885       ++i;
886     }
887   }
888 }
889
890 MeshDefinition::Blob::Blob(uint32_t offset, uint32_t length, uint16_t stride, uint16_t elementSizeHint, const std::vector<float>& min, const std::vector<float>& max)
891 : mOffset(offset),
892   mLength(length),
893   mStride(stride),
894   mElementSizeHint(elementSizeHint),
895   mMin(min),
896   mMax(max)
897 {
898 }
899
900 uint32_t MeshDefinition::Blob::GetBufferSize() const
901 {
902   return mLength;
903 }
904
905 void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
906 {
907   ComputeMinMax(mMin, mMax, numComponents, count, values);
908 }
909
910 void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
911 {
912   ApplyMinMax(mMin, mMax, count, values, sparseIndices);
913 }
914
915 void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
916 {
917   Property::Map attribMap;
918   attribMap[mName]          = mType;
919   VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
920   attribBuffer.SetData(mData.data(), mNumElements);
921
922   g.AddVertexBuffer(attribBuffer);
923 }
924
925 bool MeshDefinition::IsQuad() const
926 {
927   return CaseInsensitiveStringCompare(QUAD, mUri);
928 }
929
930 bool MeshDefinition::IsSkinned() const
931 {
932   return mJoints0.IsDefined() && mWeights0.IsDefined();
933 }
934
935 bool MeshDefinition::HasBlendShapes() const
936 {
937   return !mBlendShapes.empty();
938 }
939
940 void MeshDefinition::RequestNormals()
941 {
942   mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
943 }
944
945 void MeshDefinition::RequestTangents()
946 {
947   mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
948 }
949
950 MeshDefinition::RawData
951 MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
952 {
953   RawData raw;
954   if(IsQuad())
955   {
956     return raw;
957   }
958
959   std::string meshPath;
960   meshPath = modelsPath + mUri;
961   std::fstream fileStream;
962   if(!mUri.empty())
963   {
964     fileStream.open(meshPath, std::ios::in | std::ios::binary);
965     if(!fileStream.is_open())
966     {
967       DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
968     }
969   }
970
971   if(mIndices.IsDefined())
972   {
973     if(MaskMatch(mFlags, U32_INDICES))
974     {
975       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
976                           mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
977                          "Index buffer length not a multiple of element size");
978       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
979       raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
980
981       std::string path;
982       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
983       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
984       {
985         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
986       }
987     }
988     else if(MaskMatch(mFlags, U8_INDICES))
989     {
990       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint8_t) == 0) ||
991                           mIndices.mBlob.mStride >= sizeof(uint8_t)) &&
992                          "Index buffer length not a multiple of element size");
993       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t);
994       raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
995
996       std::string path;
997       auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
998       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
999       if(!ReadAccessor(mIndices, stream, u8s))
1000       {
1001         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
1002       }
1003
1004       auto u16s = raw.mIndices.data();
1005       auto end  = u8s + indexCount;
1006       while(u8s != end)
1007       {
1008         *u16s = static_cast<uint16_t>(*u8s);
1009         ++u16s;
1010         ++u8s;
1011       }
1012     }
1013     else
1014     {
1015       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
1016                           mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
1017                          "Index buffer length not a multiple of element size");
1018       raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
1019
1020       std::string path;
1021       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
1022       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
1023       {
1024         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
1025       }
1026     }
1027   }
1028
1029   uint32_t numberOfVertices = 0u;
1030
1031   std::vector<Vector3> positions;
1032   if(mPositions.IsDefined())
1033   {
1034     const auto bufferSize = mPositions.mBlob.GetBufferSize();
1035     uint32_t   numVector3;
1036
1037     if(MaskMatch(mFlags, S8_POSITION) || MaskMatch(mFlags, U8_POSITION))
1038     {
1039       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
1040                           mPositions.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
1041                          "Position buffer length not a multiple of element size");
1042       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
1043     }
1044     else if(MaskMatch(mFlags, S16_POSITION) || MaskMatch(mFlags, U16_POSITION))
1045     {
1046       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
1047                           mPositions.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
1048                          "Position buffer length not a multiple of element size");
1049       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
1050     }
1051     else
1052     {
1053       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
1054                           mPositions.mBlob.mStride >= sizeof(Vector3)) &&
1055                          "Position buffer length not a multiple of element size");
1056       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
1057     }
1058
1059     numberOfVertices = numVector3;
1060
1061     std::vector<uint8_t> buffer(bufferSize);
1062
1063     std::string path;
1064     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mPositions.mBufferIdx], path);
1065     if(!ReadAccessor(mPositions, stream, buffer.data()))
1066     {
1067       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
1068     }
1069
1070     GetDequantizedData(buffer, 3u, numVector3, mFlags & POSITIONS_MASK, mPositions.mNormalized);
1071
1072     if(mPositions.mNormalized)
1073     {
1074       GetDequantizedMinMax(mPositions.mBlob.mMin, mPositions.mBlob.mMax, mFlags & POSITIONS_MASK);
1075     }
1076
1077     if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
1078     {
1079       mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
1080     }
1081     else
1082     {
1083       mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
1084     }
1085
1086     if(HasBlendShapes())
1087     {
1088       positions.resize(numVector3);
1089       std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
1090     }
1091
1092     raw.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
1093   }
1094
1095   const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
1096   auto       hasNormals  = mNormals.IsDefined();
1097   if(hasNormals)
1098   {
1099     const auto bufferSize = mNormals.mBlob.GetBufferSize();
1100     uint32_t   numVector3;
1101
1102     if(MaskMatch(mFlags, S8_NORMAL))
1103     {
1104       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
1105                           mNormals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
1106                          "Normal buffer length not a multiple of element size");
1107       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
1108     }
1109     else if(MaskMatch(mFlags, S16_NORMAL))
1110     {
1111       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
1112                           mNormals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
1113                          "Normal buffer length not a multiple of element size");
1114       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
1115     }
1116     else
1117     {
1118       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
1119                           mNormals.mBlob.mStride >= sizeof(Vector3)) &&
1120                          "Normal buffer length not a multiple of element size");
1121       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
1122     }
1123
1124     std::vector<uint8_t> buffer(bufferSize);
1125
1126     std::string path;
1127     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mNormals.mBufferIdx], path);
1128     if(!ReadAccessor(mNormals, stream, buffer.data()))
1129     {
1130       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
1131     }
1132
1133     GetDequantizedData(buffer, 3u, numVector3, mFlags & NORMALS_MASK, mNormals.mNormalized);
1134
1135     if(mNormals.mNormalized)
1136     {
1137       GetDequantizedMinMax(mNormals.mBlob.mMin, mNormals.mBlob.mMax, mFlags & NORMALS_MASK);
1138     }
1139
1140     mNormals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
1141
1142     raw.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
1143   }
1144   else if(mNormals.mBlob.mLength != 0 && isTriangles)
1145   {
1146     DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
1147     static const std::function<bool(RawData&)> GenerateNormalsFunction[2] =
1148       {
1149         GenerateNormals<false>,
1150         GenerateNormals<true>,
1151       };
1152     const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw);
1153     if(!generateSuccessed)
1154     {
1155       DALI_LOG_ERROR("Failed to generate normal\n");
1156     }
1157     else
1158     {
1159       hasNormals = true;
1160     }
1161   }
1162
1163   const auto hasUvs = mTexCoords.IsDefined();
1164   if(hasUvs)
1165   {
1166     const auto bufferSize = mTexCoords.mBlob.GetBufferSize();
1167
1168     uint32_t uvCount;
1169
1170     if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD))
1171     {
1172       DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
1173                           mTexCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
1174                          "TexCoords buffer length not a multiple of element size");
1175       uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 2));
1176     }
1177     else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD))
1178     {
1179       DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
1180                           mTexCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
1181                          "TexCoords buffer length not a multiple of element size");
1182       uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 2));
1183     }
1184     else
1185     {
1186       DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
1187                           mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
1188                          "TexCoords buffer length not a multiple of element size");
1189       uvCount = static_cast<uint32_t>(bufferSize / sizeof(Vector2));
1190     }
1191
1192     std::vector<uint8_t> buffer(bufferSize);
1193
1194     std::string path;
1195     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path);
1196     if(!ReadAccessor(mTexCoords, stream, buffer.data()))
1197     {
1198       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
1199     }
1200
1201     GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, mTexCoords.mNormalized);
1202
1203     if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
1204     {
1205       auto uv    = reinterpret_cast<Vector2*>(buffer.data());
1206       auto uvEnd = uv + uvCount;
1207       while(uv != uvEnd)
1208       {
1209         uv->y = 1.0f - uv->y;
1210         ++uv;
1211       }
1212     }
1213
1214     if(mTexCoords.mNormalized)
1215     {
1216       GetDequantizedMinMax(mTexCoords.mBlob.mMin, mTexCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
1217     }
1218
1219     mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
1220
1221     raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
1222   }
1223
1224   if(mTangents.IsDefined())
1225   {
1226     const auto bufferSize = mTangents.mBlob.GetBufferSize();
1227
1228     uint32_t propertySize   = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
1229     uint32_t componentCount = static_cast<uint32_t>(propertySize / sizeof(float));
1230
1231     uint32_t numTangents;
1232
1233     if(MaskMatch(mFlags, S8_TANGENT))
1234     {
1235       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
1236                           mTangents.mBlob.mStride >= (sizeof(int8_t) * componentCount)) &&
1237                          "Tangents buffer length not a multiple of element size");
1238       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * componentCount));
1239     }
1240     else if(MaskMatch(mFlags, S16_TANGENT))
1241     {
1242       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
1243                           mTangents.mBlob.mStride >= (sizeof(int16_t) * componentCount)) &&
1244                          "Tangents buffer length not a multiple of element size");
1245       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * componentCount));
1246     }
1247     else
1248     {
1249       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
1250                           mTangents.mBlob.mStride >= propertySize) &&
1251                          "Tangents buffer length not a multiple of element size");
1252       numTangents = static_cast<uint32_t>(bufferSize / propertySize);
1253     }
1254
1255     std::vector<uint8_t> buffer(bufferSize);
1256
1257     std::string path;
1258     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTangents.mBufferIdx], path);
1259     if(!ReadAccessor(mTangents, stream, buffer.data()))
1260     {
1261       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
1262     }
1263
1264     GetDequantizedData(buffer, componentCount, numTangents, mFlags & TANGENTS_MASK, mTangents.mNormalized);
1265
1266     if(mTangents.mNormalized)
1267     {
1268       GetDequantizedMinMax(mTangents.mBlob.mMin, mTangents.mBlob.mMax, mFlags & TANGENTS_MASK);
1269     }
1270
1271     mTangents.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
1272
1273     raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
1274   }
1275   else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
1276   {
1277     DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
1278     static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2][2] =
1279       {
1280         {
1281           {
1282             GenerateTangents<false, false, false>,
1283             GenerateTangents<false, false, true>,
1284           },
1285           {
1286             GenerateTangents<false, true, false>,
1287             GenerateTangents<false, true, true>,
1288           },
1289         },
1290         {
1291           {
1292             GenerateTangents<true, false, false>,
1293             GenerateTangents<true, false, true>,
1294           },
1295           {
1296             GenerateTangents<true, true, false>,
1297             GenerateTangents<true, true, true>,
1298           },
1299         }};
1300     const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
1301     if(!generateSuccessed)
1302     {
1303       DALI_LOG_ERROR("Failed to generate tangents\n");
1304     }
1305   }
1306
1307   if(mColors.IsDefined())
1308   {
1309     uint32_t       propertySize = mColors.mBlob.mElementSizeHint;
1310     Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
1311     if(propertyType != Property::NONE)
1312     {
1313       DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) ||
1314                           mColors.mBlob.mStride >= propertySize) &&
1315                          "Colors buffer length not a multiple of element size");
1316       const auto           bufferSize = mColors.mBlob.GetBufferSize();
1317       std::vector<uint8_t> buffer(bufferSize);
1318
1319       std::string path;
1320       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path);
1321       if(!ReadAccessor(mColors, stream, buffer.data()))
1322       {
1323         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
1324       }
1325       mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
1326
1327       raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
1328     }
1329   }
1330   else
1331   {
1332     std::vector<uint8_t> buffer(raw.mAttribs[0].mNumElements * sizeof(Vector4));
1333     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
1334
1335     for(uint32_t i = 0; i < raw.mAttribs[0].mNumElements; i++)
1336     {
1337       colors[i] = Vector4::ONE;
1338     }
1339
1340     raw.mAttribs.push_back({"aVertexColor", Property::VECTOR4, raw.mAttribs[0].mNumElements, std::move(buffer)});
1341   }
1342
1343   if(IsSkinned())
1344   {
1345     std::string pathJoint;
1346     auto&       streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint);
1347     if(MaskMatch(mFlags, U16_JOINT_IDS))
1348     {
1349       ReadJointAccessor<uint16_t>(raw, mJoints0, streamJoint, pathJoint);
1350     }
1351     else if(MaskMatch(mFlags, U8_JOINT_IDS))
1352     {
1353       ReadJointAccessor<uint8_t>(raw, mJoints0, streamJoint, pathJoint);
1354     }
1355     else
1356     {
1357       ReadJointAccessor<float>(raw, mJoints0, streamJoint, pathJoint);
1358     }
1359
1360     std::string pathWeight;
1361     auto&       streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight);
1362     if(MaskMatch(mFlags, U16_WEIGHT))
1363     {
1364       ReadWeightAccessor<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
1365     }
1366     else if(MaskMatch(mFlags, U8_WEIGHT))
1367     {
1368       ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
1369     }
1370     else
1371     {
1372       ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
1373     }
1374   }
1375
1376   // Calculate the Blob for the blend shapes.
1377   Blob blendShapesBlob;
1378   blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
1379   blendShapesBlob.mLength = 0u;
1380
1381   uint32_t totalTextureSize(0u);
1382
1383   auto processAccessor = [&](const Accessor& accessor, uint32_t vector3Size) {
1384     if(accessor.IsDefined())
1385     {
1386       blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, accessor.mBlob.mOffset);
1387       blendShapesBlob.mLength += accessor.mBlob.mLength;
1388
1389       totalTextureSize += accessor.mBlob.mLength / vector3Size;
1390     }
1391   };
1392
1393   for(const auto& blendShape : mBlendShapes)
1394   {
1395     const auto positionMask = blendShape.mFlags & POSITIONS_MASK;
1396     const auto normalMask   = blendShape.mFlags & NORMALS_MASK;
1397     const auto tangentMask  = blendShape.mFlags & TANGENTS_MASK;
1398
1399     processAccessor(blendShape.deltas, MaskMatch(positionMask, S8_POSITION) ? sizeof(uint8_t) * 3 : (MaskMatch(positionMask, S16_POSITION) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1400     processAccessor(blendShape.normals, MaskMatch(normalMask, S8_NORMAL) ? sizeof(uint8_t) * 3 : (MaskMatch(normalMask, S16_NORMAL) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1401     processAccessor(blendShape.tangents, MaskMatch(tangentMask, S8_TANGENT) ? sizeof(uint8_t) * 3 : (MaskMatch(tangentMask, S16_TANGENT) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1402   }
1403
1404   if(HasBlendShapes())
1405   {
1406     // Calculate the size of one buffer inside the texture.
1407     raw.mBlendShapeBufferOffset = numberOfVertices;
1408
1409     bool     calculateGltf2BlendShapes = false;
1410     uint32_t textureWidth              = 0u;
1411     uint32_t textureHeight             = 0u;
1412
1413     if(!mBlendShapeHeader.IsDefined())
1414     {
1415       CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
1416       calculateGltf2BlendShapes = true;
1417     }
1418     else
1419     {
1420       uint16_t header[2u];
1421       ReadBlob(mBlendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
1422       textureWidth  = header[0u];
1423       textureHeight = header[1u];
1424     }
1425
1426     const uint32_t numberOfBlendShapes = mBlendShapes.size();
1427     raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
1428
1429     Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
1430     uint8_t*           geometryBuffer      = geometryPixelBuffer.GetBuffer();
1431
1432     if(calculateGltf2BlendShapes)
1433     {
1434       CalculateGltf2BlendShapes(geometryBuffer, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u], buffers);
1435     }
1436     else
1437     {
1438       Blob unnormalizeFactorBlob;
1439       unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes));
1440
1441       if(blendShapesBlob.IsDefined())
1442       {
1443         if(ReadBlob(blendShapesBlob, fileStream, geometryBuffer))
1444         {
1445           unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
1446         }
1447       }
1448
1449       // Read the unnormalize factors.
1450       if(unnormalizeFactorBlob.IsDefined())
1451       {
1452         ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
1453       }
1454     }
1455     raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
1456   }
1457
1458   return raw;
1459 }
1460
1461 MeshGeometry MeshDefinition::Load(RawData&& raw) const
1462 {
1463   MeshGeometry meshGeometry;
1464   meshGeometry.geometry = Geometry::New();
1465   meshGeometry.geometry.SetType(mPrimitiveType);
1466
1467   if(IsQuad()) // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
1468   {
1469     auto options          = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
1470     meshGeometry.geometry = MakeTexturedQuadGeometry(options);
1471   }
1472   else
1473   {
1474     if(!raw.mIndices.empty())
1475     {
1476       if(MaskMatch(mFlags, U32_INDICES))
1477       {
1478         // TODO : We can only store indeces as uint16_type. Send Dali::Geometry that we use it as uint32_t actual.
1479         meshGeometry.geometry.SetIndexBuffer(reinterpret_cast<const uint32_t*>(raw.mIndices.data()), raw.mIndices.size() / 2);
1480       }
1481       else
1482       {
1483         meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
1484       }
1485     }
1486
1487     for(auto& a : raw.mAttribs)
1488     {
1489       a.AttachBuffer(meshGeometry.geometry);
1490     }
1491
1492     if(HasBlendShapes())
1493     {
1494       meshGeometry.blendShapeBufferOffset      = raw.mBlendShapeBufferOffset;
1495       meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
1496
1497       meshGeometry.blendShapeGeometry = Texture::New(TextureType::TEXTURE_2D,
1498                                                      raw.mBlendShapeData.GetPixelFormat(),
1499                                                      raw.mBlendShapeData.GetWidth(),
1500                                                      raw.mBlendShapeData.GetHeight());
1501       meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);
1502     }
1503   }
1504
1505   return meshGeometry;
1506 }
1507
1508 void MeshDefinition::RetrieveBlendShapeComponents(bool& hasPositions, bool& hasNormals, bool& hasTangents) const
1509 {
1510   for(const auto& blendShape : mBlendShapes)
1511   {
1512     hasPositions = hasPositions || blendShape.deltas.IsDefined();
1513     hasNormals   = hasNormals || blendShape.normals.IsDefined();
1514     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
1515   }
1516 }
1517
1518 } // namespace Dali::Scene3D::Loader