Fix initial white space issue in text
[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_1000) ? 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   // If there are sparse indices then process only relevant data
703   if(sparseIndices && !sparseIndices->empty())
704   {
705     for(auto elementIndex : *sparseIndices)
706     {
707       auto value = values + (elementIndex * numComponents);
708       for(auto i = 0u; i < numComponents; ++i)
709       {
710         clampFn(min.data(), max.data(), i, *value);
711       }
712     }
713   }
714   else // if there's no sparse indices process all vertices
715   {
716     auto end = values + count * numComponents;
717     while(values != end)
718     {
719       auto     nextElement = values + numComponents;
720       uint32_t i           = 0;
721       while(values != nextElement)
722       {
723         clampFn(min.data(), max.data(), i, *values);
724         ++values;
725         ++i;
726       }
727     }
728   }
729 }
730
731 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)
732 : mOffset(offset),
733   mLength(length),
734   mStride(stride),
735   mElementSizeHint(elementSizeHint),
736   mMin(min),
737   mMax(max)
738 {
739 }
740
741 uint32_t MeshDefinition::Blob::GetBufferSize() const
742 {
743   return mLength;
744 }
745
746 void MeshDefinition::Blob::ComputeMinMax(uint32_t numComponents, uint32_t count, float* values)
747 {
748   ComputeMinMax(mMin, mMax, numComponents, count, values);
749 }
750
751 void MeshDefinition::Blob::ApplyMinMax(uint32_t count, float* values, std::vector<uint32_t>* sparseIndices) const
752 {
753   ApplyMinMax(mMin, mMax, count, values, sparseIndices);
754 }
755
756 void MeshDefinition::RawData::Attrib::AttachBuffer(Geometry& g) const
757 {
758   Property::Map attribMap;
759   attribMap[mName]          = mType;
760   VertexBuffer attribBuffer = VertexBuffer::New(attribMap);
761   attribBuffer.SetData(mData.data(), mNumElements);
762
763   g.AddVertexBuffer(attribBuffer);
764 }
765
766 bool MeshDefinition::IsQuad() const
767 {
768   return CaseInsensitiveStringCompare(QUAD, mUri);
769 }
770
771 bool MeshDefinition::IsSkinned() const
772 {
773   return mJoints0.IsDefined() && mWeights0.IsDefined();
774 }
775
776 bool MeshDefinition::HasBlendShapes() const
777 {
778   return !mBlendShapes.empty();
779 }
780
781 void MeshDefinition::RequestNormals()
782 {
783   mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
784 }
785
786 void MeshDefinition::RequestTangents()
787 {
788   mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
789 }
790
791 MeshDefinition::RawData
792 MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
793 {
794   RawData raw;
795   if(IsQuad())
796   {
797     return raw;
798   }
799
800   std::string meshPath;
801   meshPath = modelsPath + mUri;
802   std::fstream fileStream;
803   if(!mUri.empty())
804   {
805     fileStream.open(meshPath, std::ios::in | std::ios::binary);
806     if(!fileStream.is_open())
807     {
808       DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
809     }
810   }
811
812   if(mIndices.IsDefined())
813   {
814     if(MaskMatch(mFlags, U32_INDICES))
815     {
816       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
817                           mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
818                          "Index buffer length not a multiple of element size");
819       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
820       raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
821
822       std::string path;
823       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
824       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
825       {
826         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
827       }
828     }
829     else if(MaskMatch(mFlags, U8_INDICES))
830     {
831       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint8_t) == 0) ||
832                           mIndices.mBlob.mStride >= sizeof(uint8_t)) &&
833                          "Index buffer length not a multiple of element size");
834       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t);
835       raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
836
837       std::string path;
838       auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
839       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
840       if(!ReadAccessor(mIndices, stream, u8s))
841       {
842         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
843       }
844
845       auto u16s = raw.mIndices.data();
846       auto end  = u8s + indexCount;
847       while(u8s != end)
848       {
849         *u16s = static_cast<uint16_t>(*u8s);
850         ++u16s;
851         ++u8s;
852       }
853     }
854     else
855     {
856       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
857                           mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
858                          "Index buffer length not a multiple of element size");
859       raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
860
861       std::string path;
862       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
863       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
864       {
865         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
866       }
867     }
868   }
869
870   std::vector<Vector3> positions;
871   if(mPositions.IsDefined())
872   {
873     DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
874                         mPositions.mBlob.mStride >= sizeof(Vector3)) &&
875                        "Position buffer length not a multiple of element size");
876     const auto           bufferSize = mPositions.mBlob.GetBufferSize();
877     std::vector<uint8_t> buffer(bufferSize);
878
879     std::string path;
880     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mPositions.mBufferIdx], path);
881     if(!ReadAccessor(mPositions, stream, buffer.data()))
882     {
883       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
884     }
885
886     uint32_t numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
887     if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
888     {
889       mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
890     }
891     else
892     {
893       mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
894     }
895
896     if(HasBlendShapes())
897     {
898       positions.resize(numVector3);
899       std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
900     }
901
902     raw.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
903   }
904
905   const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
906   auto       hasNormals  = mNormals.IsDefined();
907   if(hasNormals)
908   {
909     DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
910                         mNormals.mBlob.mStride >= sizeof(Vector3)) &&
911                        "Normal buffer length not a multiple of element size");
912     const auto           bufferSize = mNormals.mBlob.GetBufferSize();
913     std::vector<uint8_t> buffer(bufferSize);
914
915     std::string path;
916     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mNormals.mBufferIdx], path);
917     if(!ReadAccessor(mNormals, stream, buffer.data()))
918     {
919       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
920     }
921
922     mNormals.mBlob.ApplyMinMax(static_cast<uint32_t>(bufferSize / sizeof(Vector3)), reinterpret_cast<float*>(buffer.data()));
923
924     raw.mAttribs.push_back({"aNormal", Property::VECTOR3, static_cast<uint32_t>(bufferSize / sizeof(Vector3)), std::move(buffer)});
925   }
926   else if(mNormals.mBlob.mLength != 0 && isTriangles)
927   {
928     DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
929     static const std::function<bool(RawData&)> GenerateNormalsFunction[2] =
930       {
931         GenerateNormals<false>,
932         GenerateNormals<true>,
933       };
934     const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw);
935     if(!generateSuccessed)
936     {
937       DALI_LOG_ERROR("Failed to generate normal\n");
938     }
939     else
940     {
941       hasNormals = true;
942     }
943   }
944
945   const auto hasUvs = mTexCoords.IsDefined();
946   if(hasUvs)
947   {
948     DALI_ASSERT_ALWAYS(((mTexCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
949                         mTexCoords.mBlob.mStride >= sizeof(Vector2)) &&
950                        "Normal buffer length not a multiple of element size");
951     const auto           bufferSize = mTexCoords.mBlob.GetBufferSize();
952     std::vector<uint8_t> buffer(bufferSize);
953
954     std::string path;
955     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTexCoords.mBufferIdx], path);
956     if(!ReadAccessor(mTexCoords, stream, buffer.data()))
957     {
958       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
959     }
960
961     const auto uvCount = bufferSize / sizeof(Vector2);
962     if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
963     {
964       auto uv    = reinterpret_cast<Vector2*>(buffer.data());
965       auto uvEnd = uv + uvCount;
966       while(uv != uvEnd)
967       {
968         uv->y = 1.0f - uv->y;
969         ++uv;
970       }
971     }
972
973     mTexCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
974
975     raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
976   }
977
978   if(mTangents.IsDefined())
979   {
980     uint32_t propertySize = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
981     DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
982                         mTangents.mBlob.mStride >= propertySize) &&
983                        "Tangents buffer length not a multiple of element size");
984     const auto           bufferSize = mTangents.mBlob.GetBufferSize();
985     std::vector<uint8_t> buffer(bufferSize);
986
987     std::string path;
988     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTangents.mBufferIdx], path);
989     if(!ReadAccessor(mTangents, stream, buffer.data()))
990     {
991       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
992     }
993     mTangents.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
994
995     raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
996   }
997   else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
998   {
999     DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
1000     static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2][2] =
1001       {
1002         {
1003           {
1004             GenerateTangents<false, false, false>,
1005             GenerateTangents<false, false, true>,
1006           },
1007           {
1008             GenerateTangents<false, true, false>,
1009             GenerateTangents<false, true, true>,
1010           },
1011         },
1012         {
1013           {
1014             GenerateTangents<true, false, false>,
1015             GenerateTangents<true, false, true>,
1016           },
1017           {
1018             GenerateTangents<true, true, false>,
1019             GenerateTangents<true, true, true>,
1020           },
1021         }};
1022     const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
1023     if(!generateSuccessed)
1024     {
1025       DALI_LOG_ERROR("Failed to generate tangents\n");
1026     }
1027   }
1028
1029   if(mColors.IsDefined())
1030   {
1031     uint32_t       propertySize = mColors.mBlob.mElementSizeHint;
1032     Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
1033     if(propertyType != Property::NONE)
1034     {
1035       DALI_ASSERT_ALWAYS(((mColors.mBlob.mLength % propertySize == 0) ||
1036                           mColors.mBlob.mStride >= propertySize) &&
1037                          "Colors buffer length not a multiple of element size");
1038       const auto           bufferSize = mColors.mBlob.GetBufferSize();
1039       std::vector<uint8_t> buffer(bufferSize);
1040
1041       std::string path;
1042       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mColors.mBufferIdx], path);
1043       if(!ReadAccessor(mColors, stream, buffer.data()))
1044       {
1045         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
1046       }
1047       mColors.mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
1048
1049       raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
1050     }
1051   }
1052   else
1053   {
1054     std::vector<uint8_t> buffer(raw.mAttribs[0].mNumElements * sizeof(Vector4));
1055     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
1056
1057     for(uint32_t i = 0; i < raw.mAttribs[0].mNumElements; i++)
1058     {
1059       colors[i] = Vector4::ONE;
1060     }
1061
1062     raw.mAttribs.push_back({"aVertexColor", Property::VECTOR4, raw.mAttribs[0].mNumElements, std::move(buffer)});
1063   }
1064
1065   if(IsSkinned())
1066   {
1067     std::string pathJoint;
1068     auto&       streamJoint = GetAvailableData(fileStream, meshPath, buffers[mJoints0.mBufferIdx], pathJoint);
1069     if(MaskMatch(mFlags, U16_JOINT_IDS))
1070     {
1071       ReadJointAccessor<uint16_t>(raw, mJoints0, streamJoint, pathJoint);
1072     }
1073     else if(MaskMatch(mFlags, U8_JOINT_IDS))
1074     {
1075       ReadJointAccessor<uint8_t>(raw, mJoints0, streamJoint, pathJoint);
1076     }
1077     else
1078     {
1079       ReadJointAccessor<float>(raw, mJoints0, streamJoint, pathJoint);
1080     }
1081
1082     std::string pathWeight;
1083     auto&       streamWeight = GetAvailableData(fileStream, meshPath, buffers[mWeights0.mBufferIdx], pathWeight);
1084     if(MaskMatch(mFlags, U16_WEIGHT))
1085     {
1086       ReadWeightAccessor<uint16_t>(raw, mWeights0, streamWeight, pathWeight);
1087     }
1088     else if(MaskMatch(mFlags, U8_WEIGHT))
1089     {
1090       ReadWeightAccessor<uint8_t>(raw, mWeights0, streamWeight, pathWeight);
1091     }
1092     else
1093     {
1094       ReadWeightAccessor<float>(raw, mWeights0, streamWeight, pathWeight);
1095     }
1096   }
1097
1098   // Calculate the Blob for the blend shapes.
1099   Blob blendShapesBlob;
1100   blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
1101   blendShapesBlob.mLength = 0u;
1102
1103   for(const auto& blendShape : mBlendShapes)
1104   {
1105     for(auto i : {&blendShape.deltas, &blendShape.normals, &blendShape.tangents})
1106     {
1107       if(i->IsDefined())
1108       {
1109         blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, i->mBlob.mOffset);
1110         blendShapesBlob.mLength += i->mBlob.mLength;
1111       }
1112     }
1113   }
1114
1115   if(HasBlendShapes())
1116   {
1117     const uint32_t numberOfVertices = static_cast<uint32_t>(mPositions.mBlob.mLength / sizeof(Vector3));
1118
1119     // Calculate the size of one buffer inside the texture.
1120     raw.mBlendShapeBufferOffset = numberOfVertices;
1121
1122     bool     calculateGltf2BlendShapes = false;
1123     uint32_t textureWidth              = 0u;
1124     uint32_t textureHeight             = 0u;
1125
1126     if(!mBlendShapeHeader.IsDefined())
1127     {
1128       CalculateTextureSize(static_cast<uint32_t>(blendShapesBlob.mLength / sizeof(Vector3)), textureWidth, textureHeight);
1129       calculateGltf2BlendShapes = true;
1130     }
1131     else
1132     {
1133       uint16_t header[2u];
1134       ReadBlob(mBlendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
1135       textureWidth  = header[0u];
1136       textureHeight = header[1u];
1137     }
1138
1139     const uint32_t numberOfBlendShapes = mBlendShapes.size();
1140     raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
1141
1142     Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
1143     uint8_t*           geometryBuffer      = geometryPixelBuffer.GetBuffer();
1144
1145     if(calculateGltf2BlendShapes)
1146     {
1147       CalculateGltf2BlendShapes(geometryBuffer, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u], buffers);
1148     }
1149     else
1150     {
1151       Blob unnormalizeFactorBlob;
1152       unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes));
1153
1154       if(blendShapesBlob.IsDefined())
1155       {
1156         if(ReadBlob(blendShapesBlob, fileStream, geometryBuffer))
1157         {
1158           unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
1159         }
1160       }
1161
1162       // Read the unnormalize factors.
1163       if(unnormalizeFactorBlob.IsDefined())
1164       {
1165         ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
1166       }
1167     }
1168     raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
1169   }
1170
1171   return raw;
1172 }
1173
1174 MeshGeometry MeshDefinition::Load(RawData&& raw) const
1175 {
1176   MeshGeometry meshGeometry;
1177   meshGeometry.geometry = Geometry::New();
1178   meshGeometry.geometry.SetType(mPrimitiveType);
1179
1180   if(IsQuad()) // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
1181   {
1182     auto options          = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
1183     meshGeometry.geometry = MakeTexturedQuadGeometry(options);
1184   }
1185   else
1186   {
1187     if(!raw.mIndices.empty())
1188     {
1189       if(MaskMatch(mFlags, U32_INDICES))
1190       {
1191         // TODO : We can only store indeces as uint16_type. Send Dali::Geometry that we use it as uint32_t actual.
1192         meshGeometry.geometry.SetIndexBuffer(reinterpret_cast<const uint32_t*>(raw.mIndices.data()), raw.mIndices.size() / 2);
1193       }
1194       else
1195       {
1196         meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
1197       }
1198     }
1199
1200     for(auto& a : raw.mAttribs)
1201     {
1202       a.AttachBuffer(meshGeometry.geometry);
1203     }
1204
1205     if(HasBlendShapes())
1206     {
1207       meshGeometry.blendShapeBufferOffset      = raw.mBlendShapeBufferOffset;
1208       meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
1209
1210       meshGeometry.blendShapeGeometry = Texture::New(TextureType::TEXTURE_2D,
1211                                                      raw.mBlendShapeData.GetPixelFormat(),
1212                                                      raw.mBlendShapeData.GetWidth(),
1213                                                      raw.mBlendShapeData.GetHeight());
1214       meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);
1215     }
1216   }
1217
1218   return meshGeometry;
1219 }
1220
1221 void MeshDefinition::RetrieveBlendShapeComponents(bool& hasPositions, bool& hasNormals, bool& hasTangents) const
1222 {
1223   for(const auto& blendShape : mBlendShapes)
1224   {
1225     hasPositions = hasPositions || blendShape.deltas.IsDefined();
1226     hasNormals   = hasNormals || blendShape.normals.IsDefined();
1227     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
1228   }
1229 }
1230
1231 } // namespace Dali::Scene3D::Loader