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