Added vertex color test to model primitive
[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
971 bool MeshDefinition::HasVertexColor() const
972 {
973   return !mColors.empty();
974 }
975
976 uint32_t MeshDefinition::GetNumberOfJointSets() const
977 {
978   return static_cast<uint32_t>(mJoints.size());
979 }
980
981 bool MeshDefinition::HasBlendShapes() const
982 {
983   return !mBlendShapes.empty();
984 }
985
986 void MeshDefinition::RequestNormals()
987 {
988   mNormals.mBlob.mLength = mPositions.mBlob.GetBufferSize();
989 }
990
991 void MeshDefinition::RequestTangents()
992 {
993   mTangents.mBlob.mLength = mNormals.mBlob.GetBufferSize();
994 }
995
996 MeshDefinition::RawData
997 MeshDefinition::LoadRaw(const std::string& modelsPath, BufferDefinition::Vector& buffers)
998 {
999   RawData raw;
1000   if(IsQuad())
1001   {
1002     return raw;
1003   }
1004
1005   std::string meshPath;
1006   meshPath = modelsPath + mUri;
1007   std::fstream fileStream;
1008   if(!mUri.empty())
1009   {
1010     fileStream.open(meshPath, std::ios::in | std::ios::binary);
1011     if(!fileStream.is_open())
1012     {
1013       DALI_LOG_ERROR("Fail to open buffer from %s.\n", meshPath.c_str());
1014     }
1015   }
1016
1017   if(mIndices.IsDefined())
1018   {
1019     if(MaskMatch(mFlags, U32_INDICES))
1020     {
1021       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint32_t) == 0) ||
1022                           mIndices.mBlob.mStride >= sizeof(uint32_t)) &&
1023                          "Index buffer length not a multiple of element size");
1024       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint32_t);
1025       raw.mIndices.resize(indexCount * 2); // NOTE: we need space for uint32_ts initially.
1026
1027       std::string path;
1028       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
1029       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
1030       {
1031         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
1032       }
1033     }
1034     else if(MaskMatch(mFlags, U8_INDICES))
1035     {
1036       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(uint8_t) == 0) ||
1037                           mIndices.mBlob.mStride >= sizeof(uint8_t)) &&
1038                          "Index buffer length not a multiple of element size");
1039       const auto indexCount = mIndices.mBlob.GetBufferSize() / sizeof(uint8_t);
1040       raw.mIndices.resize(indexCount); // NOTE: we need space for uint16_ts initially.
1041
1042       std::string path;
1043       auto        u8s    = reinterpret_cast<uint8_t*>(raw.mIndices.data()) + indexCount;
1044       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
1045       if(!ReadAccessor(mIndices, stream, u8s))
1046       {
1047         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
1048       }
1049
1050       auto u16s = raw.mIndices.data();
1051       auto end  = u8s + indexCount;
1052       while(u8s != end)
1053       {
1054         *u16s = static_cast<uint16_t>(*u8s);
1055         ++u16s;
1056         ++u8s;
1057       }
1058     }
1059     else
1060     {
1061       DALI_ASSERT_ALWAYS(((mIndices.mBlob.mLength % sizeof(unsigned short) == 0) ||
1062                           mIndices.mBlob.mStride >= sizeof(unsigned short)) &&
1063                          "Index buffer length not a multiple of element size");
1064       raw.mIndices.resize(mIndices.mBlob.mLength / sizeof(unsigned short));
1065
1066       std::string path;
1067       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mIndices.mBufferIdx], path);
1068       if(!ReadAccessor(mIndices, stream, reinterpret_cast<uint8_t*>(raw.mIndices.data())))
1069       {
1070         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read indices from '" << path << "'.";
1071       }
1072     }
1073   }
1074
1075   uint32_t numberOfVertices = 0u;
1076
1077   std::vector<Vector3> positions;
1078   if(mPositions.IsDefined())
1079   {
1080     const auto bufferSize = mPositions.mBlob.GetBufferSize();
1081     uint32_t   numVector3;
1082
1083     if(MaskMatch(mFlags, S8_POSITION) || MaskMatch(mFlags, U8_POSITION))
1084     {
1085       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint8_t) * 3) == 0) ||
1086                           mPositions.mBlob.mStride >= (sizeof(uint8_t) * 3)) &&
1087                          "Position buffer length not a multiple of element size");
1088       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 3));
1089     }
1090     else if(MaskMatch(mFlags, S16_POSITION) || MaskMatch(mFlags, U16_POSITION))
1091     {
1092       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % (sizeof(uint16_t) * 3) == 0) ||
1093                           mPositions.mBlob.mStride >= (sizeof(uint16_t) * 3)) &&
1094                          "Position buffer length not a multiple of element size");
1095       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 3));
1096     }
1097     else
1098     {
1099       DALI_ASSERT_ALWAYS(((mPositions.mBlob.mLength % sizeof(Vector3) == 0) ||
1100                           mPositions.mBlob.mStride >= sizeof(Vector3)) &&
1101                          "Position buffer length not a multiple of element size");
1102       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
1103     }
1104
1105     numberOfVertices = numVector3;
1106
1107     std::vector<uint8_t> buffer(bufferSize);
1108
1109     std::string path;
1110     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mPositions.mBufferIdx], path);
1111     if(!ReadAccessor(mPositions, stream, buffer.data()))
1112     {
1113       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read positions from '" << path << "'.";
1114     }
1115
1116     GetDequantizedData(buffer, 3u, numVector3, mFlags & POSITIONS_MASK, mPositions.mNormalized);
1117
1118     if(mPositions.mNormalized)
1119     {
1120       GetDequantizedMinMax(mPositions.mBlob.mMin, mPositions.mBlob.mMax, mFlags & POSITIONS_MASK);
1121     }
1122
1123     if(mPositions.mBlob.mMin.size() != 3u || mPositions.mBlob.mMax.size() != 3u)
1124     {
1125       mPositions.mBlob.ComputeMinMax(3u, numVector3, reinterpret_cast<float*>(buffer.data()));
1126     }
1127     else
1128     {
1129       mPositions.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
1130     }
1131
1132     if(HasBlendShapes())
1133     {
1134       positions.resize(numVector3);
1135       std::copy(buffer.data(), buffer.data() + buffer.size(), reinterpret_cast<uint8_t*>(positions.data()));
1136     }
1137
1138     raw.mAttribs.push_back({"aPosition", Property::VECTOR3, numVector3, std::move(buffer)});
1139   }
1140
1141   const auto isTriangles = mPrimitiveType == Geometry::TRIANGLES;
1142   auto       hasNormals  = mNormals.IsDefined();
1143   if(hasNormals)
1144   {
1145     const auto bufferSize = mNormals.mBlob.GetBufferSize();
1146     uint32_t   numVector3;
1147
1148     if(MaskMatch(mFlags, S8_NORMAL))
1149     {
1150       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int8_t) * 3) == 0) ||
1151                           mNormals.mBlob.mStride >= (sizeof(int8_t) * 3)) &&
1152                          "Normal buffer length not a multiple of element size");
1153       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * 3));
1154     }
1155     else if(MaskMatch(mFlags, S16_NORMAL))
1156     {
1157       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % (sizeof(int16_t) * 3) == 0) ||
1158                           mNormals.mBlob.mStride >= (sizeof(int16_t) * 3)) &&
1159                          "Normal buffer length not a multiple of element size");
1160       numVector3 = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * 3));
1161     }
1162     else
1163     {
1164       DALI_ASSERT_ALWAYS(((mNormals.mBlob.mLength % sizeof(Vector3) == 0) ||
1165                           mNormals.mBlob.mStride >= sizeof(Vector3)) &&
1166                          "Normal buffer length not a multiple of element size");
1167       numVector3 = static_cast<uint32_t>(bufferSize / sizeof(Vector3));
1168     }
1169
1170     std::vector<uint8_t> buffer(bufferSize);
1171
1172     std::string path;
1173     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mNormals.mBufferIdx], path);
1174     if(!ReadAccessor(mNormals, stream, buffer.data()))
1175     {
1176       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read normals from '" << path << "'.";
1177     }
1178
1179     GetDequantizedData(buffer, 3u, numVector3, mFlags & NORMALS_MASK, mNormals.mNormalized);
1180
1181     if(mNormals.mNormalized)
1182     {
1183       GetDequantizedMinMax(mNormals.mBlob.mMin, mNormals.mBlob.mMax, mFlags & NORMALS_MASK);
1184     }
1185
1186     mNormals.mBlob.ApplyMinMax(numVector3, reinterpret_cast<float*>(buffer.data()));
1187
1188     raw.mAttribs.push_back({"aNormal", Property::VECTOR3, numVector3, std::move(buffer)});
1189   }
1190   else if(mNormals.mBlob.mLength != 0 && isTriangles)
1191   {
1192     DALI_ASSERT_DEBUG(mNormals.mBlob.mLength == mPositions.mBlob.GetBufferSize());
1193     static const std::function<bool(RawData&)> GenerateNormalsFunction[2] =
1194       {
1195         GenerateNormals<false>,
1196         GenerateNormals<true>,
1197       };
1198     const bool generateSuccessed = GenerateNormalsFunction[MaskMatch(mFlags, U32_INDICES)](raw);
1199     if(!generateSuccessed)
1200     {
1201       DALI_LOG_ERROR("Failed to generate normal\n");
1202     }
1203     else
1204     {
1205       hasNormals = true;
1206     }
1207   }
1208
1209   if(!mTexCoords.empty() && mTexCoords[0].IsDefined())
1210   {
1211     auto& texCoords = mTexCoords[0];
1212     const auto bufferSize = texCoords.mBlob.GetBufferSize();
1213     uint32_t uvCount;
1214
1215     if(MaskMatch(mFlags, S8_TEXCOORD) || MaskMatch(mFlags, U8_TEXCOORD))
1216     {
1217       DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint8_t) * 2) == 0) ||
1218                           texCoords.mBlob.mStride >= (sizeof(uint8_t) * 2)) &&
1219                          "TexCoords buffer length not a multiple of element size");
1220       uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint8_t) * 2));
1221     }
1222     else if(MaskMatch(mFlags, S16_TEXCOORD) || MaskMatch(mFlags, U16_TEXCOORD))
1223     {
1224       DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % (sizeof(uint16_t) * 2) == 0) ||
1225                           texCoords.mBlob.mStride >= (sizeof(uint16_t) * 2)) &&
1226                          "TexCoords buffer length not a multiple of element size");
1227       uvCount = static_cast<uint32_t>(bufferSize / (sizeof(uint16_t) * 2));
1228     }
1229     else
1230     {
1231       DALI_ASSERT_ALWAYS(((texCoords.mBlob.mLength % sizeof(Vector2) == 0) ||
1232                           texCoords.mBlob.mStride >= sizeof(Vector2)) &&
1233                          "TexCoords buffer length not a multiple of element size");
1234       uvCount = static_cast<uint32_t>(bufferSize / sizeof(Vector2));
1235     }
1236
1237     std::vector<uint8_t> buffer(bufferSize);
1238
1239     std::string path;
1240     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[texCoords.mBufferIdx], path);
1241     if(!ReadAccessor(texCoords, stream, buffer.data()))
1242     {
1243       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read uv-s from '" << path << "'.";
1244     }
1245
1246     GetDequantizedData(buffer, 2u, uvCount, mFlags & TEXCOORDS_MASK, texCoords.mNormalized);
1247
1248     if(MaskMatch(mFlags, FLIP_UVS_VERTICAL))
1249     {
1250       auto uv    = reinterpret_cast<Vector2*>(buffer.data());
1251       auto uvEnd = uv + uvCount;
1252       while(uv != uvEnd)
1253       {
1254         uv->y = 1.0f - uv->y;
1255         ++uv;
1256       }
1257     }
1258
1259     if(texCoords.mNormalized)
1260     {
1261       GetDequantizedMinMax(texCoords.mBlob.mMin, texCoords.mBlob.mMax, mFlags & TEXCOORDS_MASK);
1262     }
1263
1264     texCoords.mBlob.ApplyMinMax(static_cast<uint32_t>(uvCount), reinterpret_cast<float*>(buffer.data()));
1265     raw.mAttribs.push_back({"aTexCoord", Property::VECTOR2, static_cast<uint32_t>(uvCount), std::move(buffer)});
1266   }
1267
1268   if(mTangents.IsDefined())
1269   {
1270     const auto bufferSize = mTangents.mBlob.GetBufferSize();
1271
1272     uint32_t propertySize   = static_cast<uint32_t>((mTangentType == Property::VECTOR4) ? sizeof(Vector4) : sizeof(Vector3));
1273     uint32_t componentCount = static_cast<uint32_t>(propertySize / sizeof(float));
1274
1275     uint32_t numTangents;
1276
1277     if(MaskMatch(mFlags, S8_TANGENT))
1278     {
1279       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int8_t) * componentCount) == 0) ||
1280                           mTangents.mBlob.mStride >= (sizeof(int8_t) * componentCount)) &&
1281                          "Tangents buffer length not a multiple of element size");
1282       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int8_t) * componentCount));
1283     }
1284     else if(MaskMatch(mFlags, S16_TANGENT))
1285     {
1286       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % (sizeof(int16_t) * componentCount) == 0) ||
1287                           mTangents.mBlob.mStride >= (sizeof(int16_t) * componentCount)) &&
1288                          "Tangents buffer length not a multiple of element size");
1289       numTangents = static_cast<uint32_t>(bufferSize / (sizeof(int16_t) * componentCount));
1290     }
1291     else
1292     {
1293       DALI_ASSERT_ALWAYS(((mTangents.mBlob.mLength % propertySize == 0) ||
1294                           mTangents.mBlob.mStride >= propertySize) &&
1295                          "Tangents buffer length not a multiple of element size");
1296       numTangents = static_cast<uint32_t>(bufferSize / propertySize);
1297     }
1298
1299     std::vector<uint8_t> buffer(bufferSize);
1300
1301     std::string path;
1302     auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mTangents.mBufferIdx], path);
1303     if(!ReadAccessor(mTangents, stream, buffer.data()))
1304     {
1305       ExceptionFlinger(ASSERT_LOCATION) << "Failed to read tangents from '" << path << "'.";
1306     }
1307
1308     GetDequantizedData(buffer, componentCount, numTangents, mFlags & TANGENTS_MASK, mTangents.mNormalized);
1309
1310     if(mTangents.mNormalized)
1311     {
1312       GetDequantizedMinMax(mTangents.mBlob.mMin, mTangents.mBlob.mMax, mFlags & TANGENTS_MASK);
1313     }
1314
1315     mTangents.mBlob.ApplyMinMax(numTangents, reinterpret_cast<float*>(buffer.data()));
1316
1317     raw.mAttribs.push_back({"aTangent", mTangentType, static_cast<uint32_t>(numTangents), std::move(buffer)});
1318   }
1319   else if(mTangents.mBlob.mLength != 0 && hasNormals && isTriangles)
1320   {
1321     DALI_ASSERT_DEBUG(mTangents.mBlob.mLength == mNormals.mBlob.GetBufferSize());
1322     static const std::function<bool(RawData&)> GenerateTangentsFunction[2][2][2] =
1323       {
1324         {
1325           {
1326             GenerateTangents<false, false, false>,
1327             GenerateTangents<false, false, true>,
1328           },
1329           {
1330             GenerateTangents<false, true, false>,
1331             GenerateTangents<false, true, true>,
1332           },
1333         },
1334         {
1335           {
1336             GenerateTangents<true, false, false>,
1337             GenerateTangents<true, false, true>,
1338           },
1339           {
1340             GenerateTangents<true, true, false>,
1341             GenerateTangents<true, true, true>,
1342           },
1343         }};
1344     const bool hasUvs            = !mTexCoords.empty() && mTexCoords[0].IsDefined();
1345     const bool generateSuccessed = GenerateTangentsFunction[MaskMatch(mFlags, U32_INDICES)][mTangentType == Property::VECTOR3][hasUvs](raw);
1346     if(!generateSuccessed)
1347     {
1348       DALI_LOG_ERROR("Failed to generate tangents\n");
1349     }
1350   }
1351
1352   // Only support 1 vertex color
1353   if(!mColors.empty() && mColors[0].IsDefined())
1354   {
1355     uint32_t       propertySize = mColors[0].mBlob.mElementSizeHint;
1356     Property::Type propertyType = (propertySize == sizeof(Vector4)) ? Property::VECTOR4 : ((propertySize == sizeof(Vector3)) ? Property::VECTOR3 : Property::NONE);
1357     if(propertyType != Property::NONE)
1358     {
1359       DALI_ASSERT_ALWAYS(((mColors[0].mBlob.mLength % propertySize == 0) ||
1360                           mColors[0].mBlob.mStride >= propertySize) &&
1361                          "Colors buffer length not a multiple of element size");
1362       const auto           bufferSize = mColors[0].mBlob.GetBufferSize();
1363       std::vector<uint8_t> buffer(bufferSize);
1364
1365       std::string path;
1366       auto&       stream = GetAvailableData(fileStream, meshPath, buffers[mColors[0].mBufferIdx], path);
1367       if(!ReadAccessor(mColors[0], stream, buffer.data()))
1368       {
1369         ExceptionFlinger(ASSERT_LOCATION) << "Failed to read colors from '" << path << "'.";
1370       }
1371       mColors[0].mBlob.ApplyMinMax(bufferSize / propertySize, reinterpret_cast<float*>(buffer.data()));
1372
1373       raw.mAttribs.push_back({"aVertexColor", propertyType, static_cast<uint32_t>(bufferSize / propertySize), std::move(buffer)});
1374     }
1375   }
1376   else
1377   {
1378     std::vector<uint8_t> buffer(raw.mAttribs[0].mNumElements * sizeof(Vector4));
1379     auto                 colors = reinterpret_cast<Vector4*>(buffer.data());
1380
1381     for(uint32_t i = 0; i < raw.mAttribs[0].mNumElements; i++)
1382     {
1383       colors[i] = Vector4::ONE;
1384     }
1385
1386     raw.mAttribs.push_back({"aVertexColor", Property::VECTOR4, raw.mAttribs[0].mNumElements, std::move(buffer)});
1387   }
1388
1389   if(IsSkinned())
1390   {
1391     int setIndex = 0;
1392     for(auto& accessor : mJoints)
1393     {
1394       std::string        pathJoint;
1395       auto&              streamJoint = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathJoint);
1396       std::ostringstream jointName;
1397       jointName << "aJoints" << setIndex;
1398       ++setIndex;
1399       ReadTypedJointAccessor(raw, mFlags, accessor, streamJoint, pathJoint, jointName.str());
1400     }
1401     setIndex = 0;
1402     for(auto& accessor : mWeights)
1403     {
1404       std::string        pathWeight;
1405       auto&              streamWeight = GetAvailableData(fileStream, meshPath, buffers[accessor.mBufferIdx], pathWeight);
1406       std::ostringstream weightName;
1407       weightName << "aWeights" << setIndex;
1408       ++setIndex;
1409       ReadTypedWeightAccessor(raw, mFlags, accessor, streamWeight, pathWeight, weightName.str());
1410     }
1411   }
1412
1413   // Calculate the Blob for the blend shapes.
1414   Blob blendShapesBlob;
1415   blendShapesBlob.mOffset = std::numeric_limits<unsigned int>::max();
1416   blendShapesBlob.mLength = 0u;
1417
1418   uint32_t totalTextureSize(0u);
1419
1420   auto processAccessor = [&](const Accessor& accessor, uint32_t vector3Size) {
1421     if(accessor.IsDefined())
1422     {
1423       blendShapesBlob.mOffset = std::min(blendShapesBlob.mOffset, accessor.mBlob.mOffset);
1424       blendShapesBlob.mLength += accessor.mBlob.mLength;
1425
1426       totalTextureSize += accessor.mBlob.mLength / vector3Size;
1427     }
1428   };
1429
1430   for(const auto& blendShape : mBlendShapes)
1431   {
1432     const auto positionMask = blendShape.mFlags & POSITIONS_MASK;
1433     const auto normalMask   = blendShape.mFlags & NORMALS_MASK;
1434     const auto tangentMask  = blendShape.mFlags & TANGENTS_MASK;
1435
1436     processAccessor(blendShape.deltas, MaskMatch(positionMask, S8_POSITION) ? sizeof(uint8_t) * 3 : (MaskMatch(positionMask, S16_POSITION) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1437     processAccessor(blendShape.normals, MaskMatch(normalMask, S8_NORMAL) ? sizeof(uint8_t) * 3 : (MaskMatch(normalMask, S16_NORMAL) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1438     processAccessor(blendShape.tangents, MaskMatch(tangentMask, S8_TANGENT) ? sizeof(uint8_t) * 3 : (MaskMatch(tangentMask, S16_TANGENT) ? sizeof(uint16_t) * 3 : sizeof(Vector3)));
1439   }
1440
1441   if(HasBlendShapes())
1442   {
1443     // Calculate the size of one buffer inside the texture.
1444     raw.mBlendShapeBufferOffset = numberOfVertices;
1445
1446     bool     calculateGltf2BlendShapes = false;
1447     uint32_t textureWidth              = 0u;
1448     uint32_t textureHeight             = 0u;
1449
1450     if(!mBlendShapeHeader.IsDefined())
1451     {
1452       CalculateTextureSize(totalTextureSize, textureWidth, textureHeight);
1453       calculateGltf2BlendShapes = true;
1454     }
1455     else
1456     {
1457       uint16_t header[2u];
1458       ReadBlob(mBlendShapeHeader, fileStream, reinterpret_cast<uint8_t*>(header));
1459       textureWidth  = header[0u];
1460       textureHeight = header[1u];
1461     }
1462
1463     const uint32_t numberOfBlendShapes = mBlendShapes.size();
1464     raw.mBlendShapeUnnormalizeFactor.Resize(numberOfBlendShapes);
1465
1466     Devel::PixelBuffer geometryPixelBuffer = Devel::PixelBuffer::New(textureWidth, textureHeight, Pixel::RGB32F);
1467     uint8_t*           geometryBuffer      = geometryPixelBuffer.GetBuffer();
1468
1469     if(calculateGltf2BlendShapes)
1470     {
1471       CalculateGltf2BlendShapes(geometryBuffer, mBlendShapes, numberOfVertices, raw.mBlendShapeUnnormalizeFactor[0u], buffers);
1472     }
1473     else
1474     {
1475       Blob unnormalizeFactorBlob;
1476       unnormalizeFactorBlob.mLength = static_cast<uint32_t>(sizeof(float) * ((BlendShapes::Version::VERSION_2_0 == mBlendShapeVersion) ? 1u : numberOfBlendShapes));
1477
1478       if(blendShapesBlob.IsDefined())
1479       {
1480         if(ReadBlob(blendShapesBlob, fileStream, geometryBuffer))
1481         {
1482           unnormalizeFactorBlob.mOffset = blendShapesBlob.mOffset + blendShapesBlob.mLength;
1483         }
1484       }
1485
1486       // Read the unnormalize factors.
1487       if(unnormalizeFactorBlob.IsDefined())
1488       {
1489         ReadBlob(unnormalizeFactorBlob, fileStream, reinterpret_cast<uint8_t*>(&raw.mBlendShapeUnnormalizeFactor[0u]));
1490       }
1491     }
1492     raw.mBlendShapeData = Devel::PixelBuffer::Convert(geometryPixelBuffer);
1493   }
1494
1495   return raw;
1496 }
1497
1498 MeshGeometry MeshDefinition::Load(RawData&& raw) const
1499 {
1500   MeshGeometry meshGeometry;
1501   meshGeometry.geometry = Geometry::New();
1502   meshGeometry.geometry.SetType(mPrimitiveType);
1503
1504   if(IsQuad()) // TODO: do this in raw data; provide MakeTexturedQuadGeometry() that only creates buffers.
1505   {
1506     auto options          = MaskMatch(mFlags, FLIP_UVS_VERTICAL) ? TexturedQuadOptions::FLIP_VERTICAL : 0;
1507     meshGeometry.geometry = MakeTexturedQuadGeometry(options);
1508   }
1509   else
1510   {
1511     if(!raw.mIndices.empty())
1512     {
1513       if(MaskMatch(mFlags, U32_INDICES))
1514       {
1515         // TODO : We can only store indeces as uint16_type. Send Dali::Geometry that we use it as uint32_t actual.
1516         meshGeometry.geometry.SetIndexBuffer(reinterpret_cast<const uint32_t*>(raw.mIndices.data()), raw.mIndices.size() / 2);
1517       }
1518       else
1519       {
1520         meshGeometry.geometry.SetIndexBuffer(raw.mIndices.data(), raw.mIndices.size());
1521       }
1522     }
1523
1524     for(auto& a : raw.mAttribs)
1525     {
1526       a.AttachBuffer(meshGeometry.geometry);
1527     }
1528
1529     if(HasBlendShapes())
1530     {
1531       meshGeometry.blendShapeBufferOffset      = raw.mBlendShapeBufferOffset;
1532       meshGeometry.blendShapeUnnormalizeFactor = std::move(raw.mBlendShapeUnnormalizeFactor);
1533
1534       meshGeometry.blendShapeGeometry = Texture::New(TextureType::TEXTURE_2D,
1535                                                      raw.mBlendShapeData.GetPixelFormat(),
1536                                                      raw.mBlendShapeData.GetWidth(),
1537                                                      raw.mBlendShapeData.GetHeight());
1538       meshGeometry.blendShapeGeometry.Upload(raw.mBlendShapeData);
1539     }
1540   }
1541
1542   return meshGeometry;
1543 }
1544
1545 void MeshDefinition::RetrieveBlendShapeComponents(bool& hasPositions, bool& hasNormals, bool& hasTangents) const
1546 {
1547   for(const auto& blendShape : mBlendShapes)
1548   {
1549     hasPositions = hasPositions || blendShape.deltas.IsDefined();
1550     hasNormals   = hasNormals || blendShape.normals.IsDefined();
1551     hasTangents  = hasTangents || blendShape.tangents.IsDefined();
1552   }
1553 }
1554
1555 } // namespace Dali::Scene3D::Loader