[dali_2.3.21] Merge branch 'devel/master'
[platform/core/uifw/dali-toolkit.git] / dali-scene3d / internal / loader / json-util.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/internal/loader/json-util.h>
20
21 // EXTERNAL INCLUDES
22 #include <dali/devel-api/common/map-wrapper.h>
23 #include <dali/public-api/common/extents.h>
24 #include <dali/public-api/math/matrix.h>
25 #include <dali/public-api/math/matrix3.h>
26 #include <dali/public-api/math/quaternion.h>
27 #include <dali/public-api/math/radian.h>
28 #include <dali/public-api/math/vector2.h>
29 #include <dali/public-api/math/vector3.h>
30 #include <dali/public-api/object/property-value.h>
31 #include <array>
32
33 namespace Dali
34 {
35 using namespace Toolkit;
36
37 namespace Scene3D
38 {
39 namespace Loader
40 {
41 namespace
42 {
43 template<typename T>
44 Property::Value ReadPrimitiveHelper(const TreeNode* tn, bool (*reader)(const TreeNode*, T&))
45 {
46   T value;
47   if(reader(tn, value))
48   {
49     return Property::Value(value);
50   }
51   return Property::Value();
52 }
53
54 template<typename T>
55 Property::Value ReadVectorHelper(const TreeNode* tn)
56 {
57   static_assert(sizeof(T) % sizeof(float) == 0, "");
58   T value;
59   if(ReadVector(tn, value.AsFloat(), sizeof(T) / sizeof(float)))
60   {
61     return Property::Value(value);
62   }
63   return Property::Value();
64 }
65
66 Property::Value ReadVectorSingleFloatHelper(const TreeNode* tn)
67 {
68   float value;
69   if(ReadVector(tn, &value, 1u))
70   {
71     return Property::Value(value);
72   }
73   return Property::Value();
74 }
75
76 Property::Value ReadRotationHelper(const TreeNode* tn)
77 {
78   switch(tn->Size())
79   {
80     case 3:
81     {
82       // degrees as per spec
83       Vector3 rotation;
84       ReadVector(tn, rotation.AsFloat(), 3u);
85       return Property::Value(Quaternion(Radian(Degree(rotation.x)),
86                                         Radian(Degree(rotation.y)),
87                                         Radian(Degree(rotation.z))));
88     }
89     case 4:
90     {
91       Vector4 v;
92       ReadVector(tn, v.AsFloat(), 4u);
93       //Quaternion
94       return Property::Value(Quaternion(v));
95     }
96     default:
97       return Property::Value();
98   }
99 }
100
101 template<typename T>
102 bool ReadQuadHelper(const TreeNode* tn, const std::array<T*, 4>& quad)
103 {
104   auto i     = quad.begin();
105   auto iEnd  = quad.end();
106   auto iJson = tn->CBegin();
107   while(iJson != tn->CEnd() && i != iEnd)
108   {
109     int value;
110     if(ReadInt(&(*iJson).second, value) && value <= std::numeric_limits<T>::max())
111     {
112       **i = value;
113       ++i;
114       ++iJson;
115     }
116     else
117     {
118       return false;
119     }
120   }
121   return true;
122 }
123
124 const std::map<std::string_view, Property::Value (*)(const TreeNode*)>& GetTypeIds()
125 {
126   static const std::map<std::string_view, Property::Value (*)(const TreeNode*)> kTypeIds{
127     // NONE
128     {"boolean", [](const TreeNode* tn) {
129        return ReadPrimitiveHelper<bool>(tn, ReadBool);
130      }},
131     {"float", [](const TreeNode* tn) {
132        return ReadPrimitiveHelper<float>(tn, ReadFloat);
133      }},
134     {"integer", [](const TreeNode* tn) {
135        return ReadPrimitiveHelper<int>(tn, ReadInt);
136      }},
137     {"vector2", ReadVectorHelper<Vector2>},
138     {"vector3", ReadVectorHelper<Vector3>},
139     {"vector4", ReadVectorHelper<Vector4>},
140     {"matrix3", ReadVectorHelper<Matrix3>},
141     {"matrix", ReadVectorHelper<Matrix>},
142     {"rectangle", [](const TreeNode* tn) {
143        Rect<int> value;
144        if(ReadQuadHelper<int>(tn, {&value.x, &value.y, &value.width, &value.height}))
145        {
146          return Property::Value(value);
147        }
148        return Property::Value();
149      }},
150     {"rotation", ReadRotationHelper},
151     // STRING - not particularly animatable
152     // ARRAY - not particularly animatable
153     // MAP - not particularly animatable
154     {"extents", [](const TreeNode* tn) {
155        Extents value;
156        if(ReadQuadHelper<uint16_t>(tn, {&value.start, &value.end, &value.top, &value.bottom}))
157        {
158          return Property::Value(value);
159        }
160        return Property::Value();
161      }},
162   };
163   return kTypeIds;
164 }
165
166 Property::Value (*const kArrayPropertyProcessors[])(const TreeNode*){
167   ReadVectorHelper<Matrix>,
168   ReadVectorHelper<Matrix3>,
169   ReadVectorHelper<Vector4>,
170   ReadVectorHelper<Vector3>,
171   ReadVectorHelper<Vector2>,
172   ReadVectorSingleFloatHelper};
173
174 } // namespace
175
176 bool ReadBool(const TreeNode* node, bool& num)
177 {
178   if(!node)
179   {
180     return false;
181   }
182
183   bool returnValue = false;
184   if(node->GetType() == TreeNode::BOOLEAN)
185   {
186     num         = node->GetBoolean();
187     returnValue = true;
188   }
189
190   return returnValue;
191 }
192
193 bool ReadInt(const TreeNode* node, int& num)
194 {
195   if(!node)
196   {
197     return false;
198   }
199
200   bool returnValue = false;
201   if(node->GetType() == TreeNode::INTEGER)
202   {
203     num         = node->GetInteger();
204     returnValue = true;
205   }
206   else if(node->GetType() == TreeNode::FLOAT)
207   {
208     num         = static_cast<int>(node->GetFloat());
209     returnValue = true;
210   }
211
212   return returnValue;
213 }
214
215 bool ReadFloat(const TreeNode* node, float& num)
216 {
217   if(!node)
218   {
219     return false;
220   }
221
222   bool returnValue = false;
223   if(node->GetType() == TreeNode::FLOAT)
224   {
225     num         = node->GetFloat();
226     returnValue = true;
227   }
228   else if(node->GetType() == TreeNode::INTEGER)
229   {
230     num         = static_cast<float>(node->GetInteger());
231     returnValue = true;
232   }
233
234   return returnValue;
235 }
236
237 bool ReadIndex(const Toolkit::TreeNode* node, Index& num)
238 {
239   bool returnValue = node && node->GetType() == TreeNode::INTEGER;
240   if(returnValue)
241   {
242     num = static_cast<Index>(node->GetInteger());
243   }
244
245   return returnValue;
246 }
247
248 bool ReadBlob(const Toolkit::TreeNode* node, unsigned int& offset, unsigned int& length)
249 {
250   if(!node)
251   {
252     return false;
253   }
254
255   int  iOffset, iLength;
256   bool success = ReadInt(node->GetChild("byteOffset"), iOffset) &&
257                  ReadInt(node->GetChild("byteLength"), iLength) &&
258                  iOffset >= 0 && iLength >= 0; // 0 length might not be sensible, but is not an error at this stage.
259   if(success)
260   {
261     offset = static_cast<unsigned int>(iOffset);
262     length = static_cast<unsigned int>(iLength);
263   }
264   return success;
265 }
266
267 size_t GetNumericalArraySize(const TreeNode* node)
268 {
269   size_t size = 0;
270   if(node->GetType() == TreeNode::ARRAY)
271   {
272     for(auto i0 = node->CBegin(), i1 = node->CEnd(); i0 != i1 &&
273                                                      ((*i0).second.GetType() == TreeNode::FLOAT || (*i0).second.GetType() == TreeNode::INTEGER);
274         ++i0)
275     {
276       ++size;
277     }
278   }
279   return size;
280 }
281
282 bool ReadVector(const TreeNode* node, float* num, unsigned int size)
283 {
284   if(!node)
285   {
286     return false;
287   }
288
289   bool returnValue = false;
290   if((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
291   {
292     unsigned int offset = 0u;
293     for(TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
294     {
295       const TreeNode& coord = (*it).second;
296       if(!ReadFloat(&coord, *(num + offset)))
297       {
298         return false;
299       }
300     }
301     returnValue = true;
302   }
303
304   return returnValue;
305 }
306
307 bool ReadVector(const Toolkit::TreeNode* node, int* num, unsigned int size)
308 {
309   if(!node)
310   {
311     return false;
312   }
313
314   bool returnValue = false;
315   if((node->Size() >= size) && (node->GetType() == TreeNode::ARRAY))
316   {
317     unsigned int offset = 0u;
318     for(TreeNode::ConstIterator it = node->CBegin(); offset < size; ++it, ++offset)
319     {
320       const TreeNode& coord = (*it).second;
321       if(!ReadInt(&coord, *(num + offset)))
322       {
323         return false;
324       }
325     }
326     returnValue = true;
327   }
328
329   return returnValue;
330 }
331
332 bool ReadColor(const TreeNode* node, Vector4& color)
333 {
334   if(nullptr == node)
335   {
336     return false;
337   }
338
339   if(!ReadVector(node, color.AsFloat(), 4))
340   {
341     if(!ReadVector(node, color.AsFloat(), 3))
342     {
343       return false;
344     }
345     color.a = 1.f;
346   }
347
348   return true;
349 }
350
351 bool ReadTimePeriod(const TreeNode* node, TimePeriod& timePeriod)
352 {
353   if(!node)
354   {
355     return false;
356   }
357
358   if(!ReadFloat(node->GetChild("delay"), timePeriod.delaySeconds) || !ReadFloat(node->GetChild("duration"), timePeriod.durationSeconds))
359   {
360     return false;
361   }
362   return true;
363 }
364
365 bool ReadString(const TreeNode* node, std::string& strValue)
366 {
367   if(!node)
368   {
369     return false;
370   }
371
372   bool returnValue = false;
373   if(node->GetType() == TreeNode::STRING)
374   {
375     strValue    = node->GetString();
376     returnValue = true;
377   }
378   return returnValue;
379 }
380
381 bool ReadStringVector(const TreeNode* node, std::vector<std::string>& strvector)
382 {
383   if(!node)
384   {
385     return false;
386   }
387
388   bool returnValue = false;
389   if(node->GetType() == TreeNode::ARRAY)
390   {
391     for(TreeNode::ConstIterator it = node->CBegin(); it != node->CEnd(); ++it)
392     {
393       const TreeNode& strNode = (*it).second;
394       if(strNode.GetType() == TreeNode::STRING)
395       {
396         strvector.push_back(strNode.GetString());
397       }
398       else
399       {
400         return false;
401       }
402     }
403     returnValue = true;
404   }
405   return returnValue;
406 }
407
408 Property::Value ReadPropertyValue(const Property::Type& propType, const TreeNode& tn)
409 {
410   switch(propType)
411   {
412     case Property::BOOLEAN:
413       return ReadPrimitiveHelper<bool>(&tn, ReadBool);
414
415     case Property::FLOAT:
416       return ReadPrimitiveHelper<float>(&tn, ReadFloat);
417
418     case Property::INTEGER:
419       return ReadPrimitiveHelper<int>(&tn, ReadInt);
420
421     case Property::VECTOR2:
422       return ReadVectorHelper<Vector2>(&tn);
423
424     case Property::VECTOR3:
425       return ReadVectorHelper<Vector3>(&tn);
426
427     case Property::VECTOR4:
428       return ReadVectorHelper<Vector4>(&tn);
429
430     case Property::MATRIX3:
431       return ReadVectorHelper<Matrix3>(&tn);
432
433     case Property::MATRIX:
434       return ReadVectorHelper<Matrix>(&tn);
435
436     case Property::RECTANGLE:
437     {
438       Rect<int> value;
439       if(ReadQuadHelper<int>(&tn, {&value.x, &value.y, &value.width, &value.height}))
440       {
441         return Property::Value(value);
442       }
443       break;
444     }
445
446     case Property::ROTATION:
447       return ReadRotationHelper(&tn);
448
449     case Property::EXTENTS:
450     {
451       Extents value;
452       if(ReadQuadHelper<uint16_t>(&tn, {&value.start, &value.end, &value.top, &value.bottom}))
453       {
454         return Property::Value(value);
455       }
456       break;
457     }
458
459     case Property::NONE: // fall
460     default:
461     {
462       DALI_ASSERT_ALWAYS(!"Property type incorrect");
463     }
464   }
465   return Property::Value();
466 }
467
468 Property::Value ReadPropertyValue(const Toolkit::TreeNode& tn)
469 {
470   Property::Value propValue;
471   if(tn.GetType() == TreeNode::OBJECT) // attempt to disambiguate type.
472   {
473     auto jsonType = tn.GetChild("type");
474     if(jsonType && jsonType->GetType() == TreeNode::STRING)
475     {
476       auto iFind = GetTypeIds().find(jsonType->GetString());
477       if(iFind != GetTypeIds().end())
478       {
479         propValue = iFind->second(tn.GetChild("value"));
480       }
481     }
482   }
483
484   if(propValue.GetType() == Property::NONE)
485   {
486     if(tn.Size() == 0)
487     {
488       switch(tn.GetType())
489       {
490         case TreeNode::BOOLEAN:
491           propValue = ReadPrimitiveHelper<bool>(&tn, ReadBool);
492           break;
493
494         case TreeNode::INTEGER:
495           propValue = ReadPrimitiveHelper<int>(&tn, ReadInt);
496           break;
497
498         case TreeNode::FLOAT:
499           propValue = ReadPrimitiveHelper<float>(&tn, ReadFloat);
500           break;
501
502         default:
503           break;
504       }
505     }
506     else
507     {
508       bool allNumbers = true;
509       for(auto i0 = tn.CBegin(), i1 = tn.CEnd(); i0 != i1; ++i0)
510       {
511         auto type = (*i0).second.GetType();
512         if(!(type == TreeNode::FLOAT || type == TreeNode::INTEGER))
513         {
514           allNumbers = false;
515           break;
516         }
517       }
518
519       if(allNumbers)
520       {
521         // NOTE: rotations / rectangles / extents must be disambiguated in all circumstances.
522         for(auto& r : kArrayPropertyProcessors)
523         {
524           propValue = r(&tn);
525           if(propValue.GetType() != Property::NONE)
526           {
527             break;
528           }
529         }
530       }
531     }
532   }
533   return propValue;
534 }
535
536 } // namespace Loader
537 } // namespace Scene3D
538 } // namespace Dali