Revert "[Tizen] Add log if destroyed visual get some signal"
[platform/core/uifw/dali-toolkit.git] / automated-tests / src / dali-scene3d / utc-Dali-NavigationMesh.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 #include <dali-test-suite-utils.h>
19 #include <dlfcn.h>
20 #include "dali-scene3d/public-api/algorithm/navigation-mesh.h"
21 #include "dali-scene3d/public-api/loader/navigation-mesh-factory.h"
22 using namespace Dali;
23 using namespace Dali::Scene3D::Algorithm;
24 using namespace Dali::Scene3D::Loader;
25
26 /**
27  * SysOverride allows overriding a system symbol and
28  * set the return value for n-th call of it.
29  *
30  * After invoking the symbol override is disabled.
31  */
32 template<class R, class F>
33 struct SysOverride
34 {
35   SysOverride(const char* funcName)
36   {
37     funcNameStr = funcName;
38     if(!func)
39     {
40       func = decltype(func)(dlsym(RTLD_NEXT, funcName));
41     }
42   }
43
44   void SetReturnValue(R value, uint32_t n)
45   {
46     if(overrideEnabled)
47     {
48       tet_infoline("Warning! Overriding return value is already enabled! Ignoring!\n");
49       return;
50     }
51     result          = value;
52     overrideCounter = n;
53     overrideEnabled = true;
54   }
55
56   template<class... Args>
57   R Invoke(Args&&... args)
58   {
59     auto retval = func(args...);
60     if(overrideEnabled)
61     {
62       if(!overrideCounter)
63       {
64         overrideEnabled = false;
65         return result;
66       }
67       overrideCounter--;
68     }
69     return retval;
70   }
71
72   std::string funcNameStr;
73   R           result{R{}};
74   F*          func{nullptr};
75   uint32_t    overrideCounter = 0;
76   bool        overrideEnabled = false;
77 };
78
79 // Override fseek()
80 static thread_local SysOverride<int, decltype(fseek)> call_fseek("fseek");
81 extern "C" int                                        fseek(FILE* s, long int o, int w)
82 {
83   return call_fseek.Invoke(s, o, w);
84 }
85
86 // Override ftell()
87 static thread_local SysOverride<int, decltype(ftell)> call_ftell("ftell");
88 extern "C" long int                                   ftell(FILE* s)
89 {
90   return call_ftell.Invoke(s);
91 }
92
93 // Override fread()
94 static thread_local SysOverride<int, decltype(fread)> call_fread("fread");
95 extern "C" size_t                                     fread(void* __restrict p, size_t s, size_t n, FILE* __restrict st)
96 {
97   return call_fread.Invoke(p, s, n, st);
98 }
99
100 int UtcDaliNavigationMeshCreateFromFileFail1(void)
101 {
102   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail1: Fails to create navigation mesh from file");
103
104   // No such file, misspelled name
105   auto result = NavigationMeshFactory::CreateFromFile("notexisting.bin");
106
107   DALI_TEST_CHECK(result == nullptr);
108
109   END_TEST;
110 }
111
112 int UtcDaliNavigationMeshCreateFromFileFail2(void)
113 {
114   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail2: Fails to create navigation mesh using file");
115
116   // Override next fseek to fail
117   call_fseek.SetReturnValue(-1, 0);
118   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
119
120   DALI_TEST_CHECK(result == nullptr);
121
122   END_TEST;
123 }
124
125 int UtcDaliNavigationMeshCreateFromFileFail3(void)
126 {
127   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail3: Fails to create navigation mesh using file");
128
129   // Override next ftell to fail
130   call_ftell.SetReturnValue(-1, 0);
131   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
132
133   DALI_TEST_CHECK(result == nullptr);
134
135   END_TEST;
136 }
137
138 int UtcDaliNavigationMeshCreateFromFileFail4(void)
139 {
140   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail4: Fails to create navigation mesh using file");
141
142   // Override 2nd fseek to fail
143   call_fseek.SetReturnValue(-1, 1);
144   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
145
146   DALI_TEST_CHECK(result == nullptr);
147
148   END_TEST;
149 }
150
151 int UtcDaliNavigationMeshCreateFromFileFail5(void)
152 {
153   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail5: Fails to create navigation mesh using file");
154
155   // Override fread() to fail reading file
156   call_fread.SetReturnValue(-1, 0);
157   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
158
159   DALI_TEST_CHECK(result == nullptr);
160
161   END_TEST;
162 }
163
164 int UtcDaliNavigationMeshCreateFromFileOk1(void)
165 {
166   tet_infoline("UtcDaliNavigationMeshCreateFromFileOk1: Creates navigation mesh using file");
167
168   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
169
170   DALI_TEST_CHECK(result != nullptr);
171
172   END_TEST;
173 }
174
175 int UtcDaliNavigationMeshCreateFromBufferP(void)
176 {
177   tet_infoline("UtcDaliNavigationMeshCreateFromBufferP: Creates navigation mesh using binary buffer");
178
179   auto                  fin    = fopen("resources/navmesh-test.bin", "rb");
180   [[maybe_unused]] auto err    = fseek(fin, 0, SEEK_END);
181   auto                  length = ftell(fin);
182   fseek(fin, 0, SEEK_SET);
183   std::vector<uint8_t> buffer;
184   buffer.resize(length);
185   fread(buffer.data(), 1, length, fin);
186   fclose(fin);
187   auto result = NavigationMeshFactory::CreateFromBuffer(buffer);
188   DALI_TEST_CHECK(result != nullptr);
189
190   END_TEST;
191 }
192
193 int UtcDaliNavigationMeshCountersP(void)
194 {
195   tet_infoline("UtcDaliNavigationMeshCountersP: Test vertex, edge and face counts");
196
197   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
198
199   DALI_TEST_CHECK(result != nullptr);
200
201   auto vertexCount = result->GetVertexCount();
202   auto edgeCount   = result->GetEdgeCount();
203   auto faceCount   = result->GetFaceCount();
204
205   DALI_TEST_EQUALS(vertexCount, 132, TEST_LOCATION);
206   DALI_TEST_EQUALS(edgeCount, 300, TEST_LOCATION);
207   DALI_TEST_EQUALS(faceCount, 165, TEST_LOCATION);
208
209   END_TEST;
210 }
211
212 int UtcDaliNavigationMeshGetVertexP(void)
213 {
214   tet_infoline("UtcDaliNavigationMeshGetVertexP: Test vertex getters");
215
216   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
217
218   DALI_TEST_CHECK(navmesh != nullptr);
219
220   auto vertexCount = navmesh->GetVertexCount();
221
222   DALI_TEST_EQUALS(vertexCount, 132, TEST_LOCATION);
223
224   // List of coords, must be verified with Blender exporter
225   // clang-format off
226   std::vector<float> vertexData = {
227     -7.000000f, -3.000000f, 0.000000f, -4.018748f, 3.000000f, 0.000000f,
228     1.943754f, -1.500000f, 0.000000f, -2.541295f, -0.756627f, 0.000000f,
229     -0.277504f, -1.593252f, 0.000000f, 0.682341f, 2.316388f, 3.349901f,
230     1.912569f, 1.240314f, 2.549901f, 2.215021f, -0.365898f, 1.749901f,
231     1.460422f, -1.815717f, 0.949901f, -0.336699f, -2.992929f, 3.829999f,
232     -3.179410f, 0.153939f, 3.829999f, -3.664814f, 2.992929f, 3.829999f,
233     -1.384417f, 0.876845f, 3.829999f, -1.571236f, 1.101834f, 3.829999f
234   };
235   // clang-format on
236
237   auto j = 0;
238   for(auto i = 0u; i < 132; i += 10, j += 3)
239   {
240     const auto* vertex = navmesh->GetVertex(i);
241     Vector3     v0(vertex->coordinates);
242     Vector3     v1(vertexData[j], vertexData[j + 1], vertexData[j + 2]);
243     DALI_TEST_EQUALS(v0, v1, TEST_LOCATION);
244   }
245
246   END_TEST;
247 }
248
249 int UtcDaliNavigationMeshGetEdgeP(void)
250 {
251   tet_infoline("UtcDaliNavigationMeshGetEdgeP: Test edge getters");
252
253   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
254
255   DALI_TEST_CHECK(navmesh != nullptr);
256
257   auto edgeCount = navmesh->GetEdgeCount();
258
259   DALI_TEST_EQUALS(edgeCount, 300, TEST_LOCATION);
260
261   // List of coords, must be verified with Blender exporter
262   // clang-format off
263   std::vector<EdgeIndex> edgeData = {
264     2, 65535, 8, 1,
265     8, 109, 124, 108,
266     10, 158, 32, 35,
267     78, 65535, 50, 52,
268     54, 75, 70, 69,
269     83, 65535, 83, 81,
270     79, 65535, 86, 42,
271     140, 65535, 94, 115,
272     111, 112, 118, 111,
273     101, 143, 106, 127
274   };
275   // clang-format on
276   auto j = 0;
277   for(auto i = 0u; i < 300; i += 30, j += 4)
278   {
279     const auto* edge = navmesh->GetEdge(i);
280     auto        e0   = edge->face[0];
281     auto        e1   = edge->face[1];
282     auto        v0   = edge->vertex[0];
283     auto        v1   = edge->vertex[1];
284
285     DALI_TEST_EQUALS(e0, edgeData[j + 0], TEST_LOCATION);
286     DALI_TEST_EQUALS(e1, edgeData[j + 1], TEST_LOCATION);
287     DALI_TEST_EQUALS(v0, edgeData[j + 2], TEST_LOCATION);
288     DALI_TEST_EQUALS(v1, edgeData[j + 3], TEST_LOCATION);
289   }
290
291   END_TEST;
292 }
293
294 int UtcDaliNavigationMeshGetFaceP(void)
295 {
296   tet_infoline("UtcDaliNavigationMeshGetFaceP: Test face getters");
297
298   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
299
300   DALI_TEST_CHECK(navmesh != nullptr);
301
302   auto faceCount = navmesh->GetFaceCount();
303
304   DALI_TEST_EQUALS(faceCount, 165, TEST_LOCATION);
305
306   // List of coords, must be verified with Blender exporter
307   // clang-format off
308
309   std::vector<NavigationMesh::Face> faceData = {
310     {{6, 10, 17}, {14, 32, 8}, {0.000000f, 0.000000f, 1.000000f}, {-3.024998f, 2.500000f, 0.000000f}},
311     {{130, 120, 44}, {228, 215, 33}, {0.000000f, 0.000000f, 1.000000f}, {-1.097451f, 1.192811f, 3.829999f}},
312     {{30, 9, 38}, {13, 291, 289}, {0.000000f, -0.000000f, 1.000000f}, {-3.029388f, -1.252209f, 0.000000f}},
313     {{55, 52, 53}, {140, 95, 96}, {0.522345f, -0.298279f, 0.798865f}, {0.743287f, 1.610713f, 3.136567f}},
314     {{69, 66, 67}, {91, 121, 122}, {0.071722f, -0.597219f, 0.798865f}, {1.632142f, 0.155658f, 2.016567f}},
315     {{41, 86, 87}, {81, 160, 80}, {-0.563316f, -0.210929f, 0.798864f}, {0.340215f, -1.799765f, 0.416567f}},
316     {{28, 19, 27}, {55, 74, 47}, {0.000000f, -0.000000f, 1.000000f}, {-0.640862f, -1.037395f, 0.000000f}},
317     {{118, 96, 111}, {213, 241, 240}, {0.000000f, 0.000000f, 1.000000f}, {-6.577459f, -0.586560f, 3.829999f}},
318     {{91, 107, 103}, {170, 258, 257}, {-0.021129f, 0.023143f, 0.999509f}, {-2.551766f, 1.007552f, 3.829145f}},
319     {{97, 120, 130}, {191, 228, 271}, {0.000000f, 0.000000f, 1.000000f}, {-1.795930f, 0.710873f, 3.829999f}},
320     {{30, 39, 31}, {290, 296, 295}, {0.000000f, 0.000000f, 1.000000f}, {-2.291577f, -0.509718f, 0.000000f}},
321   };
322   // clang-format on
323   auto j = 0;
324   for(auto i = 0u; i < 165; i += 16, j++)
325   {
326     const auto* face = navmesh->GetFace(i);
327     Vector3     n0(face->normal);
328     Vector3     c0(face->center);
329
330     Vector3 n1(faceData[j].normal);
331     Vector3 c1(faceData[j].center);
332
333     DALI_TEST_EQUALS(n0, n1, TEST_LOCATION);
334     DALI_TEST_EQUALS(c0, c1, TEST_LOCATION);
335
336     DALI_TEST_EQUALS(faceData[j].vertex[0], face->vertex[0], TEST_LOCATION);
337     DALI_TEST_EQUALS(faceData[j].vertex[1], face->vertex[1], TEST_LOCATION);
338     DALI_TEST_EQUALS(faceData[j].vertex[2], face->vertex[2], TEST_LOCATION);
339
340     DALI_TEST_EQUALS(faceData[j].edge[0], face->edge[0], TEST_LOCATION);
341     DALI_TEST_EQUALS(faceData[j].edge[1], face->edge[1], TEST_LOCATION);
342     DALI_TEST_EQUALS(faceData[j].edge[2], face->edge[2], TEST_LOCATION);
343   }
344
345   END_TEST;
346 }
347
348 int UtcDaliNavigationGetGravityP(void)
349 {
350   tet_infoline("UtcDaliNavigationGetGravityP: Tests gravity vector");
351   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
352   auto gravity = navmesh->GetGravityVector();
353
354   // navmesh-test.bin is exported in Blender and the default gravity is Z = -1
355   Dali::Vector3 expectedGravity(0.0f, 0.0f, -1.0f);
356
357   DALI_TEST_EQUALS(gravity, expectedGravity, TEST_LOCATION);
358
359   END_TEST;
360 }
361
362 int UtcDaliNavigationSetTransformP(void)
363 {
364   tet_infoline("UtcDaliNavigationSetTransformP: Test setting transform");
365
366   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
367
368   Matrix matrix;
369   matrix.SetIdentity();
370   Quaternion q = Quaternion(Radian(Degree(-90)), Vector3(1.0, 0.0, 0.0));
371   Matrix     newMatrix;
372   matrix.Multiply(newMatrix, matrix, q); // Rotate matrix along X-axis
373
374   navmesh->SetSceneTransform(newMatrix);
375
376   auto point = Vector3(0, 1, 0);
377
378   [[maybe_unused]] Vector3 navMeshLocalSpace;
379   [[maybe_unused]] Vector3 navMeshParentSpace;
380   navMeshLocalSpace = navmesh->PointSceneToLocal(point);
381
382   // Should match gravity vector
383   auto gravityVector = navmesh->GetGravityVector();
384
385   // 'point' should be turned into the gravity vector after transforming into the local space
386   DALI_TEST_EQUALS(navMeshLocalSpace, gravityVector, TEST_LOCATION);
387
388   navMeshParentSpace = navmesh->PointLocalToScene(gravityVector);
389
390   // The gravity should be transformed back into point
391   DALI_TEST_EQUALS(navMeshParentSpace, point, TEST_LOCATION);
392
393   END_TEST;
394 }
395
396 int UtcDaliNavigationFindFloor0P(void)
397 {
398   tet_infoline("UtcDaliNavigationFindFloor0P: Finds floor with result");
399
400   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
401
402   // All calculations in the navmesh local space
403   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
404
405   std::vector<Vector3>   inPositions;
406   std::vector<Vector3>   expectedPositions;
407   std::vector<FaceIndex> expectedFaceIndex;
408   std::vector<bool>      expectedResult;
409
410   // Lift slightly over the floor level
411   auto upFromGravity = navmesh->GetGravityVector() * (0.05f);
412
413   auto size = navmesh->GetFaceCount();
414   for(auto i = 0u; i < size; ++i)
415   {
416     const auto* face = navmesh->GetFace(i);
417     Vector3(face->center);
418     inPositions.emplace_back(Vector3(face->center));
419     inPositions.back() -= Vector3(upFromGravity);
420     expectedResult.emplace_back(true);
421
422     expectedPositions.emplace_back(face->center);
423     expectedFaceIndex.emplace_back(i);
424   }
425
426   // Add negative results
427   // Middle 'circle' of scene
428   inPositions.emplace_back(Vector3(-0.048838f, 0.039285f, 0.013085f));
429   expectedPositions.emplace_back();
430   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
431   expectedResult.emplace_back(false);
432
433   // Triangle under stairs
434   inPositions.emplace_back(Vector3(0.44365f, -1.787f, 0.13085f));
435   expectedPositions.emplace_back();
436   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
437   expectedResult.emplace_back(false);
438
439   // Outside area
440   inPositions.emplace_back(Vector3(0.77197f, -3.8596f, 0.13085f));
441   expectedPositions.emplace_back();
442   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
443   expectedResult.emplace_back(false);
444
445   for(auto i = 0u; i < inPositions.size(); ++i)
446   {
447     Vector3   outPosition;
448     FaceIndex faceIndex{NavigationMesh::NULL_FACE};
449     auto      result = navmesh->FindFloor(inPositions[i], outPosition, faceIndex);
450     DALI_TEST_EQUALS(bool(result), bool(expectedResult[i]), TEST_LOCATION);
451     DALI_TEST_EQUALS(faceIndex, expectedFaceIndex[i], TEST_LOCATION);
452     DALI_TEST_EQUALS(outPosition, expectedPositions[i], TEST_LOCATION);
453   }
454
455   END_TEST;
456 }
457
458 int UtcDaliNavigationFindFloorForFace1P(void)
459 {
460   tet_infoline("UtcDaliNavigationFindFloorForFace1P: Finds floor for selected face");
461
462   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
463
464   // All calculations in the navmesh local space
465   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
466
467   {
468     auto faceIndex           = FaceIndex(0u);
469     auto position            = Vector3(0, 0, 0);
470     auto dontCheckNeighbours = true;
471     auto outPosition         = Vector3();
472     auto expectedPosition    = Vector3();
473     bool result              = false;
474
475     {
476       // test 1. position lies within selected triangle
477       faceIndex           = 137;
478       position            = Vector3(-6.0767f, -1.7268f, 4.287f);
479       expectedPosition    = Vector3(-6.0767f, -1.7268f, 3.83f);
480       dontCheckNeighbours = true;
481       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
482
483       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
484       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
485     }
486
487     {
488       // test 2. position lies outside selected triangle, not checking neighbours
489       faceIndex           = 137;
490       position            = Vector3(-5.3073f, -0.6023f, 4.287f);
491       expectedPosition    = Vector3::ZERO;
492       outPosition         = Vector3::ZERO;
493       dontCheckNeighbours = true;
494       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
495
496       DALI_TEST_EQUALS(result, false, TEST_LOCATION);
497       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
498     }
499
500     {
501       // test 3. position lies outside selected triangle but this time checking neighbours
502       faceIndex           = 137;
503       position            = Vector3(-5.3073f, -0.6023f, 4.287f);
504       expectedPosition    = Vector3(-5.3073, -0.6023, 3.83);
505       outPosition         = Vector3::ZERO;
506       dontCheckNeighbours = false;
507       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
508
509       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
510       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
511     }
512   }
513
514   END_TEST;
515 }
516
517 int UtcDaliNavigationFindFloorForFace2P(void)
518 {
519   tet_infoline("UtcDaliNavigationFindFloorForFace2P: Finds floor for selected face");
520
521   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
522
523   // All calculations in the navmesh local space
524   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
525
526   {
527     [[maybe_unused]] auto faceIndex           = 0u;
528     auto                  position            = Vector3(0, 0, 0);
529     auto                  dontCheckNeighbours = true;
530     auto                  outPosition         = Vector3();
531     auto                  expectedPosition    = Vector3();
532     bool                  result              = false;
533
534     {
535       // test 4. position lies within a triangle but this time full search forced,
536       // the navmesh must have no previous searches (mCurrentFace shouldn't be set)
537       faceIndex           = 137;
538       position            = Vector3(-6.0767f, -1.7268f, 4.287f);
539       expectedPosition    = Vector3(-6.0767f, -1.7268f, 3.83f);
540       dontCheckNeighbours = true;
541       result              = navmesh->FindFloorForFace(position, NavigationMesh::NULL_FACE, dontCheckNeighbours, outPosition);
542
543       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
544       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
545     }
546   }
547
548   END_TEST;
549 }