Merge "Fix the normalization factor calculation for blendshapes" 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 <type_traits>
29
30 namespace Dali::Scene3D::Loader
31 {
32 namespace
33 {
34 template<bool use32BitIndices>
35 class IndexProvider
36 {
37 public:
38   using IndexType = typename std::conditional_t<use32BitIndices, uint32_t, uint16_t>;
39   IndexProvider(const uint16_t* indices)
40   : mData(reinterpret_cast<uintptr_t>(indices)),
41     mFunc(indices ? IncrementPointer : Increment)
42   {
43   }
44
45   IndexType operator()()
46   {
47     return mFunc(mData);
48   }
49
50 private:
51   static IndexType Increment(uintptr_t& data)
52   {
53     // mData was 'zero' at construct time. Just simply return counter start with 0.
54     return static_cast<IndexType>(data++);
55   }
56
57   static IndexType IncrementPointer(uintptr_t& data)
58   {
59     auto iPtr   = reinterpret_cast<const IndexType*>(data);
60     auto result = *iPtr;
61     data        = reinterpret_cast<uintptr_t>(++iPtr);
62     return result;
63   }
64
65   uintptr_t mData;
66   IndexType (*mFunc)(uintptr_t&);
67 };
68
69 const char* QUAD("quad");
70
71 ///@brief Reads a blob from the given stream @a source into @a target, which must have
72 /// at least @a descriptor.length bytes.
73 bool ReadBlob(const MeshDefinition::Blob& descriptor, std::istream& source, uint8_t* target)
74 {
75   source.clear();
76   if(!source.seekg(descriptor.mOffset, std::istream::beg))
77   {
78     return false;
79   }
80
81   if(descriptor.IsConsecutive())
82   {
83     return !!source.read(reinterpret_cast<char*>(target), static_cast<std::streamsize>(static_cast<size_t>(descriptor.mLength)));
84   }
85   else
86   {
87     if(descriptor.mStride > descriptor.mElementSizeHint)
88     {
89       const uint32_t diff      = descriptor.mStride - descriptor.mElementSizeHint;
90       uint32_t       readSize  = 0;
91       uint32_t       totalSize = (descriptor.mLength / descriptor.mElementSizeHint) * descriptor.mStride;
92       while(readSize < totalSize &&
93             source.read(reinterpret_cast<char*>(target), descriptor.mElementSizeHint))
94       {
95         readSize += descriptor.mStride;
96         target += descriptor.mElementSizeHint;
97         source.seekg(diff, std::istream::cur);
98       }
99       return readSize == totalSize;
100     }
101   }
102   return false;
103 }
104
105 template<typename T>
106 void ReadValues(const std::vector<uint8_t>& valuesBuffer, const std::vector<uint8_t>& indicesBuffer, uint8_t* target, uint32_t count, uint32_t elementSizeHint)
107 {
108   const T* const indicesPtr = reinterpret_cast<const T* const>(indicesBuffer.data());
109   for(uint32_t index = 0u; index < count; ++index)
110   {
111     uint32_t valuesIndex = indicesPtr[index] * elementSizeHint;
112     memcpy(target + valuesIndex, &valuesBuffer[index * elementSizeHint], elementSizeHint);
113   }
114 }
115
116 bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target, std::vector<uint32_t>* sparseIndices)
117 {
118   bool success = false;
119
120   if(accessor.mBlob.IsDefined())
121   {
122     success = ReadBlob(accessor.mBlob, source, target);
123     if(!success)
124     {
125       return false;
126     }
127   }
128
129   if(accessor.mSparse)
130   {
131     const MeshDefinition::Blob& indices = accessor.mSparse->mIndices;
132     const MeshDefinition::Blob& values  = accessor.mSparse->mValues;
133
134     if(!indices.IsDefined() || !values.IsDefined())
135     {
136       return false;
137     }
138
139     const auto           indicesBufferSize = indices.GetBufferSize();
140     std::vector<uint8_t> indicesBuffer(indicesBufferSize);
141     success = ReadBlob(indices, source, indicesBuffer.data());
142     if(!success)
143     {
144       return false;
145     }
146
147     const auto           valuesBufferSize = values.GetBufferSize();
148     std::vector<uint8_t> valuesBuffer(valuesBufferSize);
149     success = ReadBlob(values, source, valuesBuffer.data());
150     if(!success)
151     {
152       return false;
153     }
154
155     // If non-null sparse indices vector, prepare it for output
156     if(sparseIndices)
157     {
158       sparseIndices->resize(accessor.mSparse->mCount);
159     }
160
161     switch(indices.mElementSizeHint)
162     {
163       case 1u:
164       {
165         ReadValues<uint8_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
166         if(sparseIndices)
167         {
168           // convert 8-bit indices into 32-bit
169           std::transform(indicesBuffer.begin(), indicesBuffer.end(), sparseIndices->begin(), [](const uint8_t& value) { return uint32_t(value); });
170         }
171         break;
172       }
173       case 2u:
174       {
175         ReadValues<uint16_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
176         if(sparseIndices)
177         {
178           // convert 16-bit indices into 32-bit
179           std::transform(reinterpret_cast<uint16_t*>(indicesBuffer.data()),
180                          reinterpret_cast<uint16_t*>(indicesBuffer.data()) + accessor.mSparse->mCount,
181                          sparseIndices->begin(),
182                          [](const uint16_t& value) {
183                            return uint32_t(value);
184                          });
185         }
186         break;
187       }
188       case 4u:
189       {
190         ReadValues<uint32_t>(valuesBuffer, indicesBuffer, target, accessor.mSparse->mCount, values.mElementSizeHint);
191         if(sparseIndices)
192         {
193           std::copy(indicesBuffer.begin(), indicesBuffer.end(), reinterpret_cast<uint8_t*>(sparseIndices->data()));
194         }
195         break;
196       }
197       default:
198       {
199         DALI_ASSERT_DEBUG(!"Unsupported type for an index");
200       }
201     }
202   }
203
204   return success;
205 }
206
207 bool ReadAccessor(const MeshDefinition::Accessor& accessor, std::istream& source, uint8_t* target)
208 {
209   return ReadAccessor(accessor, source, target, nullptr);
210 }
211
212 template<typename T>
213 void ReadJointAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
214 {
215   constexpr auto sizeofBlobUnit = sizeof(T) * 4;
216
217   DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
218                       accessor.mBlob.mStride >= sizeofBlobUnit) &&
219                      "Joints buffer length not a multiple of element size");
220   const auto inBufferSize  = accessor.mBlob.GetBufferSize();
221   const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
222
223   std::vector<uint8_t> buffer(outBufferSize);
224   auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
225   if(!ReadAccessor(accessor, source, inBuffer))
226   {
227     ExceptionFlinger(ASSERT_LOCATION) << "Failed to read joints from '" << meshPath << "'.";
228   }
229
230   if constexpr(sizeofBlobUnit != sizeof(Vector4))
231   {
232     auto       floats = reinterpret_cast<float*>(buffer.data());
233     const auto end    = inBuffer + inBufferSize;
234     while(inBuffer != end)
235     {
236       const auto value = *reinterpret_cast<T*>(inBuffer);
237       *floats          = static_cast<float>(value);
238
239       inBuffer += sizeof(T);
240       ++floats;
241     }
242   }
243   raw.mAttribs.push_back({"aJoints", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
244 }
245
246 template<typename T>
247 void ReadWeightAccessor(MeshDefinition::RawData& raw, const MeshDefinition::Accessor& accessor, std::istream& source, const std::string& meshPath)
248 {
249   constexpr auto sizeofBlobUnit = sizeof(T) * 4;
250
251   DALI_ASSERT_ALWAYS(((accessor.mBlob.mLength % sizeofBlobUnit == 0) ||
252                       accessor.mBlob.mStride >= sizeofBlobUnit) &&
253                      "weights buffer length not a multiple of element size");
254   const auto inBufferSize  = accessor.mBlob.GetBufferSize();
255   const auto outBufferSize = (sizeof(Vector4) / sizeofBlobUnit) * inBufferSize;
256
257   std::vector<uint8_t> buffer(outBufferSize);
258   auto                 inBuffer = buffer.data() + outBufferSize - inBufferSize;
259   if(!ReadAccessor(accessor, source, inBuffer))
260   {
261     ExceptionFlinger(ASSERT_LOCATION) << "Failed to read weights from '" << meshPath << "'.";
262   }
263
264   if constexpr(sizeofBlobUnit != sizeof(Vector4))
265   {
266     auto       floats = reinterpret_cast<float*>(buffer.data());
267     const auto end    = inBuffer + inBufferSize;
268     while(inBuffer != end)
269     {
270       const auto value = *reinterpret_cast<T*>(inBuffer);
271       // Normalize weight value. value /= 255 for uint8_t weight, and value /= 65535 for uint16_t weight.
272       *floats = static_cast<float>(value) / static_cast<float>((1 << (sizeof(T) * 8)) - 1);
273
274       inBuffer += sizeof(T);
275       ++floats;
276     }
277   }
278   raw.mAttribs.push_back({"aWeights", Property::VECTOR4, static_cast<uint32_t>(outBufferSize / sizeof(Vector4)), std::move(buffer)});
279 }
280
281 template<bool use32BitsIndices, typename IndexProviderType = IndexProvider<use32BitsIndices>>
282 bool GenerateNormals(MeshDefinition::RawData& raw)
283 {
284   using IndexType = typename IndexProviderType::IndexType;
285
286   // mIndicies size must be even if we use 32bit indices.
287   if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0)))
288   {
289     return false;
290   }
291
292   auto& attribs = raw.mAttribs;
293   DALI_ASSERT_DEBUG(attribs.size() > 0); // positions
294
295   IndexProviderType getIndex(raw.mIndices.data());
296
297   const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t)));
298
299   auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
300
301   std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(Vector3));
302   auto                 normals = reinterpret_cast<Vector3*>(buffer.data());
303
304   for(uint32_t i = 0; i < numIndices; i += 3)
305   {
306     IndexType indices[]{getIndex(), getIndex(), getIndex()};
307     Vector3   pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
308
309     Vector3 a = pos[1] - pos[0];
310     Vector3 b = pos[2] - pos[0];
311
312     Vector3 normal(a.Cross(b));
313     normals[indices[0]] += normal;
314     normals[indices[1]] += normal;
315     normals[indices[2]] += normal;
316   }
317
318   auto iEnd = normals + attribs[0].mNumElements;
319   while(normals != iEnd)
320   {
321     normals->Normalize();
322     ++normals;
323   }
324
325   attribs.push_back({"aNormal", Property::VECTOR3, attribs[0].mNumElements, std::move(buffer)});
326
327   return true;
328 }
329
330 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>>
331 bool GenerateTangents(MeshDefinition::RawData& raw)
332 {
333   using IndexType = typename IndexProviderType::IndexType;
334
335   // mIndicies size must be even if we use 32bit indices.
336   if(DALI_UNLIKELY(use32BitsIndices && !raw.mIndices.empty() && !(raw.mIndices.size() % (sizeof(IndexType) / sizeof(uint16_t)) == 0)))
337   {
338     return false;
339   }
340
341   auto& attribs = raw.mAttribs;
342   // Required positions, normals, uvs (if we have). If not, skip generation
343   if(DALI_UNLIKELY(attribs.size() < (2 + static_cast<size_t>(hasUvs))))
344   {
345     return false;
346   }
347
348   std::vector<uint8_t> buffer(attribs[0].mNumElements * sizeof(T));
349   auto                 tangents = reinterpret_cast<T*>(buffer.data());
350
351   if constexpr(hasUvs)
352   {
353     IndexProviderType getIndex(raw.mIndices.data());
354
355     const uint32_t numIndices = raw.mIndices.empty() ? attribs[0].mNumElements : static_cast<uint32_t>(raw.mIndices.size() / (sizeof(IndexType) / sizeof(uint16_t)));
356
357     auto* positions = reinterpret_cast<const Vector3*>(attribs[0].mData.data());
358     auto* uvs       = reinterpret_cast<const Vector2*>(attribs[2].mData.data());
359
360     for(uint32_t i = 0; i < numIndices; i += 3)
361     {
362       IndexType indices[]{getIndex(), getIndex(), getIndex()};
363       Vector3   pos[]{positions[indices[0]], positions[indices[1]], positions[indices[2]]};
364       Vector2   uv[]{uvs[indices[0]], uvs[indices[1]], uvs[indices[2]]};
365
366       float x0 = pos[1].x - pos[0].x;
367       float y0 = pos[1].y - pos[0].y;
368       float z0 = pos[1].z - pos[0].z;
369
370       float x1 = pos[2].x - pos[0].x;
371       float y1 = pos[2].y - pos[0].y;
372       float z1 = pos[2].z - pos[0].z;
373
374       float s0 = uv[1].x - uv[0].x;
375       float t0 = uv[1].y - uv[0].y;
376
377       float s1 = uv[2].x - uv[0].x;
378       float t1 = uv[2].y - uv[0].y;
379
380       float   det = (s0 * t1 - t0 * s1);
381       float   r   = 1.f / ((std::abs(det) < Dali::Epsilon<1000>::value) ? (Dali::Epsilon<1000>::value * (det > 0.0f ? 1.f : -1.f)) : det);
382       Vector3 tangent((x0 * t1 - t0 * x1) * r, (y0 * t1 - t0 * y1) * r, (z0 * t1 - t0 * z1) * r);
383       tangents[indices[0]] += T(tangent);
384       tangents[indices[1]] += T(tangent);
385       tangents[indices[2]] += T(tangent);
386     }
387   }
388
389   auto* normals = reinterpret_cast<const Vector3*>(attribs[1].mData.data());
390   auto  iEnd    = normals + attribs[1].mNumElements;
391   while(normals != iEnd)
392   {
393     Vector3 tangentVec3;
394     if constexpr(hasUvs)
395     {
396       // Calculated by indexs
397       tangentVec3 = Vector3((*tangents).x, (*tangents).y, (*tangents).z);
398     }
399     else
400     {
401       // Only choiced by normal vector. by indexs
402       Vector3 t[]{normals->Cross(Vector3::XAXIS), normals->Cross(Vector3::YAXIS)};
403       tangentVec3 = t[t[1].LengthSquared() > t[0].LengthSquared()];
404     }
405
406     tangentVec3 -= *normals * normals->Dot(tangentVec3);
407     tangentVec3.Normalize();
408     if constexpr(useVec3)
409     {
410       *tangents = tangentVec3;
411     }
412     else
413     {
414       *tangents = Vector4(tangentVec3.x, tangentVec3.y, tangentVec3.z, 1.0f);
415     }
416
417     ++tangents;
418     ++normals;
419   }
420   attribs.push_back({"aTangent", useVec3 ? Property::VECTOR3 : Property::VECTOR4, attribs[0].mNumElements, std::move(buffer)});
421
422   return true;
423 }
424
425 void CalculateTextureSize(uint32_t totalTextureSize, uint32_t& textureWidth, uint32_t& textureHeight)
426 {
427   DALI_ASSERT_DEBUG(0u != totalTextureSize && "totalTextureSize is zero.")
428
429   // Calculate the dimensions of the texture.
430   // The total size of the texture is the length of the blend shapes blob.
431
432   textureWidth  = 0u;
433   textureHeight = 0u;
434
435   if(0u == totalTextureSize)
436   {
437     // nothing to do.
438     return;
439   }
440
441   const uint32_t pow2      = static_cast<uint32_t>(ceil(log2(totalTextureSize)));
442   const uint32_t powWidth  = pow2 >> 1u;
443   const uint32_t powHeight = pow2 - powWidth;
444
445   textureWidth  = 1u << powWidth;
446   textureHeight = 1u << powHeight;
447 }
448
449 void CalculateGltf2BlendShapes(uint8_t* geometryBuffer, const std::vector<MeshDefinition::BlendShape>& blendShapes, uint32_t numberOfVertices, float& blendShapeUnnormalizeFactor, BufferDefinition::Vector& buffers)
450 {
451   uint32_t geometryBufferIndex = 0u;
452   float    maxDistanceSquared  = 0.f;
453   Vector3* geometryBufferV3    = reinterpret_cast<Vector3*>(geometryBuffer);
454   for(const auto& blendShape : blendShapes)
455   {
456     if(blendShape.deltas.IsDefined())
457     {
458       DALI_ASSERT_ALWAYS(((blendShape.deltas.mBlob.mLength % sizeof(Vector3) == 0u) ||
459                           blendShape.deltas.mBlob.mStride >= sizeof(Vector3)) &&
460                          "Blend Shape position buffer length not a multiple of element size");
461
462       const auto            bufferSize = blendShape.deltas.mBlob.GetBufferSize();
463       std::vector<uint8_t>  buffer(bufferSize);
464       std::vector<uint32_t> sparseIndices{};
465
466       if(ReadAccessor(blendShape.deltas, buffers[blendShape.deltas.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
467       {
468         blendShape.deltas.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
469
470         // Calculate the difference with the original mesh.
471         // Find the max distance to normalize the deltas.
472         const auto* const deltasBuffer = reinterpret_cast<const Vector3* const>(buffer.data());
473
474         auto ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
475           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
476           delta                                                  = deltasBuffer[deltaIndex];
477           return std::max(maxDistanceSquared, delta.LengthSquared());
478         };
479
480         if(sparseIndices.empty())
481         {
482           for(uint32_t index = 0u; index < numberOfVertices; ++index)
483           {
484             maxDistanceSquared = ProcessVertex(geometryBufferIndex++, index);
485           }
486         }
487         else
488         {
489           // initialize blendshape texture
490           // TODO: there may be a case when sparse accessor uses a base buffer view for initial values.
491           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3::ZERO);
492           for(auto index : sparseIndices)
493           {
494             maxDistanceSquared = ProcessVertex(geometryBufferIndex + index, index);
495           }
496           geometryBufferIndex += numberOfVertices;
497         }
498       }
499     }
500
501     if(blendShape.normals.IsDefined())
502     {
503       DALI_ASSERT_ALWAYS(((blendShape.normals.mBlob.mLength % sizeof(Vector3) == 0u) ||
504                           blendShape.normals.mBlob.mStride >= sizeof(Vector3)) &&
505                          "Blend Shape normals buffer length not a multiple of element size");
506
507       const auto            bufferSize = blendShape.normals.mBlob.GetBufferSize();
508       std::vector<uint8_t>  buffer(bufferSize);
509       std::vector<uint32_t> sparseIndices;
510
511       if(ReadAccessor(blendShape.normals, buffers[blendShape.normals.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
512       {
513         blendShape.normals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
514
515         // Calculate the difference with the original mesh, and translate to make all values positive.
516         const Vector3* const deltasBuffer  = reinterpret_cast<const Vector3* const>(buffer.data());
517         auto                 ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
518           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
519           delta.x *= 0.5f;
520           delta.y *= 0.5f;
521           delta.z *= 0.5f;
522
523           delta.x += 0.5f;
524           delta.y += 0.5f;
525           delta.z += 0.5f;
526         };
527
528         if(sparseIndices.empty())
529         {
530           for(uint32_t index = 0u; index < numberOfVertices; ++index)
531           {
532             ProcessVertex(geometryBufferIndex++, index);
533           }
534         }
535         else
536         {
537           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3(0.5, 0.5, 0.5));
538           for(auto index : sparseIndices)
539           {
540             ProcessVertex(geometryBufferIndex + index, index);
541           }
542           geometryBufferIndex += numberOfVertices;
543         }
544       }
545     }
546
547     if(blendShape.tangents.IsDefined())
548     {
549       DALI_ASSERT_ALWAYS(((blendShape.tangents.mBlob.mLength % sizeof(Vector3) == 0u) ||
550                           blendShape.tangents.mBlob.mStride >= sizeof(Vector3)) &&
551                          "Blend Shape tangents buffer length not a multiple of element size");
552
553       const auto            bufferSize = blendShape.tangents.mBlob.GetBufferSize();
554       std::vector<uint8_t>  buffer(bufferSize);
555       std::vector<uint32_t> sparseIndices;
556
557       if(ReadAccessor(blendShape.tangents, buffers[blendShape.tangents.mBufferIdx].GetBufferStream(), buffer.data(), &sparseIndices))
558       {
559         blendShape.tangents.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()), &sparseIndices);
560
561         // Calculate the difference with the original mesh, and translate to make all values positive.
562         const Vector3* const deltasBuffer  = reinterpret_cast<const Vector3* const>(buffer.data());
563         auto                 ProcessVertex = [&geometryBufferV3, &deltasBuffer, &maxDistanceSquared](uint32_t geometryBufferIndex, uint32_t deltaIndex) {
564           Vector3& delta = geometryBufferV3[geometryBufferIndex] = deltasBuffer[deltaIndex];
565           delta.x *= 0.5f;
566           delta.y *= 0.5f;
567           delta.z *= 0.5f;
568
569           delta.x += 0.5f;
570           delta.y += 0.5f;
571           delta.z += 0.5f;
572         };
573
574         if(sparseIndices.empty())
575         {
576           for(uint32_t index = 0u; index < numberOfVertices; ++index)
577           {
578             ProcessVertex(geometryBufferIndex++, index);
579           }
580         }
581         else
582         {
583           std::fill(geometryBufferV3 + geometryBufferIndex, geometryBufferV3 + geometryBufferIndex + numberOfVertices, Vector3(0.5, 0.5, 0.5));
584           for(auto index : sparseIndices)
585           {
586             ProcessVertex(geometryBufferIndex + index, index);
587           }
588           geometryBufferIndex += numberOfVertices;
589         }
590       }
591     }
592   }
593
594   geometryBufferIndex = 0u;
595
596   const float maxDistance = sqrtf(maxDistanceSquared);
597
598   const float normalizeFactor = (maxDistanceSquared < Math::MACHINE_EPSILON_100) ? 1.f : (0.5f / maxDistance);
599
600   // Calculate and store the unnormalize factor.
601   blendShapeUnnormalizeFactor = maxDistance * 2.0f;
602
603   for(const auto& blendShape : blendShapes)
604   {
605     // Normalize all the deltas and translate to a possitive value.
606     // Deltas are going to be passed to the shader in a color texture
607     // whose values that are less than zero are clamped.
608     if(blendShape.deltas.IsDefined())
609     {
610       for(uint32_t index = 0u; index < numberOfVertices; ++index)
611       {
612         Vector3& delta = geometryBufferV3[geometryBufferIndex++];
613         delta.x        = Clamp(((delta.x * normalizeFactor) + 0.5f), 0.f, 1.f);
614         delta.y        = Clamp(((delta.y * normalizeFactor) + 0.5f), 0.f, 1.f);
615         delta.z        = Clamp(((delta.z * normalizeFactor) + 0.5f), 0.f, 1.f);
616       }
617     }
618
619     if(blendShape.normals.IsDefined())
620     {
621       geometryBufferIndex += numberOfVertices;
622     }
623
624     if(blendShape.tangents.IsDefined())
625     {
626       geometryBufferIndex += numberOfVertices;
627     }
628   }
629 }
630
631 std::iostream& GetAvailableData(std::fstream& meshStream, const std::string& meshPath, BufferDefinition& buffer, std::string& availablePath)
632 {
633   auto& stream  = (meshStream.is_open()) ? meshStream : buffer.GetBufferStream();
634   availablePath = (meshStream.is_open()) ? meshPath : buffer.GetUri();
635   return stream;
636 }
637
638 } // namespace
639
640 MeshDefinition::SparseBlob::SparseBlob(const Blob& indices, const Blob& values, uint32_t count)
641 : mIndices{indices},
642   mValues{values},
643   mCount{count}
644 {
645 }
646
647 MeshDefinition::SparseBlob::SparseBlob(Blob&& indices, Blob&& values, uint32_t count)
648 : mIndices(std::move(indices)),
649   mValues(std::move(values)),
650   mCount{count}
651 {
652 }
653
654 MeshDefinition::Accessor::Accessor(const MeshDefinition::Blob&       blob,
655                                    const MeshDefinition::SparseBlob& sparse,
656                                    Index                             bufferIndex)
657 : mBlob{blob},
658   mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{sparse} : nullptr},
659   mBufferIdx(bufferIndex)
660 {
661 }
662
663 MeshDefinition::Accessor::Accessor(MeshDefinition::Blob&&       blob,
664                                    MeshDefinition::SparseBlob&& sparse,
665                                    Index                        bufferIndex)
666 : mBlob{std::move(blob)},
667   mSparse{(sparse.mIndices.IsDefined() && sparse.mValues.IsDefined()) ? new SparseBlob{std::move(sparse)} : nullptr},
668   mBufferIdx(bufferIndex)
669 {
670 }
671
672 void MeshDefinition::Blob::ComputeMinMax(std::vector<float>& min, std::vector<float>& max, uint32_t numComponents, uint32_t count, const float* values)
673 {
674   min.assign(numComponents, MAXFLOAT);
675   max.assign(numComponents, -MAXFLOAT);
676   for(uint32_t i = 0; i < count; ++i)
677   {
678     for(uint32_t j = 0; j < numComponents; ++j)
679     {
680       min[j] = std::min(min[j], *values);
681       max[j] = std::max(max[j], *values);
682       values++;
683     }
684   }
685 }
686
687 void MeshDefinition::Blob::ApplyMinMax(const std::vector<float>& min, const std::vector<float>& max, uint32_t count, float* values, std::vector<uint32_t>* sparseIndices)
688 {
689   DALI_ASSERT_DEBUG(max.size() == min.size() || max.size() * min.size() == 0);
690   const auto numComponents = std::max(min.size(), max.size());
691
692   using ClampFn   = void (*)(const float*, const float*, uint32_t, float&);
693   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); })
694                                 : (max.empty() ? [](const float* min, const float* max, uint32_t i, float& value) { value = std::max(min[i], value); }
695                                                : static_cast<ClampFn>([](const float* min, const float* max, uint32_t i, float& value) { value = std::min(std::max(min[i], value), max[i]); }));
696
697   if(!clampFn)
698   {
699     return;
700   }
701
702   auto end = values + count * numComponents;
703   while(values != end)
704   {
705     auto     nextElement = values + numComponents;
706     uint32_t i           = 0;
707     while(values != nextElement)
708     {
709       clampFn(min.data(), max.data(), i, *values);
710       ++values;
711       ++i;
712     }
713   }
714 }
715
716 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)
717 : mOffset(offset),
718   mLength(length),
719   mStride(stride),
720   mElementSizeHint(elementSizeHint),
721   mMin(min),
722   mMax(max)
723 {
724 }
725
726 uint32_t MeshDefinition::Blob::GetBufferSize() const
727 {
728   return mLength;
729 }
730
731 void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
732 {
733   ComputeMinMax(mMin, mMax, numComponents, count, values);
734 }
735
736 void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
737 {
738   ApplyMinMax(mMin, mMax, count, values, sparseIndices);
739 }
740
741 void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
742 {
743   Property::Map attribMap;
744   attribMap[mName]          = mType;
745   VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
746   attribBuffer.SetData(mData.data(), mNumElements);
747
748   g.AddVertexBuffer(attribBuffer);
749 }
750
751 bool MeshDefinition::IsQuad() const
752 {
753   return CaseInsensitiveStringCompare(QUAD, mUri);
754 }
755
756 bool MeshDefinition::IsSkinned() const
757 {
758   return mJoints0.IsDefined() && mWeights0.IsDefined();
759 }
760
761 bool MeshDefinition::HasBlendShapes() const
762 {
763   return !mBlendShapes.empty();
764 }
765
766 void MeshDefinition::RequestNormals()
767 {
768   mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
769 }
770
771 void MeshDefinition::RequestTangents()
772 {
773   mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
774 }
775
776 MeshDefinition::RawData
777 MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
778 {
779   RawData raw;
780   if(IsQuad())
781   {
782     return raw;
783   }
784
785   std::string meshPath;
786   meshPath = modelsPath + mUri;
787   std::fstream fileStream;
788   if(!mUri.empty())
789   {
790     fileStream.open(meshPath, std::ios::in | std::ios::binary);
791     if(!fileStream.is_open())
792     {
793       DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
794     }
795   }
796
797   if(mIndices.IsDefined())
798   {
799     if(MaskMatch(mFlags, U32_INDICES))
800     {
801       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
802                           mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
803                          "Index buffer length not a multiple of element size");
804       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
805       raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
806
807       std::string path;
808       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
809       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
810       {
811         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
812       }
813     }
814     else if(MaskMatch(mFlags, U8_INDICES))
815     {
816       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint8_t) == 0) ||
817                           mIndices.mBlob.mStride >= sizeof(uint8_t)) &&
818                          "Index buffer length not a multiple of element size");
819       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t);
820       raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
821
822       std::string path;
823       auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
824       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
825       if(!ReadAccessor(mIndices, stream, u8s))
826       {
827         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
828       }
829
830       auto u16s = raw.mIndices.data();
831       auto end  = u8s + indexCount;
832       while(u8s != end)
833       {
834         *u16s = static_cast<uint16_t>(*u8s);
835         ++u16s;
836         ++u8s;
837       }
838     }
839     else
840     {
841       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
842                           mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
843                          "Index buffer length not a multiple of element size");
844       raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
845
846       std::string path;
847       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
848       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
849       {
850         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
851       }
852     }
853   }
854
855   std::vector<Vector3> positions;
856   if(mPositions.IsDefined())
857   {
858     DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
859                         mPositions.mBlob.mStride >= sizeof(Vector3)) &&
860                        "Position buffer length not a multiple of element size");
861     const auto           bufferSize = mPositions.mBlob.GetBufferSize();
862     std::vector<uint8_t> buffer(bufferSize);
863
864     std::string path;
865     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mPositions.mBufferIdx], path);
866     if(!ReadAccessor(mPositions, stream, buffer.data()))
867     {
868       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
869     }
870
871     uint32_t numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
872     if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
873     {
874       mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
875     }
876     else
877     {
878       mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
879     }
880
881     if(HasBlendShapes())
882     {
883       positions.resize(numVector3);
884       std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
885     }
886
887     raw.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
888   }
889
890   const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
891   auto       hasNormals  = mNormals.IsDefined();
892   if(hasNormals)
893   {
894     DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
895                         mNormals.mBlob.mStride >= sizeof(Vector3)) &&
896                        "Normal buffer length not a multiple of element size");
897     const auto           bufferSize = mNormals.mBlob.GetBufferSize();
898     std::vector<uint8_t> buffer(bufferSize);
899
900     std::string path;
901     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mNormals.mBufferIdx], path);
902     if(!ReadAccessor(mNormals, stream, buffer.data()))
903     {
904       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
905     }
906
907     mNormals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()));
908
909     raw.mAttribs.push_back({"aNormal", Property::VECTOR3, static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer)});
910   }
911   else if(mNormals.mBlob.mLength != 0 && isTriangles)
912   {
913     DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
914     static const std::function<bool(RawData&)> GenerateNormalsFunction[2] =
915       {
916         GenerateNormals<false>,
917         GenerateNormals<true>,
918       };
919     const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw);
920     if(!generateSuccessed)
921     {
922       DALI_LOG_ERROR("Failed to generate normal\n");
923     }
924     else
925     {
926       hasNormals = true;
927     }
928   }
929
930   const auto hasUvs = mTexCoords.IsDefined();
931   if(hasUvs)
932   {
933     DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
934                         mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
935                        "Normal buffer length not a multiple of element size");
936     const auto           bufferSize = mTexCoords.mBlob.GetBufferSize();
937     std::vector<uint8_t> buffer(bufferSize);
938
939     std::string path;
940     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path);
941     if(!ReadAccessor(mTexCoords, stream, buffer.data()))
942     {
943       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
944     }
945
946     const auto uvCount = bufferSize / sizeof(Vector2);
947     if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
948     {
949       auto uv    = reinterpret_cast<Vector2*>(buffer.data());
950       auto uvEnd = uv + uvCount;
951       while(uv != uvEnd)
952       {
953         uv->y = 1.0f - uv->y;
954         ++uv;
955       }
956     }
957
958     mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
959
960     raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
961   }
962
963   if(mTangents.IsDefined())
964   {
965     uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
966     DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
967                         mTangents.mBlob.mStride >= propertySize) &&
968                        "Tangents buffer length not a multiple of element size");
969     const auto           bufferSize = mTangents.mBlob.GetBufferSize();
970     std::vector<uint8_t> buffer(bufferSize);
971
972     std::string path;
973     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTangents.mBufferIdx], path);
974     if(!ReadAccessor(mTangents, stream, buffer.data()))
975     {
976       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
977     }
978     mTangents.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
979
980     raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
981   }
982   else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
983   {
984     DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
985     static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2][2] =
986       {
987         {
988           {
989             GenerateTangents<false, false, false>,
990             GenerateTangents<false, false, true>,
991           },
992           {
993             GenerateTangents<false, true, false>,
994             GenerateTangents<false, true, true>,
995           },
996         },
997         {
998           {
999             GenerateTangents<true, false, false>,
1000             GenerateTangents<true, false, true>,
1001           },
1002           {
1003             GenerateTangents<true, true, false>,
1004             GenerateTangents<true, true, true>,
1005           },
1006         }};
1007     const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
1008     if(!generateSuccessed)
1009     {
1010       DALI_LOG_ERROR("Failed to generate tangents\n");
1011     }
1012   }
1013
1014   if(mColors.IsDefined())
1015   {
1016     uint32_t       propertySize = mColors.mBlob.mElementSizeHint;
1017     Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
1018     if(propertyType != Property::NONE)
1019     {
1020       DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) ||
1021                           mColors.mBlob.mStride >= propertySize) &&
1022                          "Colors buffer length not a multiple of element size");
1023       const auto           bufferSize = mColors.mBlob.GetBufferSize();
1024       std::vector<uint8_t> buffer(bufferSize);
1025
1026       std::string path;
1027       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path);
1028       if(!ReadAccessor(mColors, stream, buffer.data()))
1029       {
1030         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
1031       }
1032       mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
1033
1034       raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
1035     }
1036   }
1037   else
1038   {
1039     std::vector<uint8_t> buffer(raw.mAttribs[0].mNumElements * sizeof(Vector4));
1040     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
1041
1042     for(uint32_t i = 0; i < raw.mAttribs[0].mNumElements; i++)
1043     {
1044       colors[i] = Vector4::ONE;
1045     }
1046
1047     raw.mAttribs.push_back({"aVertexColor", Property::VECTOR4, raw.mAttribs[0].mNumElements, std::move(buffer)});
1048   }
1049
1050   if(IsSkinned())
1051   {
1052     std::string pathJoint;
1053     auto&       streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint);
1054     if(MaskMatch(mFlags, U16_JOINT_IDS))
1055     {
1056       ReadJointAccessor<uint16_t>(raw, mJoints0, streamJoint, pathJoint);
1057     }
1058     else if(MaskMatch(mFlags, U8_JOINT_IDS))
1059     {
1060       ReadJointAccessor<uint8_t>(raw, mJoints0, streamJoint, pathJoint);
1061     }
1062     else
1063     {
1064       ReadJointAccessor<float>(raw, mJoints0, streamJoint, pathJoint);
1065     }
1066
1067     std::string pathWeight;
1068     auto&       streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight);
1069     if(MaskMatch(mFlags, U16_WEIGHT))
1070     {
1071       ReadWeightAccessor<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
1072     }
1073     else if(MaskMatch(mFlags, U8_WEIGHT))
1074     {
1075       ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
1076     }
1077     else
1078     {
1079       ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
1080     }
1081   }
1082
1083   // Calculate the Blob for the blend shapes.
1084   Blob blendShapesBlob;
1085   blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
1086   blendShapesBlob.mLength = 0u;
1087
1088   for(const auto& blendShape : mBlendShapes)
1089   {
1090     for(auto i : {&blendShape.deltas, &blendShape.normals, &blendShape.tangents})
1091     {
1092       if(i->IsDefined())
1093       {
1094         blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
1095         blendShapesBlob.mLength += i->mBlob.mLength;
1096       }
1097     }
1098   }
1099
1100   if(HasBlendShapes())
1101   {
1102     const uint32_t numberOfVertices = static_cast<uint32_t>(mPositions.mBlob.mLength / sizeof(Vector3));
1103
1104     // Calculate the size of one buffer inside the texture.
1105     raw.mBlendShapeBufferOffset = numberOfVertices;
1106
1107     bool     calculateGltf2BlendShapes = false;
1108     uint32_t textureWidth              = 0u;
1109     uint32_t textureHeight             = 0u;
1110
1111     if(!mBlendShapeHeader.IsDefined())
1112     {
1113       CalculateTextureSize(static_cast<uint32_t>(blendShapesBlob.mLength / sizeof(Vector3)), textureWidth, textureHeight);
1114       calculateGltf2BlendShapes = true;
1115     }
1116     else
1117     {
1118       uint16_t header[2u];
1119       ReadBlob(mBlendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
1120       textureWidth  = header[0u];
1121       textureHeight = header[1u];
1122     }
1123
1124     const uint32_t numberOfBlendShapes = mBlendShapes.size();
1125     raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
1126
1127     Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
1128     uint8_t*           geometryBuffer      = geometryPixelBuffer.GetBuffer();
1129
1130     if(calculateGltf2BlendShapes)
1131     {
1132       CalculateGltf2BlendShapes(geometryBuffer, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u], buffers);
1133     }
1134     else
1135     {
1136       Blob unnormalizeFactorBlob;
1137       unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes));
1138
1139       if(blendShapesBlob.IsDefined())
1140       {
1141         if(ReadBlob(blendShapesBlob, fileStream, geometryBuffer))
1142         {
1143           unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
1144         }
1145       }
1146
1147       // Read the unnormalize factors.
1148       if(unnormalizeFactorBlob.IsDefined())
1149       {
1150         ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
1151       }
1152     }
1153     raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
1154   }
1155
1156   return raw;
1157 }
1158
1159 MeshGeometry MeshDefinition::Load(RawData&& raw) const
1160 {
1161   MeshGeometry meshGeometry;
1162   meshGeometry.geometry = Geometry::New();
1163   meshGeometry.geometry.SetType(mPrimitiveType);
1164
1165   if(IsQuad()) // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
1166   {
1167     auto options          = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
1168     meshGeometry.geometry = MakeTexturedQuadGeometry(options);
1169   }
1170   else
1171   {
1172     if(!raw.mIndices.empty())
1173     {
1174       if(MaskMatch(mFlags, U32_INDICES))
1175       {
1176         // TODO : We can only store indeces as uint16_type. Send Dali::Geometry that we use it as uint32_t actual.
1177         meshGeometry.geometry.SetIndexBuffer(reinterpret_cast<const uint32_t*>(raw.mIndices.data()), raw.mIndices.size() / 2);
1178       }
1179       else
1180       {
1181         meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
1182       }
1183     }
1184
1185     for(auto& a : raw.mAttribs)
1186     {
1187       a.AttachBuffer(meshGeometry.geometry);
1188     }
1189
1190     if(HasBlendShapes())
1191     {
1192       meshGeometry.blendShapeBufferOffset      = raw.mBlendShapeBufferOffset;
1193       meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
1194
1195       meshGeometry.blendShapeGeometry = Texture::New(TextureType::TEXTURE_2D,
1196                                                      raw.mBlendShapeData.GetPixelFormat(),
1197                                                      raw.mBlendShapeData.GetWidth(),
1198                                                      raw.mBlendShapeData.GetHeight());
1199       meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);
1200     }
1201   }
1202
1203   return meshGeometry;
1204 }
1205
1206 void MeshDefinition::RetrieveBlendShapeComponents(bool& hasPositions, bool& hasNormals, bool& hasTangents) const
1207 {
1208   for(const auto& blendShape : mBlendShapes)
1209   {
1210     hasPositions = hasPositions || blendShape.deltas.IsDefined();
1211     hasNormals   = hasNormals || blendShape.normals.IsDefined();
1212     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
1213   }
1214 }
1215
1216 } // namespace Dali::Scene3D::Loader