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