[dali_2.3.21] Merge branch 'devel/master'
[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-scene3d/public-api/controls/model/model.h>
19 #include <dali-scene3d/public-api/controls/scene-view/scene-view.h>
20 #include <dali-toolkit-test-suite-utils.h>
21 #include <dali/devel-api/actors/camera-actor-devel.h>
22 #include <dali/integration-api/events/touch-event-integ.h>
23 #include <dlfcn.h>
24 #include "dali-scene3d/public-api/algorithm/navigation-mesh.h"
25 #include "dali-scene3d/public-api/loader/navigation-mesh-factory.h"
26
27 // include collider mesh data
28 #include "collider-mesh-data.h"
29
30 using namespace Dali;
31 using namespace Dali::Scene3D::Algorithm;
32 using namespace Dali::Scene3D::Loader;
33
34 /**
35  * SysOverride allows overriding a system symbol and
36  * set the return value for n-th call of it.
37  *
38  * After invoking the symbol override is disabled.
39  */
40 template<class R, class F>
41 struct SysOverride
42 {
43   SysOverride(const char* funcName)
44   {
45     funcNameStr = funcName;
46     if(!func)
47     {
48       func = decltype(func)(dlsym(RTLD_NEXT, funcName));
49     }
50   }
51
52   void SetReturnValue(R value, uint32_t n)
53   {
54     if(overrideEnabled)
55     {
56       tet_infoline("Warning! Overriding return value is already enabled! Ignoring!\n");
57       return;
58     }
59     result          = value;
60     overrideCounter = n;
61     overrideEnabled = true;
62   }
63
64   template<class... Args>
65   R Invoke(Args&&... args)
66   {
67     auto retval = func(args...);
68     if(overrideEnabled)
69     {
70       if(!overrideCounter)
71       {
72         overrideEnabled = false;
73         return result;
74       }
75       overrideCounter--;
76     }
77     return retval;
78   }
79
80   std::string funcNameStr;
81   R           result{R{}};
82   F*          func{nullptr};
83   uint32_t    overrideCounter = 0;
84   bool        overrideEnabled = false;
85 };
86
87 // Override fseek()
88 static thread_local SysOverride<int, decltype(fseek)> call_fseek("fseek");
89 extern "C" int                                        fseek(FILE* s, long int o, int w)
90 {
91   return call_fseek.Invoke(s, o, w);
92 }
93
94 // Override ftell()
95 static thread_local SysOverride<int, decltype(ftell)> call_ftell("ftell");
96 extern "C" long int                                   ftell(FILE* s)
97 {
98   return call_ftell.Invoke(s);
99 }
100
101 // Override fread()
102 static thread_local SysOverride<int, decltype(fread)> call_fread("fread");
103 extern "C" size_t                                     fread(void* __restrict p, size_t s, size_t n, FILE* __restrict st)
104 {
105   return call_fread.Invoke(p, s, n, st);
106 }
107
108 // Data to test factory
109 static std::vector<Dali::Vector3> COLLIDER_0_VERTS = {
110   Dali::Vector3(-1.000000, -1.556106, 0.000000),
111   Dali::Vector3(1.000000, -1.556106, 0.000000),
112   Dali::Vector3(-1.000000, 1.000000, 0.000000),
113   Dali::Vector3(1.000000, 1.000000, 0.000000),
114   Dali::Vector3(3.026269, -1.556106, 0.000000),
115   Dali::Vector3(3.026269, 1.000000, 0.000000),
116   Dali::Vector3(-1.000000, 2.491248, 0.000000),
117   Dali::Vector3(1.000000, 2.491248, 0.000000),
118 };
119 static std::vector<uint32_t> COLLIDER_0_IDX = {
120   1,
121   2,
122   0,
123   1,
124   5,
125   3,
126   3,
127   6,
128   2,
129   1,
130   3,
131   2,
132   1,
133   4,
134   5,
135   3,
136   7,
137   6,
138 };
139 static std::vector<Dali::Vector3> COLLIDER_1_VERTS = {
140   Dali::Vector3(-1.000000, -3.386207, 0.000000),
141   Dali::Vector3(1.000000, -3.386207, 0.000000),
142   Dali::Vector3(-1.000000, 1.000000, 0.000000),
143   Dali::Vector3(1.000000, 1.000000, 0.000000),
144   Dali::Vector3(-3.393266, -3.386207, 0.000000),
145   Dali::Vector3(-3.393266, 1.000000, 0.000000),
146 };
147 static std::vector<uint32_t> COLLIDER_1_IDX = {
148   1,
149   2,
150   0,
151   2,
152   4,
153   0,
154   1,
155   3,
156   2,
157   2,
158   5,
159   4,
160 };
161 static std::vector<Dali::Vector3> COLLIDER_2_VERTS = {
162   Dali::Vector3(-3.393266, -1.000000, 0.000000),
163   Dali::Vector3(1.000000, -1.000000, 0.000000),
164   Dali::Vector3(-3.393266, 0.491248, 0.000000),
165   Dali::Vector3(1.000000, 0.491248, 0.000000),
166 };
167 static std::vector<uint32_t> COLLIDER_2_IDX = {
168   1,
169   2,
170   0,
171   1,
172   3,
173   2,
174 };
175
176 Integration::TouchEvent GenerateSingleTouch(PointState::Type state, const Vector2& screenPosition)
177 {
178   Integration::TouchEvent touchEvent;
179   Integration::Point      point;
180   point.SetState(state);
181   point.SetScreenPosition(screenPosition);
182   point.SetDeviceClass(Device::Class::TOUCH);
183   point.SetDeviceSubclass(Device::Subclass::NONE);
184   touchEvent.points.push_back(point);
185   return touchEvent;
186 }
187
188 int UtcDaliNavigationMeshCreateFromFileFail1(void)
189 {
190   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail1: Fails to create navigation mesh from file");
191
192   // No such file, misspelled name
193   auto result = NavigationMeshFactory::CreateFromFile("notexisting.bin");
194
195   DALI_TEST_CHECK(result == nullptr);
196
197   END_TEST;
198 }
199
200 int UtcDaliNavigationMeshCreateFromFileFail2(void)
201 {
202   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail2: Fails to create navigation mesh using file");
203
204   // Override next fseek to fail
205   call_fseek.SetReturnValue(-1, 0);
206   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
207
208   DALI_TEST_CHECK(result == nullptr);
209
210   END_TEST;
211 }
212
213 int UtcDaliNavigationMeshCreateFromFileFail3(void)
214 {
215   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail3: Fails to create navigation mesh using file");
216
217   // Override next ftell to fail
218   call_ftell.SetReturnValue(-1, 0);
219   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
220
221   DALI_TEST_CHECK(result == nullptr);
222
223   END_TEST;
224 }
225
226 int UtcDaliNavigationMeshCreateFromFileFail4(void)
227 {
228   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail4: Fails to create navigation mesh using file");
229
230   // Override 2nd fseek to fail
231   call_fseek.SetReturnValue(-1, 1);
232   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
233
234   DALI_TEST_CHECK(result == nullptr);
235
236   END_TEST;
237 }
238
239 int UtcDaliNavigationMeshCreateFromFileFail5(void)
240 {
241   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail5: Fails to create navigation mesh using file");
242
243   // Override fread() to fail reading file
244   call_fread.SetReturnValue(-1, 0);
245   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
246
247   DALI_TEST_CHECK(result == nullptr);
248
249   END_TEST;
250 }
251
252 int UtcDaliNavigationMeshCreateFromFileOk1(void)
253 {
254   tet_infoline("UtcDaliNavigationMeshCreateFromFileOk1: Creates navigation mesh using file");
255
256   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
257
258   DALI_TEST_CHECK(result != nullptr);
259
260   END_TEST;
261 }
262
263 int UtcDaliNavigationMeshCreateFromBufferP(void)
264 {
265   tet_infoline("UtcDaliNavigationMeshCreateFromBufferP: Creates navigation mesh using binary buffer");
266
267   auto                  fin    = fopen("resources/navmesh-test.bin", "rb");
268   [[maybe_unused]] auto err    = fseek(fin, 0, SEEK_END);
269   auto                  length = ftell(fin);
270   fseek(fin, 0, SEEK_SET);
271   std::vector<uint8_t> buffer;
272   buffer.resize(length);
273   fread(buffer.data(), 1, length, fin);
274   fclose(fin);
275   auto result = NavigationMeshFactory::CreateFromBuffer(buffer);
276   DALI_TEST_CHECK(result != nullptr);
277
278   END_TEST;
279 }
280
281 int UtcDaliNavigationMeshCountersP(void)
282 {
283   tet_infoline("UtcDaliNavigationMeshCountersP: Test vertex, edge and face counts");
284
285   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
286
287   DALI_TEST_CHECK(result != nullptr);
288
289   auto vertexCount = result->GetVertexCount();
290   auto edgeCount   = result->GetEdgeCount();
291   auto faceCount   = result->GetFaceCount();
292
293   DALI_TEST_EQUALS(vertexCount, 132, TEST_LOCATION);
294   DALI_TEST_EQUALS(edgeCount, 300, TEST_LOCATION);
295   DALI_TEST_EQUALS(faceCount, 165, TEST_LOCATION);
296
297   END_TEST;
298 }
299
300 int UtcDaliNavigationMeshGetVertexP(void)
301 {
302   tet_infoline("UtcDaliNavigationMeshGetVertexP: Test vertex getters");
303
304   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
305
306   DALI_TEST_CHECK(navmesh != nullptr);
307
308   auto vertexCount = navmesh->GetVertexCount();
309
310   DALI_TEST_EQUALS(vertexCount, 132, TEST_LOCATION);
311
312   // List of coords, must be verified with Blender exporter
313   // clang-format off
314   std::vector<float> vertexData = {
315     -7.000000f, -3.000000f, 0.000000f, -4.018748f, 3.000000f, 0.000000f,
316     1.943754f, -1.500000f, 0.000000f, -2.541295f, -0.756627f, 0.000000f,
317     -0.277504f, -1.593252f, 0.000000f, 0.682341f, 2.316388f, 3.349901f,
318     1.912569f, 1.240314f, 2.549901f, 2.215021f, -0.365898f, 1.749901f,
319     1.460422f, -1.815717f, 0.949901f, -0.336699f, -2.992929f, 3.829999f,
320     -3.179410f, 0.153939f, 3.829999f, -3.664814f, 2.992929f, 3.829999f,
321     -1.384417f, 0.876845f, 3.829999f, -1.571236f, 1.101834f, 3.829999f
322   };
323   // clang-format on
324
325   auto j = 0;
326   for(auto i = 0u; i < 132; i += 10, j += 3)
327   {
328     const auto* vertex = navmesh->GetVertex(i);
329     Vector3     v0(vertex->coordinates);
330     Vector3     v1(vertexData[j], vertexData[j + 1], vertexData[j + 2]);
331     DALI_TEST_EQUALS(v0, v1, TEST_LOCATION);
332   }
333
334   END_TEST;
335 }
336
337 int UtcDaliNavigationMeshGetEdgeP(void)
338 {
339   tet_infoline("UtcDaliNavigationMeshGetEdgeP: Test edge getters");
340
341   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
342
343   DALI_TEST_CHECK(navmesh != nullptr);
344
345   auto edgeCount = navmesh->GetEdgeCount();
346
347   DALI_TEST_EQUALS(edgeCount, 300, TEST_LOCATION);
348
349   // List of coords, must be verified with Blender exporter
350   // clang-format off
351   std::vector<EdgeIndex> edgeData = {
352     2, 65535, 8, 1,
353     8, 109, 124, 108,
354     10, 158, 32, 35,
355     78, 65535, 50, 52,
356     54, 75, 70, 69,
357     83, 65535, 83, 81,
358     79, 65535, 86, 42,
359     140, 65535, 94, 115,
360     111, 112, 118, 111,
361     101, 143, 106, 127
362   };
363   // clang-format on
364   auto j = 0;
365   for(auto i = 0u; i < 300; i += 30, j += 4)
366   {
367     const auto* edge = navmesh->GetEdge(i);
368     auto        e0   = edge->face[0];
369     auto        e1   = edge->face[1];
370     auto        v0   = edge->vertex[0];
371     auto        v1   = edge->vertex[1];
372
373     DALI_TEST_EQUALS(e0, edgeData[j + 0], TEST_LOCATION);
374     DALI_TEST_EQUALS(e1, edgeData[j + 1], TEST_LOCATION);
375     DALI_TEST_EQUALS(v0, edgeData[j + 2], TEST_LOCATION);
376     DALI_TEST_EQUALS(v1, edgeData[j + 3], TEST_LOCATION);
377   }
378
379   END_TEST;
380 }
381
382 int UtcDaliNavigationMeshGetFaceP(void)
383 {
384   tet_infoline("UtcDaliNavigationMeshGetFaceP: Test face getters");
385
386   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
387
388   DALI_TEST_CHECK(navmesh != nullptr);
389
390   auto faceCount = navmesh->GetFaceCount();
391
392   DALI_TEST_EQUALS(faceCount, 165, TEST_LOCATION);
393
394   // List of coords, must be verified with Blender exporter
395   // clang-format off
396
397   std::vector<NavigationMesh::Face> faceData = {
398     {{6, 10, 17}, {14, 32, 8}, {0.000000f, 0.000000f, 1.000000f}, {-3.024998f, 2.500000f, 0.000000f}},
399     {{130, 120, 44}, {228, 215, 33}, {0.000000f, 0.000000f, 1.000000f}, {-1.097451f, 1.192811f, 3.829999f}},
400     {{30, 9, 38}, {13, 291, 289}, {0.000000f, -0.000000f, 1.000000f}, {-3.029388f, -1.252209f, 0.000000f}},
401     {{55, 52, 53}, {140, 95, 96}, {0.522345f, -0.298279f, 0.798865f}, {0.743287f, 1.610713f, 3.136567f}},
402     {{69, 66, 67}, {91, 121, 122}, {0.071722f, -0.597219f, 0.798865f}, {1.632142f, 0.155658f, 2.016567f}},
403     {{41, 86, 87}, {81, 160, 80}, {-0.563316f, -0.210929f, 0.798864f}, {0.340215f, -1.799765f, 0.416567f}},
404     {{28, 19, 27}, {55, 74, 47}, {0.000000f, -0.000000f, 1.000000f}, {-0.640862f, -1.037395f, 0.000000f}},
405     {{118, 96, 111}, {213, 241, 240}, {0.000000f, 0.000000f, 1.000000f}, {-6.577459f, -0.586560f, 3.829999f}},
406     {{91, 107, 103}, {170, 258, 257}, {-0.021129f, 0.023143f, 0.999509f}, {-2.551766f, 1.007552f, 3.829145f}},
407     {{97, 120, 130}, {191, 228, 271}, {0.000000f, 0.000000f, 1.000000f}, {-1.795930f, 0.710873f, 3.829999f}},
408     {{30, 39, 31}, {290, 296, 295}, {0.000000f, 0.000000f, 1.000000f}, {-2.291577f, -0.509718f, 0.000000f}},
409   };
410   // clang-format on
411   auto j = 0;
412   for(auto i = 0u; i < 165; i += 16, j++)
413   {
414     const auto* face = navmesh->GetFace(i);
415     Vector3     n0(face->normal);
416     Vector3     c0(face->center);
417
418     Vector3 n1(faceData[j].normal);
419     Vector3 c1(faceData[j].center);
420
421     DALI_TEST_EQUALS(n0, n1, TEST_LOCATION);
422     DALI_TEST_EQUALS(c0, c1, TEST_LOCATION);
423
424     DALI_TEST_EQUALS(faceData[j].vertex[0], face->vertex[0], TEST_LOCATION);
425     DALI_TEST_EQUALS(faceData[j].vertex[1], face->vertex[1], TEST_LOCATION);
426     DALI_TEST_EQUALS(faceData[j].vertex[2], face->vertex[2], TEST_LOCATION);
427
428     DALI_TEST_EQUALS(faceData[j].edge[0], face->edge[0], TEST_LOCATION);
429     DALI_TEST_EQUALS(faceData[j].edge[1], face->edge[1], TEST_LOCATION);
430     DALI_TEST_EQUALS(faceData[j].edge[2], face->edge[2], TEST_LOCATION);
431   }
432
433   END_TEST;
434 }
435
436 int UtcDaliNavigationGetGravityP(void)
437 {
438   tet_infoline("UtcDaliNavigationGetGravityP: Tests gravity vector");
439   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
440   auto gravity = navmesh->GetGravityVector();
441
442   // navmesh-test.bin is exported in Blender and the default gravity is Z = -1
443   Dali::Vector3 expectedGravity(0.0f, 0.0f, -1.0f);
444
445   DALI_TEST_EQUALS(gravity, expectedGravity, TEST_LOCATION);
446
447   END_TEST;
448 }
449
450 int UtcDaliNavigationSetTransformP(void)
451 {
452   tet_infoline("UtcDaliNavigationSetTransformP: Test setting transform");
453
454   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
455
456   Matrix matrix;
457   matrix.SetIdentity();
458   Quaternion q = Quaternion(Radian(Degree(-90)), Vector3(1.0, 0.0, 0.0));
459   Matrix     newMatrix;
460   matrix.Multiply(newMatrix, matrix, q); // Rotate matrix along X-axis
461
462   navmesh->SetSceneTransform(newMatrix);
463
464   auto point = Vector3(0, -1, 0);
465
466   [[maybe_unused]] Vector3 navMeshLocalSpace;
467   [[maybe_unused]] Vector3 navMeshParentSpace;
468   navMeshLocalSpace = navmesh->PointSceneToLocal(point);
469
470   // Should match gravity vector
471   auto gravityVector = navmesh->GetGravityVector();
472
473   // 'point' should be turned into the gravity vector after transforming into the local space
474   DALI_TEST_EQUALS(navMeshLocalSpace, gravityVector, std::numeric_limits<float>::epsilon(), TEST_LOCATION);
475
476   navMeshParentSpace = navmesh->PointLocalToScene(gravityVector);
477
478   // The gravity should be transformed back into point
479   DALI_TEST_EQUALS(navMeshParentSpace, point, std::numeric_limits<float>::epsilon(), TEST_LOCATION);
480
481   END_TEST;
482 }
483
484 int UtcDaliNavigationFindFloor0P(void)
485 {
486   tet_infoline("UtcDaliNavigationFindFloor0P: Finds floor with result");
487
488   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
489
490   // All calculations in the navmesh local space
491   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
492
493   std::vector<Vector3>   inPositions;
494   std::vector<Vector3>   expectedPositions;
495   std::vector<FaceIndex> expectedFaceIndex;
496   std::vector<bool>      expectedResult;
497
498   // Lift slightly over the floor level
499   auto upFromGravity = navmesh->GetGravityVector() * (0.05f);
500
501   auto size = navmesh->GetFaceCount();
502   for(auto i = 0u; i < size; ++i)
503   {
504     const auto* face = navmesh->GetFace(i);
505     Vector3(face->center);
506     inPositions.emplace_back(Vector3(face->center));
507     inPositions.back() -= Vector3(upFromGravity);
508     expectedResult.emplace_back(true);
509
510     expectedPositions.emplace_back(face->center);
511     expectedFaceIndex.emplace_back(i);
512   }
513
514   // Add negative results
515   // Middle 'circle' of scene
516   inPositions.emplace_back(Vector3(-0.048838f, 0.039285f, 0.013085f));
517   expectedPositions.emplace_back();
518   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
519   expectedResult.emplace_back(false);
520
521   // Triangle under stairs
522   inPositions.emplace_back(Vector3(0.44365f, -1.787f, 0.13085f));
523   expectedPositions.emplace_back();
524   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
525   expectedResult.emplace_back(false);
526
527   // Outside area
528   inPositions.emplace_back(Vector3(0.77197f, -3.8596f, 0.13085f));
529   expectedPositions.emplace_back();
530   expectedFaceIndex.emplace_back(NavigationMesh::NULL_FACE);
531   expectedResult.emplace_back(false);
532
533   for(auto i = 0u; i < inPositions.size(); ++i)
534   {
535     Vector3   outPosition;
536     FaceIndex faceIndex{NavigationMesh::NULL_FACE};
537     auto      result = navmesh->FindFloor(inPositions[i], outPosition, faceIndex);
538     DALI_TEST_EQUALS(bool(result), bool(expectedResult[i]), TEST_LOCATION);
539     DALI_TEST_EQUALS(faceIndex, expectedFaceIndex[i], TEST_LOCATION);
540     DALI_TEST_EQUALS(outPosition, expectedPositions[i], TEST_LOCATION);
541   }
542
543   END_TEST;
544 }
545
546 int UtcDaliNavigationFindFloorForFace1P(void)
547 {
548   tet_infoline("UtcDaliNavigationFindFloorForFace1P: Finds floor for selected face");
549
550   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
551
552   // All calculations in the navmesh local space
553   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
554
555   {
556     auto faceIndex           = FaceIndex(0u);
557     auto position            = Vector3(0, 0, 0);
558     auto dontCheckNeighbours = true;
559     auto outPosition         = Vector3();
560     auto expectedPosition    = Vector3();
561     bool result              = false;
562
563     {
564       // test 1. position lies within selected triangle
565       faceIndex           = 137;
566       position            = Vector3(-6.0767f, -1.7268f, 4.287f);
567       expectedPosition    = Vector3(-6.0767f, -1.7268f, 3.83f);
568       dontCheckNeighbours = true;
569       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
570
571       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
572       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
573     }
574
575     {
576       // test 2. position lies outside selected triangle, not checking neighbours
577       faceIndex           = 137;
578       position            = Vector3(-5.3073f, -0.6023f, 4.287f);
579       expectedPosition    = Vector3::ZERO;
580       outPosition         = Vector3::ZERO;
581       dontCheckNeighbours = true;
582       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
583
584       DALI_TEST_EQUALS(result, false, TEST_LOCATION);
585       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
586     }
587
588     {
589       // test 3. position lies outside selected triangle but this time checking neighbours
590       faceIndex           = 137;
591       position            = Vector3(-5.3073f, -0.6023f, 4.287f);
592       expectedPosition    = Vector3(-5.3073, -0.6023, 3.83);
593       outPosition         = Vector3::ZERO;
594       dontCheckNeighbours = false;
595       result              = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
596
597       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
598       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
599     }
600   }
601
602   END_TEST;
603 }
604
605 int UtcDaliNavigationFindFloorForFace2P(void)
606 {
607   tet_infoline("UtcDaliNavigationFindFloorForFace2P: Finds floor for selected face");
608
609   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
610
611   // All calculations in the navmesh local space
612   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
613
614   {
615     [[maybe_unused]] auto faceIndex           = 0u;
616     auto                  position            = Vector3(0, 0, 0);
617     auto                  dontCheckNeighbours = true;
618     auto                  outPosition         = Vector3();
619     auto                  expectedPosition    = Vector3();
620     bool                  result              = false;
621
622     {
623       // test 4. position lies within a triangle but this time full search forced,
624       // the navmesh must have no previous searches (mCurrentFace shouldn't be set)
625       faceIndex           = 137;
626       position            = Vector3(-6.0767f, -1.7268f, 4.287f);
627       expectedPosition    = Vector3(-6.0767f, -1.7268f, 3.83f);
628       dontCheckNeighbours = true;
629       result              = navmesh->FindFloorForFace(position, NavigationMesh::NULL_FACE, dontCheckNeighbours, outPosition);
630
631       DALI_TEST_EQUALS(result, true, TEST_LOCATION);
632       DALI_TEST_EQUALS(outPosition, expectedPosition, TEST_LOCATION);
633     }
634   }
635
636   END_TEST;
637 }
638
639 int UtcDaliNavigationMeshCreateFromVerticesAndFaces(void)
640 {
641   tet_infoline("UtcDaliNavigationMeshCreateFromVerticesAndFaces: Creates NavigationMesh using vertices and faces");
642
643   auto buffer0 = COLLIDER_BUFFER(0);
644
645   // All calculations in the navmesh local space
646   auto fn = [&](const auto& vertices, const auto& normals, const auto& indices) {
647     auto navmesh = NavigationMeshFactory::CreateFromVertexFaceList(vertices, normals, indices);
648     navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
649     DALI_TEST_EQUALS(navmesh->GetVertexCount(), vertices.size(), TEST_LOCATION);
650     DALI_TEST_EQUALS(navmesh->GetFaceCount(), indices.size() / 3, TEST_LOCATION);
651     DALI_TEST_EQUALS(navmesh->GetEdgeCount(), indices.size(), TEST_LOCATION);
652
653     // compare data
654     for(auto i = 0u; i < navmesh->GetVertexCount(); ++i)
655     {
656       Dali::Vector3 v(navmesh->GetVertex(i)->coordinates);
657       DALI_TEST_EQUALS(vertices[i], v, TEST_LOCATION);
658     }
659
660     for(auto i = 0u; i < navmesh->GetFaceCount() * 3; i += 3)
661     {
662       const auto& v = navmesh->GetFace(i / 3)->vertex;
663       DALI_TEST_EQUALS(indices[i], v[0], TEST_LOCATION);
664       DALI_TEST_EQUALS(indices[i + 1], v[1], TEST_LOCATION);
665       DALI_TEST_EQUALS(indices[i + 2], v[2], TEST_LOCATION);
666     }
667   };
668
669   std::vector<Vector3> normals;
670   normals.resize(COLLIDER_0_VERTS.size());
671   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
672   fn(COLLIDER_0_VERTS, normals, COLLIDER_0_IDX);
673
674   normals.resize(COLLIDER_1_VERTS.size());
675   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
676   fn(COLLIDER_1_VERTS, normals, COLLIDER_1_IDX);
677
678   normals.resize(COLLIDER_2_VERTS.size());
679   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
680   fn(COLLIDER_2_VERTS, normals, COLLIDER_2_IDX);
681   END_TEST;
682 }
683
684 int UtcDaliNavigationMeshCreateFromVerticesAndFacesNoNormals(void)
685 {
686   tet_infoline("UtcDaliNavigationMeshCreateFromVerticesAndFacesNoNormals: Creates NavigationMesh using vertices and faces but recalculates normals");
687
688   auto buffer0 = COLLIDER_BUFFER(0);
689
690   // All calculations in the navmesh local space
691   auto fn = [&](const auto& vertices, const auto& indices) {
692     auto navmesh = NavigationMeshFactory::CreateFromVertexFaceList(vertices.data(), nullptr, vertices.size(), indices.data(), indices.size());
693     navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
694     DALI_TEST_EQUALS(navmesh->GetVertexCount(), vertices.size(), TEST_LOCATION);
695     DALI_TEST_EQUALS(navmesh->GetFaceCount(), indices.size() / 3, TEST_LOCATION);
696     DALI_TEST_EQUALS(navmesh->GetEdgeCount(), indices.size(), TEST_LOCATION);
697
698     // compare data
699     for(auto i = 0u; i < navmesh->GetVertexCount(); ++i)
700     {
701       Dali::Vector3 v(navmesh->GetVertex(i)->coordinates);
702       DALI_TEST_EQUALS(vertices[i], v, TEST_LOCATION);
703     }
704
705     for(auto i = 0u; i < navmesh->GetFaceCount() * 3; i += 3)
706     {
707       const auto& v = navmesh->GetFace(i / 3)->vertex;
708       DALI_TEST_EQUALS(indices[i], v[0], TEST_LOCATION);
709       DALI_TEST_EQUALS(indices[i + 1], v[1], TEST_LOCATION);
710       DALI_TEST_EQUALS(indices[i + 2], v[2], TEST_LOCATION);
711     }
712   };
713
714   std::vector<Vector3> normals;
715   normals.resize(COLLIDER_0_VERTS.size());
716   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
717   fn(COLLIDER_0_VERTS, COLLIDER_0_IDX);
718
719   normals.resize(COLLIDER_1_VERTS.size());
720   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
721   fn(COLLIDER_1_VERTS, COLLIDER_1_IDX);
722
723   normals.resize(COLLIDER_2_VERTS.size());
724   std::fill(normals.begin(), normals.end(), Vector3(0.0, 1.0, 0.0));
725   fn(COLLIDER_2_VERTS, COLLIDER_2_IDX);
726   END_TEST;
727 }
728
729 int UtcDaliNavigationMeshGetBinaryTest(void)
730 {
731   tet_infoline("UtcDaliNavigationMeshGetBinaryTest: Creates meshes dynamically, reloads binaries and compares");
732
733   // Test 10 collider meshes
734   for(auto i = 0u; i < 10; ++i)
735   {
736     auto colliderMesh = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(i));
737     auto binary       = NavigationMeshFactory::GetMeshBinary(*colliderMesh);
738     DALI_TEST_EQUALS(binary.size() > 0, true, TEST_LOCATION);
739
740     auto colliderMesh2 = NavigationMeshFactory::CreateFromBuffer(binary);
741
742     DALI_TEST_EQUALS(colliderMesh->GetFaceCount(), colliderMesh2->GetFaceCount(), TEST_LOCATION);
743     DALI_TEST_EQUALS(colliderMesh->GetVertexCount(), colliderMesh2->GetVertexCount(), TEST_LOCATION);
744     DALI_TEST_EQUALS(colliderMesh->GetEdgeCount(), colliderMesh2->GetEdgeCount(), TEST_LOCATION);
745
746     // test vertices
747     for(auto idx = 0u; idx < colliderMesh->GetFaceCount(); ++idx)
748     {
749       auto v0  = colliderMesh->GetVertex(idx);
750       auto v1  = colliderMesh2->GetVertex(idx);
751       auto co0 = Vector3(v0->coordinates);
752       auto co1 = Vector3(v1->coordinates);
753       DALI_TEST_EQUALS(co0, co1, std::numeric_limits<float>::epsilon(), TEST_LOCATION);
754     }
755
756     // test face
757     for(auto idx = 0u; idx < colliderMesh->GetFaceCount(); ++idx)
758     {
759       auto  f0  = colliderMesh->GetFace(idx);
760       auto  f1  = colliderMesh2->GetFace(idx);
761       auto& vi0 = f0->vertex;
762       auto& vi1 = f1->vertex;
763       DALI_TEST_EQUALS(vi0[0], vi1[0], TEST_LOCATION);
764       DALI_TEST_EQUALS(vi0[1], vi1[1], TEST_LOCATION);
765       DALI_TEST_EQUALS(vi0[2], vi1[2], TEST_LOCATION);
766     }
767   }
768
769   END_TEST;
770 }
771
772 int UtcDaliColliderMeshModelNodeSetup(void)
773 {
774   tet_infoline("UtcDaliColliderMeshModelNodeSetup: Test different variants of setting up a collider mesh to the node");
775
776   ToolkitTestApplication   application;
777   Dali::Scene3D::ModelNode node  = Dali::Scene3D::ModelNode::New();
778   Dali::Scene3D::Model     model = Dali::Scene3D::Model::New();
779   model.AddModelNode(node);
780
781   application.GetWindow().Add(model);
782   application.SendNotification();
783   application.Render();
784
785   auto colliderMesh = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(0));
786
787   // Redundant setup test
788   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
789   node.SetColliderMesh(nullptr);
790   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
791   node.SetColliderMesh(std::move(colliderMesh));
792   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
793
794   // Reset collider mesh
795   node.SetColliderMesh(nullptr);
796   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
797
798   auto colliderMesh2 = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(1));
799   auto colliderMesh3 = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(2));
800
801   const auto& cm2 = *colliderMesh2;
802   const auto& cm3 = *colliderMesh3;
803
804   node.SetColliderMesh(std::move(colliderMesh2));
805   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
806   DALI_TEST_EQUALS(&node.GetColliderMesh(), &cm2, TEST_LOCATION);
807   node.SetColliderMesh(std::move(colliderMesh3));
808   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
809   DALI_TEST_EQUALS(&node.GetColliderMesh(), &cm3, TEST_LOCATION);
810
811   node.SetColliderMesh(nullptr);
812   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
813
814   END_TEST;
815 }
816
817 int UtcDaliColliderMeshModelNodeRemoveModelNode(void)
818 {
819   tet_infoline("UtcDaliColliderMeshModelNodeRemoveModelNode: Test removing model node when there is collider mesh attached");
820
821   ToolkitTestApplication   application;
822   Dali::Scene3D::ModelNode node  = Dali::Scene3D::ModelNode::New();
823   Dali::Scene3D::Model     model = Dali::Scene3D::Model::New();
824   model.AddModelNode(node);
825
826   application.GetWindow().Add(model);
827   application.SendNotification();
828   application.Render();
829
830   auto colliderMesh = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(0));
831
832   // Redundant setup test
833   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
834   node.SetColliderMesh(nullptr);
835   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
836   node.SetColliderMesh(std::move(colliderMesh));
837   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
838
839   model.RemoveModelNode(node);
840   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
841
842   // Reset collider mesh
843   node.SetColliderMesh(nullptr);
844   DALI_TEST_EQUALS(node.HasColliderMesh(), false, TEST_LOCATION);
845
846   auto colliderMesh1 = NavigationMeshFactory::CreateFromBuffer(GetTestColliderMesh(0));
847
848   node.SetColliderMesh(std::move(colliderMesh1));
849   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
850
851   model.AddModelNode(node);
852   DALI_TEST_EQUALS(node.HasColliderMesh(), true, TEST_LOCATION);
853
854   END_TEST;
855 }