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