1 #ifndef DALI_SCENE3D_NAVIGATION_MESH_H
2 #define DALI_SCENE3D_NAVIGATION_MESH_H
5 * Copyright (c) 2023 Samsung Electronics Co., Ltd.
7 * Licensed under the Apache License, Version 2.0 (the "License");
8 * you may not use this file except in compliance with the License.
9 * You may obtain a copy of the License at
11 * http://www.apache.org/licenses/LICENSE-2.0
13 * Unless required by applicable law or agreed to in writing, software
14 * distributed under the License is distributed on an "AS IS" BASIS,
15 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 * See the License for the specific language governing permissions and
17 * limitations under the License.
21 #include <dali/public-api/common/vector-wrapper.h>
22 #include <dali/public-api/math/matrix.h>
23 #include <dali/public-api/math/vector3.h>
24 #include <dali/public-api/math/vector4.h>
32 #include <dali-scene3d/public-api/api.h>
34 namespace Dali::Scene3D::Internal::Algorithm
39 namespace Dali::Scene3D::Loader
41 class NavigationMeshFactory;
44 constexpr auto NAVIGATION_MESH_MAX_VERTICES_PER_FACE = 3u;
45 constexpr auto NAVIGATION_MESH_MAX_EDGES_PER_FACE = 3u;
46 constexpr auto NAVIGATION_MESH_MAX_COMPONENTS_3D = 3u;
47 constexpr auto NAVIGATION_MESH_MAX_COMPONENTS_2D = 2u;
49 namespace Dali::Scene3D::Algorithm
51 // Using PImpling but not usual DALi handles as this object isn't supposed to be refcounted
52 using NavigationMeshImpl = Dali::Scene3D::Internal::Algorithm::NavigationMesh;
54 // Make each to change each index value's type here.
55 using VertexIndex = uint16_t;
56 using EdgeIndex = uint16_t;
57 using FaceIndex = uint16_t;
60 * @class NavigationMesh
62 * NavigationMesh is a set of connected faces. The data contains
63 * Polygons (Polys), Edges and Vertices and describes relations
64 * between (for example, edge knows which polys are on each side).
66 * NavigationMesh uses any coordinate system that it has been exported with.
68 * The mesh is exported with gravity direction. This is because various editors
69 * may define UP vector differently. Note, the Gravity vector points DOWN.
71 * - All calculation take place in the navigation mesh local space
72 * - The NavigationMesh should use a correct transformation matrix (SetSceneTransform())
73 * - Without transform, the NavigationMesh space stays local (compatible with exporter tool)
74 * - The NavigationMesh defines Gravity vector (down)
75 * - The finding floor results are returned back into the scene space (set with SetSceneTransform()).
78 class DALI_SCENE3D_API NavigationMesh
84 * Describes a single polygon's face
88 VertexIndex vertex[NAVIGATION_MESH_MAX_VERTICES_PER_FACE]; ///< Vertices per face
89 EdgeIndex edge[NAVIGATION_MESH_MAX_EDGES_PER_FACE]; ///< Edges per face
90 float normal[NAVIGATION_MESH_MAX_COMPONENTS_3D]; ///< Normal vector
91 float center[NAVIGATION_MESH_MAX_COMPONENTS_3D]; ///< Barycentric coordinates
97 * Describes a single edge
101 VertexIndex vertex[NAVIGATION_MESH_MAX_COMPONENTS_2D]; ///< Vertices making the edge
102 FaceIndex face[NAVIGATION_MESH_MAX_COMPONENTS_2D]; ///< Faces on both sides of edge
108 * Describes a single Vertex
115 float coordinates[NAVIGATION_MESH_MAX_COMPONENTS_3D]; ///< Coordinates of vertex
123 NavigationMesh() = delete;
132 * @brief Returns total number of faces
134 * @return number of faces
136 [[nodiscard]] uint32_t GetFaceCount() const;
139 * @brief Returns total number of edges
141 * @return number of edges
143 [[nodiscard]] uint32_t GetEdgeCount() const;
146 * @brief Returns total number of vertices
148 * @return number of vertices
150 [[nodiscard]] uint32_t GetVertexCount() const;
153 * @brief Looks for the floor under specified position
154 * @param[in] position Position to investigate
155 * @param[in] outPosition Position on the floor in found
156 * @param[out] faceIndex Index of NavigationMesh face associated with floor
158 * @return True if floor has been found, False otherwise
160 bool FindFloor(const Dali::Vector3& position, Dali::Vector3& outPosition, FaceIndex& faceIndex);
163 * @brief Looks for a floor starting from specified face
165 * The function performs lookup starting from the specified face. If 'dontCheckNeighbours' is 'true'
166 * then function will fail if 'position' falls outside boundries of face. If 'dontCheckNeighbours'
167 * is 'false' the function will continue search expanding onto neighbouring faces.
169 * @param[in] position Position to investigate
170 * @param[in] faceIndex Face index to start lookup
171 * @param[in] dontCheckNeighbours If true, the neighbouring faces won't be tested
172 * @param[out] outPosition Result of lookup
174 * @return True on success, false otherwise
176 bool FindFloorForFace(const Dali::Vector3& position, FaceIndex faceIndex, bool dontCheckNeighbours, Dali::Vector3& outPosition);
179 * @brief Returns pointer to Face structure
180 * @param[in] index Index of face to retrieve
181 * @return Pointer to valid Face structure or nullptr
183 [[nodiscard]] const Face* GetFace(FaceIndex index) const;
186 * @brief Returns edge structure
187 * @param[in] index Index of edge to retrieve
188 * @return Pointer to valid Edge structure or nullptr
190 [[nodiscard]] const Edge* GetEdge(EdgeIndex index) const;
193 * @brief Returns vertex structure
194 * @param[in] index Index of vertex to retrieve
195 * @return Pointer to valid Vertex structure or nullptr
197 [[nodiscard]] const Vertex* GetVertex(VertexIndex index) const;
200 * @brief Sets static transform for the navigation mesh object
202 * The NavigationMesh may require to be transformed into the coordinates
203 * of the scene object. The exporter exports navigation geometry in a local
204 * space. The transform must be set in order to use the navigation mesh
205 * in the scene space (most likely DALi coordinate space).
207 * The scene transform matrix can be set in the DALi event thread using
208 * Dali::DevelActor::GetWorldTransform(sceneActor)
212 * Actor parentActorOfNavigationMesh; // non-null object
213 * Dali::DevelActor::GetWorldTransform(parentActorOfNavigationMesh);
214 * navigationMesh->SetSceneTransform(parentActorOfNavigationMesh);
217 * The transform remains static until changed by calling SetSceneTransform() again.
218 * It means that if the matrix is obtained from the actor and actor transform will
219 * change the navigation mesh won't be aligned anymore.
221 * @param[in] transform Valid transform 4x4 matrix
223 void SetSceneTransform(const Dali::Matrix& transform);
226 * @brief transforms point into the NavigationMesh local space
228 * Transforms a 3D point into navigation mesh space (space used when
229 * NavigationMesh has been created, most likely 3D editor space).
231 * @param[in] point Point to transform
232 * @return Point transformed to the local space
234 Dali::Vector3 PointSceneToLocal(const Dali::Vector3& point) const;
237 * @brief Transforms point into the parent transform space
239 * Transforms the given point into the parent space (set with SetSceneTransform()).
241 * @param[in] point Point to transform
242 * @return Point transformed into the parent space
244 Dali::Vector3 PointLocalToScene(const Dali::Vector3& point) const;
247 * @brief Returns direction of the gravity vector
249 * Gravity vector points down.
251 * @return Gravity vector 3D
253 Dali::Vector3 GetGravityVector() const;
256 * @brief Performs ray/face intersect test
257 * @param[in] origin Origin of ray
258 * @param[in] direction Direction of ray
261 * @return Valid FaceIndex on hit or NULL_FACE on miss
263 [[nodiscard]] FaceIndex RayFaceIntersect(const Vector3& origin, const Vector3& direction) const;
265 static constexpr FaceIndex NULL_FACE{std::numeric_limits<FaceIndex>::max()}; ///< Represents null face
266 static constexpr EdgeIndex NULL_EDGE{std::numeric_limits<EdgeIndex>::max()}; ///< Represents null edge
269 DALI_INTERNAL explicit NavigationMesh(NavigationMeshImpl* impl);
271 std::unique_ptr<NavigationMeshImpl> mImpl;
274 // Alias name for collider mesh
275 // TODO: currently ColliderMesh is NavigationMesh however
276 // there should be separation from data and algorithms.
277 // Both, NavigationMesh and ColliderMesh use the same
278 // data structures but differ in the way they use data.
279 using ColliderMesh = NavigationMesh;
281 } // namespace Dali::Scene3D::Algorithm
282 #endif // DALI_SCENE3D_NAVIGATION_MESH_H