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