Merge "DALi Version 2.2.17" into 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/algorithm/navigation-mesh.h"
19 #include "dali-scene3d/public-api/loader/navigation-mesh-factory.h"
20 #include <dali-test-suite-utils.h>
21
22 using namespace Dali;
23 using namespace Dali::Scene3D::Algorithm;
24 using namespace Dali::Scene3D::Loader;
25
26 int UtcDaliNavigationMeshCreateFromFileFail1(void)
27 {
28   tet_infoline("UtcDaliNavigationMeshCreateFromFileFail1: Fails to create navigation mesh from file");
29
30   // No such file, misspelled name
31   auto result = NavigationMeshFactory::CreateFromFile("notexisting.bin");
32
33   DALI_TEST_CHECK(result == nullptr);
34
35   END_TEST;
36 }
37
38 int UtcDaliNavigationMeshCreateFromFileOk1(void)
39 {
40   tet_infoline("UtcDaliNavigationMeshCreateFromFileOk1: Creates navigation mesh using file");
41
42   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
43
44   DALI_TEST_CHECK(result != nullptr);
45
46   END_TEST;
47 }
48
49 int UtcDaliNavigationMeshCreateFromBufferP(void)
50 {
51   tet_infoline("UtcDaliNavigationMeshCreateFromBufferP: Creates navigation mesh using binary buffer");
52
53   auto fin = fopen("resources/navmesh-test.bin", "rb");
54   [[maybe_unused]] auto err = fseek(fin, 0, SEEK_END);
55   auto length = ftell(fin);
56   fseek( fin, 0, SEEK_SET);
57   std::vector<uint8_t> buffer;
58   buffer.resize(length);
59   fread( buffer.data(), 1, length, fin );
60   fclose(fin);
61   auto result = NavigationMeshFactory::CreateFromBuffer( buffer );
62   DALI_TEST_CHECK(result != nullptr);
63
64   END_TEST;
65 }
66
67 int UtcDaliNavigationMeshCountersP(void)
68 {
69   tet_infoline("UtcDaliNavigationMeshCountersP: Test vertex, edge and face counts");
70
71   auto result = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
72
73   DALI_TEST_CHECK(result != nullptr);
74
75   auto vertexCount = result->GetVertexCount();
76   auto edgeCount = result->GetEdgeCount();
77   auto faceCount = result->GetFaceCount();
78
79   DALI_TEST_EQUALS( vertexCount, 132, TEST_LOCATION );
80   DALI_TEST_EQUALS( edgeCount, 300, TEST_LOCATION );
81   DALI_TEST_EQUALS( faceCount, 165, TEST_LOCATION );
82
83   END_TEST;
84 }
85
86 int UtcDaliNavigationMeshGetVertexP(void)
87 {
88   tet_infoline("UtcDaliNavigationMeshGetVertexP: Test vertex getters");
89
90   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
91
92   DALI_TEST_CHECK(navmesh != nullptr);
93
94   auto vertexCount = navmesh->GetVertexCount();
95
96   DALI_TEST_EQUALS( vertexCount, 132, TEST_LOCATION );
97
98   // List of coords, must be verified with Blender exporter
99   // clang-format off
100   std::vector<float> vertexData = {
101     -7.000000f, -3.000000f, 0.000000f, -4.018748f, 3.000000f, 0.000000f,
102     1.943754f, -1.500000f, 0.000000f, -2.541295f, -0.756627f, 0.000000f,
103     -0.277504f, -1.593252f, 0.000000f, 0.682341f, 2.316388f, 3.349901f,
104     1.912569f, 1.240314f, 2.549901f, 2.215021f, -0.365898f, 1.749901f,
105     1.460422f, -1.815717f, 0.949901f, -0.336699f, -2.992929f, 3.829999f,
106     -3.179410f, 0.153939f, 3.829999f, -3.664814f, 2.992929f, 3.829999f,
107     -1.384417f, 0.876845f, 3.829999f, -1.571236f, 1.101834f, 3.829999f
108   };
109   // clang-format on
110
111   auto j = 0;
112   for( auto i = 0u; i < 132; i+= 10, j+= 3)
113   {
114     const auto* vertex = navmesh->GetVertex(i);
115     Vector3 v0(vertex->co);
116     Vector3 v1(vertexData[j], vertexData[j+1], vertexData[j+2]);
117     DALI_TEST_EQUALS( v0, v1, TEST_LOCATION);
118   }
119
120   END_TEST;
121 }
122
123 int UtcDaliNavigationMeshGetEdgeP(void)
124 {
125   tet_infoline("UtcDaliNavigationMeshGetEdgeP: Test edge getters");
126
127   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
128
129   DALI_TEST_CHECK(navmesh != nullptr);
130
131   auto edgeCount = navmesh->GetEdgeCount();
132
133   DALI_TEST_EQUALS( edgeCount, 300, TEST_LOCATION );
134
135   // List of coords, must be verified with Blender exporter
136   // clang-format off
137   std::vector<uint16_t> edgeData = {
138     2, 65535, 8, 1,
139     8, 109, 124, 108,
140     10, 158, 32, 35,
141     78, 65535, 50, 52,
142     54, 75, 70, 69,
143     83, 65535, 83, 81,
144     79, 65535, 86, 42,
145     140, 65535, 94, 115,
146     111, 112, 118, 111,
147     101, 143, 106, 127
148   };
149   // clang-format on
150   auto j = 0;
151   for( auto i = 0u; i < 300; i+= 30, j+= 4)
152   {
153     const auto* edge = navmesh->GetEdge(i);
154     auto e0 = edge->face[0];
155     auto e1 = edge->face[1];
156     auto v0 = edge->vertex[0];
157     auto v1 = edge->vertex[1];
158
159     DALI_TEST_EQUALS(e0, edgeData[j+0], TEST_LOCATION);
160     DALI_TEST_EQUALS(e1, edgeData[j+1], TEST_LOCATION);
161     DALI_TEST_EQUALS(v0, edgeData[j+2], TEST_LOCATION);
162     DALI_TEST_EQUALS(v1, edgeData[j+3], TEST_LOCATION);
163   }
164
165   END_TEST;
166 }
167
168 int UtcDaliNavigationMeshGetFaceP(void)
169 {
170   tet_infoline("UtcDaliNavigationMeshGetFaceP: Test face getters");
171
172   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
173
174   DALI_TEST_CHECK(navmesh != nullptr);
175
176   auto faceCount = navmesh->GetFaceCount();
177
178   DALI_TEST_EQUALS( faceCount, 165, TEST_LOCATION );
179
180   // List of coords, must be verified with Blender exporter
181   // clang-format off
182
183   std::vector<NavigationMesh::Face> faceData = {
184     {{6, 10, 17}, {14, 32, 8}, {0.000000f, 0.000000f, 1.000000f}, {-3.024998f, 2.500000f, 0.000000f}},
185     {{130, 120, 44}, {228, 215, 33}, {0.000000f, 0.000000f, 1.000000f}, {-1.097451f, 1.192811f, 3.829999f}},
186     {{30, 9, 38}, {13, 291, 289}, {0.000000f, -0.000000f, 1.000000f}, {-3.029388f, -1.252209f, 0.000000f}},
187     {{55, 52, 53}, {140, 95, 96}, {0.522345f, -0.298279f, 0.798865f}, {0.743287f, 1.610713f, 3.136567f}},
188     {{69, 66, 67}, {91, 121, 122}, {0.071722f, -0.597219f, 0.798865f}, {1.632142f, 0.155658f, 2.016567f}},
189     {{41, 86, 87}, {81, 160, 80}, {-0.563316f, -0.210929f, 0.798864f}, {0.340215f, -1.799765f, 0.416567f}},
190     {{28, 19, 27}, {55, 74, 47}, {0.000000f, -0.000000f, 1.000000f}, {-0.640862f, -1.037395f, 0.000000f}},
191     {{118, 96, 111}, {213, 241, 240}, {0.000000f, 0.000000f, 1.000000f}, {-6.577459f, -0.586560f, 3.829999f}},
192     {{91, 107, 103}, {170, 258, 257}, {-0.021129f, 0.023143f, 0.999509f}, {-2.551766f, 1.007552f, 3.829145f}},
193     {{97, 120, 130}, {191, 228, 271}, {0.000000f, 0.000000f, 1.000000f}, {-1.795930f, 0.710873f, 3.829999f}},
194     {{30, 39, 31}, {290, 296, 295}, {0.000000f, 0.000000f, 1.000000f}, {-2.291577f, -0.509718f, 0.000000f}},
195   };
196   // clang-format on
197   auto j = 0;
198   for( auto i = 0u; i < 165; i+= 16, j++)
199   {
200     const auto* face = navmesh->GetFace(i);
201     Vector3 n0(face->normal);
202     Vector3 c0(face->center);
203
204     Vector3 n1(faceData[j].normal);
205     Vector3 c1(faceData[j].center);
206
207     DALI_TEST_EQUALS( n0, n1, TEST_LOCATION);
208     DALI_TEST_EQUALS( c0, c1, TEST_LOCATION);
209
210     DALI_TEST_EQUALS( faceData[j].vertex[0], face->vertex[0], TEST_LOCATION);
211     DALI_TEST_EQUALS( faceData[j].vertex[1], face->vertex[1], TEST_LOCATION);
212     DALI_TEST_EQUALS( faceData[j].vertex[2], face->vertex[2], TEST_LOCATION);
213
214     DALI_TEST_EQUALS( faceData[j].edge[0], face->edge[0], TEST_LOCATION);
215     DALI_TEST_EQUALS( faceData[j].edge[1], face->edge[1], TEST_LOCATION);
216     DALI_TEST_EQUALS( faceData[j].edge[2], face->edge[2], TEST_LOCATION);
217   }
218
219   END_TEST;
220 }
221
222
223 int UtcDaliNavigationGetGravityP(void)
224 {
225   tet_infoline("UtcDaliNavigationGetGravityP: Tests gravity vector");
226   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
227   auto gravity = navmesh->GetGravityVector();
228
229   // navmesh-test.bin is exported in Blender and the default gravity is Z = -1
230   Dali::Vector3 expectedGravity( 0.0f, 0.0f, -1.0f );
231
232   DALI_TEST_EQUALS( gravity, expectedGravity, TEST_LOCATION);
233
234   END_TEST;
235 }
236
237 int UtcDaliNavigationSetTransformP(void)
238 {
239   tet_infoline("UtcDaliNavigationSetTransformP: Test setting transform");
240
241   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
242
243   Matrix matrix;
244   matrix.SetIdentity();
245   Quaternion q = Quaternion( Radian(Degree(-90)), Vector3(1.0, 0.0, 0.0));
246   Matrix newMatrix;
247   matrix.Multiply( newMatrix, matrix, q); // Rotate matrix along X-axis
248
249   navmesh->SetSceneTransform(newMatrix);
250
251   auto point = Vector3(0, 1, 0);
252
253   [[maybe_unused]] Vector3 navMeshLocalSpace;
254   [[maybe_unused]] Vector3 navMeshParentSpace;
255   navMeshLocalSpace = navmesh->PointSceneToLocal(point);
256
257   // Should match gravity vector
258   auto gravityVector = navmesh->GetGravityVector();
259
260   // 'point' should be turned into the gravity vector after transforming into the local space
261   DALI_TEST_EQUALS( navMeshLocalSpace, gravityVector, TEST_LOCATION);
262
263   navMeshParentSpace = navmesh->PointLocalToScene(gravityVector);
264
265   // The gravity should be transformed back into point
266   DALI_TEST_EQUALS( navMeshParentSpace, point, TEST_LOCATION);
267
268   END_TEST;
269 }
270
271 int UtcDaliNavigationFindFloor0P(void)
272 {
273   tet_infoline("UtcDaliNavigationFindFloor0P: Finds floor with result");
274
275   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
276
277   // All calculations in the navmesh local space
278   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
279
280   std::vector<Vector3> inPositions;
281   std::vector<Vector3> expectedPositions;
282   std::vector<uint32_t> expectedFaceIndex;
283   std::vector<bool> expectedResult;
284
285   // Lift slightly over the floor level
286   auto upFromGravity = navmesh->GetGravityVector() * (0.05f);
287
288   auto size = navmesh->GetFaceCount();
289   for( auto i = 0u; i < size; ++i)
290   {
291     const auto* face = navmesh->GetFace(i);
292     Vector3(face->center);
293     inPositions.emplace_back(Vector3(face->center));
294     inPositions.back() -= Vector3( upFromGravity );
295     expectedResult.emplace_back(true);
296
297     expectedPositions.emplace_back(face->center);
298     expectedFaceIndex.emplace_back(i);
299   }
300
301   // Add negative results
302   // Middle 'circle' of scene
303   inPositions.emplace_back(Vector3(-0.048838f, 0.039285f, 0.013085f));
304   expectedPositions.emplace_back();
305   expectedFaceIndex.emplace_back( NavigationMesh::NULL_FACE );
306   expectedResult.emplace_back(false);
307
308   // Triangle under stairs
309   inPositions.emplace_back(Vector3(0.44365f, -1.787f, 0.13085f));
310   expectedPositions.emplace_back();
311   expectedFaceIndex.emplace_back( NavigationMesh::NULL_FACE );
312   expectedResult.emplace_back(false);
313
314   // Outside area
315   inPositions.emplace_back(Vector3(0.77197f, -3.8596f, 0.13085f));
316   expectedPositions.emplace_back();
317   expectedFaceIndex.emplace_back( NavigationMesh::NULL_FACE );
318   expectedResult.emplace_back(false);
319
320   for( auto i = 0u; i < inPositions.size(); ++i )
321   {
322     Vector3  outPosition;
323     uint32_t faceIndex {NavigationMesh::NULL_FACE};
324     auto result = navmesh->FindFloor(inPositions[i], outPosition, faceIndex);
325     DALI_TEST_EQUALS( bool(result), bool(expectedResult[i]), TEST_LOCATION);
326     DALI_TEST_EQUALS( faceIndex, expectedFaceIndex[i], TEST_LOCATION);
327     DALI_TEST_EQUALS( outPosition, expectedPositions[i], TEST_LOCATION);
328   }
329
330   END_TEST;
331 }
332
333 int UtcDaliNavigationFindFloorForFace1P(void)
334 {
335   tet_infoline("UtcDaliNavigationFindFloorForFace1P: Finds floor for selected face");
336
337   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
338
339   // All calculations in the navmesh local space
340   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
341
342   {
343     auto faceIndex = 0u;
344     auto position = Vector3( 0, 0, 0);
345     auto dontCheckNeighbours = true;
346     auto outPosition = Vector3();
347     auto expectedPosition = Vector3();
348     bool result = false;
349
350     {
351       // test 1. position lies within selected triangle
352       faceIndex = 137;
353       position = Vector3(-6.0767f, -1.7268f, 4.287f);
354       expectedPosition = Vector3(-6.0767f, -1.7268f, 3.83f);
355       dontCheckNeighbours = true;
356       result = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
357
358       DALI_TEST_EQUALS( result, true, TEST_LOCATION);
359       DALI_TEST_EQUALS( outPosition, expectedPosition, TEST_LOCATION);
360     }
361
362     {
363       // test 2. position lies outside selected triangle, not checking neighbours
364       faceIndex = 137;
365       position = Vector3(-5.3073f, -0.6023f, 4.287f);
366       expectedPosition = Vector3::ZERO;
367       outPosition = Vector3::ZERO;
368       dontCheckNeighbours = true;
369       result = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
370
371       DALI_TEST_EQUALS( result, false, TEST_LOCATION);
372       DALI_TEST_EQUALS( outPosition, expectedPosition, TEST_LOCATION);
373     }
374
375     {
376       // test 3. position lies outside selected triangle but this time checking neighbours
377       faceIndex = 137;
378       position = Vector3(-5.3073f, -0.6023f, 4.287f);
379       expectedPosition = Vector3(-5.3073, -0.6023, 3.83);
380       outPosition = Vector3::ZERO;
381       dontCheckNeighbours = false;
382       result = navmesh->FindFloorForFace(position, faceIndex, dontCheckNeighbours, outPosition);
383
384       DALI_TEST_EQUALS( result, true, TEST_LOCATION);
385       DALI_TEST_EQUALS( outPosition, expectedPosition, TEST_LOCATION);
386     }
387   }
388
389   END_TEST;
390 }
391
392 int UtcDaliNavigationFindFloorForFace2P(void)
393 {
394   tet_infoline("UtcDaliNavigationFindFloorForFace2P: Finds floor for selected face");
395
396   auto navmesh = NavigationMeshFactory::CreateFromFile("resources/navmesh-test.bin");
397
398   // All calculations in the navmesh local space
399   navmesh->SetSceneTransform(Matrix(Matrix::IDENTITY));
400
401   {
402     [[maybe_unused]] auto faceIndex = 0u;
403     auto position = Vector3( 0, 0, 0);
404     auto dontCheckNeighbours = true;
405     auto outPosition = Vector3();
406     auto expectedPosition = Vector3();
407     bool result = false;
408
409     {
410       // test 4. position lies within a triangle but this time full search forced,
411       // the navmesh must have no previous searches (mCurrentFace shouldn't be set)
412       faceIndex = 137;
413       position = Vector3(-6.0767f, -1.7268f, 4.287f);
414       expectedPosition = Vector3(-6.0767f, -1.7268f, 3.83f);
415       dontCheckNeighbours = true;
416       result = navmesh->FindFloorForFace(position, NavigationMesh::NULL_FACE, dontCheckNeighbours, outPosition);
417
418       DALI_TEST_EQUALS( result, true, TEST_LOCATION);
419       DALI_TEST_EQUALS( outPosition, expectedPosition, TEST_LOCATION);
420     }
421
422   }
423
424   END_TEST;
425 }